Skip to content

Commit bf33e5b

Browse files
committed
coros: suspend metadata preservation
1 parent 9f733f4 commit bf33e5b

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ using namespace llvm;
7979

8080
#define DEBUG_TYPE "coro-split"
8181

82+
/// If set, ensures that all metadata from CoroSuspendInst's is preserved in the
83+
/// containing function.
84+
static cl::opt<bool> CoroSplitPreservesSuspendMD(
85+
"coro-split-preserves-suspend-md", cl::Hidden,
86+
cl::desc(
87+
"llvm.coro.suspend_md metadata from all suspend point instructions "
88+
"will be preserved inside llvm.coro.suspend_md_table metadata on the "
89+
"containing coroutine"));
90+
91+
static StringRef CoroSuspendMDName = "llvm.coro.suspend_md";
92+
static StringRef CoroSuspendMDTableName = "llvm.coro.suspend_md_table";
93+
8294
// FIXME:
8395
// Lower the intrinisc in CoroEarly phase if coroutine frame doesn't escape
8496
// and it is known that other transformations, for example, sanitizers
@@ -1503,10 +1515,18 @@ struct SwitchCoroutineSplitter {
15031515
Shape.SwitchLowering.ResumeSwitch = Switch;
15041516

15051517
// Split all coro.suspend calls
1518+
SmallVector<Metadata *> SuspendMdEntries;
15061519
size_t SuspendIndex = 0;
15071520
for (auto *AnyS : Shape.CoroSuspends) {
15081521
auto *S = cast<CoroSuspendInst>(AnyS);
15091522
ConstantInt *IndexVal = Shape.getIndex(SuspendIndex);
1523+
if (CoroSplitPreservesSuspendMD) {
1524+
MDNode *SuspendMD = S->getMetadata(CoroSuspendMDName);
1525+
if (SuspendMD) {
1526+
Metadata *KeyMD = ConstantAsMetadata::get(IndexVal);
1527+
SuspendMdEntries.push_back(MDNode::get(C, {KeyMD, SuspendMD}));
1528+
}
1529+
}
15101530

15111531
// Replace CoroSave with a store to Index:
15121532
// %index.addr = getelementptr %f.frame... (index field number)
@@ -1582,6 +1602,10 @@ struct SwitchCoroutineSplitter {
15821602
++SuspendIndex;
15831603
}
15841604

1605+
if (CoroSplitPreservesSuspendMD)
1606+
if (!SuspendMdEntries.empty())
1607+
F.setMetadata(CoroSuspendMDTableName, MDNode::get(C, SuspendMdEntries));
1608+
15851609
Builder.SetInsertPoint(UnreachBB);
15861610
Builder.CreateUnreachable();
15871611
DBuilder.finalize();
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; Tests that coro-split pass preserves metadata on suspend points.
2+
; RUN: opt < %s -coro-split-preserves-suspend-md -passes='cgscc(coro-split)' -S | FileCheck %s
3+
4+
define ptr @f() presplitcoroutine {
5+
entry:
6+
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
7+
%need.alloc = call i1 @llvm.coro.alloc(token %id)
8+
br i1 %need.alloc, label %dyn.alloc, label %begin
9+
10+
dyn.alloc:
11+
%size = call i32 @llvm.coro.size.i32()
12+
%alloc = call ptr @malloc(i32 %size)
13+
br label %begin
14+
15+
begin:
16+
%phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
17+
%hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)
18+
call void @print(i32 0)
19+
%0 = call i8 @llvm.coro.suspend(token none, i1 false), !llvm.coro.suspend_md !0
20+
switch i8 %0, label %suspend [i8 0, label %resume1
21+
i8 1, label %cleanup]
22+
resume1:
23+
call void @print(i32 1)
24+
%1 = call i8 @llvm.coro.suspend(token none, i1 false)
25+
switch i8 %1, label %suspend [i8 0, label %resume2
26+
i8 1, label %cleanup]
27+
resume2:
28+
call void @print(i32 2)
29+
%2 = call i8 @llvm.coro.suspend(token none, i1 true), !llvm.coro.suspend_md !1
30+
switch i8 %2, label %suspend [i8 0, label %trap
31+
i8 1, label %cleanup]
32+
trap:
33+
call void @llvm.trap()
34+
unreachable
35+
cleanup:
36+
%mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
37+
call void @free(ptr %mem)
38+
br label %suspend
39+
suspend:
40+
call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
41+
ret ptr %hdl
42+
}
43+
44+
; CHECK: define ptr @f() !llvm.coro.suspend_md_table ![[MD_TABLE:[0-9]+]]
45+
46+
; CHECK-DAG: ![[MD_TABLE]] = !{![[S0_ROW:[0-9]+]], ![[S1_ROW:[0-9]+]]}
47+
; CHECK-DAG: ![[S0_ROW]] = !{i2 0, ![[S0_MD:[0-9]+]]}
48+
; CHECK-DAG: ![[S0_MD]] = !{!"waiting"}
49+
; CHECK-DAG: ![[S1_ROW]] = !{i2 -2, ![[S1_MD:[0-9]+]]}
50+
; CHECK-DAG: ![[S1_MD]] = !{!"done"}
51+
52+
declare ptr @llvm.coro.free(token, ptr)
53+
declare i32 @llvm.coro.size.i32()
54+
declare i8 @llvm.coro.suspend(token, i1)
55+
declare void @llvm.coro.resume(ptr)
56+
declare void @llvm.coro.destroy(ptr)
57+
58+
declare token @llvm.coro.id(i32, ptr, ptr, ptr)
59+
declare i1 @llvm.coro.alloc(token)
60+
declare ptr @llvm.coro.begin(token, ptr)
61+
declare i1 @llvm.coro.end(ptr, i1, token)
62+
63+
declare noalias ptr @malloc(i32) allockind("alloc,uninitialized") "alloc-family"="malloc"
64+
declare void @print(i32)
65+
declare void @free(ptr) willreturn allockind("free") "alloc-family"="malloc"
66+
67+
!0 = !{!"waiting"}
68+
!1 = !{!"done"}
69+
attributes #1 = { coro_elide_safe }

0 commit comments

Comments
 (0)