[llvm] [SimplifyCFG] Sink stores and loads with differing alignments (PR #215858)

Sayan Sivakumaran via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 18:30:04 PDT 2026


https://github.com/sivakusayan updated https://github.com/llvm/llvm-project/pull/215858

>From 3b14ce51426edca59299ea299e3efb6c1f88b8cf Mon Sep 17 00:00:00 2001
From: Sayan Sivakumaran <sivakusayan at gmail.com>
Date: Sun, 23 Aug 2026 20:16:03 -0500
Subject: [PATCH 1/2] Pre-commit tests

---
 .../SimplifyCFG/X86/sink-common-code.ll       | 56 +++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll b/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
index 8daa2334a4a68..1bf9d5d1c3fdb 100644
--- a/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
+++ b/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
@@ -2177,6 +2177,62 @@ join:
   ret i32 %phi
 }
 
+define void @store_different_alignments(i1 %c, ptr %p1, ptr %p2) {
+; CHECK-LABEL: @store_different_alignments(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF1:%.*]], label [[IF2:%.*]]
+; CHECK:       if1:
+; CHECK-NEXT:    store i8 0, ptr [[P1:%.*]], align 2
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       if2:
+; CHECK-NEXT:    store i8 0, ptr [[P2:%.*]], align 1
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %c, label %if1, label %if2
+
+if1:
+  store i8 0, ptr %p1, align 2
+  br label %end
+
+if2:
+  store i8 0, ptr %p2, align 1
+  br label %end
+
+end:
+  ret void
+}
+
+define void @store_different_alignments_incompatible_attributes(i1 %c, ptr %p1, ptr %p2) {
+; CHECK-LABEL: @store_different_alignments_incompatible_attributes(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF1:%.*]], label [[IF2:%.*]]
+; CHECK:       if1:
+; CHECK-NEXT:    store volatile i8 0, ptr [[P1:%.*]], align 2
+; CHECK-NEXT:    br label [[END:%.*]]
+; CHECK:       if2:
+; CHECK-NEXT:    store i8 0, ptr [[P2:%.*]], align 1
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %c, label %if1, label %if2
+
+if1:
+  store volatile i8 0, ptr %p1, align 2
+  br label %end
+
+if2:
+  store i8 0, ptr %p2, align 1
+  br label %end
+
+end:
+  ret void
+}
+
 declare void @dummy()
 declare void @use.ptr(ptr)
 

>From 7abee3d88c43713f64b6a2306b7afb382b005b09 Mon Sep 17 00:00:00 2001
From: Sayan Sivakumaran <sivakusayan at gmail.com>
Date: Sun, 23 Aug 2026 20:29:49 -0500
Subject: [PATCH 2/2] [SimplifyCFG] Enable sinking instructions with differing
 alignments

---
 llvm/include/llvm/IR/Instruction.h             |  7 +++++++
 llvm/lib/IR/Instruction.cpp                    | 18 ++++++++++++++++++
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp      |  5 +++--
 .../SimplifyCFG/X86/sink-common-code.ll        | 10 ++--------
 4 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 13646ec66d6b3..c6c9e0eb0e637 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -724,6 +724,13 @@ class Instruction : public User,
   /// V and this instruction.
   LLVM_ABI void andIRFlags(const Value *V);
 
+  /// Restricts this instruction's attributes to those which are shared
+  /// with I. This will essentially:
+  ///  1) Do a logical 'and' of this instruction's flags with I's flags.
+  ///  2) Find a common alignment with I, if both instructions support a notion
+  ///  of alignment.
+  LLVM_ABI void intersectIRAttributes(const Instruction *I);
+
   /// Merge 2 debug locations and apply it to the Instruction. If the
   /// instruction is a CallIns, we need to traverse the inline chain to find
   /// the common scope. This is not efficient for N-way merging as each time
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 099a54e684c96..84c6ac0d20dfb 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -813,6 +813,24 @@ void Instruction::andIRFlags(const Value *V) {
       DestICmp->setSameSign(DestICmp->hasSameSign() && SrcICmp->hasSameSign());
 }
 
+void Instruction::intersectIRAttributes(const Instruction *I) {
+  // TODO: Should we intersect metadata here too?
+  andIRFlags(I);
+
+  auto IsLoadOrStore = [](const Instruction *I) {
+    return isa<LoadInst>(I) || isa<StoreInst>(I);
+  };
+  if (IsLoadOrStore(I) && IsLoadOrStore(this)) {
+    Align Common =
+        std::min(getLoadStoreAlignment(this), getLoadStoreAlignment(I));
+    assert(isAligned(Common, getLoadStoreAlignment(this).value()) &&
+           isAligned(Common, getLoadStoreAlignment(I).value()) &&
+           "Common alignment doesn't satisfy alignment constraints?");
+
+    setLoadStoreAlignment(this, Common);
+  }
+}
+
 const char *Instruction::getOpcodeName(unsigned OpCode) {
   switch (OpCode) {
   // Terminators
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 089892dc573f3..e29a682154e69 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2248,7 +2248,8 @@ static bool canSinkInstructions(
   const Instruction *I0 = Insts.front();
   const auto I0MMRA = MMRAMetadata(*I0);
   for (auto *I : Insts) {
-    if (!I->isSameOperationAs(I0, Instruction::CompareUsingIntersectedAttrs))
+    if (!I->isSameOperationAs(I0, Instruction::CompareUsingIntersectedAttrs |
+                                      Instruction::CompareIgnoringAlignment))
       return false;
 
     // Treat MMRAs conservatively. This pass can be quite aggressive and
@@ -2379,7 +2380,7 @@ static void sinkLastInstruction(ArrayRef<BasicBlock*> Blocks) {
       // instead of using complex API for N-way merge.
       I0->applyMergedLocation(I0->getDebugLoc(), I->getDebugLoc());
       combineMetadataForCSE(I0, I, true);
-      I0->andIRFlags(I);
+      I0->intersectIRAttributes(I);
       if (auto *CB = dyn_cast<CallBase>(I0)) {
         bool Success = CB->tryIntersectAttributes(cast<CallBase>(I));
         assert(Success && "We should not be trying to sink callbases "
diff --git a/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll b/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
index 1bf9d5d1c3fdb..e9d362f2d8538 100644
--- a/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
+++ b/llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll
@@ -2180,14 +2180,8 @@ join:
 define void @store_different_alignments(i1 %c, ptr %p1, ptr %p2) {
 ; CHECK-LABEL: @store_different_alignments(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF1:%.*]], label [[IF2:%.*]]
-; CHECK:       if1:
-; CHECK-NEXT:    store i8 0, ptr [[P1:%.*]], align 2
-; CHECK-NEXT:    br label [[END:%.*]]
-; CHECK:       if2:
-; CHECK-NEXT:    store i8 0, ptr [[P2:%.*]], align 1
-; CHECK-NEXT:    br label [[END]]
-; CHECK:       end:
+; CHECK-NEXT:    [[P2:%.*]] = select i1 [[C:%.*]], ptr [[P1:%.*]], ptr [[P3:%.*]]
+; CHECK-NEXT:    store i8 0, ptr [[P2]], align 1
 ; CHECK-NEXT:    ret void
 ;
 entry:



More information about the llvm-commits mailing list