[llvm] [LoopInterchange] Support inner-loop simple reductions via UndoSimpleReduction (PR #172970)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 24 06:14:12 PST 2025
================
@@ -1633,10 +1882,68 @@ void LoopInterchangeTransform::restructureLoops(
SE->forgetLoop(NewOuter);
}
+/// User can write, optimizers can generate simple reduction for inner loop. In
+/// order to make interchange valid, we have to undo reduction by moving th
+/// initialization and store instructions into the inner loop. So far we only
+/// handle cases where the reduction variable is initialized to a constant.
+/// For example, below code:
+///
+/// loop:
+/// re = phi<0.0, next>
+/// next = re op ...
+/// reduc_sum = phi<next> // lcssa phi
+/// MEM_REF[idx] = reduc_sum // LcssaStorer
+///
+/// is transformed into:
+///
+/// loop:
+/// tmp = MEM_REF[idx];
+/// new_var = !first_iteration ? tmp : 0.0;
+/// next = new_var op ...
+/// MEM_REF[idx] = next; // after moving
+///
+/// In this way the initial const is used in the first iteration of loop.
+void LoopInterchangeTransform::undoSimpleReduction() {
+
+ ArrayRef<LoopInterchangeLegality::SimpleReduction> InnerSimpleReductions =
+ LIL.getInnerSimpleReductions();
+
+ assert(InnerSimpleReductions.size() == 1 &&
+ "So far we only support at most one reduction.");
+
+ LoopInterchangeLegality::SimpleReduction SR = InnerSimpleReductions[0];
+ BasicBlock *InnerLoopHeader = InnerLoop->getHeader();
+ IRBuilder<> Builder(&*(InnerLoopHeader->getFirstNonPHIIt()));
+
+ // When the reduction is intialized from constant value, we need to add
+ // a stmt loading from the memory object to target basic block in inner
+ // loop during undoing the reduction.
+ Instruction *LoadMem = Builder.CreateLoad(SR.ElemTy, SR.MemRef);
+
+ // Check if it's the first iteration.
+ PHINode *IV = SR.CounterIV;
+ Value *IVInit = IV->getIncomingValueForBlock(InnerLoop->getLoopPreheader());
+ Value *FirstIter = Builder.CreateICmpNE(IV, IVInit, "first.iter");
+
+ // Init new_var to MEM_REF or CONST depending on if it is the first iteration.
+ Value *NewVar = Builder.CreateSelect(FirstIter, LoadMem, SR.Init, "new.var");
+
+ // Replace all uses of reduction var with new variable.
+ SR.Re->replaceAllUsesWith(NewVar);
+
+ // Move store instruction into inner loop, just after reduction next's def.
+ SR.LcssaStorer->setOperand(0, SR.Next);
+ SR.LcssaStorer->moveAfter(dyn_cast<Instruction>(SR.Next));
+}
+
bool LoopInterchangeTransform::transform(
ArrayRef<Instruction *> DropNoWrapInsts) {
bool Transformed = false;
+ auto &InnerSimpleReductions = LIL.getInnerSimpleReductions();
----------------
kasuga-fj wrote:
```suggestion
ArrayRef<SimpleReduction> InnerSimpleReductions = LIL.getInnerSimpleReductions();
```
https://github.com/llvm/llvm-project/pull/172970
More information about the llvm-commits
mailing list