[llvm] [InstCombine] Drop alignment assumptions more aggressively (PR #196060)

Nikolas Klauser via llvm-commits llvm-commits at lists.llvm.org
Thu May 7 00:03:31 PDT 2026


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/196060

>From 710eeaad94e35fbcfd5382957629192c601eed89 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 6 May 2026 15:09:45 +0200
Subject: [PATCH 1/4] [InstCombine] Drop alignment assumptions more
 aggressively

---
 llvm/include/llvm/Analysis/SimplifyQuery.h          |  6 ++++++
 .../llvm/Transforms/InstCombine/InstCombiner.h      |  6 ++++++
 llvm/lib/Analysis/ValueTracking.cpp                 |  5 +----
 .../lib/Transforms/InstCombine/InstCombineCalls.cpp |  7 +++----
 llvm/test/Transforms/InstCombine/assume.ll          | 13 +++++++++++++
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/Analysis/SimplifyQuery.h b/llvm/include/llvm/Analysis/SimplifyQuery.h
index d1d34f22a2fc5..46baca3ece7cc 100644
--- a/llvm/include/llvm/Analysis/SimplifyQuery.h
+++ b/llvm/include/llvm/Analysis/SimplifyQuery.h
@@ -86,6 +86,7 @@ struct SimplifyQuery {
   /// possible values for uses of undef. If it is false, simplifications are not
   /// allowed to assume a particular value for a use of undef for example.
   bool CanUseUndef = true;
+  bool AllowEphemerals = true;
 
   SimplifyQuery(const DataLayout &DL, const Instruction *CXTI = nullptr)
       : DL(DL), CxtI(CXTI) {}
@@ -115,6 +116,11 @@ struct SimplifyQuery {
     Copy.CanUseUndef = false;
     return Copy;
   }
+  SimplifyQuery allowEphemerals(bool AllowEphemerals) const {
+    SimplifyQuery Copy(*this);
+    Copy.AllowEphemerals = AllowEphemerals;
+    return Copy;
+  }
 
   /// If CanUseUndef is true, returns whether \p V is undef.
   /// Otherwise always return false.
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 5670d9b6f9f89..4791c016836e2 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -453,6 +453,12 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
     return llvm::computeKnownBits(V, SQ.getWithInstruction(CxtI), Depth);
   }
 
+  KnownBits computeKnownBits(const Value *V, const Instruction *CtxI,
+                             bool AllowEphemerals) const {
+    return llvm::computeKnownBits(
+        V, SQ.getWithInstruction(CtxI).allowEphemerals(AllowEphemerals));
+  }
+
   bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero = false,
                               const Instruction *CxtI = nullptr,
                               unsigned Depth = 0) {
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 40f1025fed4fb..afb65812f69e8 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1094,12 +1094,9 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
         continue;
       if (RetainedKnowledge RK = getKnowledgeFromBundle(
               *I, I->bundle_op_info_begin()[Elem.Index])) {
-        // Allow AllowEphemerals in isValidAssumeForContext, as the CxtI might
-        // be the producer of the pointer in the bundle. At the moment, align
-        // assumptions aren't optimized away.
         if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
             isPowerOf2_64(RK.ArgValue) &&
-            isValidAssumeForContext(I, Q.CxtI, Q.DT, /*AllowEphemerals*/ true))
+            isValidAssumeForContext(I, Q.CxtI, Q.DT, Q.AllowEphemerals))
           Known.Zero.setLowBits(Log2_64(RK.ArgValue));
       }
       continue;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index da258b3b34e27..e27492b1ea71f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3677,10 +3677,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         // Compute known bits for the pointer, passing nullptr as context to
         // avoid computeKnownBits using the assumption we are about to remove
         // for reasoning.
-        KnownBits Known = computeKnownBits(RK.WasOn, /*CtxI=*/nullptr);
-        unsigned TZ = std::min(Known.countMinTrailingZeros(),
-                               Value::MaxAlignmentExponent);
-        if ((1ULL << TZ) < RK.ArgValue)
+        KnownBits Known =
+            computeKnownBits(RK.WasOn, II, /*AllowEphemerals=*/false);
+        if ((1ULL << Known.countMinTrailingZeros()) < RK.ArgValue)
           continue;
         return CallBase::removeOperandBundle(II, OBU.getTagID());
       }
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index 6b43430229388..40fe2f5f46f1e 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -7,6 +7,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
 declare void @llvm.assume(i1) #1
+declare ptr @get_ptr()
 
 ; Check that the assume has not been removed:
 
@@ -80,6 +81,18 @@ entry:
   ret void
 }
 
+define void @redundant_align() {
+; CHECK-LABEL: @redundant_align(
+; CHECK-NEXT:    [[PTR:%.*]] = call ptr @get_ptr()
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 8) ]
+; CHECK-NEXT:    ret void
+;
+  %ptr = call ptr @get_ptr()
+  call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 8) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 8) ]
+  ret void
+}
+
 ; Same check as in @foo1, but make sure it works if the assume is first too.
 
 define i32 @foo2(ptr %a) #0 {

