aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/SimplifyCFG
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/SimplifyCFG')
-rw-r--r--test/Transforms/SimplifyCFG/2003-08-17-FoldSwitch.ll139
-rw-r--r--test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll32
-rw-r--r--test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll47
-rw-r--r--test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll32
-rw-r--r--test/Transforms/SimplifyCFG/InfLoop.ll101
-rw-r--r--test/Transforms/SimplifyCFG/PR16069.ll13
-rw-r--r--test/Transforms/SimplifyCFG/PR27615-simplify-cond-br.ll68
-rw-r--r--test/Transforms/SimplifyCFG/PhiBlockMerge.ll29
-rw-r--r--test/Transforms/SimplifyCFG/PhiEliminate2.ll37
-rw-r--r--test/Transforms/SimplifyCFG/UnreachableEliminate.ll31
-rw-r--r--test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll4
-rw-r--r--test/Transforms/SimplifyCFG/attr-convergent.ll28
-rw-r--r--test/Transforms/SimplifyCFG/basictest.ll52
-rw-r--r--test/Transforms/SimplifyCFG/branch-fold-dbg.ll6
-rw-r--r--test/Transforms/SimplifyCFG/combine-parallel-mem-md.ll55
-rw-r--r--test/Transforms/SimplifyCFG/empty-cleanuppad.ll55
-rw-r--r--test/Transforms/SimplifyCFG/guards.ll86
-rw-r--r--test/Transforms/SimplifyCFG/hoist-dbgvalue.ll7
-rw-r--r--test/Transforms/SimplifyCFG/implied-cond-matching-false-dest.ll339
-rw-r--r--test/Transforms/SimplifyCFG/implied-cond-matching-imm.ll123
-rw-r--r--test/Transforms/SimplifyCFG/implied-cond-matching.ll1029
-rw-r--r--test/Transforms/SimplifyCFG/merge-cleanuppads.ll39
-rw-r--r--test/Transforms/SimplifyCFG/merge-cond-stores-2.ll4
-rw-r--r--test/Transforms/SimplifyCFG/preserve-branchweights.ll179
-rw-r--r--test/Transforms/SimplifyCFG/speculate-store.ll100
-rw-r--r--test/Transforms/SimplifyCFG/switch-masked-bits.ll59
-rw-r--r--test/Transforms/SimplifyCFG/switch_create.ll106
-rw-r--r--test/Transforms/SimplifyCFG/switch_switch_fold.ll26
-rw-r--r--test/Transforms/SimplifyCFG/switch_thread.ll38
-rw-r--r--test/Transforms/SimplifyCFG/trap-debugloc.ll6
-rw-r--r--test/Transforms/SimplifyCFG/two-entry-phi-return.ll25
-rw-r--r--test/Transforms/SimplifyCFG/unreachable-cleanuppad.ll40
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