[llvm-dev] Coroutine elision not applied
Ariya Shajii via llvm-dev
llvm-dev at lists.llvm.org
Mon Feb 4 11:04:59 PST 2019
Hi,
I’m experimenting with LLVM coroutines, and am wondering about a particular
case where a seemingly irrelevant IR change prevents elision optimization.
Any insight into why this happens would be greatly appreciated. I'm using
LLVM 7.0.1.
The code I'm working with is basically equivalent to the following Python
example:
def my_coro(n: int):
yield n
my_var = <some extern global>
if my_var > 0:
for a in my_coro(my_var):
print a
Here’s my_coro in LLVM IR (note that there is an initial suspend, then a
suspend to yield the value, then the final suspend):
define private i8* @my_coro(i64) {
entry:
%promise = alloca i64, i64 1
%1 = bitcast i64* %promise to i8*
%id = call token @llvm.coro.id(i32 0, i8* %1, i8* null, i8* null)
%2 = alloca i64, i64 1
store i64 %0, i64* %2
%3 = call i1 @llvm.coro.alloc(token %id)
br i1 %3, label %alloc, label %begin
alloc: ; preds = %entry
%4 = call i64 @llvm.coro.size.i64()
%5 = call i8* @my_alloc(i64 %4)
br label %begin
begin: ; preds = %entry, %alloc
%6 = phi i8* [ null, %entry ], [ %5, %alloc ]
%hdl = call i8* @llvm.coro.begin(token %id, i8* %6)
%7 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %7, label %suspend [
i8 0, label %9
i8 1, label %cleanup
]
final: ; preds = %12
%8 = call i8 @llvm.coro.suspend(token none, i1 true)
switch i8 %8, label %suspend [
i8 0, label %13
i8 1, label %cleanup
]
; <label>:9: ; preds = %begin
%10 = load i64, i64* %2
store i64 %10, i64* %promise
%11 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %11, label %suspend [
i8 0, label %12
i8 1, label %cleanup
]
; <label>:12: ; preds = %9
br label %final
; <label>:13: ; preds = %final
unreachable
cleanup: ; preds = %final, %9,
%entry
%14 = call i8* @llvm.coro.free(token %id, i8* %hdl)
br label %suspend
suspend: ; preds = %final, %9,
%entry, %cleanup
%15 = call i1 @llvm.coro.end(i8* %hdl, i1 false)
ret i8* %hdl
}
And how it's called (i.e. the for-loop above):
define external void @main() {
entry:
%0 = load i64, i64* @my.var
%1 = icmp sgt i64 %0, 0
br i1 %1, label %if, label %exit
if: ; preds = %entry
%2 = load i64, i64* @my.var
%3 = call i8* @my_coro(i64 %2)
br label %for
for: ; preds = %body,
%for_cont, %if
call void @llvm.coro.resume(i8* %3)
%4 = call i1 @llvm.coro.done(i8* %3)
br i1 %4, label %cleanup, label %body
body: ; preds = %for
%5 = call i8* @llvm.coro.promise(i8* %3, i32 8, i1 false)
%6 = bitcast i8* %5 to i64*
%7 = load i64, i64* %6
call void @my_print(i64 %7)
br label %for
cleanup: ; preds = %for
call void @llvm.coro.destroy(i8* %3)
br label %exit
exit: ; preds = %entry,
%cleanup
ret void
}
Now if I optimize this with "opt -S -enable-coroutines -O3", the coroutine
allocation is _not_ elided. But if I remove the if-statement (e.g. change
the condition to 1 > 0, giving the first branch in main() an i1 true
condition), then elision does take place.
However, I see no reason why elision can't be applied to the first version
-- why does the presence of a branch outside the blocks where the coroutine
is used change anything? Am I perhaps using opt incorrectly? Any insight
would be greatly appreciated here, and thanks in advance.
Ariya
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190204/8aef65a7/attachment.html>
More information about the llvm-dev
mailing list