diff options
Diffstat (limited to 'llvm/test/Transforms/CodeExtractor')
51 files changed, 3353 insertions, 0 deletions
diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-13-LoopExtractorCrash.ll b/llvm/test/Transforms/CodeExtractor/2004-03-13-LoopExtractorCrash.ll new file mode 100644 index 00000000000..3d0339bc2db --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-13-LoopExtractorCrash.ll @@ -0,0 +1,75 @@ +; RUN: opt < %s -loop-extract -disable-output + +define void @solve() { +entry: + br label %loopentry.0 + +loopentry.0: ; preds = %endif.0, %entry + br i1 false, label %no_exit.0, label %loopexit.0 + +no_exit.0: ; preds = %loopentry.0 + br i1 false, label %then.0, label %endif.0 + +then.0: ; preds = %no_exit.0 + br i1 false, label %shortcirc_done, label %shortcirc_next + +shortcirc_next: ; preds = %then.0 + br label %shortcirc_done + +shortcirc_done: ; preds = %shortcirc_next, %then.0 + br i1 false, label %then.1, label %endif.1 + +then.1: ; preds = %shortcirc_done + br i1 false, label %cond_true, label %cond_false + +cond_true: ; preds = %then.1 + br label %cond_continue + +cond_false: ; preds = %then.1 + br label %cond_continue + +cond_continue: ; preds = %cond_false, %cond_true + br label %return + +after_ret.0: ; No predecessors! + br label %endif.1 + +endif.1: ; preds = %after_ret.0, %shortcirc_done + br label %endif.0 + +endif.0: ; preds = %endif.1, %no_exit.0 + br label %loopentry.0 + +loopexit.0: ; preds = %loopentry.0 + br i1 false, label %then.2, label %endif.2 + +then.2: ; preds = %loopexit.0 + br i1 false, label %then.3, label %endif.3 + +then.3: ; preds = %then.2 + br label %return + +after_ret.1: ; No predecessors! + br label %endif.3 + +endif.3: ; preds = %after_ret.1, %then.2 + br label %endif.2 + +endif.2: ; preds = %endif.3, %loopexit.0 + br label %loopentry.1 + +loopentry.1: ; preds = %no_exit.1, %endif.2 + br i1 false, label %no_exit.1, label %loopexit.1 + +no_exit.1: ; preds = %loopentry.1 + br label %loopentry.1 + +loopexit.1: ; preds = %loopentry.1 + br label %return + +after_ret.2: ; No predecessors! + br label %return + +return: ; preds = %after_ret.2, %loopexit.1, %then.3, %cond_continue + ret void +} diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-14-DominanceProblem.ll b/llvm/test/Transforms/CodeExtractor/2004-03-14-DominanceProblem.ll new file mode 100644 index 00000000000..2f9c0c7371c --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-14-DominanceProblem.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -loop-extract -disable-output +; This testcase is failing the loop extractor because not all exit blocks +; are dominated by all of the live-outs. + +define i32 @ab(i32 %alpha, i32 %beta) { +entry: + br label %loopentry.1.preheader + +loopentry.1.preheader: ; preds = %entry + br label %loopentry.1 + +loopentry.1: ; preds = %no_exit.1, %loopentry.1.preheader + br i1 false, label %no_exit.1, label %loopexit.0.loopexit1 + +no_exit.1: ; preds = %loopentry.1 + %tmp.53 = load i32, i32* null ; <i32> [#uses=1] + br i1 false, label %shortcirc_next.2, label %loopentry.1 + +shortcirc_next.2: ; preds = %no_exit.1 + %tmp.563 = call i32 @wins( i32 0, i32 %tmp.53, i32 3 ) ; <i32> [#uses=0] + ret i32 0 + +loopexit.0.loopexit1: ; preds = %loopentry.1 + br label %loopexit.0 + +loopexit.0: ; preds = %loopexit.0.loopexit1 + ret i32 0 +} + +declare i32 @wins(i32, i32, i32) + +declare i16 @ab_code() + diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-14-NoSwitchSupport.ll b/llvm/test/Transforms/CodeExtractor/2004-03-14-NoSwitchSupport.ll new file mode 100644 index 00000000000..7cd72797a67 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-14-NoSwitchSupport.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -loop-extract-single -disable-output + +define void @ab() { +entry: + br label %codeReplTail + +then.1: ; preds = %codeReplTail + br label %loopentry.1 + +loopentry.1: ; preds = %no_exit.1, %then.1 + br i1 false, label %no_exit.1, label %loopexit.0.loopexit1 + +no_exit.1: ; preds = %loopentry.1 + br label %loopentry.1 + +loopexit.0.loopexit: ; preds = %codeReplTail + ret void + +loopexit.0.loopexit1: ; preds = %loopentry.1 + ret void + +codeReplTail: ; preds = %codeReplTail, %entry + switch i16 0, label %codeReplTail [ + i16 0, label %loopexit.0.loopexit + i16 1, label %then.1 + ] +} + diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-17-MissedLiveIns.ll b/llvm/test/Transforms/CodeExtractor/2004-03-17-MissedLiveIns.ll new file mode 100644 index 00000000000..01fe54be29a --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-17-MissedLiveIns.ll @@ -0,0 +1,47 @@ +; RUN: opt < %s -loop-extract -disable-output + +define void @sendMTFValues() { +entry: + br i1 false, label %then.1, label %endif.1 + +then.1: ; preds = %entry + br i1 false, label %loopentry.6.preheader, label %else.0 + +endif.1: ; preds = %entry + ret void + +else.0: ; preds = %then.1 + ret void + +loopentry.6.preheader: ; preds = %then.1 + br i1 false, label %endif.7.preheader, label %loopexit.9 + +endif.7.preheader: ; preds = %loopentry.6.preheader + %tmp.183 = add i32 0, -1 ; <i32> [#uses=1] + br label %endif.7 + +endif.7: ; preds = %loopexit.15, %endif.7.preheader + br i1 false, label %loopentry.10, label %loopentry.12 + +loopentry.10: ; preds = %endif.7 + br label %loopentry.12 + +loopentry.12: ; preds = %loopentry.10, %endif.7 + %ge.2.1 = phi i32 [ 0, %loopentry.10 ], [ %tmp.183, %endif.7 ] ; <i32> [#uses=0] + br i1 false, label %loopexit.14, label %no_exit.11 + +no_exit.11: ; preds = %loopentry.12 + ret void + +loopexit.14: ; preds = %loopentry.12 + br i1 false, label %loopexit.15, label %no_exit.14 + +no_exit.14: ; preds = %loopexit.14 + ret void + +loopexit.15: ; preds = %loopexit.14 + br i1 false, label %endif.7, label %loopexit.9 + +loopexit.9: ; preds = %loopexit.15, %loopentry.6.preheader + ret void +} diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-17-UpdatePHIsOutsideRegion.ll b/llvm/test/Transforms/CodeExtractor/2004-03-17-UpdatePHIsOutsideRegion.ll new file mode 100644 index 00000000000..6b306d232e0 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-17-UpdatePHIsOutsideRegion.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -loop-extract -disable-output + +define void @maketree() { +entry: + br i1 false, label %no_exit.1, label %loopexit.0 + +no_exit.1: ; preds = %endif, %expandbox.entry, %entry + br i1 false, label %endif, label %expandbox.entry + +expandbox.entry: ; preds = %no_exit.1 + br i1 false, label %loopexit.1, label %no_exit.1 + +endif: ; preds = %no_exit.1 + br i1 false, label %loopexit.1, label %no_exit.1 + +loopexit.1: ; preds = %endif, %expandbox.entry + %ic.i.0.0.4 = phi i32 [ 0, %expandbox.entry ], [ 0, %endif ] ; <i32> [#uses=0] + ret void + +loopexit.0: ; preds = %entry + ret void +} + diff --git a/llvm/test/Transforms/CodeExtractor/2004-03-18-InvokeHandling.ll b/llvm/test/Transforms/CodeExtractor/2004-03-18-InvokeHandling.ll new file mode 100644 index 00000000000..fd9814c545f --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-03-18-InvokeHandling.ll @@ -0,0 +1,198 @@ +; RUN: opt < %s -loop-extract -disable-output + +declare i32 @_IO_getc() + +declare void @__errno_location() + +define void @yylex() personality i32 (...)* @__gcc_personality_v0 { +entry: + switch i32 0, label %label.126 [ + i32 0, label %return + i32 61, label %combine + i32 33, label %combine + i32 94, label %combine + i32 37, label %combine + i32 47, label %combine + i32 42, label %combine + i32 62, label %combine + i32 60, label %combine + i32 58, label %combine + i32 124, label %combine + i32 38, label %combine + i32 45, label %combine + i32 43, label %combine + i32 34, label %string_constant + i32 39, label %char_constant + i32 46, label %loopexit.2 + i32 57, label %loopexit.2 + i32 56, label %loopexit.2 + i32 55, label %loopexit.2 + i32 54, label %loopexit.2 + i32 53, label %loopexit.2 + i32 52, label %loopexit.2 + i32 51, label %loopexit.2 + i32 50, label %loopexit.2 + i32 49, label %loopexit.2 + i32 48, label %loopexit.2 + i32 95, label %letter + i32 122, label %letter + i32 121, label %letter + i32 120, label %letter + i32 119, label %letter + i32 118, label %letter + i32 117, label %letter + i32 116, label %letter + i32 115, label %letter + i32 114, label %letter + i32 113, label %letter + i32 112, label %letter + i32 111, label %letter + i32 110, label %letter + i32 109, label %letter + i32 108, label %letter + i32 107, label %letter + i32 106, label %letter + i32 105, label %letter + i32 104, label %letter + i32 103, label %letter + i32 102, label %letter + i32 101, label %letter + i32 100, label %letter + i32 99, label %letter + i32 98, label %letter + i32 97, label %letter + i32 90, label %letter + i32 89, label %letter + i32 88, label %letter + i32 87, label %letter + i32 86, label %letter + i32 85, label %letter + i32 84, label %letter + i32 83, label %letter + i32 82, label %letter + i32 81, label %letter + i32 80, label %letter + i32 79, label %letter + i32 78, label %letter + i32 77, label %letter + i32 75, label %letter + i32 74, label %letter + i32 73, label %letter + i32 72, label %letter + i32 71, label %letter + i32 70, label %letter + i32 69, label %letter + i32 68, label %letter + i32 67, label %letter + i32 66, label %letter + i32 65, label %letter + i32 64, label %label.13 + i32 76, label %label.12 + i32 36, label %label.11 + i32 -1, label %label.10 + ] + +label.10: ; preds = %entry + ret void + +label.11: ; preds = %entry + ret void + +label.12: ; preds = %entry + ret void + +label.13: ; preds = %entry + ret void + +letter: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry + ret void + +loopexit.2: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry + switch i32 0, label %shortcirc_next.14 [ + i32 48, label %then.20 + i32 46, label %endif.38 + ] + +then.20: ; preds = %loopexit.2 + switch i32 0, label %else.4 [ + i32 120, label %then.21 + i32 88, label %then.21 + ] + +then.21: ; preds = %then.20, %then.20 + ret void + +else.4: ; preds = %then.20 + ret void + +shortcirc_next.14: ; preds = %loopexit.2 + ret void + +endif.38: ; preds = %loopexit.2 + br i1 false, label %then.40, label %then.39 + +then.39: ; preds = %endif.38 + ret void + +then.40: ; preds = %endif.38 + invoke void @__errno_location( ) + to label %switchexit.2 unwind label %LongJmpBlkPre + +loopentry.6: ; preds = %endif.52 + switch i32 0, label %switchexit.2 [ + i32 73, label %label.82 + i32 105, label %label.82 + i32 76, label %label.80 + i32 108, label %label.80 + i32 70, label %label.78 + i32 102, label %label.78 + ] + +label.78: ; preds = %loopentry.6, %loopentry.6 + ret void + +label.80: ; preds = %loopentry.6, %loopentry.6 + ret void + +label.82: ; preds = %loopentry.6, %loopentry.6 + %c.0.15.5 = phi i32 [ %tmp.79417, %loopentry.6 ], [ %tmp.79417, %loopentry.6 ] ; <i32> [#uses=0] + ret void + +switchexit.2: ; preds = %loopentry.6, %then.40 + br i1 false, label %endif.51, label %loopexit.6 + +endif.51: ; preds = %switchexit.2 + br i1 false, label %endif.52, label %then.52 + +then.52: ; preds = %endif.51 + ret void + +endif.52: ; preds = %endif.51 + %tmp.79417 = invoke i32 @_IO_getc( ) + to label %loopentry.6 unwind label %LongJmpBlkPre ; <i32> [#uses=2] + +loopexit.6: ; preds = %switchexit.2 + ret void + +char_constant: ; preds = %entry + ret void + +string_constant: ; preds = %entry + ret void + +combine: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry + ret void + +label.126: ; preds = %entry + ret void + +return: ; preds = %entry + ret void + +LongJmpBlkPre: ; preds = %endif.52, %then.40 + %exn = landingpad { i8*, i32 } + catch i8* null + ret void +} + +declare i32 @__gcc_personality_v0(...) diff --git a/llvm/test/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll b/llvm/test/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll new file mode 100644 index 00000000000..9f70bdc71b1 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -extract-blocks -disable-output + +define void @test1() { +no_exit.0.i: + br i1 false, label %yylex.entry, label %yylex.entry + +yylex.entry: ; preds = %no_exit.0.i, %no_exit.0.i + %tmp.1027 = phi i32 [ 0, %no_exit.0.i ], [ 0, %no_exit.0.i ] ; <i32> [#uses=0] + ret void +} + +define void @test2() { +no_exit.0.i: + switch i32 0, label %yylex.entry [ + i32 0, label %yylex.entry + i32 1, label %foo + ] + +yylex.entry: ; preds = %no_exit.0.i, %no_exit.0.i + %tmp.1027 = phi i32 [ 0, %no_exit.0.i ], [ 0, %no_exit.0.i ] ; <i32> [#uses=0] + ret void + +foo: ; preds = %no_exit.0.i + ret void +} + diff --git a/llvm/test/Transforms/CodeExtractor/2004-11-12-InvokeExtract.ll b/llvm/test/Transforms/CodeExtractor/2004-11-12-InvokeExtract.ll new file mode 100644 index 00000000000..0a83681a071 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/2004-11-12-InvokeExtract.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -extract-blocks -disable-output +define i32 @foo() personality i32 (...)* @__gcc_personality_v0 { + br label %EB + +EB: ; preds = %0 + %V = invoke i32 @foo( ) + to label %Cont unwind label %Unw ; <i32> [#uses=1] + +Cont: ; preds = %EB + ret i32 %V + +Unw: ; preds = %EB + %exn = landingpad { i8*, i32 } + catch i8* null + resume { i8*, i32 } %exn +} + +declare i32 @__gcc_personality_v0(...) diff --git a/llvm/test/Transforms/CodeExtractor/BlockAddressReference.ll b/llvm/test/Transforms/CodeExtractor/BlockAddressReference.ll new file mode 100644 index 00000000000..91f85bf3ed8 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/BlockAddressReference.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -loop-extract -S | FileCheck %s + +@label = common local_unnamed_addr global i8* null + +; CHECK: define +; no outlined function +; CHECK-NOT: define +define i32 @sterix(i32 %n) { +entry: + %tobool = icmp ne i32 %n, 0 + ; this blockaddress references a basic block that goes in the extracted loop + %cond = select i1 %tobool, i8* blockaddress(@sterix, %for.cond), i8* blockaddress(@sterix, %exit) + store i8* %cond, i8** @label + %cmp5 = icmp sgt i32 %n, 0 + br i1 %cmp5, label %for.body, label %exit + +for.cond: + %mul = shl nsw i32 %s.06, 1 + %exitcond = icmp eq i32 %inc, %n + br i1 %exitcond, label %exit.loopexit, label %for.body + +for.body: + %i.07 = phi i32 [ %inc, %for.cond ], [ 0, %entry ] + %s.06 = phi i32 [ %mul, %for.cond ], [ 1, %entry ] + %inc = add nuw nsw i32 %i.07, 1 + br label %for.cond + +exit.loopexit: + %phitmp = icmp ne i32 %s.06, 2 + %phitmp8 = zext i1 %phitmp to i32 + br label %exit + +exit: + %s.1 = phi i32 [ 1, %entry ], [ %phitmp8, %exit.loopexit ] + ret i32 %s.1 +} diff --git a/llvm/test/Transforms/CodeExtractor/BlockAddressSelfReference.ll b/llvm/test/Transforms/CodeExtractor/BlockAddressSelfReference.ll new file mode 100644 index 00000000000..7d5a827a358 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/BlockAddressSelfReference.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -loop-extract -S | FileCheck %s + +@choum.addr = internal unnamed_addr constant [3 x i8*] [i8* blockaddress(@choum, %bb10), i8* blockaddress(@choum, %bb14), i8* blockaddress(@choum, %bb18)] + +; CHECK: define +; no outlined function +; CHECK-NOT: define + +define void @choum(i32 %arg, i32* nocapture %arg1, i32 %arg2) { +bb: + %tmp = icmp sgt i32 %arg, 0 + br i1 %tmp, label %bb3, label %bb24 + +bb3: ; preds = %bb + %tmp4 = sext i32 %arg2 to i64 + %tmp5 = getelementptr inbounds [3 x i8*], [3 x i8*]* @choum.addr, i64 0, i64 %tmp4 + %tmp6 = load i8*, i8** %tmp5 + %tmp7 = zext i32 %arg to i64 + br label %bb8 + +bb8: ; preds = %bb18, %bb3 + %tmp9 = phi i64 [ 0, %bb3 ], [ %tmp22, %bb18 ] + indirectbr i8* %tmp6, [label %bb10, label %bb14, label %bb18] + +bb10: ; preds = %bb8 + %tmp11 = getelementptr inbounds i32, i32* %arg1, i64 %tmp9 + %tmp12 = load i32, i32* %tmp11 + %tmp13 = add nsw i32 %tmp12, 1 + store i32 %tmp13, i32* %tmp11 + br label %bb14 + +bb14: ; preds = %bb10, %bb8 + %tmp15 = getelementptr inbounds i32, i32* %arg1, i64 %tmp9 + %tmp16 = load i32, i32* %tmp15 + %tmp17 = shl nsw i32 %tmp16, 1 + store i32 %tmp17, i32* %tmp15 + br label %bb18 + +bb18: ; preds = %bb14, %bb8 + %tmp19 = getelementptr inbounds i32, i32* %arg1, i64 %tmp9 + %tmp20 = load i32, i32* %tmp19 + %tmp21 = add nsw i32 %tmp20, -3 + store i32 %tmp21, i32* %tmp19 + %tmp22 = add nuw nsw i64 %tmp9, 1 + %tmp23 = icmp eq i64 %tmp22, %tmp7 + br i1 %tmp23, label %bb24, label %bb8 + +bb24: ; preds = %bb18, %bb + ret void +} diff --git a/llvm/test/Transforms/CodeExtractor/ExtractedFnEntryCount.ll b/llvm/test/Transforms/CodeExtractor/ExtractedFnEntryCount.ll new file mode 100644 index 00000000000..55c44e1e832 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/ExtractedFnEntryCount.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + +; This test checks to make sure that the CodeExtractor +; properly sets the entry count for the function that is +; extracted based on the root block being extracted and also +; takes into consideration if the block has edges coming from +; a block that is also being extracted. + +define i32 @inlinedFunc(i1 %cond) !prof !1 { +entry: + br i1 %cond, label %if.then, label %return, !prof !2 +if.then: + br i1 %cond, label %if.then, label %return, !prof !3 +return: ; preds = %entry + ret i32 0 +} + + +define internal i32 @dummyCaller(i1 %cond) !prof !1 { +entry: + %val = call i32 @inlinedFunc(i1 %cond) + ret i32 %val +} + +; CHECK: @inlinedFunc.1.if.then(i1 %cond) !prof [[COUNT1:![0-9]+]] + + +!llvm.module.flags = !{!0} +; CHECK: [[COUNT1]] = !{!"function_entry_count", i64 250} +!0 = !{i32 1, !"MaxFunctionCount", i32 1000} +!1 = !{!"function_entry_count", i64 1000} +!2 = !{!"branch_weights", i32 250, i32 750} +!3 = !{!"branch_weights", i32 125, i32 125} diff --git a/llvm/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll b/llvm/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll new file mode 100644 index 00000000000..8e362080dc4 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/MultipleExitBranchProb.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis -S | FileCheck %s + +; This test checks to make sure that CodeExtractor updates +; the exit branch probabilities for multiple exit blocks. + +define i32 @inlinedFunc(i1 %cond) !prof !1 { +entry: + br i1 %cond, label %if.then, label %return, !prof !2 +if.then: + br i1 %cond, label %return, label %return.2, !prof !3 +return.2: + ret i32 10 +return: ; preds = %entry + ret i32 0 +} + + +define internal i32 @dummyCaller(i1 %cond) !prof !1 { +entry: +%val = call i32 @inlinedFunc(i1 %cond) +ret i32 %val + +; CHECK-LABEL: @dummyCaller +; CHECK: call +; CHECK-NEXT: br i1 {{.*}}return.i{{.*}}return.2{{.*}}!prof [[COUNT1:![0-9]+]] +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"MaxFunctionCount", i32 10000} +!1 = !{!"function_entry_count", i64 10000} +!2 = !{!"branch_weights", i32 5, i32 5} +!3 = !{!"branch_weights", i32 4, i32 1} + +; CHECK: [[COUNT1]] = !{!"branch_weights", i32 31, i32 8} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca.ll new file mode 100644 index 00000000000..48db0b61a31 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca.ll @@ -0,0 +1,68 @@ + +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + ; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + +%"class.base" = type { %"struct.base"* } +%"struct.base" = type opaque + +@g = external local_unnamed_addr global i32, align 4 + +; Function Attrs: nounwind uwtable +define i32 @callee_sinkable_bitcast(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL:define{{.*}}@callee_sinkable_bitcast.{{[0-9]}} +; CHECK: alloca +; CHECK-NEXT: bitcast +; CHECK: call void @llvm.lifetime +bb: + %tmp = alloca %"class.base", align 4 + %tmp1 = bitcast %"class.base"* %tmp to i8* + %tmp2 = load i32, i32* @g, align 4, !tbaa !2 + %tmp3 = add nsw i32 %tmp2, 1 + %tmp4 = icmp slt i32 %arg, 0 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) #2 + %tmp11 = bitcast %"class.base"* %tmp to i32* + store i32 %tmp3, i32* %tmp11, align 4, !tbaa !2 + store i32 %tmp3, i32* @g, align 4, !tbaa !2 + call void @bar(i32* nonnull %tmp11) #2 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) #2 + br label %bb6 + +bb6: ; preds = %bb5, %bb + %tmp7 = phi i32 [ 1, %bb5 ], [ 0, %bb ] + ret i32 %tmp7 +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +declare void @bar(i32*) local_unnamed_addr #2 +declare void @bar2(i32*, i32*) local_unnamed_addr #1 + + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind uwtable +define i32 @caller(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 @callee_sinkable_bitcast(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind uwtable} +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} + + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca2.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca2.ll new file mode 100644 index 00000000000..4ca418389e5 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca2.ll @@ -0,0 +1,65 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + +%"class.base" = type { %"struct.base"* } +%"struct.base" = type opaque + +@g = external local_unnamed_addr global i32, align 4 + +define i32 @callee_no_bitcast(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL:define{{.*}}@callee_no_bitcast.{{[0-9]}} +; CHECK: alloca +; CHECK: call void @llvm.lifetime +bb: + %tmp = alloca i8, align 4 + %tmp2 = load i32, i32* @g, align 4, !tbaa !2 + %tmp3 = add nsw i32 %tmp2, 1 + %tmp4 = icmp slt i32 %arg, 0 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp) #2 + store i32 %tmp3, i32* @g, align 4, !tbaa !2 + %tmp11 = bitcast i8 * %tmp to i32* + call void @bar(i32* nonnull %tmp11) #2 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp) #2 + br label %bb6 + +bb6: ; preds = %bb5, %bb + %tmp7 = phi i32 [ 1, %bb5 ], [ 0, %bb ] + ret i32 %tmp7 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +declare void @bar(i32*) local_unnamed_addr #2 +declare void @bar2(i32*, i32*) local_unnamed_addr #1 + + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind uwtable +define i32 @caller(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 @callee_no_bitcast(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind uwtable} +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} + + + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll new file mode 100644 index 00000000000..5112135b166 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca4.ll @@ -0,0 +1,70 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + +%"class.base" = type { %"struct.base"* } +%"struct.base" = type opaque + +@g = external local_unnamed_addr global i32, align 4 + +; CHECK-LABEL: define{{.*}}@caller( +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %tmp.i) +; CHECK-NEXT: call void @callee_unknown_use1.{{.*}}(i8* %tmp.i + +define i32 @callee_unknown_use1(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL:define{{.*}}@callee_unknown_use1.{{[0-9]}} +; CHECK-NOT: alloca +bb: + %tmp = alloca i8, align 4 + %tmp2 = load i32, i32* @g, align 4, !tbaa !2 + %tmp3 = add nsw i32 %tmp2, 1 + %tmp4 = icmp slt i32 %arg, 0 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp) #2 + store i32 %tmp3, i32* @g, align 4, !tbaa !2 + %tmp11 = bitcast i8* %tmp to i32* + call void @bar(i32* nonnull %tmp11) #2 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp) #2 + br label %bb6 + +bb6: ; preds = %bb5, %bb + %tmp7 = phi i32 [ 1, %bb5 ], [ 0, %bb ] + %tmp1 = bitcast i8* %tmp to i32* + ret i32 %tmp7 +} + + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +declare void @bar(i32*) local_unnamed_addr #2 +declare void @bar2(i32*, i32*) local_unnamed_addr #1 + + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind uwtable +define i32 @caller(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 @callee_unknown_use1(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind uwtable} +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} + + + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca5.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca5.ll new file mode 100644 index 00000000000..0bde58fbccd --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAlloca5.ll @@ -0,0 +1,66 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s + +%"class.base" = type { %"struct.base"* } +%"struct.base" = type opaque + +@g = external local_unnamed_addr global i32, align 4 + +define i32 @callee_unknown_use2(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL:define{{.*}}@callee_unknown_use2.{{[0-9]}} +; CHECK-NOT: alloca +bb: + %tmp = alloca i32, align 4 + %tmp1 = bitcast i32* %tmp to i8* + %tmp2 = load i32, i32* @g, align 4, !tbaa !2 + %tmp3 = add nsw i32 %tmp2, 1 + %tmp4 = icmp slt i32 %arg, 0 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) #2 + store i32 %tmp3, i32* %tmp, align 4, !tbaa !2 + store i32 %tmp3, i32* @g, align 4, !tbaa !2 + call void @bar(i32* nonnull %tmp) #2 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) #2 + br label %bb6 + +bb6: ; preds = %bb5, %bb + %tmp7 = phi i32 [ 1, %bb5 ], [ 0, %bb ] + %tmp10 = bitcast i8* %tmp1 to i32* + ret i32 %tmp7 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +declare void @bar(i32*) local_unnamed_addr #2 +declare void @bar2(i32*, i32*) local_unnamed_addr #1 + + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind uwtable +define i32 @caller(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 @callee_unknown_use2(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind uwtable} +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} + + + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll new file mode 100644 index 00000000000..6d555b740e5 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll @@ -0,0 +1,56 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s + +; Function Attrs: nounwind uwtable +define i32 @bar(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb5 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @channels() #2 + %tmp3 = icmp slt i32 %tmp2, %arg + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb1 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + br label %bb5 + +bb5: ; preds = %bb4, %bb1, %bb + %tmp6 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ], [ 1, %bb ] + ret i32 %tmp6 +} + +declare i32 @channels(...) local_unnamed_addr #1 + +declare void @foo(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call void @bar.1. +; LIMIT-LABEL: @dummy_caller +; LIMIT: br i1 +; LIMIT-NOT: br +; LIMIT: call void @bar.1. + %tmp = tail call i32 @bar(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind } +attributes #2 = { nounwind } + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAndOr.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAndOr.ll new file mode 100644 index 00000000000..9da9ed4437e --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAndOr.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT %s +; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=3 -S | FileCheck --check-prefix=LIMIT %s + +; Function Attrs: nounwind uwtable +define i32 @bar(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb4 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @n() #2 + %tmp3 = icmp slt i32 %tmp2, %arg + br i1 %tmp3, label %bb7, label %bb4 + +bb4: ; preds = %bb1, %bb + %tmp5 = tail call i32 (...) @m() #2 + %tmp6 = icmp slt i32 %tmp5, %arg + br i1 %tmp6, label %bb7, label %bb8 + +bb7: ; preds = %bb4, %bb1 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + br label %bb8 + +bb8: ; preds = %bb7, %bb4 + %tmp9 = phi i32 [ 0, %bb7 ], [ 1, %bb4 ] + ret i32 %tmp9 +} + +declare i32 @n(...) local_unnamed_addr #1 + +declare i32 @m(...) local_unnamed_addr #1 + +declare void @foo(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK: br i1 +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call void @bar.1. +; LIMIT-LABEL: @dummy_caller +; LIMIT-NOT: br i1 +; LIMIT: call i32 @bar + %tmp = tail call i32 @bar(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind } +attributes #2 = { nounwind } + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll new file mode 100644 index 00000000000..18c934bc6a1 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll @@ -0,0 +1,85 @@ +; RUN: opt < %s -S -partial-inliner -skip-partial-inlining-cost-analysis=true | FileCheck %s + + +define i32 @callee_most(i32 %v) unnamed_addr #0 #1 { +entry: + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10 + br label %if.end + +if.end: + %v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + +define i32 @callee_noinline(i32 %v) optnone noinline { +entry: + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10 + br label %if.end + +if.end: + %v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + +define i32 @callee_writeonly(i32 %v) writeonly { +entry: + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10 + br label %if.end + +if.end: + %v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} +; CHECK-LABEL: @caller +; CHECK: call void @callee_most.2.if.then(i32 %v +; CHECK: call i32 @callee_noinline(i32 %v) +; CHECK: call void @callee_writeonly.1.if.then(i32 %v +define i32 @caller(i32 %v) { +entry: + %c1 = call i32 @callee_most(i32 %v) + %c2 = call i32 @callee_noinline(i32 %v) + %c3 = call i32 @callee_writeonly(i32 %v) + ret i32 %c3 +} + +; CHECK: define internal void @callee_writeonly.1.if.then(i32 %v, i32* %sub.out) { +; CHECK: define internal void @callee_most.2.if.then(i32 %v, i32* %sub.out) [[FN_ATTRS:#[0-9]+]] + +; attributes to preserve +attributes #0 = { + inlinehint minsize noduplicate noimplicitfloat norecurse noredzone nounwind + nonlazybind optsize safestack sanitize_address sanitize_hwaddress sanitize_memory + sanitize_thread ssp sspreq sspstrong strictfp uwtable "foo"="bar" + "patchable-function"="prologue-short-redirect" "probe-stack"="_foo_guard" "stack-probe-size"="4096" } + +; CHECK: attributes [[FN_ATTRS]] = { inlinehint minsize noduplicate noimplicitfloat norecurse noredzone nounwind nonlazybind optsize safestack sanitize_address sanitize_hwaddress sanitize_memory sanitize_thread ssp sspreq sspstrong strictfp uwtable "foo"="bar" "patchable-function"="prologue-short-redirect" "probe-stack"="_foo_guard" "stack-probe-size"="4096" } + +; attributes to drop +attributes #1 = { + alignstack=16 convergent inaccessiblememonly inaccessiblemem_or_argmemonly naked + noreturn readonly argmemonly returns_twice speculatable "thunk" +} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineCallRef.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineCallRef.ll new file mode 100644 index 00000000000..4465a0fd485 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineCallRef.ll @@ -0,0 +1,56 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s + + +; Function Attrs: nounwind +declare void @foo(...) local_unnamed_addr #0 + +; Function Attrs: noinline +define i32 @caller(i32 (i32)* nocapture %arg, i32 (i32)* nocapture %arg1, i32 %arg2) local_unnamed_addr #1 { +bb: + %tmp = tail call i32 %arg(i32 %arg2) #0 + %tmp3 = tail call i32 %arg1(i32 %arg2) #0 + %tmp4 = add nsw i32 %tmp3, %tmp + ret i32 %tmp4 +} + +; Function Attrs: nounwind +define i32 @bar(i32 %arg) #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb2 + +bb1: ; preds = %bb + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + tail call void (...) @foo() #0 + br label %bb2 + +bb2: ; preds = %bb1, %bb + %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp3 +} + +; Function Attrs: nounwind +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; check that caller is not wrongly inlined by partial inliner +; CHECK: call i32 @caller +; CHECK-NOT: call .* @bar + %tmp = tail call i32 @caller(i32 (i32)* nonnull @bar, i32 (i32)* nonnull @bar, i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind } +attributes #1 = { noinline } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 5.0.0 (trunk 300897) (llvm/trunk 300947)"} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll new file mode 100644 index 00000000000..c68a070a41d --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll @@ -0,0 +1,106 @@ +; RUN: opt < %s -S -partial-inliner -skip-partial-inlining-cost-analysis=true | FileCheck %s + +; CHECK-LABEL: @callee +; CHECK: %mul = mul nsw i32 %v, 10, !dbg ![[DBG1:[0-9]+]] +define i32 @callee(i32 %v) !dbg !16 { +entry: + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %mul = mul nsw i32 %v, 10, !dbg !17 + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10, !dbg !23 + br label %if.end + +if.end: ; preds = %if.then, %entry + %v2 = phi i32 [ %v, %entry ], [ %mul, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + +; CHECK-LABEL: @caller +; CHECK: codeRepl.i: +; CHECK-NOT: br label +; CHECK: call void @callee.2.if.then(i32 %v, i32* %mul.loc.i), !dbg ![[DBG2:[0-9]+]] +define i32 @caller(i32 %v) !dbg !8 { +entry: + %call = call i32 @callee(i32 %v), !dbg !14 + ret i32 %call +} + + +; CHECK-LABEL: @callee2 +; CHECK: %sub = sub i32 %v, 10, !dbg ![[DBG3:[0-9]+]] +define i32 @callee2(i32 %v) !dbg !18 { +entry: + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10, !dbg !20 + br label %if.end + +if.end: + %v2 = phi i32 [ %v, %entry ], [ %sub, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + +; CHECK-LABEL: @caller2 +; CHECK: codeRepl.i: +; CHECK-NOT: br label +; CHECK: call void @callee2.1.if.then(i32 %v, i32* %sub.loc.i), !dbg ![[DBG4:[0-9]+]] +define i32 @caller2(i32 %v) !dbg !21 { +entry: + %call = call i32 @callee2(i32 %v), !dbg !22 + ret i32 %call +} + +; CHECK-LABEL: define internal void @callee2.1.if.then +; CHECK: br label %if.then, !dbg ![[DBG5:[0-9]+]] + +; CHECK-LABEL: define internal void @callee.2.if.then +; CHECK: br label %if.then, !dbg ![[DBG6:[0-9]+]] + +; CHECK: ![[DBG1]] = !DILocation(line: 10, column: 7, +; CHECK: ![[DBG2]] = !DILocation(line: 10, column: 7, +; CHECK: ![[DBG3]] = !DILocation(line: 110, column: 17, +; CHECK: ![[DBG4]] = !DILocation(line: 110, column: 17, +; CHECK: ![[DBG5]] = !DILocation(line: 110, column: 17, +; CHECK: ![[DBG6]] = !DILocation(line: 10, column: 7, + + +!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 177881)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "test.c", directory: "/tmp") +!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 1, !"min_enum_size", i32 4} +!7 = !{!"clang version 6.0.0"} +!8 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 19, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "v", arg: 1, scope: !8, file: !1, line: 3, type: !11) +!14 = !DILocation(line: 5, column: 10, scope: !8) +!15 = distinct !DILexicalBlock(scope: !16, file: !1, line: 9, column: 7) +!16 = distinct !DISubprogram(name: "callee", scope: !1, file: !1, line: 8, type: !9, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!17 = !DILocation(line: 10, column: 7, scope: !15) +!18 = distinct !DISubprogram(name: "callee2", scope: !1, file: !1, line: 8, type: !9, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!19 = distinct !DILexicalBlock(scope: !18, file: !1, line: 100, column: 1) +!20 = !DILocation(line: 110, column: 17, scope: !19) +!21 = distinct !DISubprogram(name: "caller2", scope: !1, file: !1, line: 8, type: !9, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!22 = !DILocation(line: 110, column: 17, scope: !21) +!23 = !DILocation(line: 15, column: 7, scope: !15) diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineEntryPHICost.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineEntryPHICost.ll new file mode 100644 index 00000000000..a8c2d62710d --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineEntryPHICost.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s + +; Check that we do not overcompute the outlined region cost, where the PHIs in +; the outlined region entry (BB4) are moved outside the region by CodeExtractor. + +define i32 @bar(i32 %arg) { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb2 + +bb1: + br i1 undef, label %bb4, label %bb2 + +bb2: ; preds = %bb, %bb1 + br i1 undef, label %bb4, label %bb5 + +bb4: ; preds = %bb1, %bb2 + %xx1 = phi i32 [ 1, %bb1 ], [ 9, %bb2 ] + %xx2 = phi i32 [ 1, %bb1 ], [ 9, %bb2 ] + %xx3 = phi i32 [ 1, %bb1 ], [ 9, %bb2 ] + tail call void (...) @foo() #2 + br label %bb5 + +bb5: ; preds = %bb4, %bb2 + %tmp6 = phi i32 [ 1, %bb2 ], [ 9, %bb4 ] + ret i32 %tmp6 +} + +declare void @foo(...) + +define i32 @dummy_caller(i32 %arg) { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call void @bar.1. + %tmp = tail call i32 @bar(i32 %arg) + ret i32 %tmp +} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineEntryUpdate.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineEntryUpdate.ll new file mode 100644 index 00000000000..0efc8299dab --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineEntryUpdate.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -skip-partial-inlining-cost-analysis -partial-inliner -S | FileCheck %s +; RUN: opt < %s -skip-partial-inlining-cost-analysis -passes=partial-inliner -S | FileCheck %s + +define i32 @Func(i1 %cond, i32* align 4 %align.val) !prof !1 { +; CHECK: @Func({{.*}}) !prof [[REMAINCOUNT:![0-9]+]] +entry: + br i1 %cond, label %if.then, label %return +if.then: + ; Dummy store to have more than 0 uses + store i32 10, i32* %align.val, align 4 + br label %return +return: ; preds = %entry + ret i32 0 +} + +define internal i32 @Caller1(i1 %cond, i32* align 2 %align.val) !prof !3{ +entry: +; CHECK-LABEL: @Caller1 +; CHECK: br +; CHECK: call void @Func.1. +; CHECK: br +; CHECK: call void @Func.1. + %val = call i32 @Func(i1 %cond, i32* %align.val) + %val2 = call i32 @Func(i1 %cond, i32* %align.val) + ret i32 %val +} + +define internal i32 @Caller2(i1 %cond, i32* align 2 %align.val) !prof !2{ +entry: +; CHECK-LABEL: @Caller2 +; CHECK: br +; CHECK: call void @Func.1. + %val = call i32 @Func(i1 %cond, i32* %align.val) + ret i32 %val +} + +; CHECK: [[REMAINCOUNT]] = !{!"function_entry_count", i64 150} +!1 = !{!"function_entry_count", i64 200} +!2 = !{!"function_entry_count", i64 10} +!3 = !{!"function_entry_count", i64 20} + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineHighCost.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineHighCost.ll new file mode 100644 index 00000000000..e43a94dc6c3 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineHighCost.ll @@ -0,0 +1,107 @@ +; The outlined region has high frequency and the outlining +; call sequence is expensive (input, output, multiple exit etc) +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck %s +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -max-num-inline-blocks=2 -S | FileCheck --check-prefix=NOCOST %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -max-num-inline-blocks=2 -S | FileCheck --check-prefix=NOCOST %s + + +; Function Attrs: nounwind +define i32 @bar_hot_outline_region(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb16, !prof !1 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @foo() #0 + %tmp3 = tail call i32 (...) @foo() #0 + %tmp4 = tail call i32 (...) @foo() #0 + %tmp5 = tail call i32 (...) @foo() #0 + %tmp6 = tail call i32 (...) @foo() #0 + %tmp7 = tail call i32 (...) @foo() #0 + %tmp8 = add nsw i32 %arg, 1 + %tmp9 = tail call i32 @goo(i32 %tmp8) #0 + %tmp10 = tail call i32 (...) @foo() #0 + %tmp11 = icmp eq i32 %tmp10, 0 + br i1 %tmp11, label %bb12, label %bb16 + +bb12: ; preds = %bb1 + %tmp13 = tail call i32 (...) @foo() #0 + %tmp14 = icmp eq i32 %tmp13, 0 + %tmp15 = select i1 %tmp14, i32 0, i32 3 + br label %bb16 + +bb16: ; preds = %bb12, %bb1, %bb + %tmp17 = phi i32 [ 2, %bb1 ], [ %tmp15, %bb12 ], [ 0, %bb ] + ret i32 %tmp17 +} + +define i32 @bar_cold_outline_region(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb16, !prof !2 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @foo() #0 + %tmp3 = tail call i32 (...) @foo() #0 + %tmp4 = tail call i32 (...) @foo() #0 + %tmp5 = tail call i32 (...) @foo() #0 + %tmp6 = tail call i32 (...) @foo() #0 + %tmp7 = tail call i32 (...) @foo() #0 + %tmp8 = add nsw i32 %arg, 1 + %tmp9 = tail call i32 @goo(i32 %tmp8) #0 + %tmp10 = tail call i32 (...) @foo() #0 + %tmp11 = icmp eq i32 %tmp10, 0 + br i1 %tmp11, label %bb12, label %bb16 + +bb12: ; preds = %bb1 + %tmp13 = tail call i32 (...) @foo() #0 + %tmp14 = icmp eq i32 %tmp13, 0 + %tmp15 = select i1 %tmp14, i32 0, i32 3 + br label %bb16 + +bb16: ; preds = %bb12, %bb1, %bb + %tmp17 = phi i32 [ 2, %bb1 ], [ %tmp15, %bb12 ], [ 0, %bb ] + ret i32 %tmp17 +} + +; Function Attrs: nounwind +declare i32 @foo(...) local_unnamed_addr #0 + +; Function Attrs: nounwind +declare i32 @goo(i32) local_unnamed_addr #0 + +; Function Attrs: nounwind +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK-NOT: br i1 +; CHECK-NOT: call{{.*}}bar_hot_outline_region. +; NOCOST-LABEL: @dummy_caller +; NOCOST: br i1 +; NOCOST: call{{.*}}bar_hot_outline_region. + + %tmp = tail call i32 @bar_hot_outline_region(i32 %arg) + ret i32 %tmp +} + +define i32 @dummy_caller2(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller2 +; CHECK: br i1 +; CHECK: call{{.*}}bar_cold_outline_region. +; NOCOST-LABEL: @dummy_caller2 +; NOCOST: br i1 +; NOCOST: call{{.*}}bar_cold_outline_region. + + %tmp = tail call i32 @bar_cold_outline_region(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 5.0.0 (trunk 301898)"} +!1 = !{!"branch_weights", i32 2000, i32 1} +!2 = !{!"branch_weights", i32 1, i32 100} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll new file mode 100644 index 00000000000..2e0fbf6073e --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll @@ -0,0 +1,51 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s + +; Function Attrs: nounwind uwtable +define dso_local i8* @bar(i32 %arg) local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb1, label %bb5 + +bb1: ; preds = %bb + %call26 = invoke i8* @invoke_callee() #2 + to label %cont unwind label %lpad +lpad: ; preds = %if.end + %0 = landingpad { i8*, i32 } + cleanup + resume { i8*, i32 } undef + +cont: + br label %bb5 + +bb5: ; preds = %bb4, %bb1, %bb + %retval = phi i8* [ %call26, %cont ], [ undef, %bb] + ret i8* %retval +} + +; CHECK-LABEL: @dummy_caller +; CHECK-LABEL: bb: +; CHECK-NEXT: [[CALL26LOC:%.*]] = alloca i8* +; CHECK-LABEL: codeRepl.i: +; CHECK-NEXT: %lt.cast.i = bitcast i8** [[CALL26LOC]] to i8* +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %lt.cast.i) +; CHECK-NEXT: call void @bar.1.bb1(i8** [[CALL26LOC]]) +; CHECK-NEXT: %call26.reload.i = load i8*, i8** [[CALL26LOC]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %lt.cast.i) +define i8* @dummy_caller(i32 %arg) { +bb: + %tmp = tail call i8* @bar(i32 %arg) + ret i8* %tmp +} + +; CHECK-LABEL: define internal void @bar.1.bb1 +; CHECK-LABEL: bb1: +; CHECK-NEXT: %call26 = invoke i8* @invoke_callee() +; CHECK-NEXT: to label %cont unwind label %lpad +; CHECK-LABEL: cont: +; CHECK-NEXT: store i8* %call26, i8** %call26.out +; CHECK-NEXT: br label %bb5.exitStub + +; Function Attrs: nobuiltin +declare dso_local noalias nonnull i8* @invoke_callee() local_unnamed_addr #1 + +declare dso_local i32 @__gxx_personality_v0(...) diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineLiveAcross.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineLiveAcross.ll new file mode 100644 index 00000000000..1e1a1b062d4 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineLiveAcross.ll @@ -0,0 +1,61 @@ +; RUN: opt -S -partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +define i32 @test(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 (...) @bar() #1 + %tmp1 = icmp slt i32 %arg, 0 + br i1 %tmp1, label %bb6, label %bb2 + +bb2: ; preds = %bb + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + %tmp3 = tail call i32 (...) @bar() #1 + %tmp4 = icmp eq i32 %tmp3, 10 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb2 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + br label %bb6 + +bb6: ; preds = %bb5, %bb2, %bb + %tmp7 = phi i32 [ %tmp, %bb5 ], [ 0, %bb ], [ %tmp, %bb2 ] + ret i32 %tmp7 +} + +declare i32 @bar(...) local_unnamed_addr #1 + +declare void @foo(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL: @dummy_caller +; CHECK: codeRepl.i: +; CHECK: call void @test.1.bb2() +; CHECK-NOT: load +; CHECK br + +bb: + %tmp = tail call i32 @test(i32 %arg) + ret i32 %tmp +} + +; CHECK-LABEL: define internal void @test.1.bb2() +; CHECK: .exitStub: +; CHECK-NOT: store i32 %tmp7, i32* %tmp7.out +; CHECK: ret + + +attributes #0 = { nounwind uwtable } +attributes #1 = { nounwind uwtable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineNoInline.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineNoInline.ll new file mode 100644 index 00000000000..6c0b83298d2 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineNoInline.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -partial-inliner -S -stats -pass-remarks=partial-inlining 2>&1 | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S -stats -pass-remarks=partial-inlining 2>&1 | FileCheck %s + +@stat = external global i32, align 4 + +define i32 @inline_fail(i32 %count, ...) { +entry: + %vargs = alloca i8*, align 8 + %vargs1 = bitcast i8** %vargs to i8* + call void @llvm.va_start(i8* %vargs1) + %stat1 = load i32, i32* @stat, align 4 + %cmp = icmp slt i32 %stat1, 0 + br i1 %cmp, label %bb2, label %bb1 + +bb1: ; preds = %entry + %vg1 = add nsw i32 %stat1, 1 + store i32 %vg1, i32* @stat, align 4 + %va1 = va_arg i8** %vargs, i32 + call void @foo(i32 %count, i32 %va1) #2 + br label %bb2 + +bb2: ; preds = %bb1, %entry + %res = phi i32 [ 1, %bb1 ], [ 0, %entry ] + call void @llvm.va_end(i8* %vargs1) + ret i32 %res +} + +define i32 @caller(i32 %arg) { +bb: + %res = tail call i32 (i32, ...) @inline_fail(i32 %arg, i32 %arg) + ret i32 %res +} + +declare void @foo(i32, i32) +declare void @llvm.va_start(i8*) +declare void @llvm.va_end(i8*) + +; Check that no remarks have been emitted, inline_fail has not been partial +; inlined, no code has been extracted and the partial-inlining counter +; has not been incremented. + +; CHECK-NOT: remark +; CHECK: tail call i32 (i32, ...) @inline_fail(i32 %arg, i32 %arg) +; CHECK-NOT: inline_fail.1_bb1 +; CHECK-NOT: partial-inlining diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineNoLiveOut.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineNoLiveOut.ll new file mode 100644 index 00000000000..d41492f8ffd --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineNoLiveOut.ll @@ -0,0 +1,62 @@ +; RUN: opt -S -partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +define i32 @test(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = tail call i32 (...) @bar() #1 + %tmp1 = icmp slt i32 %arg, 0 + br i1 %tmp1, label %bb6, label %bb2 + +bb2: ; preds = %bb + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + %tmp3 = tail call i32 (...) @bar() #1 + %tmp4 = icmp eq i32 %tmp3, 10 + br i1 %tmp4, label %bb6, label %bb5 + +bb5: ; preds = %bb2 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + br label %bb6 + +bb6: ; preds = %bb5, %bb2, %bb + %tmp7 = phi i32 [ 1, %bb5 ], [ 0, %bb ], [ 1, %bb2 ] + ret i32 %tmp7 +} + +; Function Attrs: nounwind uwtable +declare i32 @bar(...) local_unnamed_addr #0 + +; Function Attrs: nounwind uwtable +declare void @foo(...) local_unnamed_addr #0 + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +; CHECK-LABEL: @dummy_caller +; CHECK: codeRepl.i: +; CHECK: call void @test.1.bb2() +; CHECK-NOT: load +; CHECK br +bb: + %tmp = tail call i32 @test(i32 %arg) + ret i32 %tmp +} + +; CHECK-LABEL: define internal void @test.1.bb2() +; CHECK: .exitStub: +; CHECK-NOT: store i32 %tmp7, i32* %tmp7.out +; CHECK: ret + +attributes #0 = { nounwind uwtable } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 303574)"} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineNotViable.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineNotViable.ll new file mode 100644 index 00000000000..010d677e5dc --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineNotViable.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; + +define i32 @callee_indr_branch(i32 %v) { +entry: + %cmp = icmp sgt i32 %v, 2000 + %addr = select i1 %cmp, i8* blockaddress(@callee_indr_branch, %if.then), i8* blockaddress(@callee_indr_branch, %if.end) + indirectbr i8* %addr, [ label %if.then, label %if.end] + +if.then: ; preds = %entry + %mul = mul nsw i32 %v, 10 + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10 + br label %if.end + +if.end: ; preds = %if.then, %entry + %v2 = phi i32 [ %v, %entry ], [ %mul, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + +declare void @use_fp(i8 *) +declare void @llvm.localescape(...) +declare i8* @llvm.frameaddress(i32) +declare i8* @llvm.localrecover(i8*, i8*, i32) + + + +define i32 @callee_frameescape(i32 %v) { +entry: + %a = alloca i32 + call void (...) @llvm.localescape(i32* %a) + %cmp = icmp sgt i32 %v, 2000 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %mul = mul nsw i32 %v, 10 + br label %if.then2 + +if.then2: + %sub = sub i32 %v, 10 + br label %if.end + +if.end: ; preds = %if.then, %entry + %v2 = phi i32 [ %v, %entry ], [ %mul, %if.then2 ] + %add = add nsw i32 %v2, 200 + ret i32 %add +} + + +; CHECK-LABEL: @caller +; CHECK: %r1 = call i32 @callee_indr_branch(i32 %v) +; CHECK-NEXT: %r2 = call i32 @callee_frameescape(i32 %v) +define i32 @caller(i32 %v) { +entry: + %r1 = call i32 @callee_indr_branch(i32 %v) + %r2 = call i32 @callee_frameescape(i32 %v) + %res = add i32 %r1, %r2 + ret i32 %res +} + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineORECrash.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineORECrash.ll new file mode 100644 index 00000000000..c7f14945cd3 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineORECrash.ll @@ -0,0 +1,170 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -inline-threshold=0 -disable-output + +target datalayout = "e-m:e-i64:64-n32:64" +target triple = "powerpc64le-unknown-linux-gnu" + +%0 = type { i32 (...)**, %1, %1, %3, %3, %3, i8, float, %4*, %5*, %5*, i32, i32, i32, i32, float, float, float, i8*, i32, float, float, float, i8, [7 x i8] } +%1 = type { %2, %3 } +%2 = type { [3 x %3] } +%3 = type { [4 x float] } +%4 = type <{ i8*, i16, i16, [4 x i8], i8*, i32, %3, %3, [4 x i8] }> +%5 = type { i32 (...)**, i32, i8* } +%6 = type <{ %7, [4 x i8], %19*, %20*, %30, %35, %3, float, i8, i8, i8, i8, %37, i32, [4 x i8] }> +%7 = type <{ %8, [7 x i8], void (%16*, float)*, void (%16*, float)*, i8*, %17 }> +%8 = type <{ i32 (...)**, %9, %11*, %12, %13*, %14*, %15*, i8 }> +%9 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %0**, i8, [7 x i8] }> +%11 = type { i32 (...)** } +%12 = type { float, i32, i32, float, i8, %15*, i8, i8, i8, float, i8, float, %13* } +%13 = type opaque +%14 = type { i32 (...)** } +%15 = type { i32 (...)** } +%16 = type <{ %8, [7 x i8], void (%16*, float)*, void (%16*, float)*, i8*, %17, [4 x i8] }> +%17 = type { %18 } +%18 = type { float, float, float, float, float, i32, float, float, float, float, float, i32, float, float, float, i32, i32 } +%19 = type { i32 (...)** } +%20 = type <{ i32 (...)**, %21, %25, %9, i8, [7 x i8] }> +%21 = type { %22 } +%22 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %24*, i8, [7 x i8] }> +%24 = type { i32, i32 } +%25 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %27**, i8, [7 x i8] }> +%27 = type { i32, [4 x i8], [4 x %29], i8*, i8*, i32, float, float, i32 } +%29 = type <{ %3, %3, %3, %3, %3, float, float, float, i32, i32, i32, i32, [4 x i8], i8*, float, i8, [3 x i8], float, float, i32, %3, %3, [4 x i8] }> +%30 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %32**, i8, [7 x i8] }> +%32 = type { i32 (...)**, i32, i32, i32, i8, %33*, %33*, float, float, %3, %3, %3 } +%33 = type <{ %0, %2, %3, %3, float, %3, %3, %3, %3, %3, %3, %3, float, float, i8, [3 x i8], float, float, float, float, float, float, %34*, %30, i32, i32, i32, [4 x i8] }> +%34 = type { i32 (...)** } +%35 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %33**, i8, [7 x i8] }> +%37 = type <{ i8, [3 x i8], i32, i32, [4 x i8], %39**, i8, [7 x i8] }> +%39 = type { i32 (...)** } +%40 = type <{ i32 (...)**, %9, %11*, %12, %13*, %14*, %15*, i8, [7 x i8] }> + +@gDisableDeactivation = external local_unnamed_addr global i8, align 1 +@0 = external dso_local unnamed_addr constant [29 x i8], align 1 +@1 = external dso_local unnamed_addr constant [14 x i8], align 1 +@2 = external dso_local unnamed_addr constant [22 x i8], align 1 +@gDeactivationTime = external local_unnamed_addr global float, align 4 + +declare void @_ZN15CProfileManager12Stop_ProfileEv() local_unnamed_addr + +declare void @_ZN15CProfileManager13Start_ProfileEPKc(i8*) local_unnamed_addr + +declare void @_ZN17btCollisionObject18setActivationStateEi(%0*, i32 signext) local_unnamed_addr + +declare hidden void @__clang_call_terminate(i8*) local_unnamed_addr + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: argmemonly nounwind +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #0 + +define void @_ZN23btDiscreteDynamicsWorld28internalSingleStepSimulationEf(%6*, float) unnamed_addr align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !prof !27 { + invoke void null(%6* nonnull %0, float %1) + to label %5 unwind label %3 + +; <label>:3: ; preds = %2 + %4 = landingpad { i8*, i32 } + cleanup + br label %16 + +; <label>:5: ; preds = %2 + %6 = invoke %15* null(%40* null) + to label %11 unwind label %13 + +; <label>:7: ; preds = %5 + invoke void null(%40* null) + to label %8 unwind label %13 + +; <label>:8: ; preds = %7 + invoke void null(%6* nonnull %0) + to label %9 unwind label %13 + +; <label>:9: ; preds = %8 + invoke void null(%6* nonnull %0, %17* nonnull dereferenceable(68) null) + to label %10 unwind label %13 + +; <label>:10: ; preds = %9 + invoke void null(%6* nonnull %0, float %1) + to label %11 unwind label %13 + +; <label>:11: + invoke void @_ZN23btDiscreteDynamicsWorld21updateActivationStateEf(%6* nonnull %0, float %1) + to label %12 unwind label %13 + +; <label>:12: + ret void + +; <label>:13: + %14 = landingpad { i8*, i32 } + cleanup + %15 = extractvalue { i8*, i32 } %14, 0 + br label %16 + + +; <label>:16: + call void @_ZN15CProfileManager12Stop_ProfileEv() + resume { i8*, i32 } zeroinitializer +} + +define void @_ZN23btDiscreteDynamicsWorld21updateActivationStateEf(%6* nocapture readonly, float) local_unnamed_addr align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !prof !27 { + %3 = icmp sgt i32 0, 0 + br i1 %3, label %4, label %5, !prof !29 + +; <label>:4: ; preds = %2 + br i1 false, label %5, label %6, !prof !30 + +; <label>:5: ; preds = %7, %4, %2 + ret void + +; <label>:6: ; preds = %4 + invoke void @_ZN17btCollisionObject18setActivationStateEi(%0* nonnull null, i32 signext 0) + to label %7 unwind label %8 + +; <label>:7: ; preds = %6 + invoke void @_ZN17btCollisionObject18setActivationStateEi(%0* nonnull null, i32 signext 1) + to label %5 unwind label %8 + +; <label>:8: ; preds = %7, %6 + %9 = landingpad { i8*, i32 } + cleanup + resume { i8*, i32 } %9 +} + +; Function Attrs: noreturn nounwind +declare void @llvm.trap() #1 + +attributes #0 = { argmemonly nounwind } +attributes #1 = { noreturn nounwind } + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"ProfileSummary", !1} +!1 = !{!2, !3, !4, !5, !6, !7, !8, !9} +!2 = !{!"ProfileFormat", !"InstrProf"} +!3 = !{!"TotalCount", i64 6540578580} +!4 = !{!"MaxCount", i64 629805108} +!5 = !{!"MaxInternalCount", i64 40670372} +!6 = !{!"MaxFunctionCount", i64 629805108} +!7 = !{!"NumCounts", i64 8554} +!8 = !{!"NumFunctions", i64 3836} +!9 = !{!"DetailedSummary", !10} +!10 = !{!11, !12, !13, !14, !15, !16, !16, !17, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26} +!11 = !{i32 10000, i64 629805108, i32 1} +!12 = !{i32 100000, i64 366853677, i32 2} +!13 = !{i32 200000, i64 196816893, i32 4} +!14 = !{i32 300000, i64 192575561, i32 7} +!15 = !{i32 400000, i64 130688163, i32 11} +!16 = !{i32 500000, i64 74857169, i32 19} +!17 = !{i32 600000, i64 48184151, i32 30} +!18 = !{i32 700000, i64 21298588, i32 49} +!19 = !{i32 800000, i64 10721033, i32 90} +!20 = !{i32 900000, i64 3301634, i32 202} +!21 = !{i32 950000, i64 1454952, i32 362} +!22 = !{i32 990000, i64 343872, i32 675} +!23 = !{i32 999000, i64 46009, i32 1112} +!24 = !{i32 999900, i64 6067, i32 1435} +!25 = !{i32 999990, i64 700, i32 1721} +!26 = !{i32 999999, i64 72, i32 1955} +!27 = !{!"function_entry_count", i64 700} +!28 = !{!"branch_weights", i32 701, i32 1} +!29 = !{!"branch_weights", i32 954001, i32 701} +!30 = !{!"branch_weights", i32 1, i32 954001} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll new file mode 100644 index 00000000000..5f2a0ff475d --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineOptRemark.ll @@ -0,0 +1,138 @@ +; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -disable-output < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -disable-output < %s 2>&1 | FileCheck %s +; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -disable-output -max-partial-inlining=1 < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -disable-output -max-partial-inlining=1 < %s 2>&1 | FileCheck %s + +; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -disable-partial-inlining < %s 2>&1 | FileCheck --check-prefix=LIMIT %s +; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining --disable-partial-inlining < %s 2>&1 | FileCheck --check-prefix=LIMIT %s +; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -max-partial-inlining=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s +; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -max-partial-inlining=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s +; RUN: opt -S -partial-inliner -pass-remarks=partial-inlining -inline-threshold=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s +; RUN: opt -S -passes=partial-inliner -pass-remarks=partial-inlining -inline-threshold=0 < %s 2>&1 | FileCheck --check-prefix=LIMIT %s + +define i32 @bar(i32 %arg) local_unnamed_addr #0 !dbg !5 { +bb: + %tmp = icmp slt i32 %arg, 0, !dbg !7 + br i1 %tmp, label %bb1, label %bb2, !dbg !8 + +bb1: ; preds = %bb + tail call void (...) @foo() #0, !dbg !9 + tail call void (...) @foo() #0, !dbg !10 + tail call void (...) @foo() #0, !dbg !11 + tail call void (...) @foo() #0, !dbg !12 + tail call void (...) @foo() #0, !dbg !13 + tail call void (...) @foo() #0, !dbg !14 + tail call void (...) @foo() #0, !dbg !15 + tail call void (...) @foo() #0, !dbg !16 + tail call void (...) @foo() #0, !dbg !17 + br label %bb2, !dbg !18 + +bb2: ; preds = %bb1, %bb + %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp3, !dbg !19 +} + +define i32 @bar_noinline(i32 %arg) local_unnamed_addr #1 !dbg !23 { +bb: + %tmp = icmp slt i32 %arg, 0, !dbg !24 + br i1 %tmp, label %bb1, label %bb2, !dbg !24 + +bb1: ; preds = %bb + tail call void (...) @foo() #0, !dbg !24 + tail call void (...) @foo() #0, !dbg !24 + tail call void (...) @foo() #0, !dbg !24 + br label %bb2, !dbg !24 + +bb2: ; preds = %bb1, %bb + %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp3, !dbg !24 +} + +define i32 @bar_alwaysinline(i32 %arg) local_unnamed_addr #2 !dbg !25 { +bb: + %tmp = icmp slt i32 %arg, 0, !dbg !26 + br i1 %tmp, label %bb1, label %bb2, !dbg !26 + +bb1: ; preds = %bb + tail call void (...) @foo() #0, !dbg !26 + tail call void (...) @foo() #0, !dbg !26 + tail call void (...) @foo() #0, !dbg !26 + br label %bb2, !dbg !26 + +bb2: ; preds = %bb1, %bb + %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp3, !dbg !26 +} + +define i32 @bar_cold(i32 %arg) local_unnamed_addr #3 !dbg !27 { +bb: + %tmp = icmp slt i32 %arg, 0, !dbg !28 + br i1 %tmp, label %bb1, label %bb2, !dbg !28 + +bb1: ; preds = %bb + tail call void (...) @foo() #0, !dbg !28 + tail call void (...) @foo() #0, !dbg !28 + tail call void (...) @foo() #0, !dbg !28 + br label %bb2, !dbg !28 + +bb2: ; preds = %bb1, %bb + %tmp3 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp3, !dbg !28 +} + +; Function Attrs: nounwind +declare void @foo(...) local_unnamed_addr #0 + +; Function Attrs: nounwind +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 !dbg !20 { +bb: +; CHECK:remark{{.*}}bar partially inlined into dummy_caller +; CHECK-NOT:remark{{.*}}bar_noinline partially inlined into dummy_caller +; CHECK-NOT:remark{{.*}}bar_alwaysinline partially inlined into dummy_caller +; CHECK-NOT:remark{{.*}}bar_cold partially inlined into dummy_caller +; LIMIT-NOT:remark{{.*}}bar partially inlined into dummy_caller + %tmp = tail call i32 @bar(i32 %arg), !dbg !21 + %tmp2 = tail call i32 @bar_noinline(i32 %arg), !dbg !21 + %tmp3 = tail call i32 @bar_alwaysinline(i32 %arg), !dbg !21 + %tmp4 = tail call i32 @bar_cold(i32 %arg), !dbg !21 + ret i32 %tmp, !dbg !22 +} + +attributes #0 = { nounwind } +attributes #1 = { noinline nounwind } +attributes #2 = { alwaysinline nounwind } +attributes #3 = { cold nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3} +!llvm.ident = !{!4} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, enums: !2) +!1 = !DIFile(filename: "t.c", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{!"clang "} +!5 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!6 = !DISubroutineType(types: !2) +!7 = !DILocation(line: 4, column: 14, scope: !5) +!8 = !DILocation(line: 4, column: 6, scope: !5) +!9 = !DILocation(line: 5, column: 5, scope: !5) +!10 = !DILocation(line: 6, column: 5, scope: !5) +!11 = !DILocation(line: 7, column: 5, scope: !5) +!12 = !DILocation(line: 8, column: 5, scope: !5) +!13 = !DILocation(line: 9, column: 5, scope: !5) +!14 = !DILocation(line: 10, column: 5, scope: !5) +!15 = !DILocation(line: 11, column: 5, scope: !5) +!16 = !DILocation(line: 12, column: 5, scope: !5) +!17 = !DILocation(line: 13, column: 5, scope: !5) +!18 = !DILocation(line: 14, column: 5, scope: !5) +!19 = !DILocation(line: 17, column: 1, scope: !5) +!20 = distinct !DISubprogram(name: "dummy_caller", scope: !1, file: !1, line: 19, type: !6, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!21 = !DILocation(line: 21, column: 11, scope: !20) +!22 = !DILocation(line: 21, column: 4, scope: !20) +!23 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!24 = !DILocation(line: 4, column: 6, scope: !23) +!25 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!26 = !DILocation(line: 4, column: 6, scope: !25) +!27 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!28 = !DILocation(line: 4, column: 6, scope: !27) diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineOr.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineOr.ll new file mode 100644 index 00000000000..cbf7a47de9b --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineOr.ll @@ -0,0 +1,97 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s +; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT %s + +; Function Attrs: nounwind uwtable +define i32 @bar(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb4, label %bb1 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @channels() #1 + %tmp3 = icmp slt i32 %tmp2, %arg + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb1, %bb + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + br label %bb5 + +bb5: ; preds = %bb4, %bb1 + %.0 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ] + ret i32 %.0 +} + +declare i32 @channels(...) local_unnamed_addr + +declare void @foo(...) local_unnamed_addr + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call void @bar.2. +; LIMIT-LABEL: @dummy_caller +; LIMIT-NOT: br +; LIMIT: call i32 @bar( + %tmp = tail call i32 @bar(i32 %arg) + ret i32 %tmp +} + +define i32 @bar_multi_ret(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb4, label %bb1 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @channels() #1 + %tmp3 = icmp slt i32 %tmp2, %arg + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb1, %bb + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + tail call void (...) @foo() #1 + %tmp4 = icmp slt i32 %arg, 10 + br i1 %tmp4, label %bb6, label %bb5 +bb6: + tail call void (...) @foo() #1 + %tmp5 = icmp slt i32 %arg, 3 + br i1 %tmp5, label %bb7, label %bb5 +bb7: + tail call void (...) @foo() #1 + br label %bb8 +bb8: + ret i32 0 + +bb5: ; preds = %bb4, %bb1 + %.0 = phi i32 [ 0, %bb4 ], [ 1, %bb1 ], [0, %bb6] + ret i32 %.0 +} + +define i32 @dummy_caller2(i32 %arg) local_unnamed_addr #0 { +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call {{.*}} @bar_multi_ret.1. + %tmp = tail call i32 @bar_multi_ret(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind uwtable } +attributes #1 = { nounwind } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 5.0.0 (trunk 300576)"} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll new file mode 100644 index 00000000000..09d0e2503ea --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll @@ -0,0 +1,71 @@ +; RUN: opt < %s -partial-inliner -S | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S | FileCheck %s +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=3 -skip-partial-inlining-cost-analysis -S | FileCheck --check-prefix=LIMIT3 %s +; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=3 -skip-partial-inlining-cost-analysis -S | FileCheck --check-prefix=LIMIT3 %s +; RUN: opt < %s -partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT2 %s +; RUN: opt < %s -passes=partial-inliner -max-num-inline-blocks=2 -S | FileCheck --check-prefix=LIMIT2 %s + + +; Function Attrs: nounwind uwtable +define i32 @bar(i32 %arg) local_unnamed_addr #0 { +bb: + %tmp = icmp slt i32 %arg, 0 + br i1 %tmp, label %bb4, label %bb1 + +bb1: ; preds = %bb + %tmp2 = tail call i32 (...) @n() #2 + %tmp3 = icmp slt i32 %tmp2, %arg + br i1 %tmp3, label %bb4, label %bb8 + +bb4: ; preds = %bb1, %bb + %tmp5 = tail call i32 (...) @m() #2 + %tmp6 = icmp sgt i32 %tmp5, %arg + br i1 %tmp6, label %bb7, label %bb8 + +bb7: ; preds = %bb4 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + tail call void (...) @foo() #2 + br label %bb8 + +bb8: ; preds = %bb7, %bb4, %bb1 + %tmp9 = phi i32 [ 0, %bb7 ], [ 1, %bb4 ], [ 1, %bb1 ] + ret i32 %tmp9 +} + +declare i32 @n(...) local_unnamed_addr #1 + +declare i32 @m(...) local_unnamed_addr #1 + +declare void @foo(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define i32 @dummy_caller(i32 %arg) local_unnamed_addr #0 { +bb: +; CHECK-LABEL: @dummy_caller +; CHECK: br i1 +; CHECK: br i1 +; CHECK: br i1 +; CHECK: call void @bar.1. +; LIMIT3-LABEL: @dummy_caller +; LIMIT3: br i1 +; LIMIT3: br i1 +; LIMIT3-NOT: br i1 +; LIMIT3: call void @bar.1. +; LIMIT2-LABEL: @dummy_caller +; LIMIT2-NOT: br i1 +; LIMIT2: call i32 @bar( + %tmp = tail call i32 @bar(i32 %arg) + ret i32 %tmp +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind } +attributes #2 = { nounwind } + diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll b/llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll new file mode 100644 index 00000000000..5d187abb68a --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlinePGOMultiRegion.ll @@ -0,0 +1,169 @@ +; RUN: opt -S -partial-inliner -min-block-execution=1 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -min-block-execution=1 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; Require a dummy block (if.then.b) as successor to if.then due to PI requirement +; of region containing more than one BB. +define signext i32 @bar(i32 signext %value, i32 signext %ub) #0 !prof !30 { +entry: + %value.addr = alloca i32, align 4 + %ub.addr = alloca i32, align 4 + %sum = alloca i32, align 4 + %i = alloca i32, align 4 + store i32 %value, i32* %value.addr, align 4 + store i32 %ub, i32* %ub.addr, align 4 + store i32 0, i32* %sum, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %1 = load i32, i32* %ub.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %for.body, label %for.cond2, !prof !31 + +for.body: ; preds = %for.cond + %2 = load i32, i32* %value.addr, align 4 + %rem = srem i32 %2, 20 + %cmp1 = icmp eq i32 %rem, 0 + br i1 %cmp1, label %if.then, label %if.else, !prof !32 + +if.then: ; preds = %for.body + %3 = load i32, i32* %value.addr, align 4 + %4 = load i32, i32* %i, align 4 + %mul = mul nsw i32 %4, 5 + %add = add nsw i32 %3, %mul + %5 = load i32, i32* %sum, align 4 + %add2 = add nsw i32 %5, %add + store i32 %add2, i32* %sum, align 4 + br label %if.then.b + +if.then.b: ; preds = %if.then + br label %if.end + +if.else: ; preds = %for.body + %6 = load i32, i32* %value.addr, align 4 + %7 = load i32, i32* %i, align 4 + %sub = sub nsw i32 %6, %7 + %8 = load i32, i32* %sum, align 4 + %add3 = add nsw i32 %8, %sub + store i32 %add3, i32* %sum, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + br label %for.inc + +for.inc: ; preds = %if.end + %9 = load i32, i32* %i, align 4 + %inc = add nsw i32 %9, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond + +for.cond2: ; preds = %for.cond + %10 = load i32, i32* %i, align 4 + %11 = load i32, i32* %ub.addr, align 4 + %cmp2 = icmp slt i32 %10, %11 + br i1 %cmp2, label %for.body2, label %for.end, !prof !31 + +for.body2: ; preds = %for.cond2 + %12 = load i32, i32* %value.addr, align 4 + %rem2 = srem i32 %12, 20 + %cmp3 = icmp eq i32 %rem2, 0 + br i1 %cmp3, label %if.then2, label %if.else2, !prof !32 + +if.then2: ; preds = %for.body2 + %13 = load i32, i32* %value.addr, align 4 + %14 = load i32, i32* %i, align 4 + %mul2 = mul nsw i32 %14, 5 + %add4 = add nsw i32 %13, %mul2 + %15 = load i32, i32* %sum, align 4 + %add5 = add nsw i32 %15, %add4 + store i32 %add5, i32* %sum, align 4 + br label %if.then2.b + +if.then2.b: ; preds = %if.then2 + br label %if.end2 + +if.else2: ; preds = %for.body2 + %16 = load i32, i32* %value.addr, align 4 + %17 = load i32, i32* %i, align 4 + %sub2 = sub nsw i32 %16, %17 + %18 = load i32, i32* %sum, align 4 + %add6 = add nsw i32 %18, %sub2 + store i32 %add6, i32* %sum, align 4 + br label %if.end2 + +if.end2: ; preds = %if.else2, %if.then2 + br label %for.inc2 + +for.inc2: ; preds = %if.end2 + %19 = load i32, i32* %i, align 4 + %inc2 = add nsw i32 %19, 1 + store i32 %inc2, i32* %i, align 4 + br label %for.cond2 + +for.end: ; preds = %for.cond2 + %20 = load i32, i32* %sum, align 4 + ret i32 %20 +} + +define signext i32 @foo(i32 signext %value, i32 signext %ub) #0 !prof !30 { +; CHECK-LABEL: @foo +; CHECK-NOT: call signext i32 @bar +; CHECK: codeRepl1.i: +; CHECK: call void @bar.1.if.then +; CHECK: codeRepl.i: +; CHECK: call void @bar.1.if.then2 +entry: + %value.addr = alloca i32, align 4 + %ub.addr = alloca i32, align 4 + store i32 %value, i32* %value.addr, align 4 + store i32 %ub, i32* %ub.addr, align 4 + %0 = load i32, i32* %value.addr, align 4 + %1 = load i32, i32* %ub.addr, align 4 + %call = call signext i32 @bar(i32 signext %0, i32 signext %1) + ret i32 %call +} + +; CHECK-LABEL: define internal void @bar.1.if.then2 +; CHECK: .exitStub: +; CHECK: ret void + +; CHECK-LABEL: define internal void @bar.1.if.then +; CHECK: .exitStub: +; CHECK: ret void + +!llvm.module.flags = !{!0, !1, !2} +!llvm.ident = !{!29} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{i32 1, !"ProfileSummary", !3} +!3 = !{!4, !5, !6, !7, !8, !9, !10, !11} +!4 = !{!"ProfileFormat", !"InstrProf"} +!5 = !{!"TotalCount", i64 103} +!6 = !{!"MaxCount", i64 100} +!7 = !{!"MaxInternalCount", i64 1} +!8 = !{!"MaxFunctionCount", i64 100} +!9 = !{!"NumCounts", i64 5} +!10 = !{!"NumFunctions", i64 3} +!11 = !{!"DetailedSummary", !12} +!12 = !{!13, !14, !15, !16, !17, !18, !18, !19, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28} +!13 = !{i32 10000, i64 100, i32 1} +!14 = !{i32 100000, i64 100, i32 1} +!15 = !{i32 200000, i64 100, i32 1} +!16 = !{i32 300000, i64 100, i32 1} +!17 = !{i32 400000, i64 100, i32 1} +!18 = !{i32 500000, i64 100, i32 1} +!19 = !{i32 600000, i64 100, i32 1} +!20 = !{i32 700000, i64 100, i32 1} +!21 = !{i32 800000, i64 100, i32 1} +!22 = !{i32 900000, i64 100, i32 1} +!23 = !{i32 950000, i64 100, i32 1} +!24 = !{i32 990000, i64 1, i32 4} +!25 = !{i32 999000, i64 1, i32 4} +!26 = !{i32 999900, i64 1, i32 4} +!27 = !{i32 999990, i64 1, i32 4} +!28 = !{i32 999999, i64 1, i32 4} +!29 = !{!"clang version 6.0.0 (123456)"} +!30 = !{!"function_entry_count", i64 2} +!31 = !{!"branch_weights", i32 100, i32 1} +!32 = !{!"branch_weights", i32 0, i32 100} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlinePGORegion.ll b/llvm/test/Transforms/CodeExtractor/PartialInlinePGORegion.ll new file mode 100644 index 00000000000..4aa70624315 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlinePGORegion.ll @@ -0,0 +1,120 @@ +; RUN: opt -S -partial-inliner -min-block-execution=1 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -min-block-execution=1 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; Require a dummy block (if.then.b) as successor to if.then due to PI requirement +; of region containing more than one BB. +define signext i32 @bar(i32 signext %value, i32 signext %ub) #0 !prof !30 { +entry: + %value.addr = alloca i32, align 4 + %ub.addr = alloca i32, align 4 + %sum = alloca i32, align 4 + %i = alloca i32, align 4 + store i32 %value, i32* %value.addr, align 4 + store i32 %ub, i32* %ub.addr, align 4 + store i32 0, i32* %sum, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %1 = load i32, i32* %ub.addr, align 4 + %cmp = icmp slt i32 %0, %1 + br i1 %cmp, label %for.body, label %for.end, !prof !31 + +for.body: ; preds = %for.cond + %2 = load i32, i32* %value.addr, align 4 + %rem = srem i32 %2, 20 + %cmp1 = icmp eq i32 %rem, 0 + br i1 %cmp1, label %if.then, label %if.else, !prof !32 + +if.then: ; preds = %for.body + %3 = load i32, i32* %value.addr, align 4 + %4 = load i32, i32* %i, align 4 + %mul = mul nsw i32 %4, 5 + %add = add nsw i32 %3, %mul + %5 = load i32, i32* %sum, align 4 + %add2 = add nsw i32 %5, %add + store i32 %add2, i32* %sum, align 4 + br label %if.then.b + +if.then.b: ; preds = %if.then + br label %if.end + +if.else: ; preds = %for.body + %6 = load i32, i32* %value.addr, align 4 + %7 = load i32, i32* %i, align 4 + %sub = sub nsw i32 %6, %7 + %8 = load i32, i32* %sum, align 4 + %add3 = add nsw i32 %8, %sub + store i32 %add3, i32* %sum, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + br label %for.inc + +for.inc: ; preds = %if.end + %9 = load i32, i32* %i, align 4 + %inc = add nsw i32 %9, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond + +for.end: ; preds = %for.cond + %10 = load i32, i32* %sum, align 4 + ret i32 %10 +} + +define signext i32 @foo(i32 signext %value, i32 signext %ub) #0 !prof !30 { +; CHECK-LABEL: @foo +; CHECK: codeRepl.i: +; CHECK-NOT: call signext i32 @bar +; CHECK: call void @bar.1.if.then +entry: + %value.addr = alloca i32, align 4 + %ub.addr = alloca i32, align 4 + store i32 %value, i32* %value.addr, align 4 + store i32 %ub, i32* %ub.addr, align 4 + %0 = load i32, i32* %value.addr, align 4 + %1 = load i32, i32* %ub.addr, align 4 + %call = call signext i32 @bar(i32 signext %0, i32 signext %1) + ret i32 %call +} + +; CHECK-LABEL: define internal void @bar.1.if.then +; CHECK: .exitStub: +; CHECK: ret void + +!llvm.module.flags = !{!0, !1, !2} +!llvm.ident = !{!29} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{i32 1, !"ProfileSummary", !3} +!3 = !{!4, !5, !6, !7, !8, !9, !10, !11} +!4 = !{!"ProfileFormat", !"InstrProf"} +!5 = !{!"TotalCount", i64 103} +!6 = !{!"MaxCount", i64 100} +!7 = !{!"MaxInternalCount", i64 1} +!8 = !{!"MaxFunctionCount", i64 100} +!9 = !{!"NumCounts", i64 5} +!10 = !{!"NumFunctions", i64 3} +!11 = !{!"DetailedSummary", !12} +!12 = !{!13, !14, !15, !16, !17, !18, !18, !19, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28} +!13 = !{i32 10000, i64 100, i32 1} +!14 = !{i32 100000, i64 100, i32 1} +!15 = !{i32 200000, i64 100, i32 1} +!16 = !{i32 300000, i64 100, i32 1} +!17 = !{i32 400000, i64 100, i32 1} +!18 = !{i32 500000, i64 100, i32 1} +!19 = !{i32 600000, i64 100, i32 1} +!20 = !{i32 700000, i64 100, i32 1} +!21 = !{i32 800000, i64 100, i32 1} +!22 = !{i32 900000, i64 100, i32 1} +!23 = !{i32 950000, i64 100, i32 1} +!24 = !{i32 990000, i64 1, i32 4} +!25 = !{i32 999000, i64 1, i32 4} +!26 = !{i32 999900, i64 1, i32 4} +!27 = !{i32 999990, i64 1, i32 4} +!28 = !{i32 999999, i64 1, i32 4} +!29 = !{!"clang version 6.0.0 (123456)"} +!30 = !{!"function_entry_count", i64 2} +!31 = !{!"branch_weights", i32 100, i32 1} +!32 = !{!"branch_weights", i32 0, i32 100} diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineVarArg.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArg.ll new file mode 100644 index 00000000000..8582f5e18f8 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArg.ll @@ -0,0 +1,107 @@ +; RUN: opt < %s -partial-inliner -S -skip-partial-inlining-cost-analysis | FileCheck %s +; RUN: opt < %s -passes=partial-inliner -S -skip-partial-inlining-cost-analysis | FileCheck %s + +@stat = external global i32, align 4 + +define i32 @vararg(i32 %count, ...) { +entry: + %vargs = alloca i8*, align 8 + %stat1 = load i32, i32* @stat, align 4 + %cmp = icmp slt i32 %stat1, 0 + br i1 %cmp, label %bb2, label %bb1 + +bb1: ; preds = %entry + %vg1 = add nsw i32 %stat1, 1 + store i32 %vg1, i32* @stat, align 4 + %vargs1 = bitcast i8** %vargs to i8* + call void @llvm.va_start(i8* %vargs1) + %va1 = va_arg i8** %vargs, i32 + call void @foo(i32 %count, i32 %va1) #2 + call void @llvm.va_end(i8* %vargs1) + br label %bb2 + +bb2: ; preds = %bb1, %entry + %res = phi i32 [ 1, %bb1 ], [ 0, %entry ] + ret i32 %res +} + +declare void @foo(i32, i32) +declare void @llvm.va_start(i8*) +declare void @llvm.va_end(i8*) + +define i32 @caller1(i32 %arg) { +bb: + %tmp = tail call i32 (i32, ...) @vararg(i32 %arg) + ret i32 %tmp +} +; CHECK-LABEL: @caller1 +; CHECK: codeRepl.i: +; CHECK-NEXT: call void (i32, i8**, i32, ...) @vararg.3.bb1(i32 %stat1.i, i8** %vargs.i, i32 %arg) + +define i32 @caller2(i32 %arg, float %arg2) { +bb: + %tmp = tail call i32 (i32, ...) @vararg(i32 %arg, i32 10, float %arg2) + ret i32 %tmp +} + +; CHECK-LABEL: @caller2 +; CHECK: codeRepl.i: +; CHECK-NEXT: call void (i32, i8**, i32, ...) @vararg.3.bb1(i32 %stat1.i, i8** %vargs.i, i32 %arg, i32 10, float %arg2) + +; Test case to check that we do not extract a vararg function, if va_end is in +; a block that is not outlined. +define i32 @vararg_not_legal(i32 %count, ...) { +entry: + %vargs = alloca i8*, align 8 + %vargs0 = bitcast i8** %vargs to i8* + %stat1 = load i32, i32* @stat, align 4 + %cmp = icmp slt i32 %stat1, 0 + br i1 %cmp, label %bb2, label %bb1 + +bb1: ; preds = %entry + %vg1 = add nsw i32 %stat1, 1 + store i32 %vg1, i32* @stat, align 4 + %vargs1 = bitcast i8** %vargs to i8* + call void @llvm.va_start(i8* %vargs1) + %va1 = va_arg i8** %vargs, i32 + call void @foo(i32 %count, i32 %va1) + br label %bb2 + +bb2: ; preds = %bb1, %entry + %res = phi i32 [ 1, %bb1 ], [ 0, %entry ] + %ptr = phi i8* [ %vargs1, %bb1 ], [ %vargs0, %entry] + call void @llvm.va_end(i8* %ptr) + ret i32 %res +} + +; CHECK-LABEL: @caller3 +; CHECK: tail call i32 (i32, ...) @vararg_not_legal(i32 %arg, i32 %arg) +define i32 @caller3(i32 %arg) { +bb: + %res = tail call i32 (i32, ...) @vararg_not_legal(i32 %arg, i32 %arg) + ret i32 %res +} + +declare i32* @err(i32*) + +define signext i32 @vararg2(i32 * %l, ...) { +entry: + br i1 undef, label %cleanup, label %cond.end + +cond.end: ; preds = %entry + %call51 = call i32* @err(i32* nonnull %l) + unreachable + +cleanup: ; preds = %entry + ret i32 0 +} + +define i32* @caller_with_signext(i32* %foo) { +entry: + %call1 = tail call signext i32 (i32*, ...) @vararg2(i32* %foo, i32 signext 8) + unreachable +} + +; CHECK-LABEL: @caller_with_signext +; CHECK: codeRepl.i: +; CHECK-NEXT: call void (i32*, ...) @vararg2.1.cond.end(i32* %foo, i32 signext 8) diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll new file mode 100644 index 00000000000..d19de842b61 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll @@ -0,0 +1,68 @@ +; RUN: opt < %s -S -partial-inliner -skip-partial-inlining-cost-analysis=true | FileCheck %s + +; CHECK-LABEL: @callee +; CHECK: %mul = mul nsw i32 %v, 10, !dbg ![[DBG1:[0-9]+]] +define i32 @callee(i32 %v, ...) !dbg !16 { +entry: + %cmp = icmp sgt i32 %v, 2000, !dbg !17 + br i1 %cmp, label %if.then, label %if.end, !dbg !19 + +if.then: ; preds = %entry + %mul = mul nsw i32 %v, 10, !dbg !20 + br label %if.end, !dbg !21 + +if.end: ; preds = %if.then, %entry + %v2 = phi i32 [ %v, %entry ], [ %mul, %if.then ] + %add = add nsw i32 %v2, 200, !dbg !22 + ret i32 %add, !dbg !23 +} + +; CHECK-LABEL: @caller +; CHECK: codeRepl.i: +; CHECK-NOT: br label +; CHECK: call void (i32, i32*, ...) @callee.1.if.then(i32 %v, i32* %mul.loc.i, i32 99), !dbg ![[DBG2:[0-9]+]] +define i32 @caller(i32 %v) !dbg !8 { +entry: + %call = call i32 (i32, ...) @callee(i32 %v, i32 99), !dbg !14 + ret i32 %call, !dbg !15 +} + +; CHECK-LABEL: define internal void @callee.1.if.then +; CHECK: br label %if.then, !dbg ![[DBG3:[0-9]+]] + +; CHECK: ![[DBG1]] = !DILocation(line: 10, column: 7, +; CHECK: ![[DBG2]] = !DILocation(line: 10, column: 7, +; CHECK: ![[DBG3]] = !DILocation(line: 10, column: 7, + + +!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 177881)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "test.c", directory: "/tmp") +!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 1, !"min_enum_size", i32 4} +!7 = !{!"clang version 6.0.0"} +!8 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 19, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "v", arg: 1, scope: !8, file: !1, line: 3, type: !11) +!14 = !DILocation(line: 5, column: 10, scope: !8) +!15 = !DILocation(line: 5, column: 3, scope: !8) +!16 = distinct !DISubprogram(name: "callee", scope: !1, file: !1, line: 8, type: !9, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !26) +!26 = !{!27} +!27 = !DILocalVariable(name: "v", arg: 1, scope: !16, file: !1, line: 8, type: !11) +!17 = !DILocation(line: 9, column: 9, scope: !18) +!18 = distinct !DILexicalBlock(scope: !16, file: !1, line: 9, column: 7) +!19 = !DILocation(line: 9, column: 7, scope: !16) +!20 = !DILocation(line: 10, column: 7, scope: !18) +!21 = !DILocation(line: 10, column: 5, scope: !18) +!22 = !DILocation(line: 11, column: 5, scope: !16) +!36 = !DILocation(line: 12, column: 10, scope: !16) +!23 = !DILocation(line: 12, column: 3, scope: !16) diff --git a/llvm/test/Transforms/CodeExtractor/SingleCondition.ll b/llvm/test/Transforms/CodeExtractor/SingleCondition.ll new file mode 100644 index 00000000000..334364484ee --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/SingleCondition.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -skip-partial-inlining-cost-analysis -partial-inliner -S | FileCheck %s +; RUN: opt < %s -skip-partial-inlining-cost-analysis -passes=partial-inliner -S | FileCheck %s + +define internal i32 @inlinedFunc(i1 %cond, i32* align 4 %align.val) { +entry: + br i1 %cond, label %if.then, label %return +if.then: + ; Dummy store to have more than 0 uses + store i32 10, i32* %align.val, align 4 + br label %return +return: ; preds = %entry + ret i32 0 +} + +define internal i32 @dummyCaller(i1 %cond, i32* align 2 %align.val) { +entry: +; CHECK-LABEL: @dummyCaller +; CHECK: br +; CHECK: call void @inlinedFunc.1. + %val = call i32 @inlinedFunc(i1 %cond, i32* %align.val) + ret i32 %val +} + diff --git a/llvm/test/Transforms/CodeExtractor/X86/InheritTargetAttributes.ll b/llvm/test/Transforms/CodeExtractor/X86/InheritTargetAttributes.ll new file mode 100644 index 00000000000..e6a5113261e --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/X86/InheritTargetAttributes.ll @@ -0,0 +1,40 @@ +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis | llc -filetype=null +; RUN: opt < %s -partial-inliner -skip-partial-inlining-cost-analysis -S | FileCheck %s +; This testcase checks to see if CodeExtractor properly inherits +; target specific attributes for the extracted function. This can +; cause certain instructions that depend on the attributes to not +; be lowered. Like in this test where we try to 'select' the blendvps +; intrinsic on x86 that requires the +sse4.1 target feature. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind readnone +declare <4 x float> @llvm.x86.sse41.blendvps(<4 x float>, <4 x float>, <4 x float>) #0 + +; Function Attrs: nounwind uwtable +define <4 x float> @inlinedFunc(i1, <4 x float>, <4 x float>, <4 x float>) #1 { +entry: + br i1 %0, label %if.then, label %return +if.then: +; Target intrinsic that requires sse4.1 + %target.call = call <4 x float> @llvm.x86.sse41.blendvps(<4 x float> %1, <4 x float> %2, <4 x float> %3) + br label %return +return: ; preds = %entry + %retval = phi <4 x float> [ zeroinitializer, %entry ], [ %target.call, %if.then ] + ret <4 x float> %retval +} + +; Function Attrs: nounwind uwtable +define <4 x float> @dummyCaller(i1, <4 x float>, <4 x float>, <4 x float>) #1 { +entry: + %val = call <4 x float> @inlinedFunc(i1 %0, <4 x float> %1, <4 x float> %2, <4 x float> %3) + ret <4 x float> %val +} + + +attributes #0 = { nounwind readnone } +attributes #1 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+sse4.1" } + +; CHECK: define {{.*}} @inlinedFunc.1.if.then{{.*}} [[COUNT1:#[0-9]+]] +; CHECK: [[COUNT1]] = { {{.*}} "target-cpu"="x86-64" "target-features"="+sse4.1" } diff --git a/llvm/test/Transforms/CodeExtractor/X86/lit.local.cfg b/llvm/test/Transforms/CodeExtractor/X86/lit.local.cfg new file mode 100644 index 00000000000..e71f3cc4c41 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/X86/lit.local.cfg @@ -0,0 +1,3 @@ +if not 'X86' in config.root.targets: + config.unsupported = True + diff --git a/llvm/test/Transforms/CodeExtractor/cost.ll b/llvm/test/Transforms/CodeExtractor/cost.ll new file mode 100644 index 00000000000..841b42b7c35 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/cost.ll @@ -0,0 +1,64 @@ +; RUN: opt -S < %s -partial-inliner -partial-inlining-extra-penalty=10 | FileCheck %s +; RUN: opt -S < %s -passes=partial-inliner -partial-inlining-extra-penalty=10 | FileCheck %s +define i32 @outline_region_notlikely(i32* %arg) local_unnamed_addr { +bb: +; ptr != null is predicted to be true + %tmp = icmp ne i32* %arg, null + br i1 %tmp, label %bb8, label %bb1 + +; bb1 is not likely +bb1: ; preds = %bb + %tmp2 = tail call i32 @foo(i32* nonnull %arg) + %tmp3 = tail call i32 @foo(i32* nonnull %arg) + %tmp4 = tail call i32 @foo(i32* nonnull %arg) + %tmp5 = tail call i32 @foo(i32* nonnull %arg) + %tmp6 = tail call i32 @foo(i32* nonnull %arg) + %tmp7 = tail call i32 @foo(i32* nonnull %arg) + br label %bb8 + +bb8: ; preds = %bb1, %bb + %tmp9 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp9 +} + +define i32 @outline_region_likely(i32* %arg) local_unnamed_addr { +bb: +; ptr == null is predicted to be false + %tmp = icmp eq i32* %arg, null + br i1 %tmp, label %bb8, label %bb1 + +; bb1 is likely +bb1: ; preds = %bb + %tmp2 = tail call i32 @foo(i32* nonnull %arg) + %tmp3 = tail call i32 @foo(i32* nonnull %arg) + %tmp4 = tail call i32 @foo(i32* nonnull %arg) + %tmp5 = tail call i32 @foo(i32* nonnull %arg) + %tmp6 = tail call i32 @foo(i32* nonnull %arg) + %tmp7 = tail call i32 @foo(i32* nonnull %arg) + br label %bb8 + +bb8: ; preds = %bb1, %bb + %tmp9 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp9 +} + +declare i32 @foo(i32* %arg) + +define i32 @dummy_caller(i32* %arg) local_unnamed_addr { +; CHECK-LABEL: @dummy_caller + %tmp = call i32 @outline_region_notlikely(i32* %arg) +; CHECK: call void @outline_region_notlikely.2.bb1 + %tmp2 = tail call i32 @outline_region_likely(i32* %arg) +; CHECK: %tmp2 = tail call i32 @outline_region_likely(i32* %arg) + ret i32 %tmp + +} + +; CHECK-LABEL: define internal void @outline_region_notlikely.2.bb1(i32* %arg) { +; CHECK-NEXT: newFuncRoot: + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} diff --git a/llvm/test/Transforms/CodeExtractor/cost_meta.ll b/llvm/test/Transforms/CodeExtractor/cost_meta.ll new file mode 100644 index 00000000000..ca1690a4c9f --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/cost_meta.ll @@ -0,0 +1,41 @@ +; RUN: opt -S < %s -partial-inliner -partial-inlining-extra-penalty=2000 | FileCheck %s +; RUN: opt -S < %s -passes=partial-inliner -partial-inlining-extra-penalty=2000 | FileCheck %s +define i32 @outline_region_notlikely(i32* %arg) local_unnamed_addr { +bb: +; ptr != null is predicted to be true + %tmp = icmp ne i32* %arg, null + br i1 %tmp, label %bb8, label %bb1, !prof !2 + +; bb1 is not likely +bb1: ; preds = %bb + %tmp2 = tail call i32 @foo(i32* nonnull %arg) + %tmp3 = tail call i32 @foo(i32* nonnull %arg) + %tmp4 = tail call i32 @foo(i32* nonnull %arg) + %tmp5 = tail call i32 @foo(i32* nonnull %arg) + %tmp6 = tail call i32 @foo(i32* nonnull %arg) + %tmp7 = tail call i32 @foo(i32* nonnull %arg) + br label %bb8 + +bb8: ; preds = %bb1, %bb + %tmp9 = phi i32 [ 0, %bb1 ], [ 1, %bb ] + ret i32 %tmp9 +} + +define i32 @dummy_caller(i32* %arg) local_unnamed_addr { +; CHECK-LABEL: @dummy_caller + %tmp = call i32 @outline_region_notlikely(i32* %arg) + ret i32 %tmp + } + + +; CHECK-LABEL: define internal void @outline_region_notlikely.1.bb1(i32* %arg) { +; CHECK-NEXT: newFuncRoot: + +declare i32 @foo(i32 * %arg) + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!"branch_weights", i32 2000, i32 1} diff --git a/llvm/test/Transforms/CodeExtractor/extract-assume.ll b/llvm/test/Transforms/CodeExtractor/extract-assume.ll new file mode 100644 index 00000000000..b79c6a69137 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/extract-assume.ll @@ -0,0 +1,29 @@ +; RUN: opt -passes="function(slp-vectorizer),module(hotcoldsplit),function(slp-vectorizer,print<assumptions>)" -disable-output %s 2>&1 | FileCheck %s +; +; Make sure this compiles. Check that function assumption cache is refreshed +; after extracting blocks with assume calls from the function. + +; CHECK: Cached assumptions for function: fun +; CHECK-NEXT: Cached assumptions for function: fun.cold +; CHECK-NEXT: %cmp = icmp uge i32 %x, 64 + +declare void @fun2(i32) #0 + +define void @fun(i32 %x) { +entry: + br i1 undef, label %if.then, label %if.else + +if.then: + ret void + +if.else: + %cmp = icmp uge i32 %x, 64 + call void @llvm.assume(i1 %cmp) + call void @fun2(i32 %x) + unreachable +} + +declare void @llvm.assume(i1) #1 + +attributes #0 = { alwaysinline } +attributes #1 = { nounwind } diff --git a/llvm/test/Transforms/CodeExtractor/inline_eh.ll b/llvm/test/Transforms/CodeExtractor/inline_eh.ll new file mode 100644 index 00000000000..a69e0c30bb9 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/inline_eh.ll @@ -0,0 +1,52 @@ +; RUN: opt < %s -skip-partial-inlining-cost-analysis -partial-inliner -S | FileCheck %s +; RUN: opt < %s -skip-partial-inlining-cost-analysis -passes=partial-inliner -S | FileCheck %s + +declare void @bar() +declare i32 @__gxx_personality_v0(...) +declare i8* @__cxa_begin_catch(i8*) +declare void @__cxa_end_catch() + +define internal void @callee(i1 %cond) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + br i1 %cond, label %if.then, label %if.end + +if.then: + invoke void @bar() + to label %invoke.cont unwind label %lpad + +invoke.cont: + br label %try.cont + +lpad: + %0 = landingpad { i8*, i32 } + catch i8* null + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = extractvalue { i8*, i32 } %0, 1 + br label %catch + +catch: + %3 = call i8* @__cxa_begin_catch(i8* %1) + call void @__cxa_end_catch() + br label %try.cont + +try.cont: + br label %if.end + +if.end: + ret void +} + +define internal void @caller(i1 %cond) { +; CHECK-LABEL: define {{.*}} @caller +entry: +; CHECK: entry: +; CHECK-NEXT: br i1 +; CHECK: codeRepl.i: +; CHECK-NEXT: call void @callee.1.{{.*}}() + call void @callee(i1 %cond) + ret void +} + +; CHECK-LABEL: define {{.*}} @callee.1.{{.*}}() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +; CHECK: invoke void @bar() +; CHECK: landingpad diff --git a/llvm/test/Transforms/CodeExtractor/inline_eh_1.ll b/llvm/test/Transforms/CodeExtractor/inline_eh_1.ll new file mode 100644 index 00000000000..b01abb6c1e8 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/inline_eh_1.ll @@ -0,0 +1,56 @@ +; RUN: opt < %s -skip-partial-inlining-cost-analysis -partial-inliner -S | FileCheck %s +; RUN: opt < %s -skip-partial-inlining-cost-analysis -passes=partial-inliner -S | FileCheck %s + +declare dso_local void @bar() +declare dso_local i32 @__CxxFrameHandler3(...) + +define internal void @callee(i1 %cond) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + br i1 %cond, label %if.then, label %if.end + +if.then: + invoke void @bar() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: + br label %try.cont + +ehcleanup: + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catch.dispatch + +catch.dispatch: + %1 = catchswitch within none [label %catch] unwind to caller + +catch: + %2 = catchpad within %1 [i8* null, i32 64, i8* null] + catchret from %2 to label %catchret.dest + +catchret.dest: + br label %try.cont + +try.cont: + br label %if.end + +if.end: + ret void +} + +define internal void @caller(i1 %cond) { +; CHECK-LABEL: define {{.*}} @caller +entry: +; CHECK: entry: +; CHECK-NEXT: br i1 +; CHECK: codeRepl.i: +; CHECK-NEXT: call void @callee.1.{{.*}}() + call void @callee(i1 %cond) + ret void +} + +; CHECK-LABEL: define {{.*}} @callee.1.{{.*}}() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) +; CHECK: invoke void @bar() +; CHECK: cleanuppad +; CHECK-NEXT: cleanupret +; CHECK: catchswitch +; CHECK: catchpad +; CHECK-NEXT: catchret diff --git a/llvm/test/Transforms/CodeExtractor/live_shrink.ll b/llvm/test/Transforms/CodeExtractor/live_shrink.ll new file mode 100644 index 00000000000..780ab480c4b --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/live_shrink.ll @@ -0,0 +1,67 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb5 + +bb5: ; preds = %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov() +bb: +; CHECK: bb: +; CHECK-NOT: alloca +; CHECK-NOT: bitcast +; CHECK-NOT: llvm.lifetime +; CHECK: br i1 +; CHECK: codeRepl.i: +; CHECK: call void @_Z3foov.1. + + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1. +; CHECK: newFuncRoot: +; CHECK-NEXT: %tmp = alloca %class.A +; CHECK-NEXT: %tmp1 = bitcast %class.A* %tmp to i8* +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK-NEXT: br label %bb5.exitStub + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/llvm/test/Transforms/CodeExtractor/live_shrink_gep.ll b/llvm/test/Transforms/CodeExtractor/live_shrink_gep.ll new file mode 100644 index 00000000000..aed86f84b66 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/live_shrink_gep.ll @@ -0,0 +1,66 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i8 } + +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 1 + %tmp1 = getelementptr inbounds %class.A, %class.A* %tmp, i64 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb5 + +bb5: ; preds = %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov() +bb: +; CHECK: bb: +; CHECK-NOT: alloca +; CHECK-NOT: getelementptr +; CHECK-NOT: llvm.lifetime +; CHECK: br i1 +; CHECK: codeRepl.i: +; CHECK: call void @_Z3foov.1. + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1. +; CHECK: newFuncRoot: +; CHECK-NEXT: %tmp = alloca %class.A +; CHECK-NEXT: %tmp1 = getelementptr +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: br label %bb5.exitStub + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/llvm/test/Transforms/CodeExtractor/live_shrink_hoist.ll b/llvm/test/Transforms/CodeExtractor/live_shrink_hoist.ll new file mode 100644 index 00000000000..13dab8d6b83 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/live_shrink_hoist.ll @@ -0,0 +1,70 @@ +; RUN: opt -S -partial-inliner -max-num-inline-blocks=3 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } + +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb9 + +bb4: ; preds = %bb + %foo = icmp eq i32 %tmp2, 0 + br i1 %foo, label %bb5, label %bb9 + +bb5: ; preds = %bb4 + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + %tmp5 = getelementptr inbounds %class.A, %class.A* %tmp, i64 0, i32 0 + %tmp6 = load i32, i32* %tmp5, align 4, !tbaa !6 + %tmp7 = icmp sgt i32 %tmp6, 0 + br i1 %tmp7, label %bb9, label %bb8 + +bb8: ; preds = %bb4 + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb9 + +bb9: ; preds = %bb8, %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +bb: + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1. +; CHECK: bb9: +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK: br label %.exitStub + + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} +!6 = !{!7, !3, i64 0} +!7 = !{!"_ZTS1A", !3, i64 0} diff --git a/llvm/test/Transforms/CodeExtractor/live_shrink_multiple.ll b/llvm/test/Transforms/CodeExtractor/live_shrink_multiple.ll new file mode 100644 index 00000000000..9350ca2ef9c --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/live_shrink_multiple.ll @@ -0,0 +1,66 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = alloca %class.A, align 4 + %tmp2 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp2) + %tmp3 = bitcast %class.A* %tmp1 to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp3) + %tmp4 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp5 = icmp eq i32 %tmp4, 0 + br i1 %tmp5, label %bb6, label %bb7 + +bb6: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb7 + +bb7: ; preds = %bb6, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp3) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp2) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +bb: + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1. +; CHECK: newFuncRoot: +; CHECK-NEXT: alloca +; CHECK-NEXT: bitcast +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK-NEXT: alloca +; CHECK-NEXT: bitcast +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: br label {{.*}}exitStub + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/llvm/test/Transforms/CodeExtractor/live_shrink_unsafe.ll b/llvm/test/Transforms/CodeExtractor/live_shrink_unsafe.ll new file mode 100644 index 00000000000..ea6458cc46e --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/live_shrink_unsafe.ll @@ -0,0 +1,94 @@ +; The expected behavior of this file is expected to change when partial +; inlining legality check is enhanced. + +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } + +@cond = local_unnamed_addr global i32 0, align 4 +@condptr = external local_unnamed_addr global i32*, align 8 + +; Function Attrs: uwtable +define void @_Z3foo_unknown_mem_accessv() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = alloca %class.A, align 4 + %tmp2 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp2) + %tmp3 = bitcast %class.A* %tmp1 to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp3) + %tmp4 = load i32*, i32** @condptr, align 8, !tbaa !2 + %tmp5 = load i32, i32* %tmp4, align 4, !tbaa !6 + %tmp6 = icmp eq i32 %tmp5, 0 + br i1 %tmp6, label %bb7, label %bb8 + +bb7: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb8 + +bb8: ; preds = %bb7, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp3) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp2) + ret void +} + +declare void @_Z3barv() local_unnamed_addr +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +define void @_Z3foo_unknown_calli(i32 %arg) local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + tail call void @_Z3barv() + %tmp2 = icmp eq i32 %arg, 0 + br i1 %tmp2, label %bb3, label %bb4 + +bb3: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb4 + +bb4: ; preds = %bb3, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov +; CHECK-NEXT: bb: +; CHECK: alloca +; CHECK: lifetime +bb: + call void @_Z3foo_unknown_mem_accessv() + %tmp = load i32, i32* @cond, align 4, !tbaa !2 + tail call void @_Z3foo_unknown_calli(i32 %tmp) + ret void +} + +; CHECK-LABEL define internal void @_Z3foo_unknown_calli.1_bb3 +; CHECK: newFuncRoot: +; CHECK-NEXT: br label %bb3 + +; CHECK: bb4.exitStub: +; CHECK-NEXT: ret void + +; CHECK: bb3: +; CHECK-NOT: lifetime.ed +; CHECK: br label %bb4.exitStub + + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"any pointer", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} +!6 = !{!7, !7, i64 0} +!7 = !{!"int", !4, i64 0} diff --git a/llvm/test/Transforms/CodeExtractor/unreachable-block.ll b/llvm/test/Transforms/CodeExtractor/unreachable-block.ll new file mode 100644 index 00000000000..7ce65f529a6 --- /dev/null +++ b/llvm/test/Transforms/CodeExtractor/unreachable-block.ll @@ -0,0 +1,36 @@ +; RUN: opt -S -partial-inliner %s | FileCheck %s + +; CHECK-LABEL: define void @dipsy( +; CHECK-NEXT: call void @tinkywinky.1.ontrue() +; CHECK-NEXT: call void @patatuccio() +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; CHECK-LABEL: define internal void @tinkywinky.1.ontrue() { +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label %ontrue +; CHECK: onfalse{{.*}}: +; CHECK-NEXT: ret void +; CHECK: ontrue: +; CHECK-NEXT: call void @patatino() +; CHECK-NEXT: br label %onfalse{{.*}} +; CHECK-NEXT: } + +declare void @patatino() +declare void @patatuccio() + +define fastcc void @tinkywinky() { + br i1 true, label %ontrue, label %onfalse +ontrue: + call void @patatino() + br label %onfalse +onfalse: + call void @patatuccio() + ret void +cantreachme: + ret void +} +define void @dipsy() { + call fastcc void @tinkywinky() + ret void +} |