[llvm] [InstCombine] Fold align assume into load's !align metadata if possible. (PR #123247)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 26 07:27:21 PDT 2025


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/123247

>From 524739ea7672c2d6f86e6da4e5b4bf86b15a6a54 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 17 Sep 2024 10:50:09 +0100
Subject: [PATCH 01/12] [InstCombine] Fold align assume into load's !align
 metadata if possible.

If an alignment assumption is valid in the context of a corresponding
load of the pointer the assumption applies to, the assumption can be
replaced !align metadata on the load.

The benefits of folding it into !align are that existing code makes
better use of !align and it allows removing the now-redundant call
instructions.
---
 .../InstCombine/InstCombineCalls.cpp          | 25 ++++++++++++++++---
 .../Transforms/InstCombine/assume-align.ll    |  7 +++---
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 61011d55227e7..596de10e20b6d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3076,12 +3076,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // TODO: apply range metadata for range check patterns?
     }
 
-    // Separate storage assumptions apply to the underlying allocations, not any
-    // particular pointer within them. When evaluating the hints for AA purposes
-    // we getUnderlyingObject them; by precomputing the answers here we can
-    // avoid having to do so repeatedly there.
     for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) {
       OperandBundleUse OBU = II->getOperandBundleAt(Idx);
+
+      // Separate storage assumptions apply to the underlying allocations, not any
+      // particular pointer within them. When evaluating the hints for AA purposes
+      // we getUnderlyingObject them; by precomputing the answers here we can
+      // avoid having to do so repeatedly there.
       if (OBU.getTagName() == "separate_storage") {
         assert(OBU.Inputs.size() == 2);
         auto MaybeSimplifyHint = [&](const Use &U) {
@@ -3095,6 +3096,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         MaybeSimplifyHint(OBU.Inputs[0]);
         MaybeSimplifyHint(OBU.Inputs[1]);
       }
+
+      // Try to fold alignment assumption into a load's !align metadata, if the assumption is valid in the load's context.
+      if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
+        auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);
+        if (!LI || !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
+          continue;
+        auto *Align = cast<ConstantInt>(OBU.Inputs[1]);
+        if (!isPowerOf2_64(Align->getZExtValue()))
+          continue;
+        LI->setMetadata(LLVMContext::MD_align,
+                        MDNode::get(II->getContext(),
+                                    ValueAsMetadata::getConstant(
+                                        Align)));
+        auto *New = CallBase::removeOperandBundle(II, OBU.getTagID());
+        return New;
+      }
     }
 
     // Convert nonnull assume like:
diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index 2b8ca5d25fd1a..65256377696a5 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -123,11 +123,9 @@ define i8 @assume_align_non_pow2(ptr %p) {
   ret i8 %v
 }
 
-; TODO: Can fold alignment assumption into !align metadata on load.
 define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
 ; CHECK-LABEL: @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
   %p2 = load ptr, ptr %p
@@ -171,3 +169,6 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
   call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 0) ]
   ret ptr %p2
 }
+;.
+; CHECK: [[META0]] = !{i64 8}
+;.

>From e33e425453617cfe1685319608d08140f2921fb7 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 17 Sep 2024 12:09:07 +0100
Subject: [PATCH 02/12] !fix formatting.

