[llvm] [CGP] Simple loop strength reduction for vector values (PR #226197)
Sander de Smalen via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 5 01:40:15 PDT 2026
================
@@ -8920,6 +8944,156 @@ static bool optimizeBranch(CondBrInst *Branch, const TargetLowering &TLI,
return false;
}
+// Performs very basic loop strength reduction to vector values with a known
+// evolution from one iteration to the next that are used as the value operand
+// for a store.
+// A simple example to illustrate:
+//
+// %vec.ind = phi <vscale x 2 x i64> [ %start, %entry ],
+// [ %vec.ind.next, %vector.body ]
+// %data.gep = getelementptr inbounds nuw [72 x i8], ptr %datap,
+// <vscale x 2 x i64> %vec.ind
+// %addr.gep = getelementptr inbounds nuw [8 x i8], ptr %addrp, i64 %index
+// store <vscale x 2 x ptr> %data.gep, ptr %addr.gep, align 8
+// %vec.ind.next = add nuw nsw <vscale x 2 x i64> %vec.ind, %elt.cnt.splat
+//
+// We want to change this to:
+// %base = ptrtoint(%datap) + (<stepvector> * 72)
+// %stride = splat(elementcount) * 72
+// vector.body:
+// %vec.ind = phi <vscale x 2 x i64> [ %base, %entry ],
+// [ %vec.ind.next, %vector.body ]
+// %data.val = inttoptr %vec.ind
+// %addr.gep = getelementptr inbounds nuw [8 x i8], ptr %addrp, i64 %index
+// store <vscale x 2 x ptr> %data.val, ptr %addr.gep, align 8
+// %vec.ind.next = add nuw nsw <vscale x 2 x i64> %vec.ind, %stride
+//
+// Doing so will remove a multiply from the loop, and leave the update as just
+// an add.
+//
+// TODO: Support more cases, such as the address instead of value operand for
+// strided memory operations.
+static bool strengthReduceVectorPhiUsers(PHINode *Phi, LoopInfo *LI) {
+ // We're only interested in header phis in innermost loops.
+ // We want a loop with an identifiable preheader and single latch.
+ Loop *L = LI->getLoopFor(Phi->getParent());
+ if (!L || !L->isInnermost())
+ return false;
+
+ BasicBlock *Header = L->getHeader();
+ BasicBlock *PreHeader = L->getLoopPreheader();
+ BasicBlock *Latch = L->getLoopLatch();
+ if (!PreHeader || !Latch || Phi->getParent() != Header)
+ return false;
+
+ // Check the progression of the phi.
+ Value *Start = Phi->getIncomingValueForBlock(PreHeader);
+ Value *Step = Phi->getIncomingValueForBlock(Latch);
+
+ // TODO: Handle offsets from stepvector.
+ if (!match(Start, m_Intrinsic<Intrinsic::stepvector>()))
+ return false;
+
+ Value *LoopStride = nullptr;
+ if (!match(Step, m_c_Add(m_Specific(Phi), m_Value(LoopStride))))
+ return false;
+
+ const APInt *ShiftAmt = nullptr;
+ Value *ShiftedVScale = nullptr;
+ if (!match(LoopStride,
+ m_Splat(
+ m_Value(ShiftedVScale, m_Shl(m_VScale(), m_APInt(ShiftAmt))))))
+ return false;
+
+ // Make sure the shift amount matches the minimum element count.
----------------
sdesmalen-arm wrote:
nit: I would also recommend combining the two expressions into one test to make it more clear what this code is doing:
```
// Make sure the loop stride matches the pointer stride.
auto EltCnt = cast<VectorType>(Phi->getType())->getElementCount();
const APInt *ShiftAmt = nullptr;
Value *ShiftedVScale = nullptr;
if (!match(LoopStride,
m_Splat(
m_Value(ShiftedVScale, m_Shl(m_VScale(), m_APInt(ShiftAmt))))) ||
((1ULL << ShiftAmt->getZExtValue()) != EltCnt.getKnownMinValue()))
return false;
```
(and maybe rename `ShiftedVScale` to `PtrStride`? that makes more sense with the `StructStride` definition below).
https://github.com/llvm/llvm-project/pull/226197
More information about the llvm-commits
mailing list