Skip to content

Commit 8a6248b

Browse files
authored
[SimplifyCFG] Don't separate a load/store from its gep during sinking (#102318)
If we can sink the a load/store, but not the gep producing its pointer operand, don't sink the load/store either. This may prevent the gep from being folded into an addressing mode, and may also negatively affect further analysis. Fixes #96838.
1 parent 5a4c6f9 commit 8a6248b

File tree

2 files changed

+52
-26
lines changed

2 files changed

+52
-26
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2477,6 +2477,16 @@ static bool sinkCommonCodeFromPredecessors(BasicBlock *BB,
24772477
bool followedByDeoptOrUnreachable = IsBlockFollowedByDeoptOrUnreachable(BB);
24782478

24792479
if (!followedByDeoptOrUnreachable) {
2480+
// Check whether this is the pointer operand of a load/store.
2481+
auto IsMemOperand = [](Use &U) {
2482+
auto *I = cast<Instruction>(U.getUser());
2483+
if (isa<LoadInst>(I))
2484+
return U.getOperandNo() == LoadInst::getPointerOperandIndex();
2485+
if (isa<StoreInst>(I))
2486+
return U.getOperandNo() == StoreInst::getPointerOperandIndex();
2487+
return false;
2488+
};
2489+
24802490
// Okay, we *could* sink last ScanIdx instructions. But how many can we
24812491
// actually sink before encountering instruction that is unprofitable to
24822492
// sink?
@@ -2488,6 +2498,13 @@ static bool sinkCommonCodeFromPredecessors(BasicBlock *BB,
24882498
return InstructionsToSink.contains(V);
24892499
})) {
24902500
++NumPHIInsts;
2501+
// Do not separate a load/store from the gep producing the address.
2502+
// The gep can likely be folded into the load/store as an addressing
2503+
// mode. Additionally, a load of a gep is easier to analyze than a
2504+
// load of a phi.
2505+
if (IsMemOperand(U) &&
2506+
any_of(It->second, [](Value *V) { return isa<GEPOperator>(V); }))
2507+
return false;
24912508
// FIXME: this check is overly optimistic. We may end up not sinking
24922509
// said instruction, due to the very same profitability check.
24932510
// See @creating_too_many_phis in sink-common-code.ll.

llvm/test/Transforms/SimplifyCFG/X86/sink-common-code.ll

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,14 @@ define i32 @test10(i1 zeroext %flag, i32 %x, ptr %y, ptr %s) {
304304
; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
305305
; CHECK: if.then:
306306
; CHECK-NEXT: call void @bar(i32 5)
307+
; CHECK-NEXT: store volatile i32 [[X:%.*]], ptr [[S:%.*]], align 4
307308
; CHECK-NEXT: br label [[IF_END:%.*]]
308309
; CHECK: if.else:
309310
; CHECK-NEXT: call void @bar(i32 6)
310-
; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S:%.*]], i32 0, i32 1
311+
; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S]], i32 0, i32 1
312+
; CHECK-NEXT: store volatile i32 [[X]], ptr [[GEPB]], align 4
311313
; CHECK-NEXT: br label [[IF_END]]
312314
; CHECK: if.end:
313-
; CHECK-NEXT: [[GEPB_SINK:%.*]] = phi ptr [ [[GEPB]], [[IF_ELSE]] ], [ [[S]], [[IF_THEN]] ]
314-
; CHECK-NEXT: store volatile i32 [[X:%.*]], ptr [[GEPB_SINK]], align 4
315315
; CHECK-NEXT: ret i32 1
316316
;
317317
entry:
@@ -518,23 +518,25 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
518518
!11 = !DILocation(line: 1, column: 14, scope: !8)
519519

520520