---
 .../InstCombine/InstCombineCalls.cpp          | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 596de10e20b6d..bff44e11c3ab8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3079,10 +3079,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) {
       OperandBundleUse OBU = II->getOperandBundleAt(Idx);
 
-      // Separate storage assumptions apply to the underlying allocations, not any
-      // particular pointer within them. When evaluating the hints for AA purposes
-      // we getUnderlyingObject them; by precomputing the answers here we can
-      // avoid having to do so repeatedly there.
+      // Separate storage assumptions apply to the underlying allocations, not
+      // any particular pointer within them. When evaluating the hints for AA
+      // purposes we getUnderlyingObject them; by precomputing the answers here
+      // we can avoid having to do so repeatedly there.
       if (OBU.getTagName() == "separate_storage") {
         assert(OBU.Inputs.size() == 2);
         auto MaybeSimplifyHint = [&](const Use &U) {
@@ -3097,18 +3097,19 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         MaybeSimplifyHint(OBU.Inputs[1]);
       }
 
-      // Try to fold alignment assumption into a load's !align metadata, if the assumption is valid in the load's context.
+      // Try to fold alignment assumption into a load's !align metadata, if the
+      // assumption is valid in the load's context.
       if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
         auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);
-        if (!LI || !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
+        if (!LI ||
+            !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
           continue;
         auto *Align = cast<ConstantInt>(OBU.Inputs[1]);
         if (!isPowerOf2_64(Align->getZExtValue()))
           continue;
-        LI->setMetadata(LLVMContext::MD_align,
-                        MDNode::get(II->getContext(),
-                                    ValueAsMetadata::getConstant(
-                                        Align)));
+        LI->setMetadata(
+            LLVMContext::MD_align,
+            MDNode::get(II->getContext(), ValueAsMetadata::getConstant(Align)));
         auto *New = CallBase::removeOperandBundle(II, OBU.getTagID());
         return New;
       }

>From b050881d71b224b5d0a074dda3998cd1255d1c29 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 17 Sep 2024 13:04:56 +0100
Subject: [PATCH 03/12] !fixup check alignment is ConstantInt.

---
 .../lib/Transforms/InstCombine/InstCombineCalls.cpp |  4 ++--
 llvm/test/Transforms/InstCombine/assume-align.ll    | 13 +++++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index bff44e11c3ab8..66ceda9aa4264 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3104,8 +3104,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         if (!LI ||
             !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
           continue;
-        auto *Align = cast<ConstantInt>(OBU.Inputs[1]);
-        if (!isPowerOf2_64(Align->getZExtValue()))
+        auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]);
+        if (!Align || !isPowerOf2_64(Align->getZExtValue()))
           continue;
         LI->setMetadata(
             LLVMContext::MD_align,
diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index 65256377696a5..9d9f18068bb3e 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -169,6 +169,19 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
   call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 0) ]
   ret ptr %p2
 }
+
+; !align must have a constant integer alignment.
+define ptr @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(ptr %p, i64 %align) {
+; CHECK-LABEL: @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 [[ALIGN:%.*]]) ]
+; CHECK-NEXT:    ret ptr [[P2]]
+;
+  %p2 = load ptr, ptr %p
+  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 %align) ]
+  ret ptr %p2
+}
+
 ;.
 ; CHECK: [[META0]] = !{i64 8}
 ;.

>From 6f514d0f7cbbd3431f279a893497601926afdd2d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 17 Sep 2024 13:10:16 +0100
Subject: [PATCH 04/12] !fixup check align type size.

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp |  2 +-
 llvm/test/Transforms/InstCombine/assume-align.ll     | 11 +++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 66ceda9aa4264..40da0288eccb1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3105,7 +3105,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
             !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
           continue;
         auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]);
-        if (!Align || !isPowerOf2_64(Align->getZExtValue()))
+        if (!Align || !isPowerOf2_64(Align->getZExtValue()) || Align->getType()->getScalarSizeInBits() != 64)
           continue;
         LI->setMetadata(
             LLVMContext::MD_align,
diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index 9d9f18068bb3e..c80275b6e4d78 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -133,6 +133,17 @@ define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p)
   ret ptr %p2
 }
 
+define ptr @dont_fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
+; CHECK-LABEL: @dont_fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
+; CHECK-NEXT:    ret ptr [[P2]]
+;
+  %p2 = load ptr, ptr %p
+  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 8) ]
+  ret ptr %p2
+}
+
 define ptr @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(ptr %p) {
 ; CHECK-LABEL: @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(
 ; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8

>From 5c1a12ddce8321b101c172f2e5958de3fda0f50f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 17 Sep 2024 13:17:56 +0100
Subject: [PATCH 05/12] !fixup use getKnowledgeFromBundle

---
 .../lib/Transforms/InstCombine/InstCombineCalls.cpp | 13 +++++++++----
 llvm/test/Transforms/InstCombine/assume-align.ll    |  9 ++++-----
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 40da0288eccb1..e9e476b10ff34 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3100,16 +3100,21 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // Try to fold alignment assumption into a load's !align metadata, if the
       // assumption is valid in the load's context.
       if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
+        RetainedKnowledge RK = getKnowledgeFromBundle(
+            *cast<AssumeInst>(II), II->bundle_op_info_begin()[Idx]);
+        if (!RK || RK.AttrKind != Attribute::Alignment ||
+            !isPowerOf2_64(RK.ArgValue))
+          continue;
+
         auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);
         if (!LI ||
             !isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true))
           continue;
