[IndVars] Simplify instructions after replacing header phi with preheader value

After replacing a loop phi with the preheader value, it's usually
possible to simplify some of the using instructions, so do that as
part of replaceLoopPHINodesWithPreheaderValues().

Doing this as part of IndVars is valuable, because it may make GEPs
in the loop have constant offsets and allow the following SROA run
to succeed (as demonstrated in the PhaseOrdering test).

Differential Revision: https://reviews.llvm.org/D129293
This commit is contained in:
Nikita Popov 2022-07-07 17:04:37 +02:00
parent ee4d09b8bb
commit af49bed933
13 changed files with 41 additions and 65 deletions

View File

@ -1311,11 +1311,34 @@ static void replaceLoopPHINodesWithPreheaderValues(
assert(L->isLoopSimplifyForm() && "Should only do it in simplify form!");
auto *LoopPreheader = L->getLoopPreheader();
auto *LoopHeader = L->getHeader();
SmallVector<Instruction *> Worklist;
for (auto &PN : LoopHeader->phis()) {
auto *PreheaderIncoming = PN.getIncomingValueForBlock(LoopPreheader);
for (User *U : PN.users())
Worklist.push_back(cast<Instruction>(U));
PN.replaceAllUsesWith(PreheaderIncoming);
DeadInsts.emplace_back(&PN);
}
// Replacing with the preheader value will often allow IV users to simplify
// (especially if the preheader value is a constant).
SmallPtrSet<Instruction *, 16> Visited;
while (!Worklist.empty()) {
auto *I = cast<Instruction>(Worklist.pop_back_val());
if (!Visited.insert(I).second)
continue;
// Don't simplify instructions outside the loop.
if (!L->contains(I))
continue;
if (Value *Res = simplifyInstruction(I, I->getModule()->getDataLayout())) {
for (User *U : I->users())
Worklist.push_back(cast<Instruction>(U));
I->replaceAllUsesWith(Res);
DeadInsts.emplace_back(I);
}
}
}
static void replaceWithInvariantCond(

View File

@ -14,13 +14,10 @@ define i32 @testDiv(i8* %p, i64* %p1) {
; CHECK: general_case24:
; CHECK-NEXT: br i1 false, label [[LOOP2_PREHEADER:%.*]], label [[LOOP2_EXIT]]
; CHECK: loop2.preheader:
; CHECK-NEXT: [[TMP0:%.*]] = udiv i64 14, [[INDVARS_IV]]
; CHECK-NEXT: [[TMP1:%.*]] = udiv i64 60392, [[TMP0]]
; CHECK-NEXT: br label [[LOOP2:%.*]]
; CHECK: loop2:
; CHECK-NEXT: [[INDVARS_IV_NEXT2:%.*]] = add nuw nsw i64 [[TMP1]], -1
; CHECK-NEXT: [[I4:%.*]] = load atomic i64, i64* [[P1:%.*]] unordered, align 8
; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], [[INDVARS_IV_NEXT2]]
; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], -1
; CHECK-NEXT: store atomic i64 [[I6]], i64* [[P1]] unordered, align 8
; CHECK-NEXT: br i1 true, label [[LOOP2_EXIT_LOOPEXIT:%.*]], label [[LOOP2]]
; CHECK: loop2.exit.loopexit:

View File

