[PATCH] D154695: [Coroutines] Add an O(n) algorithm for computing the cross suspend point information.
witstorm via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 19 02:17:52 PDT 2023
witstorm95 added a comment.
@ChuanqiXu I takes some time to figure out where the cross suspend point information is used and what it does . It used to determine whether the stack variable need to be placed on Coroutine frame. So the current problem does not affect the correctness of the coroutine programs.
If we stick to the definition about KIlls, we may get the wrong result in some cases. For example(llvm/test/Transforms/Coroutines/ArgAddr.ll),
define nonnull ptr @f(i32 %n) presplitcoroutine {
; CHECK-LABEL: @f(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr @f.resumers)
; CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 [[N:%.*]], ptr [[N_ADDR]], align 4
; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 24)
; CHECK-NEXT: [[TMP0:%.*]] = tail call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[CALL]])
; CHECK-NEXT: store ptr @f.resume, ptr [[TMP0]], align 8
; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds [[F_FRAME:%.*]], ptr [[TMP0]], i32 0, i32 1
; CHECK-NEXT: store ptr @f.destroy, ptr [[DESTROY_ADDR]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[F_FRAME]], ptr [[TMP0]], i32 0, i32 2
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[N_ADDR]], align 4
; CHECK-NEXT: store i32 [[TMP2]], ptr [[TMP1]], align 4
;
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null);
%n.addr = alloca i32
store i32 %n, ptr %n.addr ; this needs to go after coro.begin
%0 = tail call i32 @llvm.coro.size.i32()
%call = tail call ptr @malloc(i32 %0)
%1 = tail call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %call)
call void @ctor(ptr %n.addr)
br label %for.cond
for.cond:
%2 = load i32, ptr %n.add
%dec = add nsw i32 %2, -1
store i32 %dec, ptr %n.addr
call void @print(i32 %2)
%3 = call i8 @llvm.coro.suspend(token none, i1 false)
%conv = sext i8 %3 to i32
switch i32 %conv, label %coro_Suspend [
i32 0, label %for.cond
i32 1, label %coro_Cleanup
]
coro_Cleanup:
%4 = call ptr @llvm.coro.free(token %id, ptr nonnull %1)
call void @free(ptr %4)
br label %coro_Suspend
coro_Suspend:
call i1 @llvm.coro.end(ptr null, i1 false)
ret ptr %1
}
Apparently, stack variable %n.addr should be placed on Coroutine frame as it be used in for.cond block that contains suspend point. Right ? But If we stick to the definition about KIlls, we can't get this result. Why? Because splitAround will split for.cond into 4 blocks(for.cond, CoroSave, CoroSuspend, AfterSuspend) before the cross suspend point information is computed. And splitAround will lead some info lost. Here is CFG about function f,
F28318563: 1.jpg <https://reviews.llvm.org/F28318563>
Code of each block as follow,
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%n.addr = alloca i32, align 4
store i32 %n, ptr %n.addr, align 4
%0 = tail call i32 @llvm.coro.size.i32()
%call = tail call ptr @malloc(i32 %0)
%1 = tail call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %call)
call void @ctor(ptr %n.addr)
br label %for.cond
for.cond: ; preds = %AfterCoroSuspend, %entry
%2 = load i32, ptr %n.addr, align 4
%dec = add nsw i32 %2, -1
store i32 %dec, ptr %n.addr, align 4
call void @print(i32 %2)
br label %CoroSave
coro_Suspend: ; preds = %coro_Cleanup, %AfterCoroSuspend
br label %CoroEnd
coro_Cleanup: ; preds = %AfterCoroSuspend
%5 = call ptr @llvm.coro.free(token %id, ptr nonnull %1)
call void @free(ptr %5)
br label %coro_Suspend
CoroSave: ; preds = %for.cond
%3 = call token @llvm.coro.save(ptr %1)
br label %CoroSuspend
CoroSuspend: ; preds = %CoroSave
%4 = call i8 @llvm.coro.suspend(token %3, i1 false)
br label %AfterCoroSuspend
AfterCoroSuspend: ; preds = %CoroSuspend
%conv = sext i8 %4 to i32
switch i32 %conv, label %coro_Suspend [
i32 0, label %for.cond
i32 1, label %coro_Cleanup
]
CoroEnd: ; preds = %coro_Suspend
%6 = call i1 @llvm.coro.end(ptr null, i1 false)
br label %AfterCoroEnd
AfterCoroEnd: ; preds = %CoroEnd
ret ptr %1
Apparently, for.cond.Kills[Entry] is false, it means %n.addr not crossing a suspend point. So %n.addr will not be placed on Coroutine frame. But it should be placed on Coroutine frame actually.
If I don't understand it correctly, pelase help to point out.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154695/new/
https://reviews.llvm.org/D154695
More information about the llvm-commits
mailing list