[llvm] [InstCombine] Try folding align assumes with unkown offset (PR #204962)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 20 23:41:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-ir

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>

There are a few folds which don't depend on the offset of the alignment, but are nevertheless guarded on whether the offset is known. Run these folds unconditionally instead.


---
Full diff: https://github.com/llvm/llvm-project/pull/204962.diff


5 Files Affected:

- (modified) llvm/include/llvm/IR/BundleAttributes.h (+1) 
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+1-1) 
- (modified) llvm/lib/IR/BundleAttributes.cpp (+4-2) 
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+6-3) 
- (modified) llvm/test/Transforms/InstCombine/assume.ll (+26) 


``````````diff
diff --git a/llvm/include/llvm/IR/BundleAttributes.h b/llvm/include/llvm/IR/BundleAttributes.h
index a456be4aa7a9a..dd43d4ed276ea 100644
--- a/llvm/include/llvm/IR/BundleAttributes.h
+++ b/llvm/include/llvm/IR/BundleAttributes.h
@@ -30,6 +30,7 @@ inline BundleAttr getBundleAttrFromOBU(OperandBundleUse OBU) {
 struct AssumeAlignInfo {
   const Use &Ptr;
   const Use &Alignment;
+  const Use *Offset;
   std::optional<uint64_t> AlignmentVal;
   std::optional<uint64_t> OffsetVal;
 };
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9334551005224..70345319ed57d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1075,7 +1075,7 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
     if (Elem.Index != AssumptionCache::ExprResultIdx) {
       if (auto OBU = I->getOperandBundleAt(Elem.Index);
           getBundleAttrFromOBU(OBU) == BundleAttr::Align) {
-        auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
+        auto [Ptr, _, _2, Alignment, Offset] = getAssumeAlignInfo(OBU);
         if (Ptr == V && Alignment && Offset && isPowerOf2_64(*Alignment) &&
             isValidAssumeForContext(I, Q)) {
           Known.Zero |= (*Alignment - 1) & ~*Offset;
diff --git a/llvm/lib/IR/BundleAttributes.cpp b/llvm/lib/IR/BundleAttributes.cpp
index 2beb57c6dd710..4a6ed18714c2c 100644
--- a/llvm/lib/IR/BundleAttributes.cpp
+++ b/llvm/lib/IR/BundleAttributes.cpp
@@ -39,10 +39,12 @@ BundleAttr llvm::getBundleAttrFromID(uint32_t ID) {
 AssumeAlignInfo llvm::getAssumeAlignInfo(OperandBundleUse OBU) {
   assert(OBU.getTagID() == LLVMContext::OB_Align && OBU.Inputs.size() >= 2 &&
          OBU.Inputs.size() <= 3);
-  AssumeAlignInfo Ret{OBU.Inputs[0], OBU.Inputs[1], std::nullopt, std::nullopt};
+  AssumeAlignInfo Ret{OBU.Inputs[0], OBU.Inputs[1], nullptr, std::nullopt,
+                      std::nullopt};
   if (auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]))
     Ret.AlignmentVal = Align->getZExtValue();
   if (OBU.Inputs.size() == 3) {
+    Ret.Offset = &OBU.Inputs[2];
     if (auto *Offset = dyn_cast<ConstantInt>(OBU.Inputs[2]))
       Ret.OffsetVal = Offset->getZExtValue();
   } else {
@@ -83,7 +85,7 @@ bool llvm::assumeBundleImpliesNonNull(const Value *Val, const Function *Context,
                                       OperandBundleUse OBU) {
   switch (getBundleAttrFromOBU(OBU)) {
   case BundleAttr::Align: {
-    auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
+    auto [Ptr, _, _2, Alignment, Offset] = getAssumeAlignInfo(OBU);
     return Ptr == Val && Alignment && Offset && isPowerOf2_64(*Alignment) &&
            *Offset % *Alignment != 0;
   }
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 6992602f54fe9..ce9e4b836a56e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3701,9 +3701,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         llvm_unreachable("Unexpected Attribute");
       case BundleAttr::Align: {
         // Try to remove redundant alignment assumptions.
-        auto [Ptr, _, Alignment, Offset] = getAssumeAlignInfo(OBU);
+        auto [Ptr, _, OffsetPtr, Alignment, Offset] = getAssumeAlignInfo(OBU);
 
-        if (!Alignment || !Offset)
+        if (!Alignment)
           break;
 
         // Remove align 1 and non-power-of-two bundles; they don't add any
@@ -3716,10 +3716,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
             GEP->getMaxPreservedAlignment(getDataLayout()) >= *Alignment) {
           Builder.CreateAlignmentAssumption(
               getDataLayout(), GEP->getPointerOperand(), *Alignment,
-              *Offset == 0 ? nullptr : Builder.getInt64(*Offset));
+              OffsetPtr ? const_cast<Value *>(OffsetPtr->get()) : nullptr);
           return RemoveBundle();
         }
 
+        if (!Offset)
+          break;
+
         Value *BasePtr;
         const APInt *PtrOffset;
         if (match(Ptr.get(), m_PtrAdd(m_Value(BasePtr), m_APInt(PtrOffset)))) {
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index 2d4d51b8bbe4b..69220811ac206 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -199,6 +199,16 @@ define void @align_on_gep_keeping_alignment(ptr %ptr, i64 %offset) {
   ret void
 }
 
+define void @align_on_gep_keeping_alignment_variable_offset(ptr %ptr, i64 %offset, i64 %offset2) {
+; CHECK-LABEL: @align_on_gep_keeping_alignment_variable_offset(
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 8, i64 [[OFFSET2:%.*]]) ]
+; CHECK-NEXT:    ret void
+;
+  %ptr2 = getelementptr [8 x i8], ptr %ptr, i64 %offset
+  call void @llvm.assume(i1 true) [ "align"(ptr %ptr2, i64 8, i64 %offset2) ]
+  ret void
+}
+
 define void @align_on_gep_not_keeping_alignment(ptr %ptr, i64 %offset) {
 ; CHECK-LABEL: @align_on_gep_not_keeping_alignment(
 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr [4 x i8], ptr [[PTR:%.*]], i64 [[OFFSET:%.*]]
@@ -242,6 +252,22 @@ define void @non_power_of_two_align(ptr %ptr) {
   ret void
 }
 
+define void @non_power_of_two_align_variable_offset(ptr %ptr, i64 %i) {
+; CHECK-LABEL: @non_power_of_two_align_variable_offset(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 3, i64 %i) ]
+  ret void
+}
+
+define void @align_1_variable_offset(ptr %ptr, i64 %i) {
+; CHECK-LABEL: @align_1_variable_offset(
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 1, i64 %i) ]
+  ret void
+}
+
 ; Same check as in @foo1, but make sure it works if the assume is first too.
 
 define i32 @foo2(ptr %a) #0 {

``````````

</details>


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


More information about the llvm-commits mailing list