@ -15,24 +15,20 @@ define i1 @kill_backedge_and_phis(i8* align 1 %lhs, i8* align 1 %rhs, i32 %len)
; CHECK: loop_preheader:
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %iv.next = add nuw nsw i32 0, 1
; CHECK-NEXT: %left_ptr = getelementptr inbounds i8, i8* %lhs, i32 0
; CHECK-NEXT: %right_ptr = getelementptr inbounds i8, i8* %rhs, i32 0
; CHECK-NEXT: %result = call i1 @foo(i8* %left_ptr, i8* %right_ptr)
; CHECK-NEXT: %result = call i1 @foo(i8* %lhs, i8* %rhs)
; CHECK-NEXT: br i1 %result, label %exiting_1, label %exit.loopexit
; CHECK: exiting_1:
; CHECK-NEXT: %iv.wide.is_not_zero = icmp ne i64 0, 0
; CHECK-NEXT: br i1 false, label %exiting_2, label %exit.loopexit
; CHECK: exiting_2:
; CHECK-NEXT: %bar_ret = call i1 @bar()
; CHECK-NEXT: br i1 %bar_ret, label %exit.loopexit, label %exiting_3
; CHECK: exiting_3:
; CHECK-NEXT: %baz_ret = call i1 @baz()
; CHECK-NEXT: %continue = icmp ne i32 %iv.next, %len
; CHECK-NEXT: %continue = icmp ne i32 1, %len
; CHECK-NEXT: %or.cond = select i1 %baz_ret, i1 %continue, i1 false
; CHECK-NEXT: br i1 %or.cond, label %loop, label %exit.loopexit
; CHECK: exit.loopexit:
; CHECK-NEXT: %val.ph = phi i1 [ %baz_ret, %exiting_3 ], [ %bar_ret, %exiting_2 ], [ %iv.wide.is_not_zero, %exiting_1 ], [ %result, %loop ]
; CHECK-NEXT: %val.ph = phi i1 [ %baz_ret, %exiting_3 ], [ %bar_ret, %exiting_2 ], [ false, %exiting_1 ], [ %result, %loop ]
; CHECK-NEXT: br label %exit
; CHECK: exit:
; CHECK-NEXT: %val = phi i1 [ false, %entry ], [ %val.ph, %exit.loopexit ]
@ -88,12 +84,10 @@ define i1 @siblings(i8* align 1 %lhs, i8* align 1 %rhs, i32 %len) {
; CHECK: weird_loop:
; CHECK-NEXT: %weird.iv = phi i32 [ %weird.iv.next, %weird_loop ], [ 0, %weird_loop.preheader ]
; CHECK-NEXT: %weird.iv.next = add i32 %weird.iv, 1
; CHECK-NEXT: %weird.iv.wide = zext i32 %weird.iv to i64
; CHECK-NEXT: %weird.cond = call i1 @bar()
; CHECK-NEXT: br i1 %weird.cond, label %weird_loop, label %loop.preheader
; CHECK: loop.preheader:
; CHECK-NEXT: %weird.iv.lcssa = phi i32 [ %weird.iv, %weird_loop ]
; CHECK-NEXT: %weird.iv.wide.lcssa = phi i64 [ %weird.iv.wide, %weird_loop ]
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %iv.next = add i32 %weird.iv.lcssa, 1
@ -102,7 +96,6 @@ define i1 @siblings(i8* align 1 %lhs, i8* align 1 %rhs, i32 %len) {
; CHECK-NEXT: %result = call i1 @foo(i8* %left_ptr, i8* %right_ptr)
; CHECK-NEXT: br i1 %result, label %exiting_1, label %exit.loopexit
; CHECK: exiting_1:
; CHECK-NEXT: %iv.wide.is_not_zero = icmp ne i64 %weird.iv.wide.lcssa, %weird.iv.wide.lcssa
; CHECK-NEXT: br i1 false, label %exiting_2, label %exit.loopexit
; CHECK: exiting_2:
; CHECK-NEXT: %bar_ret = call i1 @bar()
@ -113,7 +106,7 @@ define i1 @siblings(i8* align 1 %lhs, i8* align 1 %rhs, i32 %len) {
; CHECK-NEXT: %or.cond = select i1 %baz_ret, i1 %continue, i1 false
; CHECK-NEXT: br i1 %or.cond, label %loop, label %exit.loopexit
; CHECK: exit.loopexit:
; CHECK-NEXT: %val.ph = phi i1 [ %baz_ret, %exiting_3 ], [ %bar_ret, %exiting_2 ], [ %iv.wide.is_not_zero, %exiting_1 ], [ %result, %loop ]
; CHECK-NEXT: %val.ph = phi i1 [ %baz_ret, %exiting_3 ], [ %bar_ret, %exiting_2 ], [ false, %exiting_1 ], [ %result, %loop ]
; CHECK-NEXT: br label %exit
; CHECK: exit:
; CHECK-NEXT: %val = phi i1 [ false, %entry ], [ %val.ph, %exit.loopexit ]

View File

@ -14,10 +14,8 @@ define void @foo() {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb3:
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @global, i64 0, i64 2), i64 -1
; CHECK-NEXT: [[TMP6:%.*]] = load i8, i8* [[TMP4]], align 1
; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i8* [[TMP4]], getelementptr inbounds ([0 x i8], [0 x i8]* @global, i64 0, i64 500)
; CHECK-NEXT: br i1 [[TMP5]], label [[BB7:%.*]], label [[BB11:%.*]]
; CHECK-NEXT: [[TMP6:%.*]] = load i8, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @global, i64 0, i64 1), align 1
; CHECK-NEXT: br i1 false, label [[BB7:%.*]], label [[BB11:%.*]]
; CHECK: bb7:
; CHECK-NEXT: [[TMP8:%.*]] = zext i8 [[TMP6]] to i64
; CHECK-NEXT: br i1 true, label [[BB11]], label [[BB3]]

View File

@ -89,8 +89,7 @@ define void @test4() nounwind {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BB:%.*]]
; CHECK: bb:
; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 40 to double
; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @foo(double [[INDVAR_CONV]]) #[[ATTR0]]
; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @foo(double 4.000000e+01) #[[ATTR0]]
; CHECK-NEXT: br i1 false, label [[BB]], label [[RETURN:%.*]]
; CHECK: return:
; CHECK-NEXT: ret void

View File

@ -9,8 +9,6 @@ define void @PR18642(i32 %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 0, i32 undef)
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[SMAX]], 1
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: inner.header:
; CHECK-NEXT: br i1 false, label [[INNER_LATCH:%.*]], label [[OUTER_LATCH:%.*]]
@ -19,7 +17,7 @@ define void @PR18642(i32 %x) {
; CHECK: outer.latch:
; CHECK-NEXT: br i1 false, label [[OUTER_HEADER]], label [[EXIT_LOOPEXIT1:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[INC_LCSSA:%.*]] = phi i32 [ [[TMP0]], [[INNER_LATCH]] ]
; CHECK-NEXT: [[INC_LCSSA:%.*]] = phi i32 [ -2147483648, [[INNER_LATCH]] ]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit.loopexit1:
; CHECK-NEXT: br label [[EXIT]]

View File

@ -474,7 +474,6 @@ define void @phiUsesTrunc() nounwind {
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 1 to i32
; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br i1 undef, label [[IF_THEN33:%.*]], label [[FOR_INC:%.*]]
@ -486,7 +485,7 @@ define void @phiUsesTrunc() nounwind {
; CHECK-NEXT: call void @use64(i64 1)
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[KMIN_1:%.*]] = phi i32 [ [[TMP0]], [[IF_THEN33]] ], [ 0, [[IF_THEN]] ], [ [[TMP0]], [[IF_THEN97]] ], [ 0, [[IF_ELSE]] ]
; CHECK-NEXT: [[KMIN_1:%.*]] = phi i32 [ 1, [[IF_THEN33]] ], [ 0, [[IF_THEN]] ], [ 1, [[IF_THEN97]] ], [ 0, [[IF_ELSE]] ]
; CHECK-NEXT: call void @use32(i32 [[KMIN_1]])
; CHECK-NEXT: br i1 false, label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
; CHECK: for.end.loopexit:

View File

@ -11,19 +11,15 @@ declare void @abort() #1
define i32 @main() {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_PROMOTED13:%.*]] = load i32, i32* @a, align 4
; CHECK-NEXT: br label [[FOR_COND1_PREHEADER:%.*]]
; CHECK: for.cond1.preheader:
; CHECK-NEXT: br label [[FOR_BODY3:%.*]]
; CHECK: for.body3:
; CHECK-NEXT: [[ADD:%.*]] = sub i32 0, 1
; CHECK-NEXT: [[OR:%.*]] = or i32 [[A_PROMOTED13]], [[ADD]]
; CHECK-NEXT: br i1 false, label [[FOR_BODY3]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: [[OR_LCSSA:%.*]] = phi i32 [ [[OR]], [[FOR_BODY3]] ]
; CHECK-NEXT: br i1 false, label [[FOR_COND1_PREHEADER]], label [[FOR_END6:%.*]]
; CHECK: for.end6:
; CHECK-NEXT: [[OR_LCSSA_LCSSA:%.*]] = phi i32 [ [[OR_LCSSA]], [[FOR_END]] ]
; CHECK-NEXT: [[OR_LCSSA_LCSSA:%.*]] = phi i32 [ -1, [[FOR_END]] ]
; CHECK-NEXT: store i32 [[OR_LCSSA_LCSSA]], i32* @a, align 4
; CHECK-NEXT: [[CMP7:%.*]] = icmp eq i32 [[OR_LCSSA_LCSSA]], -1
; CHECK-NEXT: br i1 [[CMP7]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]

View File

@ -10,12 +10,11 @@ define void @test() {
; CHECK: bb1:
; CHECK-NEXT: br label [[BB2]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ -9, [[BB:%.*]] ], [ [[TMP6:%.*]], [[BB1:%.*]] ]
; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ -9, [[BB:%.*]] ], [ -10, [[BB1:%.*]] ]
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb3:
; CHECK-NEXT: br i1 false, label [[BB5:%.*]], label [[BB12:%.*]]
; CHECK: bb5:
; CHECK-NEXT: [[TMP6]] = add nsw i32 -9, -1
; CHECK-NEXT: br i1 undef, label [[BB8:%.*]], label [[BB9:%.*]]
; CHECK: bb8:
; CHECK-NEXT: br label [[BB10:%.*]]

View File

@ -354,8 +354,7 @@ define void @test5(i8* %header, i32 %conv, i8 %n) {
; CHECK-NEXT: br i1 [[CMP7_I4]], label [[FOR_INNER_2]], label [[FOR_INC:%.*]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC_I3_LCSSA:%.*]] = phi i32 [ [[INC_I3]], [[FOR_INNER_2]] ]
; CHECK-NEXT: [[ADD71:%.*]] = add i32 0, [[INC_I_LCSSA]]
; CHECK-NEXT: [[ADD85:%.*]] = add i32 [[ADD71]], [[INC_I3_LCSSA]]
; CHECK-NEXT: [[ADD85:%.*]] = add i32 [[INC_I_LCSSA]], [[INC_I3_LCSSA]]
; CHECK-NEXT: br i1 false, label [[FOR_BODY]], label [[WHILE_COND_PREHEADER:%.*]]
; CHECK: while.cond.preheader:
; CHECK-NEXT: [[ADD85_LCSSA:%.*]] = phi i32 [ [[ADD85]], [[FOR_INC]] ]

View File

@ -9,17 +9,14 @@ define void @test() personality i32* ()* @snork {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB4:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[TMP1:%.*]], [[SMAX:%.*]]
; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB4]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP0]], [[BB1:%.*]] ]
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ undef, [[BB1:%.*]] ]
; CHECK-NEXT: ret void
; CHECK: bb4:
; CHECK-NEXT: [[SMAX]] = call i32 @llvm.smax.i32(i32 undef, i32 36)
; CHECK-NEXT: [[TMP6:%.*]] = invoke i32 @quux() [ "deopt"(i32 0, i32 0, i32 0, i32 180, i32 0, i32 25, i32 0, i32 7, i8* null, i32 7, i8* null, i32 7, i8* null, i32 3, i32 undef, i32 3, i32 undef, i32 7, i8* null, i32 3, i32 undef, i32 3, i32 undef, i32 3, i32 undef, i32 3, i32 undef, i32 4, double undef, i32 7, i8* null, i32 4, i64 undef, i32 7, i8* null, i32 0, i8 addrspace(1)* undef, i32 3, i32 undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 0, i8 addrspace(1)* undef, i32 7, i8* null) ]
; CHECK-NEXT: to label [[BB7:%.*]] unwind label [[BB15:%.*]]
; CHECK: bb7:
; CHECK-NEXT: [[TMP1]] = add i32 [[TMP6]], undef
; CHECK-NEXT: br label [[BB9:%.*]]
; CHECK: bb9:
; CHECK-NEXT: br i1 true, label [[BB1]], label [[BB9]]