-        auto *Align = dyn_cast<ConstantInt>(OBU.Inputs[1]);
-        if (!Align || !isPowerOf2_64(Align->getZExtValue()) || Align->getType()->getScalarSizeInBits() != 64)
-          continue;
+
         LI->setMetadata(
             LLVMContext::MD_align,
-            MDNode::get(II->getContext(), ValueAsMetadata::getConstant(Align)));
+            MDNode::get(II->getContext(), ValueAsMetadata::getConstant(
+                                              Builder.getInt64(RK.ArgValue))));
         auto *New = CallBase::removeOperandBundle(II, OBU.getTagID());
         return New;
       }
diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index c80275b6e4d78..a434bb9a24770 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -133,10 +133,9 @@ define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p)
   ret ptr %p2
 }
 
-define ptr @dont_fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
+define ptr @fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
 ; CHECK-LABEL: @dont_fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]]
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
   %p2 = load ptr, ptr %p
@@ -184,8 +183,7 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
 ; !align must have a constant integer alignment.
 define ptr @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(ptr %p, i64 %align) {
 ; CHECK-LABEL: @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 [[ALIGN:%.*]]) ]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META1:![0-9]+]]
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
   %p2 = load ptr, ptr %p
@@ -195,4 +193,5 @@ define ptr @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_met
 
 ;.
 ; CHECK: [[META0]] = !{i64 8}
+; CHECK: [[META1]] = !{i64 1}
 ;.

>From 415a83ad0d4e495e1e92a022d782e58eb463a40e Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 18 Sep 2024 11:37:09 +0100
Subject: [PATCH 06/12] !fixup update test check

---
 llvm/test/Transforms/InstCombine/assume-align.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index a434bb9a24770..7020e5920f328 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -134,7 +134,7 @@ define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p)
 }
 
 define ptr @fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
-; CHECK-LABEL: @dont_fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(
+; CHECK-LABEL: @fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(
 ; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]]
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;

>From ca75fc206efa45fca3e631c0c503403f04f0c9f4 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 18 Sep 2024 13:38:52 +0100
Subject: [PATCH 07/12] [EarlyCSE] Rematerialize alignment assumption.

---
 llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index cf11f5bc885a7..b6a6806707091 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -31,6 +31,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
@@ -1588,6 +1589,14 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
         if (InVal.IsLoad)
           if (auto *I = dyn_cast<Instruction>(Op))
             combineMetadataForCSE(I, &Inst, false);
+        if (auto *AlignMD = Inst.getMetadata(LLVMContext::MD_align)) {
+          auto *A = mdconst::extract<ConstantInt>(AlignMD->getOperand(0));
+          if (Op->getPointerAlignment(SQ.DL).value() % A->getZExtValue() != 0) {
+            IRBuilder B(&Inst);
+            B.CreateAlignmentAssumption(SQ.DL, Op, A);
+          }
+        }
+
         if (!Inst.use_empty())
           Inst.replaceAllUsesWith(Op);
         salvageKnowledge(&Inst, &AC);

>From 7cf3da30158d21ccb350a20947984fcde1475ed5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 25 Sep 2025 15:50:19 +0100
Subject: [PATCH 08/12] !fixup test

---
 llvm/test/Transforms/InstCombine/assume-align.ll | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index c64628070f2f9..b2595ed32aee0 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -182,7 +182,7 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
 
 define ptr @redundant_assume_align_1(ptr %p) {
 ; CHECK-LABEL: @redundant_assume_align_1(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META1:![0-9]+]]
 ; CHECK-NEXT:    call void @foo(ptr [[P2]])
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
@@ -195,7 +195,7 @@ define ptr @redundant_assume_align_1(ptr %p) {
 
 define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
 ; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]]
 ; CHECK-NEXT:    call void @foo(ptr [[P2]])
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
@@ -207,8 +207,7 @@ define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
 
 define ptr @assume_align_16_via_align_metadata(ptr %p) {
 ; CHECK-LABEL: @assume_align_16_via_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 16) ]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META2:![0-9]+]]
 ; CHECK-NEXT:    call void @foo(ptr [[P2]])
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
@@ -273,6 +272,7 @@ define ptr @assume_load_pointer_result(ptr %p, i64 %align) {
 ; CHECK-LABEL: @assume_load_pointer_result(
 ; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 [[ALIGN:%.*]]) ]
+; CHECK-NEXT:    ret ptr [[P2]]
 ;
   %p2 = load ptr, ptr %p
   call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 %align) ]
