summaryrefslogtreecommitdiff
path: root/test/Transforms
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-02 18:30:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-02 18:30:13 +0000
commita303c417bbdb53703c2c17398b08486bde78f1f6 (patch)
tree98366d6b93d863cefdc53f16c66c0c5ae7fb2261 /test/Transforms
parent12f3ca4cdb95b193af905a00e722a4dcb40b3de3 (diff)
Notes
Diffstat (limited to 'test/Transforms')
-rw-r--r--test/Transforms/CodeExtractor/MultipleExitBranchProb.ll6
-rw-r--r--test/Transforms/CodeExtractor/PartialInlineAnd.ll56
-rw-r--r--test/Transforms/CodeExtractor/PartialInlineAndOr.ll63
-rw-r--r--test/Transforms/CodeExtractor/PartialInlineOptRemark.ll40
-rw-r--r--test/Transforms/CodeExtractor/PartialInlineOr.ll97
-rw-r--r--test/Transforms/CodeExtractor/PartialInlineOrAnd.ll71
-rw-r--r--test/Transforms/CodeExtractor/SingleCondition.ll23
-rw-r--r--test/Transforms/CodeExtractor/unreachable-block.ll6
-rw-r--r--test/Transforms/EarlyCSE/guards.ll346
-rw-r--r--test/Transforms/GVNHoist/hoist-inline.ll2
-rw-r--r--test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll70
-rw-r--r--test/Transforms/InferAddressSpaces/AMDGPU/infer-addrspacecast.ll43
-rw-r--r--test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll39
-rw-r--r--test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll2
-rw-r--r--test/Transforms/Inline/AArch64/switch.ll123
-rw-r--r--test/Transforms/InstCombine/amdgcn-intrinsics.ll6
-rw-r--r--test/Transforms/InstCombine/and-or-not.ll40
-rw-r--r--test/Transforms/InstCombine/and.ll13
-rw-r--r--test/Transforms/InstCombine/apint-and.ll126
-rw-r--r--test/Transforms/InstCombine/apint-and1.ll57
-rw-r--r--test/Transforms/InstCombine/apint-and2.ll82
-rw-r--r--test/Transforms/InstCombine/apint-not.ll25
-rw-r--r--test/Transforms/InstCombine/apint-or.ll23
-rw-r--r--test/Transforms/InstCombine/assume2.ll8
-rw-r--r--test/Transforms/InstCombine/demorgan-zext.ll81
-rw-r--r--test/Transforms/InstCombine/demorgan.ll501
-rw-r--r--test/Transforms/InstCombine/not.ll39
-rw-r--r--test/Transforms/InstSimplify/shufflevector.ll8
-rw-r--r--test/Transforms/JumpThreading/fold-not-thread.ll111
-rw-r--r--test/Transforms/LoopUnswitch/pr32818.ll19
-rw-r--r--test/Transforms/NewGVN/pr32852.ll24
-rw-r--r--test/Transforms/ObjCARC/rv.ll25
-rw-r--r--test/Transforms/PGOProfile/memop_size_opt_zero.ll19
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2006-06-13-SingleEntryPHI.ll35
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2006-06-27-DeadSwitchCase.ll25
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-05-09-Unreachable.ll28
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-05-09-tl.ll95
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-07-12-ExitDomInfo.ll45
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-07-13-DomInfo.ll27
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-07-18-DomInfo.ll66
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-08-01-Dom.ll30
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-08-01-LCSSA.ll55
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2007-10-04-DomFrontier.ll29
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2008-06-02-DomInfo.ll26
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2008-06-17-DomFrontier.ll22
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2010-11-18-LCSSA.ll28
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2011-06-02-CritSwitch.ll28
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2011-09-26-EHCrash.ll63
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2012-04-02-IndirectBr.ll41
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2012-04-30-LoopUnswitch-LPad-Crash.ll97
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2012-05-20-Phi.ll25
-rw-r--r--test/Transforms/SimpleLoopUnswitch/2015-09-18-Addrspace.ll28
-rw-r--r--test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll28
-rw-r--r--test/Transforms/SimpleLoopUnswitch/basictest.ll184
-rw-r--r--test/Transforms/SimpleLoopUnswitch/cleanuppad.ll44
-rw-r--r--test/Transforms/SimpleLoopUnswitch/copy-metadata.ll34
-rw-r--r--test/Transforms/SimpleLoopUnswitch/crash.ll66
-rw-r--r--test/Transforms/SimpleLoopUnswitch/exponential-behavior.ll51
-rw-r--r--test/Transforms/SimpleLoopUnswitch/infinite-loop.ll64
-rw-r--r--test/Transforms/SimpleLoopUnswitch/msan.ll141
-rw-r--r--test/Transforms/SimpleLoopUnswitch/preserve-analyses.ll129
-rw-r--r--test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll185
-rw-r--r--test/Transforms/SimplifyCFG/speculate-call.ll23
63 files changed, 3570 insertions, 366 deletions
diff --git a/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll b/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll
index e37b7e636450..425e96973596 100644
--- a/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll
+++ b/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck %s
; This test checks to make sure that CodeExtractor updates
; the exit branch probabilities for multiple exit blocks.
@@ -22,7 +22,7 @@ ret i32 %val
; CHECK-LABEL: @dummyCaller
; CHECK: call
-; CHECK-NEXT: br i1 {{.*}}!prof [[COUNT1:![0-9]+]]
+; CHECK-NEXT: br i1 {{.*}}return.i{{.*}}return.2{{.*}}!prof [[COUNT1:![0-9]+]]
}
!llvm.module.flags = !{!0}
@@ -31,4 +31,4 @@ ret i32 %val
!2 = !{!"branch_weights", i32 5, i32 5}
!3 = !{!"branch_weights", i32 4, i32 1}
-; CHECK: [[COUNT1]] = !{!"branch_weights", i32 8, i32 31}
+; CHECK: [[COUNT1]] = !{!"branch_weights", i32 31, i32 8}
diff --git a/test/Transforms/CodeExtractor/PartialInlineAnd.ll b/test/Transforms/CodeExtractor/PartialInlineAnd.ll
new file mode 100644
index 000000000000..e981a5ba5816
--- /dev/null
+++ b/test/Transforms/CodeExtractor/PartialInlineAnd.ll
@@ -0,0 +1,56 @@
+; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s
+; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %arg) local_unnamed_addr #0 {
+bb:
+ %tmp = icmp slt i32 %arg, 0
+ br i1 %tmp, label %bb1, label %bb5
+
+bb1: ; preds = %bb
+ %tmp2 = tail call i32 (...) @channels() #2
+ %tmp3 = icmp slt i32 %tmp2, %arg
+ br i1 %tmp3, label %bb4, label %bb5
+
+bb4: ; preds = %bb1
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ br label %bb5
+
+bb5: ; preds = %bb4, %bb1, %bb
+ %tmp6 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ], [ 1, %bb ]
+ ret i32 %tmp6
+}
+
+declare i32 @channels(...) local_unnamed_addr #1
+
+declare void @foo(...) local_unnamed_addr #1
+
+; Function Attrs: nounwind uwtable
+define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 {
+bb:
+; CHECK-LABEL: @dummy_caller
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: call void @bar.1_
+; LIMIT-LABEL: @dummy_caller
+; LIMIT: br i1
+; LIMIT-NOT: br
+; LIMIT: call void @bar.1_
+ %tmp = tail call i32 @bar(i32 %arg)
+ ret i32 %tmp
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind }
+
diff --git a/test/Transforms/CodeExtractor/PartialInlineAndOr.ll b/test/Transforms/CodeExtractor/PartialInlineAndOr.ll
new file mode 100644
index 000000000000..485e06ce1023
--- /dev/null
+++ b/test/Transforms/CodeExtractor/PartialInlineAndOr.ll
@@ -0,0 +1,63 @@
+; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT %s
+; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT %s
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %arg) local_unnamed_addr #0 {
+bb:
+ %tmp = icmp slt i32 %arg, 0
+ br i1 %tmp, label %bb1, label %bb4
+
+bb1: ; preds = %bb
+ %tmp2 = tail call i32 (...) @n() #2
+ %tmp3 = icmp slt i32 %tmp2, %arg
+ br i1 %tmp3, label %bb7, label %bb4
+
+bb4: ; preds = %bb1, %bb
+ %tmp5 = tail call i32 (...) @m() #2
+ %tmp6 = icmp slt i32 %tmp5, %arg
+ br i1 %tmp6, label %bb7, label %bb8
+
+bb7: ; preds = %bb4, %bb1
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb4
+ %tmp9 = phi i32 [ 0, %bb7 ], [ 1, %bb4 ]
+ ret i32 %tmp9
+}
+
+declare i32 @n(...) local_unnamed_addr #1
+
+declare i32 @m(...) local_unnamed_addr #1
+
+declare void @foo(...) local_unnamed_addr #1
+
+; Function Attrs: nounwind uwtable
+define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 {
+bb:
+; CHECK-LABEL: @dummy_caller
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: call void @bar.1_
+; LIMIT-LABEL: @dummy_caller
+; LIMIT-NOT: br i1
+; LIMIT: call i32 @bar
+ %tmp = tail call i32 @bar(i32 %arg)
+ ret i32 %tmp
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind }
+
diff --git a/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll b/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll
index 3ba03843046c..c8808182f717 100644
--- a/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll
+++ b/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll
@@ -7,6 +7,8 @@
; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining --disable-partial-inlining < %s 2>&1 | FileCheck --check-prefix=LIMIT %s
; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -max-partial-inlining=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s
; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -max-partial-inlining=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s
+; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -inline-threshold=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s
+; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -inline-threshold=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s
define i32 @bar(i32 %arg) local_unnamed_addr #0 !dbg !5 {
bb:
@@ -30,6 +32,38 @@ bb2: ; preds = %bb1, %bb
ret i32 %tmp3, !dbg !19
}
+define i32 @bar_noinline(i32 %arg) local_unnamed_addr #1 !dbg !5 {
+bb:
+ %tmp = icmp slt i32 %arg, 0, !dbg !7
+ br i1 %tmp, label %bb1, label %bb2, !dbg !8
+
+bb1: ; preds = %bb
+ tail call void (...) @foo() #0, !dbg !9
+ tail call void (...) @foo() #0, !dbg !10
+ tail call void (...) @foo() #0, !dbg !11
+ br label %bb2, !dbg !18
+
+bb2: ; preds = %bb1, %bb
+ %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ]
+ ret i32 %tmp3, !dbg !19
+}
+
+define i32 @bar_alwaysinline(i32 %arg) local_unnamed_addr #2 !dbg !5 {
+bb:
+ %tmp = icmp slt i32 %arg, 0, !dbg !7
+ br i1 %tmp, label %bb1, label %bb2, !dbg !8
+
+bb1: ; preds = %bb
+ tail call void (...) @foo() #0, !dbg !9
+ tail call void (...) @foo() #0, !dbg !10
+ tail call void (...) @foo() #0, !dbg !11
+ br label %bb2, !dbg !18
+
+bb2: ; preds = %bb1, %bb
+ %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ]
+ ret i32 %tmp3, !dbg !19
+}
+
; Function Attrs: nounwind
declare void @foo(...) local_unnamed_addr #0
@@ -37,12 +71,18 @@ declare void @foo(...) local_unnamed_addr #0
define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 !dbg !20 {
bb:
; CHECK:remark{{.*}}bar partially inlined into dummy_caller
+; CHECK-NOT:remark{{.*}}bar_noinline partially inlined into dummy_caller
+; CHECK-NOT:remark{{.*}}bar_alwaysinline partially inlined into dummy_caller
; LIMIT-NOT:remark{{.*}}bar partially inlined into dummy_caller
%tmp = tail call i32 @bar(i32 %arg), !dbg !21
+ %tmp2 = tail call i32 @bar_noinline(i32 %arg), !dbg !21
+ %tmp3 = tail call i32 @bar_alwaysinline(i32 %arg), !dbg !21
ret i32 %tmp, !dbg !22
}
attributes #0 = { nounwind }
+attributes #1 = { noinline nounwind }
+attributes #2 = { alwaysinline nounwind }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3}
diff --git a/test/Transforms/CodeExtractor/PartialInlineOr.ll b/test/Transforms/CodeExtractor/PartialInlineOr.ll
new file mode 100644
index 000000000000..5408b4faaf70
--- /dev/null
+++ b/test/Transforms/CodeExtractor/PartialInlineOr.ll
@@ -0,0 +1,97 @@
+; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s
+; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %arg) local_unnamed_addr #0 {
+bb:
+ %tmp = icmp slt i32 %arg, 0
+ br i1 %tmp, label %bb4, label %bb1
+
+bb1: ; preds = %bb
+ %tmp2 = tail call i32 (...) @channels() #1
+ %tmp3 = icmp slt i32 %tmp2, %arg
+ br i1 %tmp3, label %bb4, label %bb5
+
+bb4: ; preds = %bb1, %bb
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ br label %bb5
+
+bb5: ; preds = %bb4, %bb1
+ %.0 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ]
+ ret i32 %.0
+}
+
+declare i32 @channels(...) local_unnamed_addr
+
+declare void @foo(...) local_unnamed_addr
+
+; Function Attrs: nounwind uwtable
+define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 {
+bb:
+; CHECK-LABEL: @dummy_caller
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: call void @bar.2_
+; LIMIT-LABEL: @dummy_caller
+; LIMIT-NOT: br
+; LIMIT: call i32 @bar(
+ %tmp = tail call i32 @bar(i32 %arg)
+ ret i32 %tmp
+}
+
+define i32 @bar_multi_ret(i32 %arg) local_unnamed_addr #0 {
+bb:
+ %tmp = icmp slt i32 %arg, 0
+ br i1 %tmp, label %bb4, label %bb1
+
+bb1: ; preds = %bb
+ %tmp2 = tail call i32 (...) @channels() #1
+ %tmp3 = icmp slt i32 %tmp2, %arg
+ br i1 %tmp3, label %bb4, label %bb5
+
+bb4: ; preds = %bb1, %bb
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ tail call void (...) @foo() #1
+ %tmp4 = icmp slt i32 %arg, 10
+ br i1 %tmp4, label %bb6, label %bb5
+bb6:
+ tail call void (...) @foo() #1
+ %tmp5 = icmp slt i32 %arg, 3
+ br i1 %tmp5, label %bb7, label %bb5
+bb7:
+ tail call void (...) @foo() #1
+ br label %bb8
+bb8:
+ ret i32 0
+
+bb5: ; preds = %bb4, %bb1
+ %.0 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ], [0, %bb6]
+ ret i32 %.0
+}
+
+define i32 @dummy_caller2(i32 %arg) local_unnamed_addr #0 {
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: call {{.*}} @bar_multi_ret.1_
+ %tmp = tail call i32 @bar_multi_ret(i32 %arg)
+ ret i32 %tmp
+}
+
+attributes #0 = { nounwind uwtable }
+attributes #1 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 5.0.0 (trunk 300576)"}
diff --git a/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll b/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll
new file mode 100644
index 000000000000..282d300fadb9
--- /dev/null
+++ b/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll
@@ -0,0 +1,71 @@
+; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT3 %s
+; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT3 %s
+; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT2 %s
+; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT2 %s
+
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %arg) local_unnamed_addr #0 {
+bb:
+ %tmp = icmp slt i32 %arg, 0
+ br i1 %tmp, label %bb4, label %bb1
+
+bb1: ; preds = %bb
+ %tmp2 = tail call i32 (...) @n() #2
+ %tmp3 = icmp slt i32 %tmp2, %arg
+ br i1 %tmp3, label %bb4, label %bb8
+
+bb4: ; preds = %bb1, %bb
+ %tmp5 = tail call i32 (...) @m() #2
+ %tmp6 = icmp sgt i32 %tmp5, %arg
+ br i1 %tmp6, label %bb7, label %bb8
+
+bb7: ; preds = %bb4
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ tail call void (...) @foo() #2
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb4, %bb1
+ %tmp9 = phi i32 [ 0, %bb7 ], [ 1, %bb4 ], [ 1, %bb1 ]
+ ret i32 %tmp9
+}
+
+declare i32 @n(...) local_unnamed_addr #1
+
+declare i32 @m(...) local_unnamed_addr #1
+
+declare void @foo(...) local_unnamed_addr #1
+
+; Function Attrs: nounwind uwtable
+define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 {
+bb:
+; CHECK-LABEL: @dummy_caller
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: br i1
+; CHECK: call void @bar.1_
+; LIMIT3-LABEL: @dummy_caller
+; LIMIT3: br i1
+; LIMIT3: br i1
+; LIMIT3-NOT: br i1
+; LIMIT3: call void @bar.1_
+; LIMIT2-LABEL: @dummy_caller
+; LIMIT2-NOT: br i1
+; LIMIT2: call i32 @bar(
+ %tmp = tail call i32 @bar(i32 %arg)
+ ret i32 %tmp
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind }
+
diff --git a/test/Transforms/CodeExtractor/SingleCondition.ll b/test/Transforms/CodeExtractor/SingleCondition.ll
new file mode 100644
index 000000000000..90cda889a21b
--- /dev/null
+++ b/test/Transforms/CodeExtractor/SingleCondition.ll
@@ -0,0 +1,23 @@
+; RUN: opt < %s -partial-inliner -S | FileCheck %s
+; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s
+
+define internal i32 @inlinedFunc(i1 %cond, i32* align 4 %align.val) {
+entry:
+ br i1 %cond, label %if.then, label %return
+if.then:
+ ; Dummy store to have more than 0 uses
+ store i32 10, i32* %align.val, align 4
+ br label %return
+return: ; preds = %entry
+ ret i32 0
+}
+
+define internal i32 @dummyCaller(i1 %cond, i32* align 2 %align.val) {
+entry:
+; CHECK-LABEL: @dummyCaller
+; CHECK: br
+; CHECK: call void @inlinedFunc.1_
+ %val = call i32 @inlinedFunc(i1 %cond, i32* %align.val)
+ ret i32 %val
+}
+
diff --git a/test/Transforms/CodeExtractor/unreachable-block.ll b/test/Transforms/CodeExtractor/unreachable-block.ll
index d20a35718e68..09f41f6bd2fb 100644
--- a/test/Transforms/CodeExtractor/unreachable-block.ll
+++ b/test/Transforms/CodeExtractor/unreachable-block.ll
@@ -9,13 +9,11 @@
; CHECK-LABEL: define internal void @tinkywinky.1_ontrue() {
; CHECK-NEXT: newFuncRoot:
; CHECK-NEXT: br label %ontrue
-; CHECK: .exitStub:
+; CHECK: onfalse{{.*}}:
; CHECK-NEXT: ret void
; CHECK: ontrue:
; CHECK-NEXT: call void @patatino()
-; CHECK-NEXT: br label %onfalse
-; CHECK: onfalse:
-; CHECK-NEXT: br label %.exitStub
+; CHECK-NEXT: br label %onfalse{{.*}}
; CHECK-NEXT: }
declare void @patatino()
diff --git a/test/Transforms/EarlyCSE/guards.ll b/test/Transforms/EarlyCSE/guards.ll
index 55185f9fe56c..de43264db6fa 100644
--- a/test/Transforms/EarlyCSE/guards.ll
+++ b/test/Transforms/EarlyCSE/guards.ll
@@ -3,6 +3,8 @@
declare void @llvm.experimental.guard(i1,...)
+declare void @llvm.assume(i1)
+
define i32 @test0(i32* %ptr, i1 %cond) {
; We can do store to load forwarding over a guard, since it does not
; clobber memory
@@ -180,3 +182,347 @@ define void @test6(i1 %c, i32* %ptr) {
store i32 600, i32* %ptr
ret void
}
+
+define void @test07(i32 %a, i32 %b) {
+; Check that we are able to remove the guards on the same condition even if the
+; condition is not being recalculated.
+
+; CHECK-LABEL: @test07(
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: ret void
+
+ %cmp = icmp eq i32 %a, %b
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ ret void
+}
+
+define void @test08(i32 %a, i32 %b, i32* %ptr) {
+; Check that we deal correctly with stores when removing guards in the same
+; block in case when the condition is not recalculated.
+
+; CHECK-LABEL: @test08(
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: store i32 100, i32* %ptr
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: ret void
+
+ %cmp = icmp eq i32 %a, %b
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 200, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ ret void
+}
+
+define void @test09(i32 %a, i32 %b, i1 %c, i32* %ptr) {
+; Similar to test08, but with more control flow.
+; TODO: Can we get rid of the store in the end of entry given that it is
+; post-dominated by other stores?
+
+; CHECK-LABEL: @test09(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: store i32 100, i32* %ptr
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: br i1 %c, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: store i32 500, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: store i32 600, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 200, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ br i1 %c, label %if.true, label %if.false
+
+if.true:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 500, i32* %ptr
+ br label %merge
+
+if.false:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 600, i32* %ptr
+ br label %merge
+
+merge:
+ ret void
+}
+
+define void @test10(i32 %a, i32 %b, i1 %c, i32* %ptr) {
+; Make sure that non-dominating guards do not cause other guards removal.
+
+; CHECK-LABEL: @test10(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: br i1 %c, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: store i32 100, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: store i32 200, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: store i32 300, i32* %ptr
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ br i1 %c, label %if.true, label %if.false
+
+if.true:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ br label %merge
+
+if.false:
+ store i32 200, i32* %ptr
+ br label %merge
+
+merge:
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ ret void
+}
+
+define void @test11(i32 %a, i32 %b, i32* %ptr) {
+; Make sure that branching condition is applied to guards.
+
+; CHECK-LABEL: @test11(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: br i1 %cmp, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ br i1 %cmp, label %if.true, label %if.false
+
+if.true:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ br label %merge
+
+if.false:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ br label %merge
+
+merge:
+ ret void
+}
+
+define void @test12(i32 %a, i32 %b) {
+; Check that the assume marks its condition as being true (and thus allows to
+; eliminate the dominated guards).
+
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: ret void
+
+ %cmp = icmp eq i32 %a, %b
+ call void @llvm.assume(i1 %cmp)
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ ret void
+}
+
+define void @test13(i32 %a, i32 %b, i32* %ptr) {
+; Check that we deal correctly with stores when removing guards due to assume.
+
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: ret void
+
+ %cmp = icmp eq i32 %a, %b
+ call void @llvm.assume(i1 %cmp)
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 200, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ ret void
+}
+
+define void @test14(i32 %a, i32 %b, i1 %c, i32* %ptr) {
+; Similar to test13, but with more control flow.
+; TODO: Can we get rid of the store in the end of entry given that it is
+; post-dominated by other stores?
+
+; CHECK-LABEL: @test14(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: br i1 %c, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: store i32 500, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: store i32 600, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ call void @llvm.assume(i1 %cmp)
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 200, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ br i1 %c, label %if.true, label %if.false
+
+if.true:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 500, i32* %ptr
+ br label %merge
+
+if.false:
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 600, i32* %ptr
+ br label %merge
+
+merge:
+ ret void
+}
+
+define void @test15(i32 %a, i32 %b, i1 %c, i32* %ptr) {
+; Make sure that non-dominating assumes do not cause guards removal.
+
+; CHECK-LABEL: @test15(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: br i1 %c, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: store i32 100, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: store i32 200, i32* %ptr
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: store i32 300, i32* %ptr
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+; CHECK-NEXT: store i32 400, i32* %ptr
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ br i1 %c, label %if.true, label %if.false
+
+if.true:
+ call void @llvm.assume(i1 %cmp)
+ store i32 100, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ br label %merge
+
+if.false:
+ store i32 200, i32* %ptr
+ br label %merge
+
+merge:
+ store i32 300, i32* %ptr
+ call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
+ store i32 400, i32* %ptr
+ ret void
+}
+
+define void @test16(i32 %a, i32 %b) {
+; Check that we don't bother to do anything with assumes even if we know the
+; condition being true.
+
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: ret void
+
+ %cmp = icmp eq i32 %a, %b
+ call void @llvm.assume(i1 %cmp)
+ call void @llvm.assume(i1 %cmp)
+ ret void
+}
+
+define void @test17(i32 %a, i32 %b, i1 %c, i32* %ptr) {
+; Check that we don't bother to do anything with assumes even if we know the
+; condition being true or false (includes come control flow).
+
+; CHECK-LABEL: @test17(
+; CHECK: entry:
+; CHECK-NEXT: %cmp = icmp eq i32 %a, %b
+; CHECK-NEXT: br i1 %c, label %if.true, label %if.false
+; CHECK: if.true:
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: br label %merge
+; CHECK: if.false:
+; CHECK-NEXT: call void @llvm.assume(i1 %cmp)
+; CHECK-NEXT: br label %merge
+; CHECK: merge:
+; CHECK-NEXT: ret void
+
+entry:
+ %cmp = icmp eq i32 %a, %b
+ br i1 %c, label %if.true, label %if.false
+
+if.true:
+ call void @llvm.assume(i1 %cmp)
+ br label %merge
+
+if.false:
+ call void @llvm.assume(i1 %cmp)
+ br label %merge
+
+merge:
+ ret void
+}
+
+define void @test18(i1 %c) {
+; Check that we don't bother to do anything with assumes even if we know the
+; condition being true and not being an instruction.
+
+; CHECK-LABEL: @test18(
+; CHECK-NEXT: call void @llvm.assume(i1 %c)
+; CHECK-NEXT: call void @llvm.assume(i1 %c)
+; CHECK-NEXT: ret void
+
+ call void @llvm.assume(i1 %c)
+ call void @llvm.assume(i1 %c)
+ ret void
+}
diff --git a/test/Transforms/GVNHoist/hoist-inline.ll b/test/Transforms/GVNHoist/hoist-inline.ll
index 7d761486ab15..56378d136de5 100644
--- a/test/Transforms/GVNHoist/hoist-inline.ll
+++ b/test/Transforms/GVNHoist/hoist-inline.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -O2 < %s | FileCheck %s
+; RUN: opt -S -O2 -enable-gvn-hoist < %s | FileCheck %s
; Check that the inlined loads are hoisted.
; CHECK-LABEL: define i32 @fun(
diff --git a/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll b/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll
new file mode 100644
index 000000000000..9cdf603cb248
--- /dev/null
+++ b/test/Transforms/GlobalOpt/localize-constexpr-debuginfo.ll
@@ -0,0 +1,70 @@
+; RUN: opt -S < %s -globalopt | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@_ZL1x = internal global [200 x i8]* null, align 8, !dbg !0
+
+define i32 @main(i32 %argc, i8** %argv) norecurse !dbg !18 {
+; CHECK: define i32 @main
+; Make sure we localized the global.
+; CHECK: alloca [200 x i8]*
+; Make sure the metadata is sane. Currently, we just drop the metadata,
+; so it points to nothing.
+; CHECK: call void @llvm.dbg.value(metadata !2,
+; CHECK: !2 = !{}
+entry:
+ call void @llvm.dbg.value(metadata i32 %argc, i64 0, metadata !22, metadata !23), !dbg !24
+ call void @llvm.dbg.value(metadata i8** %argv, i64 0, metadata !25, metadata !23), !dbg !26
+ %arrayidx = getelementptr inbounds i8*, i8** %argv, i64 0, !dbg !27
+ %0 = load i8*, i8** %arrayidx, align 8, !dbg !27
+ %1 = bitcast i8* %0 to [200 x i8]*, !dbg !28
+ store [200 x i8]* %1, [200 x i8]** @_ZL1x, align 8, !dbg !29
+ call void @llvm.dbg.value(metadata i8** bitcast ([200 x i8]** @_ZL1x to i8**), i64 0, metadata !30, metadata !23), !dbg !31
+ %2 = load i8*, i8** bitcast ([200 x i8]** @_ZL1x to i8**), align 8, !dbg !32
+ %3 = load i8, i8* %2, align 1, !dbg !33
+ %conv = sext i8 %3 to i32, !dbg !33
+ ret i32 %conv, !dbg !34
+}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!15, !16}
+!llvm.ident = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1)
+!1 = distinct !DIGlobalVariable(name: "x", linkageName: "_ZL1x", scope: !2, file: !14, line: 1, type: !6, isLocal: true, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !13)
+!3 = !DIFile(filename: "-", directory: "/")
+!4 = !{}
+!5 = !{!6, !11}
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 1600, elements: !9)
+!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!9 = !{!10}
+!10 = !DISubrange(count: 200)
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64)
+!13 = !{!0}
+!14 = !DIFile(filename: "<stdin>", directory: "/")
+!15 = !{i32 2, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{!"clang"}
+!18 = distinct !DISubprogram(name: "main", scope: !14, file: !14, line: 2, type: !19, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21, !21, !11}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DILocalVariable(name: "argc", arg: 1, scope: !18, file: !14, line: 2, type: !21)
+!23 = !DIExpression()
+!24 = !DILocation(line: 2, column: 14, scope: !18)
+!25 = !DILocalVariable(name: "argv", arg: 2, scope: !18, file: !14, line: 2, type: !11)
+!26 = !DILocation(line: 2, column: 26, scope: !18)
+!27 = !DILocation(line: 2, column: 52, scope: !18)
+!28 = !DILocation(line: 2, column: 38, scope: !18)
+!29 = !DILocation(line: 2, column: 36, scope: !18)
+!30 = !DILocalVariable(name: "y", scope: !18, file: !14, line: 2, type: !11)
+!31 = !DILocation(line: 2, column: 68, scope: !18)
+!32 = !DILocation(line: 2, column: 92, scope: !18)
+!33 = !DILocation(line: 2, column: 91, scope: !18)
+!34 = !DILocation(line: 2, column: 84, scope: !18)
diff --git a/test/Transforms/InferAddressSpaces/AMDGPU/infer-addrspacecast.ll b/test/Transforms/InferAddressSpaces/AMDGPU/infer-addrspacecast.ll
new file mode 100644
index 000000000000..73829e86527c
--- /dev/null
+++ b/test/Transforms/InferAddressSpaces/AMDGPU/infer-addrspacecast.ll
@@ -0,0 +1,43 @@
+; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -infer-address-spaces %s | FileCheck %s
+
+; Test that pure addrspacecast instructions not directly connected to
+; a memory operation are inferred.
+
+; CHECK-LABEL: @addrspacecast_gep_addrspacecast(
+; CHECK: %gep0 = getelementptr i32, i32 addrspace(3)* %ptr, i64 9
+; CHECK-NEXT: store i32 8, i32 addrspace(3)* %gep0, align 8
+; CHECK-NEXT: ret void
+define void @addrspacecast_gep_addrspacecast(i32 addrspace(3)* %ptr) {
+ %asc0 = addrspacecast i32 addrspace(3)* %ptr to i32 addrspace(4)*
+ %gep0 = getelementptr i32, i32 addrspace(4)* %asc0, i64 9
+ %asc1 = addrspacecast i32 addrspace(4)* %gep0 to i32 addrspace(3)*
+ store i32 8, i32 addrspace(3)* %asc1, align 8
+ ret void
+}
+
+; CHECK-LABEL: @addrspacecast_to_memory(
+; CHECK: %gep0 = getelementptr i32, i32 addrspace(3)* %ptr, i64 9
+; CHECK-NEXT: store volatile i32 addrspace(3)* %gep0, i32 addrspace(3)* addrspace(1)* undef
+; CHECK-NEXT: ret void
+define void @addrspacecast_to_memory(i32 addrspace(3)* %ptr) {
+ %asc0 = addrspacecast i32 addrspace(3)* %ptr to i32 addrspace(4)*
+ %gep0 = getelementptr i32, i32 addrspace(4)* %asc0, i64 9
+ %asc1 = addrspacecast i32 addrspace(4)* %gep0 to i32 addrspace(3)*
+ store volatile i32 addrspace(3)* %asc1, i32 addrspace(3)* addrspace(1)* undef
+ ret void
+}
+
+; CHECK-LABEL: @multiuse_addrspacecast_gep_addrspacecast(
+; CHECK: %1 = addrspacecast i32 addrspace(3)* %ptr to i32 addrspace(4)*
+; CHECK-NEXT: store volatile i32 addrspace(4)* %1, i32 addrspace(4)* addrspace(1)* undef
+; CHECK-NEXT: %gep0 = getelementptr i32, i32 addrspace(3)* %ptr, i64 9
+; CHECK-NEXT: store i32 8, i32 addrspace(3)* %gep0, align 8
+; CHECK-NEXT: ret void
+define void @multiuse_addrspacecast_gep_addrspacecast(i32 addrspace(3)* %ptr) {
+ %asc0 = addrspacecast i32 addrspace(3)* %ptr to i32 addrspace(4)*
+ store volatile i32 addrspace(4)* %asc0, i32 addrspace(4)* addrspace(1)* undef
+ %gep0 = getelementptr i32, i32 addrspace(4)* %asc0, i64 9
+ %asc1 = addrspacecast i32 addrspace(4)* %gep0 to i32 addrspace(3)*
+ store i32 8, i32 addrspace(3)* %asc1, align 8
+ ret void
+}
diff --git a/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll b/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll
index 6b94a74da35c..e2c255dcb3ef 100644
--- a/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll
+++ b/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll
@@ -5,10 +5,19 @@
@lds = internal unnamed_addr addrspace(3) global [648 x double] undef, align 8
+; CHECK-LABEL: @simplified_constexpr_gep_addrspacecast(
+; CHECK: %gep0 = getelementptr inbounds double, double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384), i64 %idx0
+; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %gep0, align 8
+define void @simplified_constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) {
+ %gep0 = getelementptr inbounds double, double addrspace(4)* addrspacecast (double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384) to double addrspace(4)*), i64 %idx0
+ %asc = addrspacecast double addrspace(4)* %gep0 to double addrspace(3)*
+ store double 1.000000e+00, double addrspace(3)* %asc, align 8
+ ret void
+}
+
; CHECK-LABEL: @constexpr_gep_addrspacecast(
-; CHECK: %gep0 = getelementptr inbounds double, double addrspace(4)* addrspacecast (double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384) to double addrspace(4)*), i64 %idx0
-; CHECK-NEXT: %asc = addrspacecast double addrspace(4)* %gep0 to double addrspace(3)*
-; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %asc
+; CHECK-NEXT: %gep0 = getelementptr inbounds double, double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384), i64 %idx0
+; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %gep0, align 8
define void @constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) {
%gep0 = getelementptr inbounds double, double addrspace(4)* getelementptr ([648 x double], [648 x double] addrspace(4)* addrspacecast ([648 x double] addrspace(3)* @lds to [648 x double] addrspace(4)*), i64 0, i64 384), i64 %idx0
%asc = addrspacecast double addrspace(4)* %gep0 to double addrspace(3)*
@@ -18,10 +27,8 @@ define void @constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) {
; CHECK-LABEL: @constexpr_gep_gep_addrspacecast(
; CHECK: %gep0 = getelementptr inbounds double, double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384), i64 %idx0
-; CHECK-NEXT: %1 = addrspacecast double addrspace(3)* %gep0 to double addrspace(4)*
-; CHECK-NEXT: %gep1 = getelementptr inbounds double, double addrspace(4)* %1, i64 %idx1
-; CHECK-NEXT: %asc = addrspacecast double addrspace(4)* %gep1 to double addrspace(3)*
-; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %asc, align 8
+; CHECK-NEXT: %gep1 = getelementptr inbounds double, double addrspace(3)* %gep0, i64 %idx1
+; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %gep1, align 8
define void @constexpr_gep_gep_addrspacecast(i64 %idx0, i64 %idx1) {
%gep0 = getelementptr inbounds double, double addrspace(4)* getelementptr ([648 x double], [648 x double] addrspace(4)* addrspacecast ([648 x double] addrspace(3)* @lds to [648 x double] addrspace(4)*), i64 0, i64 384), i64 %idx0
%gep1 = getelementptr inbounds double, double addrspace(4)* %gep0, i64 %idx1
@@ -46,3 +53,21 @@ define amdgpu_kernel void @vector_gep(<4 x [1024 x i32] addrspace(3)*> %array) n
store i32 99, i32 addrspace(4)* %p3
ret void
}
+
+; CHECK-LABEL: @repeated_constexpr_gep_addrspacecast(
+; CHECK-NEXT: %gep0 = getelementptr inbounds double, double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384), i64 %idx0
+; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %gep0, align 8
+; CHECK-NEXT: %gep1 = getelementptr inbounds double, double addrspace(3)* getelementptr inbounds ([648 x double], [648 x double] addrspace(3)* @lds, i64 0, i64 384), i64 %idx1
+; CHECK-NEXT: store double 1.000000e+00, double addrspace(3)* %gep1, align 8
+; CHECK-NEXT: ret void
+define void @repeated_constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) {
+ %gep0 = getelementptr inbounds double, double addrspace(4)* getelementptr ([648 x double], [648 x double] addrspace(4)* addrspacecast ([648 x double] addrspace(3)* @lds to [648 x double] addrspace(4)*), i64 0, i64 384), i64 %idx0
+ %asc0 = addrspacecast double addrspace(4)* %gep0 to double addrspace(3)*
+ store double 1.0, double addrspace(3)* %asc0, align 8
+
+ %gep1 = getelementptr inbounds double, double addrspace(4)* getelementptr ([648 x double], [648 x double] addrspace(4)* addrspacecast ([648 x double] addrspace(3)* @lds to [648 x double] addrspace(4)*), i64 0, i64 384), i64 %idx1
+ %asc1 = addrspacecast double addrspace(4)* %gep1 to double addrspace(3)*
+ store double 1.0, double addrspace(3)* %asc1, align 8
+
+ ret void
+}
diff --git a/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll b/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll
index b2d8ddb19565..b4e05b2e429e 100644
--- a/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll
+++ b/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll
@@ -10,7 +10,7 @@ target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
; CHECK: %tmp = load float*, float* addrspace(3)* getelementptr inbounds (%struct.bar, %struct.bar addrspace(3)* @var1, i64 0, i32 1), align 8
; CHECK: %tmp1 = load float, float* %tmp, align 4
; CHECK: store float %conv1, float* %tmp, align 4
-; CHECK: store i32 32, i32 addrspace(3)* addrspacecast (i32* bitcast (float** getelementptr (%struct.bar, %struct.bar* addrspacecast (%struct.bar addrspace(3)* @var1 to %struct.bar*), i64 0, i32 1) to i32*) to i32 addrspace(3)*), align 4
+; CHECK: store i32 32, i32 addrspace(3)* bitcast (float* addrspace(3)* getelementptr inbounds (%struct.bar, %struct.bar addrspace(3)* @var1, i64 0, i32 1) to i32 addrspace(3)*), align 4
define void @bug31948(float %a, float* nocapture readnone %x, float* nocapture readnone %y) local_unnamed_addr #0 {
entry:
%tmp = load float*, float** getelementptr (%struct.bar, %struct.bar* addrspacecast (%struct.bar addrspace(3)* @var1 to %struct.bar*), i64 0, i32 1), align 8
diff --git a/test/Transforms/Inline/AArch64/switch.ll b/test/Transforms/Inline/AArch64/switch.ll
new file mode 100644
index 000000000000..96d6bf2db682
--- /dev/null
+++ b/test/Transforms/Inline/AArch64/switch.ll
@@ -0,0 +1,123 @@
+; RUN: opt < %s -inline -inline-threshold=20 -S -mtriple=aarch64-none-linux -inline-generic-switch-cost=true | FileCheck %s
+; RUN: opt < %s -passes='cgscc(inline)' -inline-threshold=20 -S -mtriple=aarch64-none-linux -inline-generic-switch-cost=true | FileCheck %s
+
+define i32 @callee_range(i32 %a, i32* %P) {
+ switch i32 %a, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1000, label %sw.bb1
+ i32 2000, label %sw.bb1
+ i32 3000, label %sw.bb1
+ i32 4000, label %sw.bb1
+ i32 5000, label %sw.bb1
+ i32 6000, label %sw.bb1
+ i32 7000, label %sw.bb1
+ i32 8000, label %sw.bb1
+ i32 9000, label %sw.bb1
+ ]
+
+sw.default:
+ store volatile i32 %a, i32* %P
+ br label %return
+sw.bb0:
+ store volatile i32 %a, i32* %P
+ br label %return
+sw.bb1:
+ store volatile i32 %a, i32* %P
+ br label %return
+return:
+ ret i32 42
+}
+
+define i32 @caller_range(i32 %a, i32* %P) {
+; CHECK-LABEL: @caller_range(
+; CHECK: call i32 @callee_range
+ %r = call i32 @callee_range(i32 %a, i32* %P)
+ ret i32 %r
+}
+
+define i32 @callee_bittest(i32 %a, i32* %P) {
+ switch i32 %a, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb0
+ i32 4, label %sw.bb1
+ i32 5, label %sw.bb2
+ i32 6, label %sw.bb0
+ i32 7, label %sw.bb1
+ i32 8, label %sw.bb2
+ ]
+
+sw.default:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb0:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb1:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb2:
+ br label %return
+
+return:
+ ret i32 42
+}
+
+
+define i32 @caller_bittest(i32 %a, i32* %P) {
+; CHECK-LABEL: @caller_bittest(
+; CHECK-NOT: call i32 @callee_bittest
+ %r= call i32 @callee_bittest(i32 %a, i32* %P)
+ ret i32 %r
+}
+
+define i32 @callee_jumptable(i32 %a, i32* %P) {
+ switch i32 %a, label %sw.default [
+ i32 1001, label %sw.bb101
+ i32 1002, label %sw.bb102
+ i32 1003, label %sw.bb103
+ i32 1004, label %sw.bb104
+ i32 1005, label %sw.bb101
+ i32 1006, label %sw.bb102
+ i32 1007, label %sw.bb103
+ i32 1008, label %sw.bb104
+ i32 1009, label %sw.bb101
+ i32 1010, label %sw.bb102
+ i32 1011, label %sw.bb103
+ i32 1012, label %sw.bb104
+ ]
+
+sw.default:
+ br label %return
+
+sw.bb101:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb102:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb103:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+sw.bb104:
+ store volatile i32 %a, i32* %P
+ br label %return
+
+return:
+ ret i32 42
+}
+
+define i32 @caller_jumptable(i32 %a, i32 %b, i32* %P) {
+; CHECK-LABEL: @caller_jumptable(
+; CHECK: call i32 @callee_jumptable
+ %r = call i32 @callee_jumptable(i32 %b, i32* %P)
+ ret i32 %r
+}
+
diff --git a/test/Transforms/InstCombine/amdgcn-intrinsics.ll b/test/Transforms/InstCombine/amdgcn-intrinsics.ll
index 357085fd31fe..1901997c5521 100644
--- a/test/Transforms/InstCombine/amdgcn-intrinsics.ll
+++ b/test/Transforms/InstCombine/amdgcn-intrinsics.ll
@@ -1259,7 +1259,7 @@ define i64 @icmp_constant_inputs_false() {
}
; CHECK-LABEL: @icmp_constant_inputs_true(
-; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #4
+; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #5
define i64 @icmp_constant_inputs_true() {
%result = call i64 @llvm.amdgcn.icmp.i32(i32 9, i32 8, i32 34)
ret i64 %result
@@ -1524,7 +1524,7 @@ define i64 @fcmp_constant_inputs_false() {
}
; CHECK-LABEL: @fcmp_constant_inputs_true(
-; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #4
+; CHECK: %result = call i64 @llvm.read_register.i64(metadata !0) #5
define i64 @fcmp_constant_inputs_true() {
%result = call i64 @llvm.amdgcn.fcmp.f32(float 2.0, float 4.0, i32 4)
ret i64 %result
@@ -1537,4 +1537,4 @@ define i64 @fcmp_constant_to_rhs_olt(float %x) {
ret i64 %result
}
-; CHECK: attributes #4 = { convergent }
+; CHECK: attributes #5 = { convergent }
diff --git a/test/Transforms/InstCombine/and-or-not.ll b/test/Transforms/InstCombine/and-or-not.ll
index a2e8a10735fd..a8e32bd77f7f 100644
--- a/test/Transforms/InstCombine/and-or-not.ll
+++ b/test/Transforms/InstCombine/and-or-not.ll
@@ -496,31 +496,23 @@ define i32 @xor_to_xor12(float %fa, float %fb) {
ret i32 %xor
}
-; ~(~(a | b) | (a & b)) --> (a | b) & ~(a & b) -> a ^ b
+; https://bugs.llvm.org/show_bug.cgi?id=32830
+; Make sure we're matching operands correctly and not folding things wrongly.
-define i32 @demorgan_plus_and_to_xor(i32 %a, i32 %b) {
-; CHECK-LABEL: @demorgan_plus_and_to_xor(
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 %b, %a
-; CHECK-NEXT: ret i32 [[NOT]]
+define i64 @PR32830(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @PR32830(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i64 %a, -1
+; CHECK-NEXT: [[NOTB:%.*]] = xor i64 %b, -1
+; CHECK-NEXT: [[OR1:%.*]] = or i64 [[NOTB]], %a
+; CHECK-NEXT: [[OR2:%.*]] = or i64 [[NOTA]], %c
+; CHECK-NEXT: [[AND:%.*]] = and i64 [[OR1]], [[OR2]]
+; CHECK-NEXT: ret i64 [[AND]]
;
- %or = or i32 %b, %a
- %notor = xor i32 %or, -1
- %and = and i32 %b, %a
- %or2 = or i32 %and, %notor
- %not = xor i32 %or2, -1
- ret i32 %not
-}
-
-define <4 x i32> @demorgan_plus_and_to_xor_vec(<4 x i32> %a, <4 x i32> %b) {
-; CHECK-LABEL: @demorgan_plus_and_to_xor_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <4 x i32> %a, %b
-; CHECK-NEXT: ret <4 x i32> [[NOT]]
-;
- %or = or <4 x i32> %a, %b
- %notor = xor <4 x i32> %or, < i32 -1, i32 -1, i32 -1, i32 -1 >
- %and = and <4 x i32> %a, %b
- %or2 = or <4 x i32> %and, %notor
- %not = xor <4 x i32> %or2, < i32 -1, i32 -1, i32 -1, i32 -1 >
- ret <4 x i32> %not
+ %nota = xor i64 %a, -1
+ %notb = xor i64 %b, -1
+ %or1 = or i64 %notb, %a
+ %or2 = or i64 %nota, %c
+ %and = and i64 %or1, %or2
+ ret i64 %and
}
diff --git a/test/Transforms/InstCombine/and.ll b/test/Transforms/InstCombine/and.ll
index a2715c12fa88..8ef7870891f0 100644
--- a/test/Transforms/InstCombine/and.ll
+++ b/test/Transforms/InstCombine/and.ll
@@ -172,19 +172,6 @@ define i8 @test16(i8 %A) {
ret i8 %C
}
-;; ~(~X & Y) --> (X | ~Y)
-define i8 @test17(i8 %X, i8 %Y) {
-; CHECK-LABEL: @test17(
-; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 %Y, -1
-; CHECK-NEXT: [[D:%.*]] = or i8 [[Y_NOT]], %X
-; CHECK-NEXT: ret i8 [[D]]
-;
- %B = xor i8 %X, -1
- %C = and i8 %B, %Y
- %D = xor i8 %C, -1
- ret i8 %D
-}
-
define i1 @test18(i32 %A) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 %A, 127
diff --git a/test/Transforms/InstCombine/apint-and.ll b/test/Transforms/InstCombine/apint-and.ll
new file mode 100644
index 000000000000..f0381dfc2845
--- /dev/null
+++ b/test/Transforms/InstCombine/apint-and.ll
@@ -0,0 +1,126 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; FIXME: Some of these tests belong in InstSimplify.
+
+; Integer BitWidth <= 64 && BitWidth % 8 != 0.
+
+define i39 @test0(i39 %A) {
+; CHECK-LABEL: @test0(
+; CHECK-NEXT: ret i39 0
+;
+ %B = and i39 %A, 0 ; zero result
+ ret i39 %B
+}
+
+define i15 @test2(i15 %x) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: ret i15 %x
+;
+ %tmp.2 = and i15 %x, -1 ; noop
+ ret i15 %tmp.2
+}
+
+define i23 @test3(i23 %x) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: ret i23 0
+;
+ %tmp.0 = and i23 %x, 127
+ %tmp.2 = and i23 %tmp.0, 128
+ ret i23 %tmp.2
+}
+
+define i1 @test4(i37 %x) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[B:%.*]] = icmp ugt i37 %x, 2147483647
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %A = and i37 %x, -2147483648
+ %B = icmp ne i37 %A, 0
+ ret i1 %B
+}
+
+define i7 @test5(i7 %A, i7* %P) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[B:%.*]] = or i7 %A, 3
+; CHECK-NEXT: [[C:%.*]] = xor i7 [[B]], 12
+; CHECK-NEXT: store i7 [[C]], i7* %P, align 1
+; CHECK-NEXT: ret i7 3
+;
+ %B = or i7 %A, 3
+ %C = xor i7 %B, 12
+ store i7 %C, i7* %P
+ %r = and i7 %C, 3
+ ret i7 %r
+}
+
+define i47 @test7(i47 %A) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i47 %A, 39
+; CHECK-NEXT: ret i47 [[TMP1]]
+;
+ %X = ashr i47 %A, 39 ;; sign extend
+ %C1 = and i47 %X, 255
+ ret i47 %C1
+}
+
+; Integer BitWidth > 64 && BitWidth <= 1024.
+
+define i999 @test8(i999 %A) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: ret i999 0
+;
+ %B = and i999 %A, 0 ; zero result
+ ret i999 %B
+}
+
+define i1005 @test9(i1005 %x) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: ret i1005 %x
+;
+ %tmp.2 = and i1005 %x, -1 ; noop
+ ret i1005 %tmp.2
+}
+
+define i123 @test10(i123 %x) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: ret i123 0
+;
+ %tmp.0 = and i123 %x, 127
+ %tmp.2 = and i123 %tmp.0, 128
+ ret i123 %tmp.2
+}
+
+define i1 @test11(i737 %x) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[B:%.*]] = icmp ugt i737 %x, 2147483647
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %A = and i737 %x, -2147483648
+ %B = icmp ne i737 %A, 0
+ ret i1 %B
+}
+
+define i117 @test12(i117 %A, i117* %P) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[B:%.*]] = or i117 %A, 3
+; CHECK-NEXT: [[C:%.*]] = xor i117 [[B]], 12
+; CHECK-NEXT: store i117 [[C]], i117* %P, align 4
+; CHECK-NEXT: ret i117 3
+;
+ %B = or i117 %A, 3
+ %C = xor i117 %B, 12
+ store i117 %C, i117* %P
+ %r = and i117 %C, 3
+ ret i117 %r
+}
+
+define i1024 @test13(i1024 %A) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[TMP1:%.*]] = lshr i1024 %A, 1016
+; CHECK-NEXT: ret i1024 [[TMP1]]
+;
+ %X = ashr i1024 %A, 1016 ;; sign extend
+ %C1 = and i1024 %X, 255
+ ret i1024 %C1
+}
+
diff --git a/test/Transforms/InstCombine/apint-and1.ll b/test/Transforms/InstCombine/apint-and1.ll
deleted file mode 100644
index fcd2dcd23ad1..000000000000
--- a/test/Transforms/InstCombine/apint-and1.ll
+++ /dev/null
@@ -1,57 +0,0 @@
-; This test makes sure that and instructions are properly eliminated.
-; This test is for Integer BitWidth <= 64 && BitWidth % 8 != 0.
-
-; RUN: opt < %s -instcombine -S | not grep "and "
-; END.
-
-define i39 @test0(i39 %A) {
- %B = and i39 %A, 0 ; zero result
- ret i39 %B
-}
-
-define i47 @test1(i47 %A, i47 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i47 %A, -1
- %NotB = xor i47 %B, -1
- %C1 = and i47 %NotA, %NotB
- ret i47 %C1
-}
-
-define i15 @test2(i15 %x) {
- %tmp.2 = and i15 %x, -1 ; noop
- ret i15 %tmp.2
-}
-
-define i23 @test3(i23 %x) {
- %tmp.0 = and i23 %x, 127
- %tmp.2 = and i23 %tmp.0, 128
- ret i23 %tmp.2
-}
-
-define i1 @test4(i37 %x) {
- %A = and i37 %x, -2147483648
- %B = icmp ne i37 %A, 0
- ret i1 %B
-}
-
-define i7 @test5(i7 %A, i7* %P) {
- %B = or i7 %A, 3
- %C = xor i7 %B, 12
- store i7 %C, i7* %P
- %r = and i7 %C, 3
- ret i7 %r
-}
-
-define i7 @test6(i7 %A, i7 %B) {
- ;; ~(~X & Y) --> (X | ~Y)
- %t0 = xor i7 %A, -1
- %t1 = and i7 %t0, %B
- %r = xor i7 %t1, -1
- ret i7 %r
-}
-
-define i47 @test7(i47 %A) {
- %X = ashr i47 %A, 39 ;; sign extend
- %C1 = and i47 %X, 255
- ret i47 %C1
-}
diff --git a/test/Transforms/InstCombine/apint-and2.ll b/test/Transforms/InstCombine/apint-and2.ll
deleted file mode 100644
index 78dc8f990d08..000000000000
--- a/test/Transforms/InstCombine/apint-and2.ll
+++ /dev/null
@@ -1,82 +0,0 @@
-; This test makes sure that and instructions are properly eliminated.
-; This test is for Integer BitWidth > 64 && BitWidth <= 1024.
-
-; RUN: opt < %s -instcombine -S | not grep "and "
-; END.
-
-
-define i999 @test0(i999 %A) {
- %B = and i999 %A, 0 ; zero result
- ret i999 %B
-}
-
-define i477 @test1(i477 %A, i477 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i477 %A, -1
- %NotB = xor i477 %B, -1
- %C1 = and i477 %NotA, %NotB
- ret i477 %C1
-}
-
-define i129 @tst(i129 %A, i129 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i129 %A, -1
- %NotB = xor i129 %B, -1
- %C1 = and i129 %NotA, %NotB
- ret i129 %C1
-}
-
-define i65 @test(i65 %A, i65 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i65 %A, -1
- %NotB = xor i65 -1, %B
- %C1 = and i65 %NotA, %NotB
- ret i65 %C1
-}
-
-define i66 @tes(i66 %A, i66 %B) {
- ;; (~A & ~B) == (~(A | B)) - De Morgan's Law
- %NotA = xor i66 %A, -1
- %NotB = xor i66 %B, -1
- %C1 = and i66 %NotA, %NotB
- ret i66 %C1
-}
-
-define i1005 @test2(i1005 %x) {
- %tmp.2 = and i1005 %x, -1 ; noop
- ret i1005 %tmp.2
-}
-
-define i123 @test3(i123 %x) {
- %tmp.0 = and i123 %x, 127
- %tmp.2 = and i123 %tmp.0, 128
- ret i123 %tmp.2
-}
-
-define i1 @test4(i737 %x) {
- %A = and i737 %x, -2147483648
- %B = icmp ne i737 %A, 0
- ret i1 %B
-}
-
-define i117 @test5(i117 %A, i117* %P) {
- %B = or i117 %A, 3
- %C = xor i117 %B, 12
- store i117 %C, i117* %P
- %r = and i117 %C, 3
- ret i117 %r
-}
-
-define i117 @test6(i117 %A, i117 %B) {
- ;; ~(~X & Y) --> (X | ~Y)
- %t0 = xor i117 %A, -1
- %t1 = and i117 %t0, %B
- %r = xor i117 %t1, -1
- ret i117 %r
-}
-
-define i1024 @test7(i1024 %A) {
- %X = ashr i1024 %A, 1016 ;; sign extend
- %C1 = and i1024 %X, 255
- ret i1024 %C1
-}
diff --git a/test/Transforms/InstCombine/apint-not.ll b/test/Transforms/InstCombine/apint-not.ll
index 488b7f2c98e1..c5b12fd5dee5 100644
--- a/test/Transforms/InstCombine/apint-not.ll
+++ b/test/Transforms/InstCombine/apint-not.ll
@@ -15,28 +15,3 @@ define i1 @test2(i52 %A, i52 %B) {
ret i1 %Ret
}
-; Test that demorgans law can be instcombined
-define i47 @test3(i47 %A, i47 %B) {
- %a = xor i47 %A, -1
- %b = xor i47 %B, -1
- %c = and i47 %a, %b
- %d = xor i47 %c, -1
- ret i47 %d
-}
-
-; Test that demorgens law can work with constants
-define i61 @test4(i61 %A, i61 %B) {
- %a = xor i61 %A, -1
- %c = and i61 %a, 5 ; 5 = ~c2
- %d = xor i61 %c, -1
- ret i61 %d
-}
-
-; test the mirror of demorgans law...
-define i71 @test5(i71 %A, i71 %B) {
- %a = xor i71 %A, -1
- %b = xor i71 %B, -1
- %c = or i71 %a, %b
- %d = xor i71 %c, -1
- ret i71 %d
-}
diff --git a/test/Transforms/InstCombine/apint-or.ll b/test/Transforms/InstCombine/apint-or.ll
index e2312b61f2b9..33304bf8ad62 100644
--- a/test/Transforms/InstCombine/apint-or.ll
+++ b/test/Transforms/InstCombine/apint-or.ll
@@ -27,18 +27,6 @@ define i39 @test2(i39 %V, i39 %M) {
; CHECK-NEXT: ret i39 %A
}
-define i43 @test3(i43 %A, i43 %B) {
- ;; (~A | ~B) == (~(A & B)) - De Morgan's Law
- %NotA = xor i43 %A, -1
- %NotB = xor i43 %B, -1
- %C1 = or i43 %NotA, %NotB
- ret i43 %C1
-; CHECK-LABEL: @test3
-; CHECK-NEXT: %C1.demorgan = and i43 %A, %B
-; CHECK-NEXT: %C1 = xor i43 %C1.demorgan, -1
-; CHECK-NEXT: ret i43 %C1
-}
-
; These tests are for Integer BitWidth > 64 && BitWidth <= 1024.
define i1023 @test4(i1023 %A) {
;; A | ~A == -1
@@ -66,14 +54,3 @@ define i399 @test5(i399 %V, i399 %M) {
; CHECK-NEXT: ret i399 %A
}
-define i129 @test6(i129 %A, i129 %B) {
- ;; (~A | ~B) == (~(A & B)) - De Morgan's Law
- %NotA = xor i129 %A, -1
- %NotB = xor i129 %B, -1
- %C1 = or i129 %NotA, %NotB
- ret i129 %C1
-; CHECK-LABEL: @test6
-; CHECK-NEXT: %C1.demorgan = and i129 %A, %B
-; CHECK-NEXT: %C1 = xor i129 %C1.demorgan, -1
-; CHECK-NEXT: ret i129 %C1
-}
diff --git a/test/Transforms/InstCombine/assume2.ll b/test/Transforms/InstCombine/assume2.ll
index e8fbc049f41a..8dc8831fffa5 100644
--- a/test/Transforms/InstCombine/assume2.ll
+++ b/test/Transforms/InstCombine/assume2.ll
@@ -21,8 +21,8 @@ define i32 @test1(i32 %a) #0 {
define i32 @test2(i32 %a) #0 {
; CHECK-LABEL: @test2(
-; CHECK-NEXT: [[A_NOT:%.*]] = or i32 [[A:%.*]], -16
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A_NOT]], -6
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 10
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 2
;
@@ -50,8 +50,8 @@ define i32 @test3(i32 %a) #0 {
define i32 @test4(i32 %a) #0 {
; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[A_NOT:%.*]] = and i32 [[A:%.*]], 15
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A_NOT]], 10
+; CHECK-NEXT: [[V:%.*]] = or i32 [[A:%.*]], -16
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V]], -6
; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: ret i32 2
;
diff --git a/test/Transforms/InstCombine/demorgan-zext.ll b/test/Transforms/InstCombine/demorgan-zext.ll
deleted file mode 100644
index d537730ba9a6..000000000000
--- a/test/Transforms/InstCombine/demorgan-zext.ll
+++ /dev/null
@@ -1,81 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -instcombine -S | FileCheck %s
-
-; PR22723: Recognize De Morgan's Laws when obfuscated by zexts.
-
-define i32 @demorgan_or(i1 %X, i1 %Y) {
-; CHECK-LABEL: @demorgan_or(
-; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
-; CHECK-NEXT: [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
-; CHECK-NEXT: [[OR:%.*]] = zext i1 [[OR:%.*]]1 to i32
-; CHECK-NEXT: ret i32 [[OR]]
-;
- %zextX = zext i1 %X to i32
- %zextY = zext i1 %Y to i32
- %notX = xor i32 %zextX, 1
- %notY = xor i32 %zextY, 1
- %or = or i32 %notX, %notY
- ret i32 %or
-}
-
-define i32 @demorgan_and(i1 %X, i1 %Y) {
-; CHECK-LABEL: @demorgan_and(
-; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
-; CHECK-NEXT: [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
-; CHECK-NEXT: [[AND:%.*]] = zext i1 [[AND:%.*]]1 to i32
-; CHECK-NEXT: ret i32 [[AND]]
-;
- %zextX = zext i1 %X to i32
- %zextY = zext i1 %Y to i32
- %notX = xor i32 %zextX, 1
- %notY = xor i32 %zextY, 1
- %and = and i32 %notX, %notY
- ret i32 %and
-}
-
-define <2 x i32> @demorgan_or_vec(<2 x i1> %X, <2 x i1> %Y) {
-; CHECK-LABEL: @demorgan_or_vec(
-; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
-; CHECK-NEXT: [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
-; CHECK-NEXT: [[OR:%.*]] = zext <2 x i1> [[OR:%.*]]1 to <2 x i32>
-; CHECK-NEXT: ret <2 x i32> [[OR]]
-;
- %zextX = zext <2 x i1> %X to <2 x i32>
- %zextY = zext <2 x i1> %Y to <2 x i32>
- %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
- %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
- %or = or <2 x i32> %notX, %notY
- ret <2 x i32> %or
-}
-
-define <2 x i32> @demorgan_and_vec(<2 x i1> %X, <2 x i1> %Y) {
-; CHECK-LABEL: @demorgan_and_vec(
-; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
-; CHECK-NEXT: [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
-; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[AND:%.*]]1 to <2 x i32>
-; CHECK-NEXT: ret <2 x i32> [[AND]]
-;
- %zextX = zext <2 x i1> %X to <2 x i32>
- %zextY = zext <2 x i1> %Y to <2 x i32>
- %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
- %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
- %and = and <2 x i32> %notX, %notY
- ret <2 x i32> %and
-}
-
-define i32 @PR28476(i32 %x, i32 %y) {
-; CHECK-LABEL: @PR28476(
-; CHECK-NEXT: [[NOTLHS:%.*]] = icmp eq i32 %x, 0
-; CHECK-NEXT: [[NOTRHS:%.*]] = icmp eq i32 %y, 0
-; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[NOTRHS]], [[NOTLHS]]
-; CHECK-NEXT: [[COND:%.*]] = zext i1 [[TMP1]] to i32
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %cmp0 = icmp ne i32 %x, 0
- %cmp1 = icmp ne i32 %y, 0
- %and = and i1 %cmp0, %cmp1
- %zext = zext i1 %and to i32
- %cond = xor i32 %zext, 1
- ret i32 %cond
-}
-
diff --git a/test/Transforms/InstCombine/demorgan.ll b/test/Transforms/InstCombine/demorgan.ll
new file mode 100644
index 000000000000..26c2270a3fdf
--- /dev/null
+++ b/test/Transforms/InstCombine/demorgan.ll
@@ -0,0 +1,501 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+; (~A | ~B) == ~(A & B)
+
+define i43 @demorgan_or_apint1(i43 %A, i43 %B) {
+; CHECK-LABEL: @demorgan_or_apint1(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i43 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i43 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i43 [[C]]
+;
+ %NotA = xor i43 %A, -1
+ %NotB = xor i43 %B, -1
+ %C = or i43 %NotA, %NotB
+ ret i43 %C
+}
+
+; (~A | ~B) == ~(A & B)
+
+define i129 @demorgan_or_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_or_apint2(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i129 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i129 [[C]]
+;
+ %NotA = xor i129 %A, -1
+ %NotB = xor i129 %B, -1
+ %C = or i129 %NotA, %NotB
+ ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i477 @demorgan_and_apint1(i477 %A, i477 %B) {
+; CHECK-LABEL: @demorgan_and_apint1(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i477 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i477 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i477 [[C]]
+;
+ %NotA = xor i477 %A, -1
+ %NotB = xor i477 %B, -1
+ %C = and i477 %NotA, %NotB
+ ret i477 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i129 @demorgan_and_apint2(i129 %A, i129 %B) {
+; CHECK-LABEL: @demorgan_and_apint2(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i129 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i129 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i129 [[C]]
+;
+ %NotA = xor i129 %A, -1
+ %NotB = xor i129 %B, -1
+ %C = and i129 %NotA, %NotB
+ ret i129 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i65 @demorgan_and_apint3(i65 %A, i65 %B) {
+; CHECK-LABEL: @demorgan_and_apint3(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i65 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i65 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i65 [[C]]
+;
+ %NotA = xor i65 %A, -1
+ %NotB = xor i65 -1, %B
+ %C = and i65 %NotA, %NotB
+ ret i65 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i66 @demorgan_and_apint4(i66 %A, i66 %B) {
+; CHECK-LABEL: @demorgan_and_apint4(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i66 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i66 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i66 [[C]]
+;
+ %NotA = xor i66 %A, -1
+ %NotB = xor i66 %B, -1
+ %C = and i66 %NotA, %NotB
+ ret i66 %C
+}
+
+; (~A & ~B) == ~(A | B)
+
+define i47 @demorgan_and_apint5(i47 %A, i47 %B) {
+; CHECK-LABEL: @demorgan_and_apint5(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT: [[C:%.*]] = xor i47 [[C_DEMORGAN]], -1
+; CHECK-NEXT: ret i47 [[C]]
+;
+ %NotA = xor i47 %A, -1
+ %NotB = xor i47 %B, -1
+ %C = and i47 %NotA, %NotB
+ ret i47 %C
+}
+
+; This is confirming that 2 transforms work together:
+; ~(~A & ~B) --> A | B
+
+define i32 @test3(i32 %A, i32 %B) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i32 %A, %B
+; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
+;
+ %nota = xor i32 %A, -1
+ %notb = xor i32 %B, -1
+ %c = and i32 %nota, %notb
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Invert a constant if needed:
+; ~(~A & 5) --> A | ~5
+
+define i32 @test4(i32 %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[NOTC1:%.*]] = or i32 %A, -6
+; CHECK-NEXT: ret i32 [[NOTC1]]
+;
+ %nota = xor i32 %A, -1
+ %c = and i32 %nota, 5
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Test the mirror of DeMorgan's law with an extra 'not'.
+; ~(~A | ~B) --> A & B
+
+define i32 @test5(i32 %A, i32 %B) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i32 %A, %B
+; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
+;
+ %nota = xor i32 %A, -1
+ %notb = xor i32 %B, -1
+ %c = or i32 %nota, %notb
+ %notc = xor i32 %c, -1
+ ret i32 %notc
+}
+
+; Repeat with weird types for extra coverage.
+; ~(~A & ~B) --> A | B
+
+define i47 @test3_apint(i47 %A, i47 %B) {
+; CHECK-LABEL: @test3_apint(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i47 %A, %B
+; CHECK-NEXT: ret i47 [[C_DEMORGAN]]
+;
+ %nota = xor i47 %A, -1
+ %notb = xor i47 %B, -1
+ %c = and i47 %nota, %notb
+ %notc = xor i47 %c, -1
+ ret i47 %notc
+}
+
+; ~(~A & 5) --> A | ~5
+
+define i61 @test4_apint(i61 %A) {
+; CHECK-LABEL: @test4_apint(
+; CHECK-NEXT: [[NOTA:%.*]] = and i61 %A, 5
+; CHECK-NEXT: [[C:%.*]] = xor i61 [[NOTA]], 5
+; CHECK-NEXT: ret i61 [[C]]
+;
+ %nota = xor i61 %A, -1
+ %c = and i61 %nota, 5 ; 5 = ~c2
+ %notc = xor i61 %c, -1
+ ret i61 %c
+}
+
+; ~(~A | ~B) --> A & B
+
+define i71 @test5_apint(i71 %A, i71 %B) {
+; CHECK-LABEL: @test5_apint(
+; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i71 %A, %B
+; CHECK-NEXT: ret i71 [[C_DEMORGAN]]
+;
+ %nota = xor i71 %A, -1
+ %notb = xor i71 %B, -1
+ %c = or i71 %nota, %notb
+ %notc = xor i71 %c, -1
+ ret i71 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i8 @demorgan_nand(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nand(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i8 [[B_NOT]], %A
+; CHECK-NEXT: ret i8 [[NOTC]]
+;
+ %notx = xor i8 %A, -1
+ %c = and i8 %notx, %B
+ %notc = xor i8 %c, -1
+ ret i8 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i7 @demorgan_nand_apint1(i7 %A, i7 %B) {
+; CHECK-LABEL: @demorgan_nand_apint1(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i7 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i7 [[B_NOT]], %A
+; CHECK-NEXT: ret i7 [[NOTC]]
+;
+ %nota = xor i7 %A, -1
+ %c = and i7 %nota, %B
+ %notc = xor i7 %c, -1
+ ret i7 %notc
+}
+
+; ~(~A & B) --> (A | ~B)
+
+define i117 @demorgan_nand_apint2(i117 %A, i117 %B) {
+; CHECK-LABEL: @demorgan_nand_apint2(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i117 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = or i117 [[B_NOT]], %A
+; CHECK-NEXT: ret i117 [[NOTC]]
+;
+ %nota = xor i117 %A, -1
+ %c = and i117 %nota, %B
+ %notc = xor i117 %c, -1
+ ret i117 %notc
+}
+
+; ~(~A | B) --> (A & ~B)
+
+define i8 @demorgan_nor(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor(
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: ret i8 [[NOTC]]
+;
+ %notx = xor i8 %A, -1
+ %c = or i8 %notx, %B
+ %notc = xor i8 %c, -1
+ ret i8 %notc
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2a(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2a(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 23
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 23
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2a
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2b(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2b(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2b
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use one of the intermediate results?
+
+define i8 @demorgan_nor_use2c(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2c(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r = sdiv i8 %notc, %use2c
+ ret i8 %r
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ab(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ab(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT: [[B_NOT:%.*]] = xor i8 %B, -1
+; CHECK-NEXT: [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2B]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 17
+ %c = or i8 %nota, %B
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2b
+ %r2 = sdiv i8 %r1, %use2a
+ ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2ac(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2ac(
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[USE2A:%.*]] = mul i8 [[NOTA]], 17
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %nota = xor i8 %A, -1
+ %use2a = mul i8 %nota, 17
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2c
+ %r2 = sdiv i8 %r1, %use2a
+ ret i8 %r2
+}
+
+; ~(~A | B) --> (A & ~B) - what if we use two of the intermediate results?
+
+define i8 @demorgan_nor_use2bc(i8 %A, i8 %B) {
+; CHECK-LABEL: @demorgan_nor_use2bc(
+; CHECK-NEXT: [[USE2B:%.*]] = mul i8 %B, 23
+; CHECK-NEXT: [[NOTA:%.*]] = xor i8 %A, -1
+; CHECK-NEXT: [[C:%.*]] = or i8 [[NOTA]], %B
+; CHECK-NEXT: [[USE2C:%.*]] = mul i8 [[C]], 23
+; CHECK-NEXT: [[NOTC:%.*]] = xor i8 [[C]], -1
+; CHECK-NEXT: [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[R1]], [[USE2B]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %use2b = mul i8 %B, 23
+ %nota = xor i8 %A, -1
+ %c = or i8 %nota, %B
+ %use2c = mul i8 %c, 23
+ %notc = xor i8 %c, -1
+ %r1 = sdiv i8 %notc, %use2c
+ %r2 = sdiv i8 %r1, %use2b
+ ret i8 %r2
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant1(i32 %a) {
+; CHECK-LABEL: @demorganize_constant1(
+; CHECK-NEXT: [[AND:%.*]] = and i32 %a, 15
+; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT: ret i32 [[AND1]]
+;
+ %and = and i32 %a, 15
+ %and1 = xor i32 %and, -1
+ ret i32 %and1
+}
+
+; Do not apply DeMorgan's Law to constants. We prefer 'not' ops.
+
+define i32 @demorganize_constant2(i32 %a) {
+; CHECK-LABEL: @demorganize_constant2(
+; CHECK-NEXT: [[AND:%.*]] = or i32 %a, 15
+; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[AND]], -1
+; CHECK-NEXT: ret i32 [[AND1]]
+;
+ %and = or i32 %a, 15
+ %and1 = xor i32 %and, -1
+ ret i32 %and1
+}
+
+; PR22723: Recognize DeMorgan's Laws when obfuscated by zexts.
+
+define i32 @demorgan_or_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_or_zext(
+; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
+; CHECK-NEXT: [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
+; CHECK-NEXT: [[OR:%.*]] = zext i1 [[OR:%.*]]1 to i32
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %zextX = zext i1 %X to i32
+ %zextY = zext i1 %Y to i32
+ %notX = xor i32 %zextX, 1
+ %notY = xor i32 %zextY, 1
+ %or = or i32 %notX, %notY
+ ret i32 %or
+}
+
+define i32 @demorgan_and_zext(i1 %X, i1 %Y) {
+; CHECK-LABEL: @demorgan_and_zext(
+; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
+; CHECK-NEXT: [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
+; CHECK-NEXT: [[AND:%.*]] = zext i1 [[AND:%.*]]1 to i32
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %zextX = zext i1 %X to i32
+ %zextY = zext i1 %Y to i32
+ %notX = xor i32 %zextX, 1
+ %notY = xor i32 %zextY, 1
+ %and = and i32 %notX, %notY
+ ret i32 %and
+}
+
+define <2 x i32> @demorgan_or_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_or_zext_vec(
+; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
+; CHECK-NEXT: [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT: [[OR:%.*]] = zext <2 x i1> [[OR:%.*]]1 to <2 x i32>
+; CHECK-NEXT: ret <2 x i32> [[OR]]
+;
+ %zextX = zext <2 x i1> %X to <2 x i32>
+ %zextY = zext <2 x i1> %Y to <2 x i32>
+ %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
+ %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
+ %or = or <2 x i32> %notX, %notY
+ ret <2 x i32> %or
+}
+
+define <2 x i32> @demorgan_and_zext_vec(<2 x i1> %X, <2 x i1> %Y) {
+; CHECK-LABEL: @demorgan_and_zext_vec(
+; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
+; CHECK-NEXT: [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
+; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[AND:%.*]]1 to <2 x i32>
+; CHECK-NEXT: ret <2 x i32> [[AND]]
+;
+ %zextX = zext <2 x i1> %X to <2 x i32>
+ %zextY = zext <2 x i1> %Y to <2 x i32>
+ %notX = xor <2 x i32> %zextX, <i32 1, i32 1>
+ %notY = xor <2 x i32> %zextY, <i32 1, i32 1>
+ %and = and <2 x i32> %notX, %notY
+ ret <2 x i32> %and
+}
+
+define i32 @PR28476(i32 %x, i32 %y) {
+; CHECK-LABEL: @PR28476(
+; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i32 %x, 0
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 %y, 0
+; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT: [[COND:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %cmp0 = icmp ne i32 %x, 0
+ %cmp1 = icmp ne i32 %y, 0
+ %and = and i1 %cmp0, %cmp1
+ %zext = zext i1 %and to i32
+ %cond = xor i32 %zext, 1
+ ret i32 %cond
+}
+
+; ~(~(a | b) | (a & b)) --> (a | b) & ~(a & b) -> a ^ b
+
+define i32 @demorgan_plus_and_to_xor(i32 %a, i32 %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor(
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 %b, %a
+; CHECK-NEXT: ret i32 [[NOT]]
+;
+ %or = or i32 %b, %a
+ %notor = xor i32 %or, -1
+ %and = and i32 %b, %a
+ %or2 = or i32 %and, %notor
+ %not = xor i32 %or2, -1
+ ret i32 %not
+}
+
+define <4 x i32> @demorgan_plus_and_to_xor_vec(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @demorgan_plus_and_to_xor_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <4 x i32> %a, %b
+; CHECK-NEXT: ret <4 x i32> [[NOT]]
+;
+ %or = or <4 x i32> %a, %b
+ %notor = xor <4 x i32> %or, < i32 -1, i32 -1, i32 -1, i32 -1 >
+ %and = and <4 x i32> %a, %b
+ %or2 = or <4 x i32> %and, %notor
+ %not = xor <4 x i32> %or2, < i32 -1, i32 -1, i32 -1, i32 -1 >
+ ret <4 x i32> %not
+}
+
diff --git a/test/Transforms/InstCombine/not.ll b/test/Transforms/InstCombine/not.ll
index d0c242f65558..2760d4ae044d 100644
--- a/test/Transforms/InstCombine/not.ll
+++ b/test/Transforms/InstCombine/not.ll
@@ -31,45 +31,8 @@ define i1 @invert_fcmp(float %X, float %Y) {
ret i1 %not
}
-; Test that De Morgan's law can be instcombined.
-define i32 @test3(i32 %A, i32 %B) {
-; CHECK-LABEL: @test3(
-; CHECK-NEXT: [[C_DEMORGAN:%.*]] = or i32 %A, %B
-; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
-;
- %a = xor i32 %A, -1
- %b = xor i32 %B, -1
- %c = and i32 %a, %b
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
-; Test that De Morgan's law can work with constants.
-define i32 @test4(i32 %A, i32 %B) {
-; CHECK-LABEL: @test4(
-; CHECK-NEXT: [[D1:%.*]] = or i32 %A, -6
-; CHECK-NEXT: ret i32 [[D1]]
-;
- %a = xor i32 %A, -1
- %c = and i32 %a, 5
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
-; Test the mirror of De Morgan's law.
-define i32 @test5(i32 %A, i32 %B) {
-; CHECK-LABEL: @test5(
-; CHECK-NEXT: [[C_DEMORGAN:%.*]] = and i32 %A, %B
-; CHECK-NEXT: ret i32 [[C_DEMORGAN]]
-;
- %a = xor i32 %A, -1
- %b = xor i32 %B, -1
- %c = or i32 %a, %b
- %d = xor i32 %c, -1
- ret i32 %d
-}
-
; PR2298
+
define zeroext i8 @test6(i32 %a, i32 %b) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 %b, %a
diff --git a/test/Transforms/InstSimplify/shufflevector.ll b/test/Transforms/InstSimplify/shufflevector.ll
index e03916c5b90d..6af0db8e5a44 100644
--- a/test/Transforms/InstSimplify/shufflevector.ll
+++ b/test/Transforms/InstSimplify/shufflevector.ll
@@ -118,6 +118,14 @@ define <4 x i32> @undef_mask(<4 x i32> %x) {
ret <4 x i32> %shuf
}
+define <4 x i32> @undef_mask_1(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: @undef_mask_1(
+; CHECK-NEXT: ret <4 x i32> undef
+;
+ %shuf = shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> undef
+ ret <4 x i32> %shuf
+}
+
define <4 x i32> @identity_mask_0(<4 x i32> %x) {
; CHECK-LABEL: @identity_mask_0(
; CHECK-NEXT: ret <4 x i32> [[X:%.*]]
diff --git a/test/Transforms/JumpThreading/fold-not-thread.ll b/test/Transforms/JumpThreading/fold-not-thread.ll
index 75deca62f753..06ddc10e02b6 100644
--- a/test/Transforms/JumpThreading/fold-not-thread.ll
+++ b/test/Transforms/JumpThreading/fold-not-thread.ll
@@ -133,3 +133,114 @@ L3:
ret void
}
+; Make sure we can do the RAUW for %add...
+;
+; CHECK-LABEL: @rauw_if_possible(
+; CHECK: call void @f4(i32 96)
+define void @rauw_if_possible(i32 %value) nounwind {
+entry:
+ %cmp = icmp eq i32 %value, 32
+ br i1 %cmp, label %L0, label %L3
+L0:
+ call i32 @f2()
+ call i32 @f2()
+ %add = add i32 %value, 64
+ switch i32 %add, label %L3 [
+ i32 32, label %L1
+ i32 96, label %L2
+ ]
+
+L1:
+ call void @f3()
+ ret void
+L2:
+ call void @f4(i32 %add)
+ ret void
+L3:
+ call void @f3()
+ ret void
+}
+
+; Make sure we can NOT do the RAUW for %add...
+;
+; CHECK-LABEL: @rauw_if_possible2(
+; CHECK: call void @f4(i32 %add)
+define void @rauw_if_possible2(i32 %value) nounwind {
+entry:
+ %cmp = icmp eq i32 %value, 32
+ %add = add i32 %value, 64
+ br i1 %cmp, label %L0, label %L2
+L0:
+ call i32 @f2()
+ call i32 @f2()
+ switch i32 %add, label %L3 [
+ i32 32, label %L1
+ i32 96, label %L2
+ ]
+
+L1:
+ call void @f3()
+ ret void
+L2:
+ call void @f4(i32 %add)
+ ret void
+L3:
+ call void @f3()
+ ret void
+}
+
+; Make sure we can fold this branch ... We will not be able to thread it as
+; L0 is too big to duplicate.
+; We do not attempt to rewrite the indirectbr target here, but we still take
+; its target after L0 into account and that enables us to fold.
+;
+; L2 is the unreachable block here.
+;
+; CHECK-LABEL: @test_br_folding_not_threading_indirect_branch(
+; CHECK: L1:
+; CHECK: call i32 @f2()
+; CHECK: call void @f3()
+; CHECK-NEXT: ret void
+; CHECK-NOT: br
+; CHECK: L3:
+define void @test_br_folding_not_threading_indirect_branch(i1 %condx, i1 %cond) nounwind {
+entry:
+ br i1 %condx, label %X0, label %X1
+
+X0:
+ br i1 %cond, label %L0, label %L3
+
+X1:
+ br i1 %cond, label %XX1, label %L3
+
+XX1:
+ indirectbr i8* blockaddress(@test_br_folding_not_threading_indirect_branch, %L0), [label %L0]
+
+L0:
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ call i32 @f2()
+ br i1 %cond, label %L1, label %L2
+
+L1:
+ call void @f3()
+ ret void
+
+L2:
+ call void @f3()
+ ret void
+
+L3:
+ call void @f3()
+ ret void
+}
diff --git a/test/Transforms/LoopUnswitch/pr32818.ll b/test/Transforms/LoopUnswitch/pr32818.ll
new file mode 100644
index 000000000000..cda66c9dd361
--- /dev/null
+++ b/test/Transforms/LoopUnswitch/pr32818.ll
@@ -0,0 +1,19 @@
+; Check that the call doesn't get removed even if
+; it has no uses. It could have side-effects.
+; RUN: opt -loop-unswitch -S %s | FileCheck %s
+
+; CHECK-LABEL: @tinky
+define i32 @tinkywinky(i8 %patatino) {
+ %cmp1 = icmp slt i8 %patatino, 5
+ br label %body
+body:
+ %i = select i1 %cmp1, i8 6, i8 undef
+ br i1 true, label %body, label %end
+end:
+ %split = phi i8 [ %i, %body ]
+ %conv4 = sext i8 %split to i32
+; CHECK: tail call fastcc i32 @fn5(
+ %call = tail call fastcc i32 @fn5(i32 %conv4)
+ ret i32 0
+}
+declare fastcc i32 @fn5(i32 returned) unnamed_addr
diff --git a/test/Transforms/NewGVN/pr32852.ll b/test/Transforms/NewGVN/pr32852.ll
new file mode 100644
index 000000000000..1441d17361b0
--- /dev/null
+++ b/test/Transforms/NewGVN/pr32852.ll
@@ -0,0 +1,24 @@
+; Make sure GVN doesn't incorrectly think the branch terminating
+; bb2 has a constant condition.
+; RUN: opt -S -newgvn %s | FileCheck %s
+
+@a = common global i32 0
+@patatino = private unnamed_addr constant [3 x i8] c"0\0A\00"
+
+define void @tinkywinky() {
+bb:
+ %tmp = load i32, i32* @a
+ %tmp1 = icmp sge i32 %tmp, 0
+ br i1 %tmp1, label %bb2, label %bb7
+bb2:
+ %tmp4 = icmp sgt i32 %tmp, 0
+; CHECK: br i1 %tmp4, label %bb5, label %bb7
+ br i1 %tmp4, label %bb5, label %bb7
+bb5:
+ %tmp6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @patatino, i32 0, i32 0))
+ br label %bb7
+bb7:
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/test/Transforms/ObjCARC/rv.ll b/test/Transforms/ObjCARC/rv.ll
index 85a16127c6d9..e99ba92dc458 100644
--- a/test/Transforms/ObjCARC/rv.ll
+++ b/test/Transforms/ObjCARC/rv.ll
@@ -291,4 +291,29 @@ define {}* @test24(i8* %p) {
ret {}* %s
}
+declare i8* @first_test25();
+declare i8* @second_test25(i8*);
+declare void @somecall_test25();
+
+; ARC optimizer used to move the last release between the call to second_test25
+; and the call to objc_retainAutoreleasedReturnValue, causing %second to be
+; released prematurely when %first and %second were pointing to the same object.
+
+; CHECK-LABEL: define void @test25(
+; CHECK: %[[CALL1:.*]] = call i8* @second_test25(
+; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %[[CALL1]])
+
+define void @test25() {
+ %first = call i8* @first_test25()
+ %v0 = call i8* @objc_retain(i8* %first)
+ call void @somecall_test25()
+ %second = call i8* @second_test25(i8* %first)
+ %call2 = call i8* @objc_retainAutoreleasedReturnValue(i8* %second)
+ call void @objc_release(i8* %second), !clang.imprecise_release !0
+ call void @objc_release(i8* %first), !clang.imprecise_release !0
+ ret void
+}
+
+!0 = !{}
+
; CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/Transforms/PGOProfile/memop_size_opt_zero.ll b/test/Transforms/PGOProfile/memop_size_opt_zero.ll
new file mode 100644
index 000000000000..ede34f0de803
--- /dev/null
+++ b/test/Transforms/PGOProfile/memop_size_opt_zero.ll
@@ -0,0 +1,19 @@
+; Test to ensure the pgo memop optimization pass doesn't try to scale
+; up a value profile with a 0 count, which would lead to divide by 0.
+; RUN: opt < %s -passes=pgo-memop-opt -pgo-memop-count-threshold=1 -S | FileCheck %s --check-prefix=MEMOP_OPT
+; RUN: opt < %s -pgo-memop-opt -pgo-memop-count-threshold=1 -S | FileCheck %s --check-prefix=MEMOP_OPT
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo(i8* %dst, i8* %src, i64 %conv) !prof !0 {
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %conv, i32 1, i1 false), !prof !1
+ ret void
+}
+
+; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %conv, i32 1, i1 false), !prof !1
+
+!0 = !{!"function_entry_count", i64 1}
+!1 = !{!"VP", i32 1, i64 0, i64 1, i64 0, i64 2, i64 0, i64 3, i64 0, i64 9, i64 0, i64 4, i64 0, i64 5, i64 0, i64 6, i64 0, i64 7, i64 0, i64 8, i64 0}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1)
diff --git a/test/Transforms/SimpleLoopUnswitch/2006-06-13-SingleEntryPHI.ll b/test/Transforms/SimpleLoopUnswitch/2006-06-13-SingleEntryPHI.ll
new file mode 100644
index 000000000000..3b22687ca91e
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2006-06-13-SingleEntryPHI.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+
+ %struct.BLEND_MAP = type { i16, i16, i16, i32, %struct.BLEND_MAP_ENTRY* }
+ %struct.BLEND_MAP_ENTRY = type { float, i8, { [5 x float], [4 x i8] } }
+ %struct.TPATTERN = type { i16, i16, i16, i32, float, float, float, %struct.WARP*, %struct.TPATTERN*, %struct.BLEND_MAP*, { %struct.anon, [4 x i8] } }
+ %struct.TURB = type { i16, %struct.WARP*, [3 x double], i32, float, float }
+ %struct.WARP = type { i16, %struct.WARP* }
+ %struct.anon = type { float, [3 x double] }
+
+define void @Parse_Pattern() {
+entry:
+ br label %bb1096.outer20
+bb671: ; preds = %cond_true1099
+ br label %bb1096.outer23
+bb1096.outer20.loopexit: ; preds = %cond_true1099
+ %Local_Turb.0.ph24.lcssa = phi %struct.TURB* [ %Local_Turb.0.ph24, %cond_true1099 ] ; <%struct.TURB*> [#uses=1]
+ br label %bb1096.outer20
+bb1096.outer20: ; preds = %bb1096.outer20.loopexit, %entry
+ %Local_Turb.0.ph22 = phi %struct.TURB* [ undef, %entry ], [ %Local_Turb.0.ph24.lcssa, %bb1096.outer20.loopexit ] ; <%struct.TURB*> [#uses=1]
+ %tmp1098 = icmp eq i32 0, 0 ; <i1> [#uses=1]
+ br label %bb1096.outer23
+bb1096.outer23: ; preds = %bb1096.outer20, %bb671
+ %Local_Turb.0.ph24 = phi %struct.TURB* [ %Local_Turb.0.ph22, %bb1096.outer20 ], [ null, %bb671 ] ; <%struct.TURB*> [#uses=2]
+ br label %bb1096
+bb1096: ; preds = %cond_true1099, %bb1096.outer23
+ br i1 %tmp1098, label %cond_true1099, label %bb1102
+cond_true1099: ; preds = %bb1096
+ switch i32 0, label %bb1096.outer20.loopexit [
+ i32 161, label %bb671
+ i32 359, label %bb1096
+ ]
+bb1102: ; preds = %bb1096
+ %Local_Turb.0.ph24.lcssa1 = phi %struct.TURB* [ %Local_Turb.0.ph24, %bb1096 ] ; <%struct.TURB*> [#uses=0]
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2006-06-27-DeadSwitchCase.ll b/test/Transforms/SimpleLoopUnswitch/2006-06-27-DeadSwitchCase.ll
new file mode 100644
index 000000000000..04067eb05c8e
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2006-06-27-DeadSwitchCase.ll
@@ -0,0 +1,25 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+
+define void @init_caller_save() {
+entry:
+ br label %cond_true78
+cond_next20: ; preds = %cond_true64
+ br label %bb31
+bb31: ; preds = %cond_true64, %cond_true64, %cond_next20
+ %iftmp.29.1 = phi i32 [ 0, %cond_next20 ], [ 0, %cond_true64 ], [ 0, %cond_true64 ] ; <i32> [#uses=0]
+ br label %bb54
+bb54: ; preds = %cond_true78, %bb31
+ br i1 false, label %bb75, label %cond_true64
+cond_true64: ; preds = %bb54
+ switch i32 %i.0.0, label %cond_next20 [
+ i32 17, label %bb31
+ i32 18, label %bb31
+ ]
+bb75: ; preds = %bb54
+ %tmp74.0 = add i32 %i.0.0, 1 ; <i32> [#uses=1]
+ br label %cond_true78
+cond_true78: ; preds = %bb75, %entry
+ %i.0.0 = phi i32 [ 0, %entry ], [ %tmp74.0, %bb75 ] ; <i32> [#uses=2]
+ br label %bb54
+}
+
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-05-09-Unreachable.ll b/test/Transforms/SimpleLoopUnswitch/2007-05-09-Unreachable.ll
new file mode 100644
index 000000000000..4bbcc80ff3bb
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-05-09-Unreachable.ll
@@ -0,0 +1,28 @@
+; PR1333
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64"
+target triple = "i686-pc-linux-gnu"
+ %struct.ada__streams__root_stream_type = type { %struct.ada__tags__dispatch_table* }
+ %struct.ada__tags__dispatch_table = type { [1 x i8*] }
+ %struct.quotes__T173s = type { i8, %struct.quotes__T173s__T174s, [2 x [1 x double]], [2 x i16], i64, i8 }
+ %struct.quotes__T173s__T174s = type { i8, i8, i8, i16, i16, [2 x [1 x double]] }
+
+define void @quotes__write_quote() {
+entry:
+ %tmp606.i = icmp eq i32 0, 0 ; <i1> [#uses=1]
+ br label %bb
+bb: ; preds = %cond_next73, %bb, %entry
+ br i1 false, label %bb51, label %bb
+bb51: ; preds = %cond_next73, %bb
+ br i1 %tmp606.i, label %quotes__bid_ask_depth_offset_matrices__get_price.exit, label %cond_true.i
+cond_true.i: ; preds = %bb51
+ unreachable
+quotes__bid_ask_depth_offset_matrices__get_price.exit: ; preds = %bb51
+ br i1 false, label %cond_next73, label %cond_true72
+cond_true72: ; preds = %quotes__bid_ask_depth_offset_matrices__get_price.exit
+ unreachable
+cond_next73: ; preds = %quotes__bid_ask_depth_offset_matrices__get_price.exit
+ br i1 false, label %bb, label %bb51
+}
+
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-05-09-tl.ll b/test/Transforms/SimpleLoopUnswitch/2007-05-09-tl.ll
new file mode 100644
index 000000000000..835715264e1b
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-05-09-tl.ll
@@ -0,0 +1,95 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+; PR1333
+
+define void @pp_cxx_expression() {
+entry:
+ %tmp6 = lshr i32 0, 24 ; <i32> [#uses=1]
+ br label %tailrecurse
+
+tailrecurse: ; preds = %tailrecurse, %tailrecurse, %entry
+ switch i32 %tmp6, label %bb96 [
+ i32 24, label %bb10
+ i32 25, label %bb10
+ i32 28, label %bb10
+ i32 29, label %bb48
+ i32 31, label %bb48
+ i32 32, label %bb48
+ i32 33, label %bb48
+ i32 34, label %bb48
+ i32 36, label %bb15
+ i32 51, label %bb89
+ i32 52, label %bb89
+ i32 54, label %bb83
+ i32 57, label %bb59
+ i32 63, label %bb80
+ i32 64, label %bb80
+ i32 68, label %bb80
+ i32 169, label %bb75
+ i32 170, label %bb19
+ i32 171, label %bb63
+ i32 172, label %bb63
+ i32 173, label %bb67
+ i32 174, label %bb67
+ i32 175, label %bb19
+ i32 176, label %bb75
+ i32 178, label %bb59
+ i32 179, label %bb89
+ i32 180, label %bb59
+ i32 182, label %bb48
+ i32 183, label %bb48
+ i32 184, label %bb48
+ i32 185, label %bb48
+ i32 186, label %bb48
+ i32 195, label %bb48
+ i32 196, label %bb59
+ i32 197, label %bb89
+ i32 198, label %bb70
+ i32 199, label %bb59
+ i32 200, label %bb59
+ i32 201, label %bb59
+ i32 202, label %bb59
+ i32 203, label %bb75
+ i32 204, label %bb59
+ i32 205, label %tailrecurse
+ i32 210, label %tailrecurse
+ ]
+
+bb10: ; preds = %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb15: ; preds = %tailrecurse
+ ret void
+
+bb19: ; preds = %tailrecurse, %tailrecurse
+ ret void
+
+bb48: ; preds = %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb59: ; preds = %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb63: ; preds = %tailrecurse, %tailrecurse
+ ret void
+
+bb67: ; preds = %tailrecurse, %tailrecurse
+ ret void
+
+bb70: ; preds = %tailrecurse
+ ret void
+
+bb75: ; preds = %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb80: ; preds = %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb83: ; preds = %tailrecurse
+ ret void
+
+bb89: ; preds = %tailrecurse, %tailrecurse, %tailrecurse, %tailrecurse
+ ret void
+
+bb96: ; preds = %tailrecurse
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-07-12-ExitDomInfo.ll b/test/Transforms/SimpleLoopUnswitch/2007-07-12-ExitDomInfo.ll
new file mode 100644
index 000000000000..2a73a429c6ac
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-07-12-ExitDomInfo.ll
@@ -0,0 +1,45 @@
+; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output
+
+@str3 = external constant [3 x i8] ; <[3 x i8]*> [#uses=1]
+
+define i32 @stringSearch_Clib(i32 %count) {
+entry:
+ %ttmp25 = icmp sgt i32 %count, 0 ; <i1> [#uses=1]
+ br i1 %ttmp25, label %bb36.preheader, label %bb44
+
+bb36.preheader: ; preds = %entry
+ %ttmp33 = icmp slt i32 0, 250 ; <i1> [#uses=1]
+ br label %bb36.outer
+
+bb36.outer: ; preds = %bb41, %bb36.preheader
+ br i1 %ttmp33, label %bb.nph, label %bb41
+
+bb.nph: ; preds = %bb36.outer
+ %ttmp8 = icmp eq i8* null, null ; <i1> [#uses=1]
+ %ttmp6 = icmp eq i8* null, null ; <i1> [#uses=1]
+ %tmp31 = call i32 @strcspn( i8* null, i8* getelementptr ([3 x i8], [3 x i8]* @str3, i64 0, i64 0) ) ; <i32> [#uses=1]
+ br i1 %ttmp8, label %cond_next, label %cond_true
+
+cond_true: ; preds = %bb.nph
+ ret i32 0
+
+cond_next: ; preds = %bb.nph
+ br i1 %ttmp6, label %cond_next28, label %cond_true20
+
+cond_true20: ; preds = %cond_next
+ ret i32 0
+
+cond_next28: ; preds = %cond_next
+ %tmp33 = add i32 %tmp31, 0 ; <i32> [#uses=1]
+ br label %bb41
+
+bb41: ; preds = %cond_next28, %bb36.outer
+ %c.2.lcssa = phi i32 [ 0, %bb36.outer ], [ %tmp33, %cond_next28 ] ; <i32> [#uses=1]
+ br i1 false, label %bb36.outer, label %bb44
+
+bb44: ; preds = %bb41, %entry
+ %c.01.1 = phi i32 [ 0, %entry ], [ %c.2.lcssa, %bb41 ] ; <i32> [#uses=1]
+ ret i32 %c.01.1
+}
+
+declare i32 @strcspn(i8*, i8*)
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-07-13-DomInfo.ll b/test/Transforms/SimpleLoopUnswitch/2007-07-13-DomInfo.ll
new file mode 100644
index 000000000000..7299b2b1908b
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-07-13-DomInfo.ll
@@ -0,0 +1,27 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+
+define i32 @main(i32 %argc, i8** %argv) {
+entry:
+ %tmp1785365 = icmp ult i32 0, 100 ; <i1> [#uses=1]
+ br label %bb
+
+bb: ; preds = %cond_true, %entry
+ br i1 false, label %cond_true, label %cond_next
+
+cond_true: ; preds = %bb
+ br i1 %tmp1785365, label %bb, label %bb1788
+
+cond_next: ; preds = %bb
+ %iftmp.1.0 = select i1 false, i32 0, i32 0 ; <i32> [#uses=1]
+ br i1 false, label %cond_true47, label %cond_next74
+
+cond_true47: ; preds = %cond_next
+ %tmp53 = urem i32 %iftmp.1.0, 0 ; <i32> [#uses=0]
+ ret i32 0
+
+cond_next74: ; preds = %cond_next
+ ret i32 0
+
+bb1788: ; preds = %cond_true
+ ret i32 0
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-07-18-DomInfo.ll b/test/Transforms/SimpleLoopUnswitch/2007-07-18-DomInfo.ll
new file mode 100644
index 000000000000..e1ef5064a8fe
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-07-18-DomInfo.ll
@@ -0,0 +1,66 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+; PR1559
+
+target triple = "i686-pc-linux-gnu"
+ %struct.re_pattern_buffer = type { i8*, i32, i32, i32, i8*, i8*, i32, i8 }
+
+define fastcc i32 @byte_regex_compile(i8* %pattern, i32 %size, i32 %syntax, %struct.re_pattern_buffer* %bufp) {
+entry:
+ br i1 false, label %bb147, label %cond_next123
+
+cond_next123: ; preds = %entry
+ ret i32 0
+
+bb147: ; preds = %entry
+ switch i32 0, label %normal_char [
+ i32 91, label %bb1734
+ i32 92, label %bb5700
+ ]
+
+bb1734: ; preds = %bb147
+ br label %bb1855.outer.outer
+
+cond_true1831: ; preds = %bb1855.outer
+ br i1 %tmp1837, label %cond_next1844, label %cond_true1840
+
+cond_true1840: ; preds = %cond_true1831
+ ret i32 0
+
+cond_next1844: ; preds = %cond_true1831
+ br i1 false, label %bb1855.outer, label %cond_true1849
+
+cond_true1849: ; preds = %cond_next1844
+ br label %bb1855.outer.outer
+
+bb1855.outer.outer: ; preds = %cond_true1849, %bb1734
+ %b.10.ph.ph = phi i8* [ null, %cond_true1849 ], [ null, %bb1734 ] ; <i8*> [#uses=1]
+ br label %bb1855.outer
+
+bb1855.outer: ; preds = %bb1855.outer.outer, %cond_next1844
+ %b.10.ph = phi i8* [ null, %cond_next1844 ], [ %b.10.ph.ph, %bb1855.outer.outer ] ; <i8*> [#uses=1]
+ %tmp1837 = icmp eq i8* null, null ; <i1> [#uses=2]
+ br i1 false, label %cond_true1831, label %cond_next1915
+
+cond_next1915: ; preds = %cond_next1961, %bb1855.outer
+ store i8* null, i8** null
+ br i1 %tmp1837, label %cond_next1929, label %cond_true1923
+
+cond_true1923: ; preds = %cond_next1915
+ ret i32 0
+
+cond_next1929: ; preds = %cond_next1915
+ br i1 false, label %cond_next1961, label %cond_next2009
+
+cond_next1961: ; preds = %cond_next1929
+ %tmp1992 = getelementptr i8, i8* %b.10.ph, i32 0 ; <i8*> [#uses=0]
+ br label %cond_next1915
+
+cond_next2009: ; preds = %cond_next1929
+ ret i32 0
+
+bb5700: ; preds = %bb147
+ ret i32 0
+
+normal_char: ; preds = %bb147
+ ret i32 0
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-08-01-Dom.ll b/test/Transforms/SimpleLoopUnswitch/2007-08-01-Dom.ll
new file mode 100644
index 000000000000..52794891c568
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-08-01-Dom.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -licm -simple-loop-unswitch -disable-output
+; PR 1589
+
+ %struct.QBasicAtomic = type { i32 }
+
+define void @_ZNK5QDate9addMonthsEi(%struct.QBasicAtomic* sret %agg.result, %struct.QBasicAtomic* %this, i32 %nmonths) {
+entry:
+ br label %cond_true90
+
+bb16: ; preds = %cond_true90
+ br i1 false, label %bb93, label %cond_true90
+
+bb45: ; preds = %cond_true90
+ br i1 false, label %bb53, label %bb58
+
+bb53: ; preds = %bb45
+ br i1 false, label %bb93, label %cond_true90
+
+bb58: ; preds = %bb45
+ store i32 0, i32* null, align 4
+ br i1 false, label %cond_true90, label %bb93
+
+cond_true90: ; preds = %bb58, %bb53, %bb16, %entry
+ %nmonths_addr.016.1 = phi i32 [ %nmonths, %entry ], [ 0, %bb16 ], [ 0, %bb53 ], [ %nmonths_addr.016.1, %bb58 ] ; <i32> [#uses=2]
+ %tmp14 = icmp slt i32 %nmonths_addr.016.1, -11 ; <i1> [#uses=1]
+ br i1 %tmp14, label %bb16, label %bb45
+
+bb93: ; preds = %bb58, %bb53, %bb16
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-08-01-LCSSA.ll b/test/Transforms/SimpleLoopUnswitch/2007-08-01-LCSSA.ll
new file mode 100644
index 000000000000..cb65d2fb6446
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-08-01-LCSSA.ll
@@ -0,0 +1,55 @@
+; RUN: opt < %s -simple-loop-unswitch -instcombine -disable-output
+ %struct.ClassDef = type { %struct.QByteArray, %struct.QByteArray, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", i8, i8, %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", %"struct.QList<ArgumentDef>", %"struct.QMap<QByteArray,QByteArray>", i32, i32 }
+ %struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] }
+ %struct.Generator = type { %struct.FILE*, %struct.ClassDef*, %"struct.QList<ArgumentDef>", %struct.QByteArray, %"struct.QList<ArgumentDef>" }
+ %struct.QBasicAtomic = type { i32 }
+ %struct.QByteArray = type { %"struct.QByteArray::Data"* }
+ %"struct.QByteArray::Data" = type { %struct.QBasicAtomic, i32, i32, i8*, [1 x i8] }
+ %"struct.QList<ArgumentDef>" = type { %"struct.QList<ArgumentDef>::._19" }
+ %"struct.QList<ArgumentDef>::._19" = type { %struct.QListData }
+ %struct.QListData = type { %"struct.QListData::Data"* }
+ %"struct.QListData::Data" = type { %struct.QBasicAtomic, i32, i32, i32, i8, [1 x i8*] }
+ %"struct.QMap<QByteArray,QByteArray>" = type { %"struct.QMap<QByteArray,QByteArray>::._56" }
+ %"struct.QMap<QByteArray,QByteArray>::._56" = type { %struct.QMapData* }
+ %struct.QMapData = type { %struct.QMapData*, [12 x %struct.QMapData*], %struct.QBasicAtomic, i32, i32, i32, i8 }
+ %struct._IO_marker = type { %struct._IO_marker*, %struct.FILE*, i32 }
+@.str9 = external constant [1 x i8] ; <[1 x i8]*> [#uses=1]
+
+declare i32 @strcmp(i8*, i8*)
+
+define i32 @_ZN9Generator6strregEPKc(%struct.Generator* %this, i8* %s) {
+entry:
+ %s_addr.0 = select i1 false, i8* getelementptr ([1 x i8], [1 x i8]* @.str9, i32 0, i32 0), i8* %s ; <i8*> [#uses=2]
+ %tmp122 = icmp eq i8* %s_addr.0, null ; <i1> [#uses=1]
+ br label %bb184
+
+bb55: ; preds = %bb184
+ ret i32 0
+
+bb88: ; preds = %bb184
+ br i1 %tmp122, label %bb154, label %bb128
+
+bb128: ; preds = %bb88
+ %tmp138 = call i32 @strcmp( i8* null, i8* %s_addr.0 ) ; <i32> [#uses=1]
+ %iftmp.37.0.in4 = icmp eq i32 %tmp138, 0 ; <i1> [#uses=1]
+ br i1 %iftmp.37.0.in4, label %bb250, label %bb166
+
+bb154: ; preds = %bb88
+ br i1 false, label %bb250, label %bb166
+
+bb166: ; preds = %bb154, %bb128
+ %tmp175 = add i32 %idx.0, 1 ; <i32> [#uses=1]
+ %tmp177 = add i32 %tmp175, 0 ; <i32> [#uses=1]
+ %tmp181 = add i32 %tmp177, 0 ; <i32> [#uses=1]
+ %tmp183 = add i32 %i33.0, 1 ; <i32> [#uses=1]
+ br label %bb184
+
+bb184: ; preds = %bb166, %entry
+ %i33.0 = phi i32 [ 0, %entry ], [ %tmp183, %bb166 ] ; <i32> [#uses=2]
+ %idx.0 = phi i32 [ 0, %entry ], [ %tmp181, %bb166 ] ; <i32> [#uses=2]
+ %tmp49 = icmp slt i32 %i33.0, 0 ; <i1> [#uses=1]
+ br i1 %tmp49, label %bb88, label %bb55
+
+bb250: ; preds = %bb154, %bb128
+ ret i32 %idx.0
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2007-10-04-DomFrontier.ll b/test/Transforms/SimpleLoopUnswitch/2007-10-04-DomFrontier.ll
new file mode 100644
index 000000000000..efbb7619591e
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2007-10-04-DomFrontier.ll
@@ -0,0 +1,29 @@
+; RUN: opt < %s -licm -loop-unroll -disable-output
+
+@resonant = external global i32 ; <i32*> [#uses=2]
+
+define void @weightadj() {
+entry:
+ br label %bb
+
+bb: ; preds = %bb158, %entry
+ store i32 0, i32* @resonant, align 4
+ br i1 false, label %g.exit, label %bb158
+
+g.exit: ; preds = %bb68, %bb
+ br i1 false, label %bb68, label %cond_true
+
+cond_true: ; preds = %g.exit
+ store i32 1, i32* @resonant, align 4
+ br label %bb68
+
+bb68: ; preds = %cond_true, %g.exit
+ %tmp71 = icmp slt i32 0, 0 ; <i1> [#uses=1]
+ br i1 %tmp71, label %g.exit, label %bb158
+
+bb158: ; preds = %bb68, %bb
+ br i1 false, label %bb, label %return
+
+return: ; preds = %bb158
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2008-06-02-DomInfo.ll b/test/Transforms/SimpleLoopUnswitch/2008-06-02-DomInfo.ll
new file mode 100644
index 000000000000..5b3ca9c187d1
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2008-06-02-DomInfo.ll
@@ -0,0 +1,26 @@
+; RUN: opt < %s -simple-loop-unswitch -instcombine -gvn -disable-output
+; PR2372
+target triple = "i386-pc-linux-gnu"
+
+define i32 @func_3(i16 signext %p_5, i16 signext %p_6) nounwind {
+entry:
+ %tmp3 = icmp eq i16 %p_5, 0 ; <i1> [#uses=1]
+ %tmp1314 = sext i16 %p_6 to i32 ; <i32> [#uses=1]
+ %tmp28 = icmp ugt i32 %tmp1314, 3 ; <i1> [#uses=1]
+ %bothcond = or i1 %tmp28, false ; <i1> [#uses=1]
+ br label %bb
+bb: ; preds = %bb54, %entry
+ br i1 %tmp3, label %bb54, label %bb5
+bb5: ; preds = %bb
+ br i1 %bothcond, label %bb54, label %bb31
+bb31: ; preds = %bb5
+ br label %bb54
+bb54: ; preds = %bb31, %bb5, %bb
+ br i1 false, label %bb64, label %bb
+bb64: ; preds = %bb54
+ %tmp6566 = sext i16 %p_6 to i32 ; <i32> [#uses=1]
+ %tmp68 = tail call i32 (...) @func_18( i32 1, i32 %tmp6566, i32 1 ) nounwind ; <i32> [#uses=0]
+ ret i32 undef
+}
+
+declare i32 @func_18(...)
diff --git a/test/Transforms/SimpleLoopUnswitch/2008-06-17-DomFrontier.ll b/test/Transforms/SimpleLoopUnswitch/2008-06-17-DomFrontier.ll
new file mode 100644
index 000000000000..e309d60a3e43
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2008-06-17-DomFrontier.ll
@@ -0,0 +1,22 @@
+; RUN: opt < %s -licm -simple-loop-unswitch -disable-output
+@g_56 = external global i16 ; <i16*> [#uses=2]
+
+define i32 @func_67(i32 %p_68, i8 signext %p_69, i8 signext %p_71) nounwind {
+entry:
+ br label %bb
+bb: ; preds = %bb44, %entry
+ br label %bb3
+bb3: ; preds = %bb36, %bb
+ %bothcond = or i1 false, false ; <i1> [#uses=1]
+ br i1 %bothcond, label %bb29, label %bb19
+bb19: ; preds = %bb3
+ br i1 false, label %bb36, label %bb29
+bb29: ; preds = %bb19, %bb3
+ ret i32 0
+bb36: ; preds = %bb19
+ store i16 0, i16* @g_56, align 2
+ br i1 false, label %bb44, label %bb3
+bb44: ; preds = %bb44, %bb36
+ %tmp46 = load i16, i16* @g_56, align 2 ; <i16> [#uses=0]
+ br i1 false, label %bb, label %bb44
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2010-11-18-LCSSA.ll b/test/Transforms/SimpleLoopUnswitch/2010-11-18-LCSSA.ll
new file mode 100644
index 000000000000..9f71417df8ed
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2010-11-18-LCSSA.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -simple-loop-unswitch
+; PR8622
+@g_38 = external global i32, align 4
+
+define void @func_67(i32 %p_68.coerce) nounwind {
+entry:
+ br i1 true, label %for.end12, label %bb.nph
+
+bb.nph: ; preds = %entry
+ %g_38.promoted = load i32, i32* @g_38
+ br label %for.body
+
+for.body: ; preds = %for.cond, %bb.nph
+ %tobool.i = icmp eq i32 %p_68.coerce, 1
+ %xor4.i = xor i32 %p_68.coerce, 1
+ %call1 = select i1 %tobool.i, i32 0, i32 %xor4.i
+ br label %for.cond
+
+for.cond: ; preds = %for.body
+ br i1 true, label %for.cond.for.end12_crit_edge, label %for.body
+
+for.cond.for.end12_crit_edge: ; preds = %for.cond
+ store i32 %call1, i32* @g_38
+ br label %for.end12
+
+for.end12: ; preds = %for.cond.for.end12_crit_edge, %entry
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2011-06-02-CritSwitch.ll b/test/Transforms/SimpleLoopUnswitch/2011-06-02-CritSwitch.ll
new file mode 100644
index 000000000000..8c13e1854c99
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2011-06-02-CritSwitch.ll
@@ -0,0 +1,28 @@
+; RUN: opt -simple-loop-unswitch -disable-output < %s
+; PR10031
+
+define i32 @test(i32 %command) {
+entry:
+ br label %tailrecurse
+
+tailrecurse: ; preds = %if.then14, %tailrecurse, %entry
+ br i1 undef, label %if.then, label %tailrecurse
+
+if.then: ; preds = %tailrecurse
+ switch i32 %command, label %sw.bb [
+ i32 2, label %land.lhs.true
+ i32 0, label %land.lhs.true
+ ]
+
+land.lhs.true: ; preds = %if.then, %if.then
+ br i1 undef, label %sw.bb, label %if.then14
+
+if.then14: ; preds = %land.lhs.true
+ switch i32 %command, label %tailrecurse [
+ i32 0, label %sw.bb
+ i32 1, label %sw.bb
+ ]
+
+sw.bb: ; preds = %if.then14
+ unreachable
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2011-09-26-EHCrash.ll b/test/Transforms/SimpleLoopUnswitch/2011-09-26-EHCrash.ll
new file mode 100644
index 000000000000..6b7d9faf70f4
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2011-09-26-EHCrash.ll
@@ -0,0 +1,63 @@
+; RUN: opt < %s -sroa -simple-loop-unswitch -disable-output
+; PR11016
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-apple-macosx10.7.2"
+
+%class.MyContainer.1.3.19.29 = type { [6 x %class.MyMemVarClass.0.2.18.28*] }
+%class.MyMemVarClass.0.2.18.28 = type { i32 }
+
+define void @_ZN11MyContainer1fEi(%class.MyContainer.1.3.19.29* %this, i32 %doit) uwtable ssp align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %inc1 = phi i32 [ %inc, %for.inc ], [ 0, %entry ]
+ %conv = sext i32 %inc1 to i64
+ %cmp = icmp ult i64 %conv, 6
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %tobool = icmp ne i32 %doit, 0
+ br i1 %tobool, label %for.inc, label %if.then
+
+if.then: ; preds = %for.body
+ %idxprom = sext i32 %inc1 to i64
+ %array_ = getelementptr inbounds %class.MyContainer.1.3.19.29, %class.MyContainer.1.3.19.29* %this, i32 0, i32 0
+ %arrayidx = getelementptr inbounds [6 x %class.MyMemVarClass.0.2.18.28*], [6 x %class.MyMemVarClass.0.2.18.28*]* %array_, i32 0, i64 %idxprom
+ %tmp4 = load %class.MyMemVarClass.0.2.18.28*, %class.MyMemVarClass.0.2.18.28** %arrayidx, align 8
+ %isnull = icmp eq %class.MyMemVarClass.0.2.18.28* %tmp4, null
+ br i1 %isnull, label %for.inc, label %delete.notnull
+
+delete.notnull: ; preds = %if.then
+ invoke void @_ZN13MyMemVarClassD1Ev(%class.MyMemVarClass.0.2.18.28* %tmp4)
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont: ; preds = %delete.notnull
+ %0 = bitcast %class.MyMemVarClass.0.2.18.28* %tmp4 to i8*
+ call void @_ZdlPv(i8* %0) nounwind
+ br label %for.inc
+
+lpad: ; preds = %delete.notnull
+ %1 = landingpad { i8*, i32 }
+ cleanup
+ %2 = extractvalue { i8*, i32 } %1, 0
+ %3 = extractvalue { i8*, i32 } %1, 1
+ %4 = bitcast %class.MyMemVarClass.0.2.18.28* %tmp4 to i8*
+ call void @_ZdlPv(i8* %4) nounwind
+ %lpad.val = insertvalue { i8*, i32 } undef, i8* %2, 0
+ %lpad.val7 = insertvalue { i8*, i32 } %lpad.val, i32 %3, 1
+ resume { i8*, i32 } %lpad.val7
+
+for.inc: ; preds = %invoke.cont, %if.then, %for.body
+ %inc = add nsw i32 %inc1, 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
+
+declare void @_ZN13MyMemVarClassD1Ev(%class.MyMemVarClass.0.2.18.28*)
+
+declare i32 @__gxx_personality_v0(...)
+
+declare void @_ZdlPv(i8*) nounwind
diff --git a/test/Transforms/SimpleLoopUnswitch/2012-04-02-IndirectBr.ll b/test/Transforms/SimpleLoopUnswitch/2012-04-02-IndirectBr.ll
new file mode 100644
index 000000000000..133f41744a96
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2012-04-02-IndirectBr.ll
@@ -0,0 +1,41 @@
+; RUN: opt < %s -S -simple-loop-unswitch -verify-loop-info -verify-dom-info | FileCheck %s
+; PR12343: -simple-loop-unswitch crash on indirect branch
+
+; CHECK: %0 = icmp eq i64 undef, 0
+; CHECK-NEXT: br i1 %0, label %"5", label %"4"
+
+; CHECK: "5": ; preds = %entry
+; CHECK-NEXT: br label %"16"
+
+; CHECK: "16": ; preds = %"22", %"5"
+; CHECK-NEXT: indirectbr i8* undef, [label %"22", label %"33"]
+
+; CHECK: "22": ; preds = %"16"
+; CHECK-NEXT: br i1 %0, label %"16", label %"26"
+
+; CHECK: "26": ; preds = %"22"
+; CHECK-NEXT: unreachable
+
+define void @foo() {
+entry:
+ %0 = icmp eq i64 undef, 0
+ br i1 %0, label %"5", label %"4"
+
+"4": ; preds = %entry
+ unreachable
+
+"5": ; preds = %entry
+ br label %"16"
+
+"16": ; preds = %"22", %"5"
+ indirectbr i8* undef, [label %"22", label %"33"]
+
+"22": ; preds = %"16"
+ br i1 %0, label %"16", label %"26"
+
+"26": ; preds = %"22"
+ unreachable
+
+"33": ; preds = %"16"
+ unreachable
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2012-04-30-LoopUnswitch-LPad-Crash.ll b/test/Transforms/SimpleLoopUnswitch/2012-04-30-LoopUnswitch-LPad-Crash.ll
new file mode 100644
index 000000000000..8f05e58b8ebb
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2012-04-30-LoopUnswitch-LPad-Crash.ll
@@ -0,0 +1,97 @@
+; RUN: opt < %s -basicaa -instcombine -inline -functionattrs -licm -simple-loop-unswitch -gvn -verify
+; PR12573
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.7.0"
+
+%class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379 = type { %class.C.23.43.67.103.139.159.179.199.239.243.247.251.263.295.303.339.347.376*, %class.B.21.41.65.101.137.157.177.197.237.241.245.249.261.293.301.337.345.378 }
+%class.C.23.43.67.103.139.159.179.199.239.243.247.251.263.295.303.339.347.376 = type { %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* }
+%class.B.21.41.65.101.137.157.177.197.237.241.245.249.261.293.301.337.345.378 = type { %class.A.20.40.64.100.136.156.176.196.236.240.244.248.260.292.300.336.344.377* }
+%class.A.20.40.64.100.136.156.176.196.236.240.244.248.260.292.300.336.344.377 = type { i8 }
+
+define void @_Z23get_reconstruction_pathv() uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ %c = alloca %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379, align 8
+ br label %for.cond
+
+for.cond: ; preds = %for.end, %entry
+ invoke void @_ZN1DptEv(%class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* %c)
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont: ; preds = %for.cond
+ invoke void @_ZN1C3endEv()
+ to label %for.cond3 unwind label %lpad
+
+for.cond3: ; preds = %invoke.cont6, %invoke.cont
+ invoke void @_ZN1DptEv(%class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* %c)
+ to label %invoke.cont4 unwind label %lpad
+
+invoke.cont4: ; preds = %for.cond3
+ invoke void @_ZN1C3endEv()
+ to label %invoke.cont6 unwind label %lpad
+
+invoke.cont6: ; preds = %invoke.cont4
+ br i1 undef, label %for.cond3, label %for.end
+
+lpad: ; preds = %for.end, %invoke.cont4, %for.cond3, %invoke.cont, %for.cond
+ %0 = landingpad { i8*, i32 }
+ cleanup
+ resume { i8*, i32 } undef
+
+for.end: ; preds = %invoke.cont6
+ invoke void @_ZN1C13_M_insert_auxER1D()
+ to label %for.cond unwind label %lpad
+}
+
+define void @_ZN1DptEv(%class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* %this) uwtable ssp align 2 {
+entry:
+ %this.addr = alloca %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379*, align 8
+ store %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* %this, %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379** %this.addr, align 8
+ %this1 = load %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379*, %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379** %this.addr
+ %px = getelementptr inbounds %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379, %class.D.22.42.66.102.138.158.178.198.238.242.246.250.262.294.302.338.346.379* %this1, i32 0, i32 0
+ %0 = load %class.C.23.43.67.103.139.159.179.199.239.243.247.251.263.295.303.339.347.376*, %class.C.23.43.67.103.139.159.179.199.239.243.247.251.263.295.303.339.347.376** %px, align 8
+ %tobool = icmp ne %class.C.23.43.67.103.139.159.179.199.239.243.247.251.263.295.303.339.347.376* %0, null
+ br i1 %tobool, label %cond.end, label %cond.false
+
+cond.false: ; preds = %entry
+ call void @_Z10__assert13v() noreturn
+ unreachable
+
+cond.end: ; preds = %entry
+ ret void
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+declare void @_ZN1C3endEv()
+
+define void @_ZN1C13_M_insert_auxER1D() uwtable ssp align 2 {
+entry:
+ ret void
+}
+
+define void @_ZN1DD1Ev() unnamed_addr uwtable inlinehint ssp align 2 {
+entry:
+ ret void
+}
+
+define void @_ZN1DD2Ev() unnamed_addr uwtable inlinehint ssp align 2 {
+entry:
+ ret void
+}
+
+define void @_ZN1BD1Ev() unnamed_addr uwtable ssp align 2 {
+entry:
+ ret void
+}
+
+define void @_ZN1BD2Ev() unnamed_addr uwtable ssp align 2 {
+entry:
+ ret void
+}
+
+define void @_ZN1BaSERS_() uwtable ssp align 2 {
+entry:
+ unreachable
+}
+
+declare void @_Z10__assert13v() noreturn
diff --git a/test/Transforms/SimpleLoopUnswitch/2012-05-20-Phi.ll b/test/Transforms/SimpleLoopUnswitch/2012-05-20-Phi.ll
new file mode 100644
index 000000000000..e5549fe92f9a
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2012-05-20-Phi.ll
@@ -0,0 +1,25 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+; PR12887
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@a = common global i32 0, align 4
+@c = common global i32 0, align 4
+@b = common global i32 0, align 4
+
+define void @func() noreturn nounwind uwtable {
+entry:
+ %0 = load i32, i32* @a, align 4
+ %tobool = icmp eq i32 %0, 0
+ %1 = load i32, i32* @b, align 4
+ br label %while.body
+
+while.body: ; preds = %while.body, %entry
+ %d.0 = phi i8 [ undef, %entry ], [ %conv2, %while.body ]
+ %conv = sext i8 %d.0 to i32
+ %cond = select i1 %tobool, i32 0, i32 %conv
+ %conv11 = zext i8 %d.0 to i32
+ %add = add i32 %1, %conv11
+ %conv2 = trunc i32 %add to i8
+ br label %while.body
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/2015-09-18-Addrspace.ll b/test/Transforms/SimpleLoopUnswitch/2015-09-18-Addrspace.ll
new file mode 100644
index 000000000000..ddb888af8ba9
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/2015-09-18-Addrspace.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s
+
+; In cases where two address spaces do not have the same size pointer, the
+; input for the addrspacecast should not be used as a substitute for itself
+; when manipulating the pointer.
+
+target datalayout = "e-m:e-p:16:16-p1:32:16-i32:16-i64:16-n8:16"
+
+define void @foo() {
+; CHECK-LABEL: @foo
+entry:
+ %arrayidx.i1 = getelementptr inbounds i16, i16* undef, i16 undef
+ %arrayidx.i = addrspacecast i16* %arrayidx.i1 to i16 addrspace(1)*
+ br i1 undef, label %for.body.i, label %bar.exit
+
+for.body.i: ; preds = %for.body.i, %entry
+; When we call makeLoopInvariant (i.e. trivial LICM) on this load, it
+; will try to find the base object to prove deferenceability. If we look
+; through the addrspacecast, we'll fail an assertion about bitwidths matching
+; CHECK-LABEL: for.body.i
+; CHECK: %0 = load i16, i16 addrspace(1)* %arrayidx.i, align 2
+ %0 = load i16, i16 addrspace(1)* %arrayidx.i, align 2
+ %cmp1.i = icmp eq i16 %0, 0
+ br i1 %cmp1.i, label %bar.exit, label %for.body.i
+
+bar.exit: ; preds = %for.body.i, %entry
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll b/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll
new file mode 100644
index 000000000000..cbee0fef14bd
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/LIV-loop-condtion.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -simple-loop-unswitch -S 2>&1 | FileCheck %s
+
+; This is to test trivial loop unswitch only happens when trivial condition
+; itself is an LIV loop condition (not partial LIV which could occur in and/or).
+
+define i32 @test(i1 %cond1, i32 %var1) {
+entry:
+ br label %loop_begin
+
+loop_begin:
+ %var3 = phi i32 [%var1, %entry], [%var2, %do_something]
+ %cond2 = icmp eq i32 %var3, 10
+ %cond.and = and i1 %cond1, %cond2
+
+; %cond.and only has %cond1 as LIV so no unswitch should happen.
+; CHECK: br i1 %cond.and, label %do_something, label %loop_exit
+ br i1 %cond.and, label %do_something, label %loop_exit
+
+do_something:
+ %var2 = add i32 %var3, 1
+ call void @some_func() noreturn nounwind
+ br label %loop_begin
+
+loop_exit:
+ ret i32 0
+}
+
+declare void @some_func() noreturn
diff --git a/test/Transforms/SimpleLoopUnswitch/basictest.ll b/test/Transforms/SimpleLoopUnswitch/basictest.ll
new file mode 100644
index 000000000000..afca20fe2518
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/basictest.ll
@@ -0,0 +1,184 @@
+; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
+
+define i32 @test(i32* %A, i1 %C) {
+entry:
+ br label %no_exit
+no_exit: ; preds = %no_exit.backedge, %entry
+ %i.0.0 = phi i32 [ 0, %entry ], [ %i.0.0.be, %no_exit.backedge ] ; <i32> [#uses=3]
+ %gep.upgrd.1 = zext i32 %i.0.0 to i64 ; <i64> [#uses=1]
+ %tmp.7 = getelementptr i32, i32* %A, i64 %gep.upgrd.1 ; <i32*> [#uses=4]
+ %tmp.13 = load i32, i32* %tmp.7 ; <i32> [#uses=2]
+ %tmp.14 = add i32 %tmp.13, 1 ; <i32> [#uses=1]
+ store i32 %tmp.14, i32* %tmp.7
+ br i1 %C, label %then, label %endif
+then: ; preds = %no_exit
+ %tmp.29 = load i32, i32* %tmp.7 ; <i32> [#uses=1]
+ %tmp.30 = add i32 %tmp.29, 2 ; <i32> [#uses=1]
+ store i32 %tmp.30, i32* %tmp.7
+ %inc9 = add i32 %i.0.0, 1 ; <i32> [#uses=2]
+ %tmp.112 = icmp ult i32 %inc9, 100000 ; <i1> [#uses=1]
+ br i1 %tmp.112, label %no_exit.backedge, label %return
+no_exit.backedge: ; preds = %endif, %then
+ %i.0.0.be = phi i32 [ %inc9, %then ], [ %inc, %endif ] ; <i32> [#uses=1]
+ br label %no_exit
+endif: ; preds = %no_exit
+ %inc = add i32 %i.0.0, 1 ; <i32> [#uses=2]
+ %tmp.1 = icmp ult i32 %inc, 100000 ; <i1> [#uses=1]
+ br i1 %tmp.1, label %no_exit.backedge, label %return
+return: ; preds = %endif, %then
+ ret i32 %tmp.13
+}
+
+; This simple test would normally unswitch, but should be inhibited by the presence of
+; the noduplicate call.
+
+; CHECK-LABEL: @test2(
+define i32 @test2(i32* %var) {
+ %mem = alloca i32
+ store i32 2, i32* %mem
+ %c = load i32, i32* %mem
+
+ br label %loop_begin
+
+loop_begin:
+
+ %var_val = load i32, i32* %var
+
+ switch i32 %c, label %default [
+ i32 1, label %inc
+ i32 2, label %dec
+ ]
+
+inc:
+ call void @incf() noreturn nounwind
+ br label %loop_begin
+dec:
+; CHECK: call void @decf()
+; CHECK-NOT: call void @decf()
+ call void @decf() noreturn nounwind noduplicate
+ br label %loop_begin
+default:
+ br label %loop_exit
+loop_exit:
+ ret i32 0
+; CHECK: }
+}
+
+; This simple test would normally unswitch, but should be inhibited by the presence of
+; the convergent call that is not control-dependent on the unswitch condition.
+
+; CHECK-LABEL: @test3(
+define i32 @test3(i32* %var) {
+ %mem = alloca i32
+ store i32 2, i32* %mem
+ %c = load i32, i32* %mem
+
+ br label %loop_begin
+
+loop_begin:
+
+ %var_val = load i32, i32* %var
+
+; CHECK: call void @conv()
+; CHECK-NOT: call void @conv()
+ call void @conv() convergent
+
+ switch i32 %c, label %default [
+ i32 1, label %inc
+ i32 2, label %dec
+ ]
+
+inc:
+ call void @incf() noreturn nounwind
+ br label %loop_begin
+dec:
+ call void @decf() noreturn nounwind
+ br label %loop_begin
+default:
+ br label %loop_exit
+loop_exit:
+ ret i32 0
+; CHECK: }
+}
+
+; Make sure we don't unswitch, as we can not find an input value %a
+; that will effectively unswitch 0 or 3 out of the loop.
+;
+; CHECK: define void @and_or_i2_as_switch_input(i2
+; CHECK: entry:
+; This is an indication that the loop has NOT been unswitched.
+; CHECK-NOT: icmp
+; CHECK: br
+define void @and_or_i2_as_switch_input(i2 %a) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i2 [ 0, %entry ], [ %inc, %for.inc ]
+ %and = and i2 %a, %i
+ %or = or i2 %and, %i
+ switch i2 %or, label %sw.default [
+ i2 0, label %sw.bb
+ i2 3, label %sw.bb1
+ ]
+
+sw.bb:
+ br label %sw.epilog
+
+sw.bb1:
+ br label %sw.epilog
+
+sw.default:
+ br label %sw.epilog
+
+sw.epilog:
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i2 %i, 1
+ %cmp = icmp slt i2 %inc, 3
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+; Make sure we don't unswitch, as we can not find an input value %a
+; that will effectively unswitch true/false out of the loop.
+;
+; CHECK: define void @and_or_i1_as_branch_input(i1
+; CHECK: entry:
+; This is an indication that the loop has NOT been unswitched.
+; CHECK-NOT: icmp
+; CHECK: br
+define void @and_or_i1_as_branch_input(i1 %a) {
+entry:
+ br label %for.body
+
+for.body:
+ %i = phi i1 [ 0, %entry ], [ %inc, %for.inc ]
+ %and = and i1 %a, %i
+ %or = or i1 %and, %i
+ br i1 %or, label %sw.bb, label %sw.bb1
+
+sw.bb:
+ br label %sw.epilog
+
+sw.bb1:
+ br label %sw.epilog
+
+sw.epilog:
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i1 %i, 1
+ %cmp = icmp slt i1 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+declare void @incf() noreturn
+declare void @decf() noreturn
+declare void @conv() convergent
diff --git a/test/Transforms/SimpleLoopUnswitch/cleanuppad.ll b/test/Transforms/SimpleLoopUnswitch/cleanuppad.ll
new file mode 100644
index 000000000000..8ab23cb1f61c
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/cleanuppad.ll
@@ -0,0 +1,44 @@
+; RUN: opt -S -simple-loop-unswitch < %s | FileCheck %s
+target triple = "x86_64-pc-win32"
+
+define void @f(i32 %doit, i1 %x, i1 %y) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ %tobool = icmp eq i32 %doit, 0
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ br i1 %x, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ br i1 %tobool, label %if.then, label %for.inc
+
+if.then: ; preds = %for.body
+ br i1 %y, label %for.inc, label %delete.notnull
+
+delete.notnull: ; preds = %if.then
+ invoke void @g()
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont: ; preds = %delete.notnull
+ br label %for.inc
+
+lpad: ; preds = %delete.notnull
+ %cp = cleanuppad within none []
+ cleanupret from %cp unwind to caller
+
+for.inc: ; preds = %invoke.cont, %if.then, %for.body
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
+
+declare void @g()
+
+declare i32 @__CxxFrameHandler3(...)
+
+; CHECK-LABEL: define void @f(
+; CHECK: cleanuppad within none []
+; CHECK-NOT: cleanuppad
+
+attributes #0 = { ssp uwtable }
diff --git a/test/Transforms/SimpleLoopUnswitch/copy-metadata.ll b/test/Transforms/SimpleLoopUnswitch/copy-metadata.ll
new file mode 100644
index 000000000000..7085ed8e10fe
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/copy-metadata.ll
@@ -0,0 +1,34 @@
+; RUN: opt < %s -simple-loop-unswitch -S | FileCheck %s
+
+; This test checks if unswitched condition preserve make.implicit metadata.
+define i32 @test(i1 %cond) {
+; CHECK-LABEL: @test(
+entry:
+ br label %loop_begin
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 %{{.*}}, label %entry.split, label %loop_exit, !make.implicit !0
+;
+; CHECK: entry.split:
+; CHECK-NEXT: br label %loop_begin
+
+loop_begin:
+ br i1 %cond, label %continue, label %loop_exit, !make.implicit !0
+; CHECK: loop_begin:
+; CHECK-NEXT: br label %continue
+
+continue:
+ call void @some_func()
+ br label %loop_begin
+; CHECK: continue:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_begin
+
+loop_exit:
+ ret i32 0
+; CHECK: loop_exit:
+; CHECK-NEXT: ret
+}
+
+declare void @some_func()
+
+!0 = !{}
diff --git a/test/Transforms/SimpleLoopUnswitch/crash.ll b/test/Transforms/SimpleLoopUnswitch/crash.ll
new file mode 100644
index 000000000000..a6c64113c08f
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/crash.ll
@@ -0,0 +1,66 @@
+; RUN: opt < %s -simple-loop-unswitch -disable-output
+
+define void @test1(i32* %S2) {
+entry:
+ br i1 false, label %list_Length.exit, label %cond_true.i
+cond_true.i: ; preds = %entry
+ ret void
+list_Length.exit: ; preds = %entry
+ br i1 false, label %list_Length.exit9, label %cond_true.i5
+cond_true.i5: ; preds = %list_Length.exit
+ ret void
+list_Length.exit9: ; preds = %list_Length.exit
+ br i1 false, label %bb78, label %return
+bb44: ; preds = %bb78, %cond_next68
+ br i1 %tmp49.not, label %bb62, label %bb62.loopexit
+bb62.loopexit: ; preds = %bb44
+ br label %bb62
+bb62: ; preds = %bb62.loopexit, %bb44
+ br i1 false, label %return.loopexit, label %cond_next68
+cond_next68: ; preds = %bb62
+ br i1 false, label %return.loopexit, label %bb44
+bb78: ; preds = %list_Length.exit9
+ %tmp49.not = icmp eq i32* %S2, null ; <i1> [#uses=1]
+ br label %bb44
+return.loopexit: ; preds = %cond_next68, %bb62
+ %retval.0.ph = phi i32 [ 1, %cond_next68 ], [ 0, %bb62 ] ; <i32> [#uses=1]
+ br label %return
+return: ; preds = %return.loopexit, %list_Length.exit9
+ %retval.0 = phi i32 [ 0, %list_Length.exit9 ], [ %retval.0.ph, %return.loopexit ] ; <i32> [#uses=0]
+ ret void
+}
+
+define void @test2() nounwind {
+entry:
+ br label %bb.nph
+
+bb.nph: ; preds = %entry
+ %and.i13521 = and <4 x i1> undef, undef ; <<4 x i1>> [#uses=1]
+ br label %for.body
+
+for.body: ; preds = %for.body, %bb.nph
+ %or.i = select <4 x i1> %and.i13521, <4 x i32> undef, <4 x i32> undef ; <<4 x i32>> [#uses=0]
+ br i1 false, label %for.body, label %for.end
+
+for.end: ; preds = %for.body, %entry
+ ret void
+}
+
+; PR6879
+define i32* @test3(i32** %p_45, i16 zeroext %p_46, i64 %p_47, i64 %p_48, i16 signext %p_49) nounwind {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.cond4, %entry
+ br i1 false, label %for.cond4, label %for.end88
+
+for.cond4: ; preds = %for.cond
+ %conv46 = trunc i32 0 to i8 ; <i8> [#uses=2]
+ %cmp60 = icmp sgt i8 %conv46, 124 ; <i1> [#uses=1]
+ %or.cond = and i1 undef, %cmp60 ; <i1> [#uses=1]
+ %cond = select i1 %or.cond, i8 %conv46, i8 undef ; <i8> [#uses=0]
+ br label %for.cond
+
+for.end88: ; preds = %for.cond
+ ret i32* undef
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/exponential-behavior.ll b/test/Transforms/SimpleLoopUnswitch/exponential-behavior.ll
new file mode 100644
index 000000000000..52e9aa1acc2b
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/exponential-behavior.ll
@@ -0,0 +1,51 @@
+; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s
+
+define void @f(i32 %n, i32* %ptr) {
+; CHECK-LABEL: @f(
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
+ %iv.inc = add i32 %iv, 1
+ %unswitch_cond_root = icmp ne i32 %iv.inc, 42
+ %us.0 = and i1 %unswitch_cond_root, %unswitch_cond_root
+ %us.1 = and i1 %us.0, %us.0
+ %us.2 = and i1 %us.1, %us.1
+ %us.3 = and i1 %us.2, %us.2
+ %us.4 = and i1 %us.3, %us.3
+ %us.5 = and i1 %us.4, %us.4
+ %us.6 = and i1 %us.5, %us.5
+ %us.7 = and i1 %us.6, %us.6
+ %us.8 = and i1 %us.7, %us.7
+ %us.9 = and i1 %us.8, %us.8
+ %us.10 = and i1 %us.9, %us.9
+ %us.11 = and i1 %us.10, %us.10
+ %us.12 = and i1 %us.11, %us.11
+ %us.13 = and i1 %us.12, %us.12
+ %us.14 = and i1 %us.13, %us.13
+ %us.15 = and i1 %us.14, %us.14
+ %us.16 = and i1 %us.15, %us.15
+ %us.17 = and i1 %us.16, %us.16
+ %us.18 = and i1 %us.17, %us.17
+ %us.19 = and i1 %us.18, %us.18
+ %us.20 = and i1 %us.19, %us.19
+ %us.21 = and i1 %us.20, %us.20
+ %us.22 = and i1 %us.21, %us.21
+ %us.23 = and i1 %us.22, %us.22
+ %us.24 = and i1 %us.23, %us.23
+ %us.25 = and i1 %us.24, %us.24
+ %us.26 = and i1 %us.25, %us.25
+ %us.27 = and i1 %us.26, %us.26
+ %us.28 = and i1 %us.27, %us.27
+ %us.29 = and i1 %us.28, %us.28
+ br i1 %us.29, label %leave, label %be
+
+be:
+ store volatile i32 0, i32* %ptr
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/infinite-loop.ll b/test/Transforms/SimpleLoopUnswitch/infinite-loop.ll
new file mode 100644
index 000000000000..9164fd247838
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/infinite-loop.ll
@@ -0,0 +1,64 @@
+; REQUIRES: asserts
+; RUN: opt -simple-loop-unswitch -disable-output -stats -info-output-file - < %s | FileCheck --check-prefix=STATS %s
+; RUN: opt -simple-loop-unswitch -S < %s | FileCheck %s
+; PR5373
+
+; Loop unswitching shouldn't trivially unswitch the true case of condition %a
+; in the code here because it leads to an infinite loop. While this doesn't
+; contain any instructions with side effects, it's still a kind of side effect.
+; It can trivially unswitch on the false cas of condition %a though.
+
+; STATS: 2 simple-loop-unswitch - Number of branches unswitched
+; STATS: 2 simple-loop-unswitch - Number of unswitches that are trivial
+
+; CHECK-LABEL: @func_16(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 %a, label %entry.split, label %abort0
+
+; CHECK: entry.split:
+; CHECK-NEXT: br i1 %b, label %entry.split.split, label %abort1
+
+; CHECK: entry.split.split:
+; CHECK-NEXT: br label %for.body
+
+; CHECK: for.body:
+; CHECK-NEXT: br label %cond.end
+
+; CHECK: cond.end:
+; CHECK-NEXT: br label %for.body
+
+; CHECK: abort0:
+; CHECK-NEXT: call void @end0() [[NOR_NUW:#[0-9]+]]
+; CHECK-NEXT: unreachable
+
+; CHECK: abort1:
+; CHECK-NEXT: call void @end1() [[NOR_NUW]]
+; CHECK-NEXT: unreachable
+
+; CHECK: }
+
+define void @func_16(i1 %a, i1 %b) nounwind {
+entry:
+ br label %for.body
+
+for.body:
+ br i1 %a, label %cond.end, label %abort0
+
+cond.end:
+ br i1 %b, label %for.body, label %abort1
+
+abort0:
+ call void @end0() noreturn nounwind
+ unreachable
+
+abort1:
+ call void @end1() noreturn nounwind
+ unreachable
+}
+
+declare void @end0() noreturn
+declare void @end1() noreturn
+
+; CHECK: attributes #0 = { nounwind }
+; CHECK: attributes #1 = { noreturn }
+; CHECK: attributes [[NOR_NUW]] = { noreturn nounwind }
diff --git a/test/Transforms/SimpleLoopUnswitch/msan.ll b/test/Transforms/SimpleLoopUnswitch/msan.ll
new file mode 100644
index 000000000000..ec1110ac9d66
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/msan.ll
@@ -0,0 +1,141 @@
+; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
+
+declare void @unknown()
+declare void @unknown2()
+
+@y = global i64 0, align 8
+
+; The following is approximately:
+; void f(bool *x) {
+; for (int i = 0; i < 1; ++i) {
+; if (*x) {
+; if (y)
+; unknown();
+; else
+; break;
+; }
+; }
+; }
+; With MemorySanitizer, the loop can not be unswitched on "y", because "y" could
+; be uninitialized when x == false.
+; Test that the branch on "y" is inside the loop (after the first unconditional
+; branch).
+
+define void @may_not_execute_trivial(i1* %x) sanitize_memory {
+; CHECK-LABEL: @may_not_execute_trivial(
+entry:
+ %y = load i64, i64* @y, align 8
+ %y.cmp = icmp eq i64 %y, 0
+ br label %for.body
+; CHECK: %[[Y:.*]] = load i64, i64* @y
+; CHECK: %[[YCMP:.*]] = icmp eq i64 %[[Y]], 0
+; CHECK-NOT: br i1
+; CHECK: br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ %x.load = load i1, i1* %x
+ br i1 %x.load, label %for.inc, label %if.then
+; CHECK: %[[XLOAD:.*]] = load i1, i1* %x
+; CHECK: br i1 %[[XLOAD]]
+
+if.then:
+ br i1 %y.cmp, label %for.end, label %if.then4
+; CHECK: br i1 %[[YCMP]]
+
+if.then4:
+ call void @unknown()
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+
+; The same as above, but "y" is a function parameter instead of a global.
+; This shows that it is not enough to suppress hoisting of load instructions,
+; the actual problem is in the speculative branching.
+
+define void @may_not_execute2_trivial(i1* %x, i1 %y) sanitize_memory {
+; CHECK-LABEL: @may_not_execute2_trivial(
+entry:
+ br label %for.body
+; CHECK-NOT: br i1
+; CHECK: br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ %x.load = load i1, i1* %x
+ br i1 %x.load, label %for.inc, label %if.then
+; CHECK: %[[XLOAD:.*]] = load i1, i1* %x
+; CHECK: br i1 %[[XLOAD]]
+
+if.then:
+ br i1 %y, label %for.end, label %if.then4
+; CHECK: br i1 %y
+
+if.then4:
+ call void @unknown()
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+
+; The following is approximately:
+; void f() {
+; for (int i = 0; i < 1; ++i) {
+; if (y)
+; unknown();
+; else
+; break;
+; }
+; }
+; "if (y)" is guaranteed to execute; the loop can be unswitched.
+
+define void @must_execute_trivial() sanitize_memory {
+; CHECK-LABEL: @must_execute_trivial(
+entry:
+ %y = load i64, i64* @y, align 8
+ %y.cmp = icmp eq i64 %y, 0
+ br label %for.body
+; CHECK: %[[Y:.*]] = load i64, i64* @y
+; CHECK: %[[YCMP:.*]] = icmp eq i64 %[[Y]], 0
+; CHECK: br i1 %[[YCMP]], label %[[EXIT_SPLIT:.*]], label %[[PH:.*]]
+;
+; CHECK: [[PH]]:
+; CHECK: br label %for.body
+
+for.body:
+ %i = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ br i1 %y.cmp, label %for.end, label %if.then4
+; CHECK: br label %if.then4
+
+if.then4:
+ call void @unknown()
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+; CHECK: for.end:
+; CHECK: br label %[[EXIT_SPLIT]]
+;
+; CHECK: [[EXIT_SPLIT]]:
+; CHECK: ret void
+}
diff --git a/test/Transforms/SimpleLoopUnswitch/preserve-analyses.ll b/test/Transforms/SimpleLoopUnswitch/preserve-analyses.ll
new file mode 100644
index 000000000000..76b41e73ede5
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/preserve-analyses.ll
@@ -0,0 +1,129 @@
+; RUN: opt -simple-loop-unswitch -verify-loop-info -verify-dom-info -disable-output < %s
+
+; Loop unswitch should be able to unswitch these loops and
+; preserve LCSSA and LoopSimplify forms.
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:64"
+target triple = "armv6-apple-darwin9"
+
+@delim1 = external global i32 ; <i32*> [#uses=1]
+@delim2 = external global i32 ; <i32*> [#uses=1]
+
+define i32 @ineqn(i8* %s, i8* %p) nounwind readonly {
+entry:
+ %0 = load i32, i32* @delim1, align 4 ; <i32> [#uses=1]
+ %1 = load i32, i32* @delim2, align 4 ; <i32> [#uses=1]
+ br label %bb8.outer
+
+bb: ; preds = %bb8
+ %2 = icmp eq i8* %p_addr.0, %s ; <i1> [#uses=1]
+ br i1 %2, label %bb10, label %bb2
+
+bb2: ; preds = %bb
+ %3 = getelementptr inbounds i8, i8* %p_addr.0, i32 1 ; <i8*> [#uses=3]
+ switch i32 %ineq.0.ph, label %bb8.backedge [
+ i32 0, label %bb3
+ i32 1, label %bb6
+ ]
+
+bb8.backedge: ; preds = %bb6, %bb5, %bb2
+ br label %bb8
+
+bb3: ; preds = %bb2
+ %4 = icmp eq i32 %8, %0 ; <i1> [#uses=1]
+ br i1 %4, label %bb8.outer.loopexit, label %bb5
+
+bb5: ; preds = %bb3
+ br i1 %6, label %bb6, label %bb8.backedge
+
+bb6: ; preds = %bb5, %bb2
+ %5 = icmp eq i32 %8, %1 ; <i1> [#uses=1]
+ br i1 %5, label %bb7, label %bb8.backedge
+
+bb7: ; preds = %bb6
+ %.lcssa1 = phi i8* [ %3, %bb6 ] ; <i8*> [#uses=1]
+ br label %bb8.outer.backedge
+
+bb8.outer.backedge: ; preds = %bb8.outer.loopexit, %bb7
+ %.lcssa2 = phi i8* [ %.lcssa1, %bb7 ], [ %.lcssa, %bb8.outer.loopexit ] ; <i8*> [#uses=1]
+ %ineq.0.ph.be = phi i32 [ 0, %bb7 ], [ 1, %bb8.outer.loopexit ] ; <i32> [#uses=1]
+ br label %bb8.outer
+
+bb8.outer.loopexit: ; preds = %bb3
+ %.lcssa = phi i8* [ %3, %bb3 ] ; <i8*> [#uses=1]
+ br label %bb8.outer.backedge
+
+bb8.outer: ; preds = %bb8.outer.backedge, %entry
+ %ineq.0.ph = phi i32 [ 0, %entry ], [ %ineq.0.ph.be, %bb8.outer.backedge ] ; <i32> [#uses=3]
+ %p_addr.0.ph = phi i8* [ %p, %entry ], [ %.lcssa2, %bb8.outer.backedge ] ; <i8*> [#uses=1]
+ %6 = icmp eq i32 %ineq.0.ph, 1 ; <i1> [#uses=1]
+ br label %bb8
+
+bb8: ; preds = %bb8.outer, %bb8.backedge
+ %p_addr.0 = phi i8* [ %p_addr.0.ph, %bb8.outer ], [ %3, %bb8.backedge ] ; <i8*> [#uses=3]
+ %7 = load i8, i8* %p_addr.0, align 1 ; <i8> [#uses=2]
+ %8 = sext i8 %7 to i32 ; <i32> [#uses=2]
+ %9 = icmp eq i8 %7, 0 ; <i1> [#uses=1]
+ br i1 %9, label %bb10, label %bb
+
+bb10: ; preds = %bb8, %bb
+ %.0 = phi i32 [ %ineq.0.ph, %bb ], [ 0, %bb8 ] ; <i32> [#uses=1]
+ ret i32 %.0
+}
+
+; This is a simplified form of ineqn from above. It triggers some
+; different cases in the loop-unswitch code.
+
+define void @simplified_ineqn() nounwind readonly {
+entry:
+ br label %bb8.outer
+
+bb8.outer: ; preds = %bb6, %bb2, %entry
+ %x = phi i32 [ 0, %entry ], [ 0, %bb6 ], [ 1, %bb2 ] ; <i32> [#uses=1]
+ br i1 undef, label %return, label %bb2
+
+bb2: ; preds = %bb
+ switch i32 %x, label %bb6 [
+ i32 0, label %bb8.outer
+ ]
+
+bb6: ; preds = %bb2
+ br i1 undef, label %bb8.outer, label %bb2
+
+return: ; preds = %bb8, %bb
+ ret void
+}
+
+; This function requires special handling to preserve LCSSA form.
+; PR4934
+
+define void @pnp_check_irq() nounwind noredzone {
+entry:
+ %conv56 = trunc i64 undef to i32 ; <i32> [#uses=1]
+ br label %while.cond.i
+
+while.cond.i: ; preds = %while.cond.i.backedge, %entry
+ %call.i25 = call i8* @pci_get_device() nounwind noredzone ; <i8*> [#uses=2]
+ br i1 undef, label %if.then65, label %while.body.i
+
+while.body.i: ; preds = %while.cond.i
+ br i1 undef, label %if.then31.i.i, label %while.cond.i.backedge
+
+while.cond.i.backedge: ; preds = %if.then31.i.i, %while.body.i
+ br label %while.cond.i
+
+if.then31.i.i: ; preds = %while.body.i
+ switch i32 %conv56, label %while.cond.i.backedge [
+ i32 14, label %if.then42.i.i
+ i32 15, label %if.then42.i.i
+ ]
+
+if.then42.i.i: ; preds = %if.then31.i.i, %if.then31.i.i
+ %call.i25.lcssa48 = phi i8* [ %call.i25, %if.then31.i.i ], [ %call.i25, %if.then31.i.i ] ; <i8*> [#uses=0]
+ unreachable
+
+if.then65: ; preds = %while.cond.i
+ unreachable
+}
+
+declare i8* @pci_get_device() noredzone
diff --git a/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll b/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll
new file mode 100644
index 000000000000..42b4f3dea75b
--- /dev/null
+++ b/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll
@@ -0,0 +1,185 @@
+; RUN: opt -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s
+
+declare void @some_func() noreturn
+
+; This test contains two trivial unswitch condition in one loop.
+; LoopUnswitch pass should be able to unswitch the second one
+; after unswitching the first one.
+define i32 @test1(i32* %var, i1 %cond1, i1 %cond2) {
+; CHECK-LABEL: @test1(
+entry:
+ br label %loop_begin
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 %{{.*}}, label %entry.split, label %loop_exit.split
+;
+; CHECK: entry.split:
+; CHECK-NEXT: br i1 %{{.*}}, label %entry.split.split, label %loop_exit
+;
+; CHECK: entry.split.split:
+; CHECK-NEXT: br label %loop_begin
+
+loop_begin:
+ br i1 %cond1, label %continue, label %loop_exit ; first trivial condition
+; CHECK: loop_begin:
+; CHECK-NEXT: br label %continue
+
+continue:
+ %var_val = load i32, i32* %var
+ br i1 %cond2, label %do_something, label %loop_exit ; second trivial condition
+; CHECK: continue:
+; CHECK-NEXT: load
+; CHECK-NEXT: br label %do_something
+
+do_something:
+ call void @some_func() noreturn nounwind
+ br label %loop_begin
+; CHECK: do_something:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_begin
+
+loop_exit:
+ ret i32 0
+; CHECK: loop_exit:
+; CHECK-NEXT: br label %loop_exit.split
+;
+; CHECK: loop_exit.split:
+; CHECK-NEXT: ret
+}
+
+; Test for two trivially unswitchable switches.
+define i32 @test3(i32* %var, i32 %cond1, i32 %cond2) {
+; CHECK-LABEL: @test3(
+entry:
+ br label %loop_begin
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 %cond1, label %entry.split [
+; CHECK-NEXT: i32 0, label %loop_exit1
+; CHECK-NEXT: ]
+;
+; CHECK: entry.split:
+; CHECK-NEXT: switch i32 %cond2, label %loop_exit2 [
+; CHECK-NEXT: i32 42, label %loop_exit2
+; CHECK-NEXT: i32 0, label %entry.split.split
+; CHECK-NEXT: ]
+;
+; CHECK: entry.split.split:
+; CHECK-NEXT: br label %loop_begin
+
+loop_begin:
+ switch i32 %cond1, label %continue [
+ i32 0, label %loop_exit1
+ ]
+; CHECK: loop_begin:
+; CHECK-NEXT: br label %continue
+
+continue:
+ %var_val = load i32, i32* %var
+ switch i32 %cond2, label %loop_exit2 [
+ i32 0, label %do_something
+ i32 42, label %loop_exit2
+ ]
+; CHECK: continue:
+; CHECK-NEXT: load
+; CHECK-NEXT: br label %do_something
+
+do_something:
+ call void @some_func() noreturn nounwind
+ br label %loop_begin
+; CHECK: do_something:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_begin
+
+loop_exit1:
+ ret i32 0
+; CHECK: loop_exit1:
+; CHECK-NEXT: ret
+
+loop_exit2:
+ ret i32 0
+; CHECK: loop_exit2:
+; CHECK-NEXT: ret
+;
+; We shouldn't have any unreachable blocks here because the unswitched switches
+; turn into branches instead.
+; CHECK-NOT: unreachable
+}
+
+; Test for a trivially unswitchable switch with multiple exiting cases and
+; multiple looping cases.
+define i32 @test4(i32* %var, i32 %cond1, i32 %cond2) {
+; CHECK-LABEL: @test4(
+entry:
+ br label %loop_begin
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i32 %cond2, label %loop_exit2 [
+; CHECK-NEXT: i32 13, label %loop_exit1
+; CHECK-NEXT: i32 42, label %loop_exit3
+; CHECK-NEXT: i32 0, label %entry.split
+; CHECK-NEXT: i32 1, label %entry.split
+; CHECK-NEXT: i32 2, label %entry.split
+; CHECK-NEXT: ]
+;
+; CHECK: entry.split:
+; CHECK-NEXT: br label %loop_begin
+
+loop_begin:
+ %var_val = load i32, i32* %var
+ switch i32 %cond2, label %loop_exit2 [
+ i32 0, label %loop0
+ i32 1, label %loop1
+ i32 13, label %loop_exit1
+ i32 2, label %loop2
+ i32 42, label %loop_exit3
+ ]
+; CHECK: loop_begin:
+; CHECK-NEXT: load
+; CHECK-NEXT: switch i32 %cond2, label %[[UNREACHABLE:.*]] [
+; CHECK-NEXT: i32 0, label %loop0
+; CHECK-NEXT: i32 1, label %loop1
+; CHECK-NEXT: i32 2, label %loop2
+; CHECK-NEXT: ]
+
+loop0:
+ call void @some_func() noreturn nounwind
+ br label %loop_latch
+; CHECK: loop0:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_latch
+
+loop1:
+ call void @some_func() noreturn nounwind
+ br label %loop_latch
+; CHECK: loop1:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_latch
+
+loop2:
+ call void @some_func() noreturn nounwind
+ br label %loop_latch
+; CHECK: loop2:
+; CHECK-NEXT: call
+; CHECK-NEXT: br label %loop_latch
+
+loop_latch:
+ br label %loop_begin
+; CHECK: loop_latch:
+; CHECK-NEXT: br label %loop_begin
+
+loop_exit1:
+ ret i32 0
+; CHECK: loop_exit1:
+; CHECK-NEXT: ret
+
+loop_exit2:
+ ret i32 0
+; CHECK: loop_exit2:
+; CHECK-NEXT: ret
+
+loop_exit3:
+ ret i32 0
+; CHECK: loop_exit3:
+; CHECK-NEXT: ret
+;
+; CHECK: [[UNREACHABLE]]:
+; CHECK-NEXT: unreachable
+}
diff --git a/test/Transforms/SimplifyCFG/speculate-call.ll b/test/Transforms/SimplifyCFG/speculate-call.ll
new file mode 100644
index 000000000000..6e9398b6203c
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/speculate-call.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S -simplifycfg < %s | FileCheck %s
+
+; CHECK-LABEL: @speculatable_attribute
+; CHECK: select
+define i32 @speculatable_attribute(i32 %a) {
+entry:
+ %c = icmp sgt i32 %a, 64
+ br i1 %c, label %end, label %if
+
+if:
+ %val = call i32 @func() #0
+ br label %end
+
+end:
+ %ret = phi i32 [%val, %if], [0, %entry]
+ ret i32 %ret
+}
+
+define i32 @func() #0 {
+ ret i32 1
+}
+attributes #0 = { nounwind readnone speculatable }
+