[LoopInterchange] Reject interchange when a freeze would move or be cloned
Loop interchange moves four blocks to a different loop depth: the outer loop
header and latch, and the inner loop preheader and exit block. It also splits
the inner loop latch and clones the instructions that compute the latch branch
condition and induction variable updates into the new latch block.
LangRef guarantees that all uses of the value returned by one execution of a
`freeze` observe that same value. The guarantee does not extend across
executions, so one `freeze` may yield a different value each time it runs.
Different `freeze` instructions may also yield different values for the same
`undef` or poison operand. Both steps above can therefore change which value a
use observes.
Moving a `freeze` to a different loop depth changes which loop iterations share
one dynamic result. Uses that observed a single frozen value in the original
nest can observe values from separate executions after interchange. Cloning a
`freeze` creates a second, independent instruction, so the original and clone
can yield different values for the same operand.
Reject the interchange when a `freeze` appears in one of the four moved blocks
or among the instructions cloned into the new latch. A `freeze` elsewhere still
reaches the same uses from each execution, so it remains allowed. That includes
a `freeze` in the outer loop preheader and one in the inner loop body outside
the cloned computations. The check is conservative and does not try to prove
that the operand of a `freeze` is never `undef` or poison.
Assisted-by: Claude Opus 5, GPT-5.6 Sol.