[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