521-
; The load should be commoned.
521+
; The load should not be commoned, as it will get separated from the GEP
522+
; instruction producing the address.
522523
define i32 @test15(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, ptr %s) {
523524
; CHECK-LABEL: @test15(
524525
; CHECK-NEXT: entry:
525526
; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
526527
; CHECK: if.then:
527528
; CHECK-NEXT: call void @bar(i32 1)
529+
; CHECK-NEXT: [[SV1:%.*]] = load i32, ptr [[S:%.*]], align 4
528530
; CHECK-NEXT: br label [[IF_END:%.*]]
529531
; CHECK: if.else:
530532
; CHECK-NEXT: call void @bar(i32 4)
531-
; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S:%.*]], i32 0, i32 1
533+
; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], ptr [[S]], i32 0, i32 1
534+
; CHECK-NEXT: [[SV2:%.*]] = load i32, ptr [[GEPB]], align 4
532535
; CHECK-NEXT: br label [[IF_END]]
533536
; CHECK: if.end:
534-
; CHECK-NEXT: [[GEPB_SINK:%.*]] = phi ptr [ [[GEPB]], [[IF_ELSE]] ], [ [[S]], [[IF_THEN]] ]
537+
; CHECK-NEXT: [[SV2_SINK:%.*]] = phi i32 [ [[SV2]], [[IF_ELSE]] ], [ [[SV1]], [[IF_THEN]] ]
535538
; CHECK-NEXT: [[DOTSINK:%.*]] = phi i64 [ 57, [[IF_ELSE]] ], [ 56, [[IF_THEN]] ]
536-
; CHECK-NEXT: [[SV2:%.*]] = load i32, ptr [[GEPB_SINK]], align 4
537-
; CHECK-NEXT: [[EXT2:%.*]] = zext i32 [[SV2]] to i64
539+
; CHECK-NEXT: [[EXT2:%.*]] = zext i32 [[SV2_SINK]] to i64
538540
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[EXT2]], [[DOTSINK]]
539541
; CHECK-NEXT: ret i32 1
540542
;
@@ -1803,17 +1805,19 @@ define i64 @multi_use_in_block_inconsistent(i1 %cond, ptr %p, i64 %a, i64 %b) {
18031805
; CHECK: if:
18041806
; CHECK-NEXT: call void @dummy()
18051807
; CHECK-NEXT: [[GEP1_A:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]
1808+
; CHECK-NEXT: [[V_A:%.*]] = load i64, ptr [[GEP1_A]], align 8
1809+
; CHECK-NEXT: [[GEP2_A:%.*]] = getelementptr i8, ptr [[GEP1_A]], i64 [[V_A]]
18061810
; CHECK-NEXT: br label [[JOIN:%.*]]
18071811
; CHECK: else:
18081812
; CHECK-NEXT: [[GEP1_B:%.*]] = getelementptr i8, ptr [[P]], i64 [[A]]
1813+
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[P]], align 8
1814+
; CHECK-NEXT: [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B]], i64 [[V_B]]
18091815
; CHECK-NEXT: br label [[JOIN]]
18101816
; CHECK: join:
1811-
; CHECK-NEXT: [[P_SINK:%.*]] = phi ptr [ [[P]], [[ELSE]] ], [ [[GEP1_A]], [[IF]] ]
1812-
; CHECK-NEXT: [[GEP1_B_SINK:%.*]] = phi ptr [ [[GEP1_B]], [[ELSE]] ], [ [[GEP1_A]], [[IF]] ]
1813-
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[P_SINK]], align 8
1814-
; CHECK-NEXT: [[GEP2_B:%.*]] = getelementptr i8, ptr [[GEP1_B_SINK]], i64 [[V_B]]
1815-
; CHECK-NEXT: call void @use.ptr(ptr [[GEP2_B]])
1816-
; CHECK-NEXT: ret i64 [[V_B]]
1817+
; CHECK-NEXT: [[PHI1:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
1818+
; CHECK-NEXT: [[PHI2:%.*]] = phi ptr [ [[GEP2_A]], [[IF]] ], [ [[GEP2_B]], [[ELSE]] ]
1819+
; CHECK-NEXT: call void @use.ptr(ptr [[PHI2]])
1820+
; CHECK-NEXT: ret i64 [[PHI1]]
18171821
;
18181822
br i1 %cond, label %if, label %else
18191823

@@ -1873,14 +1877,15 @@ define i64 @load_with_non_sunk_gep_both(i1 %cond, ptr %p.a, ptr %p.b, i64 %a, i6
18731877
; CHECK: if:
18741878
; CHECK-NEXT: call void @dummy()
18751879
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
1880+
; CHECK-NEXT: [[V_A:%.*]] = load i64, ptr [[GEP_A]], align 8
18761881
; CHECK-NEXT: br label [[JOIN:%.*]]
18771882
; CHECK: else:
18781883
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
1884+
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[GEP_B]], align 8
18791885
; CHECK-NEXT: br label [[JOIN]]
18801886
; CHECK: join:
1881-
; CHECK-NEXT: [[GEP_B_SINK:%.*]] = phi ptr [ [[GEP_B]], [[ELSE]] ], [ [[GEP_A]], [[IF]] ]
1882-
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[GEP_B_SINK]], align 8
1883-
; CHECK-NEXT: ret i64 [[V_B]]
1887+
; CHECK-NEXT: [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
1888+
; CHECK-NEXT: ret i64 [[V]]
18841889
;
18851890
br i1 %cond, label %if, label %else
18861891

@@ -1905,14 +1910,15 @@ define i64 @load_with_non_sunk_gep_left(i1 %cond, ptr %p.a, ptr %p.b, i64 %b) {
19051910
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
19061911
; CHECK: if:
19071912
; CHECK-NEXT: call void @dummy()
1913+
; CHECK-NEXT: [[V_A:%.*]] = load i64, ptr [[P_A:%.*]], align 8
19081914
; CHECK-NEXT: br label [[JOIN:%.*]]
19091915
; CHECK: else:
19101916
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
1917+
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[GEP_B]], align 8
19111918
; CHECK-NEXT: br label [[JOIN]]
19121919
; CHECK: join:
1913-
; CHECK-NEXT: [[GEP_B_SINK:%.*]] = phi ptr [ [[GEP_B]], [[ELSE]] ], [ [[P_A:%.*]], [[IF]] ]
1914-
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[GEP_B_SINK]], align 8
1915-
; CHECK-NEXT: ret i64 [[V_B]]
1920+
; CHECK-NEXT: [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
1921+
; CHECK-NEXT: ret i64 [[V]]
19161922
;
19171923
br i1 %cond, label %if, label %else
19181924

@@ -1933,15 +1939,18 @@ join:
19331939

19341940
define i64 @load_with_non_sunk_gep_right(i1 %cond, ptr %p.a, ptr %p.b, i64 %a) {
19351941
; CHECK-LABEL: @load_with_non_sunk_gep_right(
1936-
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
1942+
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
19371943
; CHECK: if:
19381944
; CHECK-NEXT: call void @dummy()
19391945
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
1946+
; CHECK-NEXT: [[V_A:%.*]] = load i64, ptr [[GEP_A]], align 8
1947+
; CHECK-NEXT: br label [[JOIN:%.*]]
1948+
; CHECK: else:
1949+
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[P_B:%.*]], align 8
19401950
; CHECK-NEXT: br label [[JOIN]]
19411951
; CHECK: join:
1942-
; CHECK-NEXT: [[P_B_SINK:%.*]] = phi ptr [ [[GEP_A]], [[IF]] ], [ [[P_B:%.*]], [[TMP0:%.*]] ]
1943-
; CHECK-NEXT: [[V_B:%.*]] = load i64, ptr [[P_B_SINK]], align 8
1944-
; CHECK-NEXT: ret i64 [[V_B]]
1952+
; CHECK-NEXT: [[V:%.*]] = phi i64 [ [[V_A]], [[IF]] ], [ [[V_B]], [[ELSE]] ]
1953+
; CHECK-NEXT: ret i64 [[V]]
19451954
;
19461955
br i1 %cond, label %if, label %else
19471956

@@ -1966,13 +1975,13 @@ define void @store_with_non_sunk_gep(i1 %cond, ptr %p.a, ptr %p.b, i64 %a, i64 %
19661975
; CHECK: if:
19671976
; CHECK-NEXT: call void @dummy()
19681977
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr i8, ptr [[P_A:%.*]], i64 [[A:%.*]]
1978+
; CHECK-NEXT: store i64 0, ptr [[GEP_A]], align 8
19691979
; CHECK-NEXT: br label [[JOIN:%.*]]
19701980
; CHECK: else:
19711981
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr i8, ptr [[P_B:%.*]], i64 [[B:%.*]]
1982+
; CHECK-NEXT: store i64 0, ptr [[GEP_B]], align 8
19721983
; CHECK-NEXT: br label [[JOIN]]
19731984
; CHECK: join:
1974-
; CHECK-NEXT: [[GEP_B_SINK:%.*]] = phi ptr [ [[GEP_B]], [[ELSE]] ], [ [[GEP_A]], [[IF]] ]
1975-
; CHECK-NEXT: store i64 0, ptr [[GEP_B_SINK]], align 8
19761985
; CHECK-NEXT: ret void
19771986
;
19781987
br i1 %cond, label %if, label %else

0 commit comments

Comments
 (0)