Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.
/ swift-llvm Public archive

[do not merge] Support for hot/cold splitting in swift #127

Open
wants to merge 3 commits into
base: swift-5.0-branch
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
521 changes: 324 additions & 197 deletions lib/Transforms/IPO/HotColdSplitting.cpp

Large diffs are not rendered by default.

21 changes: 18 additions & 3 deletions lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,11 +895,19 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer,
const DataLayout &DL = M->getDataLayout();

// Add inputs as params, or to be filled into the struct
for (Value *input : inputs)
unsigned ArgNo = 0;
SmallVector<unsigned, 1> SwiftErrorArgs;
for (Value *input : inputs) {
if (AggregateArgs)
StructValues.push_back(input);
else
else {
params.push_back(input);
if (auto *Alloca = dyn_cast<AllocaInst>(input))
if (Alloca->isSwiftError())
SwiftErrorArgs.push_back(ArgNo);
}
++ArgNo;
}

// Create allocas for the outputs
for (Value *output : outputs) {
Expand Down Expand Up @@ -955,6 +963,12 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer,
}
codeReplacer->getInstList().push_back(call);

// Set swifterror parameter attributes.
for (unsigned SwiftErrArgNo : SwiftErrorArgs) {
call->addParamAttr(SwiftErrArgNo, Attribute::SwiftError);
newFunction->addParamAttr(SwiftErrArgNo, Attribute::SwiftError);
}