@@ -281,4 +281,6 @@ define ptr @assume_load_pointer_result(ptr %p, i64 %align) {
 
 ;.
 ; CHECK: [[META0]] = !{i64 8}
+; CHECK: [[META1]] = !{i64 1}
+; CHECK: [[META2]] = !{i64 16}
 ;.

>From 53430a6f8ae442aef50babf49687300f449eed3a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 25 Sep 2025 18:01:47 +0100
Subject: [PATCH 09/12] !fixup move code

---
 .../InstCombine/InstCombineCalls.cpp          | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index f164684ee6350..3b3ff3317e360 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3419,6 +3419,15 @@ 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.
+        KnownBits Known = computeKnownBits(RK.WasOn, /*CtxI=*/nullptr);
+        unsigned TZ = std::min(Known.countMinTrailingZeros(),
+                               Value::MaxAlignmentExponent);
+        if ((1ULL << TZ) > -RK.ArgValue)
+          return CallBase::removeOperandBundle(II, OBU.getTagID());
+
         auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);
         if (LI  &&
             isValidAssumeForContext(II, LI, &DT, /*AllowEphemerals=*/true)) {
@@ -3428,16 +3437,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                               Builder.getInt64(RK.ArgValue))));
         return CallBase::removeOperandBundle(II, OBU.getTagID());
         }
-
-        // 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)
-          continue;
-        return CallBase::removeOperandBundle(II, OBU.getTagID());
       }
     }
 

>From 6abd77d53dcde47b9926193826c570bbc54ed091 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 25 Sep 2025 18:04:43 +0100
Subject: [PATCH 10/12] !fixup update test after merge

---
 llvm/test/Transforms/InstCombine/assume-align.ll | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll
index 9ec655d18bee1..6a036b29f55df 100644
--- a/llvm/test/Transforms/InstCombine/assume-align.ll
+++ b/llvm/test/Transforms/InstCombine/assume-align.ll
@@ -182,7 +182,7 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
 
 define ptr @redundant_assume_align_1(ptr %p) {
 ; CHECK-LABEL: @redundant_assume_align_1(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META1:![0-9]+]]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
 ; CHECK-NEXT:    call void @foo(ptr [[P2]])
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
@@ -207,7 +207,7 @@ define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
 
 define ptr @assume_align_16_via_align_metadata(ptr %p) {
 ; CHECK-LABEL: @assume_align_16_via_align_metadata(
-; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META2:![0-9]+]]
+; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META1:![0-9]+]]
 ; CHECK-NEXT:    call void @foo(ptr [[P2]])
 ; CHECK-NEXT:    ret ptr [[P2]]
 ;
@@ -280,6 +280,5 @@ define ptr @assume_load_pointer_result(ptr %p, i64 %align) {
 
 ;.
 ; CHECK: [[META0]] = !{i64 8}
-; CHECK: [[META1]] = !{i64 1}
-; CHECK: [[META2]] = !{i64 16}
+; CHECK: [[META1]] = !{i64 16}
 ;.

>From d56e76706e8e04a6a00ac351a32943b808c03f8a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 26 Sep 2025 10:37:15 +0100
Subject: [PATCH 11/12] Undo EarlyCSE

---
 llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 67f96d09a7c23..0f8cc6ca6ed21 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -31,7 +31,6 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
-#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
@@ -1601,14 +1600,6 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
         if (InVal.IsLoad)
           if (auto *I = dyn_cast<Instruction>(Op))
             combineMetadataForCSE(I, &Inst, false);
-        if (auto *AlignMD = Inst.getMetadata(LLVMContext::MD_align)) {
-          auto *A = mdconst::extract<ConstantInt>(AlignMD->getOperand(0));
-          if (Op->getPointerAlignment(SQ.DL).value() % A->getZExtValue() != 0) {
-            IRBuilder B(&Inst);
-            B.CreateAlignmentAssumption(SQ.DL, Op, A);
-          }
-        }
-
         if (!Inst.use_empty())
           Inst.replaceAllUsesWith(Op);
         salvageKnowledge(&Inst, &AC);

>From cfee16dea8ca9e69abf3ed6d5f8015aa0629e63d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 26 Sep 2025 15:26:44 +0100
Subject: [PATCH 12/12] !fixup

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 0005895d7d285..11401b23e2cbd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -3429,7 +3429,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         KnownBits Known = computeKnownBits(RK.WasOn, /*CtxI=*/nullptr);
         unsigned TZ = std::min(Known.countMinTrailingZeros(),
                                Value::MaxAlignmentExponent);
-        if ((1ULL << TZ) > -RK.ArgValue)
+        if ((1ULL << TZ) > RK.ArgValue)
           return CallBase::removeOperandBundle(II, OBU.getTagID());
 
         auto *LI = dyn_cast<LoadInst>(OBU.Inputs[0]);



More information about the llvm-commits mailing list