Skip to content

Commit 2e43acf

Browse files
committed
[coroutine] should disable inline before calling coro split
summary: When callee coroutine function is inlined into caller coroutine function before coro-split pass, llvm will emits "coroutine should have exactly one defining @llvm.coro.begin". It seems that coro-early pass can not handle this quiet well. So we believe that unsplited coroutine function should not be inlined. This patch fix such issue by not inlining function if it has attribute "coroutine.presplit" (it means the function has not been splited) to fix this issue TestPlan: check-llvm Reviewed By: wenlei Differential Revision: https://reviews.llvm.org/D85812
1 parent 517caca commit 2e43acf

File tree

6 files changed

+86
-14
lines changed

6 files changed

+86
-14
lines changed

llvm/include/llvm/Transforms/Coroutines.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313

1414
namespace llvm {
1515

16+
// CoroEarly pass marks every function that has coro.begin with a string
17+
// attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine
18+
// twice. First, it lets it go through complete IPO optimization pipeline as a
19+
// single function. It forces restart of the pipeline by inserting an indirect
20+
// call to an empty function "coro.devirt.trigger" which is devirtualized by
21+
// CoroElide pass that triggers a restart of the pipeline by CGPassManager.
22+
// When CoroSplit pass sees the same coroutine the second time, it splits it up,
23+
// adds coroutine subfunctions to the SCC to be processed by IPO pipeline.
24+
#define CORO_PRESPLIT_ATTR "coroutine.presplit"
25+
#define UNPREPARED_FOR_SPLIT "0"
26+
#define PREPARED_FOR_SPLIT "1"
27+
1628
class Pass;
1729
class PassManagerBuilder;
1830

llvm/lib/Transforms/Coroutines/CoroInternal.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,6 @@ void initializeCoroSplitLegacyPass(PassRegistry &);
2626
void initializeCoroElideLegacyPass(PassRegistry &);
2727
void initializeCoroCleanupLegacyPass(PassRegistry &);
2828

29-
// CoroEarly pass marks every function that has coro.begin with a string
30-
// attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine
31-
// twice. First, it lets it go through complete IPO optimization pipeline as a
32-
// single function. It forces restart of the pipeline by inserting an indirect
33-
// call to an empty function "coro.devirt.trigger" which is devirtualized by
34-
// CoroElide pass that triggers a restart of the pipeline by CGPassManager.
35-
// When CoroSplit pass sees the same coroutine the second time, it splits it up,
36-
// adds coroutine subfunctions to the SCC to be processed by IPO pipeline.
37-
38-
#define CORO_PRESPLIT_ATTR "coroutine.presplit"
39-
#define UNPREPARED_FOR_SPLIT "0"
40-
#define PREPARED_FOR_SPLIT "1"
41-
4229
#define CORO_DEVIRT_TRIGGER_FN "coro.devirt.trigger"
4330

4431
namespace coro {

llvm/lib/Transforms/IPO/AlwaysInliner.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/IR/Module.h"
2323
#include "llvm/IR/Type.h"
2424
#include "llvm/InitializePasses.h"
25+
#include "llvm/Transforms/Coroutines.h"
2526
#include "llvm/Transforms/IPO.h"
2627
#include "llvm/Transforms/IPO/Inliner.h"
2728
#include "llvm/Transforms/Utils/Cloning.h"
@@ -44,7 +45,14 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
4445
SmallSetVector<CallBase *, 16> Calls;
4546
bool Changed = false;
4647
SmallVector<Function *, 16> InlinedFunctions;
47-
for (Function &F : M)
48+
for (Function &F : M) {
49+
// When callee coroutine function is inlined into caller coroutine function
50+
// before coro-split pass,
51+
// coro-early pass can not handle this quiet well.
52+
// So we won't inline the coroutine function if it have not been unsplited
53+
if (F.hasFnAttribute(CORO_PRESPLIT_ATTR))
54+
continue;
55+
4856
if (!F.isDeclaration() && F.hasFnAttribute(Attribute::AlwaysInline) &&
4957
isInlineViable(F).isSuccess()) {
5058
Calls.clear();
@@ -66,6 +74,7 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
6674
// invalidation issues while deleting functions.
6775
InlinedFunctions.push_back(&F);
6876
}
77+
}
6978

7079
// Remove any live functions.
7180
erase_if(InlinedFunctions, [&](Function *F) {
@@ -158,6 +167,13 @@ InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallBase &CB) {
158167
if (!Callee)
159168
return InlineCost::getNever("indirect call");
160169

170+
// When callee coroutine function is inlined into caller coroutine function
171+
// before coro-split pass,
172+
// coro-early pass can not handle this quiet well.
173+
// So we won't inline the coroutine function if it have not been unsplited
174+
if (Callee->hasFnAttribute(CORO_PRESPLIT_ATTR))
175+
return InlineCost::getNever("unsplited coroutine call");
176+
161177
// FIXME: We shouldn't even get here for declarations.
162178
if (Callee->isDeclaration())
163179
return InlineCost::getNever("no definition");

llvm/lib/Transforms/IPO/SampleProfile.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
#include "llvm/Support/ErrorOr.h"
7676
#include "llvm/Support/GenericDomTree.h"
7777
#include "llvm/Support/raw_ostream.h"
78+
#include "llvm/Transforms/Coroutines.h"
7879
#include "llvm/Transforms/IPO.h"
7980
#include "llvm/Transforms/Instrumentation.h"
8081
#include "llvm/Transforms/Utils/CallPromotionUtils.h"
@@ -920,6 +921,14 @@ bool SampleProfileLoader::inlineCallInstruction(CallBase &CB) {
920921

921922
Function *CalledFunction = CB.getCalledFunction();
922923
assert(CalledFunction);
924+
925+
// When callee coroutine function is inlined into caller coroutine function
926+
// before coro-split pass,
927+
// coro-early pass can not handle this quiet well.
928+
// So we won't inline the coroutine function if it have not been unsplited
929+
if (CalledFunction->hasFnAttribute(CORO_PRESPLIT_ATTR))
930+
return false;
931+
923932
DebugLoc DLoc = CB.getDebugLoc();
924933
BasicBlock *BB = CB.getParent();
925934
InlineParams Params = getInlineParams();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ff:152730084:141806
2+
1: 123
3+
4+
foo:152730084:141806
5+
65492: ff:302659
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; RUN: opt < %s -always-inline -barrier -coro-early -barrier -coro-split -S | FileCheck %s
2+
; RUN: opt < %s -enable-new-pm -always-inline -coro-early -coro-split -S | FileCheck %s
3+
; RUN: opt < %s -sample-profile-file=%S/Inputs/sample.text.prof -pgo-kind=pgo-sample-use-pipeline -coro-early -barrier -sample-profile -barrier -coro-split -disable-inlining=true -S | FileCheck %s
4+
; RUN: opt < %s -enable-new-pm -sample-profile-file=%S/Inputs/sample.text.prof -pgo-kind=pgo-sample-use-pipeline -coro-early -sample-profile -coro-split -disable-inlining=true -S | FileCheck %s
5+
6+
; Function Attrs: alwaysinline ssp uwtable
7+
define void @ff() #0 !dbg !12 {
8+
entry:
9+
%id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
10+
%begin = call i8* @llvm.coro.begin(token %id, i8* null)
11+
ret void
12+
}
13+
14+
; CHECK: call void @ff()
15+
; Function Attrs: alwaysinline ssp uwtable
16+
define void @foo() #0 !dbg !8 {
17+
entry:
18+
%id1 = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
19+
%begin = call i8* @llvm.coro.begin(token %id1, i8* null)
20+
call void @ff(), !dbg !11
21+
ret void
22+
}
23+
24+
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*)
25+
declare i8* @llvm.coro.begin(token, i8* writeonly)
26+
27+
attributes #0 = { alwaysinline ssp uwtable "coroutine.presplit"="1" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-sample-profile" "use-soft-float"="false" }
28+
29+
!llvm.dbg.cu = !{!0}
30+
!llvm.module.flags = !{!3, !4, !5, !6}
31+
32+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
33+
!1 = !DIFile(filename: "inline_O2.cpp", directory: "")
34+
!2 = !{}
35+
!3 = !{i32 7, !"Dwarf Version", i32 4}
36+
!4 = !{i32 2, !"Debug Info Version", i32 3}
37+
!5 = !{i32 1, !"wchar_size", i32 4}
38+
!6 = !{i32 7, !"PIC Level", i32 2}
39+
!8 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !1, file: !1, line: 46, type: !9, scopeLine: 46, flags: DIFlagPrototyped, unit: !0, retainedNodes: !2)
40+
!9 = !DISubroutineType(types: !10)
41+
!10 = !{null}
42+
!11 = !DILocation(line: 2, column: 0, scope: !8)
43+
!12 = distinct !DISubprogram(name: "ff", linkageName: "ff", scope: !1, file: !1, line: 46, type: !9, scopeLine: 46, flags: DIFlagPrototyped, unit: !0, retainedNodes: !2)

0 commit comments

Comments
 (0)