summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/LoopRotate
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/LoopRotate')
-rw-r--r--llvm/test/Transforms/LoopRotate/2009-01-25-SingleEntryPhi.ll22
-rw-r--r--llvm/test/Transforms/LoopRotate/PhiRename-1.ll96
-rw-r--r--llvm/test/Transforms/LoopRotate/PhiSelfReference-1.ll40
-rw-r--r--llvm/test/Transforms/LoopRotate/alloca.ll34
-rw-r--r--llvm/test/Transforms/LoopRotate/basic.ll65
-rw-r--r--llvm/test/Transforms/LoopRotate/callbr.ll103
-rwxr-xr-xllvm/test/Transforms/LoopRotate/catchret.ll42
-rw-r--r--llvm/test/Transforms/LoopRotate/convergent.ll32
-rw-r--r--llvm/test/Transforms/LoopRotate/crash.ll174
-rw-r--r--llvm/test/Transforms/LoopRotate/dbg-value-duplicates.ll89
-rw-r--r--llvm/test/Transforms/LoopRotate/dbgvalue.ll159
-rw-r--r--llvm/test/Transforms/LoopRotate/indirectbr.ll75
-rw-r--r--llvm/test/Transforms/LoopRotate/loopexitinglatch.ll235
-rw-r--r--llvm/test/Transforms/LoopRotate/multiple-exits.ll237
-rw-r--r--llvm/test/Transforms/LoopRotate/nosimplifylatch.ll34
-rw-r--r--llvm/test/Transforms/LoopRotate/oz-disable.ll30
-rw-r--r--llvm/test/Transforms/LoopRotate/phi-dbgvalue.ll82
-rw-r--r--llvm/test/Transforms/LoopRotate/phi-duplicate.ll41
-rw-r--r--llvm/test/Transforms/LoopRotate/pr22337.ll25
-rw-r--r--llvm/test/Transforms/LoopRotate/pr2639.ll38
-rw-r--r--llvm/test/Transforms/LoopRotate/pr33701.ll28
-rw-r--r--llvm/test/Transforms/LoopRotate/pr35210.ll127
-rw-r--r--llvm/test/Transforms/LoopRotate/pr37205.ll117
-rw-r--r--llvm/test/Transforms/LoopRotate/preserve-loop-simplify.ll65
-rw-r--r--llvm/test/Transforms/LoopRotate/preserve-mssa.ll109
-rw-r--r--llvm/test/Transforms/LoopRotate/preserve-scev.ll80
-rw-r--r--llvm/test/Transforms/LoopRotate/simplifylatch.ll76
-rw-r--r--llvm/test/Transforms/LoopRotate/vect.omp.persistence.ll35
28 files changed, 2290 insertions, 0 deletions
diff --git a/llvm/test/Transforms/LoopRotate/2009-01-25-SingleEntryPhi.ll b/llvm/test/Transforms/LoopRotate/2009-01-25-SingleEntryPhi.ll
new file mode 100644
index 00000000000..a09a2290e0a
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/2009-01-25-SingleEntryPhi.ll
@@ -0,0 +1,22 @@
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -disable-output
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
+; PR3408
+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"
+target triple = "x86_64-unknown-linux-gnu"
+ %struct.Cls = type { i32, i8, [2 x %struct.Cls*], [2 x %struct.Lit*] }
+ %struct.Lit = type { i8 }
+
+define void @picosat_main_bb13.i.i71.outer_bb132.i.i.i.outer(%struct.Cls**, %struct.Cls**, i32 %collect.i.i.i.1.lcssa, i32 %lcollect.i.i.i.2.lcssa, %struct.Cls*** %rhead.tmp.0236.out, i32* %collect.i.i.i.2.out, i32* %lcollect.i.i.i.3.ph.ph.ph.out) nounwind {
+newFuncRoot:
+ br label %codeRepl
+
+bb133.i.i.i.exitStub: ; preds = %codeRepl
+ ret void
+
+bb130.i.i.i: ; preds = %codeRepl
+ %rhead.tmp.0236.lcssa82 = phi %struct.Cls** [ null, %codeRepl ] ; <%struct.Cls**> [#uses=0]
+ br label %codeRepl
+
+codeRepl: ; preds = %bb130.i.i.i, %newFuncRoot
+ br i1 false, label %bb130.i.i.i, label %bb133.i.i.i.exitStub
+}
diff --git a/llvm/test/Transforms/LoopRotate/PhiRename-1.ll b/llvm/test/Transforms/LoopRotate/PhiRename-1.ll
new file mode 100644
index 00000000000..8bece445cf4
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/PhiRename-1.ll
@@ -0,0 +1,96 @@
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -S | FileCheck %s
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
+; CHECK-NOT: [ {{.}}tmp224
+
+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"
+
+ %struct.FILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }
+ %struct.Index_Map = type { i32, %struct.item_set** }
+ %struct.Item = type { [4 x i16], %struct.rule* }
+ %struct.__sFILEX = type opaque
+ %struct.__sbuf = type { i8*, i32 }
+ %struct.dimension = type { i16*, %struct.Index_Map, %struct.mapping*, i32, %struct.plankMap* }
+ %struct.item_set = type { i32, i32, %struct.operator*, [2 x %struct.item_set*], %struct.item_set*, i16*, %struct.Item*, %struct.Item* }
+ %struct.list = type { i8*, %struct.list* }
+ %struct.mapping = type { %struct.list**, i32, i32, i32, %struct.item_set** }
+ %struct.nonterminal = type { i8*, i32, i32, i32, %struct.plankMap*, %struct.rule* }
+ %struct.operator = type { i8*, i8, i32, i32, i32, i32, %struct.table* }
+ %struct.pattern = type { %struct.nonterminal*, %struct.operator*, [2 x %struct.nonterminal*] }
+ %struct.plank = type { i8*, %struct.list*, i32 }
+ %struct.plankMap = type { %struct.list*, i32, %struct.stateMap* }
+ %struct.rule = type { [4 x i16], i32, i32, i32, %struct.nonterminal*, %struct.pattern*, i8 }
+ %struct.stateMap = type { i8*, %struct.plank*, i32, i16* }
+ %struct.table = type { %struct.operator*, %struct.list*, i16*, [2 x %struct.dimension*], %struct.item_set** }
+@outfile = external global %struct.FILE* ; <%struct.FILE**> [#uses=1]
+@str1 = external constant [11 x i8] ; <[11 x i8]*> [#uses=1]
+@operators = weak global %struct.list* null ; <%struct.list**> [#uses=1]
+
+
+
+define i32 @opsOfArity(i32 %arity) {
+entry:
+ %arity_addr = alloca i32 ; <i32*> [#uses=2]
+ %retval = alloca i32, align 4 ; <i32*> [#uses=2]
+ %tmp = alloca i32, align 4 ; <i32*> [#uses=2]
+ %c = alloca i32, align 4 ; <i32*> [#uses=4]
+ %l = alloca %struct.list*, align 4 ; <%struct.list**> [#uses=5]
+ %op = alloca %struct.operator*, align 4 ; <%struct.operator**> [#uses=3]
+ store i32 %arity, i32* %arity_addr
+ store i32 0, i32* %c
+ %tmp1 = load %struct.list*, %struct.list** @operators ; <%struct.list*> [#uses=1]
+ store %struct.list* %tmp1, %struct.list** %l
+ br label %bb21
+
+bb: ; preds = %bb21
+ %tmp3 = getelementptr %struct.list, %struct.list* %tmp22, i32 0, i32 0 ; <i8**> [#uses=1]
+ %tmp4 = load i8*, i8** %tmp3 ; <i8*> [#uses=1]
+ %tmp45 = bitcast i8* %tmp4 to %struct.operator* ; <%struct.operator*> [#uses=1]
+ store %struct.operator* %tmp45, %struct.operator** %op
+ %tmp6 = load %struct.operator*, %struct.operator** %op ; <%struct.operator*> [#uses=1]
+ %tmp7 = getelementptr %struct.operator, %struct.operator* %tmp6, i32 0, i32 5 ; <i32*> [#uses=1]
+ %tmp8 = load i32, i32* %tmp7 ; <i32> [#uses=1]
+ %tmp9 = load i32, i32* %arity_addr ; <i32> [#uses=1]
+ icmp eq i32 %tmp8, %tmp9 ; <i1>:0 [#uses=1]
+ zext i1 %0 to i8 ; <i8>:1 [#uses=1]
+ icmp ne i8 %1, 0 ; <i1>:2 [#uses=1]
+ br i1 %2, label %cond_true, label %cond_next
+
+cond_true: ; preds = %bb
+ %tmp10 = load %struct.operator*, %struct.operator** %op ; <%struct.operator*> [#uses=1]
+ %tmp11 = getelementptr %struct.operator, %struct.operator* %tmp10, i32 0, i32 2 ; <i32*> [#uses=1]
+ %tmp12 = load i32, i32* %tmp11 ; <i32> [#uses=1]
+ %tmp13 = load %struct.FILE*, %struct.FILE** @outfile ; <%struct.FILE*> [#uses=1]
+ %tmp14 = getelementptr [11 x i8], [11 x i8]* @str1, i32 0, i32 0 ; <i8*> [#uses=1]
+ %tmp15 = call i32 (%struct.FILE*, i8*, ...) @fprintf( %struct.FILE* %tmp13, i8* %tmp14, i32 %tmp12 ) ; <i32> [#uses=0]
+ %tmp16 = load i32, i32* %c ; <i32> [#uses=1]
+ %tmp17 = add i32 %tmp16, 1 ; <i32> [#uses=1]
+ store i32 %tmp17, i32* %c
+ br label %cond_next
+
+cond_next: ; preds = %cond_true, %bb
+ %tmp19 = getelementptr %struct.list, %struct.list* %tmp22, i32 0, i32 1 ; <%struct.list**> [#uses=1]
+ %tmp20 = load %struct.list*, %struct.list** %tmp19 ; <%struct.list*> [#uses=1]
+ store %struct.list* %tmp20, %struct.list** %l
+ br label %bb21
+
+bb21: ; preds = %cond_next, %entry
+ %l.in = phi %struct.list** [ @operators, %entry ], [ %tmp19, %cond_next ]
+ %tmp22 = load %struct.list*, %struct.list** %l.in ; <%struct.list*> [#uses=1]
+ icmp ne %struct.list* %tmp22, null ; <i1>:3 [#uses=1]
+ zext i1 %3 to i8 ; <i8>:4 [#uses=1]
+ icmp ne i8 %4, 0 ; <i1>:5 [#uses=1]
+ br i1 %5, label %bb, label %bb23
+
+bb23: ; preds = %bb21
+ %tmp24 = load i32, i32* %c ; <i32> [#uses=1]
+ store i32 %tmp24, i32* %tmp
+ %tmp25 = load i32, i32* %tmp ; <i32> [#uses=1]
+ store i32 %tmp25, i32* %retval
+ br label %return
+
+return: ; preds = %bb23
+ %retval26 = load i32, i32* %retval ; <i32> [#uses=1]
+ ret i32 %retval26
+}
+
+declare i32 @fprintf(%struct.FILE*, i8*, ...)
diff --git a/llvm/test/Transforms/LoopRotate/PhiSelfReference-1.ll b/llvm/test/Transforms/LoopRotate/PhiSelfReference-1.ll
new file mode 100644
index 00000000000..7726c53e55e
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/PhiSelfReference-1.ll
@@ -0,0 +1,40 @@
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -disable-output
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
+; ModuleID = 'PhiSelfReference-1.bc'
+
+define void @snrm2(i32 %incx) {
+entry:
+ br i1 false, label %START, label %return
+
+START: ; preds = %entry
+ br i1 false, label %bb85, label %cond_false93
+
+bb52: ; preds = %bb85
+ br i1 false, label %bb307, label %cond_next71
+
+cond_next71: ; preds = %bb52
+ ret void
+
+bb85: ; preds = %START
+ br i1 false, label %bb52, label %bb88
+
+bb88: ; preds = %bb85
+ ret void
+
+cond_false93: ; preds = %START
+ ret void
+
+bb243: ; preds = %bb307
+ br label %bb307
+
+bb307: ; preds = %bb243, %bb52
+ %sx_addr.2.pn = phi float* [ %sx_addr.5, %bb243 ], [ null, %bb52 ] ; <float*> [#uses=1]
+ %sx_addr.5 = getelementptr float, float* %sx_addr.2.pn, i32 %incx ; <float*> [#uses=1]
+ br i1 false, label %bb243, label %bb310
+
+bb310: ; preds = %bb307
+ ret void
+
+return: ; preds = %entry
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/alloca.ll b/llvm/test/Transforms/LoopRotate/alloca.ll
new file mode 100644
index 00000000000..59da33f8802
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/alloca.ll
@@ -0,0 +1,34 @@
+; RUN: opt < %s -loop-rotate -S | FileCheck %s
+; RUN: opt < %s -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
+
+; Test alloca in -loop-rotate.
+
+; We expect a different value for %ptr each iteration (according to the
+; definition of alloca). I.e. each @use must be paired with an alloca.
+
+; CHECK: call void @use(i8* %
+; CHECK: %ptr = alloca i8
+
+@e = global i16 10
+
+declare void @use(i8*)
+
+define void @test() {
+entry:
+ %end = load i16, i16* @e
+ br label %loop
+
+loop:
+ %n.phi = phi i16 [ %n, %loop.fin ], [ 0, %entry ]
+ %ptr = alloca i8
+ %cond = icmp eq i16 %n.phi, %end
+ br i1 %cond, label %exit, label %loop.fin
+
+loop.fin:
+ %n = add i16 %n.phi, 1
+ call void @use(i8* %ptr)
+ br label %loop
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/basic.ll b/llvm/test/Transforms/LoopRotate/basic.ll
new file mode 100644
index 00000000000..d01d19f7f12
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/basic.ll
@@ -0,0 +1,65 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+; RUN: opt -S -passes='require<targetir>,require<assumptions>,loop(rotate)' < %s | FileCheck %s
+; RUN: opt -S -passes='require<targetir>,require<assumptions>,loop(rotate)' -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-apple-darwin10.0.0"
+
+; PR5319 - The "arrayidx" gep should be hoisted, not duplicated. We should
+; end up with one phi node.
+define void @test1() nounwind ssp {
+; CHECK-LABEL: @test1(
+entry:
+ %array = alloca [20 x i32], align 16
+ br label %for.cond
+
+for.cond: ; preds = %for.body, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %cmp = icmp slt i32 %i.0, 100
+ %arrayidx = getelementptr inbounds [20 x i32], [20 x i32]* %array, i64 0, i64 0
+ br i1 %cmp, label %for.body, label %for.end
+
+; CHECK: for.body:
+; CHECK-NEXT: phi i32 [ 0
+; CHECK-NEXT: store i32 0
+
+for.body: ; preds = %for.cond
+ store i32 0, i32* %arrayidx, align 16
+ %inc = add nsw i32 %i.0, 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ %arrayidx.lcssa = phi i32* [ %arrayidx, %for.cond ]
+ call void @g(i32* %arrayidx.lcssa) nounwind
+ ret void
+}
+
+declare void @g(i32*)
+
+; CHECK-LABEL: @test2(
+define void @test2() nounwind ssp {
+entry:
+ %array = alloca [20 x i32], align 16
+ br label %for.cond
+
+for.cond: ; preds = %for.body, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %cmp = icmp slt i32 %i.0, 100
+; CHECK: call void @f
+; CHECK-NOT: call void @f
+ call void @f() noduplicate
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %inc = add nsw i32 %i.0, 1
+ call void @h()
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+; CHECK: }
+}
+
+declare void @f() noduplicate
+declare void @h()
diff --git a/llvm/test/Transforms/LoopRotate/callbr.ll b/llvm/test/Transforms/LoopRotate/callbr.ll
new file mode 100644
index 00000000000..6eed2eb17dc
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/callbr.ll
@@ -0,0 +1,103 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info | FileCheck %s
+; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true | FileCheck %s
+
+@d = external global i64, align 8
+@f = external global i32, align 4
+@g = external global i32, align 4
+@i = external global i32, align 4
+@h = external global i32, align 4
+
+define i32 @o() #0 {
+; CHECK-LABEL: @o(
+; CHECK-NEXT: [[TMP1:%.*]] = alloca [1 x i32], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load i8*, i8** bitcast (i64* @d to i8**), align 8
+; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* @f, align 4
+; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0
+; CHECK-NEXT: br i1 [[TMP4]], label [[TMP17:%.*]], label [[DOTLR_PH2:%.*]]
+; CHECK: .lr.ph2:
+; CHECK-NEXT: br label [[TMP5:%.*]]
+; CHECK: [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[DOTLR_PH2]] ], [ [[TMP15:%.*]], [[M_EXIT:%.*]] ]
+; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], 4
+; CHECK-NEXT: [[TMP8:%.*]] = zext i1 [[TMP7]] to i32
+; CHECK-NEXT: store i32 [[TMP8]], i32* @g, align 4
+; CHECK-NEXT: [[TMP9:%.*]] = bitcast [1 x i32]* [[TMP1]] to i8*
+; CHECK-NEXT: [[TMP10:%.*]] = call i32 @n(i8* nonnull [[TMP9]], i8* [[TMP2]])
+; CHECK-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], 0
+; CHECK-NEXT: br i1 [[TMP11]], label [[THREAD_PRE_SPLIT:%.*]], label [[DOT_CRIT_EDGE:%.*]]
+; CHECK: thread-pre-split:
+; CHECK-NEXT: [[DOTPR:%.*]] = load i32, i32* @i, align 4
+; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[DOTPR]], 0
+; CHECK-NEXT: br i1 [[TMP12]], label [[M_EXIT]], label [[DOTLR_PH:%.*]]
+; CHECK: .lr.ph:
+; CHECK-NEXT: br label [[TMP13:%.*]]
+; CHECK: [[DOT11:%.*]] = phi i32 [ undef, [[DOTLR_PH]] ], [ [[TMP14:%.*]], [[J_EXIT_I:%.*]] ]
+; CHECK-NEXT: callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@o, [[M_EXIT]])) #1
+; CHECK-NEXT: to label [[J_EXIT_I]] [label %m.exit]
+; CHECK: j.exit.i:
+; CHECK-NEXT: [[TMP14]] = tail call i32 asm "", "={ax},~{dirflag},~{fpsr},~{flags}"() #2
+; CHECK-NEXT: br i1 [[TMP12]], label [[DOTM_EXIT_CRIT_EDGE:%.*]], label [[TMP13]]
+; CHECK: .m.exit_crit_edge:
+; CHECK-NEXT: [[SPLIT:%.*]] = phi i32 [ [[TMP14]], [[J_EXIT_I]] ]
+; CHECK-NEXT: br label [[M_EXIT]]
+; CHECK: m.exit:
+; CHECK-NEXT: [[DOT1_LCSSA:%.*]] = phi i32 [ [[DOT11]], [[TMP13]] ], [ [[SPLIT]], [[DOTM_EXIT_CRIT_EDGE]] ], [ undef, [[THREAD_PRE_SPLIT]] ]
+; CHECK-NEXT: store i32 [[DOT1_LCSSA]], i32* @h, align 4
+; CHECK-NEXT: [[TMP15]] = load i32, i32* @f, align 4
+; CHECK-NEXT: [[TMP16:%.*]] = icmp eq i32 [[TMP15]], 0
+; CHECK-NEXT: br i1 [[TMP16]], label [[DOT_CRIT_EDGE3:%.*]], label [[TMP5]]
+; CHECK: ._crit_edge:
+; CHECK-NEXT: br label [[TMP17]]
+; CHECK: ._crit_edge3:
+; CHECK-NEXT: br label [[TMP17]]
+; CHECK: ret i32 undef
+;
+ %1 = alloca [1 x i32], align 4
+ %2 = load i8*, i8** bitcast (i64* @d to i8**), align 8
+ br label %3
+
+; <label>:3: ; preds = %m.exit, %0
+ %4 = load i32, i32* @f, align 4
+ %5 = icmp eq i32 %4, 0
+ br i1 %5, label %16, label %6
+
+; <label>:6: ; preds = %3
+ %7 = icmp ult i32 %4, 4
+ %8 = zext i1 %7 to i32
+ store i32 %8, i32* @g, align 4
+ %9 = bitcast [1 x i32]* %1 to i8*
+ %10 = call i32 @n(i8* nonnull %9, i8* %2)
+ %11 = icmp eq i32 %10, 0
+ br i1 %11, label %thread-pre-split, label %16
+
+thread-pre-split: ; preds = %6
+ %.pr = load i32, i32* @i, align 4
+ br label %12
+
+; <label>:12: ; preds = %j.exit.i, %thread-pre-split
+ %.1 = phi i32 [ %15, %j.exit.i ], [ undef, %thread-pre-split ]
+ %13 = icmp eq i32 %.pr, 0
+ br i1 %13, label %m.exit, label %14
+
+; <label>:14: ; preds = %12
+ callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@o, %m.exit)) #1
+ to label %j.exit.i [label %m.exit]
+
+j.exit.i: ; preds = %14
+ %15 = tail call i32 asm "", "={ax},~{dirflag},~{fpsr},~{flags}"() #2
+ br label %12
+
+m.exit: ; preds = %14, %12
+ %.1.lcssa = phi i32 [ %.1, %14 ], [ %.1, %12 ]
+ store i32 %.1.lcssa, i32* @h, align 4
+ br label %3
+
+; <label>:16: ; preds = %6, %3
+ ret i32 undef
+}
+
+declare i32 @n(i8*, i8*) #0
+
+attributes #0 = { "use-soft-float"="false" }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind readnone }
diff --git a/llvm/test/Transforms/LoopRotate/catchret.ll b/llvm/test/Transforms/LoopRotate/catchret.ll
new file mode 100755
index 00000000000..f28af8aed60
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/catchret.ll
@@ -0,0 +1,42 @@
+; RUN: opt < %s -loop-rotate -S | FileCheck %s
+; RUN: opt < %s -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
+
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @always_throws()
+
+define i32 @test() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+ invoke void @always_throws()
+ to label %continue unwind label %catch.dispatch
+
+continue:
+ unreachable
+
+catch.dispatch:
+ %t0 = catchswitch within none [label %catch] unwind to caller
+
+catch:
+ %t1 = catchpad within %t0 [i8* null, i32 64, i8* null]
+ catchret from %t1 to label %for.cond
+
+for.cond:
+ %sum = phi i32 [ %add, %for.body ], [ 0, %catch ]
+ %i = phi i32 [ %inc, %for.body ], [ 0, %catch ]
+ %cmp = icmp slt i32 %i, 1
+ br i1 %cmp, label %for.body, label %return
+
+for.body:
+ %add = add nsw i32 1, %sum
+ %inc = add nsw i32 %i, 1
+ br label %for.cond
+
+return:
+ ret i32 0
+}
+
+; CHECK: catch:
+; CHECK-NEXT: catchpad
+; CHECK-NEXT: catchret
+
+declare i32 @__CxxFrameHandler3(...)
diff --git a/llvm/test/Transforms/LoopRotate/convergent.ll b/llvm/test/Transforms/LoopRotate/convergent.ll
new file mode 100644
index 00000000000..37671562142
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/convergent.ll
@@ -0,0 +1,32 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+
+@e = global i32 10
+
+declare void @f1(i32) convergent
+declare void @f2(i32)
+
+; The call to f1 in the loop header shouldn't be duplicated (meaning, loop
+; rotation shouldn't occur), because f1 is convergent.
+
+; CHECK: call void @f1
+; CHECK-NOT: call void @f1
+
+define void @test(i32 %x) {
+entry:
+ br label %loop
+
+loop:
+ %n.phi = phi i32 [ %n, %loop.fin ], [ 0, %entry ]
+ call void @f1(i32 %n.phi)
+ %cond = icmp eq i32 %n.phi, %x
+ br i1 %cond, label %exit, label %loop.fin
+
+loop.fin:
+ %n = add i32 %n.phi, 1
+ call void @f2(i32 %n)
+ br label %loop
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/crash.ll b/llvm/test/Transforms/LoopRotate/crash.ll
new file mode 100644
index 00000000000..2a45e370e18
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/crash.ll
@@ -0,0 +1,174 @@
+; RUN: opt -loop-rotate -disable-output -verify-dom-info -verify-loop-info < %s
+; RUN: opt -loop-rotate -disable-output -verify-dom-info -verify-loop-info -enable-mssa-loop-dependency=true -verify-memoryssa < %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-apple-darwin10.0.0"
+
+; PR8955 - Rotating an outer loop that has a condbr for a latch block.
+define void @test1() nounwind ssp {
+entry:
+ br label %lbl_283
+
+lbl_283: ; preds = %if.end, %entry
+ br i1 undef, label %if.else, label %if.then
+
+if.then: ; preds = %lbl_283
+ br i1 undef, label %if.end, label %for.condthread-pre-split
+
+for.condthread-pre-split: ; preds = %if.then
+ br label %for.cond
+
+for.cond: ; preds = %for.cond, %for.condthread-pre-split
+ br i1 undef, label %lbl_281, label %for.cond
+
+lbl_281: ; preds = %if.end, %for.cond
+ br label %if.end
+
+if.end: ; preds = %lbl_281, %if.then
+ br i1 undef, label %lbl_283, label %lbl_281
+
+if.else: ; preds = %lbl_283
+ ret void
+}
+
+ %struct.relation = type { [4 x i16], i32, [4 x i16], i32, i32 }
+
+define void @test2() {
+entry:
+ br i1 false, label %bb139, label %bb10.i44
+bb10.i44: ; preds = %entry
+ ret void
+bb127: ; preds = %bb139
+ br label %bb139
+bb139: ; preds = %bb127, %entry
+ br i1 false, label %bb127, label %bb142
+bb142: ; preds = %bb139
+ %r91.0.lcssa = phi %struct.relation* [ null, %bb139 ] ; <%struct.relation*> [#uses=0]
+ ret void
+}
+
+
+define void @test3() {
+entry:
+ br i1 false, label %bb139, label %cond_true
+cond_true: ; preds = %entry
+ ret void
+bb90: ; preds = %bb139
+ br i1 false, label %bb136, label %cond_next121
+cond_next121: ; preds = %bb90
+ br i1 false, label %bb136, label %bb127
+bb127: ; preds = %cond_next121
+ br label %bb136
+bb136: ; preds = %bb127, %cond_next121, %bb90
+ %changes.1 = phi i32 [ %changes.2, %bb90 ], [ %changes.2, %cond_next121 ], [ 1, %bb127 ] ; <i32> [#uses=1]
+ br label %bb139
+bb139: ; preds = %bb136, %entry
+ %changes.2 = phi i32 [ %changes.1, %bb136 ], [ 0, %entry ] ; <i32> [#uses=3]
+ br i1 false, label %bb90, label %bb142
+bb142: ; preds = %bb139
+ %changes.2.lcssa = phi i32 [ %changes.2, %bb139 ] ; <i32> [#uses=0]
+ ret void
+}
+
+define void @test4() {
+entry:
+ br i1 false, label %cond_false485, label %bb405
+bb405: ; preds = %entry
+ ret void
+cond_false485: ; preds = %entry
+ br label %bb830
+bb511: ; preds = %bb830
+ br i1 false, label %bb816, label %bb830
+cond_next667: ; preds = %bb816
+ br i1 false, label %cond_next695, label %bb680
+bb676: ; preds = %bb680
+ br label %bb680
+bb680: ; preds = %bb676, %cond_next667
+ %iftmp.68.0 = zext i1 false to i8 ; <i8> [#uses=1]
+ br i1 false, label %bb676, label %cond_next695
+cond_next695: ; preds = %bb680, %cond_next667
+ %iftmp.68.2 = phi i8 [ %iftmp.68.0, %bb680 ], [ undef, %cond_next667 ] ; <i8> [#uses=0]
+ ret void
+bb816: ; preds = %bb816, %bb511
+ br i1 false, label %cond_next667, label %bb816
+bb830: ; preds = %bb511, %cond_false485
+ br i1 false, label %bb511, label %bb835
+bb835: ; preds = %bb830
+ ret void
+}
+
+ %struct.NSArray = type { %struct.NSObject }
+ %struct.NSObject = type { %struct.objc_class* }
+ %struct.NSRange = type { i64, i64 }
+ %struct._message_ref_t = type { %struct.NSObject* (%struct.NSObject*, %struct._message_ref_t*, ...)*, %struct.objc_selector* }
+ %struct.objc_class = type opaque
+ %struct.objc_selector = type opaque
+@"\01L_OBJC_MESSAGE_REF_26" = external global %struct._message_ref_t ; <%struct._message_ref_t*> [#uses=1]
+
+define %struct.NSArray* @test5(%struct.NSArray* %self, %struct._message_ref_t* %_cmd) {
+entry:
+ br label %bb116
+
+bb116: ; preds = %bb131, %entry
+ %tmp123 = call %struct.NSRange null( %struct.NSObject* null, %struct._message_ref_t* @"\01L_OBJC_MESSAGE_REF_26", %struct.NSArray* null ) ; <%struct.NSRange> [#uses=1]
+ br i1 false, label %bb141, label %bb131
+
+bb131: ; preds = %bb116
+ %mrv_gr125 = extractvalue %struct.NSRange %tmp123, 1 ; <i64> [#uses=0]
+ br label %bb116
+
+bb141: ; preds = %bb116
+ ret %struct.NSArray* null
+}
+
+define void @test6(i8* %msg) {
+entry:
+ br label %bb15
+bb6: ; preds = %bb15
+ %gep.upgrd.1 = zext i32 %offset.1 to i64 ; <i64> [#uses=1]
+ %tmp11 = getelementptr i8, i8* %msg, i64 %gep.upgrd.1 ; <i8*> [#uses=0]
+ br label %bb15
+bb15: ; preds = %bb6, %entry
+ %offset.1 = add i32 0, 1 ; <i32> [#uses=2]
+ br i1 false, label %bb6, label %bb17
+bb17: ; preds = %bb15
+ %offset.1.lcssa = phi i32 [ %offset.1, %bb15 ] ; <i32> [#uses=0]
+ %payload_type.1.lcssa = phi i32 [ 0, %bb15 ] ; <i32> [#uses=0]
+ ret void
+}
+
+
+
+
+; PR9523 - Non-canonical loop.
+define void @test7(i8* %P) nounwind {
+entry:
+ indirectbr i8* %P, [label %"3", label %"5"]
+
+"3": ; preds = %"4", %entry
+ br i1 undef, label %"5", label %"4"
+
+"4": ; preds = %"3"
+ br label %"3"
+
+"5": ; preds = %"3", %entry
+ ret void
+}
+
+; PR21968
+define void @test8(i1 %C, i8* %P) #0 {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ br i1 %C, label %l_bad, label %for.body
+
+for.body: ; preds = %for.cond
+ indirectbr i8* %P, [label %for.inc, label %l_bad]
+
+for.inc: ; preds = %for.body
+ br label %for.cond
+
+l_bad: ; preds = %for.body, %for.cond
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/dbg-value-duplicates.ll b/llvm/test/Transforms/LoopRotate/dbg-value-duplicates.ll
new file mode 100644
index 00000000000..ce7157c571f
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/dbg-value-duplicates.ll
@@ -0,0 +1,89 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+source_filename = "/tmp/loop.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.13.0"
+
+; Function Attrs: nounwind ssp uwtable
+define void @f(float* %input, i64 %n, i64 %s) local_unnamed_addr #0 !dbg !8 {
+entry:
+ call void @llvm.dbg.value(metadata float* %input, metadata !15, metadata !DIExpression()), !dbg !20
+ call void @llvm.dbg.value(metadata i64 %n, metadata !16, metadata !DIExpression()), !dbg !21
+ call void @llvm.dbg.value(metadata i64 %s, metadata !17, metadata !DIExpression()), !dbg !22
+ call void @llvm.dbg.value(metadata i64 0, metadata !18, metadata !DIExpression()), !dbg !23
+ ; CHECK: call void @llvm.dbg.value(metadata i64 0, metadata !18, metadata !DIExpression()), !dbg !23
+ ; CHECK-NOT: call void @llvm.dbg.value(metadata i64 0, metadata !18, metadata !DIExpression()), !dbg !23
+ br label %for.cond, !dbg !24
+
+for.cond: ; preds = %for.body, %entry
+ ; CHECK: %i.02 = phi i64 [ 0, %for.body.lr.ph ], [ %add, %for.body ]
+ %i.0 = phi i64 [ 0, %entry ], [ %add, %for.body ]
+ call void @llvm.dbg.value(metadata i64 %i.0, metadata !18, metadata !DIExpression()), !dbg !23
+ %cmp = icmp slt i64 %i.0, %n, !dbg !25
+ br i1 %cmp, label %for.body, label %for.cond.cleanup, !dbg !27
+
+for.cond.cleanup: ; preds = %for.cond
+ ret void, !dbg !28
+
+for.body: ; preds = %for.cond
+ %arrayidx = getelementptr inbounds float, float* %input, i64 %i.0, !dbg !29
+ %0 = load float, float* %arrayidx, align 4, !dbg !29, !tbaa !30
+ call void @bar(float %0), !dbg !34
+ %add = add nsw i64 %i.0, %s, !dbg !35
+ call void @llvm.dbg.value(metadata i64 %add, metadata !18, metadata !DIExpression()), !dbg !23
+ ; CHECK: call void @llvm.dbg.value(metadata i64 %add, metadata !18, metadata !DIExpression()), !dbg !23
+ ; CHECK-NOT: call void @llvm.dbg.value(metadata i64 %add, metadata !18, metadata !DIExpression()), !dbg !23
+ br label %for.cond, !dbg !36, !llvm.loop !37
+}
+
+declare void @bar(float) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind ssp uwtable }
+attributes #2 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 (trunk 316689) (llvm/trunk 316685)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "/tmp/loop.c", directory: "/Data/llvm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 6.0.0 (trunk 316689) (llvm/trunk 316685)"}
+!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !14)
+!9 = !DISubroutineType(types: !10)
+!10 = !{null, !11, !13, !13}
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!12 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!13 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!14 = !{!15, !16, !17, !18}
+!15 = !DILocalVariable(name: "input", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!16 = !DILocalVariable(name: "n", arg: 2, scope: !8, file: !1, line: 2, type: !13)
+!17 = !DILocalVariable(name: "s", arg: 3, scope: !8, file: !1, line: 2, type: !13)
+!18 = !DILocalVariable(name: "i", scope: !19, file: !1, line: 3, type: !13)
+!19 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3, column: 3)
+!20 = !DILocation(line: 2, column: 15, scope: !8)
+!21 = !DILocation(line: 2, column: 32, scope: !8)
+!22 = !DILocation(line: 2, column: 45, scope: !8)
+!23 = !DILocation(line: 3, column: 18, scope: !19)
+!24 = !DILocation(line: 3, column: 8, scope: !19)
+!25 = !DILocation(line: 3, column: 26, scope: !26)
+!26 = distinct !DILexicalBlock(scope: !19, file: !1, line: 3, column: 3)
+!27 = !DILocation(line: 3, column: 3, scope: !19)
+!28 = !DILocation(line: 5, column: 1, scope: !8)
+!29 = !DILocation(line: 4, column: 9, scope: !26)
+!30 = !{!31, !31, i64 0}
+!31 = !{!"float", !32, i64 0}
+!32 = !{!"omnipotent char", !33, i64 0}
+!33 = !{!"Simple C/C++ TBAA"}
+!34 = !DILocation(line: 4, column: 5, scope: !26)
+!35 = !DILocation(line: 3, column: 31, scope: !26)
+!36 = !DILocation(line: 3, column: 3, scope: !26)
+!37 = distinct !{!37, !27, !38}
+!38 = !DILocation(line: 4, column: 17, scope: !19)
diff --git a/llvm/test/Transforms/LoopRotate/dbgvalue.ll b/llvm/test/Transforms/LoopRotate/dbgvalue.ll
new file mode 100644
index 00000000000..93e3c4c252c
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/dbgvalue.ll
@@ -0,0 +1,159 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone
+declare void @llvm.dbg.value(metadata, metadata, metadata) nounwind readnone
+
+define i32 @tak(i32 %x, i32 %y, i32 %z) nounwind ssp !dbg !0 {
+; CHECK-LABEL: define i32 @tak(
+; CHECK: entry
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %x
+; CHECK: tail call void @llvm.dbg.value(metadata i32 %call
+
+entry:
+ br label %tailrecurse
+
+tailrecurse: ; preds = %if.then, %entry
+ %x.tr = phi i32 [ %x, %entry ], [ %call, %if.then ]
+ %y.tr = phi i32 [ %y, %entry ], [ %call9, %if.then ]
+ %z.tr = phi i32 [ %z, %entry ], [ %call14, %if.then ]
+ tail call void @llvm.dbg.value(metadata i32 %x.tr, metadata !6, metadata !DIExpression()), !dbg !7
+ tail call void @llvm.dbg.value(metadata i32 %y.tr, metadata !8, metadata !DIExpression()), !dbg !9
+ tail call void @llvm.dbg.value(metadata i32 %z.tr, metadata !10, metadata !DIExpression()), !dbg !11
+ %cmp = icmp slt i32 %y.tr, %x.tr, !dbg !12
+ br i1 %cmp, label %if.then, label %if.end, !dbg !12
+
+if.then: ; preds = %tailrecurse
+ %sub = sub nsw i32 %x.tr, 1, !dbg !14
+ %call = tail call i32 @tak(i32 %sub, i32 %y.tr, i32 %z.tr), !dbg !14
+ %sub6 = sub nsw i32 %y.tr, 1, !dbg !14
+ %call9 = tail call i32 @tak(i32 %sub6, i32 %z.tr, i32 %x.tr), !dbg !14
+ %sub11 = sub nsw i32 %z.tr, 1, !dbg !14
+ %call14 = tail call i32 @tak(i32 %sub11, i32 %x.tr, i32 %y.tr), !dbg !14
+ br label %tailrecurse
+
+if.end: ; preds = %tailrecurse
+ br label %return, !dbg !16
+
+return: ; preds = %if.end
+ ret i32 %z.tr, !dbg !17
+}
+
+define i32 @tak2(i32 %x, i32 %y, i32 %z) nounwind ssp !dbg !21 {
+; CHECK-LABEL: define i32 @tak2(
+; CHECK: entry
+; CHECK: tail call void @llvm.dbg.value(metadata i32 %x.tr
+; CHECK: tail call void @llvm.dbg.value(metadata i32 undef
+
+entry:
+ br label %tailrecurse
+
+tailrecurse: ; preds = %if.then, %entry
+ %x.tr = phi i32 [ %x, %entry ], [ %call, %if.then ]
+ %y.tr = phi i32 [ %y, %entry ], [ %call9, %if.then ]
+ %z.tr = phi i32 [ %z, %entry ], [ %call14, %if.then ]
+ %cmp = icmp slt i32 %y.tr, %x.tr, !dbg !22
+ br i1 %cmp, label %if.then, label %if.end, !dbg !22
+
+if.then: ; preds = %tailrecurse
+ tail call void @llvm.dbg.value(metadata i32 %x.tr, metadata !36, metadata !DIExpression()), !dbg !37
+ tail call void @llvm.dbg.value(metadata i32 %y.tr, metadata !38, metadata !DIExpression()), !dbg !39
+ tail call void @llvm.dbg.value(metadata i32 %z.tr, metadata !40, metadata !DIExpression()), !dbg !41
+ %sub = sub nsw i32 %x.tr, 1, !dbg !24
+ %call = tail call i32 @tak(i32 %sub, i32 %y.tr, i32 %z.tr), !dbg !24
+ %sub6 = sub nsw i32 %y.tr, 1, !dbg !24
+ %call9 = tail call i32 @tak(i32 %sub6, i32 %z.tr, i32 %x.tr), !dbg !24
+ %sub11 = sub nsw i32 %z.tr, 1, !dbg !24
+ %call14 = tail call i32 @tak(i32 %sub11, i32 %x.tr, i32 %y.tr), !dbg !24
+ br label %tailrecurse
+
+if.end: ; preds = %tailrecurse
+ tail call void @llvm.dbg.value(metadata i32 %x.tr, metadata !36, metadata !DIExpression()), !dbg !37
+ tail call void @llvm.dbg.value(metadata i32 %y.tr, metadata !38, metadata !DIExpression()), !dbg !39
+ tail call void @llvm.dbg.value(metadata i32 %z.tr, metadata !40, metadata !DIExpression()), !dbg !41
+ br label %return, !dbg !26
+
+return: ; preds = %if.end
+ ret i32 %z.tr, !dbg !27
+}
+
+@channelColumns = external global i64
+@horzPlane = external global i8*, align 8
+
+define void @FindFreeHorzSeg(i64 %startCol, i64 %row, i64* %rowStart) {
+; Ensure that the loop increment basic block is rotated into the tail of the
+; body, even though it contains a debug intrinsic call.
+; CHECK-LABEL: define void @FindFreeHorzSeg(
+; CHECK: %dec = add
+; CHECK-NEXT: tail call void @llvm.dbg.value
+; CHECK: %cmp = icmp
+; CHECK: br i1 %cmp
+; CHECK: phi i64 [ %{{[^,]*}}, %{{[^,]*}} ]
+; CHECK-NEXT: br label %for.end
+
+
+entry:
+ br label %for.cond
+
+for.cond:
+ %i.0 = phi i64 [ %startCol, %entry ], [ %dec, %for.inc ]
+ %cmp = icmp eq i64 %i.0, 0
+ br i1 %cmp, label %for.end, label %for.body
+
+for.body:
+ %0 = load i64, i64* @channelColumns, align 8
+ %mul = mul i64 %0, %row
+ %add = add i64 %mul, %i.0
+ %1 = load i8*, i8** @horzPlane, align 8
+ %arrayidx = getelementptr inbounds i8, i8* %1, i64 %add
+ %2 = load i8, i8* %arrayidx, align 1
+ %tobool = icmp eq i8 %2, 0
+ br i1 %tobool, label %for.inc, label %for.end
+
+for.inc:
+ %dec = add i64 %i.0, -1
+ tail call void @llvm.dbg.value(metadata i64 %dec, metadata !DILocalVariable(scope: !0), metadata !DIExpression()), !dbg !DILocation(scope: !0)
+ br label %for.cond
+
+for.end:
+ %add1 = add i64 %i.0, 1
+ store i64 %add1, i64* %rowStart, align 8
+ ret void
+}
+
+!llvm.module.flags = !{!20}
+!llvm.dbg.cu = !{!2}
+
+!0 = distinct !DISubprogram(name: "tak", line: 32, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !18, scope: !1, type: !3)
+!1 = !DIFile(filename: "/Volumes/Lalgate/cj/llvm/projects/llvm-test/SingleSource/Benchmarks/BenchmarkGame/recursive.c", directory: "/Volumes/Lalgate/cj/D/projects/llvm-test/SingleSource/Benchmarks/BenchmarkGame")
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 2.9 (trunk 125492)", isOptimized: true, emissionKind: FullDebug, file: !18)
+!3 = !DISubroutineType(types: !4)
+!4 = !{!5}
+!5 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!6 = !DILocalVariable(name: "x", line: 32, arg: 1, scope: !0, file: !1, type: !5)
+!7 = !DILocation(line: 32, column: 13, scope: !0)
+!8 = !DILocalVariable(name: "y", line: 32, arg: 2, scope: !0, file: !1, type: !5)
+!9 = !DILocation(line: 32, column: 20, scope: !0)
+!10 = !DILocalVariable(name: "z", line: 32, arg: 3, scope: !0, file: !1, type: !5)
+!11 = !DILocation(line: 32, column: 27, scope: !0)
+!12 = !DILocation(line: 33, column: 3, scope: !13)
+!13 = distinct !DILexicalBlock(line: 32, column: 30, file: !18, scope: !0)
+!14 = !DILocation(line: 34, column: 5, scope: !15)
+!15 = distinct !DILexicalBlock(line: 33, column: 14, file: !18, scope: !13)
+!16 = !DILocation(line: 36, column: 3, scope: !13)
+!17 = !DILocation(line: 37, column: 1, scope: !13)
+!18 = !DIFile(filename: "/Volumes/Lalgate/cj/llvm/projects/llvm-test/SingleSource/Benchmarks/BenchmarkGame/recursive.c", directory: "/Volumes/Lalgate/cj/D/projects/llvm-test/SingleSource/Benchmarks/BenchmarkGame")
+!20 = !{i32 1, !"Debug Info Version", i32 3}
+!21 = distinct !DISubprogram(name: "tak", line: 32, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !2, file: !18, scope: !1, type: !3)
+!22 = !DILocation(line: 33, column: 3, scope: !23)
+!23 = distinct !DILexicalBlock(line: 32, column: 30, file: !18, scope: !21)
+!24 = !DILocation(line: 34, column: 5, scope: !25)
+!25 = distinct !DILexicalBlock(line: 33, column: 14, file: !18, scope: !23)
+!26 = !DILocation(line: 36, column: 3, scope: !23)
+!27 = !DILocation(line: 37, column: 1, scope: !23)
+!36 = !DILocalVariable(name: "x", line: 32, arg: 1, scope: !21, file: !1, type: !5)
+!37 = !DILocation(line: 32, column: 13, scope: !21)
+!38 = !DILocalVariable(name: "y", line: 32, arg: 2, scope: !21, file: !1, type: !5)
+!39 = !DILocation(line: 32, column: 20, scope: !21)
+!40 = !DILocalVariable(name: "z", line: 32, arg: 3, scope: !21, file: !1, type: !5)
+!41 = !DILocation(line: 32, column: 27, scope: !21)
diff --git a/llvm/test/Transforms/LoopRotate/indirectbr.ll b/llvm/test/Transforms/LoopRotate/indirectbr.ll
new file mode 100644
index 00000000000..a26ec375953
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/indirectbr.ll
@@ -0,0 +1,75 @@
+; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info | FileCheck %s
+; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s
+
+; PR5502
+define void @z80_do_opcodes() nounwind {
+entry:
+ br label %while.cond
+
+while.cond: ; preds = %end_opcode, %entry
+ br label %while.body
+
+while.body: ; preds = %while.cond
+ br label %indirectgoto
+
+run_opcode: ; preds = %indirectgoto
+ %tmp276 = load i8, i8* undef ; <i8> [#uses=1]
+ br label %indirectgoto
+
+if.else295: ; preds = %divide_late
+ br label %end_opcode
+
+end_opcode: ; preds = %indirectgoto, %sw.default42406, %sw.default, %if.else295
+ %opcode.2 = phi i8 [ %opcode.0, %indirectgoto ], [ 0, %sw.default42406 ], [ undef, %sw.default ], [ %opcode.0, %if.else295 ] ; <i8> [#uses=0]
+ switch i32 undef, label %while.cond [
+ i32 221, label %sw.bb11691
+ i32 253, label %sw.bb30351
+ ]
+
+sw.bb11691: ; preds = %end_opcode
+ br label %sw.default
+
+sw.default: ; preds = %sw.bb11691
+ br label %end_opcode
+
+sw.bb30351: ; preds = %end_opcode
+ br label %sw.default42406
+
+sw.default42406: ; preds = %sw.bb30351
+ br label %end_opcode
+
+indirectgoto: ; preds = %run_opcode, %while.body
+ %opcode.0 = phi i8 [ undef, %while.body ], [ %tmp276, %run_opcode ] ; <i8> [#uses=2]
+ indirectbr i8* undef, [label %run_opcode, label %if.else295, label %end_opcode]
+}
+
+; CHECK-LABEL: @foo
+define void @foo(i1 %a, i1 %b, i8* %c) {
+; CHECK: entry
+; CHECK-NEXT: br i1 %a, label %return, label %preheader
+entry:
+ br i1 %a, label %return, label %preheader
+
+; CHECK: preheader:
+; CHECK-NEXT: br label %header
+preheader:
+ br label %header
+
+; CHECK: header:
+; CHECK-NEXT: br i1 %b, label %return, label %body
+header:
+ br i1 %b, label %return, label %body
+
+; CHECK: body:
+; CHECK-NEXT: indirectbr i8* %c, [label %return, label %latch]
+body:
+ indirectbr i8* %c, [label %return, label %latch]
+
+; CHECK: latch:
+; CHECK-NEXT: br label %header
+latch:
+ br label %header
+
+return:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/loopexitinglatch.ll b/llvm/test/Transforms/LoopRotate/loopexitinglatch.ll
new file mode 100644
index 00000000000..dee29ec958e
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/loopexitinglatch.ll
@@ -0,0 +1,235 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -loop-rotate < %s -verify-loop-info -verify-dom-info | FileCheck %s
+; RUN: opt -S -loop-rotate < %s -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "thumbv8m.base-arm-none-eabi"
+
+%struct.List = type { %struct.List*, i32 }
+
+define void @list_add(%struct.List** nocapture %list, %struct.List* %data) {
+; CHECK-LABEL: @list_add(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = load %struct.List*, %struct.List** [[LIST:%.*]], align 4
+; CHECK-NEXT: [[VAL2:%.*]] = getelementptr inbounds [[STRUCT_LIST:%.*]], %struct.List* [[TMP0]], i32 0, i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[VAL2]], align 4
+; CHECK-NEXT: [[VAL1:%.*]] = getelementptr inbounds [[STRUCT_LIST]], %struct.List* [[DATA:%.*]], i32 0, i32 1
+; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[VAL1]], align 4
+; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: br i1 [[CMP3]], label [[IF_THEN_LR_PH:%.*]], label [[IF_ELSE6:%.*]]
+; CHECK: if.then.lr.ph:
+; CHECK-NEXT: br label [[IF_THEN:%.*]]
+; CHECK: for.cond:
+; CHECK-NEXT: [[CURR_0:%.*]] = phi %struct.List* [ [[TMP5:%.*]], [[IF_THEN]] ]
+; CHECK-NEXT: [[PREV_0:%.*]] = phi %struct.List* [ [[CURR_04:%.*]], [[IF_THEN]] ]
+; CHECK-NEXT: [[VAL:%.*]] = getelementptr inbounds [[STRUCT_LIST]], %struct.List* [[CURR_0]], i32 0, i32 1
+; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[VAL]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[VAL1]], align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP3]], [[TMP4]]
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[FOR_COND_IF_ELSE6_CRIT_EDGE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[CURR_04]] = phi %struct.List* [ [[TMP0]], [[IF_THEN_LR_PH]] ], [ [[CURR_0]], [[FOR_COND:%.*]] ]
+; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LIST]], %struct.List* [[CURR_04]], i32 0, i32 0
+; CHECK-NEXT: [[TMP5]] = load %struct.List*, %struct.List** [[NEXT]], align 4
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq %struct.List* [[TMP5]], null
+; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[FOR_COND]]
+; CHECK: if.else:
+; CHECK-NEXT: [[NEXT_LCSSA:%.*]] = phi %struct.List** [ [[NEXT]], [[IF_THEN]] ]
+; CHECK-NEXT: store %struct.List* [[DATA]], %struct.List** [[NEXT_LCSSA]], align 4
+; CHECK-NEXT: [[NEXT5:%.*]] = getelementptr inbounds [[STRUCT_LIST]], %struct.List* [[DATA]], i32 0, i32 0
+; CHECK-NEXT: store %struct.List* null, %struct.List** [[NEXT5]], align 4
+; CHECK-NEXT: br label [[FOR_END:%.*]]
+; CHECK: for.cond.if.else6_crit_edge:
+; CHECK-NEXT: [[SPLIT:%.*]] = phi %struct.List* [ [[PREV_0]], [[FOR_COND]] ]
+; CHECK-NEXT: br label [[IF_ELSE6]]
+; CHECK: if.else6:
+; CHECK-NEXT: [[PREV_0_LCSSA:%.*]] = phi %struct.List* [ [[SPLIT]], [[FOR_COND_IF_ELSE6_CRIT_EDGE]] ], [ null, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[TOBOOL7:%.*]] = icmp eq %struct.List* [[PREV_0_LCSSA]], null
+; CHECK-NEXT: br i1 [[TOBOOL7]], label [[IF_ELSE12:%.*]], label [[IF_THEN8:%.*]]
+; CHECK: if.then8:
+; CHECK-NEXT: [[NEXT9:%.*]] = getelementptr inbounds [[STRUCT_LIST]], %struct.List* [[PREV_0_LCSSA]], i32 0, i32 0
+; CHECK-NEXT: [[TMP6:%.*]] = bitcast %struct.List* [[PREV_0_LCSSA]] to i32*
+; CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[TMP6]], align 4
+; CHECK-NEXT: [[TMP8:%.*]] = bitcast %struct.List* [[DATA]] to i32*
+; CHECK-NEXT: store i32 [[TMP7]], i32* [[TMP8]], align 4
+; CHECK-NEXT: store %struct.List* [[DATA]], %struct.List** [[NEXT9]], align 4
+; CHECK-NEXT: br label [[FOR_END]]
+; CHECK: if.else12:
+; CHECK-NEXT: [[TMP9:%.*]] = bitcast %struct.List** [[LIST]] to i32*
+; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP9]], align 4
+; CHECK-NEXT: [[TMP11:%.*]] = bitcast %struct.List* [[DATA]] to i32*
+; CHECK-NEXT: store i32 [[TMP10]], i32* [[TMP11]], align 4
+; CHECK-NEXT: store %struct.List* [[DATA]], %struct.List** [[LIST]], align 4
+; CHECK-NEXT: br label [[FOR_END]]
+; CHECK: for.end:
+; CHECK-NEXT: ret void
+;
+entry:
+ %0 = load %struct.List*, %struct.List** %list, align 4
+ br label %for.cond
+
+for.cond: ; preds = %if.then, %entry
+ %curr.0 = phi %struct.List* [ %0, %entry ], [ %3, %if.then ]
+ %prev.0 = phi %struct.List* [ null, %entry ], [ %curr.0, %if.then ]
+ %val = getelementptr inbounds %struct.List, %struct.List* %curr.0, i32 0, i32 1
+ %1 = load i32, i32* %val, align 4
+ %val1 = getelementptr inbounds %struct.List, %struct.List* %data, i32 0, i32 1
+ %2 = load i32, i32* %val1, align 4
+ %cmp = icmp slt i32 %1, %2
+ br i1 %cmp, label %if.then, label %if.else6
+
+if.then: ; preds = %for.cond
+ %next = getelementptr inbounds %struct.List, %struct.List* %curr.0, i32 0, i32 0
+ %3 = load %struct.List*, %struct.List** %next, align 4
+ %tobool = icmp eq %struct.List* %3, null
+ br i1 %tobool, label %if.else, label %for.cond
+
+if.else: ; preds = %if.then
+ %next.lcssa = phi %struct.List** [ %next, %if.then ]
+ store %struct.List* %data, %struct.List** %next.lcssa, align 4
+ %next5 = getelementptr inbounds %struct.List, %struct.List* %data, i32 0, i32 0
+ store %struct.List* null, %struct.List** %next5, align 4
+ br label %for.end
+
+if.else6: ; preds = %for.cond
+ %prev.0.lcssa = phi %struct.List* [ %prev.0, %for.cond ]
+ %tobool7 = icmp eq %struct.List* %prev.0.lcssa, null
+ br i1 %tobool7, label %if.else12, label %if.then8
+
+if.then8: ; preds = %if.else6
+ %next9 = getelementptr inbounds %struct.List, %struct.List* %prev.0.lcssa, i32 0, i32 0
+ %4 = bitcast %struct.List* %prev.0.lcssa to i32*
+ %5 = load i32, i32* %4, align 4
+ %6 = bitcast %struct.List* %data to i32*
+ store i32 %5, i32* %6, align 4
+ store %struct.List* %data, %struct.List** %next9, align 4
+ br label %for.end
+
+if.else12: ; preds = %if.else6
+ %7 = bitcast %struct.List** %list to i32*
+ %8 = load i32, i32* %7, align 4
+ %9 = bitcast %struct.List* %data to i32*
+ store i32 %8, i32* %9, align 4
+ store %struct.List* %data, %struct.List** %list, align 4
+ br label %for.end
+
+for.end: ; preds = %if.else12, %if.then8, %if.else
+ ret void
+}
+
+define i32 @test2(i32* %l) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[L:%.*]], align 4
+; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TOBOOL2]], label [[CLEANUP:%.*]], label [[DO_COND_LR_PH:%.*]]
+; CHECK: do.cond.lr.ph:
+; CHECK-NEXT: br label [[DO_COND:%.*]]
+; CHECK: do.body:
+; CHECK-NEXT: [[A_0:%.*]] = phi i32 [ [[REM:%.*]], [[DO_COND]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[L]], align 4
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT: br i1 [[TOBOOL]], label [[DO_BODY_CLEANUP_CRIT_EDGE:%.*]], label [[DO_COND]]
+; CHECK: do.body.cleanup_crit_edge:
+; CHECK-NEXT: [[SPLIT:%.*]] = phi i32 [ [[A_0]], [[DO_BODY:%.*]] ]
+; CHECK-NEXT: br label [[CLEANUP]]
+; CHECK: cleanup:
+; CHECK-NEXT: [[A_0_LCSSA:%.*]] = phi i32 [ [[SPLIT]], [[DO_BODY_CLEANUP_CRIT_EDGE]] ], [ 100, [[ENTRY:%.*]] ]
+; CHECK-NEXT: store i32 10, i32* [[L]], align 4
+; CHECK-NEXT: br label [[CLEANUP2:%.*]]
+; CHECK: do.cond:
+; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ [[TMP0]], [[DO_COND_LR_PH]] ], [ [[TMP1]], [[DO_BODY]] ]
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP2]], 13
+; CHECK-NEXT: [[REM]] = srem i32 [[MUL]], 27
+; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[L]], align 4
+; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[TMP3]], 0
+; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CLEANUP2_LOOPEXIT:%.*]], label [[DO_BODY]]
+; CHECK: cleanup2.loopexit:
+; CHECK-NEXT: br label [[CLEANUP2]]
+; CHECK: cleanup2:
+; CHECK-NEXT: [[RETVAL_2:%.*]] = phi i32 [ [[A_0_LCSSA]], [[CLEANUP]] ], [ 0, [[CLEANUP2_LOOPEXIT]] ]
+; CHECK-NEXT: ret i32 [[RETVAL_2]]
+;
+entry:
+ br label %do.body
+
+do.body: ; preds = %do.cond, %entry
+ %a.0 = phi i32 [ 100, %entry ], [ %rem, %do.cond ]
+ %0 = load i32, i32* %l, align 4
+ %tobool = icmp eq i32 %0, 0
+ br i1 %tobool, label %cleanup, label %do.cond
+
+cleanup: ; preds = %do.body
+ %a.0.lcssa = phi i32 [ %a.0, %do.body ]
+ store i32 10, i32* %l, align 4
+ br label %cleanup2
+
+do.cond: ; preds = %do.body
+ %mul = mul nsw i32 %0, 13
+ %rem = srem i32 %mul, 27
+ %1 = load i32, i32* %l, align 4
+ %tobool1 = icmp eq i32 %1, 0
+ br i1 %tobool1, label %cleanup2.loopexit, label %do.body
+
+cleanup2.loopexit: ; preds = %do.cond
+ br label %cleanup2
+
+cleanup2: ; preds = %cleanup2.loopexit, %cleanup
+ %retval.2 = phi i32 [ %a.0.lcssa, %cleanup ], [ 0, %cleanup2.loopexit ]
+ ret i32 %retval.2
+}
+
+define i32 @no_rotate(i32* %l) {
+; CHECK-LABEL: @no_rotate(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[DO_BODY:%.*]]
+; CHECK: do.body:
+; CHECK-NEXT: [[A_0:%.*]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[REM:%.*]], [[DO_COND:%.*]] ]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[L:%.*]], align 4
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[DO_COND]]
+; CHECK: cleanup:
+; CHECK-NEXT: [[A_0_LCSSA:%.*]] = phi i32 [ [[A_0]], [[DO_BODY]] ]
+; CHECK-NEXT: store i32 10, i32* [[L]], align 4
+; CHECK-NEXT: br label [[CLEANUP2:%.*]]
+; CHECK: do.cond:
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[A_0]], 13
+; CHECK-NEXT: [[REM]] = srem i32 [[MUL]], 27
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[L]], align 4
+; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[TMP1]], 0
+; CHECK-NEXT: br i1 [[TOBOOL1]], label [[CLEANUP2_LOOPEXIT:%.*]], label [[DO_BODY]]
+; CHECK: cleanup2.loopexit:
+; CHECK-NEXT: br label [[CLEANUP2]]
+; CHECK: cleanup2:
+; CHECK-NEXT: [[RETVAL_2:%.*]] = phi i32 [ [[A_0_LCSSA]], [[CLEANUP]] ], [ 0, [[CLEANUP2_LOOPEXIT]] ]
+; CHECK-NEXT: ret i32 [[RETVAL_2]]
+;
+entry:
+ br label %do.body
+
+do.body: ; preds = %do.cond, %entry
+ %a.0 = phi i32 [ 100, %entry ], [ %rem, %do.cond ]
+ %0 = load i32, i32* %l, align 4
+ %tobool = icmp eq i32 %0, 0
+ br i1 %tobool, label %cleanup, label %do.cond
+
+cleanup: ; preds = %do.body
+ %a.0.lcssa = phi i32 [ %a.0, %do.body ]
+ store i32 10, i32* %l, align 4
+ br label %cleanup2
+
+do.cond: ; preds = %do.body
+ %mul = mul nsw i32 %a.0, 13
+ %rem = srem i32 %mul, 27
+ %1 = load i32, i32* %l, align 4
+ %tobool1 = icmp eq i32 %1, 0
+ br i1 %tobool1, label %cleanup2.loopexit, label %do.body
+
+cleanup2.loopexit: ; preds = %do.cond
+ br label %cleanup2
+
+cleanup2: ; preds = %cleanup2.loopexit, %cleanup
+ %retval.2 = phi i32 [ %a.0.lcssa, %cleanup ], [ 0, %cleanup2.loopexit ]
+ ret i32 %retval.2
+}
+
diff --git a/llvm/test/Transforms/LoopRotate/multiple-exits.ll b/llvm/test/Transforms/LoopRotate/multiple-exits.ll
new file mode 100644
index 00000000000..c6f153b8ca3
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/multiple-exits.ll
@@ -0,0 +1,237 @@
+; RUN: opt -S -loop-rotate < %s -verify-loop-info -verify-dom-info | FileCheck %s
+; RUN: opt -S -loop-rotate < %s -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.8.0"
+
+; PR7447
+define i32 @test1([100 x i32]* nocapture %a) nounwind readonly {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.cond1, %entry
+ %sum.0 = phi i32 [ 0, %entry ], [ %sum.1, %for.cond1 ]
+ %i.0 = phi i1 [ true, %entry ], [ false, %for.cond1 ]
+ br i1 %i.0, label %for.cond1, label %return
+
+for.cond1: ; preds = %for.cond, %land.rhs
+ %sum.1 = phi i32 [ %add, %land.rhs ], [ %sum.0, %for.cond ]
+ %i.1 = phi i32 [ %inc, %land.rhs ], [ 0, %for.cond ]
+ %cmp2 = icmp ult i32 %i.1, 100
+ br i1 %cmp2, label %land.rhs, label %for.cond
+
+land.rhs: ; preds = %for.cond1
+ %conv = zext i32 %i.1 to i64
+ %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* %a, i64 0, i64 %conv
+ %0 = load i32, i32* %arrayidx, align 4
+ %add = add i32 %0, %sum.1
+ %cmp4 = icmp ugt i32 %add, 1000
+ %inc = add i32 %i.1, 1
+ br i1 %cmp4, label %return, label %for.cond1
+
+return: ; preds = %for.cond, %land.rhs
+ %retval.0 = phi i32 [ 1000, %land.rhs ], [ %sum.0, %for.cond ]
+ ret i32 %retval.0
+
+; CHECK-LABEL: @test1(
+; CHECK: for.cond1.preheader:
+; CHECK: %sum.04 = phi i32 [ 0, %entry ], [ %sum.1.lcssa, %for.cond.loopexit ]
+; CHECK: br label %for.cond1
+
+; CHECK: for.cond1:
+; CHECK: %sum.1 = phi i32 [ %add, %land.rhs ], [ %sum.04, %for.cond1.preheader ]
+; CHECK: %i.1 = phi i32 [ %inc, %land.rhs ], [ 0, %for.cond1.preheader ]
+; CHECK: %cmp2 = icmp ult i32 %i.1, 100
+; CHECK: br i1 %cmp2, label %land.rhs, label %for.cond.loopexit
+}
+
+define void @test2(i32 %x) nounwind {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %if.end, %entry
+ %i.0 = phi i32 [ 0, %entry ], [ %inc, %if.end ]
+ %cmp = icmp eq i32 %i.0, %x
+ br i1 %cmp, label %return.loopexit, label %for.body
+
+for.body: ; preds = %for.cond
+ %call = tail call i32 @foo(i32 %i.0) nounwind
+ %tobool = icmp eq i32 %call, 0
+ br i1 %tobool, label %if.end, label %a
+
+if.end: ; preds = %for.body
+ %call1 = tail call i32 @foo(i32 42) nounwind
+ %inc = add i32 %i.0, 1
+ br label %for.cond
+
+a: ; preds = %for.body
+ %call2 = tail call i32 @bar(i32 1) nounwind
+ br label %return
+
+return.loopexit: ; preds = %for.cond
+ br label %return
+
+return: ; preds = %return.loopexit, %a
+ ret void
+
+; CHECK-LABEL: @test2(
+; CHECK: if.end:
+; CHECK: %inc = add i32 %i.02, 1
+; CHECK: %cmp = icmp eq i32 %inc, %x
+; CHECK: br i1 %cmp, label %for.cond.return.loopexit_crit_edge, label %for.body
+}
+
+declare i32 @foo(i32)
+
+declare i32 @bar(i32)
+
+@_ZTIi = external constant i8*
+
+; Verify dominators.
+define void @test3(i32 %x) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ %cmp2 = icmp eq i32 0, %x
+ br i1 %cmp2, label %try.cont.loopexit, label %for.body.lr.ph
+
+for.body.lr.ph: ; preds = %entry
+ br label %for.body
+
+for.body: ; preds = %for.body.lr.ph, %for.inc
+ %i.03 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
+ invoke void @_Z3fooi(i32 %i.03)
+ to label %for.inc unwind label %lpad
+
+for.inc: ; preds = %for.body
+ %inc = add i32 %i.03, 1
+ %cmp = icmp eq i32 %inc, %x
+ br i1 %cmp, label %for.cond.try.cont.loopexit_crit_edge, label %for.body
+
+lpad: ; preds = %for.body
+ %0 = landingpad { i8*, i32 }
+ catch i8* bitcast (i8** @_ZTIi to i8*)
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = extractvalue { i8*, i32 } %0, 1
+ %3 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) nounwind
+ %matches = icmp eq i32 %2, %3
+ br i1 %matches, label %catch, label %eh.resume
+
+catch: ; preds = %lpad
+ %4 = tail call i8* @__cxa_begin_catch(i8* %1) nounwind
+ br i1 true, label %invoke.cont2.loopexit, label %for.body.i.lr.ph
+
+for.body.i.lr.ph: ; preds = %catch
+ br label %for.body.i
+
+for.body.i: ; preds = %for.body.i.lr.ph, %for.inc.i
+ %i.0.i1 = phi i32 [ 0, %for.body.i.lr.ph ], [ %inc.i, %for.inc.i ]
+ invoke void @_Z3fooi(i32 %i.0.i1)
+ to label %for.inc.i unwind label %lpad.i
+
+for.inc.i: ; preds = %for.body.i
+ %inc.i = add i32 %i.0.i1, 1
+ %cmp.i = icmp eq i32 %inc.i, 0
+ br i1 %cmp.i, label %for.cond.i.invoke.cont2.loopexit_crit_edge, label %for.body.i
+
+lpad.i: ; preds = %for.body.i
+ %5 = landingpad { i8*, i32 }
+ catch i8* bitcast (i8** @_ZTIi to i8*)
+ %6 = extractvalue { i8*, i32 } %5, 0
+ %7 = extractvalue { i8*, i32 } %5, 1
+ %matches.i = icmp eq i32 %7, %3
+ br i1 %matches.i, label %catch.i, label %lpad1.body
+
+catch.i: ; preds = %lpad.i
+ %8 = tail call i8* @__cxa_begin_catch(i8* %6) nounwind
+ invoke void @test3(i32 0)
+ to label %invoke.cont2.i unwind label %lpad1.i
+
+invoke.cont2.i: ; preds = %catch.i
+ tail call void @__cxa_end_catch() nounwind
+ br label %invoke.cont2
+
+lpad1.i: ; preds = %catch.i
+ %9 = landingpad { i8*, i32 }
+ cleanup
+ %10 = extractvalue { i8*, i32 } %9, 0
+ %11 = extractvalue { i8*, i32 } %9, 1
+ tail call void @__cxa_end_catch() nounwind
+ br label %lpad1.body
+
+for.cond.i.invoke.cont2.loopexit_crit_edge: ; preds = %for.inc.i
+ br label %invoke.cont2.loopexit
+
+invoke.cont2.loopexit: ; preds = %for.cond.i.invoke.cont2.loopexit_crit_edge, %catch
+ br label %invoke.cont2
+
+invoke.cont2: ; preds = %invoke.cont2.loopexit, %invoke.cont2.i
+ tail call void @__cxa_end_catch() nounwind
+ br label %try.cont
+
+for.cond.try.cont.loopexit_crit_edge: ; preds = %for.inc
+ br label %try.cont.loopexit
+
+try.cont.loopexit: ; preds = %for.cond.try.cont.loopexit_crit_edge, %entry
+ br label %try.cont
+
+try.cont: ; preds = %try.cont.loopexit, %invoke.cont2
+ ret void
+
+lpad1.body: ; preds = %lpad1.i, %lpad.i
+ %exn.slot.0.i = phi i8* [ %10, %lpad1.i ], [ %6, %lpad.i ]
+ %ehselector.slot.0.i = phi i32 [ %11, %lpad1.i ], [ %7, %lpad.i ]
+ tail call void @__cxa_end_catch() nounwind
+ br label %eh.resume
+
+eh.resume: ; preds = %lpad1.body, %lpad
+ %exn.slot.0 = phi i8* [ %exn.slot.0.i, %lpad1.body ], [ %1, %lpad ]
+ %ehselector.slot.0 = phi i32 [ %ehselector.slot.0.i, %lpad1.body ], [ %2, %lpad ]
+ %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0
+ %lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1
+ resume { i8*, i32 } %lpad.val5
+}
+
+declare void @_Z3fooi(i32)
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i32 @llvm.eh.typeid.for(i8*) nounwind readnone
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
+
+define void @test4() nounwind uwtable {
+entry:
+ br label %"7"
+
+"3": ; preds = %"7"
+ br i1 undef, label %"31", label %"4"
+
+"4": ; preds = %"3"
+ %. = select i1 undef, float 0x3F50624DE0000000, float undef
+ %0 = add i32 %1, 1
+ br label %"7"
+
+"7": ; preds = %"4", %entry
+ %1 = phi i32 [ %0, %"4" ], [ 0, %entry ]
+ %2 = icmp slt i32 %1, 100
+ br i1 %2, label %"3", label %"8"
+
+"8": ; preds = %"7"
+ br i1 undef, label %"9", label %"31"
+
+"9": ; preds = %"8"
+ br label %"33"
+
+"27": ; preds = %"31"
+ unreachable
+
+"31": ; preds = %"8", %"3"
+ br i1 undef, label %"27", label %"32"
+
+"32": ; preds = %"31"
+ br label %"33"
+
+"33": ; preds = %"32", %"9"
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/nosimplifylatch.ll b/llvm/test/Transforms/LoopRotate/nosimplifylatch.ll
new file mode 100644
index 00000000000..07ff6643c6d
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/nosimplifylatch.ll
@@ -0,0 +1,34 @@
+; RUN: opt -S < %s -loop-rotate -licm -verify-dom-info -verify-loop-info | FileCheck %s
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+target triple = "arm64-apple-ios8.0.0"
+
+;CHECK: for.inc:
+;CHECK-NEXT: %incdec.ptr.i = getelementptr
+
+; Function Attrs: alwaysinline inlinehint nounwind readonly ssp
+define linkonce_odr hidden i64 @_ZNSt3__14findINS_11__wrap_iterIPiEEiEET_S4_S4_RKT0_(i64 %__first.coerce, i64 %__last.coerce, i32* nocapture readonly dereferenceable(4) %__value_) {
+entry:
+ %coerce.val.ip = inttoptr i64 %__first.coerce to i32*
+ %coerce.val.ip2 = inttoptr i64 %__last.coerce to i32*
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %coerce.val.ip9 = phi i32* [ %incdec.ptr.i, %for.inc ], [ %coerce.val.ip, %entry ]
+ %lnot.i = icmp eq i32* %coerce.val.ip9, %coerce.val.ip2
+ br i1 %lnot.i, label %for.end, label %for.body
+
+for.body: ; preds = %for.cond
+ %0 = load i32, i32* %coerce.val.ip9, align 4
+ %1 = load i32, i32* %__value_, align 4
+ %cmp = icmp eq i32 %0, %1
+ br i1 %cmp, label %for.end, label %for.inc
+
+for.inc: ; preds = %for.body
+ %incdec.ptr.i = getelementptr inbounds i32, i32* %coerce.val.ip9, i64 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond, %for.body
+ %coerce.val.ip9.lcssa = phi i32* [ %coerce.val.ip9, %for.cond ], [ %coerce.val.ip9, %for.body ]
+ %coerce.val.pi = ptrtoint i32* %coerce.val.ip9.lcssa to i64
+ ret i64 %coerce.val.pi
+}
diff --git a/llvm/test/Transforms/LoopRotate/oz-disable.ll b/llvm/test/Transforms/LoopRotate/oz-disable.ll
new file mode 100644
index 00000000000..7a6a9bf33a1
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/oz-disable.ll
@@ -0,0 +1,30 @@
+; REQUIRES: asserts
+; RUN: opt < %s -S -Os -debug -debug-only=loop-rotate 2>&1 | FileCheck %s -check-prefix=OS
+; RUN: opt < %s -S -Oz -debug -debug-only=loop-rotate 2>&1 | FileCheck %s -check-prefix=OZ
+
+; Loop should be rotated for -Os but not for -Oz.
+; OS: rotating Loop at depth 1
+; OZ-NOT: rotating Loop at depth 1
+
+@e = global i32 10
+
+declare void @use(i32)
+
+define void @test() {
+entry:
+ %end = load i32, i32* @e
+ br label %loop
+
+loop:
+ %n.phi = phi i32 [ %n, %loop.fin ], [ 0, %entry ]
+ %cond = icmp eq i32 %n.phi, %end
+ br i1 %cond, label %exit, label %loop.fin
+
+loop.fin:
+ %n = add i32 %n.phi, 1
+ call void @use(i32 %n)
+ br label %loop
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/phi-dbgvalue.ll b/llvm/test/Transforms/LoopRotate/phi-dbgvalue.ll
new file mode 100644
index 00000000000..c4e13dc710e
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/phi-dbgvalue.ll
@@ -0,0 +1,82 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+
+;CHECK-LABEL: func
+;CHECK-LABEL: entry
+;CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 %a
+;CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 1, metadata ![[I_VAR:[0-9]+]], metadata !DIExpression())
+;CHECK-LABEL: for.body:
+;CHECK-NEXT: [[I:%.*]] = phi i32 [ 1, %entry ], [ %inc, %for.body ]
+;CHECK-NEXT: tail call void @llvm.dbg.value(metadata i32 [[I]], metadata ![[I_VAR]], metadata !DIExpression())
+
+; CHECK: ![[I_VAR]] = !DILocalVariable(name: "i",{{.*}})
+
+; Function Attrs: noinline nounwind
+define void @func(i32 %a) local_unnamed_addr #0 !dbg !6 {
+entry:
+ tail call void @llvm.dbg.value(metadata i32 %a, metadata !10, metadata !11), !dbg !12
+ tail call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !11), !dbg !15
+ br label %for.cond, !dbg !16
+
+for.cond: ; preds = %for.body, %entry
+ %i.0 = phi i32 [ 1, %entry ], [ %inc, %for.body ]
+ tail call void @llvm.dbg.value(metadata i32 %i.0, metadata !13, metadata !11), !dbg !15
+ %cmp = icmp slt i32 %i.0, 10, !dbg !17
+ br i1 %cmp, label %for.body, label %for.end, !dbg !20
+
+for.body: ; preds = %for.cond
+ %add = add nsw i32 %i.0, %a, !dbg !22
+ %call = tail call i32 @func2(i32 %i.0, i32 %add) #3, !dbg !24
+ %inc = add nsw i32 %i.0, 1, !dbg !25
+ tail call void @llvm.dbg.value(metadata i32 %inc, metadata !13, metadata !11), !dbg !15
+ br label %for.cond, !dbg !27, !llvm.loop !28
+
+for.end: ; preds = %for.cond
+ ret void, !dbg !31
+}
+
+declare i32 @func2(i32, i32) local_unnamed_addr
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { noinline nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "debug-phi.c", directory: "/work/projects/src/tests/debug")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"clang version 5.0.0"}
+!6 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!7 = !DISubroutineType(types: !8)
+!8 = !{null, !9}
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DILocalVariable(name: "a", arg: 1, scope: !6, file: !1, line: 2, type: !9)
+!11 = !DIExpression()
+!12 = !DILocation(line: 2, column: 15, scope: !6)
+!13 = !DILocalVariable(name: "i", scope: !14, file: !1, line: 3, type: !9)
+!14 = distinct !DILexicalBlock(scope: !6, file: !1, line: 3, column: 3)
+!15 = !DILocation(line: 3, column: 11, scope: !14)
+!16 = !DILocation(line: 3, column: 7, scope: !14)
+!17 = !DILocation(line: 3, column: 20, scope: !18)
+!18 = !DILexicalBlockFile(scope: !19, file: !1, discriminator: 1)
+!19 = distinct !DILexicalBlock(scope: !14, file: !1, line: 3, column: 3)
+!20 = !DILocation(line: 3, column: 3, scope: !21)
+!21 = !DILexicalBlockFile(scope: !14, file: !1, discriminator: 1)
+!22 = !DILocation(line: 4, column: 15, scope: !23)
+!23 = distinct !DILexicalBlock(scope: !19, file: !1, line: 3, column: 31)
+!24 = !DILocation(line: 4, column: 5, scope: !23)
+!25 = !DILocation(line: 3, column: 27, scope: !26)
+!26 = !DILexicalBlockFile(scope: !19, file: !1, discriminator: 2)
+!27 = !DILocation(line: 3, column: 3, scope: !26)
+!28 = distinct !{!28, !29, !30}
+!29 = !DILocation(line: 3, column: 3, scope: !14)
+!30 = !DILocation(line: 5, column: 3, scope: !14)
+!31 = !DILocation(line: 6, column: 1, scope: !6)
diff --git a/llvm/test/Transforms/LoopRotate/phi-duplicate.ll b/llvm/test/Transforms/LoopRotate/phi-duplicate.ll
new file mode 100644
index 00000000000..d7f69d8c9cc
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/phi-duplicate.ll
@@ -0,0 +1,41 @@
+; RUN: opt -S -loop-rotate < %s | FileCheck %s
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-apple-darwin10.0"
+
+; PR5837
+define void @test(i32 %N, double* %G) nounwind ssp {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.body, %entry
+ %j.0 = phi i64 [ 1, %entry ], [ %inc, %for.body ] ; <i64> [#uses=5]
+ %cmp = icmp slt i64 %j.0, 1000 ; <i1> [#uses=1]
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %arrayidx = getelementptr inbounds double, double* %G, i64 %j.0 ; <double*> [#uses=1]
+ %tmp3 = load double, double* %arrayidx ; <double> [#uses=1]
+ %sub = sub i64 %j.0, 1 ; <i64> [#uses=1]
+ %arrayidx6 = getelementptr inbounds double, double* %G, i64 %sub ; <double*> [#uses=1]
+ %tmp7 = load double, double* %arrayidx6 ; <double> [#uses=1]
+ %add = fadd double %tmp3, %tmp7 ; <double> [#uses=1]
+ %arrayidx10 = getelementptr inbounds double, double* %G, i64 %j.0 ; <double*> [#uses=1]
+ store double %add, double* %arrayidx10
+ %inc = add nsw i64 %j.0, 1 ; <i64> [#uses=1]
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
+
+; Should only end up with one phi.
+; CHECK-LABEL: define void @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label %for.body
+; CHECK: for.body:
+; CHECK-NEXT: %j.01 = phi i64
+; CHECK-NOT: br
+; CHECK: br i1 %cmp, label %for.body, label %for.end
+; CHECK: for.end:
+; CHECK-NEXT: ret void
diff --git a/llvm/test/Transforms/LoopRotate/pr22337.ll b/llvm/test/Transforms/LoopRotate/pr22337.ll
new file mode 100644
index 00000000000..8195affbcd3
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/pr22337.ll
@@ -0,0 +1,25 @@
+; RUN: opt < %s -loop-rotate -S | FileCheck %s
+; RUN: opt < %s -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
+
+@a = external global i8, align 4
+@tmp = global i8* @a
+
+define void @f() {
+; CHECK-LABEL: define void @f(
+; CHECK: getelementptr i8, i8* @a, i32 0
+entry:
+ br label %for.preheader
+
+for.preheader:
+ br i1 undef, label %if.then8, label %for.body
+
+for.body:
+ br i1 undef, label %if.end, label %if.then8
+
+if.end:
+ %arrayidx = getelementptr i8, i8* @a, i32 0
+ br label %for.preheader
+
+if.then8:
+ unreachable
+}
diff --git a/llvm/test/Transforms/LoopRotate/pr2639.ll b/llvm/test/Transforms/LoopRotate/pr2639.ll
new file mode 100644
index 00000000000..da9a3a2b914
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/pr2639.ll
@@ -0,0 +1,38 @@
+; RUN: opt < %s -loop-deletion -loop-rotate -verify-dom-info -verify-loop-info -disable-output
+; PR 2639
+
+ %struct.HexxagonMove = type { i8, i8, i32 }
+
+define void @_ZN16HexxagonMoveList7addMoveER12HexxagonMove() {
+entry:
+ br i1 false, label %bb9.preheader, label %bb11
+
+bb9.preheader: ; preds = %entry
+ br label %bb9
+
+bb1: ; preds = %bb9
+ br i1 false, label %bb3, label %bb8
+
+bb3: ; preds = %bb1
+ br label %bb5
+
+bb4: ; preds = %bb5
+ br label %bb5
+
+bb5: ; preds = %bb4, %bb3
+ %exitcond = icmp eq i32 0, 0 ; <i1> [#uses=1]
+ br i1 %exitcond, label %bb7, label %bb4
+
+bb7: ; preds = %bb5
+ store %struct.HexxagonMove* null, %struct.HexxagonMove** null, align 4
+ br label %bb8
+
+bb8: ; preds = %bb7, %bb1
+ br label %bb9
+
+bb9: ; preds = %bb8, %bb9.preheader
+ br i1 false, label %bb11, label %bb1
+
+bb11: ; preds = %bb9, %entry
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopRotate/pr33701.ll b/llvm/test/Transforms/LoopRotate/pr33701.ll
new file mode 100644
index 00000000000..8535e317676
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/pr33701.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -disable-output
+; RUN: opt < %s -loop-rotate -verify-dom-info -verify-loop-info -enable-mssa-loop-dependency=true -verify-memoryssa -disable-output
+
+define void @func() {
+bb0:
+ br label %bb1
+
+bb1: ; preds = %bb4, %bb0
+ %0 = phi i16 [ %2, %bb4 ], [ 0, %bb0 ]
+ %1 = icmp sle i16 %0, 2
+ br i1 %1, label %bb2, label %bb5
+
+bb2: ; preds = %bb1
+ br i1 undef, label %bb6, label %bb4
+
+bb3: ; No predecessors!
+ br label %bb6
+
+bb4: ; preds = %bb2
+ %2 = add i16 undef, 1
+ br label %bb1
+
+bb5: ; preds = %bb1
+ br label %bb6
+
+bb6: ; preds = %bb5, %bb3, %bb2
+ unreachable
+}
diff --git a/llvm/test/Transforms/LoopRotate/pr35210.ll b/llvm/test/Transforms/LoopRotate/pr35210.ll
new file mode 100644
index 00000000000..a705642c435
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/pr35210.ll
@@ -0,0 +1,127 @@
+;RUN: opt %s -passes='adce,loop(rotate),adce' -S -debug-pass-manager -debug-only=loop-rotate 2>&1 | FileCheck %s
+;RUN: opt %s -passes='adce,loop(rotate),adce' -S -debug-pass-manager -debug-only=loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa 2>&1 | FileCheck %s --check-prefix=MSSA
+;REQUIRES: asserts
+
+; This test is to make sure we invalidate the post dominator pass after loop rotate simplifies the loop latch.
+; The adce passes are here to make sure post dominator analysis is required.
+
+; CHECK: Starting llvm::Function pass manager run.
+; CHECK-NEXT: Running pass: ADCEPass on f
+; CHECK-NEXT: Running analysis: PostDominatorTreeAnalysis on f
+; CHECK-NEXT: Running pass: FunctionToLoopPassAdaptor{{.*}} on f
+; CHECK-NEXT: Starting llvm::Function pass manager run.
+; CHECK-NEXT: Running pass: LoopSimplifyPass on f
+; CHECK-NEXT: Running analysis: LoopAnalysis on f
+; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on f
+; CHECK-NEXT: Running analysis: AssumptionAnalysis on f
+; CHECK-NEXT: Running pass: LCSSAPass on f
+; CHECK-NEXT: Finished llvm::Function pass manager run.
+; CHECK-NEXT: Running analysis: AAManager on f
+; CHECK-NEXT: Running analysis: TargetLibraryAnalysis on f
+; CHECK-NEXT: Running analysis: ScalarEvolutionAnalysis on f
+; CHECK-NEXT: Running analysis: TargetIRAnalysis on f
+; CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy{{.*}} on f
+; CHECK-NEXT: Starting Loop pass manager run.
+; CHECK-NEXT: Running analysis: PassInstrumentationAnalysis on bb
+; CHECK-NEXT: Running pass: LoopRotatePass on Loop at depth 1 containing: %bb<header><exiting>,%bb4<latch>
+; CHECK-NEXT: Folding loop latch bb4 into bb
+; CHECK-NEXT: Invalidating all non-preserved analyses for: bb
+; CHECK-NEXT: Finished Loop pass manager run.
+; CHECK-NEXT: Invalidating all non-preserved analyses for: f
+; CHECK-NEXT: Invalidating analysis: PostDominatorTreeAnalysis on f
+; CHECK-NEXT: Running pass: ADCEPass on f
+; CHECK-NEXT: Running analysis: PostDominatorTreeAnalysis on f
+; CHECK-NEXT: Finished llvm::Function pass manager run.
+
+; MSSA: Starting llvm::Function pass manager run.
+; MSSA-NEXT: Running pass: ADCEPass on f
+; MSSA-NEXT: Running analysis: PostDominatorTreeAnalysis on f
+; MSSA-NEXT: Running pass: FunctionToLoopPassAdaptor{{.*}} on f
+; MSSA-NEXT: Starting llvm::Function pass manager run.
+; MSSA-NEXT: Running pass: LoopSimplifyPass on f
+; MSSA-NEXT: Running analysis: LoopAnalysis on f
+; MSSA-NEXT: Running analysis: DominatorTreeAnalysis on f
+; MSSA-NEXT: Running analysis: AssumptionAnalysis on f
+; MSSA-NEXT: Running pass: LCSSAPass on f
+; MSSA-NEXT: Finished llvm::Function pass manager run.
+; MSSA-NEXT: Running analysis: MemorySSAAnalysis on f
+; MSSA-NEXT: Running analysis: AAManager on f
+; MSSA-NEXT: Running analysis: TargetLibraryAnalysis on f
+; MSSA-NEXT: Running analysis: ScalarEvolutionAnalysis on f
+; MSSA-NEXT: Running analysis: TargetIRAnalysis on f
+; MSSA-NEXT: Running analysis: InnerAnalysisManagerProxy{{.*}} on f
+; MSSA-NEXT: Starting Loop pass manager run.
+; MSSA-NEXT: Running analysis: PassInstrumentationAnalysis on bb
+; MSSA-NEXT: Running pass: LoopRotatePass on Loop at depth 1 containing: %bb<header><exiting>,%bb4<latch>
+; MSSA-NEXT: Folding loop latch bb4 into bb
+; MSSA-NEXT: Invalidating all non-preserved analyses for: bb
+; MSSA-NEXT: Finished Loop pass manager run.
+; MSSA-NEXT: Invalidating all non-preserved analyses for: f
+; MSSA-NEXT: Invalidating analysis: PostDominatorTreeAnalysis on f
+; MSSA-NEXT: Running pass: ADCEPass on f
+; MSSA-NEXT: Running analysis: PostDominatorTreeAnalysis on f
+; MSSA-NEXT: Finished llvm::Function pass manager run.
+
+
+; CHECK-LABEL: define i8 @f() {
+; CHECK-NEXT : entry:
+; CHECK-NEXT : br label %bb
+; CHECK-NEXT :
+; CHECK-NEXT : bb: ; preds = %bb, %entry
+; CHECK-NEXT : %mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb ]
+; CHECK-NEXT : %tmp5 = icmp eq i8 %mode.0, 1
+; CHECK-NEXT : %indvar.next = add i8 %mode.0, 1
+; CHECK-NEXT : br i1 %tmp5, label %bb5, label %bb
+; CHECK-NEXT :
+; CHECK-NEXT : bb5: ; preds = %bb
+; CHECK-NEXT : tail call void @raise_exception() #0
+; CHECK-NEXT : unreachable
+; CHECK-NEXT : }
+; CHECK-NEXT :
+; CHECK-NEXT : ; Function Attrs: noreturn
+; CHECK-NEXT : declare void @raise_exception() #0
+; CHECK-NEXT :
+; CHECK-NEXT : attributes #0 = { noreturn }
+
+; MSSA-LABEL: define i8 @f() {
+; MSSA-NEXT : entry:
+; MSSA-NEXT : br label %bb
+; MSSA-NEXT :
+; MSSA-NEXT : bb: ; preds = %bb, %entry
+; MSSA-NEXT : %mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb ]
+; MSSA-NEXT : %tmp5 = icmp eq i8 %mode.0, 1
+; MSSA-NEXT : %indvar.next = add i8 %mode.0, 1
+; MSSA-NEXT : br i1 %tmp5, label %bb5, label %bb
+; MSSA-NEXT :
+; MSSA-NEXT : bb5: ; preds = %bb
+; MSSA-NEXT : tail call void @raise_exception() #0
+; MSSA-NEXT : unreachable
+; MSSA-NEXT : }
+; MSSA-NEXT :
+; MSSA-NEXT : ; Function Attrs: noreturn
+; MSSA-NEXT : declare void @raise_exception() #0
+; MSSA-NEXT :
+; MSSA-NEXT : attributes #0 = { noreturn }
+
+define i8 @f() {
+entry:
+ br label %bb
+
+bb: ; preds = %bb4, %entry
+ %mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb4 ]
+ %tmp5 = icmp eq i8 %mode.0, 1
+ br i1 %tmp5, label %bb5, label %bb4
+
+bb4: ; preds = %bb2
+ %indvar.next = add i8 %mode.0, 1
+ br label %bb
+
+bb5: ; preds = %bb2
+ tail call void @raise_exception() #0
+ unreachable
+}
+
+; Function Attrs: noreturn
+declare void @raise_exception() #0
+
+attributes #0 = { noreturn }
diff --git a/llvm/test/Transforms/LoopRotate/pr37205.ll b/llvm/test/Transforms/LoopRotate/pr37205.ll
new file mode 100644
index 00000000000..20ad7568189
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/pr37205.ll
@@ -0,0 +1,117 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -indvars -verify -loop-rotate -loop-idiom < %s | FileCheck %s
+; RUN: opt -S -indvars -verify -loop-rotate -loop-idiom -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+
+; Verify that we invalidate SCEV properly.
+
+define void @test_01() {
+; CHECK-LABEL: @test_01(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[LBL1:%.*]]
+; CHECK: lbl1:
+; CHECK-NEXT: br label [[FOR_COND:%.*]]
+; CHECK: for.cond:
+; CHECK-NEXT: br i1 false, label [[FOR_BODY3_LR_PH:%.*]], label [[FOR_COND_FOR_END5_CRIT_EDGE:%.*]]
+; CHECK: for.body3.lr.ph:
+; CHECK-NEXT: br label [[FOR_BODY3:%.*]]
+; CHECK: for.cond1:
+; CHECK-NEXT: br i1 false, label [[FOR_BODY3]], label [[FOR_COND1_FOR_END5_CRIT_EDGE:%.*]]
+; CHECK: for.body3:
+; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[FOR_COND1:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: br label [[LBL1]]
+; CHECK: for.cond.for.end5_crit_edge:
+; CHECK-NEXT: br label [[FOR_END5:%.*]]
+; CHECK: for.cond1.for.end5_crit_edge:
+; CHECK-NEXT: br label [[FOR_END5]]
+; CHECK: for.end5:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %lbl1
+
+lbl1: ; preds = %if.then, %entry
+ br label %for.cond
+
+for.cond: ; preds = %lbl1
+ br label %for.cond1
+
+for.cond1: ; preds = %if.end, %for.cond
+ br i1 false, label %for.body3, label %for.end5
+
+for.body3: ; preds = %for.cond1
+ br i1 false, label %if.then, label %if.end
+
+if.then: ; preds = %for.body3
+ br label %lbl1
+
+if.end: ; preds = %for.body3
+ br label %for.cond1
+
+for.end5: ; preds = %for.cond1
+ ret void
+}
+
+define void @test_02() {
+; CHECK-LABEL: @test_02(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[LBL1:%.*]]
+; CHECK: lbl1:
+; CHECK-NEXT: br label [[FOR_COND:%.*]]
+; CHECK: for.cond:
+; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END7:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: br i1 false, label [[FOR_BODY_LR_PH:%.*]], label [[IF_THEN_FOR_END6_CRIT_EDGE:%.*]]
+; CHECK: for.body.lr.ph:
+; CHECK-NEXT: br label [[FOR_BODY:%.*]]
+; CHECK: for.body:
+; CHECK-NEXT: br i1 false, label [[IF_THEN3:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then3:
+; CHECK-NEXT: br label [[LBL1]]
+; CHECK: if.end:
+; CHECK-NEXT: br label [[FOR_COND4:%.*]]
+; CHECK: for.cond4:
+; CHECK-NEXT: br i1 false, label [[FOR_BODY]], label [[FOR_COND1_FOR_END6_CRIT_EDGE:%.*]]
+; CHECK: if.then.for.end6_crit_edge:
+; CHECK-NEXT: br label [[FOR_END6:%.*]]
+; CHECK: for.cond1.for.end6_crit_edge:
+; CHECK-NEXT: br label [[FOR_END6]]
+; CHECK: for.end6:
+; CHECK-NEXT: ret void
+; CHECK: if.end7:
+; CHECK-NEXT: unreachable
+;
+entry:
+ br label %lbl1
+
+lbl1: ; preds = %if.then3, %entry
+ br label %for.cond
+
+for.cond: ; preds = %lbl1
+ br i1 false, label %if.then, label %if.end7
+
+if.then: ; preds = %for.cond
+ br label %for.cond1
+
+for.cond1: ; preds = %for.cond4, %if.then
+ br i1 undef, label %for.body, label %for.end6
+
+for.body: ; preds = %for.cond1
+ br i1 false, label %if.then3, label %if.end
+
+if.then3: ; preds = %for.body
+ br label %lbl1
+
+if.end: ; preds = %for.body
+ br label %for.cond4
+
+for.cond4: ; preds = %if.end
+ br label %for.cond1
+
+for.end6: ; preds = %for.cond1
+ ret void
+
+if.end7: ; preds = %for.cond
+ unreachable
+}
diff --git a/llvm/test/Transforms/LoopRotate/preserve-loop-simplify.ll b/llvm/test/Transforms/LoopRotate/preserve-loop-simplify.ll
new file mode 100644
index 00000000000..53fa02a42a8
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/preserve-loop-simplify.ll
@@ -0,0 +1,65 @@
+; RUN: opt -S -loop-rotate < %s -verify-loop-info | FileCheck %s
+;
+; Verify that LoopRotate preserves LoopSimplify form even in very peculiar loop
+; structures. We manually validate the CFG with FileCheck because currently we
+; can't cause a failure when LoopSimplify fails to be preserved.
+
+define void @PR18643() {
+; CHECK-LABEL: @PR18643(
+entry:
+ br label %outer.header
+; CHECK: br label %outer.header
+
+outer.header:
+; CHECK: outer.header:
+ br i1 undef, label %inner.header, label %outer.body
+; CHECK-NEXT: br i1 {{[^,]*}}, label %[[INNER_PREROTATE_PREHEADER:[^,]*]], label %outer.body
+
+; CHECK: [[INNER_PREROTATE_PREHEADER]]:
+; CHECK-NEXT: br i1 {{[^,]*}}, label %[[INNER_PREROTATE_PREHEADER_SPLIT_RETURN:[^,]*]], label %[[INNER_ROTATED_PREHEADER:[^,]*]]
+
+; CHECK: [[INNER_ROTATED_PREHEADER]]:
+; CHECK-NEXT: br label %inner.body
+
+inner.header:
+; Now the latch!
+; CHECK: inner.header:
+ br i1 undef, label %return, label %inner.body
+; CHECK-NEXT: br i1 {{[^,]*}}, label %[[INNER_SPLIT_RETURN:[^,]*]], label %inner.body
+
+inner.body:
+; Now the header!
+; CHECK: inner.body:
+ br i1 undef, label %outer.latch, label %inner.latch
+; CHECK-NEXT: br i1 {{[^,]*}}, label %[[INNER_SPLIT_OUTER_LATCH:[^,]*]], label %inner.header
+
+inner.latch:
+; Dead!
+ br label %inner.header
+
+outer.body:
+; CHECK: outer.body:
+ br label %outer.latch
+; CHECK-NEXT: br label %outer.latch
+
+; L2 -> L1 exit edge needs a simplified exit block.
+; CHECK: [[INNER_SPLIT_OUTER_LATCH]]:
+; CHECK-NEXT: br label %outer.latch
+
+outer.latch:
+; CHECK: outer.latch:
+ br label %outer.header
+; CHECK-NEXT: br label %outer.header
+
+; L1 -> L0 exit edge need sa simplified exit block.
+; CHECK: [[INNER_PREROTATE_PREHEADER_SPLIT_RETURN]]:
+; CHECK-NEXT: br label %return
+
+; L2 -> L0 exit edge needs a simplified exit block.
+; CHECK: [[INNER_SPLIT_RETURN]]:
+; CHECK-NEXT: br label %return
+
+return:
+; CHECK: return:
+ unreachable
+}
diff --git a/llvm/test/Transforms/LoopRotate/preserve-mssa.ll b/llvm/test/Transforms/LoopRotate/preserve-mssa.ll
new file mode 100644
index 00000000000..d975f80cd9e
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/preserve-mssa.ll
@@ -0,0 +1,109 @@
+; RUN: opt -S -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa < %s | FileCheck %s
+
+; CHECK-LABEL: @multiedge(
+define void @multiedge() {
+entry:
+ br label %retry
+
+retry: ; preds = %sw.epilog, %entry
+ br i1 undef, label %cleanup, label %if.end
+
+if.end: ; preds = %retry
+ switch i32 undef, label %sw.epilog [
+ i32 -3, label %cleanup
+ i32 -5, label %cleanup
+ i32 -16, label %cleanup
+ i32 -25, label %cleanup
+ ]
+
+sw.epilog: ; preds = %if.end
+ br label %retry
+
+cleanup: ; preds = %if.end, %if.end, %if.end, %if.end, %retry
+ ret void
+}
+
+; CHECK-LABEL: @read_line(
+define internal fastcc i32 @read_line(i8* nocapture %f) unnamed_addr {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %if.end, %entry
+ %call = call i8* @prepbuffer(i8* nonnull undef)
+ %call1 = call i8* @fgets(i8* %call, i32 8192, i8* %f)
+ br i1 undef, label %if.then, label %if.end
+
+if.then: ; preds = %for.cond
+ ret i32 undef
+
+if.end: ; preds = %for.cond
+ %call4 = call i64 @strlen(i8* %call)
+ br label %for.cond
+}
+
+declare dso_local i8* @prepbuffer(i8*) local_unnamed_addr
+declare dso_local i8* @fgets(i8*, i32, i8* nocapture) local_unnamed_addr
+declare dso_local i64 @strlen(i8* nocapture) local_unnamed_addr
+
+
+; CHECK-LABEL: @loop3
+define dso_local fastcc void @loop3() unnamed_addr {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.body, %entry
+ br i1 undef, label %for.body, label %for.end81
+
+for.body: ; preds = %for.cond
+ %.idx122.val = load i32, i32* undef, align 8
+ call fastcc void @cont()
+ br label %for.cond
+
+for.end81: ; preds = %for.cond
+ ret void
+}
+
+; CHECK-LABEL: @loop4
+define dso_local fastcc void @loop4() unnamed_addr {
+entry:
+ br label %while.cond
+
+while.cond: ; preds = %while.body, %entry
+ br i1 undef, label %while.end, label %while.body
+
+while.body: ; preds = %while.cond
+ call fastcc void @cont()
+ br label %while.cond
+
+while.end: ; preds = %while.cond
+ call fastcc void @cont()
+ call fastcc void @cont()
+ ret void
+}
+
+; Function Attrs: inlinehint nounwind uwtable
+declare dso_local fastcc void @cont() unnamed_addr
+
+@glob_array = internal unnamed_addr constant [3 x i32] [i32 1, i32 0, i32 2], align 4
+; Test against failure in MemorySSAUpdater, when rotate clones instructions as Value.
+; CHECK-LABEL: @loop5
+define dso_local fastcc void @loop5() unnamed_addr {
+entry:
+ br label %for.body
+
+do.cond: ; preds = %for.body
+ unreachable
+
+for.body: ; preds = %if.end, %entry
+ %indvar = phi i64 [ %indvar.next, %if.end ], [ 0, %entry ]
+ %array = getelementptr inbounds [3 x i32], [3 x i32]* @glob_array, i64 0, i64 %indvar
+ %0 = load i32, i32* %array, align 4
+ br i1 undef, label %do.cond, label %if.end
+
+if.end: ; preds = %for.body
+ store i32 undef, i32* undef, align 4
+ %indvar.next = add nuw nsw i64 %indvar, 1
+ br label %for.body
+}
+
+
diff --git a/llvm/test/Transforms/LoopRotate/preserve-scev.ll b/llvm/test/Transforms/LoopRotate/preserve-scev.ll
new file mode 100644
index 00000000000..2faf8ec487a
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/preserve-scev.ll
@@ -0,0 +1,80 @@
+; RUN: opt < %s -loop-rotate -loop-reduce -verify-dom-info -verify-loop-info -disable-output
+; RUN: opt < %s -loop-rotate -loop-reduce -enable-mssa-loop-dependency=true -verify-memoryssa -verify-dom-info -verify-loop-info -disable-output
+
+define fastcc void @foo(i32* %A, i64 %i) nounwind {
+BB:
+ br label %BB1
+
+BB1: ; preds = %BB19, %BB
+ %tttmp1 = getelementptr i32, i32* %A, i64 %i
+ %tttmp2 = load i32, i32* %tttmp1
+ %tttmp3 = add i32 %tttmp2, 1
+ store i32 %tttmp3, i32* %tttmp1
+ br label %BB4
+
+BB2: ; preds = %BB4
+ %tmp = bitcast i32 undef to i32 ; <i32> [#uses=1]
+ %tttmp7 = getelementptr i32, i32* %A, i64 %i
+ %tttmp8 = load i32, i32* %tttmp7
+ %tttmp9 = add i32 %tttmp8, 3
+ store i32 %tttmp9, i32* %tttmp7
+ br label %BB4
+
+BB4: ; preds = %BB2, %BB1
+ %tmp5 = phi i32 [ undef, %BB1 ], [ %tmp, %BB2 ] ; <i32> [#uses=1]
+ %tttmp4 = getelementptr i32, i32* %A, i64 %i
+ %tttmp5 = load i32, i32* %tttmp4
+ %tttmp6 = add i32 %tttmp5, 3
+ store i32 %tttmp6, i32* %tttmp4
+ br i1 false, label %BB8, label %BB2
+
+BB8: ; preds = %BB6
+ %tmp7 = bitcast i32 %tmp5 to i32 ; <i32> [#uses=2]
+ %tttmp10 = getelementptr i32, i32* %A, i64 %i
+ %tttmp11 = load i32, i32* %tttmp10
+ %tttmp12 = add i32 %tttmp11, 3
+ store i32 %tttmp12, i32* %tttmp10
+ br i1 false, label %BB9, label %BB13
+
+BB9: ; preds = %BB12, %BB8
+ %tmp10 = phi i32 [ %tmp11, %BB12 ], [ %tmp7, %BB8 ] ; <i32> [#uses=2]
+ %tmp11 = add i32 %tmp10, 1 ; <i32> [#uses=1]
+ %tttmp13 = getelementptr i32, i32* %A, i64 %i
+ %tttmp14 = load i32, i32* %tttmp13
+ %tttmp15 = add i32 %tttmp14, 3
+ store i32 %tttmp15, i32* %tttmp13
+ br label %BB12
+
+BB12: ; preds = %BB9
+ br i1 false, label %BB9, label %BB17
+
+BB13: ; preds = %BB15, %BB8
+ %tmp14 = phi i32 [ %tmp16, %BB15 ], [ %tmp7, %BB8 ] ; <i32> [#uses=1]
+ %tttmp16 = getelementptr i32, i32* %A, i64 %i
+ %tttmp17 = load i32, i32* %tttmp16
+ %tttmp18 = add i32 %tttmp17, 3
+ store i32 %tttmp18, i32* %tttmp16
+ br label %BB15
+
+BB15: ; preds = %BB13
+ %tmp16 = add i32 %tmp14, -1 ; <i32> [#uses=1]
+ %tttmp19 = getelementptr i32, i32* %A, i64 %i
+ %tttmp20 = load i32, i32* %tttmp19
+ %tttmp21 = add i32 %tttmp20, 3
+ store i32 %tttmp21, i32* %tttmp19
+ br i1 false, label %BB13, label %BB18
+
+BB17: ; preds = %BB12
+ br label %BB19
+
+BB18: ; preds = %BB15
+ %tttmp22 = getelementptr i32, i32* %A, i64 %i
+ %tttmp23 = load i32, i32* %tttmp22
+ %tttmp24 = add i32 %tttmp23, 3
+ store i32 %tttmp24, i32* %tttmp22
+ br label %BB19
+
+BB19: ; preds = %BB18, %BB17
+ %tmp20 = phi i32 [ %tmp10, %BB17 ], [ undef, %BB18 ] ; <i32> [#uses=0]
+ br label %BB1
+}
diff --git a/llvm/test/Transforms/LoopRotate/simplifylatch.ll b/llvm/test/Transforms/LoopRotate/simplifylatch.ll
new file mode 100644
index 00000000000..215622fe302
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/simplifylatch.ll
@@ -0,0 +1,76 @@
+; RUN: opt -S < %s -loop-rotate -licm -verify-dom-info -verify-loop-info | FileCheck %s
+; PR2624 unroll multiple exits
+
+@mode_table = global [4 x i32] zeroinitializer ; <[4 x i32]*> [#uses=1]
+
+; CHECK-LABEL: @f(
+; CHECK-NOT: bb:
+define i8 @f() {
+entry:
+ tail call i32 @fegetround( ) ; <i32>:0 [#uses=1]
+ br label %bb
+
+bb: ; preds = %bb4, %entry
+ %mode.0 = phi i8 [ 0, %entry ], [ %indvar.next, %bb4 ] ; <i8> [#uses=4]
+ zext i8 %mode.0 to i32 ; <i32>:1 [#uses=1]
+ getelementptr [4 x i32], [4 x i32]* @mode_table, i32 0, i32 %1 ; <i32*>:2 [#uses=1]
+ load i32, i32* %2, align 4 ; <i32>:3 [#uses=1]
+ icmp eq i32 %3, %0 ; <i1>:4 [#uses=1]
+ br i1 %4, label %bb1, label %bb2
+
+bb1: ; preds = %bb
+ ret i8 %mode.0
+
+bb2: ; preds = %bb
+ icmp eq i8 %mode.0, 1 ; <i1>:5 [#uses=1]
+ br i1 %5, label %bb5, label %bb4
+
+bb4: ; preds = %bb2
+ %indvar.next = add i8 %mode.0, 1 ; <i8> [#uses=1]
+ br label %bb
+
+bb5: ; preds = %bb2
+ tail call void @raise_exception( ) noreturn
+ unreachable
+}
+
+declare i32 @fegetround()
+
+declare void @raise_exception() noreturn
+
+;CHECK: for.body.lr.ph:
+;CHECK-NEXT: %arrayidx1 = getelementptr inbounds i8, i8* %CurPtr, i64 0
+;CHECK-NEXT: %0 = load i8, i8* %arrayidx1, align 1
+;CHECK-NEXT: %conv2 = sext i8 %0 to i32
+;CHECK-NEXT: br label %for.body
+
+define i32 @foo(i8* %CurPtr, i32 %a) #0 {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %i.0 = phi i32 [ 1, %entry ], [ %inc, %for.inc ]
+ %cmp = icmp ne i32 %i.0, %a
+ br i1 %cmp, label %for.body, label %return
+
+for.body: ; preds = %for.cond
+ %idxprom = zext i32 %i.0 to i64
+ %arrayidx = getelementptr inbounds i8, i8* %CurPtr, i64 %idxprom
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = sext i8 %0 to i32
+ %arrayidx1 = getelementptr inbounds i8, i8* %CurPtr, i64 0
+ %1 = load i8, i8* %arrayidx1, align 1
+ %conv2 = sext i8 %1 to i32
+ %cmp3 = icmp ne i32 %conv, %conv2
+ br i1 %cmp3, label %return, label %for.inc
+
+for.inc: ; preds = %for.body
+ %inc = add i32 %i.0, 1
+ br label %for.cond
+
+return: ; preds = %for.cond, %for.body
+ %retval.0 = phi i32 [ 0, %for.body ], [ 1, %for.cond ]
+ ret i32 %retval.0
+}
+
+attributes #0 = { nounwind uwtable }
diff --git a/llvm/test/Transforms/LoopRotate/vect.omp.persistence.ll b/llvm/test/Transforms/LoopRotate/vect.omp.persistence.ll
new file mode 100644
index 00000000000..c4c987e7b2b
--- /dev/null
+++ b/llvm/test/Transforms/LoopRotate/vect.omp.persistence.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -loop-rotate -S | FileCheck %s
+; RUN: opt < %s -loop-rotate -enable-mssa-loop-dependency=true -verify-memoryssa -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; Ensure that "llvm.loop.vectorize.enable" metadata was not lost after loop-rotate.
+; In past LoopRotate was clearing that metadata.
+;
+; See http://reviews.llvm.org/D3348 for details.
+
+; CHECK-LABEL: @foo
+; CHECK: loop_cond:
+; CHECK-NOT: loop-inc
+; CHECK: br i1 %cmp, label %return, label %loop_cond, !llvm.loop !0
+; CHECK: !0 = distinct !{!0, !1}
+; CHECK: !1 = !{!"llvm.loop.vectorize.enable", i1 true}
+define i32 @foo(i32 %a) {
+entry:
+ br label %loop_cond
+
+loop_cond:
+ %indx = phi i32 [ 1, %entry ], [ %inc, %loop_inc ]
+ %cmp = icmp ne i32 %indx, %a
+ br i1 %cmp, label %return, label %loop_inc
+
+loop_inc:
+ %inc = add i32 %indx, 1
+ br label %loop_cond, !llvm.loop !0
+
+return:
+ ret i32 0
+}
+
+!0 = !{!0, !1}
+!1 = !{!"llvm.loop.vectorize.enable", i1 true}
OpenPOWER on IntegriCloud