Skip to content

Commit c8c6cec

Browse files
ChuanqiXu9memfrob
authored andcommitted
[Coroutine] Recommit Add statistics for the number of elided coroutine
Now we lack a benchmark to measure the performance change for each commit. Since coro elide is the main optimization in coroutine module, I wonder it may be an estimation to count the number of elided coroutine in private code bases. e.g., for a certain commit, if we found that the number of elided goes down, we could find it before the commit check-in. Reviewed By: lxfind Differential Revision: https://reviews.llvm.org/D105095
1 parent 611ad2e commit c8c6cec

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

llvm/lib/Transforms/Coroutines/CoroElide.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "llvm/Transforms/Coroutines/CoroElide.h"
1010
#include "CoroInternal.h"
1111
#include "llvm/ADT/DenseMap.h"
12+
#include "llvm/ADT/Statistic.h"
1213
#include "llvm/Analysis/AliasAnalysis.h"
1314
#include "llvm/Analysis/InstructionSimplify.h"
1415
#include "llvm/IR/Dominators.h"
@@ -21,6 +22,8 @@ using namespace llvm;
2122

2223
#define DEBUG_TYPE "coro-elide"
2324

25+
STATISTIC(NumOfCoroElided, "The # of coroutine get elided.");
26+
2427
namespace {
2528
// Created on demand if the coro-elide pass has work to do.
2629
struct Lowerer : coro::LowererBase {
@@ -344,6 +347,7 @@ bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA,
344347
elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign.first,
345348
FrameSizeAndAlign.second, AA);
346349
coro::replaceCoroFree(CoroId, /*Elide=*/true);
350+
NumOfCoroElided++;
347351
}
348352

349353
return true;
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
; Tests that the number elided coroutine is record correctly.
2+
; REQUIRES: asserts
3+
;
4+
; RUN: opt < %s -S \
5+
; RUN: -passes='cgscc(repeat<2>(inline,function(coro-elide,dce)))' -stats 2>&1 \
6+
; RUN: | FileCheck %s
7+
8+
; CHECK: 2 coro-elide - The # of coroutine get elided.
9+
10+
declare void @print(i32) nounwind
11+
12+
; resume part of the coroutine
13+
define fastcc void @f.resume(i8*) {
14+
tail call void @print(i32 0)
15+
ret void
16+
}
17+
18+
; destroy part of the coroutine
19+
define fastcc void @f.destroy(i8*) {
20+
tail call void @print(i32 1)
21+
ret void
22+
}
23+
24+
; cleanup part of the coroutine
25+
define fastcc void @f.cleanup(i8*) {
26+
tail call void @print(i32 2)
27+
ret void
28+
}
29+
30+
@f.resumers = internal constant [3 x void (i8*)*] [void (i8*)* @f.resume,
31+
void (i8*)* @f.destroy,
32+
void (i8*)* @f.cleanup]
33+
34+
; a coroutine start function
35+
define i8* @f() {
36+
entry:
37+
%id = call token @llvm.coro.id(i32 0, i8* null,
38+
i8* bitcast (i8*()* @f to i8*),
39+
i8* bitcast ([3 x void (i8*)*]* @f.resumers to i8*))
40+
%alloc = call i1 @llvm.coro.alloc(token %id)
41+
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
42+
ret i8* %hdl
43+
}
44+
45+
define void @callResume() {
46+
entry:
47+
%hdl = call i8* @f()
48+
49+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
50+
%1 = bitcast i8* %0 to void (i8*)*
51+
call fastcc void %1(i8* %hdl)
52+
53+
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
54+
%3 = bitcast i8* %2 to void (i8*)*
55+
call fastcc void %3(i8* %hdl)
56+
57+
ret void
58+
}
59+
60+
define void @callResumeMultiRet(i1 %b) {
61+
entry:
62+
%hdl = call i8* @f()
63+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
64+
%1 = bitcast i8* %0 to void (i8*)*
65+
call fastcc void %1(i8* %hdl)
66+
br i1 %b, label %destroy, label %ret
67+
68+
destroy:
69+
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
70+
%3 = bitcast i8* %2 to void (i8*)*
71+
call fastcc void %3(i8* %hdl)
72+
ret void
73+
74+
ret:
75+
ret void
76+
}
77+
78+
define void @callResumeMultiRetDommmed(i1 %b) {
79+
entry:
80+
%hdl = call i8* @f()
81+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
82+
%1 = bitcast i8* %0 to void (i8*)*
83+
call fastcc void %1(i8* %hdl)
84+
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
85+
%3 = bitcast i8* %2 to void (i8*)*
86+
call fastcc void %3(i8* %hdl)
87+
br i1 %b, label %destroy, label %ret
88+
89+
destroy:
90+
ret void
91+
92+
ret:
93+
ret void
94+
}
95+
96+
define void @eh() personality i8* null {
97+
entry:
98+
%hdl = call i8* @f()
99+
100+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
101+
%1 = bitcast i8* %0 to void (i8*)*
102+
invoke void %1(i8* %hdl)
103+
to label %cont unwind label %ehcleanup
104+
cont:
105+
ret void
106+
107+
ehcleanup:
108+
%tok = cleanuppad within none []
109+
cleanupret from %tok unwind to caller
110+
}
111+
112+
; no devirtualization here, since coro.begin info parameter is null
113+
define void @no_devirt_info_null() {
114+
entry:
115+
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
116+
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
117+
118+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
119+
%1 = bitcast i8* %0 to void (i8*)*
120+
call fastcc void %1(i8* %hdl)
121+
122+
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
123+
%3 = bitcast i8* %2 to void (i8*)*
124+
call fastcc void %3(i8* %hdl)
125+
126+
ret void
127+
}
128+
129+
; no devirtualization here, since coro.begin is not visible
130+
define void @no_devirt_no_begin(i8* %hdl) {
131+
entry:
132+
133+
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
134+
%1 = bitcast i8* %0 to void (i8*)*
135+
call fastcc void %1(i8* %hdl)
136+
137+
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
138+
%3 = bitcast i8* %2 to void (i8*)*
139+
call fastcc void %3(i8* %hdl)
140+
141+
ret void
142+
}
143+
144+
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
145+
declare i8* @llvm.coro.begin(token, i8*)
146+
declare i8* @llvm.coro.frame()
147+
declare i8* @llvm.coro.subfn.addr(i8*, i8)
148+
declare i1 @llvm.coro.alloc(token)

0 commit comments

Comments
 (0)