[llvm] [GVN] Use willNotFreeBetween in loop-load PRE (PR #228033)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 03:56:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: anupkum-sgs
<details>
<summary>Changes</summary>
`canBeFreed` used by GVN is very conservative. For an argument, one of the cases
where it returns false is when the argument has `nofree`/`readonly` and
`noalias`. A pointer that may alias a clobber in the loop is never `noalias`, so
PRE bails out even when nothing on the path can free the object.
This uses `willNotFreeBetween` alongside `canBeFreed`. The header load has
already dereferenced `LoadPtr` on an iteration, so only a deallocation between
that load and the reload can make the same address unsafe to read again.
The non-linear walk this relies on landed in #<!-- -->223580. The existing limit of 32
instructions per query is left unchanged.
This is the first of two patches, split as suggested in review of my earlier
combined change in #<!-- -->227983. The follow-up will allow a blocker inside an inner
loop; that change is a no-op in many cases without this one, since in the
aliasing cases it targets, `canBeFreed` returns true and PRE bails out before
reaching it.
One phase-ordering test regresses: in `cse_two_guards` the load that is now
PRE'd becomes a loop-carried recurrence, so the second loop is no longer
vectorized.
RFC: https://discourse.llvm.org/t/rfc-extending-gvns-loop-load-pre/91740
---
Patch is 22.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/228033.diff
4 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+7-1)
- (modified) llvm/test/Transforms/GVN/PRE/pre-aliasning-path.ll (+14-6)
- (modified) llvm/test/Transforms/GVN/PRE/pre-loop-load.ll (+98-12)
- (modified) llvm/test/Transforms/PhaseOrdering/X86/ptrtoaddr-ptrtoint.ll (+12-61)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index b8a44882af867..fe698d235f721 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2032,7 +2032,13 @@ bool GVNPass::performLoopLoadPRE(LoadInst *Load,
// Make sure the memory at this pointer cannot be freed, therefore we can
// safely reload from it after clobber.
- if (LoadPtr->canBeFreed())
+ //
+ // The header load has already dereferenced LoadPtr on this iteration, so
+ // only a deallocation between that load and the reload in LoopBlock can make
+ // the same address unsafe to read again. Check every path between these two
+ // points for an instruction that may deallocate the memory.
+ if (LoadPtr->canBeFreed() &&
+ !willNotFreeBetween(Load, LoopBlock->getTerminator(), DT))
return false;
// TODO: Support critical edge splitting if blocker has more than 1 successor.
diff --git a/llvm/test/Transforms/GVN/PRE/pre-aliasning-path.ll b/llvm/test/Transforms/GVN/PRE/pre-aliasning-path.ll
index 7dc884f87e360..3d4feb76aaa44 100644
--- a/llvm/test/Transforms/GVN/PRE/pre-aliasning-path.ll
+++ b/llvm/test/Transforms/GVN/PRE/pre-aliasning-path.ll
@@ -8,22 +8,26 @@ declare void @side_effect_1(i32 %x) nofree
declare void @no_side_effect() readonly
-; TODO: We can PRE the load into the cold path, removing it from the hot path.
+; We can PRE the load into the cold path, removing it from the hot path: the
+; callee is nofree, so %p cannot be deallocated between the loads.
define i32 @test_01(ptr %p) {
; CHECK-LABEL: @test_01(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE1:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE1]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[X]], 100
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH:%.*]]
; CHECK: hot_path:
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: cold_path:
; CHECK-NEXT: call void @side_effect_0() #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
+; CHECK-NEXT: [[X2]] = phi i32 [ [[X_PRE]], [[COLD_PATH]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
@@ -55,22 +59,26 @@ exit:
ret i32 %x
}
-; TODO: We can PRE the load into the cold path, removing it from the hot path.
+; We can PRE the load into the cold path, removing it from the hot path: the
+; callee is nofree, so %p cannot be deallocated between the loads.
define i32 @test_02(ptr %p) {
; CHECK-LABEL: @test_02(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE1:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE1]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[X]], 100
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH:%.*]]
; CHECK: hot_path:
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: cold_path:
; CHECK-NEXT: call void @side_effect_1(i32 [[X]]) #[[ATTR0]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
+; CHECK-NEXT: [[X2]] = phi i32 [ [[X_PRE]], [[COLD_PATH]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
diff --git a/llvm/test/Transforms/GVN/PRE/pre-loop-load.ll b/llvm/test/Transforms/GVN/PRE/pre-loop-load.ll
index 8f1b73ad8383d..f1d3a813445ac 100644
--- a/llvm/test/Transforms/GVN/PRE/pre-loop-load.ll
+++ b/llvm/test/Transforms/GVN/PRE/pre-loop-load.ll
@@ -107,22 +107,26 @@ exit:
}
-; TODO: We can PRE the load away from the hot path.
+; We can PRE the load away from the hot path: @side_effect is nofree, so the
+; object under %p cannot be deallocated between the loads.
define i32 @test_load_on_cold_path(ptr %p) {
; CHECK-LABEL: @test_load_on_cold_path(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE1:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE1]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH:%.*]]
; CHECK: hot_path:
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: cold_path:
; CHECK-NEXT: call void @side_effect() #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
+; CHECK-NEXT: [[X2]] = phi i32 [ [[X_PRE]], [[COLD_PATH]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
@@ -355,22 +359,26 @@ exit:
ret i32 %x
}
-; TODO: We can PRE via splitting of the critical edge in the cold path.
+; We PRE into the cold path. TODO: split the critical edge so that the reload
+; does not also run on the path that leaves the loop.
define i32 @test_load_on_exiting_cold_path_01(ptr %p) {
; CHECK-LABEL: @test_load_on_exiting_cold_path_01(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE2:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE2]], [[ENTRY:%.*]] ], [ [[X3:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH:%.*]]
; CHECK: hot_path:
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: cold_path:
; CHECK-NEXT: [[SIDE_COND:%.*]] = call i1 @side_effect_cond() #[[ATTR0]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br i1 [[SIDE_COND]], label [[BACKEDGE]], label [[COLD_EXIT:%.*]]
; CHECK: backedge:
+; CHECK-NEXT: [[X3]] = phi i32 [ [[X_PRE]], [[COLD_PATH]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
@@ -570,14 +578,17 @@ exit:
ret i32 %x
}
-; TODO: We can PRE via splitting of the critical edge in the cold path. Make sure we only insert 1 load.
+; We PRE into the last cold block, inserting exactly 1 load. TODO: split the
+; critical edge so that the reload does not also run on the path that leaves the
+; loop.
define i32 @test_load_on_multi_exiting_cold_path(ptr %p) {
; CHECK-LABEL: @test_load_on_multi_exiting_cold_path(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE2:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE2]], [[ENTRY:%.*]] ], [ [[X3:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH_1:%.*]]
; CHECK: hot_path:
@@ -590,8 +601,10 @@ define i32 @test_load_on_multi_exiting_cold_path(ptr %p) {
; CHECK-NEXT: br i1 [[SIDE_COND_2]], label [[COLD_PATH_3:%.*]], label [[COLD_EXIT]]
; CHECK: cold_path.3:
; CHECK-NEXT: [[SIDE_COND_3:%.*]] = call i1 @side_effect_cond() #[[ATTR0]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br i1 [[SIDE_COND_3]], label [[BACKEDGE]], label [[COLD_EXIT]]
; CHECK: backedge:
+; CHECK-NEXT: [[X3]] = phi i32 [ [[X_PRE]], [[COLD_PATH_3]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
@@ -773,14 +786,16 @@ exit:
ret i32 %x
}
-; TODO: We can PRE via split of critical edge.
+; We PRE into the call block. TODO: split the critical edge so that the reload
+; does not also run on the path that leaves the loop.
define i32 @test_side_exit_after_merge(ptr %p) {
; CHECK-LABEL: @test_side_exit_after_merge(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE2:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
-; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE2]], [[ENTRY:%.*]] ], [ [[X3:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_PATH:%.*]]
; CHECK: hot_path:
@@ -790,11 +805,14 @@ define i32 @test_side_exit_after_merge(ptr %p) {
; CHECK-NEXT: br i1 [[COND_1]], label [[DO_CALL:%.*]], label [[SIDE_EXITING:%.*]]
; CHECK: do_call:
; CHECK-NEXT: [[SIDE_COND:%.*]] = call i1 @side_effect_cond() #[[ATTR0]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: br label [[SIDE_EXITING]]
; CHECK: side_exiting:
+; CHECK-NEXT: [[X4:%.*]] = phi i32 [ [[X_PRE]], [[DO_CALL]] ], [ 0, [[COLD_PATH]] ]
; CHECK-NEXT: [[SIDE_COND_PHI:%.*]] = phi i1 [ [[SIDE_COND]], [[DO_CALL]] ], [ true, [[COLD_PATH]] ]
; CHECK-NEXT: br i1 [[SIDE_COND_PHI]], label [[BACKEDGE]], label [[COLD_EXIT:%.*]]
; CHECK: backedge:
+; CHECK-NEXT: [[X3]] = phi i32 [ [[X4]], [[SIDE_EXITING]] ], [ [[X]], [[HOT_PATH]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
@@ -940,3 +958,71 @@ backedge:
exit:
ret i32 %x
}
+
+; We can PRE into the merge block. %merge has two predecessors, so proving the
+; absence of a deallocation requires walking both paths back to the header load.
+define i32 @test_merged_nofree_paths(ptr %p, i1 %take.a) {
+; CHECK-LABEL: @test_merged_nofree_paths(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X_PRE1:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[X_PRE1]], [[ENTRY:%.*]] ], [ [[X2:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label [[HOT_PATH:%.*]], label [[COLD_ENTRY:%.*]]
+; CHECK: hot_path:
+; CHECK-NEXT: br label [[BACKEDGE]]
+; CHECK: cold_entry:
+; CHECK-NEXT: br i1 [[TAKE_A:%.*]], label [[PATH_A:%.*]], label [[PATH_B:%.*]]
+; CHECK: path_a:
+; CHECK-NEXT: call void @side_effect() #[[ATTR0]]
+; CHECK-NEXT: br label [[MERGE:%.*]]
+; CHECK: path_b:
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: call void @side_effect() #[[ATTR0]]
+; CHECK-NEXT: [[X_PRE:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT: br label [[BACKEDGE]]
+; CHECK: backedge:
+; CHECK-NEXT: [[X2]] = phi i32 [ [[X_PRE]], [[MERGE]] ], [ [[X]], [[HOT_PATH]] ]
+; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[X]]
+; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 1000
+; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: ret i32 [[X]]
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
+ %x = load i32, ptr %p
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %hot_path, label %cold_entry
+
+hot_path:
+ br label %backedge
+
+cold_entry:
+ br i1 %take.a, label %path_a, label %path_b
+
+path_a:
+ call void @side_effect() nofree
+ br label %merge
+
+path_b:
+ br label %merge
+
+merge:
+ call void @side_effect() nofree
+ br label %backedge
+
+backedge:
+ %iv.next = add i32 %iv, %x
+ %loop.cond = icmp ult i32 %iv.next, 1000
+ br i1 %loop.cond, label %loop, label %exit
+
+exit:
+ ret i32 %x
+}
diff --git a/llvm/test/Transforms/PhaseOrdering/X86/ptrtoaddr-ptrtoint.ll b/llvm/test/Transforms/PhaseOrdering/X86/ptrtoaddr-ptrtoint.ll
index 1bb6b2fb5bd3a..4fd4a808f9501 100644
--- a/llvm/test/Transforms/PhaseOrdering/X86/ptrtoaddr-ptrtoint.ll
+++ b/llvm/test/Transforms/PhaseOrdering/X86/ptrtoaddr-ptrtoint.ll
@@ -156,58 +156,7 @@ define i64 @cse_two_guards(ptr %base, i64 %n, ptr %cmp) {
; CHECK: [[LOOP2_BODY_LR_PH]]:
; CHECK-NEXT: [[SEL_LCSSA:%.*]] = phi i64 [ [[RDX_SELECT]], %[[MIDDLE_BLOCK]] ], [ [[SEL:%.*]], %[[LOOP1_INC]] ]
; CHECK-NEXT: [[TMP9:%.*]] = uitofp nneg i64 [[SEL_LCSSA]] to double
-; CHECK-NEXT: [[TMP21:%.*]] = sub i64 add (i64 ptrtoaddr (ptr @end to i64), i64 -48), [[TMP0]]
-; CHECK-NEXT: [[TMP27:%.*]] = udiv i64 [[TMP21]], 48
-; CHECK-NEXT: [[TMP28:%.*]] = add nuw nsw i64 [[TMP27]], 1
-; CHECK-NEXT: [[MIN_ITERS_CHECK18:%.*]] = icmp ult i64 [[TMP21]], 144
-; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK18]], label %[[LOOP2_BODY_PREHEADER:.*]], label %[[VECTOR_MEMCHECK:.*]]
-; CHECK: [[VECTOR_MEMCHECK]]:
-; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[BASE]], i64 8
-; CHECK-NEXT: [[SCEVGEP16:%.*]] = getelementptr i8, ptr [[CMP]], i64 8
-; CHECK-NEXT: [[BOUND0:%.*]] = icmp ult ptr [[BASE]], [[SCEVGEP16]]
-; CHECK-NEXT: [[BOUND1:%.*]] = icmp ult ptr [[CMP]], [[SCEVGEP]]
-; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
-; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label %[[LOOP2_BODY_PREHEADER]], label %[[VECTOR_PH19:.*]]
-; CHECK: [[VECTOR_PH19]]:
-; CHECK-NEXT: [[N_VEC21:%.*]] = and i64 [[TMP28]], 1152921504606846974
-; CHECK-NEXT: [[BROADCAST_SPLATINSERT22:%.*]] = insertelement <2 x double> poison, double [[TMP9]], i64 0
-; CHECK-NEXT: [[TMP10:%.*]] = mul i64 [[N_VEC21]], 48
-; CHECK-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[TMP10]]
-; CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr [[CMP]], align 8, !alias.scope [[META3:![0-9]+]]
-; CHECK-NEXT: [[BROADCAST_SPLATINSERT24:%.*]] = insertelement <2 x i64> poison, i64 [[TMP12]], i64 0
-; CHECK-NEXT: [[TMP13:%.*]] = uitofp <2 x i64> [[BROADCAST_SPLATINSERT24]] to <2 x double>
-; CHECK-NEXT: [[TMP14:%.*]] = fmul nnan <2 x double> [[BROADCAST_SPLATINSERT22]], [[TMP13]]
-; CHECK-NEXT: [[TMP15:%.*]] = fcmp ugt <2 x double> [[TMP14]], zeroinitializer
-; CHECK-NEXT: [[TMP16:%.*]] = shufflevector <2 x i1> [[TMP15]], <2 x i1> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP17:%.*]] = freeze <2 x i1> [[TMP16]]
-; CHECK-NEXT: [[TMP18:%.*]] = bitcast <2 x i1> [[TMP17]] to i2
-; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i2 [[TMP18]], 0
-; CHECK-NEXT: [[BROADCAST_SPLATINSERT26:%.*]] = insertelement <2 x i64> poison, i64 [[TMP0]], i64 0
-; CHECK-NEXT: [[BROADCAST_SPLAT27:%.*]] = shufflevector <2 x i64> [[BROADCAST_SPLATINSERT26]], <2 x i64> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP19:%.*]] = bitcast <2 x i1> [[TMP17]] to i2
-; CHECK-NEXT: [[DOTNOT39:%.*]] = icmp eq i2 [[TMP19]], 0
-; CHECK-NEXT: br label %[[VECTOR_BODY28:.*]]
-; CHECK: [[VECTOR_BODY28]]:
-; CHECK-NEXT: [[INDEX29:%.*]] = phi i64 [ 0, %[[VECTOR_PH19]] ], [ [[INDEX_NEXT33:%.*]], %[[TMP22:.*]] ]
-; CHECK-NEXT: [[VEC_PHI30:%.*]] = phi <2 x i64> [ [[BROADCAST_SPLAT27]], %[[VECTOR_PH19]] ], [ [[TMP24:%.*]], %[[TMP22]] ]
-; CHECK-NEXT: [[TMP20:%.*]] = phi <2 x i1> [ zeroinitializer, %[[VECTOR_PH19]] ], [ [[TMP23:%.*]], %[[TMP22]] ]
-; CHECK-NEXT: br i1 [[DOTNOT39]], label %[[TMP22]], label %[[BB21:.*]]
-; CHECK: [[BB21]]:
-; CHECK-NEXT: store i64 0, ptr [[BASE]], align 8, !alias.scope [[META6:![0-9]+]], !noalias [[META3]]
-; CHECK-NEXT: br label %[[TMP22]]
-; CHECK: [[TMP22]]:
-; CHECK-NEXT: [[TMP23]] = select i1 [[DOTNOT]], <2 x i1> [[TMP20]], <2 x i1> [[TMP17]]
-; CHECK-NEXT: [[TMP24]] = select i1 [[DOTNOT]], <2 x i64> [[VEC_PHI30]], <2 x i64> zeroinitializer
-; CHECK-NEXT: [[INDEX_NEXT33]] = add nuw i64 [[INDEX29]], 2
-; CHECK-NEXT: [[TMP25:%.*]] = icmp eq i64 [[INDEX_NEXT33]], [[N_VEC21]]
-; CHECK-NEXT: br i1 [[TMP25]], label %[[MIDDLE_BLOCK34:.*]], label %[[VECTOR_BODY28]], !llvm.loop [[LOOP8:![0-9]+]]
-; CHECK: [[MIDDLE_BLOCK34]]:
-; CHECK-NEXT: [[TMP26:%.*]] = tail call i64 @llvm.experimental.vector.extract.last.active.v2i64(<2 x i64> [[TMP24]], <2 x i1> [[TMP23]], i64 [[TMP0]])
-; CHECK-NEXT: [[CMP_N35:%.*]] = icmp eq i64 [[TMP28]], [[N_VEC21]]
-; CHECK-NEXT: br i1 [[CMP_N35]], label %[[RET]], label %[[LOOP2_BODY_PREHEADER]]
-; CHECK: [[LOOP2_BODY_PREHEADER]]:
-; CHECK-NEXT: [[RES12_PH:%.*]] = phi i64 [ [[TMP0]], %[[VECTOR_MEMCHECK]] ], [ [[TMP0]], %[[LOOP2_BODY_LR_PH]] ], [ [[TMP26]], %[[MIDDLE_BLOCK34]] ]
-; CHECK-NEXT: [[IT2_010_PH:%.*]] = phi ptr [ [[BASE]], %[[VECTOR_MEMCHECK]] ], [ [[BASE]], %[[LOOP2_BODY_LR_PH]] ], [ [[TMP11]], %[[MIDDLE_BLOCK34]] ]
+; CHECK-NEXT: [[CMP_VAL_I_PRE11:%.*]] = load i64, ptr [[CMP]], align 8
; CHECK-NEXT: br label %[[LOOP2_BODY:.*]]
; CHECK: [[LOOP1_INC]]:
; CHECK-NEXT: [[R8:%.*]] = phi i64 [ [[SEL]], %[[LOOP1_INC]] ], [ [[R8_PH]], %[[LOOP1_INC_PREHEADER41]] ]
@@ -216,26 +165,28 @@ define i64 @cse_two_guards(ptr %base, i64 %n, ptr %cmp) {
; CHECK-NEXT: [[SEL]] = select i1 [[GT]], i64 0, i64 [[R8]]
; CHECK-NEXT: [[NEXT_I]] = getelementptr nusw nuw i8, ptr [[IT1_07]], i64 48
; CHECK-NEXT: [[NE_I_NOT:%.*]] = icmp eq ptr [[NEXT_I]], @end
-; CHECK-NEXT: br i1 [[NE_I_NOT]], label %[[LOOP2_BODY_LR_PH]], label %[[LOOP1_INC]], !llvm.loop [[LOOP9:![0-9]+]]
+; CHECK-NEXT: br i1 [[NE_I_NOT]], label %[[LOOP2_BODY_LR_PH]], label %[[LOOP1_INC]], !llvm.loop [[LOOP3:![0-9]+]]
; CHECK: [[RET]]:
-; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[TMP0]], %[[ENTRY]] ], [ [[TMP26]], %[[MIDDLE_BLOCK34]] ], [ [[RES11:%.*]], %[[LOOP2_INC:.*]] ]
+; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[TMP0]], %[[ENTRY]] ], [ [[RES14:%.*]], %[[LOOP2_INC:.*]] ]
; CHECK-NEXT: ret i64 [[RES]]
; CHECK: [[LOOP2_BODY]]:
-; CHECK-NEXT: [[RES12:%.*]] = phi i64 [ [[RES11]], %[[LOOP2_INC]] ], [ [[RES12_PH]], %[[LOOP2_BODY_PREHEADER]] ]
-; CHECK-NEXT: [[IT2_010:%.*]] = phi ptr [ [[NEXT_I5:%.*]], %[[LOOP2_INC]] ], [ [[IT2_010_PH]], %[[LOOP2_BODY_PREHEADER]] ]
-; CHECK-NEXT: [[CMP_VAL_I:%.*]] = load i64, ptr [[CMP]], align 8
+; CHECK-NEXT: [[RES15:%.*]] = phi i64 [ [[TMP0]], %[[LOOP2_BODY_LR_PH]] ], [ [[RES14]], %[[LOOP2_INC]] ]
+; CHECK-NEXT: [[CMP_VAL_I:%.*]] = phi i64 [ [[CMP_VAL_I_PRE11]], %[[LOOP2_BODY_LR_PH]] ], [ [[CMP_VAL_I12:%.*]...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/228033
More information about the llvm-commits
mailing list