View File

@ -10,11 +10,6 @@ define void @test() {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 112, -1
; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP3]], [[TMP3]]
; CHECK-NEXT: [[TMP6:%.*]] = mul nsw i32 11, -6
; CHECK-NEXT: [[TMP7:%.*]] = mul nsw i32 [[TMP6]], [[TMP5]]
; CHECK-NEXT: [[TMP8:%.*]] = add nuw nsw i32 [[TMP7]], 11
; CHECK-NEXT: [[TMP9:%.*]] = and i32 undef, 1
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP9]], 0
; CHECK-NEXT: br i1 [[TMP10]], label [[BB33_LOOPEXIT1:%.*]], label [[BB34_PREHEADER:%.*]]
@ -24,14 +19,10 @@ define void @test() {
; CHECK-NEXT: [[TMP2_LCSSA12:%.*]] = phi i32 [ 11, [[BB34]] ]
; CHECK-NEXT: br label [[BB33_LOOPEXIT:%.*]]
; CHECK: bb12:
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[TMP40:%.*]], 0
; CHECK-NEXT: br label [[BB14:%.*]]
; CHECK: bb14:
; CHECK-NEXT: br i1 true, label [[BB32:%.*]], label [[BB22:%.*]]
; CHECK: bb22:
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 4 to i32
; CHECK-NEXT: [[TMP23:%.*]] = or i32 [[TMP1]], undef
; CHECK-NEXT: [[TMP24:%.*]] = add i32 [[TMP23]], undef
; CHECK-NEXT: br i1 false, label [[BB42:%.*]], label [[BB25:%.*]]
; CHECK: bb25:
; CHECK-NEXT: br label [[BB31:%.*]]
@ -50,14 +41,10 @@ define void @test() {
; CHECK-NEXT: call void @use(i32 [[TMP210]])
; CHECK-NEXT: ret void
; CHECK: bb34:
; CHECK-NEXT: [[TMP36:%.*]] = xor i32 0, [[TMP8]]
; CHECK-NEXT: [[TMP38:%.*]] = add i32 [[TMP36]], undef
; CHECK-NEXT: [[TMP39:%.*]] = add i32 [[TMP38]], undef
; CHECK-NEXT: [[TMP40]] = sext i32 [[TMP39]] to i64
; CHECK-NEXT: br i1 false, label [[BB11]], label [[BB12:%.*]]
; CHECK: bb42:
; CHECK-NEXT: [[TMP24_LCSSA:%.*]] = phi i32 [ [[TMP24]], [[BB22]] ]
; CHECK-NEXT: [[TMP18_LCSSA4:%.*]] = phi i64 [ [[TMP0]], [[BB22]] ]
; CHECK-NEXT: [[TMP24_LCSSA:%.*]] = phi i32 [ undef, [[BB22]] ]
; CHECK-NEXT: [[TMP18_LCSSA4:%.*]] = phi i64 [ 0, [[BB22]] ]
; CHECK-NEXT: store atomic i64 [[TMP18_LCSSA4]], i64 addrspace(1)* undef unordered, align 8
; CHECK-NEXT: call void @use(i32 [[TMP24_LCSSA]])
; CHECK-NEXT: ret void

View File

@ -58,17 +58,8 @@ exit:
define i16 @test(i16 %arg) {
; CHECK-LABEL: @test(
; CHECK-NEXT: bb6.i.i.i:
; CHECK-NEXT: [[DATA_I:%.*]] = alloca [2 x i8], align 2
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr nonnull [[DATA_I]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[DATA_I]], i64 1
; CHECK-NEXT: [[TMP1:%.*]] = trunc i16 [[ARG:%.*]] to i8
; CHECK-NEXT: [[TMP2:%.*]] = lshr i16 [[ARG]], 8
; CHECK-NEXT: [[TMP3:%.*]] = trunc i16 [[TMP2]] to i8
; CHECK-NEXT: store i8 [[TMP3]], ptr [[DATA_I]], align 2
; CHECK-NEXT: store i8 [[TMP1]], ptr [[TMP0]], align 1
; CHECK-NEXT: [[DOTSROA_0_0_COPYLOAD_I:%.*]] = load i16, ptr [[DATA_I]], align 2
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr nonnull [[DATA_I]])
; CHECK-NEXT: ret i16 [[DOTSROA_0_0_COPYLOAD_I]]
; CHECK-NEXT: [[DATA_I_SROA_0_0_INSERT_INSERT:%.*]] = call i16 @llvm.bswap.i16(i16 [[ARG:%.*]])
; CHECK-NEXT: ret i16 [[DATA_I_SROA_0_0_INSERT_INSERT]]
;
%ret = call i16 @helper(i16 %arg, i64 1)
ret i16 %ret