diff options
Diffstat (limited to 'test/Transforms/SimplifyCFG')
32 files changed, 2683 insertions, 252 deletions
diff --git a/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll b/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll index 806659635e4b..a81e7a6caaa3 100644 --- a/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll +++ b/test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll @@ -1,81 +1,104 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py ; RUN: opt < %s -simplifycfg -S | FileCheck %s -; CHECK-NOT: switch - ; Test normal folding define i32 @test1() { - switch i32 5, label %Default [ - i32 0, label %Foo - i32 1, label %Bar - i32 2, label %Baz - i32 5, label %TheDest - ] -Default: ; preds = %0 - ret i32 -1 -Foo: ; preds = %0 - ret i32 -2 -Bar: ; preds = %0 - ret i32 -3 -Baz: ; preds = %0 - ret i32 -4 -TheDest: ; preds = %0 - ret i32 1234 +; CHECK-LABEL: @test1( +; CHECK-NEXT: TheDest: +; CHECK-NEXT: ret i32 1234 +; + switch i32 5, label %Default [ + i32 0, label %Foo + i32 1, label %Bar + i32 2, label %Baz + i32 5, label %TheDest + ] +Default: + ret i32 -1 +Foo: + ret i32 -2 +Bar: + ret i32 -3 +Baz: + ret i32 -4 +TheDest: + ret i32 1234 } ; Test folding to default dest define i32 @test2() { - switch i32 3, label %Default [ - i32 0, label %Foo - i32 1, label %Bar - i32 2, label %Baz - i32 5, label %TheDest - ] -Default: ; preds = %0 - ret i32 1234 -Foo: ; preds = %0 - ret i32 -2 -Bar: ; preds = %0 - ret i32 -5 -Baz: ; preds = %0 - ret i32 -6 -TheDest: ; preds = %0 - ret i32 -8 +; CHECK-LABEL: @test2( +; CHECK-NEXT: Default: +; CHECK-NEXT: ret i32 1234 +; + switch i32 3, label %Default [ + i32 0, label %Foo + i32 1, label %Bar + i32 2, label %Baz + i32 5, label %TheDest + ] +Default: + ret i32 1234 +Foo: + ret i32 -2 +Bar: + ret i32 -5 +Baz: + ret i32 -6 +TheDest: + ret i32 -8 } ; Test folding all to same dest define i32 @test3(i1 %C) { - br i1 %C, label %Start, label %TheDest +; CHECK-LABEL: @test3( +; CHECK-NEXT: TheDest: +; CHECK-NEXT: ret i32 1234 +; + br i1 %C, label %Start, label %TheDest Start: ; preds = %0 - switch i32 3, label %TheDest [ - i32 0, label %TheDest - i32 1, label %TheDest - i32 2, label %TheDest - i32 5, label %TheDest - ] -TheDest: ; preds = %Start, %Start, %Start, %Start, %Start, %0 - ret i32 1234 + switch i32 3, label %TheDest [ + i32 0, label %TheDest + i32 1, label %TheDest + i32 2, label %TheDest + i32 5, label %TheDest + ] +TheDest: + ret i32 1234 } ; Test folding switch -> branch define i32 @test4(i32 %C) { - switch i32 %C, label %L1 [ - i32 0, label %L2 - ] -L1: ; preds = %0 - ret i32 0 -L2: ; preds = %0 - ret i32 1 +; 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]] +; + switch i32 %C, label %L1 [ + i32 0, label %L2 + ] +L1: + ret i32 0 +L2: + ret i32 1 } ; Can fold into a cond branch! define i32 @test5(i32 %C) { - switch i32 %C, label %L1 [ - i32 0, label %L2 - i32 123, label %L1 - ] -L1: ; preds = %0, %0 - ret i32 0 -L2: ; preds = %0 - ret i32 1 +; 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]] +; + switch i32 %C, label %L1 [ + i32 0, label %L2 + i32 123, label %L1 + ] +L1: + ret i32 0 +L2: + ret i32 1 } diff --git a/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll b/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll index 13ccad6a1eeb..21e9bc7b7f4e 100644 --- a/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll +++ b/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll @@ -1,6 +1,6 @@ ; RUN: opt < %s -simplifycfg -S > %t ; RUN: not grep "^BB.tomerge" %t -; RUN: grep "^BB.nomerge" %t | count 2 +; RUN: grep "^BB.nomerge" %t | count 4 ; ModuleID = '<stdin>' declare i1 @foo() @@ -54,24 +54,24 @@ Exit: ; preds = %Succ ret void } -; This function can be merged +; This function can't be merged (for keeping canonical loop structures) define void @c() { entry: - br label %BB.tomerge + br label %BB.nomerge -BB.tomerge: ; preds = %Common, %entry +BB.nomerge: ; preds = %Common, %entry br label %Succ Succ: ; preds = %Common, %BB.tomerge, %Pre-Exit ; This phi has identical values for Common and (through BB) Common, ; blocks can't be merged - %b = phi i32 [ 1, %BB.tomerge ], [ 1, %Common ], [ 2, %Pre-Exit ] + %b = phi i32 [ 1, %BB.nomerge ], [ 1, %Common ], [ 2, %Pre-Exit ] %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Common, label %Pre-Exit Common: ; preds = %Succ %cond = call i1 @foo( ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Succ + br i1 %cond, label %BB.nomerge, label %Succ Pre-Exit: ; preds = %Succ ; This adds a backedge, so the %b phi node gets a third branch and is @@ -83,25 +83,25 @@ Exit: ; preds = %Pre-Exit ret void } -; This function can be merged +; This function can't be merged (for keeping canonical loop structures) define void @d() { entry: - br label %BB.tomerge + br label %BB.nomerge -BB.tomerge: ; preds = %Common, %entry +BB.nomerge: ; preds = %Common, %entry ; This phi has a matching value (0) with below phi (0), so blocks ; can be merged. %a = phi i32 [ 1, %entry ], [ 0, %Common ] ; <i32> [#uses=1] br label %Succ Succ: ; preds = %Common, %BB.tomerge - %b = phi i32 [ %a, %BB.tomerge ], [ 0, %Common ] ; <i32> [#uses=0] + %b = phi i32 [ %a, %BB.nomerge ], [ 0, %Common ] ; <i32> [#uses=0] %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Common, label %Exit Common: ; preds = %Succ %cond = call i1 @foo( ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Succ + br i1 %cond, label %BB.nomerge, label %Succ Exit: ; preds = %Succ ret void @@ -110,21 +110,21 @@ Exit: ; preds = %Succ ; This function can be merged define void @e() { entry: - br label %BB.tomerge + br label %Succ -BB.tomerge: ; preds = %Use, %entry +Succ: ; preds = %Use, %entry ; This phi is used somewhere else than Succ, but this should not prevent ; merging this block %a = phi i32 [ 1, %entry ], [ 0, %Use ] ; <i32> [#uses=1] - br label %Succ + br label %BB.tomerge -Succ: ; preds = %BB.tomerge +BB.tomerge: ; preds = %BB.tomerge %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Use, label %Exit Use: ; preds = %Succ %cond = call i1 @bar( i32 %a ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Exit + br i1 %cond, label %Succ, label %Exit Exit: ; preds = %Use, %Succ ret void diff --git a/test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll b/test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll index 154677b0747f..dee2e9b3294f 100644 --- a/test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll +++ b/test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll @@ -1,4 +1,5 @@ -; RUN: opt < %s -simplifycfg -S | grep "%outval = phi i32 .*mux" +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -simplifycfg -S | FileCheck %s ; PR2540 ; Outval should end up with a select from 0/2, not all constants. @@ -8,29 +9,47 @@ target triple = "i386-pc-linux-gnu" @.str = internal constant [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=1] define i32 @main() nounwind { +; CHECK-LABEL: @main( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = load i32, i32* @g_37, align 4 +; CHECK-NEXT: [[CMPA:%.*]] = icmp ne i32 [[L]], 0 +; CHECK-NEXT: br i1 [[CMPA]], label %func_1.exit, label %mooseblock +; CHECK: mooseblock: +; CHECK-NEXT: [[CMPB:%.*]] = icmp eq i1 [[CMPA]], false +; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[CMPB]], [[CMPA]] +; CHECK-NEXT: [[DOTMUX:%.*]] = select i1 [[CMPB]], i32 0, i32 2 +; CHECK-NEXT: br i1 [[BRMERGE]], label %func_1.exit, label %infloop +; CHECK: func_1.exit: +; CHECK-NEXT: [[OUTVAL:%.*]] = phi i32 [ 1, %entry ], [ [[DOTMUX]], %mooseblock ] +; CHECK-NEXT: [[POUT:%.*]] = tail call i32 (i8*, ...) @printf +; CHECK-NEXT: ret i32 0 +; CHECK: infloop: +; CHECK-NEXT: br label %infloop +; entry: - %l = load i32, i32* @g_37, align 4 ; <i32> [#uses=1] - %cmpa = icmp ne i32 %l, 0 ; <i1> [#uses=3] - br i1 %cmpa, label %func_1.exit, label %mooseblock + %l = load i32, i32* @g_37, align 4 ; <i32> [#uses=1] + %cmpa = icmp ne i32 %l, 0 ; <i1> [#uses=3] + br i1 %cmpa, label %func_1.exit, label %mooseblock mooseblock: ; preds = %entry - %cmpb = icmp eq i1 %cmpa, false ; <i1> [#uses=2] - br i1 %cmpb, label %monkeyblock, label %beeblock + %cmpb = icmp eq i1 %cmpa, false ; <i1> [#uses=2] + br i1 %cmpb, label %monkeyblock, label %beeblock monkeyblock: ; preds = %monkeyblock, %mooseblock - br i1 %cmpb, label %cowblock, label %monkeyblock + br i1 %cmpb, label %cowblock, label %monkeyblock beeblock: ; preds = %beeblock, %mooseblock - br i1 %cmpa, label %cowblock, label %beeblock + br i1 %cmpa, label %cowblock, label %beeblock cowblock: ; preds = %beeblock, %monkeyblock - %cowval = phi i32 [ 2, %beeblock ], [ 0, %monkeyblock ] ; <i32> [#uses=1] - br label %func_1.exit + %cowval = phi i32 [ 2, %beeblock ], [ 0, %monkeyblock ] ; <i32> [#uses=1] + br label %func_1.exit func_1.exit: ; preds = %cowblock, %entry - %outval = phi i32 [ %cowval, %cowblock ], [ 1, %entry ] ; <i32> [#uses=1] - %pout = tail call i32 (i8*, ...) @printf( i8* noalias getelementptr ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %outval ) nounwind ; <i32> [#uses=0] - ret i32 0 + %outval = phi i32 [ %cowval, %cowblock ], [ 1, %entry ] ; <i32> [#uses=1] + %pout = tail call i32 (i8*, ...) @printf( i8* noalias getelementptr ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %outval ) nounwind ; <i32> [#uses=0] + ret i32 0 } -declare i32 @printf(i8*, ...) nounwind +declare i32 @printf(i8*, ...) nounwind + diff --git a/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll b/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll index b07ef970a20a..6e8593755c7d 100644 --- a/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll +++ b/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll @@ -5,7 +5,7 @@ ; RUN: not grep X: %t ; RUN: not grep 'switch i32[^U]+%U' %t ; RUN: not grep "^BB.tomerge" %t -; RUN: grep "^BB.nomerge" %t | count 2 +; RUN: grep "^BB.nomerge" %t | count 4 ; ; ModuleID = '<stdin>' @@ -179,24 +179,24 @@ Exit: ; preds = %Succ ret void } -; This function can be merged +; This function can't be merged (for keeping canonical loop structures) define void @c() { entry: - br label %BB.tomerge + br label %BB.nomerge -BB.tomerge: ; preds = %Common, %entry +BB.nomerge: ; preds = %Common, %entry br label %Succ Succ: ; preds = %Common, %BB.tomerge, %Pre-Exit ; This phi has identical values for Common and (through BB) Common, ; blocks can't be merged - %b = phi i32 [ 1, %BB.tomerge ], [ 1, %Common ], [ 2, %Pre-Exit ] + %b = phi i32 [ 1, %BB.nomerge ], [ 1, %Common ], [ 2, %Pre-Exit ] %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Common, label %Pre-Exit Common: ; preds = %Succ %cond = call i1 @foo( ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Succ + br i1 %cond, label %BB.nomerge, label %Succ Pre-Exit: ; preds = %Succ ; This adds a backedge, so the %b phi node gets a third branch and is @@ -208,25 +208,25 @@ Exit: ; preds = %Pre-Exit ret void } -; This function can be merged +; This function can't be merged (for keeping canonical loop structures) define void @d() { entry: - br label %BB.tomerge + br label %BB.nomerge -BB.tomerge: ; preds = %Common, %entry +BB.nomerge: ; preds = %Common, %entry ; This phi has a matching value (0) with below phi (0), so blocks ; can be merged. %a = phi i32 [ 1, %entry ], [ 0, %Common ] ; <i32> [#uses=1] br label %Succ Succ: ; preds = %Common, %BB.tomerge - %b = phi i32 [ %a, %BB.tomerge ], [ 0, %Common ] ; <i32> [#uses=0] + %b = phi i32 [ %a, %BB.nomerge ], [ 0, %Common ] ; <i32> [#uses=0] %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Common, label %Exit Common: ; preds = %Succ %cond = call i1 @foo( ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Succ + br i1 %cond, label %BB.nomerge, label %Succ Exit: ; preds = %Succ ret void @@ -235,21 +235,21 @@ Exit: ; preds = %Succ ; This function can be merged define void @e() { entry: - br label %BB.tomerge + br label %Succ -BB.tomerge: ; preds = %Use, %entry +Succ: ; preds = %Use, %entry ; This phi is used somewhere else than Succ, but this should not prevent ; merging this block %a = phi i32 [ 1, %entry ], [ 0, %Use ] ; <i32> [#uses=1] - br label %Succ + br label %BB.tomerge -Succ: ; preds = %BB.tomerge +BB.tomerge: ; preds = %Succ %conde = call i1 @foo( ) ; <i1> [#uses=1] br i1 %conde, label %Use, label %Exit Use: ; preds = %Succ %cond = call i1 @bar( i32 %a ) ; <i1> [#uses=1] - br i1 %cond, label %BB.tomerge, label %Exit + br i1 %cond, label %Succ, label %Exit Exit: ; preds = %Use, %Succ ret void diff --git a/test/Transforms/SimplifyCFG/InfLoop.ll b/test/Transforms/SimplifyCFG/InfLoop.ll new file mode 100644 index 000000000000..a56076e42ce1 --- /dev/null +++ b/test/Transforms/SimplifyCFG/InfLoop.ll @@ -0,0 +1,101 @@ +; RUN: opt < %s -simplifycfg -disable-output +; END. + +target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" +target triple = "thumbv7-apple-ios9.0.0" + +%struct.anon = type { %struct.anon.0, i32, i32, %union.T1 } +%struct.anon.0 = type { i32, [256 x i32], [256 x i8] } +%union.T1 = type { %struct.F} +%struct.F = type { i32 } + +@U = internal global %struct.anon zeroinitializer, align 4 + +define void @main() { +entry: + %0 = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @U, i32 0, i32 2), align 4 + %cmp.i = icmp eq i32 %0, -1 + br i1 %cmp.i, label %if.then, label %if.end + +if.then: ; preds = %entry + br label %if.end + +if.end: ; preds = %entry, %if.then + %1 = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @U, i32 0, i32 2), align 4 + %bf.load = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @U, i32 0, i32 3, i32 0, i32 0), align 4 + %cmp = icmp slt i32 %0, 0 + br i1 %cmp, label %if.end7, label %cond.false + +cond.false: ; preds = %if.end + %add = and i32 %bf.load, 30 + %shl = add nuw nsw i32 %add, 2 + br label %if.end7 + +if.end7: ; preds = %if.end, %cond.false + %2 = icmp eq i32 %0, 1 + br i1 %2, label %if.then9, label %if.else10 + +if.then9: ; preds = %if.end7 + br label %if.end29 + +if.else10: ; preds = %if.end7 + %cmp11 = icmp ugt i32 %0, 13 + br i1 %cmp11, label %if.then12, label %if.else14 + +if.then12: ; preds = %if.else10 + br label %if.end26 + +if.else14: ; preds = %if.else10 + %tobool = icmp eq i1 %2, 0 + br i1 %tobool, label %lor.rhs, label %if.then18 + +lor.rhs: ; preds = %if.else14 + %tobool.not.i = icmp eq i1 %2, 0 + br i1 %tobool.not.i, label %if.else21, label %if.end.i54 + +if.end.i54: ; preds = %lor.rhs + br label %for.cond.i + +for.cond.i: ; preds = %if.end6.i, %if.end.i54 + %ix.0.i = phi i32 [ 0, %if.end.i54 ], [ %inc.i55, %if.end6.i ] + %ret.0.off0.i = phi i1 [ false, %if.end.i54 ], [ %.ret.0.off0.i, %if.end6.i ] + %cmp2.i = icmp ult i32 %ix.0.i, 2 + br i1 %cmp2.i, label %for.body.i, label %TmpSimpleNeedExt.exit + +for.body.i: ; preds = %for.cond.i + %arrayidx.i = getelementptr inbounds %struct.anon, %struct.anon* @U, i32 0, i32 0, i32 2, i32 %ix.0.i + %elt = load i8, i8* %arrayidx.i, align 1 + %cmp3.i = icmp sgt i8 %elt, 7 + br i1 %cmp3.i, label %if.else21, label %if.end6.i + +if.end6.i: ; preds = %for.body.i + %cmp10.i = icmp ugt i8 %elt, 59 + %.ret.0.off0.i = or i1 %ret.0.off0.i, %cmp10.i + %inc.i55 = add i32 %ix.0.i, 1 + br label %for.cond.i + +TmpSimpleNeedExt.exit: ; preds = %for.body.i + br i1 %ret.0.off0.i, label %if.then18, label %if.else21 + +if.then18: ; preds = %if.else14, %TmpSimpleNeedExt.exit + br label %if.end26 + +if.else21: ; preds = %for.body.i, %lor.rhs, %TmpSimpleNeedExt.exit + br label %if.end26 + +if.end26: ; preds = %if.then18, %if.else21, %if.then12 + %cmp.i51 = icmp slt i32 %0, 7 + br i1 %cmp.i51, label %if.then.i, label %if.end.i + +if.then.i: ; preds = %if.end26 + br label %if.end.i + +if.end.i: ; preds = %if.then.i, %if.end26 + br label %if.end29 + +if.then2.i: ; preds = %if.end.i + br label %if.end29 + +if.end29: ; preds = %if.end.i, %if.then2.i, %if.then9 + ret void +} diff --git a/test/Transforms/SimplifyCFG/PR16069.ll b/test/Transforms/SimplifyCFG/PR16069.ll index 0b3d67794513..9048b5680c75 100644 --- a/test/Transforms/SimplifyCFG/PR16069.ll +++ b/test/Transforms/SimplifyCFG/PR16069.ll @@ -1,9 +1,13 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py ; RUN: opt < %s -simplifycfg -S | FileCheck %s @b = extern_weak global i32 define i32 @foo(i1 %y) { -; CHECK: define i32 @foo(i1 %y) { +; CHECK-LABEL: @foo( +; CHECK: [[COND_I:%.*]] = phi i32 [ srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb2 ], [ 0, %0 ] +; CHECK-NEXT: ret i32 [[COND_I]] +; br i1 %y, label %bb1, label %bb2 bb1: br label %bb3 @@ -11,18 +15,19 @@ bb2: br label %bb3 bb3: %cond.i = phi i32 [ 0, %bb1 ], [ srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb2 ] -; CHECK: phi i32 {{.*}} srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb2 ret i32 %cond.i } define i32 @foo2(i1 %x) { -; CHECK: define i32 @foo2(i1 %x) { +; CHECK-LABEL: @foo2( +; CHECK: [[COND:%.*]] = phi i32 [ 0, %bb1 ], [ srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb0 ] +; CHECK-NEXT: ret i32 [[COND]] +; bb0: br i1 %x, label %bb1, label %bb2 bb1: br label %bb2 bb2: %cond = phi i32 [ 0, %bb1 ], [ srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb0 ] -; CHECK: %cond = phi i32 [ 0, %bb1 ], [ srem (i32 1, i32 zext (i1 icmp eq (i32* @b, i32* null) to i32)), %bb0 ] ret i32 %cond } diff --git a/test/Transforms/SimplifyCFG/PR27615-simplify-cond-br.ll b/test/Transforms/SimplifyCFG/PR27615-simplify-cond-br.ll new file mode 100644 index 000000000000..872444d01655 --- /dev/null +++ b/test/Transforms/SimplifyCFG/PR27615-simplify-cond-br.ll @@ -0,0 +1,68 @@ +; RUN: opt -S -simplifycfg -strip-debug < %s | FileCheck %s +; RUN: opt -S -simplifycfg < %s | FileCheck %s + +; Test case for BUG-27615 +; Test that simplify cond branch produce same result for debug and non-debug builds +; CHECK: select i1 %or.cond, i32 -1, i32 5 +; CHECK-NOT: bb1: + +; ModuleID = './csmith107.i.debug.ll' +source_filename = "./csmith107.i.debug.ll" + +@a = global i16 0 +@b = global i32 0 +@c = global i16* null + + +; Function Attrs: nounwind +define i16 @fn1() #3 !dbg !15 { +bb2: + store i32 -1, i32* @b, align 1 + %_tmp1.pre = load i16, i16* @a, align 1, !dbg !19 + %_tmp2.pre = load i16*, i16** @c, align 1 + tail call void @llvm.dbg.value(metadata i16 6, i64 0, metadata !22, metadata !23), !dbg !24 + tail call void @llvm.dbg.value(metadata i16 %_tmp1.pre, i64 0, metadata !25, metadata !23), !dbg !19 + %_tmp3 = load i16, i16* %_tmp2.pre, align 1 + %_tmp4 = icmp ne i16 %_tmp3, 0 + %_tmp6 = icmp ne i16 %_tmp1.pre, 0 + %or.cond = and i1 %_tmp6, %_tmp4 + br i1 %or.cond, label %bb5, label %bb1 + +bb1: ; preds = %bb2 + store i32 5, i32* @b, align 1 + br label %bb5 + +bb5: ; preds = %bb1, %bb2 + ret i16 0 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #4 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!12, !13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "FlexC Compiler v6.36 (LLVM)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !3) +!1 = !DIFile(filename: "csmith107.i.c", directory: "/tmp") +!2 = !{} +!3 = !{!4, !6, !10} +!4 = !DIGlobalVariable(name: "a", scope: null, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, variable: i16* @a) +!5 = !DIBasicType(name: "int", size: 16, align: 16, encoding: DW_ATE_signed) +!6 = !DIGlobalVariable(name: "b", scope: null, file: !1, line: 3, type: !7, isLocal: false, isDefinition: true, variable: i32* @b) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint32_t", file: !1, line: 1, baseType: !8) +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "__u32_t", file: !1, baseType: !9) +!9 = !DIBasicType(name: "unsigned long", size: 32, align: 16, encoding: DW_ATE_unsigned) +!10 = !DIGlobalVariable(name: "c", scope: null, file: !1, line: 4, type: !11, isLocal: false, isDefinition: true, variable: i16** @c) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 16, align: 16) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!15 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 5, type: !16, isLocal: false, isDefinition: true, scopeLine: 5, isOptimized: false, unit: !0, variables: !2) +!16 = !DISubroutineType(types: !17) +!17 = !{!5} +!19 = !DILocation(line: 8, column: 16, scope: !20) +!20 = !DILexicalBlock(scope: !15, file: !1, line: 7, column: 29) +!22 = !DILocalVariable(name: "d", scope: !20, line: 8, type: !5) +!23 = !DIExpression() +!24 = !DILocation(line: 8, column: 9, scope: !20) +!25 = !DILocalVariable(name: "e", scope: !20, line: 8, type: !5) + diff --git a/test/Transforms/SimplifyCFG/PhiBlockMerge.ll b/test/Transforms/SimplifyCFG/PhiBlockMerge.ll index 555082921b96..85b987060181 100644 --- a/test/Transforms/SimplifyCFG/PhiBlockMerge.ll +++ b/test/Transforms/SimplifyCFG/PhiBlockMerge.ll @@ -1,24 +1,29 @@ +; NOTE: Assertions have been autogenerated by update_test_checks.py ; Test merging of blocks that only have PHI nodes in them ; ; RUN: opt < %s -simplifycfg -S | FileCheck %s ; define i32 @test(i1 %a, i1 %b) { - br i1 %a, label %M, label %O +; CHECK-LABEL: @test( +; CHECK: M: +; CHECK-NEXT: [[DOT:%.*]] = select i1 %b, i32 0, i32 1 +; CHECK-NEXT: [[W:%.*]] = select i1 %a, i32 2, i32 [[DOT]] +; CHECK-NEXT: [[R:%.*]] = add i32 [[W]], 1 +; CHECK-NEXT: ret i32 [[R]] +; + br i1 %a, label %M, label %O O: ; preds = %0 -; CHECK: select i1 %b, i32 0, i32 1 -; CHECK-NOT: phi - br i1 %b, label %N, label %Q + br i1 %b, label %N, label %Q Q: ; preds = %O - br label %N + br label %N N: ; preds = %Q, %O - ; This block should be foldable into M - %Wp = phi i32 [ 0, %O ], [ 1, %Q ] ; <i32> [#uses=1] - br label %M + ; This block should be foldable into M + %Wp = phi i32 [ 0, %O ], [ 1, %Q ] ; <i32> [#uses=1] + br label %M M: ; preds = %N, %0 - %W = phi i32 [ %Wp, %N ], [ 2, %0 ] ; <i32> [#uses=1] - %R = add i32 %W, 1 ; <i32> [#uses=1] - ret i32 %R -; CHECK: ret + %W = phi i32 [ %Wp, %N ], [ 2, %0 ] ; <i32> [#uses=1] + %R = add i32 %W, 1 ; <i32> [#uses=1] + ret i32 %R } diff --git a/test/Transforms/SimplifyCFG/PhiEliminate2.ll b/test/Transforms/SimplifyCFG/PhiEliminate2.ll index 0b3893d520db..0ca65286da35 100644 --- a/test/Transforms/SimplifyCFG/PhiEliminate2.ll +++ b/test/Transforms/SimplifyCFG/PhiEliminate2.ll @@ -1,17 +1,34 @@ -; RUN: opt < %s -simplifycfg -S | not grep br +; RUN: opt < %s -simplifycfg -S | FileCheck %s -define i32 @test(i1 %C, i32 %V1, i32 %V2, i16 %V3) { +; Use a select to make this a single BB. +; Also, make sure the profile metadata is propagated to the select (PR26636). + +define i32 @FoldTwoEntryPHINode(i1 %C, i32 %V1, i32 %V2, i16 %V3) { entry: - br i1 %C, label %then, label %else -then: ; preds = %entry - %V4 = or i32 %V2, %V1 ; <i32> [#uses=1] + br i1 %C, label %then, label %else, !prof !0, !unpredictable !1 +then: + %V4 = or i32 %V2, %V1 br label %Cont -else: ; preds = %entry - %V5 = sext i16 %V3 to i32 ; <i32> [#uses=1] +else: + %V5 = sext i16 %V3 to i32 br label %Cont -Cont: ; preds = %then, %else - %V6 = phi i32 [ %V5, %else ], [ %V4, %then ] ; <i32> [#uses=0] - call i32 @test( i1 false, i32 0, i32 0, i16 0 ) ; <i32>:0 [#uses=0] +Cont: + %V6 = phi i32 [ %V5, %else ], [ %V4, %then ] + call i32 @FoldTwoEntryPHINode( i1 false, i32 0, i32 0, i16 0 ) ret i32 %V1 + +; CHECK-LABEL: @FoldTwoEntryPHINode( +; CHECK-NEXT: entry: +; CHECK-NEXT: %V5 = sext i16 %V3 to i32 +; CHECK-NEXT: %V4 = or i32 %V2, %V1 +; CHECK-NEXT: %V6 = select i1 %C, i32 %V4, i32 %V5, !prof !0, !unpredictable !1 +; CHECK-NEXT: %0 = call i32 @FoldTwoEntryPHINode(i1 false, i32 0, i32 0, i16 0) +; CHECK-NEXT: ret i32 %V1 } +!0 = !{!"branch_weights", i32 3, i32 5} +!1 = !{} + +; CHECK: !0 = !{!"branch_weights", i32 3, i32 5} +; CHECK: !1 = !{} + diff --git a/test/Transforms/SimplifyCFG/UnreachableEliminate.ll b/test/Transforms/SimplifyCFG/UnreachableEliminate.ll index 87872a6a8a10..be612b288b77 100644 --- a/test/Transforms/SimplifyCFG/UnreachableEliminate.ll +++ b/test/Transforms/SimplifyCFG/UnreachableEliminate.ll @@ -96,3 +96,34 @@ bb2: store i8 2, i8* %ptr.2, align 8 ret void } + +define i32 @test7(i1 %X) { +entry: + br i1 %X, label %if, label %else + +if: + call void undef() + br label %else + +else: + %phi = phi i32 [ 0, %entry ], [ 1, %if ] + ret i32 %phi +} +; CHECK-LABEL: define i32 @test7( +; CHECK-NOT: call +; CHECK: ret i32 0 + +define void @test8(i1 %X, void ()* %Y) { +entry: + br i1 %X, label %if, label %else + +if: + br label %else + +else: + %phi = phi void ()* [ %Y, %entry ], [ null, %if ] + call void %phi() + ret void +} +; CHECK-LABEL: define void @test8( +; CHECK: call void %Y( diff --git a/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll b/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll index 6953cf9c8b33..bae8c1dc5a4b 100644 --- a/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll +++ b/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll @@ -1306,8 +1306,8 @@ l6: ; Speculation depth must be limited to avoid a zero-cost instruction cycle. ; CHECK-LABEL: @PR26308( -; CHECK: cleanup4: -; CHECK-NEXT: br label %cleanup4 +; CHECK: while.body: +; CHECK-NEXT: br label %while.body define i32 @PR26308(i1 %B, i64 %load) { entry: diff --git a/test/Transforms/SimplifyCFG/attr-convergent.ll b/test/Transforms/SimplifyCFG/attr-convergent.ll new file mode 100644 index 000000000000..a5f363d055a6 --- /dev/null +++ b/test/Transforms/SimplifyCFG/attr-convergent.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +; Checks that the SimplifyCFG pass won't duplicate a call to a function marked +; convergent. +; +; CHECK: call void @barrier +; CHECK-NOT: call void @barrier +define void @check(i1 %cond, i32* %out) { +entry: + br i1 %cond, label %if.then, label %if.end + +if.then: + store i32 5, i32* %out + br label %if.end + +if.end: + %x = phi i1 [ true, %entry ], [ false, %if.then ] + call void @barrier() + br i1 %x, label %cond.end, label %cond.false + +cond.false: + br label %cond.end + +cond.end: + ret void +} + +declare void @barrier() convergent diff --git a/test/Transforms/SimplifyCFG/basictest.ll b/test/Transforms/SimplifyCFG/basictest.ll index d4a9c81e506d..686a535a32d9 100644 --- a/test/Transforms/SimplifyCFG/basictest.ll +++ b/test/Transforms/SimplifyCFG/basictest.ll @@ -25,6 +25,54 @@ define void @test3(i1 %T) { ; CHECK-NEXT: 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) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, 0 + br i1 %cmp2, label %else, label %untaken + +else: + call void @foo() + ret void + +untaken: + ret void +} + +; 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) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %else, label %untaken + +else: + call void @foo() + ret void + +untaken: + ret void +} + +declare void @foo() ; PR5795 define void @test5(i32 %A) { @@ -75,10 +123,10 @@ declare i8 @test6g(i8*) !0 = !{!1, !1, i64 0} !1 = !{!"foo"} !2 = !{i8 0, i8 2} -!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !7, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !4, subprograms: !4, globals: !4) +!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !7, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !4) !4 = !{} !5 = !DILocation(line: 23, scope: !6) -!6 = distinct !DISubprogram(name: "foo", scope: !3, file: !7, line: 1, type: !DISubroutineType(types: !4), isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, variables: !4) +!6 = distinct !DISubprogram(name: "foo", scope: !3, file: !7, line: 1, type: !DISubroutineType(types: !4), isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !3, variables: !4) !7 = !DIFile(filename: "foo.c", directory: "/") !8 = !{i32 2, !"Dwarf Version", i32 2} !9 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/test/Transforms/SimplifyCFG/branch-fold-dbg.ll b/test/Transforms/SimplifyCFG/branch-fold-dbg.ll index 34871063bbcc..3c01e71f54a5 100644 --- a/test/Transforms/SimplifyCFG/branch-fold-dbg.ll +++ b/test/Transforms/SimplifyCFG/branch-fold-dbg.ll @@ -39,11 +39,11 @@ BB5: ; preds = %BB3, %BB2, %BB1, %E declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnone -!llvm.dbg.sp = !{!0} +!llvm.dbg.cu = !{!2} -!0 = distinct !DISubprogram(name: "foo", line: 231, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !15, scope: !1, type: !3) +!0 = distinct !DISubprogram(name: "foo", line: 231, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !15, scope: !1, type: !3) !1 = !DIFile(filename: "a.c", directory: "/private/tmp") -!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang (trunk 129006)", isOptimized: true, emissionKind: 0, file: !15, enums: !4, retainedTypes: !4) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang (trunk 129006)", isOptimized: true, emissionKind: FullDebug, file: !15, enums: !4, retainedTypes: !4) !3 = !DISubroutineType(types: !4) !4 = !{null} !5 = !DILocation(line: 131, column: 2, scope: !0) diff --git a/test/Transforms/SimplifyCFG/combine-parallel-mem-md.ll b/test/Transforms/SimplifyCFG/combine-parallel-mem-md.ll new file mode 100644 index 000000000000..7afde1ff8d9a --- /dev/null +++ b/test/Transforms/SimplifyCFG/combine-parallel-mem-md.ll @@ -0,0 +1,55 @@ +; RUN: opt -simplifycfg -S < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: norecurse nounwind uwtable +define void @Test(i32* nocapture %res, i32* nocapture readnone %c, i32* nocapture readonly %d, i32* nocapture readonly %p) #0 { +entry: + br label %for.body + +; CHECK-LABEL: @Test +; CHECK: load i32, i32* {{.*}}, align 4, !llvm.mem.parallel_loop_access !0 +; CHECK: load i32, i32* {{.*}}, align 4, !llvm.mem.parallel_loop_access !0 +; CHECK: store i32 {{.*}}, align 4, !llvm.mem.parallel_loop_access !0 +; CHECK-NOT: load +; CHECK-NOT: store + +for.body: ; preds = %cond.end, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %cond.end ] + %arrayidx = getelementptr inbounds i32, i32* %p, i64 %indvars.iv + %0 = load i32, i32* %arrayidx, align 4, !llvm.mem.parallel_loop_access !0 + %cmp1 = icmp eq i32 %0, 0 + br i1 %cmp1, label %cond.true, label %cond.false + +cond.false: ; preds = %for.body + %arrayidx3 = getelementptr inbounds i32, i32* %res, i64 %indvars.iv + %v = load i32, i32* %arrayidx3, align 4, !llvm.mem.parallel_loop_access !0 + %arrayidx7 = getelementptr inbounds i32, i32* %d, i64 %indvars.iv + %1 = load i32, i32* %arrayidx7, align 4, !llvm.mem.parallel_loop_access !0 + %add = add nsw i32 %1, %v + br label %cond.end + +cond.true: ; preds = %for.body + %arrayidx4 = getelementptr inbounds i32, i32* %res, i64 %indvars.iv + %w = load i32, i32* %arrayidx4, align 4, !llvm.mem.parallel_loop_access !0 + %arrayidx8 = getelementptr inbounds i32, i32* %d, i64 %indvars.iv + %2 = load i32, i32* %arrayidx8, align 4, !llvm.mem.parallel_loop_access !0 + %add2 = add nsw i32 %2, %w + br label %cond.end + +cond.end: ; preds = %for.body, %cond.false + %cond = phi i32 [ %add, %cond.false ], [ %add2, %cond.true ] + %arrayidx9 = getelementptr inbounds i32, i32* %res, i64 %indvars.iv + store i32 %cond, i32* %arrayidx9, align 4, !llvm.mem.parallel_loop_access !0 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 16 + br i1 %exitcond, label %for.end, label %for.body, !llvm.loop !0 + +for.end: ; preds = %cond.end + ret void +} + +attributes #0 = { norecurse nounwind uwtable } + +!0 = distinct !{!0, !1} +!1 = !{!"llvm.loop.vectorize.enable", i1 true} diff --git a/test/Transforms/SimplifyCFG/empty-cleanuppad.ll b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll index 57b362889955..9f657a81a05b 100644 --- a/test/Transforms/SimplifyCFG/empty-cleanuppad.ll +++ b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll @@ -404,6 +404,59 @@ catch.cont: ; preds = %catch 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 { +entry: + %s = alloca i8, align 1 + call void @llvm.lifetime.start(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 + +ehcleanup: + %cleanup.pad = cleanuppad within none [] + call void @llvm.lifetime.end(i64 1, i8* nonnull %s) + cleanupret from %cleanup.pad unwind label %catch.dispatch + +catch.dispatch: + %catch.switch = catchswitch within none [label %catch] unwind to caller + +catch: + %catch.pad = catchpad within %catch.switch [i8* null, i32 0, i8* null] + catchret from %catch.pad to label %try.cont + +try.cont: + ret i32 0 +} + +; CHECK-LABEL: define void @f10( +define void @f10(i32 %V) personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @g() + to label %unreachable unwind label %cleanup +; CHECK: call void @g() +; CHECK-NEXT: unreachable + +unreachable: + unreachable + +cleanup: + %cp = cleanuppad within none [] + switch i32 %V, label %cleanupret1 [ + i32 0, label %cleanupret2 + ] + +cleanupret1: + cleanupret from %cp unwind to caller + +cleanupret2: + cleanupret from %cp unwind to caller +} %struct.S = type { i8 } %struct.S2 = type { i8 } @@ -413,3 +466,5 @@ declare void @use_x(i32 %x) declare i32 @__CxxFrameHandler3(...) +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) diff --git a/test/Transforms/SimplifyCFG/guards.ll b/test/Transforms/SimplifyCFG/guards.ll new file mode 100644 index 000000000000..71144d7ac24f --- /dev/null +++ b/test/Transforms/SimplifyCFG/guards.ll @@ -0,0 +1,86 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s + +declare void @llvm.experimental.guard(i1, ...) + +define i32 @f_0(i1 %c) { +; CHECK-LABEL: @f_0( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] +; CHECK-NEXT: unreachable +entry: + call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] + ret i32 10 +} + +define i32 @f_1(i1 %c) { +; Demonstrate that we (intentionally) do not simplify a guard on undef + +; CHECK-LABEL: @f_1( +; CHECK: ret i32 10 +; CHECK: ret i32 20 + +entry: + br i1 %c, label %true, label %false + +true: + call void(i1, ...) @llvm.experimental.guard(i1 undef) [ "deopt"() ] + ret i32 10 + +false: + ret i32 20 +} + +define i32 @f_2(i1 %c, i32* %buf) { +; CHECK-LABEL: @f_2( +entry: + br i1 %c, label %guard_block, label %merge_block + +guard_block: + call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] + %val = load i32, i32* %buf + br label %merge_block + +merge_block: + %to.return = phi i32 [ %val, %guard_block ], [ 50, %entry ] + ret i32 %to.return +; CHECK: guard_block: +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] +; CHECK-NEXT: unreachable + +; CHECK: merge_block: +; CHECK-NEXT: ret i32 50 +} + +define i32 @f_3(i1* %c, i32* %buf) { +; CHECK-LABEL: @f_3( +entry: + %c0 = load volatile i1, i1* %c + br i1 %c0, label %guard_block, label %merge_block + +guard_block: + call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] + %val = load i32, i32* %buf + %c2 = load volatile i1, i1* %c + br i1 %c2, label %left, label %right + +merge_block: + %c1 = load volatile i1, i1* %c + br i1 %c1, label %left, label %right + +left: + %val.left = phi i32 [ %val, %guard_block ], [ 50, %merge_block ] + ret i32 %val.left + +right: + %val.right = phi i32 [ %val, %guard_block ], [ 100, %merge_block ] + ret i32 %val.right + +; 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: [[VAL:%[^ ]]] = select i1 %c1, i32 50, i32 100 +; CHECK-NEXT: ret i32 [[VAL]] +} diff --git a/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll b/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll index 887373a2d3db..e91fa731c59d 100644 --- a/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll +++ b/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll @@ -30,17 +30,16 @@ declare i32 @bar(...) declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnone !llvm.module.flags = !{!21} -!llvm.dbg.sp = !{!0} +!llvm.dbg.cu = !{!2} -!0 = distinct !DISubprogram(name: "foo", line: 2, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !20, scope: !1, type: !3) +!0 = distinct !DISubprogram(name: "foo", line: 2, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !20, scope: !1, type: !3) !1 = !DIFile(filename: "b.c", directory: "/private/tmp") -!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", isOptimized: true, emissionKind: 0, file: !20, enums: !8, retainedTypes: !8) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", isOptimized: true, emissionKind: FullDebug, file: !20) !3 = !DISubroutineType(types: !4) !4 = !{!5} !5 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !6 = !DILocalVariable(name: "i", line: 2, arg: 1, scope: !0, file: !1, type: !5) !7 = !DILocation(line: 2, column: 13, scope: !0) -!8 = !{i32 0} !9 = !DILocalVariable(name: "k", line: 3, scope: !10, file: !1, type: !5) !10 = distinct !DILexicalBlock(line: 2, column: 16, file: !20, scope: !0) !11 = !DILocation(line: 3, column: 12, scope: !10) diff --git a/test/Transforms/SimplifyCFG/implied-cond-matching-false-dest.ll b/test/Transforms/SimplifyCFG/implied-cond-matching-false-dest.ll new file mode 100644 index 000000000000..1d29813ecfa2 --- /dev/null +++ b/test/Transforms/SimplifyCFG/implied-cond-matching-false-dest.ll @@ -0,0 +1,339 @@ +; RUN: opt %s -S -simplifycfg | FileCheck %s + +declare void @is(i1) + +; If A == B is false then A == B is implied false. +; CHECK-LABEL: @test_eq_eq +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_eq(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp eq i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A == B is false then A != B is implied true. +; CHECK-LABEL: @test_eq_ne +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_ne(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ne i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A != B is false then A != B is implied false. +; CHECK-LABEL: @test_ne_ne +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ne(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ne i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A != B is false then A >u B is implied false. +; CHECK-LABEL: @test_ne_ugt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A != B is false then A >=u B is implied true. +; CHECK-LABEL: @test_ne_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ne_uge(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A != B is false then A <u B is implied false. +; CHECK-LABEL: @test_ne_ult +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ult(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A != B is false then A <=u B is implied true. +; CHECK-LABEL: @test_ne_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ne_ule(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A >u B is false then A >u B is implied false. +; CHECK-LABEL: @test_ugt_ugt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ugt_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A >u B is false then A <=u B is implied true. +; CHECK-LABEL: @test_ugt_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ugt_ule(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A >=u B is false then A >=u B is implied false. +; CHECK-LABEL: @test_uge_uge +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_uge_uge(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A >=u B is false then A <u B is implied true. +; CHECK-LABEL: @test_uge_ult +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_uge_ult(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A >=u B is false then A <=u B is implied true. +; CHECK-LABEL: @test_uge_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_uge_ule(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A <u B is false then A <u B is implied false. +; CHECK-LABEL: @test_ult_ult +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ult_ult(i32 %a, i32 %b) { + %cmp1 = icmp ult i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; If A <=u B is false then A <=u B is implied false. +; CHECK-LABEL: @test_ule_ule +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ule_ule(i32 %a, i32 %b) { + %cmp1 = icmp ule i32 %a, %b + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} diff --git a/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll b/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll new file mode 100644 index 000000000000..60ef81365982 --- /dev/null +++ b/test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll @@ -0,0 +1,123 @@ +; RUN: opt %s -S -simplifycfg | FileCheck %s + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test1 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test1(i32 %a) { + %cmp1 = icmp eq i32 %a, 0 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, 1 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test2 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test2(i32 %a) { + %cmp1 = icmp ugt i32 %a, 5 + br i1 %cmp1, label %untaken, label %taken + +taken: + %cmp2 = icmp ugt i32 %a, 6 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is false +; CHECK-LABEL: @test3 +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test3(i32 %a) { + %cmp1 = icmp ugt i32 %a, 1 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, 0 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is true +; CHECK-LABEL: @test4 +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test4(i32 %a) { + %cmp1 = icmp sgt i32 %a, 1 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, 0 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; cmp1 implies cmp2 is true +; CHECK-LABEL: @test5 +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test5(i32 %a) { + %cmp1 = icmp sgt i32 %a, 5 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, -1 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +declare void @is(i1) diff --git a/test/Transforms/SimplifyCFG/implied-cond-matching.ll b/test/Transforms/SimplifyCFG/implied-cond-matching.ll new file mode 100644 index 000000000000..33fc016bd386 --- /dev/null +++ b/test/Transforms/SimplifyCFG/implied-cond-matching.ll @@ -0,0 +1,1029 @@ +; RUN: opt %s -S -simplifycfg | FileCheck %s + +declare void @dead() +declare void @alive() +declare void @is(i1) + +; Test same condition with swapped operands. +; void test_swapped_ops(unsigned a, unsigned b) { +; if (a > b) { +; if (b > a) <- always false +; dead(); +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_ops +; CHECK-NOT: call void @dead() +; CHECK: call void @alive() +; CHECK: ret +define void @test_swapped_ops(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + %cmp1 = icmp ugt i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end + +if.then2: + call void @dead() + br label %if.end + +if.end: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +; void test_swapped_pred(unsigned a, unsigned b) { +; if (a > b) { +; alive(); +; if (b < a) <- always true; remove branch +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_pred +; CHECK: call void @alive() +; CHECK-NEXT: call void @alive() +; CHECK: ret +define void @test_swapped_pred(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + call void @alive() + %cmp1 = icmp ult i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +; A == B implies A == B is true. +; CHECK-LABEL: @test_eq_eq +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_eq(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, %b + br i1 %cmp2, label %eq_eq_istrue, label %eq_eq_isfalse + +eq_eq_istrue: + call void @is(i1 true) + ret void + +eq_eq_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A != B is false. +; CHECK-LABEL: @test_eq_ne +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_ne(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ne i32 %a, %b + br i1 %cmp2, label %eq_ne_istrue, label %eq_ne_isfalse + +eq_ne_istrue: + call void @is(i1 true) + ret void + +eq_ne_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >u B is false. +; CHECK-LABEL: @test_eq_ugt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_ugt(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %eq_ugt_istrue, label %eq_ugt_isfalse + +eq_ugt_istrue: + call void @is(i1 true) + ret void + +eq_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >=u B is true. +; CHECK-LABEL: @test_eq_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_uge(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %eq_uge_istrue, label %eq_uge_isfalse + +eq_uge_istrue: + call void @is(i1 true) + ret void + +eq_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A <u B is false. +; CHECK-LABEL: @test_eq_ult +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_ult(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %eq_ult_istrue, label %eq_ult_isfalse + +eq_ult_istrue: + call void @is(i1 true) + ret void + +eq_ult_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A <=u B is true. +; CHECK-LABEL: @test_eq_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_ule(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %eq_ule_istrue, label %eq_ule_isfalse + +eq_ule_istrue: + call void @is(i1 true) + ret void + +eq_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >s B is false. +; CHECK-LABEL: @test_eq_sgt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_sgt(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %eq_sgt_istrue, label %eq_sgt_isfalse + +eq_sgt_istrue: + call void @is(i1 true) + ret void + +eq_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >=s B is true. +; CHECK-LABEL: @test_eq_sge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_sge(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %eq_sge_istrue, label %eq_sge_isfalse + +eq_sge_istrue: + call void @is(i1 true) + ret void + +eq_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A <s B is false. +; CHECK-LABEL: @test_eq_slt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_slt(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp slt i32 %a, %b + br i1 %cmp2, label %eq_slt_istrue, label %eq_slt_isfalse + +eq_slt_istrue: + call void @is(i1 true) + ret void + +eq_slt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A <=s B is true. +; CHECK-LABEL: @test_eq_sle +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_sle(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %eq_sle_istrue, label %eq_sle_isfalse + +eq_sle_istrue: + call void @is(i1 true) + ret void + +eq_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A != B is true. +; CHECK-LABEL: @test_ne_ne +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ne_ne(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ne i32 %a, %b + br i1 %cmp2, label %ne_ne_istrue, label %ne_ne_isfalse + +ne_ne_istrue: + call void @is(i1 true) + ret void + +ne_ne_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_ugt +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %ne_ugt_istrue, label %ne_ugt_isfalse + +ne_ugt_istrue: + call void @is(i1 true) + ret void + +ne_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >=u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_uge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_uge(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %ne_uge_istrue, label %ne_uge_isfalse + +ne_uge_istrue: + call void @is(i1 true) + ret void + +ne_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A <u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_ult +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ult(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %ne_ult_istrue, label %ne_ult_isfalse + +ne_ult_istrue: + call void @is(i1 true) + ret void + +ne_ult_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A <=u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_ule +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ule(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %ne_ule_istrue, label %ne_ule_isfalse + +ne_ule_istrue: + call void @is(i1 true) + ret void + +ne_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_sgt +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_sgt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %ne_sgt_istrue, label %ne_sgt_isfalse + +ne_sgt_istrue: + call void @is(i1 true) + ret void + +ne_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >=s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_sge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_sge(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %ne_sge_istrue, label %ne_sge_isfalse + +ne_sge_istrue: + call void @is(i1 true) + ret void + +ne_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A <s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_slt +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_slt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp slt i32 %a, %b + br i1 %cmp2, label %ne_slt_istrue, label %ne_slt_isfalse + +ne_slt_istrue: + call void @is(i1 true) + ret void + +ne_slt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A <=s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_sle +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_sle(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %ne_sle_istrue, label %ne_sle_isfalse + +ne_sle_istrue: + call void @is(i1 true) + ret void + +ne_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A >u B is true. +; CHECK-LABEL: @test_ugt_ugt +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ugt_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %ugt_ugt_istrue, label %ugt_ugt_isfalse + +ugt_ugt_istrue: + call void @is(i1 true) + ret void + +ugt_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A >=u B is true. +; CHECK-LABEL: @test_ugt_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ugt_uge(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %ugt_uge_istrue, label %ugt_uge_isfalse + +ugt_uge_istrue: + call void @is(i1 true) + ret void + +ugt_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A <u B is false. +; CHECK-LABEL: @test_ugt_ult +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ugt_ult(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %ugt_ult_istrue, label %ugt_ult_isfalse + +ugt_ult_istrue: + call void @is(i1 true) + ret void + +ugt_ult_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A <=u B is false. +; CHECK-LABEL: @test_ugt_ule +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ugt_ule(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %ugt_ule_istrue, label %ugt_ule_isfalse + +ugt_ule_istrue: + call void @is(i1 true) + ret void + +ugt_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u B implies A >=u B is true. +; CHECK-LABEL: @test_uge_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_uge_uge(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %uge_uge_istrue, label %uge_uge_isfalse + +uge_uge_istrue: + call void @is(i1 true) + ret void + +uge_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u B implies A <u B is false. +; CHECK-LABEL: @test_uge_ult +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_uge_ult(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %uge_ult_istrue, label %uge_ult_isfalse + +uge_ult_istrue: + call void @is(i1 true) + ret void + +uge_ult_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u B implies A <=u B is unknown to be true or false. +; CHECK-LABEL: @test_uge_ule +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_uge_ule(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %uge_ule_istrue, label %uge_ule_isfalse + +uge_ule_istrue: + call void @is(i1 true) + ret void + +uge_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <u B implies A <u B is true. +; CHECK-LABEL: @test_ult_ult +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ult_ult(i32 %a, i32 %b) { + %cmp1 = icmp ult i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, %b + br i1 %cmp2, label %ult_ult_istrue, label %ult_ult_isfalse + +ult_ult_istrue: + call void @is(i1 true) + ret void + +ult_ult_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <u B implies A <=u B is true. +; CHECK-LABEL: @test_ult_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ult_ule(i32 %a, i32 %b) { + %cmp1 = icmp ult i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %ult_ule_istrue, label %ult_ule_isfalse + +ult_ule_istrue: + call void @is(i1 true) + ret void + +ult_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <=u B implies A <=u B is true. +; CHECK-LABEL: @test_ule_ule +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ule_ule(i32 %a, i32 %b) { + %cmp1 = icmp ule i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %ule_ule_istrue, label %ule_ule_isfalse + +ule_ule_istrue: + call void @is(i1 true) + ret void + +ule_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A >s B is true. +; CHECK-LABEL: @test_sgt_sgt +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sgt_sgt(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %sgt_sgt_istrue, label %sgt_sgt_isfalse + +sgt_sgt_istrue: + call void @is(i1 true) + ret void + +sgt_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A >=s B is true. +; CHECK-LABEL: @test_sgt_sge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sgt_sge(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %sgt_sge_istrue, label %sgt_sge_isfalse + +sgt_sge_istrue: + call void @is(i1 true) + ret void + +sgt_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A <s B is false. +; CHECK-LABEL: @test_sgt_slt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sgt_slt(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp slt i32 %a, %b + br i1 %cmp2, label %sgt_slt_istrue, label %sgt_slt_isfalse + +sgt_slt_istrue: + call void @is(i1 true) + ret void + +sgt_slt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A <=s B is false. +; CHECK-LABEL: @test_sgt_sle +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sgt_sle(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %sgt_sle_istrue, label %sgt_sle_isfalse + +sgt_sle_istrue: + call void @is(i1 true) + ret void + +sgt_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=s B implies A >=s B is true. +; CHECK-LABEL: @test_sge_sge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sge_sge(i32 %a, i32 %b) { + %cmp1 = icmp sge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %sge_sge_istrue, label %sge_sge_isfalse + +sge_sge_istrue: + call void @is(i1 true) + ret void + +sge_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=s B implies A <s B is false. +; CHECK-LABEL: @test_sge_slt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sge_slt(i32 %a, i32 %b) { + %cmp1 = icmp sge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp slt i32 %a, %b + br i1 %cmp2, label %sge_slt_istrue, label %sge_slt_isfalse + +sge_slt_istrue: + call void @is(i1 true) + ret void + +sge_slt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=s B implies A <=s B is unknown to be true or false. +; CHECK-LABEL: @test_sge_sle +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sge_sle(i32 %a, i32 %b) { + %cmp1 = icmp sge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %sge_sle_istrue, label %sge_sle_isfalse + +sge_sle_istrue: + call void @is(i1 true) + ret void + +sge_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <s B implies A <s B is true. +; CHECK-LABEL: @test_slt_slt +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_slt_slt(i32 %a, i32 %b) { + %cmp1 = icmp slt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp slt i32 %a, %b + br i1 %cmp2, label %slt_slt_istrue, label %slt_slt_isfalse + +slt_slt_istrue: + call void @is(i1 true) + ret void + +slt_slt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <s B implies A <=s B is true. +; CHECK-LABEL: @test_slt_sle +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_slt_sle(i32 %a, i32 %b) { + %cmp1 = icmp slt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %slt_sle_istrue, label %slt_sle_isfalse + +slt_sle_istrue: + call void @is(i1 true) + ret void + +slt_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A <=s B implies A <=s B is true. +; CHECK-LABEL: @test_sle_sle +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sle_sle(i32 %a, i32 %b) { + %cmp1 = icmp sle i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %sle_sle_istrue, label %sle_sle_isfalse + +sle_sle_istrue: + call void @is(i1 true) + ret void + +sle_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u 5 implies A <u 5 is false. +; CHECK-LABEL: @test_uge_ult_const +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_uge_ult_const(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, 5 + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ult i32 %a, 5 + br i1 %cmp2, label %istrue, label %isfalse + +istrue: + call void @is(i1 true) + ret void + +isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} diff --git a/test/Transforms/SimplifyCFG/merge-cleanuppads.ll b/test/Transforms/SimplifyCFG/merge-cleanuppads.ll new file mode 100644 index 000000000000..23bbbca72346 --- /dev/null +++ b/test/Transforms/SimplifyCFG/merge-cleanuppads.ll @@ -0,0 +1,39 @@ +; RUN: opt -S -simplifycfg < %s | FileCheck %s +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc18.0.0" + +; Function Attrs: uwtable +define void @test1() #0 personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @may_throw(i32 3) + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + tail call void @may_throw(i32 2) #2 + tail call void @may_throw(i32 1) #2 + ret void + +ehcleanup: ; preds = %entry + %cp = cleanuppad within none [] + tail call void @may_throw(i32 2) #2 [ "funclet"(token %cp) ] + cleanupret from %cp unwind label %ehcleanup2 + +ehcleanup2: + %cp2 = cleanuppad within none [] + tail call void @may_throw(i32 1) #2 [ "funclet"(token %cp2) ] + cleanupret from %cp2 unwind to caller +} + +; CHECK-LABEL: define void @test1( +; CHECK: %[[cp:.*]] = cleanuppad within none [] +; CHECK: tail call void @may_throw(i32 2) #2 [ "funclet"(token %[[cp]]) ] +; CHECK: tail call void @may_throw(i32 1) #2 [ "funclet"(token %[[cp]]) ] +; CHECK: cleanupret from %[[cp]] unwind to caller + +declare void @may_throw(i32) #1 + +declare i32 @__CxxFrameHandler3(...) + +attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } diff --git a/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll b/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll index fe498b5334e8..3d69d25f6c6d 100644 --- a/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll +++ b/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll @@ -27,10 +27,10 @@ target triple = "armv7--linux-gnueabihf" ; CHECK: select ; CHECK-NOT: select ; CHECK: br i1 {{.*}}, label %[[L:.*]], label %[[R:.*]] -; CHECK: [[L]] ; preds = +; CHECK: [[L]]: ; preds = ; CHECK-NEXT: store ; CHECK-NEXT: br label %[[R]] -; CHECK: [[R]] ; preds = +; CHECK: [[R]]: ; preds = ; CHECK-NEXT: ret i32 0 define i32 @f(i32* %b) { diff --git a/test/Transforms/SimplifyCFG/preserve-branchweights.ll b/test/Transforms/SimplifyCFG/preserve-branchweights.ll index ae1794b1c61a..dba5dcf68b0c 100644 --- a/test/Transforms/SimplifyCFG/preserve-branchweights.ll +++ b/test/Transforms/SimplifyCFG/preserve-branchweights.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -simplifycfg -S -o - < %s | FileCheck %s declare void @helper(i32) @@ -21,11 +22,33 @@ Z: ret void } +; Make sure the metadata name string is "branch_weights" before propagating it. + +define void @fake_weights(i1 %a, i1 %b) { +; CHECK-LABEL: @fake_weights( +entry: + br i1 %a, label %Y, label %X, !prof !12 +; CHECK: %or.cond = and i1 %a.not, %c +; CHECK-NEXT: br i1 %or.cond, label %Z, label %Y, !prof !1 +; CHECK: Y: +X: + %c = or i1 %b, false + br i1 %c, label %Z, label %Y, !prof !1 + +Y: + call void @helper(i32 0) + ret void + +Z: + call void @helper(i32 1) + ret void +} + define void @test2(i1 %a, i1 %b) { ; CHECK-LABEL: @test2( entry: br i1 %a, label %X, label %Y, !prof !1 -; CHECK: br i1 %or.cond, label %Z, label %Y, !prof !1 +; CHECK: br i1 %or.cond, label %Z, label %Y, !prof !2 ; CHECK-NOT: !prof X: @@ -43,7 +66,7 @@ Z: define void @test3(i1 %a, i1 %b) { ; CHECK-LABEL: @test3( -; CHECK-NOT: !prof +; CHECK: br i1 %or.cond, label %Z, label %Y, !prof !1 entry: br i1 %a, label %X, label %Y, !prof !1 @@ -62,7 +85,7 @@ Z: define void @test4(i1 %a, i1 %b) { ; CHECK-LABEL: @test4( -; CHECK-NOT: !prof +; CHECK: br i1 %or.cond, label %Z, label %Y, !prof !1 entry: br i1 %a, label %X, label %Y @@ -91,7 +114,7 @@ entry: ; CHECK: switch i32 %N, label %sw2 [ ; CHECK: i32 3, label %sw.bb1 ; CHECK: i32 2, label %sw.bb -; CHECK: ], !prof !2 +; CHECK: ], !prof !3 sw.bb: call void @helper(i32 0) @@ -124,7 +147,7 @@ entry: ; CHECK: i32 3, label %sw.bb1 ; CHECK: i32 2, label %sw.bb ; CHECK: i32 4, label %sw.bb5 -; CHECK: ], !prof !3 +; CHECK: ], !prof !4 sw.bb: call void @helper(i32 0) @@ -159,7 +182,7 @@ define void @test1_swap(i1 %a, i1 %b) { ; CHECK-LABEL: @test1_swap( entry: br i1 %a, label %Y, label %X, !prof !0 -; CHECK: br i1 %or.cond, label %Y, label %Z, !prof !4 +; CHECK: br i1 %or.cond, label %Y, label %Z, !prof !5 X: %c = or i1 %b, false @@ -179,7 +202,7 @@ define void @test7(i1 %a, i1 %b) { entry: %c = or i1 %b, false br i1 %a, label %Y, label %X, !prof !0 -; CHECK: br i1 %brmerge, label %Y, label %Z, !prof !5 +; CHECK: br i1 %brmerge, label %Y, label %Z, !prof !6 X: br i1 %c, label %Y, label %Z, !prof !6 @@ -198,7 +221,7 @@ define void @test8(i64 %x, i64 %y) nounwind { ; CHECK-LABEL: @test8( entry: %lt = icmp slt i64 %x, %y -; CHECK: br i1 %lt, label %a, label %b, !prof !6 +; CHECK: br i1 %lt, label %a, label %b, !prof !7 %qux = select i1 %lt, i32 0, i32 2 switch i32 %qux, label %bees [ i32 0, label %a @@ -231,7 +254,7 @@ entry: ; CHECK: i32 1, label %end ; CHECK: i32 2, label %end ; CHECK: i32 92, label %end -; CHECK: ], !prof !7 +; CHECK: ], !prof !8 a: call void @helper(i32 0) nounwind @@ -269,7 +292,7 @@ lor.end: ; CHECK-LABEL: @test10( ; CHECK: %x.off = add i32 %x, -1 ; CHECK: %switch = icmp ult i32 %x.off, 3 -; CHECK: br i1 %switch, label %lor.end, label %lor.rhs, !prof !8 +; CHECK: br i1 %switch, label %lor.end, label %lor.rhs, !prof !9 } ; Remove dead cases from the switch. @@ -281,7 +304,7 @@ define void @test11(i32 %x) nounwind { ], !prof !8 ; CHECK-LABEL: @test11( ; CHECK: %cond = icmp eq i32 %i, 24 -; CHECK: br i1 %cond, label %c, label %a, !prof !9 +; CHECK: br i1 %cond, label %c, label %a, !prof !10 a: call void @helper(i32 0) nounwind @@ -344,7 +367,7 @@ c: @max_regno = common global i32 0, align 4 define void @test14(i32* %old, i32 %final) { ; CHECK-LABEL: @test14 -; CHECK: br i1 %or.cond, label %for.exit, label %for.inc, !prof !10 +; CHECK: br i1 %or.cond, label %for.exit, label %for.inc, !prof !11 for.cond: br label %for.cond2 for.cond2: @@ -364,6 +387,107 @@ for.exit: ret void } +; Don't drop the metadata. + +define i32 @HoistThenElseCodeToIf(i32 %n) { +; CHECK-LABEL: @HoistThenElseCodeToIf( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 %n, 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 + br i1 %tobool, label %if, label %else, !prof !0 + +if: + br label %return + +else: + br label %return + +return: + %retval.0 = phi i32 [ 1, %if ], [ 234, %else ] + ret i32 %retval.0 +} + +; The selects should have freshly calculated branch weights. + +define i32 @SimplifyCondBranchToCondBranch(i1 %cmpa, i1 %cmpb) { +; CHECK-LABEL: @SimplifyCondBranchToCondBranch( +; CHECK-NEXT: block1: +; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 %cmpa, %cmpb +; CHECK-NEXT: [[DOTMUX:%.*]] = select i1 %cmpa, i32 0, i32 2, !prof !13 +; CHECK-NEXT: [[OUTVAL:%.*]] = select i1 [[BRMERGE]], i32 [[DOTMUX]], i32 1, !prof !14 +; CHECK-NEXT: ret i32 [[OUTVAL]] +; +block1: + br i1 %cmpa, label %block3, label %block2, !prof !13 + +block2: + br i1 %cmpb, label %block3, label %exit, !prof !14 + +block3: + %cowval = phi i32 [ 2, %block2 ], [ 0, %block1 ] + br label %exit + +exit: + %outval = phi i32 [ %cowval, %block3 ], [ 1, %block2 ] + ret i32 %outval +} + +; Swap the operands of the compares to verify that the weights update correctly. + +define i32 @SimplifyCondBranchToCondBranchSwap(i1 %cmpa, i1 %cmpb) { +; CHECK-LABEL: @SimplifyCondBranchToCondBranchSwap( +; CHECK-NEXT: block1: +; CHECK-NEXT: [[CMPA_NOT:%.*]] = xor i1 %cmpa, true +; CHECK-NEXT: [[CMPB_NOT:%.*]] = xor i1 %cmpb, true +; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[CMPA_NOT]], [[CMPB_NOT]] +; CHECK-NEXT: [[DOTMUX:%.*]] = select i1 [[CMPA_NOT]], i32 0, i32 2, !prof !15 +; CHECK-NEXT: [[OUTVAL:%.*]] = select i1 [[BRMERGE]], i32 [[DOTMUX]], i32 1, !prof !16 +; CHECK-NEXT: ret i32 [[OUTVAL]] +; +block1: + br i1 %cmpa, label %block2, label %block3, !prof !13 + +block2: + br i1 %cmpb, label %exit, label %block3, !prof !14 + +block3: + %cowval = phi i32 [ 2, %block2 ], [ 0, %block1 ] + br label %exit + +exit: + %outval = phi i32 [ %cowval, %block3 ], [ 1, %block2 ] + ret i32 %outval +} + +define i32 @SimplifyCondBranchToCondBranchSwapMissingWeight(i1 %cmpa, i1 %cmpb) { +; CHECK-LABEL: @SimplifyCondBranchToCondBranchSwapMissingWeight( +; CHECK-NEXT: block1: +; CHECK-NEXT: [[CMPA_NOT:%.*]] = xor i1 %cmpa, true +; CHECK-NEXT: [[CMPB_NOT:%.*]] = xor i1 %cmpb, true +; CHECK-NEXT: [[BRMERGE:%.*]] = or i1 [[CMPA_NOT]], [[CMPB_NOT]] +; CHECK-NEXT: [[DOTMUX:%.*]] = select i1 [[CMPA_NOT]], i32 0, i32 2, !prof !17 +; CHECK-NEXT: [[OUTVAL:%.*]] = select i1 [[BRMERGE]], i32 [[DOTMUX]], i32 1, !prof !18 +; CHECK-NEXT: ret i32 [[OUTVAL]] +; +block1: + br i1 %cmpa, label %block2, label %block3, !prof !13 + +block2: + br i1 %cmpb, label %exit, label %block3 + +block3: + %cowval = phi i32 [ 2, %block2 ], [ 0, %block1 ] + br label %exit + +exit: + %outval = phi i32 [ %cowval, %block3 ], [ 1, %block2 ] + ret i32 %outval +} + !0 = !{!"branch_weights", i32 3, i32 5} !1 = !{!"branch_weights", i32 1, i32 1} !2 = !{!"branch_weights", i32 1, i32 2} @@ -376,17 +500,28 @@ for.exit: !9 = !{!"branch_weights", i32 7, i32 6} !10 = !{!"branch_weights", i32 672646, i32 21604207} !11 = !{!"branch_weights", i32 6960, i32 21597248} +!12 = !{!"these_are_not_the_branch_weights_you_are_looking_for", i32 3, i32 5} +!13 = !{!"branch_weights", i32 2, i32 3} +!14 = !{!"branch_weights", i32 4, i32 7} ; CHECK: !0 = !{!"branch_weights", i32 5, i32 11} -; CHECK: !1 = !{!"branch_weights", i32 1, i32 5} -; CHECK: !2 = !{!"branch_weights", i32 7, i32 1, i32 2} -; CHECK: !3 = !{!"branch_weights", i32 49, i32 12, i32 24, i32 35} -; CHECK: !4 = !{!"branch_weights", i32 11, i32 5} -; CHECK: !5 = !{!"branch_weights", i32 17, i32 15} -; CHECK: !6 = !{!"branch_weights", i32 9, i32 7} -; CHECK: !7 = !{!"branch_weights", i32 17, i32 9, i32 8, i32 7, i32 17} -; CHECK: !8 = !{!"branch_weights", i32 24, i32 33} -; CHECK: !9 = !{!"branch_weights", i32 8, i32 33} +; CHECK: !1 = !{!"branch_weights", i32 1, i32 3} +; CHECK: !2 = !{!"branch_weights", i32 1, i32 5} +; CHECK: !3 = !{!"branch_weights", i32 7, i32 1, i32 2} +; CHECK: !4 = !{!"branch_weights", i32 49, i32 12, i32 24, i32 35} +; CHECK: !5 = !{!"branch_weights", i32 11, i32 5} +; CHECK: !6 = !{!"branch_weights", i32 17, i32 15} +; CHECK: !7 = !{!"branch_weights", i32 9, i32 7} +; CHECK: !8 = !{!"branch_weights", i32 17, i32 9, i32 8, i32 7, i32 17} +; CHECK: !9 = !{!"branch_weights", i32 24, i32 33} +; CHECK: !10 = !{!"branch_weights", i32 8, i32 33} ;; The false weight prints out as a negative integer here, but inside llvm, we ;; treat the weight as an unsigned integer. -; CHECK: !10 = !{!"branch_weights", i32 112017436, i32 -735157296} +; CHECK: !11 = !{!"branch_weights", i32 112017436, i32 -735157296} +; CHECK: !12 = !{!"branch_weights", i32 3, i32 5} +; CHECK: !13 = !{!"branch_weights", i32 22, i32 12} +; CHECK: !14 = !{!"branch_weights", i32 34, i32 21} +; CHECK: !15 = !{!"branch_weights", i32 33, i32 14} +; CHECK: !16 = !{!"branch_weights", i32 47, i32 8} +; CHECK: !17 = !{!"branch_weights", i32 6, i32 2} +; CHECK: !18 = !{!"branch_weights", i32 8, i32 2} diff --git a/test/Transforms/SimplifyCFG/speculate-store.ll b/test/Transforms/SimplifyCFG/speculate-store.ll index c1ac7bcea249..497e024e2489 100644 --- a/test/Transforms/SimplifyCFG/speculate-store.ll +++ b/test/Transforms/SimplifyCFG/speculate-store.ll @@ -1,108 +1,90 @@ ; RUN: opt -simplifycfg -S < %s | FileCheck %s -define void @ifconvertstore(i32 %m, i32* %A, i32* %B, i32 %C, i32 %D) { +define void @ifconvertstore(i32* %A, i32 %B, i32 %C, i32 %D) { +; CHECK-LABEL: @ifconvertstore( +; CHECK: store i32 %B, i32* %A +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 %D, 42 +; CHECK-NEXT: [[C_B:%.*]] = select i1 [[CMP]], i32 %C, i32 %B, !prof !0 +; CHECK-NEXT: store i32 [[C_B]], i32* %A +; CHECK-NEXT: ret void +; entry: - %arrayidx = getelementptr inbounds i32, i32* %B, i64 0 - %0 = load i32, i32* %arrayidx, align 4 - %add = add nsw i32 %0, %C - %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 0 - ; First store to the location. - store i32 %add, i32* %arrayidx2, align 4 - %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 1 - %1 = load i32, i32* %arrayidx4, align 4 - %add5 = add nsw i32 %1, %D - %cmp6 = icmp sgt i32 %add5, %C - br i1 %cmp6, label %if.then, label %ret.end + store i32 %B, i32* %A + %cmp = icmp sgt i32 %D, 42 + br i1 %cmp, label %if.then, label %ret.end, !prof !0 ; Make sure we speculate stores like the following one. It is cheap compared to ; a mispredicated branch. -; CHECK-LABEL: @ifconvertstore( -; CHECK: %add5.add = select i1 %cmp6, i32 %add5, i32 %add -; CHECK: store i32 %add5.add, i32* %arrayidx2, align 4 if.then: - store i32 %add5, i32* %arrayidx2, align 4 + store i32 %C, i32* %A br label %ret.end ret.end: ret void } -define void @noifconvertstore1(i32 %m, i32* %A, i32* %B, i32 %C, i32 %D) { -entry: - %arrayidx = getelementptr inbounds i32, i32* %B, i64 0 - %0 = load i32, i32* %arrayidx, align 4 - %add = add nsw i32 %0, %C - %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 0 - ; Store to a different location. - store i32 %add, i32* %arrayidx, align 4 - %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 1 - %1 = load i32, i32* %arrayidx4, align 4 - %add5 = add nsw i32 %1, %D - %cmp6 = icmp sgt i32 %add5, %C - br i1 %cmp6, label %if.then, label %ret.end +define void @noifconvertstore1(i32* %A1, i32* %A2, i32 %B, i32 %C, i32 %D) { ; CHECK-LABEL: @noifconvertstore1( ; CHECK-NOT: select +; +entry: + store i32 %B, i32* %A1 + %cmp = icmp sgt i32 %D, 42 + br i1 %cmp, label %if.then, label %ret.end + if.then: - store i32 %add5, i32* %arrayidx2, align 4 + store i32 %C, i32* %A2 br label %ret.end ret.end: ret void } +; This function could store to our address, so we can't repeat the first store a second time. declare void @unknown_fun() -define void @noifconvertstore2(i32 %m, i32* %A, i32* %B, i32 %C, i32 %D) { +define void @noifconvertstore2(i32* %A, i32 %B, i32 %C, i32 %D) { +; CHECK-LABEL: @noifconvertstore2( +; CHECK-NOT: select +; entry: - %arrayidx = getelementptr inbounds i32, i32* %B, i64 0 - %0 = load i32, i32* %arrayidx, align 4 - %add = add nsw i32 %0, %C - %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 0 - ; First store to the location. - store i32 %add, i32* %arrayidx2, align 4 + store i32 %B, i32* %A call void @unknown_fun() - %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 1 - %1 = load i32, i32* %arrayidx4, align 4 - %add5 = add nsw i32 %1, %D - %cmp6 = icmp sgt i32 %add5, %C + %cmp6 = icmp sgt i32 %D, 42 br i1 %cmp6, label %if.then, label %ret.end -; CHECK-LABEL: @noifconvertstore2( -; CHECK-NOT: select if.then: - store i32 %add5, i32* %arrayidx2, align 4 + store i32 %C, i32* %A br label %ret.end ret.end: ret void } -define void @noifconvertstore_volatile(i32 %m, i32* %A, i32* %B, i32 %C, i32 %D) { -entry: - %arrayidx = getelementptr inbounds i32, i32* %B, i64 0 - %0 = load i32, i32* %arrayidx, align 4 - %add = add nsw i32 %0, %C - %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 0 +; Make sure we don't speculate volatile stores. +define void @noifconvertstore_volatile(i32* %A, i32 %B, i32 %C, i32 %D) { +; CHECK-LABEL: @noifconvertstore_volatile( +; CHECK-NOT: select +; +entry: ; First store to the location. - store i32 %add, i32* %arrayidx2, align 4 - %arrayidx4 = getelementptr inbounds i32, i32* %B, i64 1 - %1 = load i32, i32* %arrayidx4, align 4 - %add5 = add nsw i32 %1, %D - %cmp6 = icmp sgt i32 %add5, %C + store i32 %B, i32* %A + %cmp6 = icmp sgt i32 %D, 42 br i1 %cmp6, label %if.then, label %ret.end -; Make sure we don't speculate volatile stores. -; CHECK-LABEL: @noifconvertstore_volatile( -; CHECK-NOT: select if.then: - store volatile i32 %add5, i32* %arrayidx2, align 4 + store volatile i32 %C, i32* %A br label %ret.end ret.end: ret void } + +; CHECK: !0 = !{!"branch_weights", i32 3, i32 5} +!0 = !{!"branch_weights", i32 3, i32 5} + diff --git a/test/Transforms/SimplifyCFG/switch-masked-bits.ll b/test/Transforms/SimplifyCFG/switch-masked-bits.ll index 692973c362bf..2d46aac23f61 100644 --- a/test/Transforms/SimplifyCFG/switch-masked-bits.ll +++ b/test/Transforms/SimplifyCFG/switch-masked-bits.ll @@ -1,10 +1,18 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -simplifycfg < %s | FileCheck %s define i32 @test1(i32 %x) nounwind { +; CHECK-LABEL: @test1( +; CHECK-NEXT: a: +; CHECK-NEXT: [[I:%.*]] = shl i32 %x, 1 +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 24 +; CHECK-NEXT: [[DOT:%.*]] = select i1 [[COND]], i32 5, i32 0 +; CHECK-NEXT: ret i32 [[DOT]] +; %i = shl i32 %x, 1 switch i32 %i, label %a [ - i32 21, label %b - i32 24, label %c + i32 21, label %b + i32 24, label %c ] a: @@ -13,18 +21,18 @@ b: ret i32 3 c: ret i32 5 -; CHECK-LABEL: @test1( -; CHECK: %cond = icmp eq i32 %i, 24 -; CHECK: %. = select i1 %cond, i32 5, i32 0 -; CHECK: ret i32 %. } define i32 @test2(i32 %x) nounwind { +; CHECK-LABEL: @test2( +; CHECK-NEXT: a: +; CHECK-NEXT: ret i32 0 +; %i = shl i32 %x, 1 switch i32 %i, label %a [ - i32 21, label %b - i32 23, label %c + i32 21, label %b + i32 23, label %c ] a: @@ -33,6 +41,37 @@ b: ret i32 3 c: ret i32 5 -; CHECK-LABEL: @test2( -; CHECK: ret i32 0 } + +; We're sign extending an 8-bit value. +; The switch condition must be in the range [-128, 127], so any cases outside of that range must be dead. + +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: + %sext = sext i8 %condition to i32 + switch i32 %sext, label %default [ + i32 -2147483648, label %a + i32 -129, label %a + i32 -128, label %a + i32 -1, label %a + i32 0, label %a + i32 127, label %a + i32 128, label %a + i32 2147483647, label %a + ] + +a: + ret i1 1 + +default: + ret i1 0 +} + diff --git a/test/Transforms/SimplifyCFG/switch_create.ll b/test/Transforms/SimplifyCFG/switch_create.ll index 490b7513a944..29d3a34a05e6 100644 --- a/test/Transforms/SimplifyCFG/switch_create.ll +++ b/test/Transforms/SimplifyCFG/switch_create.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -simplifycfg < %s | FileCheck -check-prefix=CHECK %s +; RUN: opt -S -simplifycfg < %s | FileCheck %s ; RUN: opt -S -default-data-layout="p:32:32-p1:16:16" -simplifycfg < %s | FileCheck -check-prefix=CHECK -check-prefix=DL %s declare void @foo1() @@ -554,3 +554,107 @@ bb20: ; preds = %bb19, %bb8 ; CHECK: %arg.off = add i32 %arg, -8 ; CHECK: icmp ult i32 %arg.off, 11 } + +define void @PR26323(i1 %tobool23, i32 %tmp3) { +entry: + %tobool5 = icmp ne i32 %tmp3, 0 + %neg14 = and i32 %tmp3, -2 + %cmp17 = icmp ne i32 %neg14, -1 + %or.cond = and i1 %tobool5, %tobool23 + %or.cond1 = and i1 %cmp17, %or.cond + br i1 %or.cond1, label %if.end29, label %if.then27 + +if.then27: ; preds = %entry + call void @foo1() + unreachable + +if.end29: ; preds = %entry + ret void +} + +; CHECK-LABEL: define void @PR26323( +; CHECK: %tobool5 = icmp ne i32 %tmp3, 0 +; CHECK: %neg14 = and i32 %tmp3, -2 +; CHECK: %cmp17 = icmp ne i32 %neg14, -1 +; CHECK: %or.cond = and i1 %tobool5, %tobool23 +; CHECK: %or.cond1 = and i1 %cmp17, %or.cond +; CHECK: br i1 %or.cond1, label %if.end29, label %if.then27 + +; Form a switch when and'ing a negated power of two +; CHECK-LABEL: define void @test19 +; CHECK: switch i32 %arg, label %else [ +; CHECK: i32 32, label %if +; CHECK: i32 13, label %if +; CHECK: i32 12, label %if +define void @test19(i32 %arg) { + %and = and i32 %arg, -2 + %cmp1 = icmp eq i32 %and, 12 + %cmp2 = icmp eq i32 %arg, 32 + %pred = or i1 %cmp1, %cmp2 + br i1 %pred, label %if, label %else + +if: + call void @foo1() + ret void + +else: + ret void +} + +; Since %cmp1 is always false, a switch is never formed +; CHECK-LABEL: define void @test20 +; CHECK-NOT: switch +; CHECK: ret void +define void @test20(i32 %arg) { + %and = and i32 %arg, -2 + %cmp1 = icmp eq i32 %and, 13 + %cmp2 = icmp eq i32 %arg, 32 + %pred = or i1 %cmp1, %cmp2 + br i1 %pred, label %if, label %else + +if: + call void @foo1() + ret void + +else: + ret void +} + +; Form a switch when or'ing a power of two +; CHECK-LABEL: define void @test21 +; CHECK: i32 32, label %else +; CHECK: i32 13, label %else +; CHECK: i32 12, label %else +define void @test21(i32 %arg) { + %and = or i32 %arg, 1 + %cmp1 = icmp ne i32 %and, 13 + %cmp2 = icmp ne i32 %arg, 32 + %pred = and i1 %cmp1, %cmp2 + br i1 %pred, label %if, label %else + +if: + call void @foo1() + ret void + +else: + ret void +} + +; Since %cmp1 is always false, a switch is never formed +; CHECK-LABEL: define void @test22 +; CHECK-NOT: switch +; CHECK: ret void +define void @test22(i32 %arg) { + %and = or i32 %arg, 1 + %cmp1 = icmp ne i32 %and, 12 + %cmp2 = icmp ne i32 %arg, 32 + %pred = and i1 %cmp1, %cmp2 + br i1 %pred, label %if, label %else + +if: + call void @foo1() + ret void + +else: + ret void +}
\ No newline at end of file diff --git a/test/Transforms/SimplifyCFG/switch_switch_fold.ll b/test/Transforms/SimplifyCFG/switch_switch_fold.ll index 2e2e31014017..7f6f1c94bd4a 100644 --- a/test/Transforms/SimplifyCFG/switch_switch_fold.ll +++ b/test/Transforms/SimplifyCFG/switch_switch_fold.ll @@ -1,8 +1,7 @@ -; RUN: opt < %s -simplifycfg -S | \ -; RUN: grep switch | count 1 +; RUN: opt < %s -simplifycfg -S | FileCheck %s -; Test that a switch going to a switch on the same value can be merged. All -; three switches in this example can be merged into one big one. +; Test that a switch going to a switch on the same value can be merged. +; All three switches in this example can be merged into one big one. declare void @foo1() @@ -43,5 +42,24 @@ F: ; preds = %F, %T, %0, %0 D: ; preds = %F call void @foo4( ) ret void + +; CHECK-LABEL: @test1( +; CHECK-NEXT: switch i32 %V, label %infloop [ +; CHECK-NEXT: i32 4, label %A +; CHECK-NEXT: i32 17, label %B +; CHECK-NEXT: i32 18, label %B +; CHECK-NEXT: i32 42, label %D +; CHECK-NEXT: ] +; CHECK: A: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: ret void +; CHECK: B: +; CHECK-NEXT: call void @foo2() +; CHECK-NEXT: ret void +; CHECK: D: +; CHECK-NEXT: call void @foo4() +; CHECK-NEXT: ret void +; CHECK: infloop: +; CHECK-NEXT: br label %infloop } diff --git a/test/Transforms/SimplifyCFG/switch_thread.ll b/test/Transforms/SimplifyCFG/switch_thread.ll index 93966841a425..32e0325df7f2 100644 --- a/test/Transforms/SimplifyCFG/switch_thread.ll +++ b/test/Transforms/SimplifyCFG/switch_thread.ll @@ -1,5 +1,4 @@ -; RUN: opt < %s -simplifycfg -S | \ -; RUN: not grep "call void @DEAD" +; RUN: opt < %s -simplifycfg -S | FileCheck %s ; Test that we can thread a simple known condition through switch statements. @@ -45,6 +44,21 @@ B: ; preds = %T C: ; preds = %B, %A, %A2, %T, %T call void @DEAD( ) ret void + +; CHECK-LABEL: @test1( +; CHECK-NEXT: switch i32 %V, label %A [ +; CHECK-NEXT: i32 4, label %T +; CHECK-NEXT: i32 17, label %Done +; CHECK-NEXT: ] +; CHECK: T: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: call void @foo2() +; CHECK-NEXT: br label %Done +; CHECK: A: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: br label %Done +; CHECK: Done: +; CHECK-NEXT: ret void } define void @test2(i32 %V) { @@ -75,5 +89,25 @@ D: ; preds = %A, %0 ret void E: ; preds = %A, %0 ret void + +; CHECK-LABEL: @test2( +; CHECK-NEXT: switch i32 %V, label %A [ +; CHECK-NEXT: i32 4, label %T +; CHECK-NEXT: i32 17, label %D +; CHECK-NEXT: i32 1234, label %E +; CHECK-NEXT: ] +; CHECK: A: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 %V, 42 +; CHECK-NEXT: br i1 [[COND]], label %D, label %E +; CHECK: T: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: ret void +; CHECK: D: +; CHECK-NEXT: call void @foo1() +; CHECK-NEXT: ret void +; CHECK: E: +; CHECK-NEXT: ret void } diff --git a/test/Transforms/SimplifyCFG/trap-debugloc.ll b/test/Transforms/SimplifyCFG/trap-debugloc.ll index 2887aaf52eee..a912dc561a4f 100644 --- a/test/Transforms/SimplifyCFG/trap-debugloc.ll +++ b/test/Transforms/SimplifyCFG/trap-debugloc.ll @@ -9,16 +9,14 @@ define void @foo() nounwind ssp !dbg !0 { !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!10} -!llvm.dbg.sp = !{!0} -!0 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, file: !8, scope: !1, type: !3) +!0 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2, file: !8, scope: !1, type: !3) !1 = !DIFile(filename: "foo.c", directory: "/private/tmp") -!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "Apple clang version 3.0 (tags/Apple/clang-206.1) (based on LLVM 3.0svn)", isOptimized: true, emissionKind: 0, file: !8, enums: !{}, retainedTypes: !{}, subprograms: !9) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "Apple clang version 3.0 (tags/Apple/clang-206.1) (based on LLVM 3.0svn)", isOptimized: true, emissionKind: FullDebug, file: !8, enums: !{}, retainedTypes: !{}) !3 = !DISubroutineType(types: !4) !4 = !{null} !5 = !DILocation(line: 4, column: 2, scope: !6) !6 = distinct !DILexicalBlock(line: 3, column: 12, file: !8, scope: !0) !7 = !DILocation(line: 5, column: 1, scope: !6) !8 = !DIFile(filename: "foo.c", directory: "/private/tmp") -!9 = !{!0} !10 = !{i32 1, !"Debug Info Version", i32 3} diff --git a/test/Transforms/SimplifyCFG/two-entry-phi-return.ll b/test/Transforms/SimplifyCFG/two-entry-phi-return.ll index fb18624c71f7..1e9aa6b48f6b 100644 --- a/test/Transforms/SimplifyCFG/two-entry-phi-return.ll +++ b/test/Transforms/SimplifyCFG/two-entry-phi-return.ll @@ -1,15 +1,26 @@ -; RUN: opt < %s -simplifycfg -S | not grep br +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -simplifycfg -S | FileCheck %s define i1 @qux(i8* %m, i8* %n, i8* %o, i8* %p) nounwind { +; CHECK-LABEL: @qux( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i8* %m, %n +; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i8* %o, %p +; CHECK-NEXT: [[TMP15_:%.*]] = select i1 [[TMP7]], i1 [[TMP15]], i1 false, !prof !0 +; CHECK-NEXT: ret i1 [[TMP15_]] +; entry: - %tmp7 = icmp eq i8* %m, %n - br i1 %tmp7, label %bb, label %UnifiedReturnBlock + %tmp7 = icmp eq i8* %m, %n + br i1 %tmp7, label %bb, label %UnifiedReturnBlock, !prof !0 bb: - %tmp15 = icmp eq i8* %o, %p - br label %UnifiedReturnBlock + %tmp15 = icmp eq i8* %o, %p + br label %UnifiedReturnBlock UnifiedReturnBlock: - %result = phi i1 [ 0, %entry ], [ %tmp15, %bb ] - ret i1 %result + %result = phi i1 [ 0, %entry ], [ %tmp15, %bb ] + ret i1 %result + } + +!0 = !{!"branch_weights", i32 4, i32 64} diff --git a/test/Transforms/SimplifyCFG/unreachable-cleanuppad.ll b/test/Transforms/SimplifyCFG/unreachable-cleanuppad.ll new file mode 100644 index 000000000000..9198b2a6ea4a --- /dev/null +++ b/test/Transforms/SimplifyCFG/unreachable-cleanuppad.ll @@ -0,0 +1,40 @@ +; RUN: opt -simplifycfg -S < %s | FileCheck %s +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-win32" + +declare i32 @__CxxFrameHandler3(...) + +declare void @fn_2() + +define void @fn_1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 { +entry: + br i1 %B, label %__Ea.exit, label %lor.lhs.false.i.i + +lor.lhs.false.i.i: + br i1 %B, label %if.end.i.i, label %__Ea.exit + +if.end.i.i: + invoke void @fn_2() + to label %__Ea.exit unwind label %ehcleanup.i + +ehcleanup.i: + %t4 = cleanuppad within none [] + br label %arraydestroy.body.i + +arraydestroy.body.i: + %gep = getelementptr i8, i8* null, i32 -1 + br label %dtor.exit.i + +dtor.exit.i: + br i1 %B, label %arraydestroy.done3.i, label %arraydestroy.body.i + +arraydestroy.done3.i: + cleanupret from %t4 unwind to caller + +__Ea.exit: + ret void +} + +; CHECK-LABEL: define void @fn_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret void |
