[llvm] [InferAlignment] Add variable offset alignment analysis for GEPs in InferAlignment (PR #185980)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 5 09:48:09 PDT 2026


================
@@ -133,32 +183,134 @@ bool inferAlignment(Function &F, AssumptionCache &AC, DominatorTree &DT) {
     return Align(1ull << std::min(Known.getBitWidth() - 1, TrailZ));
   };
 
+  // Helper function to compute variable offset alignment and base pointer.
+  // If ConstOffset > 0, the effective offset alignment is limited by the
+  // constant offset.
+  auto computeVariableOffsetAlignment =
+      [&](Value *Ptr, uint64_t ConstOffset = 0) -> std::pair<Value *, Align> {
+    Align VarOffsetAlign = Align(1);
+    Value *VarBasePtr = Ptr;
+
+    if (auto *GEP = dyn_cast<GEPOperator>(VarBasePtr)) {
+      // We can only handle GEPs with a single index
+      if (GEP->getNumIndices() == 1) {
+        Value *Idx = GEP->idx_begin()->get();
+        Align IndexAlign(1);
+
+        if (auto PatternAlign = getIndexAlignmentFromPattern(Idx))
+          IndexAlign = *PatternAlign;
+
+        Type *EltTy = GEP->getSourceElementType();
+        TypeSize EltSizeType = DL.getTypeAllocSize(EltTy);
+
+        // If we encounter a scalable type, we can't compute alignment.
+        if (!EltSizeType.isScalable()) {
+          uint64_t EltSize = EltSizeType.getFixedValue();
+
+          // Compute offset alignment: multiply index alignment by element size,
+          // then take the greatest power of 2 that divides the product.
+          uint64_t Product = IndexAlign.value() * EltSize;
+          uint64_t ProductAlignValue =
+              Product > 0 ? (Product & (~Product + 1)) : 1;
+          VarOffsetAlign = Align(ProductAlignValue);
+        }
+
+        VarBasePtr = GEP->getPointerOperand();
+      }
+    }
+    VarBasePtr = VarBasePtr->stripPointerCasts();
+
+    // If we have a constant offset, the effective alignment is the GCD of both.
+    if (ConstOffset > 0)
+      VarOffsetAlign = commonAlignment(VarOffsetAlign, ConstOffset);
+
+    return {VarBasePtr, VarOffsetAlign};
+  };
+
   // Propagate alignment between loads and stores that originate from the
   // same base pointer.
   ScopedHT BestBasePointerAligns;
+
+  auto updateBestBaseAlign = [&](Value *BasePtr, Align NewAlign) {
+    if (Align Old = BestBasePointerAligns.lookup(BasePtr); Old != Align()) {
+      if (NewAlign <= Old)
+        return;
+    }
+    BestBasePointerAligns.insert(BasePtr, NewAlign);
----------------
yasmincs wrote:

I have tested this with patterns such as: 
entry:
  br i1 %cond, label %then, label %else

then:
  call void @llvm.assume(i1 true) ["align"(ptr %a, i32 64)]
  br label %merge

else:
  %load = load i32, ptr %a, align 4
  br label %merge

merge:
  ret void

The code works as intended. After the for loop going through all the instructions in a BasicBlock, the loop pushes the next child node on the stack or removes the AlignmentScope if all of the children have been visited.

https://github.com/llvm/llvm-project/pull/185980


More information about the llvm-commits mailing list