[llvm] [LoopSink] check conflicting preheader memory access before sink (PR #195510)
Arda Serdar Pektezol via llvm-commits
llvm-commits at lists.llvm.org
Sun May 3 10:54:27 PDT 2026
https://github.com/pektezol updated https://github.com/llvm/llvm-project/pull/195510
>From 7d88effe5239e7ddab19885b577b12075d1a61d9 Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Sun, 3 May 2026 11:22:51 +0300
Subject: [PATCH 1/2] [LoopSink] check conflicting preheader memory access
before sink
---
llvm/lib/Transforms/Scalar/LoopSink.cpp | 21 +++++++++
.../test/Transforms/LICM/loopsink-pr191581.ll | 46 +++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 llvm/test/Transforms/LICM/loopsink-pr191581.ll
diff --git a/llvm/lib/Transforms/Scalar/LoopSink.cpp b/llvm/lib/Transforms/Scalar/LoopSink.cpp
index b9fde4c6a3b76..5c5c8deb0023a 100644
--- a/llvm/lib/Transforms/Scalar/LoopSink.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSink.cpp
@@ -179,6 +179,25 @@ findBBsToSinkInto(const Loop &L, const SmallPtrSetImpl<BasicBlock *> &UseBBs,
return BBsToSinkInto;
}
+/// Returns true when an \p I from the \p PreheaderBB has conflicting memory
+/// access over the later preheader instructions.
+static bool hasConflictingPreheaderMemoryAccess(Instruction &I, AAResults *AA,
+ BasicBlock *PreheaderBB) {
+ if (!I.mayReadOrWriteMemory())
+ return false;
+
+ for (Instruction &OtherI : make_range(I.getIterator(), PreheaderBB->end())) {
+ if (!OtherI.mayReadOrWriteMemory())
+ continue;
+ if (!I.mayWriteToMemory() && !OtherI.mayWriteToMemory())
+ continue;
+ if (!AA || isModOrRefSet(AA->getModRefInfo(&I, &OtherI)))
+ return true;
+ }
+
+ return false;
+}
+
// Sinks \p I from the loop \p L's preheader to its uses. Returns true if
// sinking is successful.
// \p LoopBlockNumber is used to sort the insertion blocks to ensure
@@ -343,6 +362,8 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI,
"Insts in a loop's preheader should have loop invariant operands!");
if (!canSinkOrHoistInst(I, &AA, &DT, &L, MSSAU, false, LICMFlags))
continue;
+ if (hasConflictingPreheaderMemoryAccess(I, &AA, Preheader))
+ continue;
if (sinkInstruction(L, I, ColdLoopBBs, LoopBlockNumber, LI, DT, BFI,
&MSSAU)) {
Changed = true;
diff --git a/llvm/test/Transforms/LICM/loopsink-pr191581.ll b/llvm/test/Transforms/LICM/loopsink-pr191581.ll
new file mode 100644
index 0000000000000..ab9ce4a4a6357
--- /dev/null
+++ b/llvm/test/Transforms/LICM/loopsink-pr191581.ll
@@ -0,0 +1,46 @@
+; RUN: opt -S -verify-memoryssa -passes=loop-sink < %s | FileCheck %s
+; RUN: opt -S -verify-memoryssa -aa-pipeline=basic-aa -passes=loop-sink < %s | FileCheck %s
+
+; Don't sink preheader call with memory access across a later
+; conflicting preheader store.
+; CHECK: @PR191581
+; CHECK-NEXT: preheader
+; CHECK-NEXT: %call = call i32 @n()
+; CHECK-NEXT: store i32 9, ptr @i
+
+
+ at i = global i32 0, align 4
+ at e = global i32 0, align 4
+
+define i32 @n() #0 {
+ store i32 1, ptr @i, align 4
+ ret i32 0
+}
+
+define void @PR191581() !prof !0 {
+preheader:
+ %call = call i32 @n()
+ store i32 9, ptr @i, align 4
+ br label %loop_header
+
+loop_header:
+ br i1 false, label %loop_inc, label %cold_body
+
+cold_body:
+ store i32 %call, ptr @e, align 4
+ br label %loop_inc
+
+loop_inc:
+ br i1 true, label %exit, label %loop_inc.loop_header_crit_edge, !prof !1
+
+loop_inc.loop_header_crit_edge:
+ br label %loop_header
+
+exit:
+ ret void
+}
+
+attributes #0 = { nounwind memory(write) }
+
+!0 = !{!"function_entry_count", i64 1}
+!1 = !{!"branch_weights", i32 -1, i32 0}
>From 2b94dec594a809a3141486b0b4c6154b640d72f0 Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Sun, 3 May 2026 20:54:06 +0300
Subject: [PATCH 2/2] [LoopSink] use BatchAAResults, update testcase checks
---
llvm/lib/Transforms/Scalar/LoopSink.cpp | 10 ++++--
.../test/Transforms/LICM/loopsink-pr191581.ll | 33 ++++++++++++++++---
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LoopSink.cpp b/llvm/lib/Transforms/Scalar/LoopSink.cpp
index 5c5c8deb0023a..e417cf632220a 100644
--- a/llvm/lib/Transforms/Scalar/LoopSink.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSink.cpp
@@ -181,7 +181,8 @@ findBBsToSinkInto(const Loop &L, const SmallPtrSetImpl<BasicBlock *> &UseBBs,
/// Returns true when an \p I from the \p PreheaderBB has conflicting memory
/// access over the later preheader instructions.
-static bool hasConflictingPreheaderMemoryAccess(Instruction &I, AAResults *AA,
+static bool hasConflictingPreheaderMemoryAccess(Instruction &I,
+ BatchAAResults &BAA,
BasicBlock *PreheaderBB) {
if (!I.mayReadOrWriteMemory())
return false;
@@ -191,7 +192,9 @@ static bool hasConflictingPreheaderMemoryAccess(Instruction &I, AAResults *AA,
continue;
if (!I.mayWriteToMemory() && !OtherI.mayWriteToMemory())
continue;
- if (!AA || isModOrRefSet(AA->getModRefInfo(&I, &OtherI)))
+
+ if (isModOrRefSet(
+ BAA.getModRefInfo(&OtherI, MemoryLocation::getOrNone(&I))))
return true;
}
@@ -362,7 +365,8 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI,
"Insts in a loop's preheader should have loop invariant operands!");
if (!canSinkOrHoistInst(I, &AA, &DT, &L, MSSAU, false, LICMFlags))
continue;
- if (hasConflictingPreheaderMemoryAccess(I, &AA, Preheader))
+ BatchAAResults BAA(AA);
+ if (hasConflictingPreheaderMemoryAccess(I, BAA, Preheader))
continue;
if (sinkInstruction(L, I, ColdLoopBBs, LoopBlockNumber, LI, DT, BFI,
&MSSAU)) {
diff --git a/llvm/test/Transforms/LICM/loopsink-pr191581.ll b/llvm/test/Transforms/LICM/loopsink-pr191581.ll
index ab9ce4a4a6357..f2a4e4a4d4cdf 100644
--- a/llvm/test/Transforms/LICM/loopsink-pr191581.ll
+++ b/llvm/test/Transforms/LICM/loopsink-pr191581.ll
@@ -1,23 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -verify-memoryssa -passes=loop-sink < %s | FileCheck %s
-; RUN: opt -S -verify-memoryssa -aa-pipeline=basic-aa -passes=loop-sink < %s | FileCheck %s
; Don't sink preheader call with memory access across a later
; conflicting preheader store.
-; CHECK: @PR191581
-; CHECK-NEXT: preheader
-; CHECK-NEXT: %call = call i32 @n()
-; CHECK-NEXT: store i32 9, ptr @i
@i = global i32 0, align 4
@e = global i32 0, align 4
define i32 @n() #0 {
+; CHECK-LABEL: define i32 @n(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: store i32 1, ptr @i, align 4
+; CHECK-NEXT: ret i32 0
+;
store i32 1, ptr @i, align 4
ret i32 0
}
define void @PR191581() !prof !0 {
+; CHECK-LABEL: define void @PR191581(
+; CHECK-SAME: ) !prof [[PROF0:![0-9]+]] {
+; CHECK-NEXT: [[PREHEADER:.*:]]
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @n()
+; CHECK-NEXT: store i32 9, ptr @i, align 4
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: br i1 false, label %[[LOOP_INC:.*]], label %[[COLD_BODY:.*]]
+; CHECK: [[COLD_BODY]]:
+; CHECK-NEXT: store i32 [[CALL]], ptr @e, align 4
+; CHECK-NEXT: br label %[[LOOP_INC]]
+; CHECK: [[LOOP_INC]]:
+; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP_INC_LOOP_HEADER_CRIT_EDGE:.*]], !prof [[PROF1:![0-9]+]]
+; CHECK: [[LOOP_INC_LOOP_HEADER_CRIT_EDGE]]:
+; CHECK-NEXT: br label %[[LOOP_HEADER]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
preheader:
%call = call i32 @n()
store i32 9, ptr @i, align 4
@@ -44,3 +63,7 @@ attributes #0 = { nounwind memory(write) }
!0 = !{!"function_entry_count", i64 1}
!1 = !{!"branch_weights", i32 -1, i32 0}
+;.
+; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1}
+; CHECK: [[PROF1]] = !{!"branch_weights", i32 -1, i32 0}
+;.
More information about the llvm-commits
mailing list