[LICM][SCCP] Regenerate test checks (NFC)

This commit is contained in:
Nikita Popov 2021-07-22 21:06:39 +02:00
parent f719dff043
commit 4294657bd5
5 changed files with 746 additions and 408 deletions

View File

@ -1,3 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -licm -S | FileCheck %s ; RUN: opt < %s -licm -S | FileCheck %s
; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop(licm)' < %s -S | FileCheck %s ; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop(licm)' < %s -S | FileCheck %s
@ -5,6 +6,27 @@ target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i386-pc-windows-msvc18.0.0" target triple = "i386-pc-windows-msvc18.0.0"
define void @test1(i32* %s, i1 %b) personality i32 (...)* @__CxxFrameHandler3 { define void @test1(i32* %s, i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @pure_computation()
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: br i1 [[B:%.*]], label [[TRY_CONT_LOOPEXIT:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[WHILE_COND]] unwind label [[CATCH_DISPATCH:%.*]]
; CHECK: catch.dispatch:
; CHECK-NEXT: [[DOTLCSSA1:%.*]] = phi i32 [ [[TMP0]], [[WHILE_BODY]] ]
; CHECK-NEXT: [[CS:%.*]] = catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
; CHECK-NEXT: [[CP:%.*]] = catchpad within [[CS]] [i8* null, i32 64, i8* null]
; CHECK-NEXT: store i32 [[DOTLCSSA1]], i32* [[S:%.*]], align 4
; CHECK-NEXT: catchret from [[CP]] to label [[TRY_CONT:%.*]]
; CHECK: try.cont.loopexit:
; CHECK-NEXT: br label [[TRY_CONT]]
; CHECK: try.cont:
; CHECK-NEXT: ret void
;
entry: entry:
br label %while.cond br label %while.cond
@ -29,11 +51,23 @@ try.cont: ; preds = %catch, %while.cond
ret void ret void
} }
; CHECK-LABEL: define void @test1(
; CHECK: %[[CALL:.*]] = call i32 @pure_computation()
; CHECK: phi i32 [ %[[CALL]]
define void @test2(i32* %s, i1 %b) personality i32 (...)* @__CxxFrameHandler3 { define void @test2(i32* %s, i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: br i1 [[B:%.*]], label [[TRY_CONT:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[WHILE_COND]] unwind label [[CATCH_DISPATCH:%.*]]
; CHECK: catch.dispatch:
; CHECK-NEXT: [[CP:%.*]] = cleanuppad within none []
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @pure_computation() [ "funclet"(token [[CP]]) ]
; CHECK-NEXT: store i32 [[TMP0]], i32* [[S:%.*]], align 4
; CHECK-NEXT: cleanupret from [[CP]] unwind to caller
; CHECK: try.cont:
; CHECK-NEXT: ret void
;
entry: entry:
br label %while.cond br label %while.cond
@ -55,13 +89,38 @@ try.cont: ; preds = %catch, %while.cond
ret void ret void
} }
; CHECK-LABEL: define void @test2(
; CHECK: %[[CP:.*]] = cleanuppad within none []
; CHECK-NEXT: %[[CALL:.*]] = call i32 @pure_computation() [ "funclet"(token %[[CP]]) ]
; CHECK-NEXT: store i32 %[[CALL]], i32* %s
; CHECK-NEXT: cleanupret from %[[CP]] unwind to caller
define void @test3(i1 %a, i1 %b, i1 %c) personality i32 (...)* @__CxxFrameHandler3 { define void @test3(i1 %a, i1 %b, i1 %c) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTFRAME:%.*]] = alloca i8, align 4
; CHECK-NEXT: [[DOTFRAME2:%.*]] = alloca i8, align 4
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[DOTFRAME]] to i32*
; CHECK-NEXT: [[BC2:%.*]] = bitcast i8* [[DOTFRAME2]] to i32*
; CHECK-NEXT: br i1 [[A:%.*]], label [[TRY_SUCCESS_OR_CAUGHT:%.*]], label [[FORBODY_PREHEADER:%.*]]
; CHECK: forbody.preheader:
; CHECK-NEXT: store i32 1, i32* [[BC]], align 4
; CHECK-NEXT: store i32 2, i32* [[BC2]], align 4
; CHECK-NEXT: br label [[FORBODY:%.*]]
; CHECK: catch.object.Throwable:
; CHECK-NEXT: [[CP:%.*]] = catchpad within [[CS:%.*]] [i8* null, i32 64, i8* null]
; CHECK-NEXT: unreachable
; CHECK: try.success.or.caught.loopexit:
; CHECK-NEXT: br label [[TRY_SUCCESS_OR_CAUGHT]]
; CHECK: try.success.or.caught:
; CHECK-NEXT: ret void
; CHECK: postinvoke:
; CHECK-NEXT: br i1 [[B:%.*]], label [[ELSE:%.*]], label [[FORCOND_BACKEDGE:%.*]]
; CHECK: forcond.backedge:
; CHECK-NEXT: br i1 [[C:%.*]], label [[TRY_SUCCESS_OR_CAUGHT_LOOPEXIT:%.*]], label [[FORBODY]]
; CHECK: catch.dispatch:
; CHECK-NEXT: [[CS]] = catchswitch within none [label %catch.object.Throwable] unwind to caller
; CHECK: forbody:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[POSTINVOKE:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
; CHECK: else:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[FORCOND_BACKEDGE]] unwind label [[CATCH_DISPATCH]]
;
entry: entry:
%.frame = alloca i8, align 4 %.frame = alloca i8, align 4
%.frame2 = alloca i8, align 4 %.frame2 = alloca i8, align 4
@ -96,13 +155,6 @@ else: ; preds = %postinvoke
to label %forcond.backedge unwind label %catch.dispatch to label %forcond.backedge unwind label %catch.dispatch
} }
; CHECK-LABEL: define void @test3(
; CHECK-LABEL: forbody.preheader:
; CHECK: store i32 1, i32* %bc, align 4
; CHECK: store i32 2, i32* %bc2, align 4
; CHECK: catchswitch within none
; CHECK-LABEL: forbody:
declare void @may_throw() declare void @may_throw()
declare i32 @pure_computation() nounwind argmemonly readonly declare i32 @pure_computation() nounwind argmemonly readonly

View File

@ -1,3 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -basic-aa -licm -S | FileCheck %s ; RUN: opt < %s -basic-aa -licm -S | FileCheck %s
; RUN: opt < %s -debugify -basic-aa -licm -S | FileCheck %s -check-prefix=DEBUGIFY ; RUN: opt < %s -debugify -basic-aa -licm -S | FileCheck %s -check-prefix=DEBUGIFY
; RUN: opt < %s -basic-aa -licm -S -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s ; RUN: opt < %s -basic-aa -licm -S -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s
@ -9,6 +10,14 @@ declare void @foo()
; Sink readonly function. ; Sink readonly function.
define i32 @test1(i8* %P) { define i32 @test1(i8* %P) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[A_LE:%.*]] = call i32 @strlen(i8* [[P:%.*]]) #[[ATTR3:[0-9]+]]
; CHECK-NEXT: ret i32 [[A_LE]]
;
br label %Loop br label %Loop
Loop: ; preds = %Loop, %0 Loop: ; preds = %Loop, %0
@ -17,16 +26,21 @@ Loop: ; preds = %Loop, %0
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %A ret i32 %A
; CHECK-LABEL: @test1(
; CHECK: Out:
; CHECK-NEXT: call i32 @strlen
; CHECK-NEXT: ret i32 %A
} }
declare double @sin(double) readnone nounwind declare double @sin(double) readnone nounwind
; Sink readnone function out of loop with unknown memory behavior. ; Sink readnone function out of loop with unknown memory behavior.
define double @test2(double %X) { define double @test2(double %X) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[A_LE:%.*]] = call double @sin(double [[X:%.*]]) #[[ATTR4:[0-9]+]]
; CHECK-NEXT: ret double [[A_LE]]
;
br label %Loop br label %Loop
Loop: ; preds = %Loop, %0 Loop: ; preds = %Loop, %0
@ -36,14 +50,19 @@ Loop: ; preds = %Loop, %0
Out: ; preds = %Loop Out: ; preds = %Loop
ret double %A ret double %A
; CHECK-LABEL: @test2(
; CHECK: Out:
; CHECK-NEXT: call double @sin
; CHECK-NEXT: ret double %A
} }
; FIXME: Should be able to sink this case ; FIXME: Should be able to sink this case
define i32 @test2b(i32 %X) { define i32 @test2b(i32 %X) {
; CHECK-LABEL: @test2b(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[A_LE:%.*]] = sdiv i32 10, [[X:%.*]]
; CHECK-NEXT: ret i32 [[A_LE]]
;
br label %Loop br label %Loop
Loop: ; preds = %Loop, %0 Loop: ; preds = %Loop, %0
@ -53,13 +72,18 @@ Loop: ; preds = %Loop, %0
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %A ret i32 %A
; CHECK-LABEL: @test2b(
; CHECK: Out:
; CHECK-NEXT: sdiv
; CHECK-NEXT: ret i32 %A
} }
define double @test2c(double* %P) { define double @test2c(double* %P) {
; CHECK-LABEL: @test2c(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[A_LE:%.*]] = load double, double* [[P:%.*]], align 8, !invariant.load !0
; CHECK-NEXT: ret double [[A_LE]]
;
br label %Loop br label %Loop
Loop: ; preds = %Loop, %0 Loop: ; preds = %Loop, %0
@ -69,15 +93,25 @@ Loop: ; preds = %Loop, %0
Out: ; preds = %Loop Out: ; preds = %Loop
ret double %A ret double %A
; CHECK-LABEL: @test2c(
; CHECK: Out:
; CHECK-NEXT: load double
; CHECK-NEXT: ret double %A
} }
; This testcase checks to make sure the sinker does not cause problems with ; This testcase checks to make sure the sinker does not cause problems with
; critical edges. ; critical edges.
define void @test3() { define void @test3() {
; CHECK-LABEL: @test3(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br i1 false, label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: Loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: Exit.loopexit:
; CHECK-NEXT: [[X_LE:%.*]] = add i32 0, 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: Exit:
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_LE]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret void
;
Entry: Entry:
br i1 false, label %Loop, label %Exit br i1 false, label %Loop, label %Exit
Loop: Loop:
@ -87,10 +121,6 @@ Exit:
%Y = phi i32 [ 0, %Entry ], [ %X, %Loop ] %Y = phi i32 [ 0, %Entry ], [ %X, %Loop ]
ret void ret void
; CHECK-LABEL: @test3(
; CHECK: Exit.loopexit:
; CHECK-NEXT: %X.le = add i32 0, 1
; CHECK-NEXT: br label %Exit
} }
@ -99,6 +129,20 @@ Exit:
; iteration of the loop. ; iteration of the loop.
; ;
define i32 @test4(i32 %N) { define i32 @test4(i32 %N) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[LOOP]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 1
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[LOOP]] ]
; CHECK-NEXT: [[TMP_6_LE:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: [[TMP_7_LE:%.*]] = sub i32 [[TMP_6_LE]], [[N]]
; CHECK-NEXT: ret i32 [[TMP_7_LE]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: ; preds = %Loop, %Entry Loop: ; preds = %Loop, %Entry
@ -110,12 +154,6 @@ Loop: ; preds = %Loop, %Entry
br i1 %tmp.1, label %Loop, label %Out br i1 %tmp.1, label %Loop, label %Out
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %tmp.7 ret i32 %tmp.7
; CHECK-LABEL: @test4(
; CHECK: Out:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn
; CHECK-NEXT: mul i32 %N, %[[LCSSAPHI]]
; CHECK-NEXT: sub i32 %tmp.6.le, %N
; CHECK-NEXT: ret i32
} }
; To reduce register pressure, if a load is hoistable out of the loop, and the ; To reduce register pressure, if a load is hoistable out of the loop, and the
@ -125,6 +163,18 @@ Out: ; preds = %Loop
@X = global i32 5 ; <i32*> [#uses=1] @X = global i32 5 ; <i32*> [#uses=1]
define i32 @test5(i32 %N) { define i32 @test5(i32 %N) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[LOOP]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 1
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[TMP_6_LE:%.*]] = load i32, i32* @X, align 4
; CHECK-NEXT: ret i32 [[TMP_6_LE]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: ; preds = %Loop, %Entry Loop: ; preds = %Loop, %Entry
@ -135,10 +185,6 @@ Loop: ; preds = %Loop, %Entry
br i1 %tmp.1, label %Loop, label %Out br i1 %tmp.1, label %Loop, label %Out
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %tmp.6 ret i32 %tmp.6
; CHECK-LABEL: @test5(
; CHECK: Out:
; CHECK-NEXT: %tmp.6.le = load i32, i32* @X
; CHECK-NEXT: ret i32 %tmp.6.le
} }
@ -152,6 +198,15 @@ Out: ; preds = %Loop
@X2 = external global %Ty @X2 = external global %Ty
define i32 @test6() { define i32 @test6() {
; CHECK-LABEL: @test6(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[DEAD_LE:%.*]] = getelementptr [[TY:%.*]], %Ty* @X2, i64 0, i32 0
; CHECK-NEXT: [[SUNK2_LE:%.*]] = load i32, i32* [[DEAD_LE]], align 4
; CHECK-NEXT: ret i32 [[SUNK2_LE]]
;
br label %Loop br label %Loop
Loop: Loop:
%dead = getelementptr %Ty, %Ty* @X2, i64 0, i32 0 %dead = getelementptr %Ty, %Ty* @X2, i64 0, i32 0
@ -159,11 +214,6 @@ Loop:
br i1 false, label %Loop, label %Out br i1 false, label %Loop, label %Out
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %sunk2 ret i32 %sunk2
; CHECK-LABEL: @test6(
; CHECK: Out:
; CHECK-NEXT: %dead.le = getelementptr %Ty, %Ty* @X2, i64 0, i32 0
; CHECK-NEXT: %sunk2.le = load i32, i32* %dead.le
; CHECK-NEXT: ret i32 %sunk2.le
} }
@ -172,6 +222,27 @@ Out: ; preds = %Loop
; multiple exits. ; multiple exits.
; ;
define i32 @test7(i32 %N, i1 %C) { define i32 @test7(i32 %N, i1 %C) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[CONTLOOP:%.*]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: br i1 [[C:%.*]], label [[CONTLOOP]], label [[OUT1:%.*]]
; CHECK: ContLoop:
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 1
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT2:%.*]]
; CHECK: Out1:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[LOOP]] ]
; CHECK-NEXT: [[TMP_6_LE:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: [[TMP_7_LE2:%.*]] = sub i32 [[TMP_6_LE]], [[N]]
; CHECK-NEXT: ret i32 [[TMP_7_LE2]]
; CHECK: Out2:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA5:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[CONTLOOP]] ]
; CHECK-NEXT: [[TMP_6_LE4:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA5]]
; CHECK-NEXT: [[TMP_7_LE:%.*]] = sub i32 [[TMP_6_LE4]], [[N]]
; CHECK-NEXT: ret i32 [[TMP_7_LE]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: ; preds = %ContLoop, %Entry Loop: ; preds = %ContLoop, %Entry
@ -187,17 +258,6 @@ Out1: ; preds = %Loop
ret i32 %tmp.7 ret i32 %tmp.7
Out2: ; preds = %ContLoop Out2: ; preds = %ContLoop
ret i32 %tmp.7 ret i32 %tmp.7
; CHECK-LABEL: @test7(
; CHECK: Out1:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn
; CHECK-NEXT: mul i32 %N, %[[LCSSAPHI]]
; CHECK-NEXT: sub i32 %tmp.6.le, %N
; CHECK-NEXT: ret
; CHECK: Out2:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn
; CHECK-NEXT: mul i32 %N, %[[LCSSAPHI]]
; CHECK-NEXT: sub i32 %tmp.6.le4, %N
; CHECK-NEXT: ret
} }
@ -205,6 +265,22 @@ Out2: ; preds = %ContLoop
; some exits out of the loop, and that we can do so without breaking dominator ; some exits out of the loop, and that we can do so without breaking dominator
; info. ; info.
define i32 @test8(i1 %C1, i1 %C2, i32* %P, i32* %Q) { define i32 @test8(i1 %C1, i1 %C2, i32* %P, i32* %Q) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 [[C1:%.*]], label [[CONT:%.*]], label [[EXIT1:%.*]]
; CHECK: Cont:
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: store i32 [[X]], i32* [[Q:%.*]], align 4
; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i32 0
; CHECK: exit2:
; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i32 [ [[X]], [[CONT]] ]
; CHECK-NEXT: [[V_LE:%.*]] = add i32 [[X_LCSSA]], 1
; CHECK-NEXT: ret i32 [[V_LE]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: ; preds = %Cont, %Entry Loop: ; preds = %Cont, %Entry
@ -218,17 +294,28 @@ exit1: ; preds = %Loop
ret i32 0 ret i32 0
exit2: ; preds = %Cont exit2: ; preds = %Cont
ret i32 %V ret i32 %V
; CHECK-LABEL: @test8(
; CHECK: exit1:
; CHECK-NEXT: ret i32 0
; CHECK: exit2:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i32 [ %X
; CHECK-NEXT: %V.le = add i32 %[[LCSSAPHI]], 1
; CHECK-NEXT: ret i32 %V.le
} }
define void @test9() { define void @test9() {
; CHECK-LABEL: @test9(
; CHECK-NEXT: loopentry.2.i:
; CHECK-NEXT: br i1 false, label [[NO_EXIT_1_I_PREHEADER:%.*]], label [[LOOPENTRY_3_I_PREHEADER:%.*]]
; CHECK: no_exit.1.i.preheader:
; CHECK-NEXT: br label [[NO_EXIT_1_I:%.*]]
; CHECK: no_exit.1.i:
; CHECK-NEXT: br i1 false, label [[RETURN_I:%.*]], label [[ENDIF_8_I:%.*]]
; CHECK: endif.8.i:
; CHECK-NEXT: br i1 false, label [[NO_EXIT_1_I]], label [[LOOPENTRY_3_I_PREHEADER_LOOPEXIT:%.*]]
; CHECK: loopentry.3.i.preheader.loopexit:
; CHECK-NEXT: [[INC_1_I_LE:%.*]] = add i32 0, 1
; CHECK-NEXT: br label [[LOOPENTRY_3_I_PREHEADER]]
; CHECK: loopentry.3.i.preheader:
; CHECK-NEXT: [[ARG_NUM_0_I_PH13000:%.*]] = phi i32 [ 0, [[LOOPENTRY_2_I:%.*]] ], [ [[INC_1_I_LE]], [[LOOPENTRY_3_I_PREHEADER_LOOPEXIT]] ]
; CHECK-NEXT: ret void
; CHECK: return.i:
; CHECK-NEXT: ret void
;
loopentry.2.i: loopentry.2.i:
br i1 false, label %no_exit.1.i.preheader, label %loopentry.3.i.preheader br i1 false, label %no_exit.1.i.preheader, label %loopentry.3.i.preheader
no_exit.1.i.preheader: ; preds = %loopentry.2.i no_exit.1.i.preheader: ; preds = %loopentry.2.i
@ -246,16 +333,25 @@ loopentry.3.i.preheader: ; preds = %loopentry.3.i.preheader.loopexit, %loopentr
return.i: ; preds = %no_exit.1.i return.i: ; preds = %no_exit.1.i
ret void ret void
; CHECK-LABEL: @test9(
; CHECK: loopentry.3.i.preheader.loopexit:
; CHECK-NEXT: %inc.1.i.le = add i32 0, 1
; CHECK-NEXT: br label %loopentry.3.i.preheader
} }
; Potentially trapping instructions may be sunk as long as they are guaranteed ; Potentially trapping instructions may be sunk as long as they are guaranteed
; to be executed. ; to be executed.
define i32 @test10(i32 %N) { define i32 @test10(i32 %N) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[LOOP]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 0
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[LOOP]] ]
; CHECK-NEXT: [[TMP_6_LE:%.*]] = sdiv i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: ret i32 [[TMP_6_LE]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: ; preds = %Loop, %Entry Loop: ; preds = %Loop, %Entry
@ -267,15 +363,17 @@ Loop: ; preds = %Loop, %Entry
Out: ; preds = %Loop Out: ; preds = %Loop
ret i32 %tmp.6 ret i32 %tmp.6
; CHECK-LABEL: @test10(
; CHECK: Out:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn
; CHECK-NEXT: %tmp.6.le = sdiv i32 %N, %[[LCSSAPHI]]
; CHECK-NEXT: ret i32 %tmp.6.le
} }
; Should delete, not sink, dead instructions. ; Should delete, not sink, dead instructions.
define void @test11() { define void @test11() {
; CHECK-LABEL: @test11(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[OUT:%.*]]
; CHECK: Out:
; CHECK-NEXT: ret void
;
br label %Loop br label %Loop
Loop: Loop:
%dead1 = getelementptr %Ty, %Ty* @X2, i64 0, i32 0 %dead1 = getelementptr %Ty, %Ty* @X2, i64 0, i32 0
@ -283,15 +381,11 @@ Loop:
br i1 false, label %Loop, label %Out br i1 false, label %Loop, label %Out
Out: Out:
ret void ret void
; CHECK-LABEL: @test11(
; CHECK: Out:
; CHECK-NEXT: ret void
; The GEP in dead1 is adding a zero offset, so the DIExpression can be kept as ; The GEP in dead1 is adding a zero offset, so the DIExpression can be kept as
; a "register location". ; a "register location".
; The GEP in dead2 is adding a 4 bytes to the pointer, so the DIExpression is ; The GEP in dead2 is adding a 4 bytes to the pointer, so the DIExpression is
; turned into an "implicit location" using DW_OP_stack_value. ; turned into an "implicit location" using DW_OP_stack_value.
;
; DEBUGIFY-LABEL: @test11( ; DEBUGIFY-LABEL: @test11(
; DEBUGIFY: call void @llvm.dbg.value(metadata %Ty* @X2, metadata {{.*}}, metadata !DIExpression()) ; DEBUGIFY: call void @llvm.dbg.value(metadata %Ty* @X2, metadata {{.*}}, metadata !DIExpression())
; DEBUGIFY: call void @llvm.dbg.value(metadata %Ty* @X2, metadata {{.*}}, metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)) ; DEBUGIFY: call void @llvm.dbg.value(metadata %Ty* @X2, metadata {{.*}}, metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value))
@ -302,6 +396,46 @@ Out:
; Test a *many* way nested loop with multiple exit blocks both of which exit ; Test a *many* way nested loop with multiple exit blocks both of which exit
; multiple loop nests. This exercises LCSSA corner cases. ; multiple loop nests. This exercises LCSSA corner cases.
define i32 @PR18753(i1* %a, i1* %b, i1* %c, i1* %d) { define i32 @PR18753(i1* %a, i1* %b, i1* %c, i1* %d) {
; CHECK-LABEL: @PR18753(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[L1_HEADER:%.*]]
; CHECK: l1.header:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[L1_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds [1 x i32], [1 x i32]* @c, i64 0, i64 [[IV]]
; CHECK-NEXT: br label [[L2_HEADER:%.*]]
; CHECK: l2.header:
; CHECK-NEXT: [[X0:%.*]] = load i1, i1* [[C:%.*]], align 4
; CHECK-NEXT: br i1 [[X0]], label [[L1_LATCH]], label [[L3_PREHEADER:%.*]]
; CHECK: l3.preheader:
; CHECK-NEXT: br label [[L3_HEADER:%.*]]
; CHECK: l3.header:
; CHECK-NEXT: [[X1:%.*]] = load i1, i1* [[D:%.*]], align 4
; CHECK-NEXT: br i1 [[X1]], label [[L2_LATCH:%.*]], label [[L4_PREHEADER:%.*]]
; CHECK: l4.preheader:
; CHECK-NEXT: br label [[L4_HEADER:%.*]]
; CHECK: l4.header:
; CHECK-NEXT: [[X2:%.*]] = load i1, i1* [[A:%.*]], align 1
; CHECK-NEXT: br i1 [[X2]], label [[L3_LATCH:%.*]], label [[L4_BODY:%.*]]
; CHECK: l4.body:
; CHECK-NEXT: call void @f(i32* [[ARRAYIDX_I]])
; CHECK-NEXT: [[X3:%.*]] = load i1, i1* [[B:%.*]], align 1
; CHECK-NEXT: br i1 [[X3]], label [[L4_LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: l4.latch:
; CHECK-NEXT: call void @g()
; CHECK-NEXT: [[X4:%.*]] = load i1, i1* [[B]], align 4
; CHECK-NEXT: br i1 [[X4]], label [[L4_HEADER]], label [[EXIT]]
; CHECK: l3.latch:
; CHECK-NEXT: br label [[L3_HEADER]]
; CHECK: l2.latch:
; CHECK-NEXT: br label [[L2_HEADER]]
; CHECK: l1.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 1
; CHECK-NEXT: br label [[L1_HEADER]]
; CHECK: exit:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[IV]], [[L4_LATCH]] ], [ [[IV]], [[L4_BODY]] ]
; CHECK-NEXT: [[L_LE:%.*]] = trunc i64 [[IV_LCSSA]] to i32
; CHECK-NEXT: ret i32 [[L_LE]]
;
entry: entry:
br label %l1.header br label %l1.header
@ -351,11 +485,6 @@ l1.latch:
exit: exit:
%lcssa = phi i32 [ %l, %l4.latch ], [ %l, %l4.body ] %lcssa = phi i32 [ %l, %l4.latch ], [ %l, %l4.body ]
; CHECK-LABEL: @PR18753(
; CHECK: exit:
; CHECK-NEXT: %[[LCSSAPHI:.*]] = phi i64 [ %iv, %l4.latch ], [ %iv, %l4.body ]
; CHECK-NEXT: %l.le = trunc i64 %[[LCSSAPHI]] to i32
; CHECK-NEXT: ret i32 %l.le
ret i32 %lcssa ret i32 %lcssa
} }
@ -366,7 +495,26 @@ exit:
; available (which is used for creating loads that may be used by the SSA ; available (which is used for creating loads that may be used by the SSA
; updater) ; updater)
define void @test13() { define void @test13() {
; CHECK-LABEL: @test13 ; CHECK-LABEL: @test13(
; CHECK-NEXT: br label [[LAB59:%.*]]
; CHECK: lab19:
; CHECK-NEXT: br i1 false, label [[LAB20:%.*]], label [[LAB38_LOOPEXIT:%.*]]
; CHECK: lab20:
; CHECK-NEXT: br label [[LAB60:%.*]]
; CHECK: lab21:
; CHECK-NEXT: br i1 undef, label [[LAB22:%.*]], label [[LAB38:%.*]]
; CHECK: lab22:
; CHECK-NEXT: br label [[LAB38]]
; CHECK: lab38.loopexit:
; CHECK-NEXT: br label [[LAB38]]
; CHECK: lab38:
; CHECK-NEXT: ret void
; CHECK: lab59:
; CHECK-NEXT: indirectbr i8* undef, [label [[LAB60]], label %lab38]
; CHECK: lab60:
; CHECK-NEXT: store i32 2145244101, i32* undef, align 4
; CHECK-NEXT: indirectbr i8* undef, [label [[LAB21:%.*]], label %lab19]
;
br label %lab59 br label %lab59
lab19: lab19:
@ -388,35 +536,36 @@ lab59:
indirectbr i8* undef, [label %lab60, label %lab38] indirectbr i8* undef, [label %lab60, label %lab38]
lab60: lab60:
; CHECK: lab60:
; CHECK: store
; CHECK-NEXT: indirectbr
store i32 2145244101, i32* undef, align 4 store i32 2145244101, i32* undef, align 4
indirectbr i8* undef, [label %lab21, label %lab19] indirectbr i8* undef, [label %lab21, label %lab19]
} }
; Check if LICM can sink a sinkable instruction the exit blocks through ; Check if LICM can sink a sinkable instruction the exit blocks through
; a non-trivially replacable PHI node. ; a non-trivially replacable PHI node.
;
; CHECK-LABEL: @test14
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL: Out12.split.loop.exit:
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12.split.loop.exit1:
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL2]], %N
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12:
; CHECK: phi i32 [ %[[MUL]], %Out12.split.loop.exit ], [ %[[SUB]], %Out12.split.loop.exit1 ]
define i32 @test14(i32 %N, i32 %N2, i1 %C) { define i32 @test14(i32 %N, i32 %N2, i1 %C) {
; CHECK-LABEL: @test14(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[CONTLOOP:%.*]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: br i1 [[C:%.*]], label [[CONTLOOP]], label [[OUT12_SPLIT_LOOP_EXIT1:%.*]]
; CHECK: ContLoop:
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 1
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT12_SPLIT_LOOP_EXIT:%.*]]
; CHECK: Out12.split.loop.exit:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA4:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[CONTLOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE3:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA4]]
; CHECK-NEXT: br label [[OUT12:%.*]]
; CHECK: Out12.split.loop.exit1:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[LOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: [[SINK_SUB_LE:%.*]] = sub i32 [[SINK_MUL_LE]], [[N]]
; CHECK-NEXT: br label [[OUT12]]
; CHECK: Out12:
; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ [[SINK_MUL_LE3]], [[OUT12_SPLIT_LOOP_EXIT]] ], [ [[SINK_SUB_LE]], [[OUT12_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: ret i32 [[TMP]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: Loop:
@ -439,27 +588,31 @@ Out12:
; to the shared operations. As of now, we split predecessors of non-trivially ; to the shared operations. As of now, we split predecessors of non-trivially
; replicalbe PHIs by default in LICM because all incoming edges of a ; replicalbe PHIs by default in LICM because all incoming edges of a
; non-trivially replacable PHI in LCSSA is critical. ; non-trivially replacable PHI in LCSSA is critical.
;
; CHECK-LABEL: @test15
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL: Out12.split.loop.exit:
; CHECK: %[[LCSSAPHI:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop ]
; CHECK: %[[MUL:.*]] = mul i32 %N, %[[LCSSAPHI]]
; CHECK: %[[SUB:.*]] = sub i32 %[[MUL]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12.split.loop.exit1:
; CHECK: %[[LCSSAPHI2:.*]] = phi i32 [ %N_addr.0.pn, %Loop ]
; CHECK: %[[MUL2:.*]] = mul i32 %N, %[[LCSSAPHI2]]
; CHECK: %[[SUB2:.*]] = sub i32 %[[MUL2]], %N
; CHECK: br label %Out12
;
; CHECK-LABEL: Out12:
; CHECK: phi i32 [ %[[SUB]], %Out12.split.loop.exit ], [ %[[SUB2]], %Out12.split.loop.exit1 ]
define i32 @test15(i32 %N, i32 %N2, i1 %C) { define i32 @test15(i32 %N, i32 %N2, i1 %C) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[CONTLOOP:%.*]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: br i1 [[C:%.*]], label [[CONTLOOP]], label [[OUT12_SPLIT_LOOP_EXIT1:%.*]]
; CHECK: ContLoop:
; CHECK-NEXT: [[TMP_1:%.*]] = icmp ne i32 [[N_ADDR_0_PN]], 1
; CHECK-NEXT: br i1 [[TMP_1]], label [[LOOP]], label [[OUT12_SPLIT_LOOP_EXIT:%.*]]
; CHECK: Out12.split.loop.exit:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA5:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[CONTLOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE4:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA5]]
; CHECK-NEXT: [[SINK_SUB2_LE:%.*]] = sub i32 [[SINK_MUL_LE4]], [[N2:%.*]]
; CHECK-NEXT: br label [[OUT12:%.*]]
; CHECK: Out12.split.loop.exit1:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[LOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: [[SINK_SUB_LE:%.*]] = sub i32 [[SINK_MUL_LE]], [[N]]
; CHECK-NEXT: br label [[OUT12]]
; CHECK: Out12:
; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ [[SINK_SUB2_LE]], [[OUT12_SPLIT_LOOP_EXIT]] ], [ [[SINK_SUB_LE]], [[OUT12_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: ret i32 [[TMP]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: Loop:
@ -479,22 +632,37 @@ Out12:
; Sink through a non-trivially replacable PHI node which use the same sinkable ; Sink through a non-trivially replacable PHI node which use the same sinkable
; instruction multiple times. ; instruction multiple times.
;
; CHECK-LABEL: @test16
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
;
; CHECK-LABEL: Out.split.loop.exit:
; CHECK: %[[PHI:.*]] = phi i32 [ %l2, %ContLoop ]
; CHECK: br label %Out
;
; CHECK-LABEL: Out.split.loop.exit1:
; CHECK: %[[SINKABLE:.*]] = mul i32 %l2.lcssa, %t.le
; CHECK: br label %Out
;
; CHECK-LABEL: Out:
; CHECK: %idx = phi i32 [ %[[PHI]], %Out.split.loop.exit ], [ %[[SINKABLE]], %Out.split.loop.exit1 ]
define i32 @test16(i1 %c, i8** %P, i32* %P2, i64 %V) { define i32 @test16(i1 %c, i8** %P, i32* %P2, i64 %V) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_PH:%.*]]
; CHECK: loop.ph:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[LOOP_PH]] ], [ [[NEXT:%.*]], [[CONTLOOP:%.*]] ]
; CHECK-NEXT: [[L2:%.*]] = call i32 @getv()
; CHECK-NEXT: switch i32 [[L2]], label [[CONTLOOP]] [
; CHECK-NEXT: i32 32, label [[OUT_SPLIT_LOOP_EXIT1:%.*]]
; CHECK-NEXT: i32 46, label [[OUT_SPLIT_LOOP_EXIT1]]
; CHECK-NEXT: i32 95, label [[OUT_SPLIT_LOOP_EXIT1]]
; CHECK-NEXT: ]
; CHECK: ContLoop:
; CHECK-NEXT: [[NEXT]] = add nuw i64 [[IV]], 1
; CHECK-NEXT: [[C1:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C1]], label [[LOOP]], label [[OUT_SPLIT_LOOP_EXIT:%.*]]
; CHECK: Out.split.loop.exit:
; CHECK-NEXT: [[IDX_PH:%.*]] = phi i32 [ [[L2]], [[CONTLOOP]] ]
; CHECK-NEXT: br label [[OUT:%.*]]
; CHECK: Out.split.loop.exit1:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i64 [ [[IV]], [[LOOP]] ], [ [[IV]], [[LOOP]] ], [ [[IV]], [[LOOP]] ]
; CHECK-NEXT: [[L2_LCSSA:%.*]] = phi i32 [ [[L2]], [[LOOP]] ], [ [[L2]], [[LOOP]] ], [ [[L2]], [[LOOP]] ]
; CHECK-NEXT: [[T_LE:%.*]] = trunc i64 [[IV_LCSSA]] to i32
; CHECK-NEXT: [[SINKABLE_LE:%.*]] = mul i32 [[L2_LCSSA]], [[T_LE]]
; CHECK-NEXT: br label [[OUT]]
; CHECK: Out:
; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PH]], [[OUT_SPLIT_LOOP_EXIT]] ], [ [[SINKABLE_LE]], [[OUT_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: ret i32 [[IDX]]
;
entry: entry:
br label %loop.ph br label %loop.ph
loop.ph: loop.ph:
@ -520,27 +688,48 @@ Out:
; Sink a sinkable instruction through multiple non-trivially replacable PHIs in ; Sink a sinkable instruction through multiple non-trivially replacable PHIs in
; differect exit blocks. ; differect exit blocks.
;
; CHECK-LABEL: @test17
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
;
; CHECK-LABEL:OutA.split.loop.exit{{.*}}:
; CHECK: %[[OP1:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop1 ]
; CHECK: %[[SINKABLE:.*]] = mul i32 %N, %[[OP1]]
; CHECK: br label %OutA
;
; CHECK-LABEL:OutA:
; CHECK: phi i32{{.*}}[ %[[SINKABLE]], %OutA.split.loop.exit{{.*}} ]
;
; CHECK-LABEL:OutB.split.loop.exit{{.*}}:
; CHECK: %[[OP2:.*]] = phi i32 [ %N_addr.0.pn, %ContLoop2 ]
; CHECK: %[[SINKABLE2:.*]] = mul i32 %N, %[[OP2]]
; CHECK: br label %OutB
;
; CHECK-LABEL:OutB:
; CHECK: phi i32 {{.*}}[ %[[SINKABLE2]], %OutB.split.loop.exit{{.*}} ]
define i32 @test17(i32 %N, i32 %N2) { define i32 @test17(i32 %N, i32 %N2) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[N_ADDR_0_PN:%.*]] = phi i32 [ [[DEC:%.*]], [[CONTLOOP3:%.*]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[C0:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C0]], label [[CONTLOOP1:%.*]], label [[OUTA_SPLIT_LOOP_EXIT3:%.*]]
; CHECK: ContLoop1:
; CHECK-NEXT: [[C1:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C1]], label [[CONTLOOP2:%.*]], label [[OUTA_SPLIT_LOOP_EXIT:%.*]]
; CHECK: ContLoop2:
; CHECK-NEXT: [[C2:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C2]], label [[CONTLOOP3]], label [[OUTB_SPLIT_LOOP_EXIT1:%.*]]
; CHECK: ContLoop3:
; CHECK-NEXT: [[C3:%.*]] = call i1 @getc()
; CHECK-NEXT: [[DEC]] = add i32 [[N_ADDR_0_PN]], -1
; CHECK-NEXT: br i1 [[C3]], label [[LOOP]], label [[OUTB_SPLIT_LOOP_EXIT:%.*]]
; CHECK: OutA.split.loop.exit:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[CONTLOOP1]] ]
; CHECK-NEXT: [[SINK_MUL_LE:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA]]
; CHECK-NEXT: br label [[OUTA:%.*]]
; CHECK: OutA.split.loop.exit3:
; CHECK-NEXT: [[TMP1_PH4:%.*]] = phi i32 [ [[N2:%.*]], [[LOOP]] ]
; CHECK-NEXT: br label [[OUTA]]
; CHECK: OutA:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[SINK_MUL_LE]], [[OUTA_SPLIT_LOOP_EXIT]] ], [ [[TMP1_PH4]], [[OUTA_SPLIT_LOOP_EXIT3]] ]
; CHECK-NEXT: br label [[OUT12:%.*]]
; CHECK: OutB.split.loop.exit:
; CHECK-NEXT: [[TMP2_PH:%.*]] = phi i32 [ [[DEC]], [[CONTLOOP3]] ]
; CHECK-NEXT: br label [[OUTB:%.*]]
; CHECK: OutB.split.loop.exit1:
; CHECK-NEXT: [[N_ADDR_0_PN_LCSSA6:%.*]] = phi i32 [ [[N_ADDR_0_PN]], [[CONTLOOP2]] ]
; CHECK-NEXT: [[SINK_MUL_LE5:%.*]] = mul i32 [[N]], [[N_ADDR_0_PN_LCSSA6]]
; CHECK-NEXT: br label [[OUTB]]
; CHECK: OutB:
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP2_PH]], [[OUTB_SPLIT_LOOP_EXIT]] ], [ [[SINK_MUL_LE5]], [[OUTB_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: br label [[OUT12]]
; CHECK: Out12:
; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ [[TMP1]], [[OUTA]] ], [ [[TMP2]], [[OUTB]] ]
; CHECK-NEXT: ret i32 [[TMP]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: Loop:
@ -572,30 +761,35 @@ Out12:
; Sink a sinkable instruction through both trivially and non-trivially replacable PHIs. ; Sink a sinkable instruction through both trivially and non-trivially replacable PHIs.
;
; CHECK-LABEL: @test18
; CHECK-LABEL: Loop:
; CHECK-NOT: mul
; CHECK-NOT: sub
;
; CHECK-LABEL:Out12.split.loop.exit:
; CHECK: %[[OP:.*]] = phi i32 [ %iv, %ContLoop ]
; CHECK: %[[DEC:.*]] = phi i32 [ %dec, %ContLoop ]
; CHECK: %[[SINKMUL:.*]] = mul i32 %N, %[[OP]]
; CHECK: %[[SINKSUB:.*]] = sub i32 %[[SINKMUL]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL:Out12.split.loop.exit1:
; CHECK: %[[OP2:.*]] = phi i32 [ %iv, %Loop ]
; CHECK: %[[SINKMUL2:.*]] = mul i32 %N, %[[OP2]]
; CHECK: %[[SINKSUB2:.*]] = sub i32 %[[SINKMUL2]], %N2
; CHECK: br label %Out12
;
; CHECK-LABEL:Out12:
; CHECK: %tmp1 = phi i32 [ %[[SINKSUB]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
; CHECK: %tmp2 = phi i32 [ %[[DEC]], %Out12.split.loop.exit ], [ %[[SINKSUB2]], %Out12.split.loop.exit1 ]
; CHECK: %add = add i32 %tmp1, %tmp2
define i32 @test18(i32 %N, i32 %N2) { define i32 @test18(i32 %N, i32 %N2) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: Entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[DEC:%.*]], [[CONTLOOP:%.*]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[C0:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C0]], label [[CONTLOOP]], label [[OUT12_SPLIT_LOOP_EXIT1:%.*]]
; CHECK: ContLoop:
; CHECK-NEXT: [[DEC]] = add i32 [[IV]], -1
; CHECK-NEXT: [[C1:%.*]] = call i1 @getc()
; CHECK-NEXT: br i1 [[C1]], label [[LOOP]], label [[OUT12_SPLIT_LOOP_EXIT:%.*]]
; CHECK: Out12.split.loop.exit:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[CONTLOOP]] ]
; CHECK-NEXT: [[TMP2_PH:%.*]] = phi i32 [ [[DEC]], [[CONTLOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE:%.*]] = mul i32 [[N]], [[IV_LCSSA]]
; CHECK-NEXT: [[SINK_SUB_LE4:%.*]] = sub i32 [[SINK_MUL_LE]], [[N2:%.*]]
; CHECK-NEXT: br label [[OUT12:%.*]]
; CHECK: Out12.split.loop.exit1:
; CHECK-NEXT: [[IV_LCSSA7:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
; CHECK-NEXT: [[SINK_MUL_LE6:%.*]] = mul i32 [[N]], [[IV_LCSSA7]]
; CHECK-NEXT: [[SINK_SUB_LE:%.*]] = sub i32 [[SINK_MUL_LE6]], [[N2]]
; CHECK-NEXT: br label [[OUT12]]
; CHECK: Out12:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[SINK_SUB_LE4]], [[OUT12_SPLIT_LOOP_EXIT]] ], [ [[SINK_SUB_LE]], [[OUT12_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP2_PH]], [[OUT12_SPLIT_LOOP_EXIT]] ], [ [[SINK_SUB_LE]], [[OUT12_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i32 [[ADD]]
;
Entry: Entry:
br label %Loop br label %Loop
Loop: Loop:
@ -618,12 +812,23 @@ Out12:
; Do not sink an instruction through a non-trivially replacable PHI, to avoid ; Do not sink an instruction through a non-trivially replacable PHI, to avoid
; assert while splitting predecessors, if the terminator of predecessor is an ; assert while splitting predecessors, if the terminator of predecessor is an
; indirectbr. ; indirectbr.
; CHECK-LABEL: @test19
; CHECK-LABEL: L0:
; CHECK: %sinkable = mul
; CHECK: %sinkable2 = add
define i32 @test19(i1 %cond, i1 %cond2, i8* %address, i32 %v1) nounwind { define i32 @test19(i1 %cond, i1 %cond2, i8* %address, i32 %v1) nounwind {
; CHECK-LABEL: @test19(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = select i1 [[COND:%.*]], i8* blockaddress(@test19, [[EXIT:%.*]]), i8* [[ADDRESS:%.*]]
; CHECK-NEXT: [[INDIRECT_GOTO_DEST2:%.*]] = select i1 [[COND2:%.*]], i8* blockaddress(@test19, [[EXIT]]), i8* [[ADDRESS]]
; CHECK-NEXT: br label [[L0:%.*]]
; CHECK: L0:
; CHECK-NEXT: [[V2:%.*]] = call i32 @getv()
; CHECK-NEXT: [[SINKABLE:%.*]] = mul i32 [[V1:%.*]], [[V2]]
; CHECK-NEXT: [[SINKABLE2:%.*]] = add i32 [[V1]], [[V2]]
; CHECK-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[L1:%.*]], label %exit]
; CHECK: L1:
; CHECK-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST2]], [label [[L0]], label %exit]
; CHECK: exit:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SINKABLE]], [[L0]] ], [ [[SINKABLE2]], [[L1]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry: entry:
br label %L0 br label %L0
L0: L0:
@ -645,12 +850,29 @@ exit:
; Do not sink through a non-trivially replacable PHI if splitting predecessors ; Do not sink through a non-trivially replacable PHI if splitting predecessors
; not allowed in SplitBlockPredecessors(). ; not allowed in SplitBlockPredecessors().
;
; CHECK-LABEL: @test20
; CHECK-LABEL: while.cond
; CHECK: %sinkable = mul
; CHECK: %sinkable2 = add
define void @test20(i32* %s, i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 { define void @test20(i32* %s, i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test20(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: [[V:%.*]] = call i32 @getv()
; CHECK-NEXT: [[SINKABLE:%.*]] = mul i32 [[V]], [[V2:%.*]]
; CHECK-NEXT: [[SINKABLE2:%.*]] = add i32 [[V]], [[V2]]
; CHECK-NEXT: br i1 [[B:%.*]], label [[TRY_CONT:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[WHILE_BODY2:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
; CHECK: while.body2:
; CHECK-NEXT: invoke void @may_throw2()
; CHECK-NEXT: to label [[WHILE_COND]] unwind label [[CATCH_DISPATCH]]
; CHECK: catch.dispatch:
; CHECK-NEXT: [[DOTLCSSA1:%.*]] = phi i32 [ [[SINKABLE]], [[WHILE_BODY]] ], [ [[SINKABLE2]], [[WHILE_BODY2]] ]
; CHECK-NEXT: [[CP:%.*]] = cleanuppad within none []
; CHECK-NEXT: store i32 [[DOTLCSSA1]], i32* [[S:%.*]], align 4
; CHECK-NEXT: cleanupret from [[CP]] unwind to caller
; CHECK: try.cont:
; CHECK-NEXT: ret void
;
entry: entry:
br label %while.cond br label %while.cond
while.cond: while.cond:
@ -676,13 +898,26 @@ try.cont:
; The sinkable call should be sunk into an exit block split. After splitting ; The sinkable call should be sunk into an exit block split. After splitting
; the exit block, BlockColor for new blocks should be added properly so ; the exit block, BlockColor for new blocks should be added properly so
; that we should be able to access valid ColorVector. ; that we should be able to access valid ColorVector.
;
; CHECK-LABEL:@test21_pr36184
; CHECK-LABEL: Loop
; CHECK-NOT: %sinkableCall
; CHECK-LABEL:Out.split.loop.exit
; CHECK: %sinkableCall
define i32 @test21_pr36184(i8* %P) personality i32 (...)* @__CxxFrameHandler3 { define i32 @test21_pr36184(i8* %P) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test21_pr36184(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_PH:%.*]]
; CHECK: loop.ph:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: Loop:
; CHECK-NEXT: br i1 false, label [[CONTLOOP:%.*]], label [[OUT_SPLIT_LOOP_EXIT1:%.*]]
; CHECK: ContLoop:
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[OUT_SPLIT_LOOP_EXIT:%.*]]
; CHECK: Out.split.loop.exit:
; CHECK-NEXT: [[IDX_PH:%.*]] = phi i32 [ 0, [[CONTLOOP]] ]
; CHECK-NEXT: br label [[OUT:%.*]]
; CHECK: Out.split.loop.exit1:
; CHECK-NEXT: [[SINKABLECALL_LE:%.*]] = call i32 @strlen(i8* [[P:%.*]]) #[[ATTR3]]
; CHECK-NEXT: br label [[OUT]]
; CHECK: Out:
; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_PH]], [[OUT_SPLIT_LOOP_EXIT]] ], [ [[SINKABLECALL_LE]], [[OUT_SPLIT_LOOP_EXIT1]] ]
; CHECK-NEXT: ret i32 [[IDX]]
;
entry: entry:
br label %loop.ph br label %loop.ph
@ -702,11 +937,30 @@ Out:
} }
; We do not support splitting a landingpad block if BlockColors is not empty. ; We do not support splitting a landingpad block if BlockColors is not empty.
; CHECK-LABEL: @test22
; CHECK-LABEL: while.body2
; CHECK-LABEL: %mul
; CHECK-NOT: lpadBB.split{{.*}}
define void @test22(i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 { define void @test22(i1 %b, i32 %v1, i32 %v2) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test22(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: br i1 [[B:%.*]], label [[TRY_CONT:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: invoke void @may_throw()
; CHECK-NEXT: to label [[WHILE_BODY2:%.*]] unwind label [[LPADBB:%.*]]
; CHECK: while.body2:
; CHECK-NEXT: [[V:%.*]] = call i32 @getv()
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[V]], [[V2:%.*]]
; CHECK-NEXT: invoke void @may_throw2()
; CHECK-NEXT: to label [[WHILE_COND]] unwind label [[LPADBB]]
; CHECK: lpadBB:
; CHECK-NEXT: [[DOTLCSSA1:%.*]] = phi i32 [ 0, [[WHILE_BODY]] ], [ [[MUL]], [[WHILE_BODY2]] ]
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: br label [[LPADBBSUCC1:%.*]]
; CHECK: lpadBBSucc1:
; CHECK-NEXT: ret void
; CHECK: try.cont:
; CHECK-NEXT: ret void
;
entry: entry:
br label %while.cond br label %while.cond
while.cond: while.cond:

View File

@ -1,23 +1,25 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -sccp -loop-deletion -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; RUN: opt < %s -sccp -loop-deletion -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
declare double @sqrt(double) readnone nounwind declare double @sqrt(double) readnone nounwind
%empty = type {} %empty = type {}
declare %empty @has_side_effects() declare %empty @has_side_effects()
define double @test_0(i32 %param) {
; CHECK-LABEL: @test_0(
; CHECK-NOT: br
entry:
; No matter how hard you try, sqrt(1.0) is always 1.0. This allows the ; No matter how hard you try, sqrt(1.0) is always 1.0. This allows the
; optimizer to delete this loop. ; optimizer to delete this loop.
define double @test_0(i32 %param) {
; CHECK-LABEL: @test_0(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret double 1.000000e+00
;
entry:
br label %Loop br label %Loop
Loop: ; preds = %Loop, %entry Loop: ; preds = %Loop, %entry
%I2 = phi i32 [ 0, %entry ], [ %I3, %Loop ] ; <i32> [#uses=1] %I2 = phi i32 [ 0, %entry ], [ %I3, %Loop ]
%V = phi double [ 1.000000e+00, %entry ], [ %V2, %Loop ] ; <double> [#uses=2] %V = phi double [ 1.000000e+00, %entry ], [ %V2, %Loop ]
%V2 = call double @sqrt( double %V ) ; <double> [#uses=1] %V2 = call double @sqrt( double %V )
%I3 = add i32 %I2, 1 ; <i32> [#uses=2] %I3 = add i32 %I2, 1
%tmp.7 = icmp ne i32 %I3, %param ; <i1> [#uses=1] %tmp.7 = icmp ne i32 %I3, %param
br i1 %tmp.7, label %Loop, label %Exit br i1 %tmp.7, label %Loop, label %Exit
Exit: ; preds = %Loop Exit: ; preds = %Loop
ret double %V ret double %V
@ -25,7 +27,9 @@ Exit: ; preds = %Loop
define i32 @test_1() { define i32 @test_1() {
; CHECK-LABEL: @test_1( ; CHECK-LABEL: @test_1(
; CHECK: call %empty @has_side_effects() ; CHECK-NEXT: [[TMP1:%.*]] = call [[EMPTY:%.*]] @has_side_effects()
; CHECK-NEXT: ret i32 0
;
%1 = call %empty @has_side_effects() %1 = call %empty @has_side_effects()
ret i32 0 ret i32 0
} }

View File

@ -1,3 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; RUN: opt < %s -ipsccp -S | FileCheck %s ; RUN: opt < %s -ipsccp -S | FileCheck %s
; PR36485 ; PR36485
; musttail call result can\'t be replaced with a constant, unless the call ; musttail call result can\'t be replaced with a constant, unless the call
@ -6,11 +7,25 @@
declare i32 @external() declare i32 @external()
define i8* @start(i8 %v) { define i8* @start(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@start
; CHECK-SAME: (i8 [[V:%.*]]) {
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
; CHECK-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 0)
; CHECK-NEXT: ret i8* [[CA]]
; CHECK: false:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
; CHECK-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
; CHECK: c2_true:
; CHECK-NEXT: ret i8* null
; CHECK: c2_false:
; CHECK-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 [[V]])
; CHECK-NEXT: ret i8* [[CA2]]
;
%c1 = icmp eq i8 %v, 0 %c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false br i1 %c1, label %true, label %false
true: true:
; CHECK: %ca = musttail call i8* @side_effects(i8 0)
; CHECK: ret i8* %ca
%ca = musttail call i8* @side_effects(i8 %v) %ca = musttail call i8* @side_effects(i8 %v)
ret i8* %ca ret i8* %ca
false: false:
@ -18,41 +33,48 @@ false:
br i1 %c2, label %c2_true, label %c2_false br i1 %c2, label %c2_true, label %c2_false
c2_true: c2_true:
%ca1 = musttail call i8* @no_side_effects(i8 %v) %ca1 = musttail call i8* @no_side_effects(i8 %v)
; CHECK: ret i8* null
ret i8* %ca1 ret i8* %ca1
c2_false: c2_false:
; CHECK: %ca2 = musttail call i8* @dont_zap_me(i8 %v)
; CHECK: ret i8* %ca2
%ca2 = musttail call i8* @dont_zap_me(i8 %v) %ca2 = musttail call i8* @dont_zap_me(i8 %v)
ret i8* %ca2 ret i8* %ca2
} }
define internal i8* @side_effects(i8 %v) { define internal i8* @side_effects(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@side_effects
; CHECK-SAME: (i8 [[V:%.*]]) {
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @start(i8 0)
; CHECK-NEXT: ret i8* [[CA]]
;
%i1 = call i32 @external() %i1 = call i32 @external()
; since this goes back to `start` the SCPP should be see that the return value ; since this goes back to `start` the SCPP should be see that the return value
; is always `null`. ; is always `null`.
; The call can't be removed due to `external` call above, though. ; The call can't be removed due to `external` call above, though.
; CHECK: %ca = musttail call i8* @start(i8 0)
%ca = musttail call i8* @start(i8 %v) %ca = musttail call i8* @start(i8 %v)
; Thus the result must be returned anyway ; Thus the result must be returned anyway
; CHECK: ret i8* %ca
ret i8* %ca ret i8* %ca
} }
; The call to this function is removed, so the return value must be zapped
define internal i8* @no_side_effects(i8 %v) readonly nounwind { define internal i8* @no_side_effects(i8 %v) readonly nounwind {
; The call to this function is removed, so the return value must be zapped ; CHECK-LABEL: define {{[^@]+}}@no_side_effects
; CHECK: ret i8* undef ; CHECK-SAME: (i8 [[V:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: ret i8* undef
;
ret i8* null ret i8* null
} }
; The call to this function cannot be removed due to side effects. Thus the
; return value should stay as it is, and should not be zapped.
define internal i8* @dont_zap_me(i8 %v) { define internal i8* @dont_zap_me(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@dont_zap_me
; CHECK-SAME: (i8 [[V:%.*]]) {
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: ret i8* null
;
%i1 = call i32 @external() %i1 = call i32 @external()
; The call to this function cannot be removed due to side effects. Thus the
; return value should stay as it is, and should not be zapped.
; CHECK: ret i8* null
ret i8* null ret i8* null
} }

View File

@ -1,21 +1,27 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -S -ipsccp | FileCheck %s ; RUN: opt < %s -S -ipsccp | FileCheck %s
; PR5596 ; PR5596
; IPSCCP should propagate the 0 argument, eliminate the switch, and propagate ; IPSCCP should propagate the 0 argument, eliminate the switch, and propagate
; the result. ; the result.
; CHECK: define i32 @main() #0 {
; CHECK-NEXT: entry:
; CHECK-NOT: call
; CHECK-NEXT: ret i32 123
define i32 @main() noreturn nounwind { define i32 @main() noreturn nounwind {
; CHECK-LABEL: @main(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 123
;
entry: entry:
%call2 = tail call i32 @wwrite(i64 0) nounwind %call2 = tail call i32 @wwrite(i64 0) nounwind
ret i32 %call2 ret i32 %call2
} }
define internal i32 @wwrite(i64 %i) nounwind readnone { define internal i32 @wwrite(i64 %i) nounwind readnone {
; CHECK-LABEL: @wwrite(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[SW_DEFAULT:%.*]]
; CHECK: sw.default:
; CHECK-NEXT: ret i32 undef
;
entry: entry:
switch i64 %i, label %sw.default [ switch i64 %i, label %sw.default [
i64 3, label %return i64 3, label %return