diff --git a/llvm/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll b/llvm/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll index a7583e4fe30ff..b3b94611116a5 100644 --- a/llvm/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll +++ b/llvm/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; Test normal folding @@ -71,9 +71,9 @@ TheDest: define i32 @test4(i32 %C) { ; CHECK-LABEL: @test4( ; CHECK-NEXT: L1: -; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 %C, 0 -; CHECK-NEXT: [[DOT:%.*]] = select i1 [[COND]], i32 1, i32 0 -; CHECK-NEXT: ret i32 [[DOT]] +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND]], i32 1, i32 0 +; CHECK-NEXT: ret i32 [[SPEC_SELECT]] ; switch i32 %C, label %L1 [ i32 0, label %L2 @@ -88,9 +88,9 @@ L2: define i32 @test5(i32 %C) { ; CHECK-LABEL: @test5( ; CHECK-NEXT: L1: -; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 %C, 0 -; CHECK-NEXT: [[DOT:%.*]] = select i1 [[COND]], i32 1, i32 0 -; CHECK-NEXT: ret i32 [[DOT]] +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND]], i32 1, i32 0 +; CHECK-NEXT: ret i32 [[SPEC_SELECT]] ; switch i32 %C, label %L1 [ i32 0, label %L2 diff --git a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll index 51baa5b7f9b3c..eaa2bb7f6baaf 100644 --- a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll +++ b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll @@ -4,7 +4,7 @@ define void @foo(i1 %C, i32* %P) { ; CHECK-LABEL: @foo( -; CHECK-NEXT: store i32 7, i32* [[P:%.*]] +; CHECK-NEXT: store i32 7, i32* [[P:%.*]], align 4 ; CHECK-NEXT: ret void ; br i1 %C, label %T, label %F diff --git a/llvm/test/Transforms/SimplifyCFG/PowerPC/cttz-ctlz-spec.ll b/llvm/test/Transforms/SimplifyCFG/PowerPC/cttz-ctlz-spec.ll index b81a923fa2c7c..1f2ddb92c98b3 100644 --- a/llvm/test/Transforms/SimplifyCFG/PowerPC/cttz-ctlz-spec.ll +++ b/llvm/test/Transforms/SimplifyCFG/PowerPC/cttz-ctlz-spec.ll @@ -1,13 +1,16 @@ -; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck -enable-var-scope %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s target datalayout = "E-m:e-i64:64-n32:64" target triple = "powerpc64-unknown-linux-gnu" define i64 @test1(i64 %A) { ; CHECK-LABEL: @test1( -; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0 -; CHECK-NEXT: [[CTLZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %A, i1 true) -; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i64 64, i64 [[CTLZ]] -; CHECK-NEXT: ret i64 [[SEL]] +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true) +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]] +; CHECK-NEXT: ret i64 [[SPEC_SELECT]] +; entry: %tobool = icmp eq i64 %A, 0 br i1 %tobool, label %cond.end, label %cond.true @@ -23,10 +26,12 @@ cond.end: ; preds = %entry, %cond.true define i64 @test1b(i64 %A) { ; CHECK-LABEL: @test1b( -; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0 -; CHECK-NEXT: [[CTTZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %A, i1 true) -; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i64 64, i64 [[CTTZ]] -; CHECK-NEXT: ret i64 [[SEL]] +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true) +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]] +; CHECK-NEXT: ret i64 [[SPEC_SELECT]] +; entry: %tobool = icmp eq i64 %A, 0 br i1 %tobool, label %cond.end, label %cond.true diff --git a/llvm/test/Transforms/SimplifyCFG/X86/disable-lookup-table.ll b/llvm/test/Transforms/SimplifyCFG/X86/disable-lookup-table.ll index 0d6b823bd88fe..07d0adb48a478 100644 --- a/llvm/test/Transforms/SimplifyCFG/X86/disable-lookup-table.ll +++ b/llvm/test/Transforms/SimplifyCFG/X86/disable-lookup-table.ll @@ -51,7 +51,7 @@ define i32 @bar(i32 %c) { ; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]] ; CHECK: switch.lookup: ; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table.bar, i32 0, i32 [[SWITCH_TABLEIDX]] -; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]] +; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, i32* [[SWITCH_GEP]], align 4 ; CHECK-NEXT: ret i32 [[SWITCH_LOAD]] ; CHECK: return: ; CHECK-NEXT: ret i32 15 diff --git a/llvm/test/Transforms/SimplifyCFG/X86/empty-cleanuppad.ll b/llvm/test/Transforms/SimplifyCFG/X86/empty-cleanuppad.ll index c682c1eebf0ed..7e378d1ed09b9 100644 --- a/llvm/test/Transforms/SimplifyCFG/X86/empty-cleanuppad.ll +++ b/llvm/test/Transforms/SimplifyCFG/X86/empty-cleanuppad.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S -hoist-common-insts=true | FileCheck %s ; ModuleID = 'cppeh-simplify.cpp' @@ -16,14 +17,12 @@ target triple = "x86_64-pc-windows-msvc18.0.0" ; In this case, both cleanup pads can be eliminated and the invoke can be ; converted to a call. ; -; CHECK: define void @f1() -; CHECK: entry: -; CHECK: call void @g() -; CHECK: ret void -; CHECK-NOT: cleanuppad -; CHECK: } -; define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f1( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: ret void +; entry: invoke void @g() to label %invoke.cont unwind label %ehcleanup @@ -56,22 +55,24 @@ ehcleanup.1: ; preds = %ehcleanup ; should unwind to the caller (that is, exception handling continues with the ; parent frame of the caller). ; -; CHECK: define void @f2() -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: ehcleanup: -; CHECK: cleanuppad within none -; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b) -; CHECK: cleanupret from %0 unwind label %catch.dispatch -; CHECK: catch.dispatch: -; CHECK: catchswitch within none [label %catch] unwind to caller -; CHECK: catch: -; CHECK: catchpad -; CHECK: catchret -; CHECK-NOT: cleanuppad -; CHECK: } -; define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[B:%.*]] = alloca [[STRUCT_S2:%.*]], align 1 +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[TRY_CONT:%.*]] unwind label [[EHCLEANUP:%.*]] +; CHECK: ehcleanup: +; CHECK-NEXT: [[TMP0:%.*]] = cleanuppad within none [] +; CHECK-NEXT: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[B]]) +; CHECK-NEXT: cleanupret from [[TMP0]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP1:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[TMP1]] to label [[TRY_CONT]] +; CHECK: try.cont: +; CHECK-NEXT: ret void +; entry: %b = alloca %struct.S2, align 1 invoke void @g() to label %invoke.cont unwind label %ehcleanup @@ -117,23 +118,25 @@ ehcleanup.1: ; ; In this case the inner cleanup pad should be eliminated and the invoke of g() ; should unwind directly to the catchpad. -; -; CHECK-LABEL: define void @f3() -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: to label %try.cont unwind label %catch.dispatch -; CHECK: catch.dispatch: -; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1 -; CHECK: catch: -; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null] -; CHECK: catchret -; CHECK: ehcleanup.1: -; CHECK: cleanuppad -; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a) -; CHECK: cleanupret from %cp3 unwind to caller -; CHECK: } -; + define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_S2:%.*]], align 1 +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind label [[EHCLEANUP_1:%.*]] +; CHECK: catch: +; CHECK-NEXT: [[CP2:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[CP2]] to label [[TRY_CONT]] +; CHECK: try.cont: +; CHECK-NEXT: ret void +; CHECK: ehcleanup.1: +; CHECK-NEXT: [[CP3:%.*]] = cleanuppad within none [] +; CHECK-NEXT: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[A]]) +; CHECK-NEXT: cleanupret from [[CP3]] unwind to caller +; entry: %a = alloca %struct.S2, align 1 invoke void @g() to label %invoke.cont unwind label %ehcleanup @@ -180,29 +183,30 @@ ehcleanup.1: ; catch block should be converted to a call (that is, that is, exception ; handling continues with the parent frame of the caller).) ; -; CHECK-LABEL: define void @f4() -; CHECK: entry: -; CHECK: call void @g ; Note: The cleanuppad simplification will insert an unconditional branch here ; but it will be eliminated, placing the following invoke in the entry BB. -; CHECK: invoke void @g() -; CHECK: to label %try.cont unwind label %catch.dispatch -; CHECK: catch.dispatch: -; CHECK: catchswitch within none [label %catch] unwind to caller -; CHECK: catch: -; CHECK: catchpad -; CHECK: catchret -; CHECK-NOT: cleanuppad -; CHECK: } ; define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f4( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[TMP0]] to label [[TRY_CONT]] +; CHECK: try.cont: +; CHECK-NEXT: ret void +; entry: invoke void @g() - to label %invoke.cont unwind label %ehcleanup + to label %invoke.cont unwind label %ehcleanup invoke.cont: ; preds = %entry invoke void @g() - to label %try.cont unwind label %catch.dispatch + to label %try.cont unwind label %catch.dispatch catch.dispatch: ; preds = %invoke.cont %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup @@ -238,24 +242,31 @@ ehcleanup: ; In this case, the cleanup pad should be eliminated and the PHI node in the ; cleanup pad should be sunk into the catch dispatch block. ; -; CHECK-LABEL: define i32 @f6() -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: invoke.cont: -; CHECK: invoke void @g() -; CHECK-NOT: ehcleanup: -; CHECK-NOT: cleanuppad -; CHECK: catch.dispatch: -; CHECK: %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] -; CHECK: } define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f6( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: invoke.cont: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[STATE_0:%.*]] = phi i32 [ 2, [[INVOKE_CONT]] ], [ 1, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[TMP0]] to label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[STATE_0]], [[CATCH:%.*]] ], [ 0, [[INVOKE_CONT]] ] +; CHECK-NEXT: ret i32 [[RETVAL_0]] +; entry: invoke void @g() - to label %invoke.cont unwind label %ehcleanup + to label %invoke.cont unwind label %ehcleanup invoke.cont: ; preds = %entry invoke void @g() - to label %return unwind label %ehcleanup + to label %return unwind label %ehcleanup ehcleanup: ; preds = %invoke.cont, %entry %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] @@ -295,30 +306,38 @@ return: ; preds = %invoke.cont, %catch ; In this case, the cleanup pad should be eliminated and the PHI node in the ; cleanup pad should be merged with the PHI node in the catch dispatch block. ; -; CHECK-LABEL: define i32 @f7() -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: invoke.cont: -; CHECK: invoke void @g() -; CHECK: invoke.cont.1: -; CHECK: invoke void @g() -; CHECK-NOT: ehcleanup: -; CHECK-NOT: cleanuppad -; CHECK: catch.dispatch: -; CHECK: %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ] -; CHECK: } define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f7( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: invoke.cont: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT_1:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: invoke.cont.1: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[STATE_1:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 3, [[INVOKE_CONT_1]] ], [ 2, [[INVOKE_CONT]] ] +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[TMP0]] to label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[STATE_1]], [[CATCH:%.*]] ], [ 0, [[INVOKE_CONT_1]] ] +; CHECK-NEXT: ret i32 [[RETVAL_0]] +; entry: invoke void @g() - to label %invoke.cont unwind label %catch.dispatch + to label %invoke.cont unwind label %catch.dispatch invoke.cont: ; preds = %entry invoke void @g() - to label %invoke.cont.1 unwind label %ehcleanup + to label %invoke.cont.1 unwind label %ehcleanup invoke.cont.1: ; preds = %invoke.cont invoke void @g() - to label %return unwind label %ehcleanup + to label %return unwind label %ehcleanup ehcleanup: ; preds = %invoke.cont.1, %invoke.cont %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ] @@ -365,24 +384,34 @@ return: ; preds = %invoke.cont.1, %cat ; should have an incoming value entry for path from 'foo' that references the ; PHI node itself. ; -; CHECK-LABEL: define void @f8() -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: invoke.cont: -; CHECK: invoke void @g() -; CHECK-NOT: ehcleanup: -; CHECK-NOT: cleanuppad -; CHECK: catch.dispatch: -; CHECK: %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ] -; CHECK: } define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f8( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: invoke.cont: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[X:%.*]] = phi i32 [ 2, [[INVOKE_CONT]] ], [ 1, [[ENTRY:%.*]] ], [ [[X]], [[CATCH_CONT:%.*]] ] +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: call void @use_x(i32 [[X]]) +; CHECK-NEXT: catchret from [[TMP0]] to label [[CATCH_CONT]] +; CHECK: catch.cont: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[RETURN]] unwind label [[CATCH_DISPATCH]] +; CHECK: return: +; CHECK-NEXT: ret void +; entry: invoke void @g() - to label %invoke.cont unwind label %ehcleanup + to label %invoke.cont unwind label %ehcleanup invoke.cont: ; preds = %entry invoke void @g() - to label %return unwind label %ehcleanup + to label %return unwind label %ehcleanup ehcleanup: ; preds = %invoke.cont, %entry %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] @@ -399,24 +428,33 @@ catch: ; preds = %catch.dispatch catch.cont: ; preds = %catch invoke void @g() - to label %return unwind label %catch.dispatch + to label %return unwind label %catch.dispatch return: ; preds = %invoke.cont, %catch.cont ret void } -; CHECK-LABEL: define i32 @f9() -; CHECK: entry: -; CHECK: invoke void @"\01??1S2@@QEAA@XZ"( -; CHECK-NOT: cleanuppad -; CHECK: catch.dispatch: -; CHECK: } define i32 @f9() personality i32 (...)* @__CxxFrameHandler3 { +; CHECK-LABEL: @f9( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[S:%.*]] = alloca i8, align 1 +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[S]]) +; CHECK-NEXT: [[BC:%.*]] = bitcast i8* [[S]] to %struct.S2* +; CHECK-NEXT: invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* [[BC]]) +; CHECK-NEXT: to label [[TRY_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[CATCH_SWITCH:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[CATCH_PAD:%.*]] = catchpad within [[CATCH_SWITCH]] [i8* null, i32 0, i8* null] +; CHECK-NEXT: catchret from [[CATCH_PAD]] to label [[TRY_CONT]] +; CHECK: try.cont: +; CHECK-NEXT: ret i32 0 +; entry: %s = alloca i8, align 1 call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %s) %bc = bitcast i8* %s to %struct.S2* invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* %bc) - to label %try.cont unwind label %ehcleanup + to label %try.cont unwind label %ehcleanup ehcleanup: %cleanup.pad = cleanuppad within none [] @@ -434,13 +472,15 @@ try.cont: ret i32 0 } -; CHECK-LABEL: define void @f10( define void @f10(i32 %V) personality i32 (...)* @__CxxFrameHandler3 { +; CHECK-LABEL: @f10( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: unreachable +; entry: invoke void @g() - to label %unreachable unwind label %cleanup -; CHECK: call void @g() -; CHECK-NEXT: unreachable + to label %unreachable unwind label %cleanup unreachable: unreachable @@ -448,7 +488,7 @@ unreachable: cleanup: %cp = cleanuppad within none [] switch i32 %V, label %cleanupret1 [ - i32 0, label %cleanupret2 + i32 0, label %cleanupret2 ] cleanupret1: @@ -458,37 +498,39 @@ cleanupret2: cleanupret from %cp unwind to caller } -; CHECK-LABEL: define void @f11( ; This case tests the handling of an empty cleanup pad that ; contains a lifetime_end intrinsic and does not dominate its ; successor. -; CHECK: entry: -; CHECK: invoke void @g() -; CHECK: invoke.cont: -; CHECK: invoke void @g() -; CHECK: invoke.cont2: -; CHECK: invoke void @g() -; CHECK-NOT: ehcleanup: -; CHECK-NOT: phi -; CHECK-NOT: cleanuppad -; CHECK-NOT: lifetime.end -; CHECK: catch.dispatch: -; CHECK: catchswitch -; CHECK: catch: -; CHECK: catchret -; CHECK: } define void @f11() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @f11( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: invoke.cont: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: invoke.cont2: +; CHECK-NEXT: invoke void @g() +; CHECK-NEXT: to label [[RETURN:%.*]] unwind label [[CATCH_DISPATCH]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: catchret from [[TMP0]] to label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; entry: invoke void @g() - to label %invoke.cont unwind label %ehcleanup + to label %invoke.cont unwind label %ehcleanup invoke.cont: ; preds = %entry invoke void @g() - to label %invoke.cont2 unwind label %ehcleanup + to label %invoke.cont2 unwind label %ehcleanup invoke.cont2: ; preds = %invoke.cont invoke void @g() - to label %return unwind label %catch.dispatch + to label %return unwind label %catch.dispatch ehcleanup: ; preds = %invoke.cont, %entry %x = phi i8* [ undef, %invoke.cont ], [ undef, %entry ] diff --git a/llvm/test/Transforms/SimplifyCFG/X86/merge-cond-stores-cost.ll b/llvm/test/Transforms/SimplifyCFG/X86/merge-cond-stores-cost.ll index 9813ea652005a..efb2c864bfbe7 100644 --- a/llvm/test/Transforms/SimplifyCFG/X86/merge-cond-stores-cost.ll +++ b/llvm/test/Transforms/SimplifyCFG/X86/merge-cond-stores-cost.ll @@ -8,14 +8,14 @@ define void @test_costly(i32* %p, i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-NEXT: br i1 [[X1]], label [[FALLTHROUGH:%.*]], label [[YES1:%.*]] ; CHECK: yes1: ; CHECK-NEXT: [[VAL0:%.*]] = sdiv i32 [[D:%.*]], [[C:%.*]] -; CHECK-NEXT: store i32 [[VAL0]], i32* [[P:%.*]] +; CHECK-NEXT: store i32 [[VAL0]], i32* [[P:%.*]], align 4 ; CHECK-NEXT: br label [[FALLTHROUGH]] ; CHECK: fallthrough: ; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[B:%.*]], 0 ; CHECK-NEXT: br i1 [[X2]], label [[END:%.*]], label [[YES2:%.*]] ; CHECK: yes2: ; CHECK-NEXT: [[VAL1:%.*]] = sdiv i32 [[C]], [[D]] -; CHECK-NEXT: store i32 [[VAL1]], i32* [[P]] +; CHECK-NEXT: store i32 [[VAL1]], i32* [[P]], align 4 ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/SimplifyCFG/basictest.ll b/llvm/test/Transforms/SimplifyCFG/basictest.ll index 9f9ed4ab9eacf..4f8372703d133 100644 --- a/llvm/test/Transforms/SimplifyCFG/basictest.ll +++ b/llvm/test/Transforms/SimplifyCFG/basictest.ll @@ -1,39 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test CFG simplify removal of branch instructions. ; ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; RUN: opt < %s -passes=simplify-cfg -S | FileCheck %s define void @test1() { - br label %1 - ret void ; CHECK-LABEL: @test1( -; CHECK-NEXT: ret void +; CHECK-NEXT: ret void +; + br label %1 + ret void } define void @test2() { - ret void - ret void ; CHECK-LABEL: @test2( -; CHECK-NEXT: ret void -; CHECK-NEXT: } +; CHECK-NEXT: ret void +; + ret void + ret void } define void @test3(i1 %T) { - br i1 %T, label %1, label %1 - ret void ; CHECK-LABEL: @test3( -; CHECK-NEXT: ret void +; CHECK-NEXT: ret void +; + br i1 %T, label %1, label %1 + ret void } ; Folding branch to a common destination. -; CHECK-LABEL: @test4_fold -; CHECK: %cmp1 = icmp eq i32 %a, %b -; CHECK: %cmp2 = icmp ugt i32 %a, 0 -; CHECK: %or.cond = and i1 %cmp1, %cmp2 -; CHECK: br i1 %or.cond, label %else, label %untaken -; CHECK-NOT: taken: -; CHECK: ret void define void @test4_fold(i32 %a, i32 %b) { +; CHECK-LABEL: @test4_fold( +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[A]], 0 +; CHECK-NEXT: [[OR_COND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: br i1 [[OR_COND]], label [[ELSE:%.*]], label [[UNTAKEN:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @foo() +; CHECK-NEXT: ret void +; CHECK: untaken: +; CHECK-NEXT: ret void +; %cmp1 = icmp eq i32 %a, %b br i1 %cmp1, label %taken, label %untaken @@ -51,12 +58,12 @@ untaken: ; Prefer a simplification based on a dominating condition rather than folding a ; branch to a common destination. -; CHECK-LABEL: @test4 -; CHECK-NOT: br -; CHECK-NOT: br -; CHECK-NOT: call -; CHECK: ret void define void @test4_no_fold(i32 %a, i32 %b) { +; CHECK-LABEL: @test4_no_fold( +; CHECK-NEXT: untaken: +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret void +; %cmp1 = icmp eq i32 %a, %b br i1 %cmp1, label %taken, label %untaken @@ -76,9 +83,12 @@ declare void @foo() ; PR5795 define void @test5(i32 %A) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: ret void +; switch i32 %A, label %return [ - i32 2, label %1 - i32 10, label %2 + i32 2, label %1 + i32 10, label %2 ] ret void @@ -87,18 +97,22 @@ define void @test5(i32 %A) { return: ; preds = %entry ret void -; CHECK-LABEL: @test5( -; CHECK-NEXT: ret void } ; PR14893 define i8 @test6f() { -; CHECK-LABEL: @test6f -; CHECK: alloca i8, align 1 -; CHECK-NEXT: call i8 @test6g -; CHECK-NEXT: icmp eq i8 %tmp, 0 -; CHECK-NEXT: load i8, i8* %r, align 1{{$}} +; CHECK-LABEL: @test6f( +; CHECK-NEXT: bb0: +; CHECK-NEXT: [[R:%.*]] = alloca i8, align 1 +; CHECK-NEXT: [[TMP:%.*]] = call i8 @test6g(i8* [[R]]) +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[TMP]], 0 +; CHECK-NEXT: [[TMP3:%.*]] = load i8, i8* [[R]], align 1 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i8 [[TMP3]], 1 +; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP1]], i1 true, i1 [[TMP4]] +; CHECK-NEXT: [[TMP6:%.*]] = select i1 [[OR_COND]], i8 0, i8 1 +; CHECK-NEXT: ret i8 [[TMP6]] +; bb0: %r = alloca i8, align 1 diff --git a/llvm/test/Transforms/SimplifyCFG/div-rem-pairs.ll b/llvm/test/Transforms/SimplifyCFG/div-rem-pairs.ll index 621151c8a05ff..db3879f95dfb7 100644 --- a/llvm/test/Transforms/SimplifyCFG/div-rem-pairs.ll +++ b/llvm/test/Transforms/SimplifyCFG/div-rem-pairs.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s ; We could hoist the div/rem in these tests because it's safe to do so. @@ -7,14 +8,14 @@ define i32 @hoist_sdiv(i32 %a, i32 %b) { ; CHECK-LABEL: @hoist_sdiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -34,14 +35,14 @@ end: define i64 @hoist_udiv(i64 %a, i64 %b) { ; CHECK-LABEL: @hoist_udiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = urem i64 %a, %b +; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = udiv i64 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i64 [[RET]] ; entry: @@ -61,14 +62,14 @@ end: define i16 @hoist_srem(i16 %a, i16 %b) { ; CHECK-LABEL: @hoist_srem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[REM:%.*]] = srem i16 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM:%.*]] = srem i16 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i16 [[RET]] ; entry: @@ -88,14 +89,14 @@ end: define i8 @hoist_urem(i8 %a, i8 %b) { ; CHECK-LABEL: @hoist_urem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i8 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[REM:%.*]] = urem i8 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM:%.*]] = urem i8 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i8 [[RET]] ; entry: diff --git a/llvm/test/Transforms/SimplifyCFG/guards.ll b/llvm/test/Transforms/SimplifyCFG/guards.ll index 51fe86a13f7d7..e11d64dbedd21 100644 --- a/llvm/test/Transforms/SimplifyCFG/guards.ll +++ b/llvm/test/Transforms/SimplifyCFG/guards.ll @@ -64,15 +64,15 @@ merge_block: define i32 @f_3(i1* %c, i32* %buf) { ; CHECK-LABEL: @f_3( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[C0:%.*]] = load volatile i1, i1* [[C:%.*]] +; CHECK-NEXT: [[C0:%.*]] = load volatile i1, i1* [[C:%.*]], align 1 ; CHECK-NEXT: br i1 [[C0]], label [[GUARD_BLOCK:%.*]], label [[MERGE_BLOCK:%.*]] ; CHECK: guard_block: ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] ; CHECK-NEXT: unreachable ; CHECK: merge_block: -; CHECK-NEXT: [[C1:%.*]] = load volatile i1, i1* [[C]] -; CHECK-NEXT: [[DOT:%.*]] = select i1 [[C1]], i32 50, i32 100 -; CHECK-NEXT: ret i32 [[DOT]] +; CHECK-NEXT: [[C1:%.*]] = load volatile i1, i1* [[C]], align 1 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C1]], i32 50, i32 100 +; CHECK-NEXT: ret i32 [[SPEC_SELECT]] ; entry: %c0 = load volatile i1, i1* %c diff --git a/llvm/test/Transforms/SimplifyCFG/implied-cond.ll b/llvm/test/Transforms/SimplifyCFG/implied-cond.ll index dae7ad85d0fdc..97eb060d11b9b 100644 --- a/llvm/test/Transforms/SimplifyCFG/implied-cond.ll +++ b/llvm/test/Transforms/SimplifyCFG/implied-cond.ll @@ -1,17 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt %s -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 | FileCheck %s ; Check for when one branch implies the value of a successors conditional and ; it's not simply the same conditional repeated. define void @test(i32 %length.i, i32 %i) { -; CHECK-LABEL: @test +; CHECK-LABEL: @test( +; CHECK-NEXT: [[IPLUS1:%.*]] = add nsw i32 [[I:%.*]], 1 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 [[IPLUS1]], [[LENGTH_I:%.*]] +; CHECK-NEXT: br i1 [[VAR29]], label [[IN_BOUNDS:%.*]], label [[OUT_OF_BOUNDS:%.*]] +; CHECK: in_bounds: +; CHECK-NEXT: ret void +; CHECK: out_of_bounds: +; CHECK-NEXT: call void @foo(i64 0) +; CHECK-NEXT: unreachable +; %iplus1 = add nsw i32 %i, 1 %var29 = icmp slt i32 %iplus1, %length.i -; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds br i1 %var29, label %next, label %out_of_bounds next: -; CHECK-LABEL: in_bounds: -; CHECK-NEXT: ret void %var30 = icmp slt i32 %i, %length.i br i1 %var30, label %in_bounds, label %out_of_bounds2 @@ -30,15 +37,28 @@ out_of_bounds2: ; If the add is not nsw, it's not safe to use the fact about i+1 to imply the ; i condition since it could have overflowed. define void @test_neg(i32 %length.i, i32 %i) { -; CHECK-LABEL: @test_neg +; CHECK-LABEL: @test_neg( +; CHECK-NEXT: [[IPLUS1:%.*]] = add i32 [[I:%.*]], 1 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 [[IPLUS1]], [[LENGTH_I:%.*]] +; CHECK-NEXT: br i1 [[VAR29]], label [[NEXT:%.*]], label [[OUT_OF_BOUNDS:%.*]] +; CHECK: next: +; CHECK-NEXT: [[VAR30:%.*]] = icmp slt i32 [[I]], [[LENGTH_I]] +; CHECK-NEXT: br i1 [[VAR30]], label [[IN_BOUNDS:%.*]], label [[OUT_OF_BOUNDS2:%.*]] +; CHECK: in_bounds: +; CHECK-NEXT: ret void +; CHECK: out_of_bounds: +; CHECK-NEXT: call void @foo(i64 0) +; CHECK-NEXT: unreachable +; CHECK: out_of_bounds2: +; CHECK-NEXT: call void @foo(i64 1) +; CHECK-NEXT: unreachable +; %iplus1 = add i32 %i, 1 %var29 = icmp slt i32 %iplus1, %length.i -; CHECK: br i1 %var29, label %next, label %out_of_bounds br i1 %var29, label %next, label %out_of_bounds next: %var30 = icmp slt i32 %i, %length.i -; CHECK: br i1 %var30, label %in_bounds, label %out_of_bounds2 br i1 %var30, label %in_bounds, label %out_of_bounds2 in_bounds: @@ -55,10 +75,18 @@ out_of_bounds2: define void @test2(i32 %length.i, i32 %i) { -; CHECK-LABEL: @test2 +; CHECK-LABEL: @test2( +; CHECK-NEXT: [[IPLUS100:%.*]] = add nsw i32 [[I:%.*]], 100 +; CHECK-NEXT: [[VAR29:%.*]] = icmp slt i32 [[IPLUS100]], [[LENGTH_I:%.*]] +; CHECK-NEXT: br i1 [[VAR29]], label [[IN_BOUNDS:%.*]], label [[OUT_OF_BOUNDS:%.*]] +; CHECK: in_bounds: +; CHECK-NEXT: ret void +; CHECK: out_of_bounds: +; CHECK-NEXT: call void @foo(i64 0) +; CHECK-NEXT: unreachable +; %iplus100 = add nsw i32 %i, 100 %var29 = icmp slt i32 %iplus100, %length.i -; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds br i1 %var29, label %next, label %out_of_bounds next: diff --git a/llvm/test/Transforms/SimplifyCFG/inline-asm-sink.ll b/llvm/test/Transforms/SimplifyCFG/inline-asm-sink.ll index 8200b813c75b3..163fa8a7c8e02 100644 --- a/llvm/test/Transforms/SimplifyCFG/inline-asm-sink.ll +++ b/llvm/test/Transforms/SimplifyCFG/inline-asm-sink.ll @@ -1,29 +1,37 @@ -; RUN: opt < %s -mem2reg -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck -enable-var-scope %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -mem2reg -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s define i32 @test(i32 %x) { -; CHECK-LABEL: @test +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[X:%.*]], 0 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TMP1:%.*]] = call i32 asm "mov $0, #1", "=r"() #[[ATTR0:[0-9]+]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TMP2:%.*]] = call i32 asm "mov $0, #2", "=r"() #[[ATTR0]] +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[Y_0:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP2]], [[IF_ELSE]] ] +; CHECK-NEXT: ret i32 [[Y_0]] +; entry: %y = alloca i32, align 4 %tobool = icmp ne i32 %x, 0 br i1 %tobool, label %if.then, label %if.else if.then: -; CHECK: if.then: -; CHECK: [[ASM1:%.*]] = call i32 asm "mov $0, #1", "=r"() %tmp1 = call i32 asm "mov $0, #1", "=r"() nounwind readnone store i32 %tmp1, i32* %y, align 4 br label %if.end if.else: -; CHECK: if.else: -; CHECK: [[ASM2:%.*]] = call i32 asm "mov $0, #2", "=r"() %tmp2 = call i32 asm "mov $0, #2", "=r"() nounwind readnone store i32 %tmp2, i32* %y, align 4 br label %if.end if.end: -; CHECK: if.end: -; CHECK: {{%.*}} = phi i32 [ [[ASM1]], %if.then ], [ [[ASM2]], %if.else ] %tmp3 = load i32, i32* %y, align 4 ret i32 %tmp3 } diff --git a/llvm/test/Transforms/SimplifyCFG/invoke.ll b/llvm/test/Transforms/SimplifyCFG/invoke.ll index 5e0d2627b546d..82ac7e30f959c 100644 --- a/llvm/test/Transforms/SimplifyCFG/invoke.ll +++ b/llvm/test/Transforms/SimplifyCFG/invoke.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" @@ -9,153 +10,187 @@ declare i32 @nounwind_fn() nounwind declare i32 @fn() -; CHECK-LABEL: @f1( define i8* @f1() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @f1( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; entry: -; CHECK: call void @llvm.trap() -; CHECK: unreachable %call = invoke noalias i8* undef() - to label %invoke.cont unwind label %lpad + to label %invoke.cont unwind label %lpad invoke.cont: ret i8* %call lpad: %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer + filter [0 x i8*] zeroinitializer %1 = extractvalue { i8*, i32 } %0, 0 tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind unreachable } -; CHECK-LABEL: @f2( define i8* @f2() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @f2( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; entry: -; CHECK: call void @llvm.trap() -; CHECK: unreachable %call = invoke noalias i8* null() - to label %invoke.cont unwind label %lpad + to label %invoke.cont unwind label %lpad invoke.cont: ret i8* %call lpad: %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer + filter [0 x i8*] zeroinitializer %1 = extractvalue { i8*, i32 } %0, 0 tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind unreachable } -; CHECK-LABEL: @f2_no_null_opt( define i8* @f2_no_null_opt() nounwind uwtable ssp #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @f2_no_null_opt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = invoke noalias i8* null() +; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: invoke.cont: +; CHECK-NEXT: ret i8* [[CALL]] +; CHECK: lpad: +; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: filter [0 x i8*] zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0 +; CHECK-NEXT: tail call void @__cxa_call_unexpected(i8* [[TMP1]]) #[[ATTR6:[0-9]+]] +; CHECK-NEXT: unreachable +; entry: -; CHECK: invoke noalias i8* null() %call = invoke noalias i8* null() - to label %invoke.cont unwind label %lpad + to label %invoke.cont unwind label %lpad -; CHECK: invoke.cont: -; CHECK: ret i8* %call invoke.cont: ret i8* %call lpad: %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer + filter [0 x i8*] zeroinitializer %1 = extractvalue { i8*, i32 } %0, 0 tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind -; CHECK: unreachable unreachable } -; CHECK-LABEL: @f3( define i32 @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK-NEXT: entry +; CHECK-LABEL: @f3( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 3 +; entry: -; CHECK-NEXT: ret i32 3 %call = invoke i32 @read_only() - to label %invoke.cont unwind label %lpad + to label %invoke.cont unwind label %lpad invoke.cont: ret i32 3 lpad: %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer + filter [0 x i8*] zeroinitializer %1 = extractvalue { i8*, i32 } %0, 0 tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind unreachable } -; CHECK-LABEL: @f4( define i32 @f4() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK-NEXT: entry +; CHECK-LABEL: @f4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = call i32 @read_only() +; CHECK-NEXT: ret i32 [[CALL]] +; entry: -; CHECK-NEXT: call i32 @read_only() %call = invoke i32 @read_only() - to label %invoke.cont unwind label %lpad + to label %invoke.cont unwind label %lpad invoke.cont: -; CHECK-NEXT: ret i32 %call ret i32 %call lpad: %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer + filter [0 x i8*] zeroinitializer %1 = extractvalue { i8*, i32 } %0, 0 tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind unreachable } -; CHECK-LABEL: @f5( define i32 @f5(i1 %cond, i8* %a, i8* %b) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @f5( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[X:%.*]], label [[Y:%.*]] +; CHECK: x: +; CHECK-NEXT: [[CALL:%.*]] = invoke i32 @fn() +; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: y: +; CHECK-NEXT: [[CALL2:%.*]] = call i32 @nounwind_fn() +; CHECK-NEXT: br label [[CONT]] +; CHECK: cont: +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[CALL]], [[X]] ], [ [[CALL2]], [[Y]] ] +; CHECK-NEXT: ret i32 [[PHI]] +; CHECK: lpad: +; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: filter [0 x i8*] zeroinitializer +; CHECK-NEXT: tail call void @__cxa_call_unexpected(i8* [[A:%.*]]) #[[ATTR6]] +; CHECK-NEXT: unreachable +; entry: br i1 %cond, label %x, label %y x: -; CHECK: invoke i32 @fn() %call = invoke i32 @fn() - to label %cont unwind label %lpad + to label %cont unwind label %lpad y: -; CHECK: call i32 @nounwind_fn() %call2 = invoke i32 @nounwind_fn() - to label %cont unwind label %lpad + to label %cont unwind label %lpad cont: -; CHECK: phi i32 -; CHECK: ret i32 %phi %phi = phi i32 [%call, %x], [%call2, %y] ret i32 %phi lpad: -; CHECK-NOT: phi %phi2 = phi i8* [%a, %x], [%b, %y] %0 = landingpad { i8*, i32 } - filter [0 x i8*] zeroinitializer -; CHECK: __cxa_call_unexpected(i8* %a) + filter [0 x i8*] zeroinitializer tail call void @__cxa_call_unexpected(i8* %phi2) noreturn nounwind unreachable } -; CHECK-LABEL: @f6( define void @f6() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: @f6( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FOO:%.*]] = invoke i32 @fn() +; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD:%.*]] +; CHECK: invoke.cont2: +; CHECK-NEXT: ret void +; CHECK: lpad: +; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: ret void +; entry: invoke void @purefn() - to label %invoke.cont1 unwind label %lpad + to label %invoke.cont1 unwind label %lpad invoke.cont1: %foo = invoke i32 @fn() - to label %invoke.cont2 unwind label %lpad + to label %invoke.cont2 unwind label %lpad invoke.cont2: ret void lpad: -; CHECK-NOT: phi %tmp = phi i8* [ null, %invoke.cont1 ], [ null, %entry ] landingpad { i8*, i32 } - cleanup + cleanup ret void } diff --git a/llvm/test/Transforms/SimplifyCFG/invoke_unwind.ll b/llvm/test/Transforms/SimplifyCFG/invoke_unwind.ll index bf832111fbaee..ac79556b3cea8 100644 --- a/llvm/test/Transforms/SimplifyCFG/invoke_unwind.ll +++ b/llvm/test/Transforms/SimplifyCFG/invoke_unwind.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s declare void @bar() @@ -6,30 +7,32 @@ declare void @bar() ; instructions to call instructions if the handler just rethrows the exception. define i32 @test1() personality i32 (...)* @__gxx_personality_v0 { ; CHECK-LABEL: @test1( -; CHECK-NEXT: call void @bar(), !prof ![[PROF:[0-9]+]] -; CHECK-NEXT: ret i32 0 - invoke void @bar( ) - to label %1 unwind label %Rethrow, !prof !0 - ret i32 0 +; CHECK-NEXT: call void @bar(), !prof !0 +; CHECK-NEXT: ret i32 0 +; + invoke void @bar( ) + to label %1 unwind label %Rethrow, !prof !0 + ret i32 0 Rethrow: - %exn = landingpad {i8*, i32} - catch i8* null - resume { i8*, i32 } %exn + %exn = landingpad {i8*, i32} + catch i8* null + resume { i8*, i32 } %exn } !0 = !{!"branch_weights", i32 369, i32 2} define i32 @test2() personality i32 (...)* @__gxx_personality_v0 { ; CHECK-LABEL: @test2( -; CHECK-NEXT: call void @bar() [ "foo"(i32 100) ] -; CHECK-NEXT: ret i32 0 - invoke void @bar( ) [ "foo"(i32 100) ] - to label %1 unwind label %Rethrow - ret i32 0 +; CHECK-NEXT: call void @bar() [ "foo"(i32 100) ] +; CHECK-NEXT: ret i32 0 +; + invoke void @bar( ) [ "foo"(i32 100) ] + to label %1 unwind label %Rethrow + ret i32 0 Rethrow: - %exn = landingpad {i8*, i32} - catch i8* null - resume { i8*, i32 } %exn + %exn = landingpad {i8*, i32} + catch i8* null + resume { i8*, i32 } %exn } declare i64 @dummy1() @@ -39,20 +42,29 @@ declare i64 @dummy2() ; instructions to call instructions if they share a common trivial unwind ; block. define i64 @test3(i1 %cond) personality i32 (...)* @__gxx_personality_v0 { -entry: ; CHECK-LABEL: @test3( -; CHECK: %call1 = call i64 @dummy1() -; CHECK: %call2 = call i64 @dummy2() -; CHECK-NOT: resume { i8*, i32 } %lp +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[BR1:%.*]], label [[BR2:%.*]] +; CHECK: br1: +; CHECK-NEXT: [[CALL1:%.*]] = call i64 @dummy1() +; CHECK-NEXT: br label [[INVOKE_CONT:%.*]] +; CHECK: br2: +; CHECK-NEXT: [[CALL2:%.*]] = call i64 @dummy2() +; CHECK-NEXT: br label [[INVOKE_CONT]] +; CHECK: invoke.cont: +; CHECK-NEXT: [[C:%.*]] = phi i64 [ [[CALL1]], [[BR1]] ], [ [[CALL2]], [[BR2]] ] +; CHECK-NEXT: ret i64 [[C]] +; +entry: br i1 %cond, label %br1, label %br2 br1: %call1 = invoke i64 @dummy1() - to label %invoke.cont unwind label %lpad1 + to label %invoke.cont unwind label %lpad1 br2: %call2 = invoke i64 @dummy2() - to label %invoke.cont unwind label %lpad2 + to label %invoke.cont unwind label %lpad2 invoke.cont: %c = phi i64 [%call1, %br1], [%call2, %br2] @@ -61,7 +73,7 @@ invoke.cont: lpad1: %0 = landingpad { i8*, i32 } - cleanup + cleanup br label %rethrow rethrow: @@ -70,10 +82,8 @@ rethrow: lpad2: %1 = landingpad { i8*, i32 } - cleanup + cleanup br label %rethrow } declare i32 @__gxx_personality_v0(...) - -; CHECK: ![[PROF]] = !{!"branch_weights", i32 371} diff --git a/llvm/test/Transforms/SimplifyCFG/merge-default.ll b/llvm/test/Transforms/SimplifyCFG/merge-default.ll index c503f374a08a6..28e5a292091f3 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-default.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-default.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" @@ -8,27 +9,27 @@ declare void @f() define void @foo(i32 %Kind) { ; CHECK-LABEL: @foo( -; CHECK-NEXT:entry: -; CHECK-NEXT: switch i32 %Kind, label %sw.epilog [ -; CHECK-NEXT: i32 15, label %sw.bb2 -; CHECK-NEXT: i32 2, label %sw.bb -; CHECK-NEXT: ] -; CHECK: sw.bb: -; CHECK-NEXT: call void @g() -; CHECK-NEXT: call void @g() -; CHECK-NEXT: br label %sw.epilog -; CHECK: sw.bb2: -; CHECK-NEXT: call void @f() -; CHECK-NEXT: br label %sw.epilog -; CHECK: sw.epilog: -; CHECK-NEXT: ret void -; CHECK-NEXT:} +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[KIND:%.*]], label [[SW_EPILOG:%.*]] [ +; CHECK-NEXT: i32 15, label [[SW_BB2:%.*]] +; CHECK-NEXT: i32 2, label [[SW_BB:%.*]] +; CHECK-NEXT: ] +; CHECK: sw.bb: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: call void @g() +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.bb2: +; CHECK-NEXT: call void @f() +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.epilog: +; CHECK-NEXT: ret void +; entry: switch i32 %Kind, label %sw.epilog [ - i32 1, label %sw.epilog - i32 2, label %sw.bb - i32 15, label %sw.bb2 + i32 1, label %sw.epilog + i32 2, label %sw.bb + i32 15, label %sw.bb2 ] sw.bb: diff --git a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll index 5da4ec2628b62..4d44042a4892b 100644 --- a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll +++ b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll @@ -11,8 +11,8 @@ define i32 @upper_bound(i32* %r, i32 %high, i32 %k) nounwind { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[WHILE_COND:%.*]] ; CHECK: while.cond: -; CHECK-NEXT: [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH:%.*]], [[ENTRY:%.*]] ], [ [[DIV_HIGH_ADDR_0:%.*]], [[WHILE_BODY:%.*]] ] -; CHECK-NEXT: [[LOW_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[LOW_0_ADD2:%.*]], [[WHILE_BODY]] ] +; CHECK-NEXT: [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH:%.*]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[WHILE_BODY:%.*]] ] +; CHECK-NEXT: [[LOW_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[SPEC_SELECT1:%.*]], [[WHILE_BODY]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LOW_0]], [[HIGH_ADDR_0]] ; CHECK-NEXT: br i1 [[CMP]], label [[WHILE_BODY]], label [[WHILE_END:%.*]] ; CHECK: while.body: @@ -20,11 +20,11 @@ define i32 @upper_bound(i32* %r, i32 %high, i32 %k) nounwind { ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[ADD]], 2 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[DIV]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[R:%.*]], i64 [[IDXPROM]] -; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARRAYIDX]] +; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[K:%.*]], [[TMP0]] ; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[DIV]], 1 -; CHECK-NEXT: [[DIV_HIGH_ADDR_0]] = select i1 [[CMP1]], i32 [[DIV]], i32 [[HIGH_ADDR_0]] -; CHECK-NEXT: [[LOW_0_ADD2]] = select i1 [[CMP1]], i32 [[LOW_0]], i32 [[ADD2]] +; CHECK-NEXT: [[SPEC_SELECT]] = select i1 [[CMP1]], i32 [[DIV]], i32 [[HIGH_ADDR_0]] +; CHECK-NEXT: [[SPEC_SELECT1]] = select i1 [[CMP1]], i32 [[LOW_0]], i32 [[ADD2]] ; CHECK-NEXT: br label [[WHILE_COND]] ; CHECK: while.end: ; CHECK-NEXT: ret i32 [[LOW_0]] diff --git a/llvm/test/Transforms/SimplifyCFG/noreturn-call.ll b/llvm/test/Transforms/SimplifyCFG/noreturn-call.ll index f891fb349a6f4..7a26b7870e35a 100644 --- a/llvm/test/Transforms/SimplifyCFG/noreturn-call.ll +++ b/llvm/test/Transforms/SimplifyCFG/noreturn-call.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; PR1796 @@ -6,7 +7,7 @@ declare void @Finisher(i32) noreturn ; Make sure we optimize a sequence of two calls (second unreachable); define void @double_call(i32) { ; CHECK-LABEL: @double_call( -; CHECK-NEXT: tail call void @Finisher(i32 %0) #0 +; CHECK-NEXT: tail call void @Finisher(i32 [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: unreachable ; tail call void @Finisher(i32 %0) noreturn @@ -18,7 +19,7 @@ define void @double_call(i32) { ; is that it must be followed by [optional bitcast then] ret). define void @must_tail(i32) { ; CHECK-LABEL: @must_tail( -; CHECK-NEXT: musttail call void @Finisher(i32 %0) #0 +; CHECK-NEXT: musttail call void @Finisher(i32 [[TMP0:%.*]]) #[[ATTR0]] ; CHECK-NEXT: ret void ; musttail call void @Finisher(i32 %0) #0 diff --git a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights-switch-create.ll b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights-switch-create.ll index dd463b1b24138..5cea6c879dd53 100644 --- a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights-switch-create.ll +++ b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights-switch-create.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S -o - < %s | FileCheck %s declare void @func2(i32) @@ -8,12 +9,27 @@ declare void @func8(i32) ;; test1 - create a switch with case 2 and case 4 from two branches: N == 2 ;; and N == 4. define void @test1(i32 %N) nounwind uwtable { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[N:%.*]], label [[IF_ELSE8:%.*]] [ +; CHECK-NEXT: i32 2, label [[IF_THEN:%.*]] +; CHECK-NEXT: i32 4, label [[IF_THEN7:%.*]] +; CHECK-NEXT: ], !prof !0 +; CHECK: if.then: +; CHECK-NEXT: call void @func2(i32 [[N]]) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: br label [[IF_END9:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: call void @func4(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[IF_END9]] +; CHECK: if.else8: +; CHECK-NEXT: call void @func8(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[IF_END9]] +; CHECK: if.end9: +; CHECK-NEXT: ret void +; entry: %cmp = icmp eq i32 %N, 2 br i1 %cmp, label %if.then, label %if.else, !prof !0 -; CHECK: test1 -; CHECK: switch i32 %N -; CHECK: ], !prof !0 if.then: call void @func2(i32 %N) nounwind @@ -40,21 +56,45 @@ if.end9: ;; test2 - Merge two switches where PredDefault == BB. define void @test2(i32 %M, i32 %N) nounwind uwtable { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[M:%.*]], 2 +; CHECK-NEXT: br i1 [[CMP]], label [[SW1:%.*]], label [[SW2:%.*]] +; CHECK: sw1: +; CHECK-NEXT: switch i32 [[N:%.*]], label [[SW_EPILOG:%.*]] [ +; CHECK-NEXT: i32 2, label [[SW_BB:%.*]] +; CHECK-NEXT: i32 3, label [[SW_BB1:%.*]] +; CHECK-NEXT: i32 4, label [[SW_BB5:%.*]] +; CHECK-NEXT: ], !prof !1 +; CHECK: sw.bb: +; CHECK-NEXT: call void @func2(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.bb1: +; CHECK-NEXT: call void @func4(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw2: +; CHECK-NEXT: switch i32 [[N]], label [[SW_EPILOG]] [ +; CHECK-NEXT: i32 2, label [[SW_BB4:%.*]] +; CHECK-NEXT: i32 4, label [[SW_BB5]] +; CHECK-NEXT: ], !prof !2 +; CHECK: sw.bb4: +; CHECK-NEXT: call void @func6(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.bb5: +; CHECK-NEXT: call void @func8(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.epilog: +; CHECK-NEXT: ret void +; entry: %cmp = icmp sgt i32 %M, 2 br i1 %cmp, label %sw1, label %sw2 sw1: switch i32 %N, label %sw2 [ - i32 2, label %sw.bb - i32 3, label %sw.bb1 + i32 2, label %sw.bb + i32 3, label %sw.bb1 ], !prof !2 -; CHECK: test2 -; CHECK: switch i32 %N, label %sw.epilog -; CHECK: i32 2, label %sw.bb -; CHECK: i32 3, label %sw.bb1 -; CHECK: i32 4, label %sw.bb5 -; CHECK: ], !prof !1 sw.bb: call void @func2(i32 %N) nounwind @@ -68,8 +108,8 @@ sw2: ;; Here "case 2" is invalidated if control is transferred through default case ;; of the first switch. switch i32 %N, label %sw.epilog [ - i32 2, label %sw.bb4 - i32 4, label %sw.bb5 + i32 2, label %sw.bb4 + i32 4, label %sw.bb5 ], !prof !3 sw.bb4: @@ -86,22 +126,46 @@ sw.epilog: ;; test3 - Merge two switches where PredDefault != BB. define void @test3(i32 %M, i32 %N) nounwind uwtable { +; CHECK-LABEL: @test3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[M:%.*]], 2 +; CHECK-NEXT: br i1 [[CMP]], label [[SW1:%.*]], label [[SW2:%.*]] +; CHECK: sw1: +; CHECK-NEXT: switch i32 [[N:%.*]], label [[SW_BB:%.*]] [ +; CHECK-NEXT: i32 1, label [[SW_BB1:%.*]] +; CHECK-NEXT: i32 3, label [[SW_BB4:%.*]] +; CHECK-NEXT: i32 2, label [[SW_EPILOG:%.*]] +; CHECK-NEXT: ], !prof !3 +; CHECK: sw.bb: +; CHECK-NEXT: call void @func2(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.bb1: +; CHECK-NEXT: call void @func4(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw2: +; CHECK-NEXT: switch i32 [[N]], label [[SW_EPILOG]] [ +; CHECK-NEXT: i32 3, label [[SW_BB4]] +; CHECK-NEXT: i32 4, label [[SW_BB5:%.*]] +; CHECK-NEXT: ], !prof !4 +; CHECK: sw.bb4: +; CHECK-NEXT: call void @func6(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.bb5: +; CHECK-NEXT: call void @func8(i32 [[N]]) #[[ATTR1]] +; CHECK-NEXT: br label [[SW_EPILOG]] +; CHECK: sw.epilog: +; CHECK-NEXT: ret void +; entry: %cmp = icmp sgt i32 %M, 2 br i1 %cmp, label %sw1, label %sw2 sw1: switch i32 %N, label %sw.bb [ - i32 2, label %sw2 - i32 3, label %sw2 - i32 1, label %sw.bb1 + i32 2, label %sw2 + i32 3, label %sw2 + i32 1, label %sw.bb1 ], !prof !4 -; CHECK: test3 -; CHECK: switch i32 %N, label %sw.bb -; CHECK: i32 1, label %sw.bb1 -; CHECK: i32 3, label %sw.bb4 -; CHECK: i32 2, label %sw.epilog -; CHECK: ], !prof !3 sw.bb: call void @func2(i32 %N) nounwind @@ -113,8 +177,8 @@ sw.bb1: sw2: switch i32 %N, label %sw.epilog [ - i32 3, label %sw.bb4 - i32 4, label %sw.bb5 + i32 3, label %sw.bb4 + i32 4, label %sw.bb5 ], !prof !5 sw.bb4: diff --git a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll index 38d82bb944812..3e5a2a9000413 100644 --- a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll +++ b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll @@ -541,8 +541,8 @@ define i32 @HoistThenElseCodeToIf(i32 %n) { ; CHECK-LABEL: @HoistThenElseCodeToIf( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N:%.*]], 0 -; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[TOBOOL]], i32 1, i32 234, !prof !12 -; CHECK-NEXT: ret i32 [[RETVAL_0]] +; CHECK-NEXT: [[DOT:%.*]] = select i1 [[TOBOOL]], i32 1, i32 234, !prof !12 +; CHECK-NEXT: ret i32 [[DOT]] ; entry: %tobool = icmp eq i32 %n, 0 diff --git a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll index 48dd2d92f4c3a..45399d649e071 100644 --- a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll +++ b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll @@ -1,15 +1,21 @@ -; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S | FileCheck -enable-var-scope %s -; RUN: opt < %s -passes='simplify-cfg' -S | FileCheck -enable-var-scope %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -sink-common-insts -S | FileCheck %s +; RUN: opt < %s -passes='simplify-cfg' -S | FileCheck %s define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS:%.*]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA]], [[NBLKS]] +; CHECK-NEXT: [[CMP2_SINK:%.*]] = select i1 [[FLAG:%.*]], i1 [[CMP]], i1 [[CMP2]] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[CMP2_SINK]] to i8 +; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL3]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL4]] +; entry: br i1 %flag, label %if.then, label %if.else -; CHECK-LABEL: test1 -; CHECK: add -; CHECK: select -; CHECK: icmp -; CHECK-NOT: br if.then: %cmp = icmp uge i32 %blksA, %nblks %frombool1 = zext i1 %cmp to i8 @@ -28,14 +34,18 @@ if.end: } define zeroext i1 @test2(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS:%.*]], [[BLKSB:%.*]] +; CHECK-NEXT: [[ADD_SINK:%.*]] = select i1 [[FLAG:%.*]], i32 [[NBLKS]], i32 [[ADD]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[ADD_SINK]] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[CMP2]] to i8 +; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL3]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL4]] +; entry: br i1 %flag, label %if.then, label %if.else -; CHECK-LABEL: test2 -; CHECK: add -; CHECK: select -; CHECK: icmp -; CHECK-NOT: br if.then: %cmp = icmp uge i32 %blksA, %nblks %frombool1 = zext i1 %cmp to i8 @@ -56,6 +66,15 @@ if.end: declare i32 @foo(i32, i32) nounwind readnone define i32 @test3(i1 zeroext %flag, i32 %x, i32 %y) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y_SINK1:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: [[Y_SINK:%.*]] = select i1 [[FLAG]], i32 [[X]], i32 [[Y]] +; CHECK-NEXT: [[X1:%.*]] = call i32 @foo(i32 [[Y_SINK1]], i32 0) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: [[Y1:%.*]] = call i32 @foo(i32 [[Y_SINK]], i32 1) #[[ATTR0]] +; CHECK-NEXT: [[RET:%.*]] = add i32 [[X1]], [[Y1]] +; CHECK-NEXT: ret i32 [[RET]] +; entry: br i1 %flag, label %if.then, label %if.else @@ -76,14 +95,15 @@ if.end: ret i32 %ret } -; CHECK-LABEL: test3 -; CHECK: select -; CHECK: call -; CHECK: call -; CHECK: add -; CHECK-NOT: br define i32 @test4(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7 +; CHECK-NEXT: [[B:%.*]] = add i32 [[X:%.*]], [[DOTSINK]] +; CHECK-NEXT: store i32 [[B]], i32* [[Y:%.*]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -101,12 +121,22 @@ if.end: ret i32 1 } -; CHECK-LABEL: test4 -; CHECK: select -; CHECK: store -; CHECK-NOT: store define i32 @test5(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 5 +; CHECK-NEXT: store volatile i32 [[A]], i32* [[Y:%.*]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[B:%.*]] = add i32 [[X]], 7 +; CHECK-NEXT: store i32 [[B]], i32* [[Y]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -124,11 +154,15 @@ if.end: ret i32 1 } -; CHECK-LABEL: test5 -; CHECK: store volatile -; CHECK: store define i32 @test6(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7 +; CHECK-NEXT: [[B:%.*]] = add i32 [[X:%.*]], [[DOTSINK]] +; CHECK-NEXT: store volatile i32 [[B]], i32* [[Y:%.*]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -146,12 +180,16 @@ if.end: ret i32 1 } -; CHECK-LABEL: test6 -; CHECK: select -; CHECK: store volatile -; CHECK-NOT: store define i32 @test7(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7 +; CHECK-NEXT: [[W:%.*]] = load volatile i32, i32* [[Y:%.*]], align 4 +; CHECK-NEXT: [[B:%.*]] = add i32 [[W]], [[DOTSINK]] +; CHECK-NEXT: store volatile i32 [[B]], i32* [[Y]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -171,16 +209,26 @@ if.end: ret i32 1 } -; CHECK-LABEL: test7 -; CHECK-DAG: select -; CHECK-DAG: load volatile -; CHECK: store volatile -; CHECK-NOT: load -; CHECK-NOT: store ; %z and %w are in different blocks. We shouldn't sink the add because ; there may be intervening memory instructions. define i32 @test8(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Z:%.*]] = load volatile i32, i32* [[Y:%.*]], align 4 +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[A:%.*]] = add i32 [[Z]], 5 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[W:%.*]] = load volatile i32, i32* [[Y]], align 4 +; CHECK-NEXT: [[B:%.*]] = add i32 [[W]], 7 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[B_SINK:%.*]] = phi i32 [ [[B]], [[IF_ELSE]] ], [ [[A]], [[IF_THEN]] ] +; CHECK-NEXT: store volatile i32 [[B_SINK]], i32* [[Y]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: %z = load volatile i32, i32* %y br i1 %flag, label %if.then, label %if.else @@ -200,12 +248,27 @@ if.end: ret i32 1 } -; CHECK-LABEL: test8 -; CHECK: add -; CHECK: add ; The extra store in %if.then means %z and %w are not equivalent. define i32 @test9(i1 zeroext %flag, i32 %x, i32* %y, i32* %p) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 7, i32* [[P:%.*]], align 4 +; CHECK-NEXT: [[Z:%.*]] = load volatile i32, i32* [[Y:%.*]], align 4 +; CHECK-NEXT: store i32 6, i32* [[P]], align 4 +; CHECK-NEXT: [[A:%.*]] = add i32 [[Z]], 5 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[W:%.*]] = load volatile i32, i32* [[Y]], align 4 +; CHECK-NEXT: [[B:%.*]] = add i32 [[W]], 7 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[B_SINK:%.*]] = phi i32 [ [[B]], [[IF_ELSE]] ], [ [[A]], [[IF_THEN]] ] +; CHECK-NEXT: store volatile i32 [[B_SINK]], i32* [[Y]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -227,14 +290,27 @@ if.end: ret i32 1 } -; CHECK-LABEL: test9 -; CHECK: add -; CHECK: add %struct.anon = type { i32, i32 } ; The GEP indexes a struct type so cannot have a variable last index. define i32 @test10(i1 zeroext %flag, i32 %x, i32* %y, %struct.anon* %s) { +; CHECK-LABEL: @test10( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[X:%.*]], 5 +; CHECK-NEXT: [[GEPA:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[S:%.*]], i32 0, i32 0 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[X]], 6 +; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[S]], i32 0, i32 1 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[GEPB_SINK:%.*]] = phi i32* [ [[GEPB]], [[IF_ELSE]] ], [ [[GEPA]], [[IF_THEN]] ] +; CHECK-NEXT: store volatile i32 [[X]], i32* [[GEPB_SINK]], align 4 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -254,14 +330,24 @@ if.end: ret i32 1 } -; CHECK-LABEL: test10 -; CHECK: getelementptr -; CHECK: getelementptr -; CHECK: phi -; CHECK: store volatile ; The shufflevector's mask operand cannot be merged in a PHI. define i32 @test11(i1 zeroext %flag, i32 %w, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[W:%.*]], 5 +; CHECK-NEXT: [[SV1:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[W]], 6 +; CHECK-NEXT: [[SV2:%.*]] = shufflevector <2 x i32> [[X]], <2 x i32> [[Y]], <2 x i32> +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[P:%.*]] = phi <2 x i32> [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -280,12 +366,24 @@ if.end: ret i32 1 } -; CHECK-LABEL: test11 -; CHECK: shufflevector -; CHECK: shufflevector ; We can't common an intrinsic! define i32 @test12(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { +; CHECK-LABEL: @test12( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[W:%.*]], 5 +; CHECK-NEXT: [[SV1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[W]], 6 +; CHECK-NEXT: [[SV2:%.*]] = call i32 @llvm.cttz.i32(i32 [[X]], i1 false) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -307,12 +405,17 @@ if.end: declare i32 @llvm.ctlz.i32(i32 %x, i1 immarg) readnone declare i32 @llvm.cttz.i32(i32 %x, i1 immarg) readnone -; CHECK-LABEL: test12 -; CHECK: call i32 @llvm.ctlz -; CHECK: call i32 @llvm.cttz ; The TBAA metadata should be properly combined. define i32 @test13(i1 zeroext %flag, i32 %x, i32* %y) { +; CHECK-LABEL: @test13( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG:%.*]], i32 5, i32 7 +; CHECK-NEXT: [[W:%.*]] = load volatile i32, i32* [[Y:%.*]], align 4 +; CHECK-NEXT: [[B:%.*]] = add i32 [[W]], [[DOTSINK]] +; CHECK-NEXT: store volatile i32 [[B]], i32* [[Y]], align 4, !tbaa [[TBAA4:![0-9]+]] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -338,15 +441,15 @@ if.end: !3 = !{ !"const float", !2, i64 0 } !4 = !{ !"special float", !2, i64 1 } -; CHECK-LABEL: test13 -; CHECK-DAG: select -; CHECK-DAG: load volatile -; CHECK: store volatile {{.*}}, !tbaa ![[$TBAA:[0-9]]] -; CHECK-NOT: load -; CHECK-NOT: store ; The call should be commoned. define i32 @test13a(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { +; CHECK-LABEL: @test13a( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y_SINK:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: [[SV2:%.*]] = call i32 @bar(i32 [[Y_SINK]]) +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -364,12 +467,19 @@ if.end: } declare i32 @bar(i32) -; CHECK-LABEL: test13a -; CHECK: %[[x:.*]] = select i1 %flag -; CHECK: call i32 @bar(i32 %[[x]]) ; The load should be commoned. define i32 @test14(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, %struct.anon* %s) { +; CHECK-LABEL: @test14( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK1:%.*]] = select i1 [[FLAG:%.*]], i32 1, i32 4 +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG]], i32 56, i32 57 +; CHECK-NEXT: [[DUMMY2:%.*]] = add i32 [[X:%.*]], [[DOTSINK1]] +; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[S:%.*]], i32 0, i32 1 +; CHECK-NEXT: [[SV2:%.*]] = load i32, i32* [[GEPB]], align 4 +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[SV2]], [[DOTSINK]] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -405,13 +515,28 @@ declare void @llvm.dbg.value(metadata, metadata, metadata) !10 = !DIFile(filename: "a.c", directory: "a/b") !11 = !DILocation(line: 1, column: 14, scope: !8) -; CHECK-LABEL: test14 -; CHECK: getelementptr -; CHECK: load -; CHECK-NOT: load ; The load should be commoned. define i32 @test15(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, %struct.anon* %s) { +; CHECK-LABEL: @test15( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[X:%.*]], 1 +; CHECK-NEXT: [[GEPA:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[S:%.*]], i32 0, i32 0 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[DUMMY2:%.*]] = add i32 [[X]], 4 +; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[S]], i32 0, i32 1 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[GEPB_SINK:%.*]] = phi i32* [ [[GEPB]], [[IF_ELSE]] ], [ [[GEPA]], [[IF_THEN]] ] +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i64 [ 57, [[IF_ELSE]] ], [ 56, [[IF_THEN]] ] +; CHECK-NEXT: [[SV2:%.*]] = load i32, i32* [[GEPB_SINK]], align 4 +; CHECK-NEXT: [[EXT2:%.*]] = zext i32 [[SV2]] to i64 +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[EXT2]], [[DOTSINK]] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -436,12 +561,25 @@ if.end: ret i32 1 } -; CHECK-LABEL: test15 -; CHECK: getelementptr -; CHECK: load -; CHECK-NOT: load define zeroext i1 @test_crash(i1 zeroext %flag, i32* %i4, i32* %m, i32* %n) { +; CHECK-LABEL: @test_crash( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I4:%.*]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[M:%.*]], align 4 +; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[N:%.*]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[TMP4_SINK:%.*]] = phi i32 [ [[TMP4]], [[IF_ELSE]] ], [ -1, [[IF_THEN]] ] +; CHECK-NEXT: [[TMP3_SINK:%.*]] = phi i32 [ [[TMP3]], [[IF_ELSE]] ], [ [[TMP1]], [[IF_THEN]] ] +; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP3_SINK]], [[TMP4_SINK]] +; CHECK-NEXT: store i32 [[TMP5]], i32* [[I4]], align 4 +; CHECK-NEXT: ret i1 true +; entry: br i1 %flag, label %if.then, label %if.else @@ -462,11 +600,28 @@ if.end: ret i1 true } -; CHECK-LABEL: test_crash ; No checks for test_crash - just ensure it doesn't crash! define zeroext i1 @test16(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) { - +; CHECK-LABEL: @test16( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]] +; CHECK-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[CMP]] to i8 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END]] +; CHECK: if.then2: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[CMP2]] to i8 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[OBEYS_0:%.*]] = phi i8 [ [[FROMBOOL1]], [[IF_THEN]] ], [ [[FROMBOOL3]], [[IF_THEN2]] ], [ 0, [[IF_ELSE]] ] +; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[OBEYS_0]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL4]] +; entry: br i1 %flag, label %if.then, label %if.else @@ -490,12 +645,28 @@ if.end: ret i1 %tobool4 } -; CHECK-LABEL: test16 -; CHECK: zext -; CHECK: zext define zeroext i1 @test16a(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks, i8* %p) { - +; CHECK-LABEL: @test16a( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]] +; CHECK-NEXT: br label [[IF_END_SINK_SPLIT:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]] +; CHECK-NEXT: br label [[IF_END_SINK_SPLIT]] +; CHECK: if.end.sink.split: +; CHECK-NEXT: [[CMP2_SINK:%.*]] = phi i1 [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[CMP2_SINK]] to i8 +; CHECK-NEXT: store i8 [[FROMBOOL3]], i8* [[P:%.*]], align 1 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i1 true +; entry: br i1 %flag, label %if.then, label %if.else @@ -519,15 +690,34 @@ if.end: ret i1 true } -; CHECK-LABEL: test16a -; CHECK: zext -; CHECK-NOT: zext define zeroext i1 @test17(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +; CHECK-LABEL: @test17( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[FLAG:%.*]], label [[IF_END:%.*]] [ +; CHECK-NEXT: i32 0, label [[IF_THEN:%.*]] +; CHECK-NEXT: i32 1, label [[IF_THEN2:%.*]] +; CHECK-NEXT: ] +; CHECK: if.then: +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]] +; CHECK-NEXT: br label [[IF_END_SINK_SPLIT:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]] +; CHECK-NEXT: br label [[IF_END_SINK_SPLIT]] +; CHECK: if.end.sink.split: +; CHECK-NEXT: [[CMP2_SINK:%.*]] = phi i1 [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = call i8 @i1toi8(i1 [[CMP2_SINK]]) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[OBEYS_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[FROMBOOL3]], [[IF_END_SINK_SPLIT]] ] +; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[OBEYS_0]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL4]] +; entry: switch i32 %flag, label %if.end [ - i32 0, label %if.then - i32 1, label %if.then2 + i32 0, label %if.then + i32 1, label %if.then2 ] if.then: @@ -548,31 +738,38 @@ if.end: } declare i8 @i1toi8(i1) -; CHECK-LABEL: test17 -; CHECK: if.then: -; CHECK-NEXT: icmp uge -; CHECK-NEXT: br label %[[x:.*]] -; CHECK: if.then2: -; CHECK-NEXT: add -; CHECK-NEXT: icmp ule -; CHECK-NEXT: br label %[[x]] -; CHECK: [[x]]: -; CHECK-NEXT: %[[y:.*]] = phi i1 [ %cmp -; CHECK-NEXT: %[[z:.*]] = call i8 @i1toi8(i1 %[[y]]) -; CHECK-NEXT: br label %if.end -; CHECK: if.end: -; CHECK-NEXT: phi i8 -; CHECK-DAG: [ %[[z]], %[[x]] ] -; CHECK-DAG: [ 0, %entry ] define zeroext i1 @test18(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +; CHECK-LABEL: @test18( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[FLAG:%.*]], label [[IF_THEN3:%.*]] [ +; CHECK-NEXT: i32 0, label [[IF_THEN:%.*]] +; CHECK-NEXT: i32 1, label [[IF_THEN2:%.*]] +; CHECK-NEXT: ] +; CHECK: if.then: +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]] +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.then3: +; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[NBLKS]], [[BLKSA]] +; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i32 [[ADD2]], [[BLKSA]] +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[CMP3_SINK:%.*]] = phi i1 [ [[CMP3]], [[IF_THEN3]] ], [ [[CMP2]], [[IF_THEN2]] ], [ [[CMP]], [[IF_THEN]] ] +; CHECK-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[CMP3_SINK]] to i8 +; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[FROMBOOL4]], 0 +; CHECK-NEXT: ret i1 [[TOBOOL4]] +; entry: switch i32 %flag, label %if.then3 [ - i32 0, label %if.then - i32 1, label %if.then2 + i32 0, label %if.then + i32 1, label %if.then2 ] if.then: @@ -598,15 +795,22 @@ if.end: ret i1 %tobool4 } -; CHECK-LABEL: test18 -; CHECK: if.end: -; CHECK-NEXT: %[[x:.*]] = phi i1 -; CHECK-DAG: [ %cmp, %if.then ] -; CHECK-DAG: [ %cmp2, %if.then2 ] -; CHECK-DAG: [ %cmp3, %if.then3 ] -; CHECK-NEXT: zext i1 %[[x]] to i8 define i32 @test_pr30188(i1 zeroext %flag, i32 %x) { +; CHECK-LABEL: @test_pr30188( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4 +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 [[X:%.*]], i32* [[Y]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: store i32 [[X]], i32* [[Z]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i32 1 +; entry: %y = alloca i32 %z = alloca i32 @@ -624,12 +828,27 @@ if.end: ret i32 1 } -; CHECK-LABEL: test_pr30188 -; CHECK-NOT: select -; CHECK: store -; CHECK: store define i32 @test_pr30188a(i1 zeroext %flag, i32 %x) { +; CHECK-LABEL: @test_pr30188a( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4 +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: [[ONE:%.*]] = load i32, i32* [[Y]], align 4 +; CHECK-NEXT: [[TWO:%.*]] = add i32 [[ONE]], 2 +; CHECK-NEXT: store i32 [[TWO]], i32* [[Y]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[THREE:%.*]] = load i32, i32* [[Z]], align 4 +; CHECK-NEXT: [[FOUR:%.*]] = add i32 [[THREE]], 2 +; CHECK-NEXT: store i32 [[FOUR]], i32* [[Y]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i32 1 +; entry: %y = alloca i32 %z = alloca i32 @@ -652,16 +871,23 @@ if.end: ret i32 1 } -; CHECK-LABEL: test_pr30188a -; CHECK-NOT: select -; CHECK: load -; CHECK: load -; CHECK: store ; The phi is confusing - both add instructions are used by it, but ; not on their respective unconditional arcs. It should not be ; optimized. define void @test_pr30292(i1 %cond, i1 %cond2, i32 %a, i32 %b) { +; CHECK-LABEL: @test_pr30292( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A:%.*]], 1 +; CHECK-NEXT: br label [[SUCC:%.*]] +; CHECK: two: +; CHECK-NEXT: call void @g() +; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[A]], 1 +; CHECK-NEXT: br label [[SUCC]] +; CHECK: succ: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD1]], [[SUCC]] ], [ [[ADD2]], [[TWO:%.*]] ] +; CHECK-NEXT: br i1 [[COND:%.*]], label [[TWO]], label [[SUCC]] +; entry: %add1 = add i32 %a, 1 br label %succ @@ -680,11 +906,28 @@ succ: } declare void @g() -; CHECK-LABEL: test_pr30292 -; CHECK: phi i32 [ 0, %entry ], [ %add1, %succ ], [ %add2, %two ] define zeroext i1 @test_pr30244(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) { - +; CHECK-LABEL: @test_pr30244( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[P:%.*]] = alloca i8, align 1 +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[BLKSA:%.*]], [[NBLKS:%.*]] +; CHECK-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[CMP]] to i8 +; CHECK-NEXT: store i8 [[FROMBOOL1]], i8* [[P]], align 1 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: br i1 [[FLAG2:%.*]], label [[IF_THEN2:%.*]], label [[IF_END]] +; CHECK: if.then2: +; CHECK-NEXT: [[ADD:%.*]] = add i32 [[NBLKS]], [[BLKSB:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[ADD]], [[BLKSA]] +; CHECK-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[CMP2]] to i8 +; CHECK-NEXT: store i8 [[FROMBOOL3]], i8* [[P]], align 1 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i1 true +; entry: %p = alloca i8 br i1 %flag, label %if.then, label %if.else @@ -709,11 +952,18 @@ if.end: ret i1 true } -; CHECK-LABEL: @test_pr30244 -; CHECK: store -; CHECK: store define i32 @test_pr30373a(i1 zeroext %flag, i32 %x, i32 %y) { +; CHECK-LABEL: @test_pr30373a( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y_SINK1:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: [[Y_SINK:%.*]] = select i1 [[FLAG]], i32 [[X]], i32 [[Y]] +; CHECK-NEXT: [[X1:%.*]] = call i32 @foo(i32 [[Y_SINK1]], i32 0) #[[ATTR0]] +; CHECK-NEXT: [[Y1:%.*]] = call i32 @foo(i32 [[Y_SINK]], i32 1) #[[ATTR0]] +; CHECK-NEXT: [[Z1:%.*]] = lshr i32 [[Y1]], 8 +; CHECK-NEXT: [[RET:%.*]] = add i32 [[X1]], [[Z1]] +; CHECK-NEXT: ret i32 [[RET]] +; entry: br i1 %flag, label %if.then, label %if.else @@ -736,12 +986,18 @@ if.end: ret i32 %ret } -; CHECK-LABEL: test_pr30373a -; CHECK: lshr -; CHECK-NOT: exact -; CHECK: } define i32 @test_pr30373b(i1 zeroext %flag, i32 %x, i32 %y) { +; CHECK-LABEL: @test_pr30373b( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y_SINK1:%.*]] = select i1 [[FLAG:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: [[Y_SINK:%.*]] = select i1 [[FLAG]], i32 [[X]], i32 [[Y]] +; CHECK-NEXT: [[X1:%.*]] = call i32 @foo(i32 [[Y_SINK1]], i32 0) #[[ATTR0]] +; CHECK-NEXT: [[Y1:%.*]] = call i32 @foo(i32 [[Y_SINK]], i32 1) #[[ATTR0]] +; CHECK-NEXT: [[Z1:%.*]] = lshr i32 [[Y1]], 8 +; CHECK-NEXT: [[RET:%.*]] = add i32 [[X1]], [[Z1]] +; CHECK-NEXT: ret i32 [[RET]] +; entry: br i1 %flag, label %if.then, label %if.else @@ -764,17 +1020,19 @@ if.end: ret i32 %ret } -; CHECK-LABEL: test_pr30373b -; CHECK: lshr -; CHECK-NOT: exact -; CHECK: } ; FIXME: Should turn into select -; CHECK-LABEL: @allow_intrinsic_remove_constant( -; CHECK: %sv1 = call float @llvm.fma.f32(float %dummy, float 2.000000e+00, float 1.000000e+00) -; CHECK: %sv2 = call float @llvm.fma.f32(float 2.000000e+00, float %dummy1, float 1.000000e+00) define float @allow_intrinsic_remove_constant(i1 zeroext %flag, float %w, float %x, float %y) { +; CHECK-LABEL: @allow_intrinsic_remove_constant( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DUMMY:%.*]] = fadd float [[W:%.*]], 4.000000e+00 +; CHECK-NEXT: [[SV1:%.*]] = call float @llvm.fma.f32(float [[DUMMY]], float 2.000000e+00, float 1.000000e+00) +; CHECK-NEXT: [[DUMMY1:%.*]] = fadd float [[W]], 8.000000e+00 +; CHECK-NEXT: [[SV2:%.*]] = call float @llvm.fma.f32(float 2.000000e+00, float [[DUMMY1]], float 1.000000e+00) +; CHECK-NEXT: [[P:%.*]] = select i1 [[FLAG:%.*]], float [[SV1]], float [[SV2]] +; CHECK-NEXT: ret float [[P]] +; entry: br i1 %flag, label %if.then, label %if.else @@ -795,10 +1053,22 @@ if.end: declare float @llvm.fma.f32(float, float, float) -; CHECK-LABEL: @no_remove_constant_immarg( -; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true) -; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false) define i32 @no_remove_constant_immarg(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { +; CHECK-LABEL: @no_remove_constant_immarg( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[W:%.*]], 5 +; CHECK-NEXT: [[SV1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[W]], 6 +; CHECK-NEXT: [[SV2:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X]], i1 false) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[SV1]], [[IF_THEN]] ], [ [[SV2]], [[IF_ELSE]] ] +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -820,10 +1090,19 @@ if.end: declare void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) ; Make sure a memcpy size isn't replaced with a variable -; CHECK-LABEL: @no_replace_memcpy_size( -; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) -; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) define void @no_replace_memcpy_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +; CHECK-LABEL: @no_replace_memcpy_size( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* [[DST:%.*]], i8 addrspace(1)* [[SRC:%.*]], i64 1024, i1 false) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* [[DST]], i8 addrspace(1)* [[SRC]], i64 4096, i1 false) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; entry: br i1 %flag, label %if.then, label %if.else @@ -842,10 +1121,19 @@ if.end: declare void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) ; Make sure a memmove size isn't replaced with a variable -; CHECK-LABEL: @no_replace_memmove_size( -; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) -; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) define void @no_replace_memmove_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +; CHECK-LABEL: @no_replace_memmove_size( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* [[DST:%.*]], i8 addrspace(1)* [[SRC:%.*]], i64 1024, i1 false) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* [[DST]], i8 addrspace(1)* [[SRC]], i64 4096, i1 false) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; entry: br i1 %flag, label %if.then, label %if.else @@ -864,10 +1152,19 @@ if.end: declare void @llvm.memset.p1i8.i64(i8 addrspace(1)* nocapture, i8, i64, i1) ; Make sure a memset size isn't replaced with a variable -; CHECK-LABEL: @no_replace_memset_size( -; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 1024, i1 false) -; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 4096, i1 false) define void @no_replace_memset_size(i1 zeroext %flag, i8 addrspace(1)* %dst) { +; CHECK-LABEL: @no_replace_memset_size( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* [[DST:%.*]], i8 0, i64 1024, i1 false) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* [[DST]], i8 0, i64 4096, i1 false) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; entry: br i1 %flag, label %if.then, label %if.else @@ -886,6 +1183,20 @@ if.end: ; Check that simplifycfg doesn't sink and merge inline-asm instructions. define i32 @test_inline_asm1(i32 %c, i32 %r6) { +; CHECK-LABEL: @test_inline_asm1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C:%.*]], 0 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TMP0:%.*]] = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 [[R6:%.*]], i32 8) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TMP1:%.*]] = call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 [[R6]], i32 6) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[R6_ADDR_0:%.*]] = phi i32 [ [[TMP0]], [[IF_THEN]] ], [ [[TMP1]], [[IF_ELSE]] ] +; CHECK-NEXT: ret i32 [[R6_ADDR_0]] +; entry: %tobool = icmp eq i32 %c, 0 br i1 %tobool, label %if.else, label %if.then @@ -903,13 +1214,24 @@ if.end: ret i32 %r6.addr.0 } -; CHECK-LABEL: @test_inline_asm1( -; CHECK: call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 %r6, i32 8) -; CHECK: call i32 asm "rorl $2, $0", "=&r,0,n,~{dirflag},~{fpsr},~{flags}"(i32 %r6, i32 6) declare i32 @call_target() define void @test_operand_bundles(i1 %cond, i32* %ptr) { +; CHECK-LABEL: @test_operand_bundles( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[VAL0:%.*]] = call i32 @call_target() [ "deopt"(i32 10) ] +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: right: +; CHECK-NEXT: [[VAL1:%.*]] = call i32 @call_target() [ "deopt"(i32 20) ] +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[VAL1_SINK:%.*]] = phi i32 [ [[VAL1]], [[RIGHT]] ], [ [[VAL0]], [[LEFT]] ] +; CHECK-NEXT: store i32 [[VAL1_SINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: ret void +; entry: br i1 %cond, label %left, label %right @@ -927,15 +1249,16 @@ merge: ret void } -; CHECK-LABEL: @test_operand_bundles( -; CHECK: left: -; CHECK-NEXT: %val0 = call i32 @call_target() [ "deopt"(i32 10) ] -; CHECK: right: -; CHECK-NEXT: %val1 = call i32 @call_target() [ "deopt"(i32 20) ] %T = type {i32, i32} define i32 @test_insertvalue(i1 zeroext %flag, %T %P) { +; CHECK-LABEL: @test_insertvalue( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DOTSINK:%.*]] = select i1 [[FLAG:%.*]], i32 0, i32 1 +; CHECK-NEXT: [[T2:%.*]] = insertvalue [[T:%.*]] [[P:%.*]], i32 [[DOTSINK]], 0 +; CHECK-NEXT: ret i32 1 +; entry: br i1 %flag, label %if.then, label %if.else @@ -952,22 +1275,42 @@ if.end: ret i32 1 } -; CHECK-LABEL: @test_insertvalue -; CHECK: select -; CHECK: insertvalue -; CHECK-NOT: insertvalue declare void @baz(i32) define void @test_sink_void_calls(i32 %x) { +; CHECK-LABEL: @test_sink_void_calls( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i32 0, label [[RETURN:%.*]] +; CHECK-NEXT: i32 1, label [[BB1:%.*]] +; CHECK-NEXT: i32 2, label [[BB2:%.*]] +; CHECK-NEXT: i32 3, label [[BB3:%.*]] +; CHECK-NEXT: i32 4, label [[BB4:%.*]] +; CHECK-NEXT: ] +; CHECK: bb1: +; CHECK-NEXT: br label [[RETURN]] +; CHECK: bb2: +; CHECK-NEXT: br label [[RETURN]] +; CHECK: bb3: +; CHECK-NEXT: br label [[RETURN]] +; CHECK: bb4: +; CHECK-NEXT: br label [[RETURN]] +; CHECK: default: +; CHECK-NEXT: unreachable +; CHECK: return: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ 90, [[BB4]] ], [ 78, [[BB3]] ], [ 56, [[BB2]] ], [ 34, [[BB1]] ], [ 12, [[ENTRY:%.*]] ] +; CHECK-NEXT: call void @baz(i32 [[DOTSINK]]) +; CHECK-NEXT: ret void +; entry: switch i32 %x, label %default [ - i32 0, label %bb0 - i32 1, label %bb1 - i32 2, label %bb2 - i32 3, label %bb3 - i32 4, label %bb4 + i32 0, label %bb0 + i32 1, label %bb1 + i32 2, label %bb2 + i32 3, label %bb3 + i32 4, label %bb4 ] bb0: call void @baz(i32 12) @@ -991,20 +1334,25 @@ return: ; Check that the calls get sunk to the return block. ; We would previously not sink calls without uses, see PR41259. -; CHECK-LABEL: @test_sink_void_calls -; CHECK-NOT: call -; CHECK-LABEL: return: -; CHECK: phi -; CHECK: call -; CHECK-NOT: call -; CHECK: ret } -; CHECK-LABEL: @test_not_sink_lifetime_marker -; CHECK-NOT: select -; CHECK: call void @llvm.lifetime.end -; CHECK: call void @llvm.lifetime.end define i32 @test_not_sink_lifetime_marker(i1 zeroext %flag, i32 %x) { +; CHECK-LABEL: @test_not_sink_lifetime_marker( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4 +; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[Y_CAST:%.*]] = bitcast i32* [[Y]] to i8* +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[Y_CAST]]) +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[Z_CAST:%.*]] = bitcast i32* [[Z]] to i8* +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[Z_CAST]]) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret i32 1 +; entry: %y = alloca i32 %z = alloca i32 @@ -1026,7 +1374,3 @@ if.end: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) - -; CHECK: ![[$TBAA]] = !{![[TYPE:[0-9]]], ![[TYPE]], i64 0} -; CHECK: ![[TYPE]] = !{!"float", ![[TEXT:[0-9]]]} -; CHECK: ![[TEXT]] = !{!"an example type tree"} diff --git a/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll b/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll index e8d5e11d00264..58b0d4c889a3a 100644 --- a/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll +++ b/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s ; We're sign extending an 8-bit value. @@ -8,13 +9,19 @@ define i1 @repeated_signbits(i8 %condition) { ; CHECK-LABEL: @repeated_signbits( -; CHECK: switch i32 -; CHECK-DAG: i32 -128, label %a -; CHECK-DAG: i32 -1, label %a -; CHECK-DAG: i32 0, label %a -; CHECK-DAG: i32 127, label %a +; CHECK-NEXT: entry: +; CHECK-NEXT: [[SEXT:%.*]] = sext i8 [[CONDITION:%.*]] to i32 +; CHECK-NEXT: switch i32 [[SEXT]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i32 0, label [[A:%.*]] +; CHECK-NEXT: i32 127, label [[A]] +; CHECK-NEXT: i32 -128, label [[A]] +; CHECK-NEXT: i32 -1, label [[A]] ; CHECK-NEXT: ] -; CHECK-NOT: , !prof +; CHECK: a: +; CHECK-NEXT: [[MERGE:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ false, [[DEFAULT]] ] +; CHECK-NEXT: ret i1 [[MERGE]] +; CHECK: default: +; CHECK-NEXT: br label [[A]] ; entry: %sext = sext i8 %condition to i32 diff --git a/llvm/test/Transforms/SimplifyCFG/switch-on-const-select.ll b/llvm/test/Transforms/SimplifyCFG/switch-on-const-select.ll index 013096625b1cc..528dee019d51c 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-on-const-select.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-on-const-select.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck -enable-var-scope %s +; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; Test basic folding to a conditional branch. define i32 @foo(i64 %x, i64 %y) nounwind { @@ -11,11 +11,11 @@ define i32 @foo(i64 %x, i64 %y) nounwind { ; CHECK-NEXT: [[LT:%.*]] = icmp slt i64 [[X]], [[Y]] ; CHECK-NEXT: br i1 [[LT]], label [[A:%.*]], label [[B]] ; CHECK: a: -; CHECK-NEXT: tail call void @bees.a() #0 +; CHECK-NEXT: tail call void @bees.a() #[[ATTR0:[0-9]+]] ; CHECK-NEXT: ret i32 1 ; CHECK: b: ; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 0, [[SWITCH]] ], [ 2, [[ENTRY:%.*]] ] -; CHECK-NEXT: tail call void @bees.b() #0 +; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] ; CHECK-NEXT: ret i32 [[RETVAL]] ; entry: @@ -45,7 +45,7 @@ bees: define i32 @bar(i64 %x, i64 %y) nounwind { ; CHECK-LABEL: @bar( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call void @bees.a() #0 +; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] ; CHECK-NEXT: ret i32 0 ; entry: @@ -72,7 +72,7 @@ bees: define void @bazz(i64 %x, i64 %y) nounwind { ; CHECK-LABEL: @bazz( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call void @bees.b() #0 +; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]] ; CHECK-NEXT: ret void ; entry: @@ -98,7 +98,7 @@ bees: define void @quux(i64 %x, i64 %y) nounwind { ; CHECK-LABEL: @quux( ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call void @bees.a() #0 +; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]] ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/SimplifyCFG/switch-to-select-multiple-edge-per-block-phi.ll b/llvm/test/Transforms/SimplifyCFG/switch-to-select-multiple-edge-per-block-phi.ll index fe69de4c3aa89..8579c7bf62aef 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch-to-select-multiple-edge-per-block-phi.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch-to-select-multiple-edge-per-block-phi.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; a, b; @@ -20,16 +21,16 @@ define i32 @fn1() { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @b, align 4 ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0 -; CHECK-NEXT: br i1 [[TOBOOL]], label %return, label %if.then +; CHECK-NEXT: br i1 [[TOBOOL]], label [[RETURN:%.*]], label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 ; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[TMP1]], 0 -; CHECK-NEXT: [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP:%.*]], i32 0, i32 0 +; CHECK-NEXT: [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], i32 0, i32 0 ; CHECK-NEXT: [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[TMP1]], 5 ; CHECK-NEXT: [[SWITCH_SELECT2:%.*]] = select i1 [[SWITCH_SELECTCMP1]], i32 5, i32 [[SWITCH_SELECT]] -; CHECK-NEXT: br label %return +; CHECK-NEXT: br label [[RETURN]] ; CHECK: return: -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[SWITCH_SELECT2]], %if.then ], [ 0, %entry ] +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[SWITCH_SELECT2]], [[IF_THEN]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RETVAL_0]] ; entry: diff --git a/llvm/test/Transforms/SimplifyCFG/volatile-phioper.ll b/llvm/test/Transforms/SimplifyCFG/volatile-phioper.ll index 467251e6f6422..0ef738975f1d8 100644 --- a/llvm/test/Transforms/SimplifyCFG/volatile-phioper.ll +++ b/llvm/test/Transforms/SimplifyCFG/volatile-phioper.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s ; ; rdar:13349374 @@ -6,16 +7,31 @@ ; Essentially, volatile needs to be backdoor that tells the optimizer ; it can no longer use language standard as an excuse. The compiler ; needs to expose the volatile access to the platform. -; -; CHECK-LABEL: @test( -; CHECK: entry: -; CHECK: @Trace -; CHECK: while.body: -; CHECK: store volatile -; CHECK: end: + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" define void @test(i8** nocapture %PeiServices) #0 { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 (...) @Trace() #[[ATTR2:[0-9]+]] +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[CALL]], 0 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_BODY:%.*]], label [[IF_THEN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[CALL1:%.*]] = tail call i32 (...) @Trace() #[[ATTR2]] +; CHECK-NEXT: br label [[WHILE_BODY]] +; CHECK: while.body: +; CHECK-NEXT: [[ADDR_017:%.*]] = phi i8* [ [[INCDEC_PTR:%.*]], [[WHILE_BODY]] ], [ null, [[IF_THEN]] ], [ null, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[X_016:%.*]] = phi i8 [ [[INC:%.*]], [[WHILE_BODY]] ], [ 0, [[IF_THEN]] ], [ 0, [[ENTRY]] ] +; CHECK-NEXT: [[INC]] = add i8 [[X_016]], 1 +; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i8, i8* [[ADDR_017]], i64 1 +; CHECK-NEXT: store volatile i8 [[X_016]], i8* [[ADDR_017]], align 1 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint i8* [[INCDEC_PTR]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 4096 +; CHECK-NEXT: br i1 [[CMP]], label [[WHILE_BODY]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: ret void +; entry: %call = tail call i32 (...) @Trace() #2 %tobool = icmp eq i32 %call, 0