>From d9998f79c7699b1c63f7b401a20549234338f208 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 6 May 2026 19:08:32 +0200
Subject: [PATCH 2/4] Address comment

---
 llvm/include/llvm/Analysis/SimplifyQuery.h |  2 +-
 llvm/include/llvm/Analysis/ValueTracking.h |  5 +++++
 llvm/lib/Analysis/InstructionSimplify.cpp  |  2 +-
 llvm/lib/Analysis/ScalarEvolution.cpp      |  4 +++-
 llvm/lib/Analysis/ValueTracking.cpp        | 23 +++++++++++-----------
 5 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/Analysis/SimplifyQuery.h b/llvm/include/llvm/Analysis/SimplifyQuery.h
index 46baca3ece7cc..b81b1dae27471 100644
--- a/llvm/include/llvm/Analysis/SimplifyQuery.h
+++ b/llvm/include/llvm/Analysis/SimplifyQuery.h
@@ -86,7 +86,7 @@ struct SimplifyQuery {
   /// possible values for uses of undef. If it is false, simplifications are not
   /// allowed to assume a particular value for a use of undef for example.
   bool CanUseUndef = true;
-  bool AllowEphemerals = true;
+  bool AllowEphemerals = false;
 
   SimplifyQuery(const DataLayout &DL, const Instruction *CXTI = nullptr)
       : DL(DL), CxtI(CXTI) {}
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index ff2712efe1ef5..00469421d55b4 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -629,6 +629,11 @@ LLVM_ABI bool isValidAssumeForContext(const Instruction *I,
                                       const DominatorTree *DT = nullptr,
                                       bool AllowEphemerals = false);
 
+inline bool isValidAssumeForContext(const Instruction *I,
+                                    const SimplifyQuery &Q) {
+  return isValidAssumeForContext(I, Q.CxtI, Q.DT, Q.AllowEphemerals);
+}
+
 /// Returns true, if no instruction between \p Assume and \p CtxI may free
 /// memory and the function is marked as NoSync. The latter ensures the current
 /// function cannot arrange for another thread to free on its behalf.
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index af21e46563f94..2bd0eb269510f 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3784,7 +3784,7 @@ static Value *simplifyICmpWithDominatingAssume(CmpPredicate Predicate,
       CallInst *Assume = cast<CallInst>(AssumeVH);
       if (std::optional<bool> Imp = isImpliedCondition(
               Assume->getArgOperand(0), Predicate, LHS, RHS, Q.DL))
-        if (isValidAssumeForContext(Assume, Q.CxtI, Q.DT))
+        if (isValidAssumeForContext(Assume, Q))
           return ConstantInt::get(getCompareTy(LHS), *Imp);
     }
   }
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 74037b7274336..e15ed1591ed64 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6558,7 +6558,9 @@ APInt ScalarEvolution::getConstantMultipleImpl(const SCEV *S,
         CtxI = I;
     }
     unsigned Known =
-        computeKnownBits(U->getValue(), getDataLayout(), &AC, CtxI, &DT)
+        computeKnownBits(U->getValue(),
+                         SimplifyQuery(getDataLayout(), &DT, &AC, CtxI)
+                             .allowEphemerals(true))
             .countMinTrailingZeros();
     return GetShiftedByZeros(Known);
   }
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index afb65812f69e8..ed3476c6ad145 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -852,7 +852,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
 
           return false;
         }();
-        if (AssumeImpliesNonNull && isValidAssumeForContext(I, Q.CxtI, Q.DT))
+        if (AssumeImpliesNonNull && isValidAssumeForContext(I, Q))
           return true;
       }
       continue;
@@ -868,7 +868,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
     if (!match(I->getArgOperand(0), m_c_ICmp(Pred, m_V, m_Value(RHS))))
       continue;
 
-    if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
+    if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q))
       return true;
   }
 
@@ -1095,8 +1095,7 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
       if (RetainedKnowledge RK = getKnowledgeFromBundle(
               *I, I->bundle_op_info_begin()[Elem.Index])) {
         if (RK.WasOn == V && RK.AttrKind == Attribute::Alignment &&
-            isPowerOf2_64(RK.ArgValue) &&
-            isValidAssumeForContext(I, Q.CxtI, Q.DT, Q.AllowEphemerals))
+            isPowerOf2_64(RK.ArgValue) && isValidAssumeForContext(I, Q))
           Known.Zero.setLowBits(Log2_64(RK.ArgValue));
       }
       continue;
@@ -1108,14 +1107,14 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
 
     Value *Arg = I->getArgOperand(0);
 
