diff options
Diffstat (limited to 'test/Transforms/LICM')
27 files changed, 408 insertions, 30 deletions
diff --git a/test/Transforms/LICM/2003-02-26-LoopExitNotDominated.ll b/test/Transforms/LICM/2003-02-26-LoopExitNotDominated.ll index cf05206179386..ff20312ec372b 100644 --- a/test/Transforms/LICM/2003-02-26-LoopExitNotDominated.ll +++ b/test/Transforms/LICM/2003-02-26-LoopExitNotDominated.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -basicaa -licm -disable-output +; RUN: opt < %s -basicaa -licm -disable-output ;%MoveArray = external global [64 x ulong] diff --git a/test/Transforms/LICM/2003-02-27-NestedLoopExitBlocks.ll b/test/Transforms/LICM/2003-02-27-NestedLoopExitBlocks.ll index bf209eaa479f0..4782bd17f8933 100644 --- a/test/Transforms/LICM/2003-02-27-NestedLoopExitBlocks.ll +++ b/test/Transforms/LICM/2003-02-27-NestedLoopExitBlocks.ll @@ -1,6 +1,6 @@ ; Exit blocks need to be updated for all nested loops... -; RUN: llvm-as < %s | opt -loopsimplify +; RUN: opt < %s -loopsimplify define i32 @yyparse() { bb0: diff --git a/test/Transforms/LICM/2003-02-27-PreheaderExitNodeUpdate.ll b/test/Transforms/LICM/2003-02-27-PreheaderExitNodeUpdate.ll index 4b51a3be4b065..2718cb1053773 100644 --- a/test/Transforms/LICM/2003-02-27-PreheaderExitNodeUpdate.ll +++ b/test/Transforms/LICM/2003-02-27-PreheaderExitNodeUpdate.ll @@ -1,7 +1,7 @@ ; This testcase fails because preheader insertion is not updating exit node ; information for loops. -; RUN: llvm-as < %s | opt -licm +; RUN: opt < %s -licm define i32 @main(i32 %argc, i8** %argv) { bb0: diff --git a/test/Transforms/LICM/2003-02-27-PreheaderProblem.ll b/test/Transforms/LICM/2003-02-27-PreheaderProblem.ll index 18b86064ed04a..70a04c73b1d3e 100644 --- a/test/Transforms/LICM/2003-02-27-PreheaderProblem.ll +++ b/test/Transforms/LICM/2003-02-27-PreheaderProblem.ll @@ -3,7 +3,7 @@ ; happens because preheader insertion doesn't insert a preheader for this ; case... bad. -; RUN: llvm-as < %s | opt -licm -loop-deletion -simplifycfg | llvm-dis | \ +; RUN: opt < %s -licm -loop-deletion -simplifycfg -S | \ ; RUN: not grep {br } define i32 @main(i32 %argc) { diff --git a/test/Transforms/LICM/2003-02-27-StoreSinkPHIs.ll b/test/Transforms/LICM/2003-02-27-StoreSinkPHIs.ll index 7ce164ec237f7..a9c6b856f8ea5 100644 --- a/test/Transforms/LICM/2003-02-27-StoreSinkPHIs.ll +++ b/test/Transforms/LICM/2003-02-27-StoreSinkPHIs.ll @@ -1,6 +1,6 @@ ; LICM is adding stores before phi nodes. bad. -; RUN: llvm-as < %s | opt -licm +; RUN: opt < %s -licm define i1 @test(i1 %c) { ; <label>:0 diff --git a/test/Transforms/LICM/2003-02-28-PromoteDifferentType.ll b/test/Transforms/LICM/2003-02-28-PromoteDifferentType.ll index 849ecd7cb1bbd..c759e6eff8e7e 100644 --- a/test/Transforms/LICM/2003-02-28-PromoteDifferentType.ll +++ b/test/Transforms/LICM/2003-02-28-PromoteDifferentType.ll @@ -1,6 +1,6 @@ ; Test that hoisting is disabled for pointers of different types... ; -; RUN: llvm-as < %s | opt -licm +; RUN: opt < %s -licm define void @test(i32* %P) { br label %Loop diff --git a/test/Transforms/LICM/2003-05-02-LoadHoist.ll b/test/Transforms/LICM/2003-05-02-LoadHoist.ll index 7b58535972e50..71d3e789aa083 100644 --- a/test/Transforms/LICM/2003-05-02-LoadHoist.ll +++ b/test/Transforms/LICM/2003-05-02-LoadHoist.ll @@ -3,7 +3,7 @@ ; loaded from. Basically if the load gets hoisted, the subtract gets turned ; into a constant zero. ; -; RUN: llvm-as < %s | opt -licm -gvn -instcombine | llvm-dis | grep load +; RUN: opt < %s -licm -gvn -instcombine -S | grep load @X = global i32 7 ; <i32*> [#uses=2] diff --git a/test/Transforms/LICM/2003-12-11-SinkingToPHI.ll b/test/Transforms/LICM/2003-12-11-SinkingToPHI.ll index e491c9aee479a..67c3951d74e4a 100644 --- a/test/Transforms/LICM/2003-12-11-SinkingToPHI.ll +++ b/test/Transforms/LICM/2003-12-11-SinkingToPHI.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm | lli +; RUN: opt < %s -licm | lli define i32 @main() { entry: diff --git a/test/Transforms/LICM/2004-09-14-AliasAnalysisInvalidate.ll b/test/Transforms/LICM/2004-09-14-AliasAnalysisInvalidate.ll index b9c9eb3739999..16f4fed34ec37 100644 --- a/test/Transforms/LICM/2004-09-14-AliasAnalysisInvalidate.ll +++ b/test/Transforms/LICM/2004-09-14-AliasAnalysisInvalidate.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -globalsmodref-aa -licm -disable-output +; RUN: opt < %s -globalsmodref-aa -licm -disable-output @PL_regcomp_parse = internal global i8* null ; <i8**> [#uses=2] diff --git a/test/Transforms/LICM/2004-11-17-UndefIndexCrash.ll b/test/Transforms/LICM/2004-11-17-UndefIndexCrash.ll index 9a53d95996a77..a119865f05199 100644 --- a/test/Transforms/LICM/2004-11-17-UndefIndexCrash.ll +++ b/test/Transforms/LICM/2004-11-17-UndefIndexCrash.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -disable-output +; RUN: opt < %s -licm -disable-output %struct.roadlet = type { i8*, %struct.vehicle*, [8 x %struct.roadlet*], [8 x %struct.roadlet* (%struct.roadlet*, %struct.vehicle*, i32)*] } %struct.vehicle = type { %struct.roadlet*, i8*, i32, i32, %union.._631., i32 } %union.._631. = type { i32 } diff --git a/test/Transforms/LICM/2005-03-24-LICM-Aggregate-Crash.ll b/test/Transforms/LICM/2005-03-24-LICM-Aggregate-Crash.ll index b001cd0d5cd2d..91740cf0eb717 100644 --- a/test/Transforms/LICM/2005-03-24-LICM-Aggregate-Crash.ll +++ b/test/Transforms/LICM/2005-03-24-LICM-Aggregate-Crash.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -disable-output +; RUN: opt < %s -licm -disable-output define void @test({ i32 }* %P) { br label %Loop diff --git a/test/Transforms/LICM/2006-09-12-DeadUserOfSunkInstr.ll b/test/Transforms/LICM/2006-09-12-DeadUserOfSunkInstr.ll index c2c4bcb4ab0be..9763660ffb0be 100644 --- a/test/Transforms/LICM/2006-09-12-DeadUserOfSunkInstr.ll +++ b/test/Transforms/LICM/2006-09-12-DeadUserOfSunkInstr.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -disable-output +; RUN: opt < %s -licm -disable-output ; PR908 ; END. diff --git a/test/Transforms/LICM/2007-05-22-VolatileSink.ll b/test/Transforms/LICM/2007-05-22-VolatileSink.ll index bf5d7bc092977..c12e13beccf59 100644 --- a/test/Transforms/LICM/2007-05-22-VolatileSink.ll +++ b/test/Transforms/LICM/2007-05-22-VolatileSink.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm | llvm-dis | grep {volatile store} +; RUN: opt < %s -licm -S | grep {volatile store} ; PR1435 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64" target triple = "i686-apple-darwin8" diff --git a/test/Transforms/LICM/2007-07-30-AliasSet.ll b/test/Transforms/LICM/2007-07-30-AliasSet.ll index 110d884494645..8ecd1bcee4866 100644 --- a/test/Transforms/LICM/2007-07-30-AliasSet.ll +++ b/test/Transforms/LICM/2007-07-30-AliasSet.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -loop-unswitch -disable-output +; RUN: opt < %s -licm -loop-unswitch -disable-output %struct.III_scalefac_t = type { [22 x i32], [13 x [3 x i32]] } %struct.gr_info = type { i32, i32, i32, i32, i32, i32, i32, i32, [3 x i32], [3 x i32], i32, i32, i32, i32, i32, i32, i32, i32, i32, i32*, [4 x i32] } diff --git a/test/Transforms/LICM/2007-09-17-PromoteValue.ll b/test/Transforms/LICM/2007-09-17-PromoteValue.ll index e9ba9e16318fe..31abd8c180a50 100644 --- a/test/Transforms/LICM/2007-09-17-PromoteValue.ll +++ b/test/Transforms/LICM/2007-09-17-PromoteValue.ll @@ -2,7 +2,7 @@ ; Do not promote getelementptr because it may exposes load from a null pointer ; and store from a null pointer which are covered by ; icmp eq %struct.decision* null, null condition. -; RUN: llvm-as < %s | opt -licm | llvm-dis | not grep promoted +; RUN: opt < %s -licm -S | not grep promoted %struct.decision = type { i8, %struct.decision* } define i32 @main() { diff --git a/test/Transforms/LICM/2007-09-24-PromoteNullValue.ll b/test/Transforms/LICM/2007-09-24-PromoteNullValue.ll index f9f45f389b8a8..916f479cba149 100644 --- a/test/Transforms/LICM/2007-09-24-PromoteNullValue.ll +++ b/test/Transforms/LICM/2007-09-24-PromoteNullValue.ll @@ -1,5 +1,5 @@ ; Do not promote null value because it may be unsafe to do so. -; RUN: llvm-as < %s | opt -licm | llvm-dis | not grep promoted +; RUN: opt < %s -licm -S | not grep promoted define i32 @f(i32 %foo, i32 %bar, i32 %com) { entry: diff --git a/test/Transforms/LICM/2007-10-01-PromoteSafeValue.ll b/test/Transforms/LICM/2007-10-01-PromoteSafeValue.ll index 7359cc0695ad2..59f1dcbe2d7b1 100644 --- a/test/Transforms/LICM/2007-10-01-PromoteSafeValue.ll +++ b/test/Transforms/LICM/2007-10-01-PromoteSafeValue.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm | llvm-dis | grep promoted +; RUN: opt < %s -licm -S | grep promoted ; Promote value if at least one use is safe diff --git a/test/Transforms/LICM/2008-05-20-AliasSetVAArg.ll b/test/Transforms/LICM/2008-05-20-AliasSetVAArg.ll index dcb20e7bbd0c0..a5a7bf85f10d4 100644 --- a/test/Transforms/LICM/2008-05-20-AliasSetVAArg.ll +++ b/test/Transforms/LICM/2008-05-20-AliasSetVAArg.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -disable-output +; RUN: opt < %s -licm -disable-output ; PR2346 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-f80:128:128" target triple = "i686-pc-linux-gnu" diff --git a/test/Transforms/LICM/2008-07-22-LoadGlobalConstant.ll b/test/Transforms/LICM/2008-07-22-LoadGlobalConstant.ll index 3824d53597723..7810309384386 100644 --- a/test/Transforms/LICM/2008-07-22-LoadGlobalConstant.ll +++ b/test/Transforms/LICM/2008-07-22-LoadGlobalConstant.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm -enable-licm-constant-variables | llvm-dis | grep -A 1 entry | grep load.*@a +; RUN: opt < %s -licm -enable-licm-constant-variables -S | grep -A 1 entry | grep load.*@a @a = external constant float* define void @test(i32 %count) { diff --git a/test/Transforms/LICM/2009-03-25-AliasSetTracker.ll b/test/Transforms/LICM/2009-03-25-AliasSetTracker.ll index c3c9a810c52c5..d1fe48c2357ae 100644 --- a/test/Transforms/LICM/2009-03-25-AliasSetTracker.ll +++ b/test/Transforms/LICM/2009-03-25-AliasSetTracker.ll @@ -1,5 +1,5 @@ -; RUN: llvm-as < %s | opt -licm -loop-index-split -instcombine -disable-output +; RUN: opt < %s -licm -loop-index-split -instcombine -disable-output %struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] } %struct._IO_marker = type { %struct._IO_marker*, %struct.FILE*, i32 } diff --git a/test/Transforms/LICM/Preserve-LCSSA.ll b/test/Transforms/LICM/Preserve-LCSSA.ll index 850d071810ef0..24c4ad1da42de 100644 --- a/test/Transforms/LICM/Preserve-LCSSA.ll +++ b/test/Transforms/LICM/Preserve-LCSSA.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -loop-rotate -licm -loop-unswitch -disable-output +; RUN: opt < %s -loop-rotate -licm -loop-unswitch -disable-output define i32 @stringSearch_Clib(i32 %count) { entry: diff --git a/test/Transforms/LICM/basictest.ll b/test/Transforms/LICM/basictest.ll index 0a57ce4539fed..1dbb4dc6b4993 100644 --- a/test/Transforms/LICM/basictest.ll +++ b/test/Transforms/LICM/basictest.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | opt -licm | llvm-dis +; RUN: opt < %s -licm | llvm-dis define void @testfunc(i32 %i) { ; <label>:0 diff --git a/test/Transforms/LICM/hoisting.ll b/test/Transforms/LICM/hoisting.ll new file mode 100644 index 0000000000000..e7d36afb91b15 --- /dev/null +++ b/test/Transforms/LICM/hoisting.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -licm -S | FileCheck %s + +@X = global i32 0 ; <i32*> [#uses=1] + +declare void @foo() + +; This testcase tests for a problem where LICM hoists +; potentially trapping instructions when they are not guaranteed to execute. +define i32 @test1(i1 %c) { +; CHECK: @test1 + %A = load i32* @X ; <i32> [#uses=2] + br label %Loop +Loop: ; preds = %LoopTail, %0 + call void @foo( ) + br i1 %c, label %LoopTail, label %IfUnEqual + +IfUnEqual: ; preds = %Loop +; CHECK: IfUnEqual: +; CHECK-NEXT: sdiv i32 4, %A + %B1 = sdiv i32 4, %A ; <i32> [#uses=1] + br label %LoopTail + +LoopTail: ; preds = %IfUnEqual, %Loop + %B = phi i32 [ 0, %Loop ], [ %B1, %IfUnEqual ] ; <i32> [#uses=1] + br i1 %c, label %Loop, label %Out +Out: ; preds = %LoopTail + %C = sub i32 %A, %B ; <i32> [#uses=1] + ret i32 %C +} + + +declare void @foo2(i32) + + +;; It is ok and desirable to hoist this potentially trapping instruction. +define i32 @test2(i1 %c) { +; CHECK: @test2 +; CHECK-NEXT: load i32* @X +; CHECK-NEXT: %B = sdiv i32 4, %A + %A = load i32* @X ; <i32> [#uses=2] + br label %Loop +Loop: + ;; Should have hoisted this div! + %B = sdiv i32 4, %A ; <i32> [#uses=2] + call void @foo2( i32 %B ) + br i1 %c, label %Loop, label %Out +Out: ; preds = %Loop + %C = sub i32 %A, %B ; <i32> [#uses=1] + ret i32 %C +} diff --git a/test/Transforms/LICM/licm_preserve_dbginfo.ll b/test/Transforms/LICM/licm_preserve_dbginfo.ll new file mode 100644 index 0000000000000..e013c27354490 --- /dev/null +++ b/test/Transforms/LICM/licm_preserve_dbginfo.ll @@ -0,0 +1,55 @@ +; RUN: opt -licm -S <%s | FileCheck %s +; Test that licm doesn't sink/delete debug info. +define i32 @foo(i32 %a, i32 %j) nounwind { +entry: +;CHECK: entry: + call void @llvm.dbg.func.start(metadata !0) + call void @llvm.dbg.stoppoint(i32 3, i32 5, metadata !1) +;CHECK: %mul = mul i32 %j, %j + br label %for.cond + +for.cond: +;CHECK: for.cond: + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %s.0 = phi i32 [ 0, %entry ], [ %add, %for.inc ] + call void @llvm.dbg.stoppoint(i32 4, i32 5, metadata !1) +; CHECK: call void @llvm.dbg.stoppoint(i32 4, i32 5, metadata !1) + %cmp = icmp slt i32 %i.0, %a + br i1 %cmp, label %for.body, label %for.end + +for.body: +;CHECK: for.body: + call void @llvm.dbg.stoppoint(i32 5, i32 2, metadata !1) +;CHECK: call void @llvm.dbg.stoppoint(i32 5, i32 2, metadata !1) + %mul = mul i32 %j, %j + %add = add nsw i32 %s.0, %mul + br label %for.inc + +for.inc: +;CHECK: for.inc: + call void @llvm.dbg.stoppoint(i32 4, i32 18, metadata !1) +;CHECK: call void @llvm.dbg.stoppoint(i32 4, i32 18, metadata !1) + %inc = add nsw i32 %i.0, 1 + br label %for.cond + +for.end: + call void @llvm.dbg.stoppoint(i32 7, i32 5, metadata !1) + br label %0 + +; <label>:0 ; preds = %for.end + call void @llvm.dbg.stoppoint(i32 8, i32 1, metadata !1) + call void @llvm.dbg.region.end(metadata !0) + ret i32 %s.0 +} + +declare void @llvm.dbg.func.start(metadata) nounwind readnone + +declare void @llvm.dbg.declare({ }*, metadata) nounwind readnone + +declare void @llvm.dbg.stoppoint(i32, i32, metadata) nounwind readnone + +declare void @llvm.dbg.region.end(metadata) nounwind readnone + +!0 = metadata !{i32 458798, i32 0, metadata !1, metadata !"foo", metadata !"foo", metadata !"foo", metadata !1, i32 2, metadata !2, i1 false, i1 true}; [DW_TAG_subprogram ] +!1 = metadata !{i32 458769, i32 0, i32 12, metadata !"licm.c", metadata !"/home/edwin", metadata !"clang 1.1", i1 true, i1 false, metadata !"", i32 0}; [DW_TAG_compile_unit ] +!2 = metadata !{i32 458788, metadata !1, metadata !"int", metadata !1, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5}; [DW_TAG_base_type ] diff --git a/test/Transforms/LICM/no-preheader-test.ll b/test/Transforms/LICM/no-preheader-test.ll index 6ea08612ea869..bd3eea38ef3eb 100644 --- a/test/Transforms/LICM/no-preheader-test.ll +++ b/test/Transforms/LICM/no-preheader-test.ll @@ -1,5 +1,5 @@ ; Test that LICM works when there is not a loop-preheader -; RUN: llvm-as < %s | opt -licm | llvm-dis +; RUN: opt < %s -licm | llvm-dis define void @testfunc(i32 %i.s, i1 %ifcond) { br i1 %ifcond, label %Then, label %Else diff --git a/test/Transforms/LICM/scalar_promote.ll b/test/Transforms/LICM/scalar_promote.ll index f6c0f0821a30b..ef28c38ca6071 100644 --- a/test/Transforms/LICM/scalar_promote.ll +++ b/test/Transforms/LICM/scalar_promote.ll @@ -1,13 +1,17 @@ -; RUN: llvm-as < %s | opt -licm -disable-output -stats |& \ -; RUN: grep {memory locations promoted to register} +; RUN: opt < %s -licm -S | FileCheck %s @X = global i32 7 ; <i32*> [#uses=4] -define void @testfunc(i32 %i) { -; <label>:0 +define void @test1(i32 %i) { +Entry: br label %Loop +; CHECK: @test1 +; CHECK: Entry: +; CHECK-NEXT: load i32* @X +; CHECK-NEXT: br label %Loop + Loop: ; preds = %Loop, %0 - %j = phi i32 [ 0, %0 ], [ %Next, %Loop ] ; <i32> [#uses=1] + %j = phi i32 [ 0, %Entry ], [ %Next, %Loop ] ; <i32> [#uses=1] %x = load i32* @X ; <i32> [#uses=1] %x2 = add i32 %x, 1 ; <i32> [#uses=1] store i32 %x2, i32* @X @@ -15,12 +19,23 @@ Loop: ; preds = %Loop, %0 %cond = icmp eq i32 %Next, 0 ; <i1> [#uses=1] br i1 %cond, label %Out, label %Loop -Out: ; preds = %Loop +Out: ret void +; CHECK: Out: +; CHECK-NEXT: store i32 %x2, i32* @X +; CHECK-NEXT: ret void + } -define void @testhard(i32 %i) { +define void @test2(i32 %i) { +Entry: br label %Loop +; CHECK: @test2 +; CHECK: Entry: +; CHECK-NEXT: %X1 = getelementptr i32* @X, i64 0 +; CHECK-NEXT: %X2 = getelementptr i32* @X, i64 0 +; CHECK-NEXT: %X1.promoted = load i32* %X1 +; CHECK-NEXT: br label %Loop Loop: ; preds = %Loop, %0 %X1 = getelementptr i32* @X, i64 0 ; <i32*> [#uses=1] @@ -32,4 +47,27 @@ Loop: ; preds = %Loop, %0 Exit: ; preds = %Loop ret void +; CHECK: Exit: +; CHECK-NEXT: store i32 %V, i32* %X1 +; CHECK-NEXT: ret void } + + + +define void @test3(i32 %i) { +; CHECK: @test3 + br label %Loop +Loop: + ; Should not promote this to a register + %x = volatile load i32* @X + %x2 = add i32 %x, 1 + store i32 %x2, i32* @X + br i1 true, label %Out, label %Loop + +; CHECK: Loop: +; CHECK-NEXT: volatile load + +Out: ; preds = %Loop + ret void +} + diff --git a/test/Transforms/LICM/sinking.ll b/test/Transforms/LICM/sinking.ll new file mode 100644 index 0000000000000..11112eb74443f --- /dev/null +++ b/test/Transforms/LICM/sinking.ll @@ -0,0 +1,235 @@ +; RUN: opt < %s -basicaa -licm -S | FileCheck %s + +declare i32 @strlen(i8*) readonly + +declare void @foo() + +; Sink readonly function. +define i32 @test1(i8* %P) { + br label %Loop + +Loop: ; preds = %Loop, %0 + %A = call i32 @strlen( i8* %P ) readonly + br i1 false, label %Loop, label %Out + +Out: ; preds = %Loop + ret i32 %A +; CHECK: @test1 +; CHECK: Out: +; CHECK-NEXT: call i32 @strlen +; CHECK-NEXT: ret i32 %A +} + +declare double @sin(double) readnone + +; Sink readnone function out of loop with unknown memory behavior. +define double @test2(double %X) { + br label %Loop + +Loop: ; preds = %Loop, %0 + call void @foo( ) + %A = call double @sin( double %X ) readnone + br i1 true, label %Loop, label %Out + +Out: ; preds = %Loop + ret double %A +; CHECK: @test2 +; CHECK: Out: +; CHECK-NEXT: call double @sin +; CHECK-NEXT: ret double %A +} + +; This testcase checks to make sure the sinker does not cause problems with +; critical edges. +define void @test3() { +Entry: + br i1 false, label %Loop, label %Exit +Loop: + %X = add i32 0, 1 + br i1 false, label %Loop, label %Exit +Exit: + %Y = phi i32 [ 0, %Entry ], [ %X, %Loop ] + ret void + +; CHECK: @test3 +; CHECK: Exit.loopexit: +; CHECK-NEXT: %X = add i32 0, 1 +; CHECK-NEXT: br label %Exit + +} + +; If the result of an instruction is only used outside of the loop, sink +; the instruction to the exit blocks instead of executing it on every +; iteration of the loop. +; +define i32 @test4(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] + %tmp.6 = mul i32 %N, %N_addr.0.pn ; <i32> [#uses=1] + %tmp.7 = sub i32 %tmp.6, %N ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.7 +; CHECK: @test4 +; CHECK: Out: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6, %N +; CHECK-NEXT: ret i32 +} + +; To reduce register pressure, if a load is hoistable out of the loop, and the +; result of the load is only used outside of the loop, sink the load instead of +; hoisting it! +; +@X = global i32 5 ; <i32*> [#uses=1] + +define i32 @test5(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] + %tmp.6 = load i32* @X ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.6 +; CHECK: @test5 +; CHECK: Out: +; CHECK-NEXT: %tmp.6 = load i32* @X +; CHECK-NEXT: ret i32 %tmp.6 +} + + + +; The loop sinker was running from the bottom of the loop to the top, causing +; it to miss opportunities to sink instructions that depended on sinking other +; instructions from the loop. Instead they got hoisted, which is better than +; leaving them in the loop, but increases register pressure pointlessly. + + %Ty = type { i32, i32 } +@X2 = external global %Ty + +define i32 @test6() { + br label %Loop +Loop: + %dead = getelementptr %Ty* @X2, i64 0, i32 0 + %sunk2 = load i32* %dead + br i1 false, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %sunk2 +; CHECK: @test6 +; CHECK: Out: +; CHECK-NEXT: %dead = getelementptr %Ty* @X2, i64 0, i32 0 +; CHECK-NEXT: %sunk2 = load i32* %dead +; CHECK-NEXT: ret i32 %sunk2 +} + + + +; This testcase ensures that we can sink instructions from loops with +; multiple exits. +; +define i32 @test7(i32 %N, i1 %C) { +Entry: + br label %Loop +Loop: ; preds = %ContLoop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %ContLoop ], [ %N, %Entry ] + %tmp.6 = mul i32 %N, %N_addr.0.pn + %tmp.7 = sub i32 %tmp.6, %N ; <i32> [#uses=2] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + br i1 %C, label %ContLoop, label %Out1 +ContLoop: + %tmp.1 = icmp ne i32 %N_addr.0.pn, 1 + br i1 %tmp.1, label %Loop, label %Out2 +Out1: ; preds = %Loop + ret i32 %tmp.7 +Out2: ; preds = %ContLoop + ret i32 %tmp.7 +; CHECK: @test7 +; CHECK: Out1: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6, %N +; CHECK-NEXT: ret +; CHECK: Out2: +; CHECK-NEXT: mul i32 %N, %N_addr.0.pn +; CHECK-NEXT: sub i32 %tmp.6 +; CHECK-NEXT: ret +} + + +; This testcase checks to make sure we can sink values which are only live on +; some exits out of the loop, and that we can do so without breaking dominator +; info. +define i32 @test8(i1 %C1, i1 %C2, i32* %P, i32* %Q) { +Entry: + br label %Loop +Loop: ; preds = %Cont, %Entry + br i1 %C1, label %Cont, label %exit1 +Cont: ; preds = %Loop + %X = load i32* %P ; <i32> [#uses=2] + store i32 %X, i32* %Q + %V = add i32 %X, 1 ; <i32> [#uses=1] + br i1 %C2, label %Loop, label %exit2 +exit1: ; preds = %Loop + ret i32 0 +exit2: ; preds = %Cont + ret i32 %V +; CHECK: @test8 +; CHECK: exit1: +; CHECK-NEXT: ret i32 0 +; CHECK: exit2: +; CHECK-NEXT: %V = add i32 %X, 1 +; CHECK-NEXT: ret i32 %V +} + + +define void @test9() { +loopentry.2.i: + br i1 false, label %no_exit.1.i.preheader, label %loopentry.3.i.preheader +no_exit.1.i.preheader: ; preds = %loopentry.2.i + br label %no_exit.1.i +no_exit.1.i: ; preds = %endif.8.i, %no_exit.1.i.preheader + br i1 false, label %return.i, label %endif.8.i +endif.8.i: ; preds = %no_exit.1.i + %inc.1.i = add i32 0, 1 ; <i32> [#uses=1] + br i1 false, label %no_exit.1.i, label %loopentry.3.i.preheader.loopexit +loopentry.3.i.preheader.loopexit: ; preds = %endif.8.i + br label %loopentry.3.i.preheader +loopentry.3.i.preheader: ; preds = %loopentry.3.i.preheader.loopexit, %loopentry.2.i + %arg_num.0.i.ph13000 = phi i32 [ 0, %loopentry.2.i ], [ %inc.1.i, %loopentry.3.i.preheader.loopexit ] ; <i32> [#uses=0] + ret void +return.i: ; preds = %no_exit.1.i + ret void + +; CHECK: @test9 +; CHECK: loopentry.3.i.preheader.loopexit: +; CHECK-NEXT: %inc.1.i = add i32 0, 1 +; CHECK-NEXT: br label %loopentry.3.i.preheader +} + + +; Potentially trapping instructions may be sunk as long as they are guaranteed +; to be executed. +define i32 @test10(i32 %N) { +Entry: + br label %Loop +Loop: ; preds = %Loop, %Entry + %N_addr.0.pn = phi i32 [ %dec, %Loop ], [ %N, %Entry ] ; <i32> [#uses=3] + %tmp.6 = sdiv i32 %N, %N_addr.0.pn ; <i32> [#uses=1] + %dec = add i32 %N_addr.0.pn, -1 ; <i32> [#uses=1] + %tmp.1 = icmp ne i32 %N_addr.0.pn, 0 ; <i1> [#uses=1] + br i1 %tmp.1, label %Loop, label %Out +Out: ; preds = %Loop + ret i32 %tmp.6 + +; CHECK: @test10 +; CHECK: Out: +; CHECK-NEXT: %tmp.6 = sdiv i32 %N, %N_addr.0.pn +; CHECK-NEXT: ret i32 %tmp.6 +} + |
