summaryrefslogtreecommitdiff
path: root/test/Transforms/SimplifyCFG
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/SimplifyCFG')
-rw-r--r--test/Transforms/SimplifyCFG/AArch64/cttz-ctlz.ll43
-rw-r--r--test/Transforms/SimplifyCFG/ARM/cttz-ctlz.ll43
-rw-r--r--test/Transforms/SimplifyCFG/ARM/lit.local.cfg5
-rw-r--r--test/Transforms/SimplifyCFG/Mips/cttz-ctlz.ll43
-rw-r--r--test/Transforms/SimplifyCFG/Mips/lit.local.cfg5
-rw-r--r--test/Transforms/SimplifyCFG/PR25267.ll24
-rw-r--r--test/Transforms/SimplifyCFG/SpeculativeExec.ll26
-rw-r--r--test/Transforms/SimplifyCFG/X86/speculate-cttz-ctlz.ll24
-rw-r--r--test/Transforms/SimplifyCFG/basictest.ll14
-rw-r--r--test/Transforms/SimplifyCFG/branch-fold-dbg.ll8
-rw-r--r--test/Transforms/SimplifyCFG/empty-cleanuppad.ll415
-rw-r--r--test/Transforms/SimplifyCFG/hoist-dbgvalue.ll10
-rw-r--r--test/Transforms/SimplifyCFG/implied-cond.ll81
-rw-r--r--test/Transforms/SimplifyCFG/invoke_unwind.ll13
-rw-r--r--test/Transforms/SimplifyCFG/merge-cond-stores-2.ll215
-rw-r--r--test/Transforms/SimplifyCFG/merge-cond-stores.ll241
-rw-r--r--test/Transforms/SimplifyCFG/no_speculative_loads_with_asan.ll40
-rw-r--r--test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll32
-rw-r--r--test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll32
-rw-r--r--test/Transforms/SimplifyCFG/preserve-load-metadata.ll32
-rw-r--r--test/Transforms/SimplifyCFG/preserve-make-implicit-on-switch-to-br.ll30
-rw-r--r--test/Transforms/SimplifyCFG/speculate-math.ll45
-rw-r--r--test/Transforms/SimplifyCFG/statepoint-invoke-unwind.ll6
-rw-r--r--test/Transforms/SimplifyCFG/switch-dead-default.ll179
-rw-r--r--test/Transforms/SimplifyCFG/trap-debugloc.ll6
-rw-r--r--test/Transforms/SimplifyCFG/wineh-unreachable.ll83
26 files changed, 1647 insertions, 48 deletions
diff --git a/test/Transforms/SimplifyCFG/AArch64/cttz-ctlz.ll b/test/Transforms/SimplifyCFG/AArch64/cttz-ctlz.ll
new file mode 100644
index 000000000000..e32d711143dc
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/AArch64/cttz-ctlz.ll
@@ -0,0 +1,43 @@
+; RUN: opt -S -simplifycfg -mtriple=aarch64 < %s | FileCheck %s
+
+define i32 @ctlz(i32 %A) {
+; CHECK-LABEL: @ctlz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+define i32 @cttz(i32 %A) {
+; CHECK-LABEL: @cttz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i32 @llvm.cttz.i32(i32, i1)
+
diff --git a/test/Transforms/SimplifyCFG/ARM/cttz-ctlz.ll b/test/Transforms/SimplifyCFG/ARM/cttz-ctlz.ll
new file mode 100644
index 000000000000..ffcf2175091f
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/ARM/cttz-ctlz.ll
@@ -0,0 +1,43 @@
+; RUN: opt -S -simplifycfg -mtriple=arm -mattr=+v6t2 < %s | FileCheck %s
+
+define i32 @ctlz(i32 %A) {
+; CHECK-LABEL: @ctlz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+define i32 @cttz(i32 %A) {
+; CHECK-LABEL: @cttz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i32 @llvm.cttz.i32(i32, i1)
+
diff --git a/test/Transforms/SimplifyCFG/ARM/lit.local.cfg b/test/Transforms/SimplifyCFG/ARM/lit.local.cfg
new file mode 100644
index 000000000000..5a3b8565213d
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/ARM/lit.local.cfg
@@ -0,0 +1,5 @@
+config.suffixes = ['.ll']
+
+targets = set(config.root.targets_to_build.split())
+if not 'ARM' in targets:
+ config.unsupported = True
diff --git a/test/Transforms/SimplifyCFG/Mips/cttz-ctlz.ll b/test/Transforms/SimplifyCFG/Mips/cttz-ctlz.ll
new file mode 100644
index 000000000000..b4bfb51dd142
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/Mips/cttz-ctlz.ll
@@ -0,0 +1,43 @@
+; RUN: opt -S -simplifycfg -mtriple=mips-linux-gnu < %s | FileCheck %s
+
+define i32 @ctlz(i32 %A) {
+; CHECK-LABEL: @ctlz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+define i32 @cttz(i32 %A) {
+; CHECK-LABEL: @cttz(
+; CHECK: [[ICMP:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
+; CHECK-NEXT: [[CTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+; CHECK-NEXT: [[SEL:%[A-Za-z0-9.]+]] = select i1 [[ICMP]], i32 32, i32 [[CTZ]]
+; CHECK-NEXT: ret i32 [[SEL]]
+entry:
+ %tobool = icmp eq i32 %A, 0
+ br i1 %tobool, label %cond.end, label %cond.true
+
+cond.true:
+ %0 = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
+ br label %cond.end
+
+cond.end:
+ %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ]
+ ret i32 %cond
+}
+
+declare i32 @llvm.ctlz.i32(i32, i1)
+declare i32 @llvm.cttz.i32(i32, i1)
+
diff --git a/test/Transforms/SimplifyCFG/Mips/lit.local.cfg b/test/Transforms/SimplifyCFG/Mips/lit.local.cfg
new file mode 100644
index 000000000000..683bfdccb742
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/Mips/lit.local.cfg
@@ -0,0 +1,5 @@
+config.suffixes = ['.ll']
+
+targets = set(config.root.targets_to_build.split())
+if not 'Mips' in targets:
+ config.unsupported = True
diff --git a/test/Transforms/SimplifyCFG/PR25267.ll b/test/Transforms/SimplifyCFG/PR25267.ll
new file mode 100644
index 000000000000..a13d45a0f271
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/PR25267.ll
@@ -0,0 +1,24 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+define void @f() {
+entry:
+ br label %for.cond
+
+for.cond:
+ %phi = phi i1 [ false, %entry ], [ true, %for.body ]
+ %select = select i1 %phi, i32 1, i32 2
+ br label %for.body
+
+for.body:
+ switch i32 %select, label %for.cond [
+ i32 1, label %return
+ i32 2, label %for.body
+ ]
+
+return:
+ ret void
+}
+
+; CHECK-LABEL: define void @f(
+; CHECK: br label %[[LABEL:.*]]
+; CHECK: br label %[[LABEL]]
diff --git a/test/Transforms/SimplifyCFG/SpeculativeExec.ll b/test/Transforms/SimplifyCFG/SpeculativeExec.ll
index c23a96df52ee..73f9a0f88aca 100644
--- a/test/Transforms/SimplifyCFG/SpeculativeExec.ll
+++ b/test/Transforms/SimplifyCFG/SpeculativeExec.ll
@@ -69,3 +69,29 @@ end:
ret i8* %x10
}
+
+define i32* @test5(i32 %a, i32 %b, i32 %c, i32* dereferenceable(10) %ptr1,
+ i32* dereferenceable(10) %ptr2, i32** dereferenceable(10) %ptr3) nounwind {
+; CHECK-LABEL: @test5(
+entry:
+ %tmp1 = icmp eq i32 %b, 0
+ br i1 %tmp1, label %bb1, label %bb3
+
+bb1: ; preds = %entry
+ %tmp2 = icmp sgt i32 %c, 1
+ br i1 %tmp2, label %bb2, label %bb3
+; CHECK: bb1:
+; CHECK-NEXT: icmp sgt i32 %c, 1
+; CHECK-NEXT: load i32*, i32** %ptr3
+; CHECK-NOT: dereferenceable
+; CHECK-NEXT: select i1 %tmp2, i32* %tmp3, i32* %ptr2
+; CHECK-NEXT: ret i32* %tmp3.ptr2
+
+bb2: ; preds = bb1
+ %tmp3 = load i32*, i32** %ptr3, !dereferenceable !{i64 10}
+ br label %bb3
+
+bb3: ; preds = %bb2, %entry
+ %tmp4 = phi i32* [ %ptr1, %entry ], [ %ptr2, %bb1 ], [ %tmp3, %bb2 ]
+ ret i32* %tmp4
+}
diff --git a/test/Transforms/SimplifyCFG/X86/speculate-cttz-ctlz.ll b/test/Transforms/SimplifyCFG/X86/speculate-cttz-ctlz.ll
index 69f6c69059d4..bee80e6acce0 100644
--- a/test/Transforms/SimplifyCFG/X86/speculate-cttz-ctlz.ll
+++ b/test/Transforms/SimplifyCFG/X86/speculate-cttz-ctlz.ll
@@ -7,9 +7,7 @@ define i64 @test1(i64 %A) {
; ALL-LABEL: @test1(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %A, i1 true)
-; LZCNT-NEXT: select i1 [[COND]], i64 64, i64 [[CTLZ]]
-; BMI-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i64 64, i64 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i64 %A, 0
@@ -28,9 +26,7 @@ define i32 @test2(i32 %A) {
; ALL-LABEL: @test2(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true)
-; LZCNT-NEXT: select i1 [[COND]], i32 32, i32 [[CTLZ]]
-; BMI-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i32 32, i32 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i32 %A, 0
@@ -50,9 +46,7 @@ define signext i16 @test3(i16 signext %A) {
; ALL-LABEL: @test3(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i16 %A, 0
; ALL: [[CTLZ:%[A-Za-z0-9]+]] = tail call i16 @llvm.ctlz.i16(i16 %A, i1 true)
-; LZCNT-NEXT: select i1 [[COND]], i16 16, i16 [[CTLZ]]
-; BMI-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i16 16, i16 [[CTLZ]]
; ALL: ret
entry:
%tobool = icmp eq i16 %A, 0
@@ -72,9 +66,7 @@ define i64 @test1b(i64 %A) {
; ALL-LABEL: @test1b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i64 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %A, i1 true)
-; BMI-NEXT: select i1 [[COND]], i64 64, i64 [[CTTZ]]
-; LZCNT-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i64 64, i64 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i64 %A, 0
@@ -94,9 +86,7 @@ define i32 @test2b(i32 %A) {
; ALL-LABEL: @test2b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i32 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %A, i1 true)
-; BMI-NEXT: select i1 [[COND]], i32 32, i32 [[CTTZ]]
-; LZCNT-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i32 32, i32 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i32 %A, 0
@@ -116,9 +106,7 @@ define signext i16 @test3b(i16 signext %A) {
; ALL-LABEL: @test3b(
; ALL: [[COND:%[A-Za-z0-9]+]] = icmp eq i16 %A, 0
; ALL: [[CTTZ:%[A-Za-z0-9]+]] = tail call i16 @llvm.cttz.i16(i16 %A, i1 true)
-; BMI-NEXT: select i1 [[COND]], i16 16, i16 [[CTTZ]]
-; LZCNT-NOT: select
-; GENERIC-NOT: select
+; ALL-NEXT: select i1 [[COND]], i16 16, i16 [[CTTZ]]
; ALL: ret
entry:
%tobool = icmp eq i16 %A, 0
diff --git a/test/Transforms/SimplifyCFG/basictest.ll b/test/Transforms/SimplifyCFG/basictest.ll
index d228499b2ec5..d4a9c81e506d 100644
--- a/test/Transforms/SimplifyCFG/basictest.ll
+++ b/test/Transforms/SimplifyCFG/basictest.ll
@@ -50,7 +50,7 @@ define i8 @test6f() {
; CHECK: alloca i8, align 1
; CHECK-NEXT: call i8 @test6g
; CHECK-NEXT: icmp eq i8 %tmp, 0
-; CHECK-NEXT: load i8, i8* %r, align 1{{$}}
+; CHECK-NEXT: load i8, i8* %r, align 1, !dbg !{{[0-9]+$}}
bb0:
%r = alloca i8, align 1
@@ -58,7 +58,7 @@ bb0:
%tmp1 = icmp eq i8 %tmp, 0
br i1 %tmp1, label %bb2, label %bb1
bb1:
- %tmp3 = load i8, i8* %r, align 1, !range !2, !tbaa !1
+ %tmp3 = load i8, i8* %r, align 1, !range !2, !tbaa !1, !dbg !5
%tmp4 = icmp eq i8 %tmp3, 1
br i1 %tmp4, label %bb2, label %bb3
bb2:
@@ -69,6 +69,16 @@ bb3:
}
declare i8 @test6g(i8*)
+!llvm.dbg.cu = !{!3}
+!llvm.module.flags = !{!8, !9}
+
!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)
+!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)
+!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 fac5b186e89d..34871063bbcc 100644
--- a/test/Transforms/SimplifyCFG/branch-fold-dbg.ll
+++ b/test/Transforms/SimplifyCFG/branch-fold-dbg.ll
@@ -4,7 +4,7 @@
@0 = external hidden constant [5 x %0], align 4
-define void @foo(i32) nounwind ssp {
+define void @foo(i32) nounwind ssp !dbg !0 {
Entry:
%1 = icmp slt i32 %0, 0, !dbg !5
br i1 %1, label %BB5, label %BB1, !dbg !5
@@ -41,14 +41,14 @@ declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnon
!llvm.dbg.sp = !{!0}
-!0 = !DISubprogram(name: "foo", line: 231, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !15, scope: !1, type: !3, function: void (i32)* @foo)
+!0 = distinct !DISubprogram(name: "foo", line: 231, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !15, scope: !1, type: !3)
!1 = !DIFile(filename: "a.c", directory: "/private/tmp")
-!2 = !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: 0, file: !15, enums: !4, retainedTypes: !4)
!3 = !DISubroutineType(types: !4)
!4 = !{null}
!5 = !DILocation(line: 131, column: 2, scope: !0)
!6 = !DILocation(line: 134, column: 2, scope: !0)
-!7 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "bar", line: 232, scope: !8, file: !1, type: !9)
+!7 = !DILocalVariable(name: "bar", line: 232, scope: !8, file: !1, type: !9)
!8 = distinct !DILexicalBlock(line: 231, column: 1, file: !15, scope: !0)
!9 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 32, align: 32, scope: !2, baseType: !10)
!10 = !DIDerivedType(tag: DW_TAG_const_type, scope: !2, baseType: !11)
diff --git a/test/Transforms/SimplifyCFG/empty-cleanuppad.ll b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll
new file mode 100644
index 000000000000..57b362889955
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll
@@ -0,0 +1,415 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+; ModuleID = 'cppeh-simplify.cpp'
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc18.0.0"
+
+
+; This case arises when two objects with empty destructors are cleaned up.
+;
+; void f1() {
+; S a;
+; S b;
+; g();
+; }
+;
+; In this case, both cleanup pads can be eliminated and the invoke can be
+; converted to a call.
+;
+; CHECK: define void @f1()
+; CHECK: entry:
+; CHECK: call void @g()
+; CHECK: ret void
+; CHECK-NOT: cleanuppad
+; CHECK: }
+;
+define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @g() to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ ret void
+
+ehcleanup: ; preds = %entry
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %ehcleanup.1
+
+ehcleanup.1: ; preds = %ehcleanup
+ %1 = cleanuppad within none []
+ cleanupret from %1 unwind to caller
+}
+
+
+; This case arises when an object with an empty destructor must be cleaned up
+; outside of a try-block and an object with a non-empty destructor must be
+; cleaned up within the try-block.
+;
+; void f2() {
+; S a;
+; try {
+; S2 b;
+; g();
+; } catch (...) {}
+; }
+;
+; In this case, the outermost cleanup pad can be eliminated and the catch block
+; should unwind to the caller (that is, exception handling continues with the
+; parent frame of the caller).
+;
+; CHECK: define void @f2()
+; CHECK: entry:
+; CHECK: invoke void @g()
+; CHECK: ehcleanup:
+; CHECK: cleanuppad within none
+; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
+; CHECK: cleanupret from %0 unwind label %catch.dispatch
+; CHECK: catch.dispatch:
+; CHECK: catchswitch within none [label %catch] unwind to caller
+; CHECK: catch:
+; CHECK: catchpad
+; CHECK: catchret
+; CHECK-NOT: cleanuppad
+; CHECK: }
+;
+define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ %b = alloca %struct.S2, align 1
+ invoke void @g() to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ br label %try.cont
+
+ehcleanup: ; preds = %entry
+ %0 = cleanuppad within none []
+ call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
+ cleanupret from %0 unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %ehcleanup
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %catchret.dest
+
+catchret.dest: ; preds = %catch
+ br label %try.cont
+
+try.cont: ; preds = %catchret.dest, %invoke.cont
+ ret void
+
+ehcleanup.1:
+ %2 = cleanuppad within none []
+ cleanupret from %2 unwind to caller
+}
+
+
+; This case arises when an object with a non-empty destructor must be cleaned up
+; outside of a try-block and an object with an empty destructor must be cleaned
+; within the try-block.
+;
+; void f3() {
+; S2 a;
+; try {
+; S b;
+; g();
+; } catch (...) {}
+; }
+;
+; In this case the inner cleanup pad should be eliminated and the invoke of g()
+; should unwind directly to the catchpad.
+;
+; CHECK-LABEL: define void @f3()
+; CHECK: entry:
+; CHECK: invoke void @g()
+; CHECK: to label %try.cont unwind label %catch.dispatch
+; CHECK: catch.dispatch:
+; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1
+; CHECK: catch:
+; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null]
+; CHECK: catchret
+; CHECK: ehcleanup.1:
+; CHECK: cleanuppad
+; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
+; CHECK: cleanupret from %cp3 unwind to caller
+; CHECK: }
+;
+define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ %a = alloca %struct.S2, align 1
+ invoke void @g() to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ br label %try.cont
+
+ehcleanup: ; preds = %entry
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %ehcleanup
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
+
+catch: ; preds = %catch.dispatch
+ %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %cp2 to label %catchret.dest
+
+catchret.dest: ; preds = %catch
+ br label %try.cont
+
+try.cont: ; preds = %catchret.dest, %invoke.cont
+ ret void
+
+ehcleanup.1:
+ %cp3 = cleanuppad within none []
+ call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
+ cleanupret from %cp3 unwind to caller
+}
+
+
+; This case arises when an object with an empty destructor may require cleanup
+; from either inside or outside of a try-block.
+;
+; void f4() {
+; S a;
+; g();
+; try {
+; g();
+; } catch (...) {}
+; }
+;
+; In this case, the cleanuppad should be eliminated, the invoke outside of the
+; catch block should be converted to a call (that is, that is, exception
+; handling continues with the parent frame of the caller).)
+;
+; CHECK-LABEL: define void @f4()
+; CHECK: entry:
+; CHECK: call void @g
+; Note: The cleanuppad simplification will insert an unconditional branch here
+; but it will be eliminated, placing the following invoke in the entry BB.
+; CHECK: invoke void @g()
+; CHECK: to label %try.cont unwind label %catch.dispatch
+; CHECK: catch.dispatch:
+; CHECK: catchswitch within none [label %catch] unwind to caller
+; CHECK: catch:
+; CHECK: catchpad
+; CHECK: catchret
+; CHECK-NOT: cleanuppad
+; CHECK: }
+;
+define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @g()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ invoke void @g()
+ to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %invoke.cont
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
+
+catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %0 to label %try.cont
+
+try.cont: ; preds = %catch, %invoke.cont
+ ret void
+
+ehcleanup:
+ %cp2 = cleanuppad within none []
+ cleanupret from %cp2 unwind to caller
+}
+
+; This case tests simplification of an otherwise empty cleanup pad that contains
+; a PHI node.
+;
+; int f6() {
+; int state = 1;
+; try {
+; S a;
+; g();
+; state = 2;
+; g();
+; } catch (...) {
+; return state;
+; }
+; return 0;
+; }
+;
+; In this case, the cleanup pad should be eliminated and the PHI node in the
+; cleanup pad should be sunk into the catch dispatch block.
+;
+; CHECK-LABEL: define i32 @f6()
+; CHECK: entry:
+; CHECK: invoke void @g()
+; CHECK: invoke.cont:
+; CHECK: invoke void @g()
+; CHECK-NOT: ehcleanup:
+; CHECK-NOT: cleanuppad
+; CHECK: catch.dispatch:
+; CHECK: %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
+; CHECK: }
+define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @g()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ invoke void @g()
+ to label %return unwind label %ehcleanup
+
+ehcleanup: ; preds = %invoke.cont, %entry
+ %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %ehcleanup
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %return
+
+return: ; preds = %invoke.cont, %catch
+ %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
+ ret i32 %retval.0
+}
+
+; This case tests another variation of simplification of an otherwise empty
+; cleanup pad that contains a PHI node.
+;
+; int f7() {
+; int state = 1;
+; try {
+; g();
+; state = 2;
+; S a;
+; g();
+; state = 3;
+; g();
+; } catch (...) {
+; return state;
+; }
+; return 0;
+; }
+;
+; In this case, the cleanup pad should be eliminated and the PHI node in the
+; cleanup pad should be merged with the PHI node in the catch dispatch block.
+;
+; CHECK-LABEL: define i32 @f7()
+; CHECK: entry:
+; CHECK: invoke void @g()
+; CHECK: invoke.cont:
+; CHECK: invoke void @g()
+; CHECK: invoke.cont.1:
+; CHECK: invoke void @g()
+; CHECK-NOT: ehcleanup:
+; CHECK-NOT: cleanuppad
+; CHECK: catch.dispatch:
+; CHECK: %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
+; CHECK: }
+define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @g()
+ to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont: ; preds = %entry
+ invoke void @g()
+ to label %invoke.cont.1 unwind label %ehcleanup
+
+invoke.cont.1: ; preds = %invoke.cont
+ invoke void @g()
+ to label %return unwind label %ehcleanup
+
+ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
+ %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %ehcleanup, %entry
+ %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %return
+
+return: ; preds = %invoke.cont.1, %catch
+ %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
+ ret i32 %retval.0
+}
+
+; This case tests a scenario where an empty cleanup pad is not dominated by all
+; of the predecessors of its successor, but the successor references a PHI node
+; in the empty cleanup pad.
+;
+; Conceptually, the case being modeled is something like this:
+;
+; int f8() {
+; int x = 1;
+; try {
+; S a;
+; g();
+; x = 2;
+; retry:
+; g();
+; return
+; } catch (...) {
+; use_x(x);
+; }
+; goto retry;
+; }
+;
+; While that C++ syntax isn't legal, the IR below is.
+;
+; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
+; should have an incoming value entry for path from 'foo' that references the
+; PHI node itself.
+;
+; CHECK-LABEL: define void @f8()
+; CHECK: entry:
+; CHECK: invoke void @g()
+; CHECK: invoke.cont:
+; CHECK: invoke void @g()
+; CHECK-NOT: ehcleanup:
+; CHECK-NOT: cleanuppad
+; CHECK: catch.dispatch:
+; CHECK: %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ]
+; CHECK: }
+define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @g()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont: ; preds = %entry
+ invoke void @g()
+ to label %return unwind label %ehcleanup
+
+ehcleanup: ; preds = %invoke.cont, %entry
+ %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %ehcleanup, %catch.cont
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ call void @use_x(i32 %x)
+ catchret from %1 to label %catch.cont
+
+catch.cont: ; preds = %catch
+ invoke void @g()
+ to label %return unwind label %catch.dispatch
+
+return: ; preds = %invoke.cont, %catch.cont
+ ret void
+}
+
+%struct.S = type { i8 }
+%struct.S2 = type { i8 }
+declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
+declare void @g()
+declare void @use_x(i32 %x)
+
+declare i32 @__CxxFrameHandler3(...)
+
diff --git a/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll b/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll
index 345cf6282e3c..887373a2d3db 100644
--- a/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll
+++ b/test/Transforms/SimplifyCFG/hoist-dbgvalue.ll
@@ -1,6 +1,6 @@
; RUN: opt -simplifycfg -S < %s | FileCheck %s
-define i32 @foo(i32 %i) nounwind ssp {
+define i32 @foo(i32 %i) nounwind ssp !dbg !0 {
call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !6, metadata !DIExpression()), !dbg !7
call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !9, metadata !DIExpression()), !dbg !11
%1 = icmp ne i32 %i, 0, !dbg !12
@@ -32,16 +32,16 @@ declare void @llvm.dbg.value(metadata, i64, metadata, metadata) nounwind readnon
!llvm.module.flags = !{!21}
!llvm.dbg.sp = !{!0}
-!0 = !DISubprogram(name: "foo", line: 2, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !20, scope: !1, type: !3, function: i32 (i32)* @foo)
+!0 = distinct !DISubprogram(name: "foo", line: 2, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, file: !20, scope: !1, type: !3)
!1 = !DIFile(filename: "b.c", directory: "/private/tmp")
-!2 = !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: 0, file: !20, enums: !8, retainedTypes: !8)
!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(tag: DW_TAG_arg_variable, name: "i", line: 2, arg: 1, scope: !0, file: !1, type: !5)
+!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(tag: DW_TAG_auto_variable, name: "k", line: 3, scope: !10, file: !1, type: !5)
+!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)
!12 = !DILocation(line: 4, column: 3, scope: !10)
diff --git a/test/Transforms/SimplifyCFG/implied-cond.ll b/test/Transforms/SimplifyCFG/implied-cond.ll
new file mode 100644
index 000000000000..317adc4c3472
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/implied-cond.ll
@@ -0,0 +1,81 @@
+; RUN: opt %s -S -simplifycfg | FileCheck %s
+; Check for when one branch implies the value of a successors conditional and
+; it's not simply the same conditional repeated.
+
+define void @test(i32 %length.i, i32 %i) {
+; CHECK-LABEL: @test
+ %iplus1 = add nsw i32 %i, 1
+ %var29 = icmp slt i32 %iplus1, %length.i
+; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds
+ br i1 %var29, label %next, label %out_of_bounds
+
+next:
+; CHECK-LABEL: in_bounds:
+; CHECK-NEXT: ret void
+ %var30 = icmp slt i32 %i, %length.i
+ br i1 %var30, label %in_bounds, label %out_of_bounds2
+
+in_bounds:
+ ret void
+
+out_of_bounds:
+ call void @foo(i64 0)
+ unreachable
+
+out_of_bounds2:
+ call void @foo(i64 1)
+ unreachable
+}
+
+; If the add is not nsw, it's not safe to use the fact about i+1 to imply the
+; i condition since it could have overflowed.
+define void @test_neg(i32 %length.i, i32 %i) {
+; CHECK-LABEL: @test_neg
+ %iplus1 = add i32 %i, 1
+ %var29 = icmp slt i32 %iplus1, %length.i
+; CHECK: br i1 %var29, label %next, label %out_of_bounds
+ br i1 %var29, label %next, label %out_of_bounds
+
+next:
+ %var30 = icmp slt i32 %i, %length.i
+; CHECK: br i1 %var30, label %in_bounds, label %out_of_bounds2
+ br i1 %var30, label %in_bounds, label %out_of_bounds2
+
+in_bounds:
+ ret void
+
+out_of_bounds:
+ call void @foo(i64 0)
+ unreachable
+
+out_of_bounds2:
+ call void @foo(i64 1)
+ unreachable
+}
+
+
+define void @test2(i32 %length.i, i32 %i) {
+; CHECK-LABEL: @test2
+ %iplus100 = add nsw i32 %i, 100
+ %var29 = icmp slt i32 %iplus100, %length.i
+; CHECK: br i1 %var29, label %in_bounds, label %out_of_bounds
+ br i1 %var29, label %next, label %out_of_bounds
+
+next:
+ %var30 = icmp slt i32 %i, %length.i
+ br i1 %var30, label %in_bounds, label %out_of_bounds2
+
+in_bounds:
+ ret void
+
+out_of_bounds:
+ call void @foo(i64 0)
+ unreachable
+
+out_of_bounds2:
+ call void @foo(i64 1)
+ unreachable
+}
+
+declare void @foo(i64)
+
diff --git a/test/Transforms/SimplifyCFG/invoke_unwind.ll b/test/Transforms/SimplifyCFG/invoke_unwind.ll
index 3b4c09d96f77..100bfd4e9e3e 100644
--- a/test/Transforms/SimplifyCFG/invoke_unwind.ll
+++ b/test/Transforms/SimplifyCFG/invoke_unwind.ll
@@ -17,4 +17,17 @@ Rethrow:
resume { i8*, i32 } %exn
}
+define i32 @test2() personality i32 (...)* @__gxx_personality_v0 {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: call void @bar() [ "foo"(i32 100) ]
+; CHECK-NEXT: ret i32 0
+ invoke void @bar( ) [ "foo"(i32 100) ]
+ to label %1 unwind label %Rethrow
+ ret i32 0
+Rethrow:
+ %exn = landingpad {i8*, i32}
+ catch i8* null
+ resume { i8*, i32 } %exn
+}
+
declare i32 @__gxx_personality_v0(...)
diff --git a/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll b/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll
new file mode 100644
index 000000000000..fe498b5334e8
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/merge-cond-stores-2.ll
@@ -0,0 +1,215 @@
+; RUN: opt -S < %s -simplifycfg -simplifycfg-merge-cond-stores=true -simplifycfg-merge-cond-stores-aggressively=false -phi-node-folding-threshold=2 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "armv7--linux-gnueabihf"
+
+; This is a bit reversal that has been run through the early optimizer (-mem2reg -gvn -instcombine).
+; There should be no additional PHIs created at all. The store should be on its own in a predicated
+; block and there should be no PHIs.
+
+; CHECK-LABEL: @f
+; Exactly 15 phis, as there are 15 in the original test case.
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK: select
+; CHECK-NOT: select
+; CHECK: br i1 {{.*}}, label %[[L:.*]], label %[[R:.*]]
+; CHECK: [[L]] ; preds =
+; CHECK-NEXT: store
+; CHECK-NEXT: br label %[[R]]
+; CHECK: [[R]] ; preds =
+; CHECK-NEXT: ret i32 0
+
+define i32 @f(i32* %b) {
+entry:
+ %0 = load i32, i32* %b, align 4
+ %and = and i32 %0, 1
+ %tobool = icmp eq i32 %and, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then: ; preds = %entry
+ %or = or i32 %0, -2147483648
+ store i32 %or, i32* %b, align 4
+ br label %if.end
+
+if.end: ; preds = %entry, %if.then
+ %1 = phi i32 [ %0, %entry ], [ %or, %if.then ]
+ %and1 = and i32 %1, 2
+ %tobool2 = icmp eq i32 %and1, 0
+ br i1 %tobool2, label %if.end5, label %if.then3
+
+if.then3: ; preds = %if.end
+ %or4 = or i32 %1, 1073741824
+ store i32 %or4, i32* %b, align 4
+ br label %if.end5
+
+if.end5: ; preds = %if.end, %if.then3
+ %2 = phi i32 [ %1, %if.end ], [ %or4, %if.then3 ]
+ %and6 = and i32 %2, 4
+ %tobool7 = icmp eq i32 %and6, 0
+ br i1 %tobool7, label %if.end10, label %if.then8
+
+if.then8: ; preds = %if.end5
+ %or9 = or i32 %2, 536870912
+ store i32 %or9, i32* %b, align 4
+ br label %if.end10
+
+if.end10: ; preds = %if.end5, %if.then8
+ %3 = phi i32 [ %2, %if.end5 ], [ %or9, %if.then8 ]
+ %and11 = and i32 %3, 8
+ %tobool12 = icmp eq i32 %and11, 0
+ br i1 %tobool12, label %if.end15, label %if.then13
+
+if.then13: ; preds = %if.end10
+ %or14 = or i32 %3, 268435456
+ store i32 %or14, i32* %b, align 4
+ br label %if.end15
+
+if.end15: ; preds = %if.end10, %if.then13
+ %4 = phi i32 [ %3, %if.end10 ], [ %or14, %if.then13 ]
+ %and16 = and i32 %4, 16
+ %tobool17 = icmp eq i32 %and16, 0
+ br i1 %tobool17, label %if.end20, label %if.then18
+
+if.then18: ; preds = %if.end15
+ %or19 = or i32 %4, 134217728
+ store i32 %or19, i32* %b, align 4
+ br label %if.end20
+
+if.end20: ; preds = %if.end15, %if.then18
+ %5 = phi i32 [ %4, %if.end15 ], [ %or19, %if.then18 ]
+ %and21 = and i32 %5, 32
+ %tobool22 = icmp eq i32 %and21, 0
+ br i1 %tobool22, label %if.end25, label %if.then23
+
+if.then23: ; preds = %if.end20
+ %or24 = or i32 %5, 67108864
+ store i32 %or24, i32* %b, align 4
+ br label %if.end25
+
+if.end25: ; preds = %if.end20, %if.then23
+ %6 = phi i32 [ %5, %if.end20 ], [ %or24, %if.then23 ]
+ %and26 = and i32 %6, 64
+ %tobool27 = icmp eq i32 %and26, 0
+ br i1 %tobool27, label %if.end30, label %if.then28
+
+if.then28: ; preds = %if.end25
+ %or29 = or i32 %6, 33554432
+ store i32 %or29, i32* %b, align 4
+ br label %if.end30
+
+if.end30: ; preds = %if.end25, %if.then28
+ %7 = phi i32 [ %6, %if.end25 ], [ %or29, %if.then28 ]
+ %and31 = and i32 %7, 256
+ %tobool32 = icmp eq i32 %and31, 0
+ br i1 %tobool32, label %if.end35, label %if.then33
+
+if.then33: ; preds = %if.end30
+ %or34 = or i32 %7, 8388608
+ store i32 %or34, i32* %b, align 4
+ br label %if.end35
+
+if.end35: ; preds = %if.end30, %if.then33
+ %8 = phi i32 [ %7, %if.end30 ], [ %or34, %if.then33 ]
+ %and36 = and i32 %8, 512
+ %tobool37 = icmp eq i32 %and36, 0
+ br i1 %tobool37, label %if.end40, label %if.then38
+
+if.then38: ; preds = %if.end35
+ %or39 = or i32 %8, 4194304
+ store i32 %or39, i32* %b, align 4
+ br label %if.end40
+
+if.end40: ; preds = %if.end35, %if.then38
+ %9 = phi i32 [ %8, %if.end35 ], [ %or39, %if.then38 ]
+ %and41 = and i32 %9, 1024
+ %tobool42 = icmp eq i32 %and41, 0
+ br i1 %tobool42, label %if.end45, label %if.then43
+
+if.then43: ; preds = %if.end40
+ %or44 = or i32 %9, 2097152
+ store i32 %or44, i32* %b, align 4
+ br label %if.end45
+
+if.end45: ; preds = %if.end40, %if.then43
+ %10 = phi i32 [ %9, %if.end40 ], [ %or44, %if.then43 ]
+ %and46 = and i32 %10, 2048
+ %tobool47 = icmp eq i32 %and46, 0
+ br i1 %tobool47, label %if.end50, label %if.then48
+
+if.then48: ; preds = %if.end45
+ %or49 = or i32 %10, 1048576
+ store i32 %or49, i32* %b, align 4
+ br label %if.end50
+
+if.end50: ; preds = %if.end45, %if.then48
+ %11 = phi i32 [ %10, %if.end45 ], [ %or49, %if.then48 ]
+ %and51 = and i32 %11, 4096
+ %tobool52 = icmp eq i32 %and51, 0
+ br i1 %tobool52, label %if.end55, label %if.then53
+
+if.then53: ; preds = %if.end50
+ %or54 = or i32 %11, 524288
+ store i32 %or54, i32* %b, align 4
+ br label %if.end55
+
+if.end55: ; preds = %if.end50, %if.then53
+ %12 = phi i32 [ %11, %if.end50 ], [ %or54, %if.then53 ]
+ %and56 = and i32 %12, 8192
+ %tobool57 = icmp eq i32 %and56, 0
+ br i1 %tobool57, label %if.end60, label %if.then58
+
+if.then58: ; preds = %if.end55
+ %or59 = or i32 %12, 262144
+ store i32 %or59, i32* %b, align 4
+ br label %if.end60
+
+if.end60: ; preds = %if.end55, %if.then58
+ %13 = phi i32 [ %12, %if.end55 ], [ %or59, %if.then58 ]
+ %and61 = and i32 %13, 16384
+ %tobool62 = icmp eq i32 %and61, 0
+ br i1 %tobool62, label %if.end65, label %if.then63
+
+if.then63: ; preds = %if.end60
+ %or64 = or i32 %13, 131072
+ store i32 %or64, i32* %b, align 4
+ br label %if.end65
+
+if.end65: ; preds = %if.end60, %if.then63
+ %14 = phi i32 [ %13, %if.end60 ], [ %or64, %if.then63 ]
+ %and66 = and i32 %14, 32768
+ %tobool67 = icmp eq i32 %and66, 0
+ br i1 %tobool67, label %if.end70, label %if.then68
+
+if.then68: ; preds = %if.end65
+ %or69 = or i32 %14, 65536
+ store i32 %or69, i32* %b, align 4
+ br label %if.end70
+
+if.end70: ; preds = %if.end65, %if.then68
+ %15 = phi i32 [ %14, %if.end65 ], [ %or69, %if.then68 ]
+ %and71 = and i32 %15, 128
+ %tobool72 = icmp eq i32 %and71, 0
+ br i1 %tobool72, label %if.end75, label %if.then73
+
+if.then73: ; preds = %if.end70
+ %or74 = or i32 %15, 16777216
+ store i32 %or74, i32* %b, align 4
+ br label %if.end75
+
+if.end75: ; preds = %if.end70, %if.then73
+ ret i32 0
+}
diff --git a/test/Transforms/SimplifyCFG/merge-cond-stores.ll b/test/Transforms/SimplifyCFG/merge-cond-stores.ll
new file mode 100644
index 000000000000..77e3158d9bbd
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/merge-cond-stores.ll
@@ -0,0 +1,241 @@
+; RUN: opt -simplifycfg -instcombine < %s -simplifycfg-merge-cond-stores=true -simplifycfg-merge-cond-stores-aggressively=false -phi-node-folding-threshold=2 -S | FileCheck %s
+
+; CHECK-LABEL: @test_simple
+; This test should succeed and end up if-converted.
+; CHECK: icmp eq i32 %b, 0
+; CHECK-NEXT: icmp ne i32 %a, 0
+; CHECK-NEXT: xor i1 %x2, true
+; CHECK-NEXT: %[[x:.*]] = or i1 %{{.*}}, %{{.*}}
+; CHECK-NEXT: br i1 %[[x]]
+; CHECK: store
+; CHECK-NOT: store
+; CHECK: ret
+define void @test_simple(i32* %p, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %fallthrough, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+fallthrough:
+ %x2 = icmp eq i32 %b, 0
+ br i1 %x2, label %end, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %end
+
+end:
+ ret void
+}
+
+; CHECK-LABEL: @test_recursive
+; This test should entirely fold away, leaving one large basic block.
+; CHECK: store
+; CHECK-NOT: store
+; CHECK: ret
+define void @test_recursive(i32* %p, i32 %a, i32 %b, i32 %c, i32 %d) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %fallthrough, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+fallthrough:
+ %x2 = icmp eq i32 %b, 0
+ br i1 %x2, label %next, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %next
+
+next:
+ %x3 = icmp eq i32 %c, 0
+ br i1 %x3, label %fallthrough2, label %yes3
+
+yes3:
+ store i32 2, i32* %p
+ br label %fallthrough2
+
+fallthrough2:
+ %x4 = icmp eq i32 %d, 0
+ br i1 %x4, label %end, label %yes4
+
+yes4:
+ store i32 3, i32* %p
+ br label %end
+
+
+end:
+ ret void
+}
+
+; CHECK-LABEL: @test_not_ifconverted
+; The code in each diamond is too large - it won't be if-converted so our
+; heuristics should say no.
+; CHECK: store
+; CHECK: store
+; CHECK: ret
+define void @test_not_ifconverted(i32* %p, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %fallthrough, label %yes1
+
+yes1:
+ %y1 = or i32 %b, 55
+ %y2 = add i32 %y1, 24
+ %y3 = and i32 %y2, 67
+ store i32 %y3, i32* %p
+ br label %fallthrough
+
+fallthrough:
+ %x2 = icmp eq i32 %b, 0
+ br i1 %x2, label %end, label %yes2
+
+yes2:
+ %z1 = or i32 %a, 55
+ %z2 = add i32 %z1, 24
+ %z3 = and i32 %z2, 67
+ store i32 %z3, i32* %p
+ br label %end
+
+end:
+ ret void
+}
+
+; CHECK-LABEL: @test_aliasing1
+; The store to %p clobbers the previous store, so if-converting this would
+; be illegal.
+; CHECK: store
+; CHECK: store
+; CHECK: ret
+define void @test_aliasing1(i32* %p, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %fallthrough, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+fallthrough:
+ %y1 = load i32, i32* %p
+ %x2 = icmp eq i32 %y1, 0
+ br i1 %x2, label %end, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %end
+
+end:
+ ret void
+}
+
+; CHECK-LABEL: @test_aliasing2
+; The load from %q aliases with %p, so if-converting this would be illegal.
+; CHECK: store
+; CHECK: store
+; CHECK: ret
+define void @test_aliasing2(i32* %p, i32* %q, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %fallthrough, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+fallthrough:
+ %y1 = load i32, i32* %q
+ %x2 = icmp eq i32 %y1, 0
+ br i1 %x2, label %end, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %end
+
+end:
+ ret void
+}
+
+declare void @f()
+
+; CHECK-LABEL: @test_diamond_simple
+; This should get if-converted.
+; CHECK: store
+; CHECK-NOT: store
+; CHECK: ret
+define i32 @test_diamond_simple(i32* %p, i32* %q, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %no1, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+no1:
+ %z1 = add i32 %a, %b
+ br label %fallthrough
+
+fallthrough:
+ %z2 = phi i32 [ %z1, %no1 ], [ 0, %yes1 ]
+ %x2 = icmp eq i32 %b, 0
+ br i1 %x2, label %no2, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %end
+
+no2:
+ %z3 = sub i32 %z2, %b
+ br label %end
+
+end:
+ %z4 = phi i32 [ %z3, %no2 ], [ 3, %yes2 ]
+ ret i32 %z4
+}
+
+; CHECK-LABEL: @test_diamond_alias3
+; Now there is a call to f() in the bottom branch. The store in the first
+; branch would now be reordered with respect to the call if we if-converted,
+; so we must not.
+; CHECK: store
+; CHECK: store
+; CHECK: ret
+define i32 @test_diamond_alias3(i32* %p, i32* %q, i32 %a, i32 %b) {
+entry:
+ %x1 = icmp eq i32 %a, 0
+ br i1 %x1, label %no1, label %yes1
+
+yes1:
+ store i32 0, i32* %p
+ br label %fallthrough
+
+no1:
+ call void @f()
+ %z1 = add i32 %a, %b
+ br label %fallthrough
+
+fallthrough:
+ %z2 = phi i32 [ %z1, %no1 ], [ 0, %yes1 ]
+ %x2 = icmp eq i32 %b, 0
+ br i1 %x2, label %no2, label %yes2
+
+yes2:
+ store i32 1, i32* %p
+ br label %end
+
+no2:
+ call void @f()
+ %z3 = sub i32 %z2, %b
+ br label %end
+
+end:
+ %z4 = phi i32 [ %z3, %no2 ], [ 3, %yes2 ]
+ ret i32 %z4
+}
diff --git a/test/Transforms/SimplifyCFG/no_speculative_loads_with_asan.ll b/test/Transforms/SimplifyCFG/no_speculative_loads_with_asan.ll
new file mode 100644
index 000000000000..063bde83f7b3
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/no_speculative_loads_with_asan.ll
@@ -0,0 +1,40 @@
+; RUN: opt -simplifycfg -S %s | FileCheck %s
+; Make sure we don't speculate loads under AddressSanitizer.
+@g = global i32 0, align 4
+
+define i32 @TestNoAsan(i32 %cond) nounwind readonly uwtable {
+entry:
+ %tobool = icmp eq i32 %cond, 0
+ br i1 %tobool, label %return, label %if.then
+
+if.then: ; preds = %entry
+ %0 = load i32, i32* @g, align 4
+ br label %return
+
+return: ; preds = %entry, %if.then
+ %retval = phi i32 [ %0, %if.then ], [ 0, %entry ]
+ ret i32 %retval
+; CHECK-LABEL: @TestNoAsan
+; CHECK: %[[LOAD:[^ ]*]] = load
+; CHECK: select{{.*}}[[LOAD]]
+; CHECK: ret i32
+}
+
+define i32 @TestAsan(i32 %cond) nounwind readonly uwtable sanitize_address {
+entry:
+ %tobool = icmp eq i32 %cond, 0
+ br i1 %tobool, label %return, label %if.then
+
+if.then: ; preds = %entry
+ %0 = load i32, i32* @g, align 4
+ br label %return
+
+return: ; preds = %entry, %if.then
+ %retval = phi i32 [ %0, %if.then ], [ 0, %entry ]
+ ret i32 %retval
+; CHECK-LABEL: @TestAsan
+; CHECK: br i1
+; CHECK: load i32, i32* @g
+; CHECK: br label
+; CHECK: ret i32
+}
diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll
new file mode 100644
index 000000000000..94d3565ce985
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll
@@ -0,0 +1,32 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+declare void @bar(i32*)
+declare void @baz(i32*)
+
+; CHECK-LABEL: @test_load_combine_metadata(
+; Check that dereferenceable metadata is combined
+; CHECK: load i32*, i32** %p
+; CHECK-SAME: !dereferenceable ![[DEREF:[0-9]+]]
+; CHECK: t:
+; CHECK: f:
+define void @test_load_combine_metadata(i1 %c, i32** %p) {
+ br i1 %c, label %t, label %f
+
+t:
+ %v1 = load i32*, i32** %p, !dereferenceable !0
+ call void @bar(i32* %v1)
+ br label %cont
+
+f:
+ %v2 = load i32*, i32** %p, !dereferenceable !1
+ call void @baz(i32* %v2)
+ br label %cont
+
+cont:
+ ret void
+}
+
+; CHECK: ![[DEREF]] = !{i64 8}
+
+!0 = !{i64 8}
+!1 = !{i64 16}
diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll
new file mode 100644
index 000000000000..92bdf6ec5c1a
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll
@@ -0,0 +1,32 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+declare void @bar(i32*)
+declare void @baz(i32*)
+
+; CHECK-LABEL: @test_load_combine_metadata(
+; Check that dereferenceable_or_null metadata is combined
+; CHECK: load i32*, i32** %p
+; CHECK-SAME: !dereferenceable_or_null ![[DEREF:[0-9]+]]
+; CHECK: t:
+; CHECK: f:
+define void @test_load_combine_metadata(i1 %c, i32** %p) {
+ br i1 %c, label %t, label %f
+
+t:
+ %v1 = load i32*, i32** %p, !dereferenceable_or_null !0
+ call void @bar(i32* %v1)
+ br label %cont
+
+f:
+ %v2 = load i32*, i32** %p, !dereferenceable_or_null !1
+ call void @baz(i32* %v2)
+ br label %cont
+
+cont:
+ ret void
+}
+
+; CHECK: ![[DEREF]] = !{i64 8}
+
+!0 = !{i64 8}
+!1 = !{i64 16}
diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata.ll
new file mode 100644
index 000000000000..89815c843152
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/preserve-load-metadata.ll
@@ -0,0 +1,32 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+declare void @bar(i32*)
+declare void @baz(i32*)
+
+; CHECK-LABEL: @test_load_combine_metadata(
+; Check that align metadata is combined
+; CHECK: load i32*, i32** %p
+; CHECK-SAME: !align ![[ALIGN:[0-9]+]]
+; CHECK: t:
+; CHECK: f:
+define void @test_load_combine_metadata(i1 %c, i32** %p) {
+ br i1 %c, label %t, label %f
+
+t:
+ %v1 = load i32*, i32** %p, !align !0
+ call void @bar(i32* %v1)
+ br label %cont
+
+f:
+ %v2 = load i32*, i32** %p, !align !1
+ call void @baz(i32* %v2)
+ br label %cont
+
+cont:
+ ret void
+}
+
+; CHECK: ![[ALIGN]] = !{i64 8}
+
+!0 = !{i64 8}
+!1 = !{i64 16}
diff --git a/test/Transforms/SimplifyCFG/preserve-make-implicit-on-switch-to-br.ll b/test/Transforms/SimplifyCFG/preserve-make-implicit-on-switch-to-br.ll
new file mode 100644
index 000000000000..0e95336bbc1f
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/preserve-make-implicit-on-switch-to-br.ll
@@ -0,0 +1,30 @@
+; RUN: opt %s -simplifycfg -S | FileCheck %s
+
+; ConstantFoldTerminator function can convert SwitchInst with one case (and default) to
+; a conditional BranchInst. This test checks the converted BranchInst preserve the
+; make.implicit metadata.
+
+declare i32 @consume(i32*)
+declare void @trap()
+
+define i32 @copy-metadata(i32* %x) {
+
+entry:
+ %x.int = ptrtoint i32* %x to i64
+
+; CHECK: br i1 %cond, label %is_null, label %default, !make.implicit !0
+ switch i64 %x.int, label %default [
+ i64 0, label %is_null
+ ], !make.implicit !0
+
+default:
+ %0 = call i32 @consume(i32* %x)
+ ret i32 %0
+
+is_null:
+ call void @trap()
+ unreachable
+}
+
+!0 = !{}
+
diff --git a/test/Transforms/SimplifyCFG/speculate-math.ll b/test/Transforms/SimplifyCFG/speculate-math.ll
index 0ba93d29117a..5655d5d78821 100644
--- a/test/Transforms/SimplifyCFG/speculate-math.ll
+++ b/test/Transforms/SimplifyCFG/speculate-math.ll
@@ -1,4 +1,5 @@
-; RUN: opt -S -simplifycfg -phi-node-folding-threshold=2 < %s | FileCheck %s
+; RUN: opt -S -simplifycfg < %s | FileCheck %s --check-prefix=EXPENSIVE --check-prefix=ALL
+; RUN: opt -S -simplifycfg -speculate-one-expensive-inst=false < %s | FileCheck %s --check-prefix=CHEAP --check-prefix=ALL
declare float @llvm.sqrt.f32(float) nounwind readonly
declare float @llvm.fma.f32(float, float, float) nounwind readonly
@@ -7,8 +8,26 @@ declare float @llvm.fabs.f32(float) nounwind readonly
declare float @llvm.minnum.f32(float, float) nounwind readonly
declare float @llvm.maxnum.f32(float, float) nounwind readonly
-; CHECK-LABEL: @sqrt_test(
-; CHECK: select
+; ALL-LABEL: @fdiv_test(
+; EXPENSIVE: select i1 %cmp, double %div, double 0.0
+; CHEAP-NOT: select
+
+define double @fdiv_test(double %a, double %b) {
+entry:
+ %cmp = fcmp ogt double %a, 0.0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true:
+ %div = fdiv double %b, %a
+ br label %cond.end
+
+cond.end:
+ %cond = phi double [ %div, %cond.true ], [ 0.0, %entry ]
+ ret double %cond
+}
+
+; ALL-LABEL: @sqrt_test(
+; ALL: select
define void @sqrt_test(float addrspace(1)* noalias nocapture %out, float %a) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
@@ -24,8 +43,8 @@ test_sqrt.exit: ; preds = %cond.else.i, %entry
ret void
}
-; CHECK-LABEL: @fabs_test(
-; CHECK: select
+; ALL-LABEL: @fabs_test(
+; ALL: select
define void @fabs_test(float addrspace(1)* noalias nocapture %out, float %a) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
@@ -41,8 +60,8 @@ test_fabs.exit: ; preds = %cond.else.i, %entry
ret void
}
-; CHECK-LABEL: @fma_test(
-; CHECK: select
+; ALL-LABEL: @fma_test(
+; ALL: select
define void @fma_test(float addrspace(1)* noalias nocapture %out, float %a, float %b, float %c) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
@@ -58,8 +77,8 @@ test_fma.exit: ; preds = %cond.else.i, %entry
ret void
}
-; CHECK-LABEL: @fmuladd_test(
-; CHECK: select
+; ALL-LABEL: @fmuladd_test(
+; ALL: select
define void @fmuladd_test(float addrspace(1)* noalias nocapture %out, float %a, float %b, float %c) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
@@ -75,8 +94,8 @@ test_fmuladd.exit: ; preds = %cond.else.i, %en
ret void
}
-; CHECK-LABEL: @minnum_test(
-; CHECK: select
+; ALL-LABEL: @minnum_test(
+; ALL: select
define void @minnum_test(float addrspace(1)* noalias nocapture %out, float %a, float %b) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
@@ -92,8 +111,8 @@ test_minnum.exit: ; preds = %cond.else.i, %ent
ret void
}
-; CHECK-LABEL: @maxnum_test(
-; CHECK: select
+; ALL-LABEL: @maxnum_test(
+; ALL: select
define void @maxnum_test(float addrspace(1)* noalias nocapture %out, float %a, float %b) nounwind {
entry:
%cmp.i = fcmp olt float %a, 0.000000e+00
diff --git a/test/Transforms/SimplifyCFG/statepoint-invoke-unwind.ll b/test/Transforms/SimplifyCFG/statepoint-invoke-unwind.ll
index 994e47eb0d64..53daa8292da7 100644
--- a/test/Transforms/SimplifyCFG/statepoint-invoke-unwind.ll
+++ b/test/Transforms/SimplifyCFG/statepoint-invoke-unwind.ll
@@ -3,15 +3,15 @@
; not optimized into call
declare i64 addrspace(1)* @gc_call()
-declare i32 @llvm.experimental.gc.statepoint.p0f_p1i64f(i64, i32, i64 addrspace(1)* ()*, i32, i32, ...)
+declare token @llvm.experimental.gc.statepoint.p0f_p1i64f(i64, i32, i64 addrspace(1)* ()*, i32, i32, ...)
declare i32* @fake_personality_function()
define i32 @test() gc "statepoint-example" personality i32* ()* @fake_personality_function {
; CHECK-LABEL: test
entry:
; CHECK-LABEL: entry:
- ; CHECK-NEXT: %sp = invoke i32 (i64, i32, i64 addrspace(1)* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p1i64f
- %sp = invoke i32 (i64, i32, i64 addrspace(1)* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p1i64f(i64 0, i32 0, i64 addrspace(1)* ()* @gc_call, i32 0, i32 0, i32 0, i32 0)
+ ; CHECK-NEXT: %sp = invoke token (i64, i32, i64 addrspace(1)* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p1i64f
+ %sp = invoke token (i64, i32, i64 addrspace(1)* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p1i64f(i64 0, i32 0, i64 addrspace(1)* ()* @gc_call, i32 0, i32 0, i32 0, i32 0)
to label %normal unwind label %exception
exception:
diff --git a/test/Transforms/SimplifyCFG/switch-dead-default.ll b/test/Transforms/SimplifyCFG/switch-dead-default.ll
new file mode 100644
index 000000000000..e5c2ef65b318
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/switch-dead-default.ll
@@ -0,0 +1,179 @@
+; RUN: opt %s -S -simplifycfg | FileCheck %s
+declare void @foo(i32)
+
+define void @test(i1 %a) {
+; CHECK-LABEL: @test
+; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
+ switch i1 %a, label %default [i1 1, label %true
+ i1 0, label %false]
+true:
+ call void @foo(i32 1)
+ ret void
+false:
+ call void @foo(i32 3)
+ ret void
+default:
+ call void @foo(i32 2)
+ ret void
+}
+
+define void @test2(i2 %a) {
+; CHECK-LABEL: @test2
+ switch i2 %a, label %default [i2 0, label %case0
+ i2 1, label %case1
+ i2 2, label %case2
+ i2 3, label %case3]
+case0:
+ call void @foo(i32 0)
+ ret void
+case1:
+ call void @foo(i32 1)
+ ret void
+case2:
+ call void @foo(i32 2)
+ ret void
+case3:
+ call void @foo(i32 3)
+ ret void
+default:
+; CHECK-LABEL: default1:
+; CHECK-NEXT: unreachable
+ call void @foo(i32 4)
+ ret void
+}
+
+; This one is a negative test - we know the value of the default,
+; but that's about it
+define void @test3(i2 %a) {
+; CHECK-LABEL: @test3
+ switch i2 %a, label %default [i2 0, label %case0
+ i2 1, label %case1
+ i2 2, label %case2]
+
+case0:
+ call void @foo(i32 0)
+ ret void
+case1:
+ call void @foo(i32 1)
+ ret void
+case2:
+ call void @foo(i32 2)
+ ret void
+default:
+; CHECK-LABEL: default:
+; CHECK-NEXT: call void @foo
+ call void @foo(i32 0)
+ ret void
+}
+
+; Negative test - check for possible overflow when computing
+; number of possible cases.
+define void @test4(i128 %a) {
+; CHECK-LABEL: @test4
+ switch i128 %a, label %default [i128 0, label %case0
+ i128 1, label %case1]
+
+case0:
+ call void @foo(i32 0)
+ ret void
+case1:
+ call void @foo(i32 1)
+ ret void
+default:
+; CHECK-LABEL: default:
+; CHECK-NEXT: call void @foo
+ call void @foo(i32 0)
+ ret void
+}
+
+; All but one bit known zero
+define void @test5(i8 %a) {
+; CHECK-LABEL: @test5
+; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
+ %cmp = icmp ult i8 %a, 2
+ call void @llvm.assume(i1 %cmp)
+ switch i8 %a, label %default [i8 1, label %true
+ i8 0, label %false]
+true:
+ call void @foo(i32 1)
+ ret void
+false:
+ call void @foo(i32 3)
+ ret void
+default:
+ call void @foo(i32 2)
+ ret void
+}
+
+;; All but one bit known one
+define void @test6(i8 %a) {
+; CHECK-LABEL: @test6
+; CHECK: @llvm.assume
+; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
+ %and = and i8 %a, 254
+ %cmp = icmp eq i8 %and, 254
+ call void @llvm.assume(i1 %cmp)
+ switch i8 %a, label %default [i8 255, label %true
+ i8 254, label %false]
+true:
+ call void @foo(i32 1)
+ ret void
+false:
+ call void @foo(i32 3)
+ ret void
+default:
+ call void @foo(i32 2)
+ ret void
+}
+
+; Check that we can eliminate both dead cases and dead defaults
+; within a single run of simplify-cfg
+define void @test7(i8 %a) {
+; CHECK-LABEL: @test7
+; CHECK: @llvm.assume
+; CHECK: br i1 [[IGNORE:%.*]], label %true, label %false
+ %and = and i8 %a, 254
+ %cmp = icmp eq i8 %and, 254
+ call void @llvm.assume(i1 %cmp)
+ switch i8 %a, label %default [i8 255, label %true
+ i8 254, label %false
+ i8 0, label %also_dead]
+true:
+ call void @foo(i32 1)
+ ret void
+false:
+ call void @foo(i32 3)
+ ret void
+also_dead:
+ call void @foo(i32 5)
+ ret void
+default:
+ call void @foo(i32 2)
+ ret void
+}
+
+;; All but one bit known undef
+;; Note: This is currently testing an optimization which doesn't trigger. The
+;; case this is protecting against is that a bit could be assumed both zero
+;; *or* one given we know it's undef. ValueTracking doesn't do this today,
+;; but it doesn't hurt to confirm.
+define void @test8(i8 %a) {
+; CHECK-LABEL: @test8(
+; CHECK: switch i8
+ %and = and i8 %a, 254
+ %cmp = icmp eq i8 %and, undef
+ call void @llvm.assume(i1 %cmp)
+ switch i8 %a, label %default [i8 255, label %true
+ i8 254, label %false]
+true:
+ call void @foo(i32 1)
+ ret void
+false:
+ call void @foo(i32 3)
+ ret void
+default:
+ call void @foo(i32 2)
+ ret void
+}
+
+declare void @llvm.assume(i1)
diff --git a/test/Transforms/SimplifyCFG/trap-debugloc.ll b/test/Transforms/SimplifyCFG/trap-debugloc.ll
index fedf6b172d75..2887aaf52eee 100644
--- a/test/Transforms/SimplifyCFG/trap-debugloc.ll
+++ b/test/Transforms/SimplifyCFG/trap-debugloc.ll
@@ -1,7 +1,7 @@
; RUN: opt -S -simplifycfg < %s | FileCheck %s
; Radar 9342286
; Assign DebugLoc to trap instruction.
-define void @foo() nounwind ssp {
+define void @foo() nounwind ssp !dbg !0 {
; CHECK: call void @llvm.trap(), !dbg
store i32 42, i32* null, !dbg !5
ret void, !dbg !7
@@ -11,9 +11,9 @@ define void @foo() nounwind ssp {
!llvm.module.flags = !{!10}
!llvm.dbg.sp = !{!0}
-!0 = !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, file: !8, scope: !1, type: !3, function: void ()* @foo)
+!0 = distinct !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, file: !8, scope: !1, type: !3)
!1 = !DIFile(filename: "foo.c", directory: "/private/tmp")
-!2 = !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: 0, file: !8, enums: !{}, retainedTypes: !{}, subprograms: !9)
!3 = !DISubroutineType(types: !4)
!4 = !{null}
!5 = !DILocation(line: 4, column: 2, scope: !6)
diff --git a/test/Transforms/SimplifyCFG/wineh-unreachable.ll b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
new file mode 100644
index 000000000000..670119467dae
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
@@ -0,0 +1,83 @@
+; RUN: opt -S -simplifycfg < %s | FileCheck %s
+
+declare void @Personality()
+declare void @f()
+
+; CHECK-LABEL: define void @test1()
+define void @test1() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+ ; CHECK: call void @f()
+ invoke void @f()
+ to label %exit unwind label %unreachable.unwind
+exit:
+ ret void
+unreachable.unwind:
+ cleanuppad within none []
+ unreachable
+}
+
+; CHECK-LABEL: define void @test2()
+define void @test2() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+ invoke void @f()
+ to label %exit unwind label %catch.pad
+catch.pad:
+ %cs1 = catchswitch within none [label %catch.body] unwind label %unreachable.unwind
+ ; CHECK: catch.pad:
+ ; CHECK-NEXT: catchswitch within none [label %catch.body] unwind to caller
+catch.body:
+ ; CHECK: catch.body:
+ ; CHECK-NEXT: catchpad within %cs1
+ ; CHECK-NEXT: call void @f()
+ ; CHECK-NEXT: unreachable
+ %catch = catchpad within %cs1 []
+ call void @f()
+ catchret from %catch to label %unreachable
+exit:
+ ret void
+unreachable.unwind:
+ cleanuppad within none []
+ unreachable
+unreachable:
+ unreachable
+}
+
+; CHECK-LABEL: define void @test3()
+define void @test3() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+ invoke void @f()
+ to label %exit unwind label %cleanup.pad
+cleanup.pad:
+ ; CHECK: %cleanup = cleanuppad within none []
+ ; CHECK-NEXT: call void @f()
+ ; CHECK-NEXT: unreachable
+ %cleanup = cleanuppad within none []
+ invoke void @f()
+ to label %cleanup.ret unwind label %unreachable.unwind
+cleanup.ret:
+ ; This cleanupret should be rewritten to unreachable,
+ ; and merged into the pred block.
+ cleanupret from %cleanup unwind label %unreachable.unwind
+exit:
+ ret void
+unreachable.unwind:
+ cleanuppad within none []
+ unreachable
+}
+
+; CHECK-LABEL: define void @test5()
+define void @test5() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+ invoke void @f()
+ to label %exit unwind label %catch.pad
+
+catch.pad:
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
+
+catch.body:
+ %catch = catchpad within %cs1 []
+ catchret from %catch to label %exit
+
+exit:
+ unreachable
+}