-    if (Arg == V && isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+    if (Arg == V && isValidAssumeForContext(I, Q)) {
       assert(BitWidth == 1 && "assume operand is not i1?");
       (void)BitWidth;
       Known.setAllOnes();
       return;
     }
     if (match(Arg, m_Not(m_Specific(V))) &&
-        isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+        isValidAssumeForContext(I, Q)) {
       assert(BitWidth == 1 && "assume operand is not i1?");
       (void)BitWidth;
       Known.setAllZero();
@@ -1123,7 +1122,7 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
     }
     auto *Trunc = dyn_cast<TruncInst>(Arg);
     if (Trunc && Trunc->getOperand(0) == V &&
-        isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+        isValidAssumeForContext(I, Q)) {
       if (Trunc->hasNoUnsignedWrap()) {
         Known = KnownBits::makeConstant(APInt(BitWidth, 1));
         return;
@@ -1140,7 +1139,7 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
     if (!Cmp)
       continue;
 
-    if (!isValidAssumeForContext(I, Q.CxtI, Q.DT))
+    if (!isValidAssumeForContext(I, Q))
       continue;
 
     computeKnownBitsFromICmpCond(V, Cmp, Known, Q, /*Invert=*/false);
@@ -2666,7 +2665,7 @@ bool llvm::isKnownToBeAPowerOfTwo(const Value *V, bool OrZero,
       CallInst *I = cast<CallInst>(AssumeVH);
       if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, I->getArgOperand(0),
                                            /*CondIsTrue=*/true) &&
-          isValidAssumeForContext(I, Q.CxtI, Q.DT))
+          isValidAssumeForContext(I, Q))
         return true;
     }
   }
@@ -4114,7 +4113,7 @@ static bool isKnownNonEqualFromContext(const Value *V1, const Value *V2,
     if (isImpliedCondition(I->getArgOperand(0), ICmpInst::ICMP_NE, V1, V2, Q.DL,
                            /*LHSIsTrue=*/true, Depth)
             .value_or(false) &&
-        isValidAssumeForContext(I, Q.CxtI, Q.DT))
+        isValidAssumeForContext(I, Q))
       return true;
   }
 
@@ -4887,7 +4886,7 @@ static KnownFPClass computeKnownFPClassFromContext(const Value *V,
     assert(I->getIntrinsicID() == Intrinsic::assume &&
            "must be an assume intrinsic");
 
-    if (!isValidAssumeForContext(I, Q.CxtI, Q.DT))
+    if (!isValidAssumeForContext(I, Q))
       continue;
 
     computeKnownFPClassFromCond(V, I->getArgOperand(0),
@@ -10480,7 +10479,7 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
       assert(I->getIntrinsicID() == Intrinsic::assume &&
              "must be an assume intrinsic");
 
-      if (!isValidAssumeForContext(I, SQ.CxtI, SQ.DT))
+      if (!isValidAssumeForContext(I, SQ))
         continue;
       Value *Arg = I->getArgOperand(0);
       ICmpInst *Cmp = dyn_cast<ICmpInst>(Arg);

>From e60cfc34f6bd56a2e6b43834966773e1afece36c Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 6 May 2026 19:11:31 +0200
Subject: [PATCH 3/4] Refactor

---
 llvm/include/llvm/Transforms/InstCombine/InstCombiner.h | 6 ------
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp    | 5 ++---
 2 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 4791c016836e2..5670d9b6f9f89 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -453,12 +453,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
     return llvm::computeKnownBits(V, SQ.getWithInstruction(CxtI), Depth);
   }
 
-  KnownBits computeKnownBits(const Value *V, const Instruction *CtxI,
-                             bool AllowEphemerals) const {
-    return llvm::computeKnownBits(
-        V, SQ.getWithInstruction(CtxI).allowEphemerals(AllowEphemerals));
-  }
-
   bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero = false,
                               const Instruction *CxtI = nullptr,
                               unsigned Depth = 0) {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index e27492b1ea71f..91132d9d6ee02 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3677,9 +3677,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         // Compute known bits for the pointer, passing nullptr as context to
         // avoid computeKnownBits using the assumption we are about to remove
         // for reasoning.
-        KnownBits Known =
-            computeKnownBits(RK.WasOn, II, /*AllowEphemerals=*/false);
-        if ((1ULL << Known.countMinTrailingZeros()) < RK.ArgValue)
+        if ((1ULL << computeKnownBits(RK.WasOn, II).countMinTrailingZeros()) <
+            RK.ArgValue)
           continue;
         return CallBase::removeOperandBundle(II, OBU.getTagID());
       }

>From c3979eafc187ddba6c110133b7173217d54a3cb6 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 7 May 2026 09:03:15 +0200
Subject: [PATCH 4/4] Update comment

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 91132d9d6ee02..b4e2ebea4d196 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3674,9 +3674,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         if (!UO || isa<Argument>(UO))
           continue;
 
-        // Compute known bits for the pointer, passing nullptr as context to
-        // avoid computeKnownBits using the assumption we are about to remove
-        // for reasoning.
+        // Compute known bits for the pointer and drop the assume if the
+        // known alignment isn't increased by it.
         if ((1ULL << computeKnownBits(RK.WasOn, II).countMinTrailingZeros()) <
             RK.ArgValue)
           continue;



More information about the llvm-commits mailing list