diff options
Diffstat (limited to 'llvm/test/Transforms/LoopRotate')
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} |