[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