Function::arg_iterator OutputArgBegin = newFunction->arg_begin();
unsigned FirstOut = inputs.size();
if (!AggregateArgs)
Expand Down Expand Up @@ -1370,7 +1384,8 @@ Function *CodeExtractor::extractCodeRegion() {

// Mark the new function `noreturn` if applicable.
bool doesNotReturn = none_of(*newFunction, [](const BasicBlock &BB) {
return isa<ReturnInst>(BB.getTerminator());
auto *Term = BB.getTerminator();
return isa<ReturnInst>(Term) || isa<CatchReturnInst>(Term) || isa<ResumeInst>(Term);
});
if (doesNotReturn)
newFunction->setDoesNotReturn();
Expand Down
65 changes: 65 additions & 0 deletions test/Transforms/HotColdSplit/eh-pads.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
; RUN: opt -S -hotcoldsplit < %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

; CHECK-LABEL: define {{.*}}@foo(
; CHECK: landingpad
; CHECK: sideeffect(i32 2)
define void @foo(i32 %cond) personality i8 0 {
entry:
invoke void @llvm.donothing() to label %normal unwind label %exception

exception:
; Note: EH pads are not candidates for region entry points.
%cleanup = landingpad i8 cleanup
br label %continue_exception

continue_exception:
call void @sideeffect(i32 0)
call void @sideeffect(i32 1)
call void @sink()
ret void

normal:
call void @sideeffect(i32 2)
ret void
}

; CHECK-LABEL: define {{.*}}@bar(
; CHECK-NOT: landingpad
define void @bar(i32 %cond) personality i8 0 {
entry:
br i1 undef, label %exit, label %continue

exit:
ret void

continue:
invoke void @sink() to label %normal unwind label %exception

exception:
; Note: EH pads are not candidates for region entry points.
%cleanup = landingpad i8 cleanup
ret void

normal:
call void @sideeffect(i32 0)
call void @sideeffect(i32 1)
ret void
}

; CHECK-LABEL: define {{.*}}@foo.cold.1(
; CHECK: sideeffect(i32 0)
; CHECK: sideeffect(i32 1)
; CHECK: sink

; CHECK-LABEL: define {{.*}}@bar.cold.1(
; CHECK: sideeffect(i32 0)
; CHECK: sideeffect(i32 1)

declare void @sideeffect(i32)

declare void @sink() cold

declare void @llvm.donothing() nounwind readnone
63 changes: 63 additions & 0 deletions test/Transforms/HotColdSplit/extraction-subregion-breaks-phis.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
; RUN: opt -S -hotcoldsplit < %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

; CHECK-LABEL: define {{.*}}@foo(
; CHECK: call {{.*}}@foo.cold.1(
; CHECK: unreachable

; CHECK-LABEL: define {{.*}}@foo.cold.1(
; CHECK: switch i32 undef, label %sw.epilog.i
define void @foo(i32 %QMM) {
entry:
switch i32 %QMM, label %entry.if.end16_crit_edge [
i32 1, label %if.then
]

entry.if.end16_crit_edge: ; preds = %entry
br label %if.end16

if.then: ; preds = %entry
br i1 undef, label %cond.true.i.i, label %_ZN10StringView8popFrontEv.exit.i

cond.true.i.i: ; preds = %if.then
ret void

_ZN10StringView8popFrontEv.exit.i: ; preds = %if.then
switch i32 undef, label %sw.epilog.i [
i32 81, label %if.end16
i32 82, label %sw.bb4.i
i32 83, label %sw.bb8.i
i32 84, label %sw.bb12.i
i32 65, label %if.end16
i32 66, label %sw.bb20.i
i32 67, label %sw.bb24.i
i32 68, label %sw.bb28.i
]

sw.bb4.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.bb8.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.bb12.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.bb20.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.bb24.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.bb28.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

sw.epilog.i: ; preds = %_ZN10StringView8popFrontEv.exit.i
br label %if.end16

if.end16: ; preds = %sw.epilog.i, %sw.bb28.i, %sw.bb24.i, %sw.bb20.i, %sw.bb12.i, %sw.bb8.i, %sw.bb4.i, %_ZN10StringView8popFrontEv.exit.i, %_ZN10StringView8popFrontEv.exit.i, %entry.if.end16_crit_edge
%0 = phi i8 [ 0, %entry.if.end16_crit_edge ], [ 0, %_ZN10StringView8popFrontEv.exit.i ], [ 0, %_ZN10StringView8popFrontEv.exit.i ], [ 1, %sw.bb4.i ], [ 2, %sw.bb8.i ], [ 3, %sw.bb12.i ], [ 1, %sw.bb20.i ], [ 2, %sw.bb24.i ], [ 3, %sw.bb28.i ], [ 0, %sw.epilog.i ]
unreachable
}
29 changes: 29 additions & 0 deletions test/Transforms/HotColdSplit/forward-dfs-reaches-marked-block.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; RUN: opt -hotcoldsplit -S < %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

; CHECK-LABEL: define {{.*}}@fun
; CHECK: call {{.*}}@fun.cold.1(
define void @fun() {
entry:
br i1 undef, label %if.then, label %if.else

if.then:
; This will be marked by the inverse DFS on sink-predecesors.
br label %sink

sink:
call void @sink()

; Do not allow the forward-DFS on sink-successors to mark the block again.
br i1 undef, label %if.then, label %if.then.exit

if.then.exit:
ret void

if.else:
ret void
}

declare void @sink() cold
64 changes: 64 additions & 0 deletions test/Transforms/HotColdSplit/mark-the-whole-func-cold.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
; RUN: opt -S -hotcoldsplit < %s | FileCheck %s

; Source:
;
; extern __attribute__((cold)) void sink();
; extern void sideeffect(int);
; void foo(int cond1, int cond2) {
; if (cond1) {
; if (cond2) {
; sideeffect(0);
; } else {
; sideeffect(1);
; }
; sink();
; } else {
; sideeffect(2);
; }
; sink();
; }

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

; CHECK: define {{.*}}@_Z3fooii{{.*}}#[[outlined_func_attr:[0-9]+]]
; CHECK-NOT: _Z3fooii.cold
; CHECK: attributes #[[outlined_func_attr]] = { {{.*}}minsize
define void @_Z3fooii(i32, i32) {
%3 = alloca i32, align 4
%4 = alloca i32, align 4
store i32 %0, i32* %3, align 4
store i32 %1, i32* %4, align 4
%5 = load i32, i32* %3, align 4
%6 = icmp ne i32 %5, 0
br i1 %6, label %7, label %13

; <label>:7: ; preds = %2
%8 = load i32, i32* %4, align 4
%9 = icmp ne i32 %8, 0
br i1 %9, label %10, label %11

; <label>:10: ; preds = %7
call void @_Z10sideeffecti(i32 0)
br label %12

; <label>:11: ; preds = %7
call void @_Z10sideeffecti(i32 1)
br label %12

; <label>:12: ; preds = %11, %10
call void @_Z4sinkv() #3
br label %14

; <label>:13: ; preds = %2
call void @_Z10sideeffecti(i32 2)
br label %14

; <label>:14: ; preds = %13, %12
call void @_Z4sinkv() #3
ret void
}

declare void @_Z10sideeffecti(i32)

declare void @_Z4sinkv() cold
73 changes: 73 additions & 0 deletions test/Transforms/HotColdSplit/noreturn.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
; RUN: opt -hotcoldsplit -S < %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t }
%struct.__sigset_t = type { [16 x i64] }

; Don't outline noreturn calls which aren't explicitly marked cold.

; CHECK-LABEL: define {{.*}}@foo(
; CHECK-NOT: foo.cold.1
define void @foo(i32, %struct.__jmp_buf_tag*) {
%3 = icmp eq i32 %0, 0
tail call void @_Z10sideeffectv()
br i1 %3, label %5, label %4

; <label>:4: ; preds = %2
tail call void @longjmp(%struct.__jmp_buf_tag* %1, i32 0)
unreachable

; <label>:5: ; preds = %2
ret void
}

; Do outline noreturn calls marked cold.

; CHECK-LABEL: define {{.*}}@bar(
; CHECK: call {{.*}}@bar.cold.1(
define void @bar(i32) {
%2 = icmp eq i32 %0, 0
tail call void @_Z10sideeffectv()
br i1 %2, label %sink, label %exit

sink:
tail call void @_Z10sideeffectv()
tail call void @_Z10sideeffectv()
tail call void @_Z10sideeffectv()
call void @llvm.trap()
unreachable

exit:
ret void
}

; Do outline noreturn calls preceded by a cold call.

; CHECK-LABEL: define {{.*}}@baz(
; CHECK: call {{.*}}@baz.cold.1(
define void @baz(i32, %struct.__jmp_buf_tag*) {
%3 = icmp eq i32 %0, 0
tail call void @_Z10sideeffectv()
br i1 %3, label %5, label %4

; <label>:4: ; preds = %2
call void @sink()
tail call void @longjmp(%struct.__jmp_buf_tag* %1, i32 0)
unreachable

; <label>:5: ; preds = %2
ret void
}

; CHECK-LABEL: define {{.*}}@bar.cold.1(
; CHECK: call {{.*}}@llvm.trap(

declare void @sink() cold

declare void @llvm.trap() noreturn cold

declare void @_Z10sideeffectv()

declare void @longjmp(%struct.__jmp_buf_tag*, i32) noreturn nounwind
27 changes: 27 additions & 0 deletions test/Transforms/HotColdSplit/outline-cold-asm.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; RUN: opt -hotcoldsplit -S < %s | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"

; CHECK-LABEL: define {{.*}}@fun(
; CHECK: call {{.*}}@fun.cold.1(

; CHECK-LABEL: define {{.*}}@fun.cold.1(
; CHECK: asm ""

define void @fun() {
entry:
br i1 undef, label %if.then, label %if.else

if.then:
ret void

if.else:
call void asm "", ""()
call void @sink()
call void @sink()
call void @sink()
ret void
}

declare void @sink() cold
Loading