[llvm] [LICM] Improve LICM when calls only change Inaccessible memory (PR #169379)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 09:36:23 PDT 2026
https://github.com/CarolineConcatto updated https://github.com/llvm/llvm-project/pull/169379
>From 8c3dc41a3c07e379cf0c81c6c16fe7a6fcfe0138 Mon Sep 17 00:00:00 2001
From: CarolineConcatto <caroline.concatto at arm.com>
Date: Fri, 31 Oct 2025 16:26:46 +0000
Subject: [PATCH 1/2] [Draft][LICM] Modify noConflictingReadWrites behaviour
for calls
Change behaviour of noConflictingReadWrites for calls, it
allows to hoist calls from the loop when there is no conflict
with other memory Uses in the loop.
This patch implements two changes for the Memory access that are Use:
1) Alias-aware handling of call Uses:
Check if the memory Uses in the loop reads the same memory locations
as 'I' modifies(the call that can be hoisted). If not, 'I' can be hoisted.
There is a positive test called loop_alias tests for these changes.
2) Only consider Uses occurring before 'I'(the call that can be hoisted)
Only checks clobber for all memory uses in the loop that happens before 'I'.
This change is tested with hoist_until_I.
---
llvm/lib/Transforms/Scalar/LICM.cpp | 18 ++-
llvm/test/Transforms/LICM/call-hoisting.ll | 21 +--
.../LICM/hoist-inaccesiblemem-call.ll | 132 ++++++++++++++++++
3 files changed, 159 insertions(+), 12 deletions(-)
create mode 100644 llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 03edf9e3b0c1e..772604ff66635 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2315,6 +2315,15 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *IMD = MSSA->getMemoryAccess(I);
BatchAAResults BAA(*AA);
auto *Source = getClobberingMemoryAccess(*MSSA, BAA, Flags, IMD);
+ auto *CallI = dyn_cast<CallBase>(I);
+ auto doesItReadILoc = [&](Instruction *UserI) -> bool {
+ // Blocks if call reads the location I.
+ if (auto *OtherCB = dyn_cast_or_null<CallBase>(UserI)) {
+ ModRefInfo MRI = AA->getModRefInfo(CallI, OtherCB);
+ return isRefSet(MRI);
+ }
+ return true;
+ };
// Make sure there are no clobbers inside the loop.
if (!MSSA->isLiveOnEntryDef(Source) && CurLoop->contains(Source->getBlock()))
return false;
@@ -2328,11 +2337,14 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *Accesses = MSSA->getBlockAccesses(BB);
if (!Accesses)
continue;
+ bool FoundI = false;
for (const auto &MA : *Accesses)
if (const auto *MU = dyn_cast<MemoryUse>(&MA)) {
auto *MD = getClobberingMemoryAccess(*MSSA, BAA, Flags,
const_cast<MemoryUse *>(MU));
- if (!MSSA->isLiveOnEntryDef(MD) && CurLoop->contains(MD->getBlock()))
+ // Check clobbering only for Uses that happens before I
+ if (!MSSA->isLiveOnEntryDef(MD) && CurLoop->contains(MD->getBlock()) &&
+ !FoundI)
return false;
} else if (const auto *MD = dyn_cast<MemoryDef>(&MA)) {
if (auto *LI = dyn_cast<LoadInst>(MD->getMemoryInst())) {
@@ -2353,8 +2365,10 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *SCI = cast<CallInst>(I);
// If the instruction we are wanting to hoist is also a call
// instruction then we need not check mod/ref info with itself
- if (SCI == CI)
+ if (SCI == CI) {
+ FoundI = true;
continue;
+ }
ModRefInfo MRI = BAA.getModRefInfo(CI, SCI);
if (isModOrRefSet(MRI))
return false;
diff --git a/llvm/test/Transforms/LICM/call-hoisting.ll b/llvm/test/Transforms/LICM/call-hoisting.ll
index 1078c079dfa42..edc907d9e5a97 100644
--- a/llvm/test/Transforms/LICM/call-hoisting.ll
+++ b/llvm/test/Transforms/LICM/call-hoisting.ll
@@ -399,10 +399,10 @@ exit:
define void @neg_ref(ptr %loc) {
; CHECK-LABEL: define void @neg_ref(
; CHECK-SAME: ptr [[LOC:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
+; CHECK-NEXT: [[LOOP:.*]]:
+; CHECK-NEXT: br label %[[LOOP1:.*]]
+; CHECK: [[LOOP1]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[LOOP]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[LOC]], align 4
; CHECK-NEXT: [[EARLYCND:%.*]] = icmp eq i32 [[V]], 198
@@ -410,7 +410,7 @@ define void @neg_ref(ptr %loc) {
; CHECK: [[BACKEDGE]]:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
-; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT2:.*]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1]], label %[[EXIT2:.*]]
; CHECK: [[EXIT1]]:
; CHECK-NEXT: ret void
; CHECK: [[EXIT2]]:
@@ -536,14 +536,14 @@ exit:
define i32 @neg_not_argmemonly(ptr %loc, ptr %loc2) {
; CHECK-LABEL: define i32 @neg_not_argmemonly(
; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[LOOP:.*]]:
; CHECK-NEXT: call void @not_argmemonly(i32 0, ptr [[LOC]])
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[LOOP1:.*]]
+; CHECK: [[LOOP1]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[LOOP]] ], [ [[IV_NEXT:%.*]], %[[LOOP1]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
-; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[VAL_LE:%.*]] = call i32 @load(ptr [[LOC2]])
; CHECK-NEXT: ret i32 [[VAL_LE]]
@@ -620,3 +620,4 @@ exit:
ret void
}
+
diff --git a/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll b/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
new file mode 100644
index 0000000000000..d3ff60ef6ba1d
--- /dev/null
+++ b/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
@@ -0,0 +1,132 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,loop-mssa(licm)' < %s -S | FileCheck %s
+
+
+define dso_local i32 @loop_alias(i32 %x, ptr %a, ptr %b) #0{
+; CHECK-LABEL: define dso_local i32 @loop_alias(
+; CHECK-SAME: i32 [[X:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i64 1
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP:%.*]], %[[LOOP]] ], [ [[VAL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PHI]], i64 0
+; CHECK-NEXT: [[VAL2:%.*]] = call i32 @fn_args(ptr [[GEP2]])
+; CHECK-NEXT: [[GEP]] = getelementptr inbounds nuw i32, ptr [[PHI]], i64 0
+; CHECK-NEXT: [[ACC:%.*]] = add nuw nsw i32 [[VAL2]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ACC]], 10
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[AFTER_LOOP:.*]]
+; CHECK: [[AFTER_LOOP]]:
+; CHECK-NEXT: [[ACC_LCSSA:%.*]] = phi i32 [ [[ACC]], %[[LOOP]] ]
+; CHECK-NEXT: ret i32 [[ACC_LCSSA]]
+;
+entry:
+ %val = getelementptr inbounds nuw i32, ptr %a, i64 1
+ br label %loop
+loop:
+ %phi = phi ptr [ %gep, %loop ], [ %val, %entry ]
+ %44 = load i32, ptr %phi, align 16
+ %gep2 = getelementptr i8, ptr %phi, i64 0
+ %val2 = call i32 @fn_args(ptr %gep2)
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem()
+ %gep = getelementptr inbounds nuw i32, ptr %phi, i64 0
+ %acc = add nuw nsw i32 %val2, 1
+ %cmp = icmp ult i32 %acc, 10
+ br i1 %cmp, label %loop, label %after_loop
+after_loop:
+ ret i32 %acc
+}
+
+declare i32 @fn_args(ptr) nounwind willreturn
+memory(argmem: read)
+
+define void @hoist_untill_I(ptr noalias %loc, ptr noalias %loc2){
+; CHECK-LABEL: define void @hoist_untill_I(
+; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[LOC2:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[LOC2]], align 4
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: br label %[[FOR_BODY:.*]]
+; CHECK: [[FOR_COND_CLEANUP:.*:]]
+; CHECK-NEXT: ret void
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: store i32 [[VAL]], ptr [[LOC]], align 4
+; CHECK-NEXT: br label %[[FOR_BODY]]
+;
+entry:
+ br label %for.body
+for.cond.cleanup: ; preds = %for.body
+ ret void
+for.body:
+ %val = load i32, ptr %loc2
+ store i32 %val, ptr %loc
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem()
+ br label %for.body
+}
+
+
+define void @neg_hoist_untill_I(ptr noalias %loc, ptr noalias %loc2){
+; CHECK-LABEL: define void @neg_hoist_untill_I(
+; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[LOC2:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[LOC2]], align 4
+; CHECK-NEXT: br label %[[FOR_BODY:.*]]
+; CHECK: [[FOR_BODY]]:
+; CHECK-NEXT: store i32 [[VAL]], ptr [[LOC]], align 4
+; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: br label %[[FOR_BODY]]
+;
+entry:
+ br label %for.body
+for.body:
+ %val = load i32, ptr %loc2
+ store i32 %val, ptr %loc
+ call void @fn_read_inaccessible_mem()
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem()
+ br label %for.body
+}
+
+
+; Nothing should be hoisted from the loop because volatile
+; sets inaccessible memory to read write
+define void @neg_volatile(ptr %loc, ptr %loc2) {
+; CHECK-LABEL: define void @neg_volatile(
+; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: store volatile i32 0, ptr [[LOC]], align 4
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: br label %[[LOOP]]
+;
+entry:
+ br label %loop
+
+loop:
+ %val = load i32, ptr %loc2
+ store volatile i32 0, ptr %loc
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem()
+ br label %loop
+}
+
+declare void @fn_write_inaccessible_mem()#0
+ memory(inaccessiblemem: write)
+
+declare void @fn_read_inaccessible_mem()#0
+ memory(inaccessiblemem: read)
+
+declare void @fn_readwrite_inaccessible_mem()#0
+ memory(inaccessiblemem: readwrite)
+
+; Needs to set nounwind because of doesNotThrow
+attributes #0 = { mustprogress nofree norecurse nosync nounwind}
>From 3966e4b22a06d08c417ce6b400b0ceffa4564c62 Mon Sep 17 00:00:00 2001
From: CarolineConcatto <caroline.concatto at arm.com>
Date: Tue, 3 Mar 2026 18:21:33 +0000
Subject: [PATCH 2/2] Address review comments
---
llvm/lib/Transforms/Scalar/LICM.cpp | 27 ++--
llvm/test/Analysis/MemorySSA/pr43438.ll | 6 +-
.../2011-04-06-PromoteResultOfPromotion.ll | 17 +--
llvm/test/Transforms/LICM/call-hoisting.ll | 12 +-
llvm/test/Transforms/LICM/guards.ll | 7 +-
.../LICM/hoist-inaccesiblemem-call.ll | 118 +++++++++++++++---
llvm/test/Transforms/LICM/pr50367.ll | 4 +-
llvm/test/Transforms/LICM/pr59324.ll | 4 +-
llvm/test/Transforms/LICM/store-hoisting.ll | 23 ++--
.../invariant-store-vectorization.ll | 57 ++++-----
10 files changed, 171 insertions(+), 104 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 772604ff66635..21ff0eb69509a 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -2315,15 +2315,6 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *IMD = MSSA->getMemoryAccess(I);
BatchAAResults BAA(*AA);
auto *Source = getClobberingMemoryAccess(*MSSA, BAA, Flags, IMD);
- auto *CallI = dyn_cast<CallBase>(I);
- auto doesItReadILoc = [&](Instruction *UserI) -> bool {
- // Blocks if call reads the location I.
- if (auto *OtherCB = dyn_cast_or_null<CallBase>(UserI)) {
- ModRefInfo MRI = AA->getModRefInfo(CallI, OtherCB);
- return isRefSet(MRI);
- }
- return true;
- };
// Make sure there are no clobbers inside the loop.
if (!MSSA->isLiveOnEntryDef(Source) && CurLoop->contains(Source->getBlock()))
return false;
@@ -2337,15 +2328,19 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *Accesses = MSSA->getBlockAccesses(BB);
if (!Accesses)
continue;
- bool FoundI = false;
for (const auto &MA : *Accesses)
if (const auto *MU = dyn_cast<MemoryUse>(&MA)) {
auto *MD = getClobberingMemoryAccess(*MSSA, BAA, Flags,
const_cast<MemoryUse *>(MU));
- // Check clobbering only for Uses that happens before I
- if (!MSSA->isLiveOnEntryDef(MD) && CurLoop->contains(MD->getBlock()) &&
- !FoundI)
- return false;
+ if (!MSSA->isLiveOnEntryDef(MD) && CurLoop->contains(MD->getBlock())) {
+ auto *MDI = dyn_cast_or_null<MemoryDef>(MD);
+ // It checks only if I is clobbering.
+ // If IMD is not the same as I (that it wants to hoist), assumes they
+ // clobber
+ // Sync store is not allowed, but store hoist is allowed
+ if (!Flags.getIsSink() && (MDI && MDI->getMemoryInst() != I))
+ return false;
+ }
} else if (const auto *MD = dyn_cast<MemoryDef>(&MA)) {
if (auto *LI = dyn_cast<LoadInst>(MD->getMemoryInst())) {
(void)LI; // Silence warning.
@@ -2365,10 +2360,8 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
auto *SCI = cast<CallInst>(I);
// If the instruction we are wanting to hoist is also a call
// instruction then we need not check mod/ref info with itself
- if (SCI == CI) {
- FoundI = true;
+ if (SCI == CI)
continue;
- }
ModRefInfo MRI = BAA.getModRefInfo(CI, SCI);
if (isModOrRefSet(MRI))
return false;
diff --git a/llvm/test/Analysis/MemorySSA/pr43438.ll b/llvm/test/Analysis/MemorySSA/pr43438.ll
index 0e09137c1cf9a..c2a8d68930e0d 100644
--- a/llvm/test/Analysis/MemorySSA/pr43438.ll
+++ b/llvm/test/Analysis/MemorySSA/pr43438.ll
@@ -46,11 +46,7 @@ if.end569: ; preds = %if.else568, %if.the
; CHECK-LABEL: @f(i1 %arg)
-; CHECK: 7 = MemoryPhi(
-; CHECK: 6 = MemoryPhi(
-; CHECK: 10 = MemoryPhi(
-; CHECK: 9 = MemoryPhi(
-; CHECK: 8 = MemoryPhi(
+; CHECK: 4 = MemoryPhi(
define void @f(i1 %arg) {
entry:
%e = alloca i16, align 1
diff --git a/llvm/test/Transforms/LICM/2011-04-06-PromoteResultOfPromotion.ll b/llvm/test/Transforms/LICM/2011-04-06-PromoteResultOfPromotion.ll
index 0d32e508edf5f..07352a299f76b 100644
--- a/llvm/test/Transforms/LICM/2011-04-06-PromoteResultOfPromotion.ll
+++ b/llvm/test/Transforms/LICM/2011-04-06-PromoteResultOfPromotion.ll
@@ -9,10 +9,12 @@ define void @f() {
; CHECK-LABEL: define void @f() {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[L_87_I:%.*]] = alloca [9 x i16], align 16
-; CHECK-NEXT: [[G_58_PROMOTED:%.*]] = load i32, ptr @g_58, align 4, !tbaa [[INT_TBAA0:![0-9]+]]
+; CHECK-NEXT: store ptr @g_58, ptr @g_116, align 8, !tbaa [[ANYPTR_TBAA0:![0-9]+]]
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr @g_116, align 8, !tbaa [[ANYPTR_TBAA0]]
+; CHECK-NEXT: [[TMP2_PROMOTED:%.*]] = load i32, ptr [[TMP2]], align 4, !tbaa [[INT_TBAA4:![0-9]+]]
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
-; CHECK-NEXT: [[TMP31:%.*]] = phi i32 [ [[G_58_PROMOTED]], %[[ENTRY]] ], [ [[OR:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT: [[TMP31:%.*]] = phi i32 [ [[TMP2_PROMOTED]], %[[ENTRY]] ], [ [[OR:%.*]], %[[FOR_BODY]] ]
; CHECK-NEXT: [[INC12:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[INC:%.*]], %[[FOR_BODY]] ]
; CHECK-NEXT: [[OR]] = or i32 [[TMP31]], 10
; CHECK-NEXT: [[INC]] = add nsw i32 [[INC12]], 1
@@ -20,8 +22,7 @@ define void @f() {
; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_END:.*]]
; CHECK: [[FOR_END]]:
; CHECK-NEXT: [[OR_LCSSA:%.*]] = phi i32 [ [[OR]], %[[FOR_BODY]] ]
-; CHECK-NEXT: store ptr @g_58, ptr @g_116, align 8, !tbaa [[ANYPTR_TBAA4:![0-9]+]]
-; CHECK-NEXT: store i32 [[OR_LCSSA]], ptr @g_58, align 4, !tbaa [[INT_TBAA0]]
+; CHECK-NEXT: store i32 [[OR_LCSSA]], ptr [[TMP2]], align 4, !tbaa [[INT_TBAA4]]
; CHECK-NEXT: ret void
;
@@ -52,10 +53,10 @@ for.end: ; preds = %for.inc
!5 = !{!"any pointer", !1}
!6 = !{!"int", !1}
;.
-; CHECK: [[INT_TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
-; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]]}
+; CHECK: [[ANYPTR_TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
+; CHECK: [[META1]] = !{!"any pointer", [[META2:![0-9]+]]}
; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]]}
; CHECK: [[META3]] = !{!"Simple C/C++ TBAA"}
-; CHECK: [[ANYPTR_TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0}
-; CHECK: [[META5]] = !{!"any pointer", [[META2]]}
+; CHECK: [[INT_TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0}
+; CHECK: [[META5]] = !{!"int", [[META2]]}
;.
diff --git a/llvm/test/Transforms/LICM/call-hoisting.ll b/llvm/test/Transforms/LICM/call-hoisting.ll
index edc907d9e5a97..011d4654a2d1b 100644
--- a/llvm/test/Transforms/LICM/call-hoisting.ll
+++ b/llvm/test/Transforms/LICM/call-hoisting.ll
@@ -251,11 +251,11 @@ define i32 @neg_conflicting_read(ptr noalias %loc, ptr noalias %otherloc) {
; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[OTHERLOC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
+; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[VAL:%.*]] = call i32 @load(ptr [[LOC]])
-; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -399,18 +399,18 @@ exit:
define void @neg_ref(ptr %loc) {
; CHECK-LABEL: define void @neg_ref(
; CHECK-SAME: ptr [[LOC:%.*]]) {
-; CHECK-NEXT: [[LOOP:.*]]:
-; CHECK-NEXT: br label %[[LOOP1:.*]]
-; CHECK: [[LOOP1]]:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[LOOP]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
+; CHECK-NEXT: [[LOOP1:.*]]:
; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[LOC]], align 4
; CHECK-NEXT: [[EARLYCND:%.*]] = icmp eq i32 [[V]], 198
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[LOOP1]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
; CHECK-NEXT: br i1 [[EARLYCND]], label %[[EXIT1:.*]], label %[[BACKEDGE]]
; CHECK: [[BACKEDGE]]:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
-; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP1]], label %[[EXIT2:.*]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT2:.*]]
; CHECK: [[EXIT1]]:
; CHECK-NEXT: ret void
; CHECK: [[EXIT2]]:
diff --git a/llvm/test/Transforms/LICM/guards.ll b/llvm/test/Transforms/LICM/guards.ll
index 361d938ce19b8..492444c7269d5 100644
--- a/llvm/test/Transforms/LICM/guards.ll
+++ b/llvm/test/Transforms/LICM/guards.ll
@@ -113,12 +113,11 @@ define void @test3(i1 %cond, ptr %ptr) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND:%.*]]) [ "deopt"(i32 0) ]
-; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, ptr [[PTR:%.*]], align 4
+; CHECK-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[PTR_PROMOTED]], [[ENTRY:%.*]] ], [ 0, [[LOOP]] ]
-; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[X_INC:%.*]], [[LOOP]] ]
-; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_INC:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4
; CHECK-NEXT: [[X_INC]] = add i32 [[X]], [[TMP0]]
; CHECK-NEXT: br label [[LOOP]]
;
diff --git a/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll b/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
index d3ff60ef6ba1d..152ba07db7cd2 100644
--- a/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
+++ b/llvm/test/Transforms/LICM/hoist-inaccesiblemem-call.ll
@@ -2,18 +2,21 @@
; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<target-ir>,loop-mssa(licm)' < %s -S | FileCheck %s
-define dso_local i32 @loop_alias(i32 %x, ptr %a, ptr %b) #0{
+;; It should hoist fn_write_inaccessible_mem
+;; because there is no conflict between inaccessible memory
+;; fn_read_inaccessible_mem is a nice side effect
+define dso_local i32 @loop_alias(i32 %x, ptr %a, ptr %b) #0 {
; CHECK-LABEL: define dso_local i32 @loop_alias(
; CHECK-SAME: i32 [[X:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i64 1
; CHECK-NEXT: call void @fn_write_inaccessible_mem()
-; CHECK-NEXT: call void @fn_read_inaccessible_mem()
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP:%.*]], %[[LOOP]] ], [ [[VAL]], %[[ENTRY]] ]
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PHI]], i64 0
; CHECK-NEXT: [[VAL2:%.*]] = call i32 @fn_args(ptr [[GEP2]])
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[VAL2]])
; CHECK-NEXT: [[GEP]] = getelementptr inbounds nuw i32, ptr [[PHI]], i64 0
; CHECK-NEXT: [[ACC:%.*]] = add nuw nsw i32 [[VAL2]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ACC]], 10
@@ -31,7 +34,7 @@ loop:
%gep2 = getelementptr i8, ptr %phi, i64 0
%val2 = call i32 @fn_args(ptr %gep2)
call void @fn_write_inaccessible_mem()
- call void @fn_read_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %val2)
%gep = getelementptr inbounds nuw i32, ptr %phi, i64 0
%acc = add nuw nsw i32 %val2, 1
%cmp = icmp ult i32 %acc, 10
@@ -43,13 +46,96 @@ after_loop:
declare i32 @fn_args(ptr) nounwind willreturn
memory(argmem: read)
+;; It should be able to hoist fn_write_inaccessible_mem
+define dso_local i32 @loop_alias_store(i32 %x, ptr %a) #0 {
+; CHECK-LABEL: define dso_local i32 @loop_alias_store(
+; CHECK-SAME: i32 [[X:%.*]], ptr [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i64 1
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP:%.*]], %[[LOOP]] ], [ [[VAL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PHI]], align 16
+; CHECK-NEXT: [[GEP]] = getelementptr i8, ptr [[PHI]], i64 0
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[TMP0]])
+; CHECK-NEXT: [[ACC:%.*]] = add nuw nsw i32 [[TMP0]], 1
+; CHECK-NEXT: store i32 [[ACC]], ptr [[A]], align 16
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ACC]], 10
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[AFTER_LOOP:.*]]
+; CHECK: [[AFTER_LOOP]]:
+; CHECK-NEXT: [[ACC_LCSSA:%.*]] = phi i32 [ [[ACC]], %[[LOOP]] ]
+; CHECK-NEXT: ret i32 [[ACC_LCSSA]]
+;
+entry:
+ %val = getelementptr inbounds nuw i32, ptr %a, i64 1
+ br label %loop
+loop:
+ %phi = phi ptr [ %gep, %loop ], [ %val, %entry ]
+ %44 = load i32, ptr %phi, align 16
+ %gep = getelementptr i8, ptr %phi, i64 0
+ %val2 = call i32 @fn_args(ptr %gep)
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %44)
+ %acc = add nuw nsw i32 %44, 1
+ store i32 %acc, ptr %a, align 16
+ %cmp = icmp ult i32 %acc, 10
+ br i1 %cmp, label %loop, label %after_loop
+after_loop:
+ ret i32 %acc
+}
+
+;; It should NOT hoist fn_write_inaccessible_mem
+;; Because fn_args_2 reads same memory location
+define dso_local i32 @ne_loop_alias(i32 %x, ptr %a, ptr %b) #0 {
+; CHECK-LABEL: define dso_local i32 @ne_loop_alias(
+; CHECK-SAME: i32 [[X:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds nuw i32, ptr [[A]], i64 1
+; CHECK-NEXT: call void @fn_write_inaccessible_mem()
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP:%.*]], %[[LOOP]] ], [ [[VAL]], %[[ENTRY]] ]
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PHI]], i64 0
+; CHECK-NEXT: [[VAL2:%.*]] = call i32 @fn_args_2(ptr [[GEP2]])
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[VAL2]])
+; CHECK-NEXT: [[GEP]] = getelementptr inbounds nuw i32, ptr [[PHI]], i64 0
+; CHECK-NEXT: [[ACC:%.*]] = add nuw nsw i32 [[VAL2]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ACC]], 10
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[AFTER_LOOP:.*]]
+; CHECK: [[AFTER_LOOP]]:
+; CHECK-NEXT: [[ACC_LCSSA:%.*]] = phi i32 [ [[ACC]], %[[LOOP]] ]
+; CHECK-NEXT: ret i32 [[ACC_LCSSA]]
+;
+entry:
+ %val = getelementptr inbounds nuw i32, ptr %a, i64 1
+ br label %loop
+loop:
+ %phi = phi ptr [ %gep, %loop ], [ %val, %entry ]
+ %44 = load i32, ptr %phi, align 16
+ %gep2 = getelementptr i8, ptr %phi, i64 0
+ %val2 = call i32 @fn_args_2(ptr %gep2)
+ call void @fn_write_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %val2)
+ %gep = getelementptr inbounds nuw i32, ptr %phi, i64 0
+ %acc = add nuw nsw i32 %val2, 1
+ %cmp = icmp ult i32 %acc, 10
+ br i1 %cmp, label %loop, label %after_loop
+after_loop:
+ ret i32 %acc
+}
+declare i32 @fn_args_2(ptr) nounwind willreturn
+memory(inaccessiblemem:read)
+
+;; Should hoist fn_write_inaccessible_mem
+;; It does not alias with store
define void @hoist_untill_I(ptr noalias %loc, ptr noalias %loc2){
; CHECK-LABEL: define void @hoist_untill_I(
; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[LOC2:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[LOC2]], align 4
; CHECK-NEXT: call void @fn_write_inaccessible_mem()
-; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[VAL]])
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_COND_CLEANUP:.*:]]
; CHECK-NEXT: ret void
@@ -65,11 +151,12 @@ for.body:
%val = load i32, ptr %loc2
store i32 %val, ptr %loc
call void @fn_write_inaccessible_mem()
- call void @fn_read_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %val)
br label %for.body
}
-
+;; Should NOT hoist fn_write_inaccessible_mem
+;; because fn_read_inaccessible_mem reads the same memory location
define void @neg_hoist_untill_I(ptr noalias %loc, ptr noalias %loc2){
; CHECK-LABEL: define void @neg_hoist_untill_I(
; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[LOC2:%.*]]) {
@@ -78,9 +165,9 @@ define void @neg_hoist_untill_I(ptr noalias %loc, ptr noalias %loc2){
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: store i32 [[VAL]], ptr [[LOC]], align 4
-; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 0)
; CHECK-NEXT: call void @fn_write_inaccessible_mem()
-; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[VAL]])
; CHECK-NEXT: br label %[[FOR_BODY]]
;
entry:
@@ -88,24 +175,25 @@ entry:
for.body:
%val = load i32, ptr %loc2
store i32 %val, ptr %loc
- call void @fn_read_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 0)
call void @fn_write_inaccessible_mem()
- call void @fn_read_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %val)
br label %for.body
}
-; Nothing should be hoisted from the loop because volatile
-; sets inaccessible memory to read write
+;; Nothing should be hoisted from the loop because volatile
+;; sets inaccessible memory to read write
define void @neg_volatile(ptr %loc, ptr %loc2) {
; CHECK-LABEL: define void @neg_volatile(
; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[LOC2]], align 4
; CHECK-NEXT: store volatile i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: call void @fn_write_inaccessible_mem()
-; CHECK-NEXT: call void @fn_read_inaccessible_mem()
+; CHECK-NEXT: call void @fn_read_inaccessible_mem(i32 [[VAL]])
; CHECK-NEXT: br label %[[LOOP]]
;
entry:
@@ -115,14 +203,14 @@ loop:
%val = load i32, ptr %loc2
store volatile i32 0, ptr %loc
call void @fn_write_inaccessible_mem()
- call void @fn_read_inaccessible_mem()
+ call void @fn_read_inaccessible_mem(i32 %val)
br label %loop
}
declare void @fn_write_inaccessible_mem()#0
memory(inaccessiblemem: write)
-declare void @fn_read_inaccessible_mem()#0
+declare void @fn_read_inaccessible_mem(i32)#0
memory(inaccessiblemem: read)
declare void @fn_readwrite_inaccessible_mem()#0
diff --git a/llvm/test/Transforms/LICM/pr50367.ll b/llvm/test/Transforms/LICM/pr50367.ll
index 6aafff74f61d8..3e3e5c92cd481 100644
--- a/llvm/test/Transforms/LICM/pr50367.ll
+++ b/llvm/test/Transforms/LICM/pr50367.ll
@@ -44,6 +44,9 @@ define void @store_null(i1 %arg) {
; CHECK-LABEL: define void @store_null(
; CHECK-SAME: i1 [[ARG:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store ptr null, ptr @e, align 8, !tbaa [[ANYPTR_TBAA0]]
+; CHECK-NEXT: [[PTR:%.*]] = load ptr, ptr @e, align 8, !tbaa [[ANYPTR_TBAA0]]
+; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4, !tbaa [[INT_TBAA4]]
; CHECK-NEXT: br label %[[LOOP1:.*]]
; CHECK: [[LOOP1]]:
; CHECK-NEXT: br label %[[LOOP2:.*]]
@@ -53,7 +56,6 @@ define void @store_null(i1 %arg) {
; CHECK-NEXT: store i32 0, ptr null, align 4
; CHECK-NEXT: br label %[[LOOP2]]
; CHECK: [[LOOP_LATCH]]:
-; CHECK-NEXT: store i32 0, ptr null, align 4, !tbaa [[INT_TBAA4]]
; CHECK-NEXT: br label %[[LOOP1]]
;
entry:
diff --git a/llvm/test/Transforms/LICM/pr59324.ll b/llvm/test/Transforms/LICM/pr59324.ll
index ec33a0f8ded0f..bb5570fec8b56 100644
--- a/llvm/test/Transforms/LICM/pr59324.ll
+++ b/llvm/test/Transforms/LICM/pr59324.ll
@@ -4,10 +4,10 @@
define void @test(ptr %a) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br label [[LOOP:%.*]]
-; CHECK: loop:
; CHECK-NEXT: store ptr null, ptr null, align 8
; CHECK-NEXT: [[P:%.*]] = load ptr, ptr null, align 8
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: store i32 [[V]], ptr [[A:%.*]], align 4
; CHECK-NEXT: br label [[LOOP]]
diff --git a/llvm/test/Transforms/LICM/store-hoisting.ll b/llvm/test/Transforms/LICM/store-hoisting.ll
index 016364fff9fbb..e49e0724978df 100644
--- a/llvm/test/Transforms/LICM/store-hoisting.ll
+++ b/llvm/test/Transforms/LICM/store-hoisting.ll
@@ -188,20 +188,20 @@ define void @neg_ref(ptr %loc) {
; CHECK-LABEL: define void @neg_ref(
; CHECK-SAME: ptr [[LOC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[LOC]], align 4
+; CHECK-NEXT: [[EARLYCND:%.*]] = icmp eq i32 [[V]], 198
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
-; CHECK-NEXT: [[EARLYCND:%.*]] = icmp eq i32 0, 198
; CHECK-NEXT: br i1 [[EARLYCND]], label %[[EXIT1:.*]], label %[[BACKEDGE]]
; CHECK: [[BACKEDGE]]:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT2:.*]]
; CHECK: [[EXIT1]]:
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: ret void
; CHECK: [[EXIT2]]:
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: ret void
;
entry:
@@ -231,11 +231,11 @@ define void @neg_ref2(ptr %loc) {
; CHECK-SAME: ptr [[LOC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: store i32 198, ptr [[LOC]], align 4
-; CHECK-NEXT: [[LOC_PROMOTED:%.*]] = load i32, ptr [[LOC]], align 4
+; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[LOC_PROMOTED]], %[[ENTRY]] ], [ 0, %[[BACKEDGE:.*]] ]
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[LOC]], align 4
; CHECK-NEXT: [[EARLYCND:%.*]] = icmp eq i32 [[TMP0]], 198
; CHECK-NEXT: br i1 [[EARLYCND]], label %[[EXIT1:.*]], label %[[BACKEDGE]]
; CHECK: [[BACKEDGE]]:
@@ -243,10 +243,8 @@ define void @neg_ref2(ptr %loc) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT2:.*]]
; CHECK: [[EXIT1]]:
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: ret void
; CHECK: [[EXIT2]]:
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: ret void
;
entry:
@@ -553,17 +551,16 @@ define i32 @test_dominating_read(ptr %loc) {
; CHECK-LABEL: define i32 @test_dominating_read(
; CHECK-SAME: ptr [[LOC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[LOC_PROMOTED:%.*]] = load i32, ptr [[LOC]], align 4
+; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[LOC_PROMOTED]], %[[ENTRY]] ], [ 0, %[[LOOP]] ]
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT: [[RELOAD:%.*]] = load i32, ptr [[LOC]], align 4
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RELOAD_LCSSA:%.*]] = phi i32 [ [[TMP0]], %[[LOOP]] ]
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
+; CHECK-NEXT: [[RELOAD_LCSSA:%.*]] = phi i32 [ [[RELOAD]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[RELOAD_LCSSA]]
;
entry:
@@ -588,10 +585,10 @@ define void @test_dominated_readonly(ptr %loc) {
; CHECK-LABEL: define void @test_dominated_readonly(
; CHECK-SAME: ptr [[LOC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT: store i32 0, ptr [[LOC]], align 4
; CHECK-NEXT: call void @readonly()
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
diff --git a/llvm/test/Transforms/LoopVectorize/invariant-store-vectorization.ll b/llvm/test/Transforms/LoopVectorize/invariant-store-vectorization.ll
index 7c4263617a6d9..11012875edb75 100644
--- a/llvm/test/Transforms/LoopVectorize/invariant-store-vectorization.ll
+++ b/llvm/test/Transforms/LoopVectorize/invariant-store-vectorization.ll
@@ -20,38 +20,30 @@ define i32 @inv_val_store_to_inv_address_with_reduction(ptr %a, i64 %n, ptr %b)
; CHECK-LABEL: @inv_val_store_to_inv_address_with_reduction(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NTRUNC:%.*]] = trunc i64 [[N:%.*]] to i32
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A:%.*]], align 4
; CHECK-NEXT: [[SMAX2:%.*]] = call i64 @llvm.smax.i64(i64 [[N]], i64 1)
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp slt i64 [[N]], 4
-; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_MEMCHECK:%.*]]
-; CHECK: vector.memcheck:
-; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 4
-; CHECK-NEXT: [[TMP0:%.*]] = shl i64 [[N]], 2
-; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[B:%.*]], i64 [[TMP0]]
-; CHECK-NEXT: [[BOUND0:%.*]] = icmp ult ptr [[A]], [[SCEVGEP1]]
-; CHECK-NEXT: [[BOUND1:%.*]] = icmp ult ptr [[B]], [[SCEVGEP]]
-; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
-; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
+; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[SMAX2]], 9223372036854775804
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP2:%.*]], [[VECTOR_BODY]] ]
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [4 x i8], ptr [[B]], i64 [[INDEX]]
-; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP1]], align 8, !alias.scope [[META0:![0-9]+]]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [4 x i8], ptr [[B:%.*]], i64 [[INDEX]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP1]], align 8
; CHECK-NEXT: [[TMP2]] = add <4 x i32> [[VEC_PHI]], [[WIDE_LOAD]]
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META3:![0-9]+]], !noalias [[META0]]
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP3]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
+; CHECK-NEXT: br i1 [[TMP3]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi <4 x i32> [ [[TMP2]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[TMP4:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[DOTLCSSA]])
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[SMAX2]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_END:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
-; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ], [ 0, [[VECTOR_MEMCHECK]] ]
-; CHECK-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[TMP4]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY]] ], [ 0, [[VECTOR_MEMCHECK]] ]
+; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[TMP4]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], [[FOR_BODY]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
@@ -59,10 +51,9 @@ define i32 @inv_val_store_to_inv_address_with_reduction(ptr %a, i64 %n, ptr %b)
; CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds nuw [4 x i8], ptr [[B]], i64 [[I]]
; CHECK-NEXT: [[I2:%.*]] = load i32, ptr [[I1]], align 8
; CHECK-NEXT: [[I3]] = add i32 [[I0]], [[I2]]
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[I_NEXT]], [[N]]
-; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP8:![0-9]+]]
+; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP3:![0-9]+]]
; CHECK: for.end.loopexit:
; CHECK-NEXT: [[I3_LCSSA:%.*]] = phi i32 [ [[I3]], [[FOR_BODY]] ]
; CHECK-NEXT: br label [[FOR_END]]
@@ -113,11 +104,11 @@ define void @inv_val_store_to_inv_address(ptr %a, i64 %n, ptr %b) {
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [4 x i8], ptr [[B]], i64 [[INDEX]]
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META9:![0-9]+]], !noalias [[META12:![0-9]+]]
-; CHECK-NEXT: store <4 x i32> [[BROADCAST_SPLAT]], ptr [[TMP1]], align 4, !alias.scope [[META12]]
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META4:![0-9]+]], !noalias [[META7:![0-9]+]]
+; CHECK-NEXT: store <4 x i32> [[BROADCAST_SPLAT]], ptr [[TMP1]], align 4, !alias.scope [[META7]]
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP2]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP14:![0-9]+]]
+; CHECK-NEXT: br i1 [[TMP2]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[SMAX2]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_END:%.*]], label [[SCALAR_PH]]
@@ -131,7 +122,7 @@ define void @inv_val_store_to_inv_address(ptr %a, i64 %n, ptr %b) {
; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[I1]], align 4
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[I_NEXT]], [[N]]
-; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP15:![0-9]+]]
+; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP10:![0-9]+]]
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
@@ -190,36 +181,36 @@ define void @inv_val_store_to_inv_address_conditional(ptr %a, i64 %n, ptr %b, i3
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[PRED_STORE_CONTINUE10:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [4 x i8], ptr [[B]], i64 [[INDEX]]
-; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP1]], align 8, !alias.scope [[META16:![0-9]+]], !noalias [[META19:![0-9]+]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP1]], align 8, !alias.scope [[META11:![0-9]+]], !noalias [[META14:![0-9]+]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <4 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT4]]
-; CHECK-NEXT: store <4 x i32> [[BROADCAST_SPLAT]], ptr [[TMP1]], align 4, !alias.scope [[META16]], !noalias [[META19]]
+; CHECK-NEXT: store <4 x i32> [[BROADCAST_SPLAT]], ptr [[TMP1]], align 4, !alias.scope [[META11]], !noalias [[META14]]
; CHECK-NEXT: [[TMP3:%.*]] = extractelement <4 x i1> [[TMP2]], i64 0
; CHECK-NEXT: br i1 [[TMP3]], label [[PRED_STORE_IF:%.*]], label [[PRED_STORE_CONTINUE:%.*]]
; CHECK: pred.store.if:
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META19]]
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META14]]
; CHECK-NEXT: br label [[PRED_STORE_CONTINUE]]
; CHECK: pred.store.continue:
; CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x i1> [[TMP2]], i64 1
; CHECK-NEXT: br i1 [[TMP4]], label [[PRED_STORE_IF5:%.*]], label [[PRED_STORE_CONTINUE6:%.*]]
; CHECK: pred.store.if5:
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META19]]
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META14]]
; CHECK-NEXT: br label [[PRED_STORE_CONTINUE6]]
; CHECK: pred.store.continue6:
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <4 x i1> [[TMP2]], i64 2
; CHECK-NEXT: br i1 [[TMP5]], label [[PRED_STORE_IF7:%.*]], label [[PRED_STORE_CONTINUE8:%.*]]
; CHECK: pred.store.if7:
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META19]]
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META14]]
; CHECK-NEXT: br label [[PRED_STORE_CONTINUE8]]
; CHECK: pred.store.continue8:
; CHECK-NEXT: [[TMP6:%.*]] = extractelement <4 x i1> [[TMP2]], i64 3
; CHECK-NEXT: br i1 [[TMP6]], label [[PRED_STORE_IF9:%.*]], label [[PRED_STORE_CONTINUE10]]
; CHECK: pred.store.if9:
-; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META19]]
+; CHECK-NEXT: store i32 [[NTRUNC]], ptr [[A]], align 4, !alias.scope [[META14]]
; CHECK-NEXT: br label [[PRED_STORE_CONTINUE10]]
; CHECK: pred.store.continue10:
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP21:![0-9]+]]
+; CHECK-NEXT: br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP16:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[SMAX2]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_END:%.*]], label [[SCALAR_PH]]
@@ -239,7 +230,7 @@ define void @inv_val_store_to_inv_address_conditional(ptr %a, i64 %n, ptr %b, i3
; CHECK: latch:
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 1
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[I_NEXT]], [[N]]
-; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP22:![0-9]+]]
+; CHECK-NEXT: br i1 [[COND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop [[LOOP17:![0-9]+]]
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
@@ -388,16 +379,16 @@ define void @multiple_uniform_stores(ptr nocapture %var1, ptr nocapture readonly
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ [[TMP15]], [[VECTOR_PH]] ], [ [[TMP17:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [4 x i8], ptr [[INVARIANT_GEP]], i64 [[INDEX]]
-; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[GEP]], align 4, !alias.scope [[META23:![0-9]+]]
+; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[GEP]], align 4, !alias.scope [[META18:![0-9]+]]
; CHECK-NEXT: [[TMP16:%.*]] = add <4 x i32> [[VEC_PHI]], [[WIDE_LOAD]]
; CHECK-NEXT: [[TMP17]] = add <4 x i32> [[TMP16]], splat (i32 1)
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
; CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP18]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP26:![0-9]+]]
+; CHECK-NEXT: br i1 [[TMP18]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP21:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi <4 x i32> [ [[TMP17]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[TMP19:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[DOTLCSSA]])
-; CHECK-NEXT: store i32 [[TMP19]], ptr [[ARRAYIDX5]], align 4, !alias.scope [[META27:![0-9]+]], !noalias [[META23]]
+; CHECK-NEXT: store i32 [[TMP19]], ptr [[ARRAYIDX5]], align 4, !alias.scope [[META22:![0-9]+]], !noalias [[META18]]
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP8]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_INC8_LOOPEXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
@@ -415,7 +406,7 @@ define void @multiple_uniform_stores(ptr nocapture %var1, ptr nocapture readonly
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[INDVARS_IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[ITR]], [[LFTR_WIDEIV]]
-; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_INC8_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY3]], !llvm.loop [[LOOP29:![0-9]+]]
+; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_INC8_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY3]], !llvm.loop [[LOOP24:![0-9]+]]
; CHECK: for.inc8.loopexit.loopexit:
; CHECK-NEXT: br label [[FOR_INC8_LOOPEXIT]]
; CHECK: for.inc8.loopexit:
More information about the llvm-commits
mailing list