Skip to content

Commit 19a4f52

Browse files
authored
[Coroutines] Add llvm.coro.is_in_ramp and drop return value of llvm.coro.end (llvm#153404)
As mentioned in llvm#151067, current design of `llvm.coro.end` mixes two functionalities: querying where we are and lowering to some code. This patch separate these functionalities into independent intrinsics by introducing a new intrinsic `llvm.coro.is_in_ramp`.
1 parent df69dfe commit 19a4f52

File tree

147 files changed

+438
-378
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

147 files changed

+438
-378
lines changed

clang/lib/CodeGen/CGCoroutine.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -575,17 +575,19 @@ struct CallCoroEnd final : public EHScopeStack::Cleanup {
575575
llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
576576
// See if we have a funclet bundle to associate coro.end with. (WinEH)
577577
auto Bundles = getBundlesForCoroEnd(CGF);
578-
auto *CoroEnd =
579-
CGF.Builder.CreateCall(CoroEndFn,
580-
{NullPtr, CGF.Builder.getTrue(),
581-
llvm::ConstantTokenNone::get(CoroEndFn->getContext())},
582-
Bundles);
578+
CGF.Builder.CreateCall(
579+
CoroEndFn,
580+
{NullPtr, CGF.Builder.getTrue(),
581+
llvm::ConstantTokenNone::get(CoroEndFn->getContext())},
582+
Bundles);
583583
if (Bundles.empty()) {
584584
// Otherwise, (landingpad model), create a conditional branch that leads
585585
// either to a cleanup block or a block with EH resume instruction.
586586
auto *ResumeBB = CGF.getEHResumeBlock(/*isCleanup=*/true);
587587
auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont");
588-
CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
588+
auto *CoroIsInRampFn = CGM.getIntrinsic(llvm::Intrinsic::coro_is_in_ramp);
589+
auto *CoroIsInRamp = CGF.Builder.CreateCall(CoroIsInRampFn);
590+
CGF.Builder.CreateCondBr(CoroIsInRamp, CleanupContBB, ResumeBB);
589591
CGF.EmitBlock(CleanupContBB);
590592
}
591593
}

clang/test/CodeGenCoroutines/coro-builtins.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void f(int n) {
3737
// CHECK-NEXT: call ptr @llvm.coro.free(token %[[COROID]], ptr %[[FRAME]])
3838
__builtin_coro_free(__builtin_coro_frame());
3939

40-
// CHECK-NEXT: call i1 @llvm.coro.end(ptr %[[FRAME]], i1 false, token none)
40+
// CHECK-NEXT: call void @llvm.coro.end(ptr %[[FRAME]], i1 false, token none)
4141
__builtin_coro_end(__builtin_coro_frame(), 0);
4242

4343
// CHECK-NEXT: call i8 @llvm.coro.suspend(token none, i1 true)

clang/test/CodeGenCoroutines/coro-eh-cleanup.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ coro_t f() {
6060

6161
// CHECK: [[COROENDBB]]:
6262
// CHECK-NEXT: %[[CLPAD:.+]] = cleanuppad within none
63-
// CHECK-NEXT: call i1 @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %[[CLPAD]]) ]
63+
// CHECK-NEXT: call void @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %[[CLPAD]]) ]
6464
// CHECK-NEXT: cleanupret from %[[CLPAD]] unwind label
6565

6666
// CHECK-LPAD: @_Z1fv(
@@ -76,8 +76,8 @@ coro_t f() {
7676
// CHECK-LPAD: to label %{{.+}} unwind label %[[UNWINDBB:.+]]
7777

7878
// CHECK-LPAD: [[UNWINDBB]]:
79-
// CHECK-LPAD: %[[I1RESUME:.+]] = call i1 @llvm.coro.end(ptr null, i1 true, token none)
80-
// CHECK-LPAD: br i1 %[[I1RESUME]], label %[[EHRESUME:.+]], label
79+
// CHECK-LPAD: %[[InRamp:.+]] = call i1 @llvm.coro.is_in_ramp()
80+
// CHECK-LPAD: br i1 %[[InRamp]], label %{{.+}}, label %[[EHRESUME:.+]]
8181
// CHECK-LPAD: [[EHRESUME]]:
8282
// CHECK-LPAD-NEXT: %[[exn:.+]] = load ptr, ptr %exn.slot, align 8
8383
// CHECK-LPAD-NEXT: %[[sel:.+]] = load i32, ptr %ehselector.slot, align 4

clang/test/CodeGenCoroutines/coro-lambda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ void f() {
5555
// CHECK: alloca %"struct.Task::promise_type"
5656
// CHECK: call token @llvm.coro.id(
5757
// CHECK: call i8 @llvm.coro.suspend(
58-
// CHECK: call i1 @llvm.coro.end(
58+
// CHECK: call void @llvm.coro.end(

clang/test/CodeGenCoroutines/coro-params.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam)
117117
// CHECK-NEXT: call ptr @llvm.coro.free(
118118

119119
// The original trivial_abi parameter is destroyed when returning from the ramp.
120-
// CHECK: call i1 @llvm.coro.end
120+
// CHECK: call void @llvm.coro.end
121121
// CHECK: call void @_ZN10TrivialABID1Ev(ptr {{[^,]*}} %[[TrivialAlloca]])
122122
}
123123

@@ -242,6 +242,6 @@ void msabi(MSParm p) {
242242
co_return;
243243

244244
// The local alloca is used for the destructor call at the end of the ramp.
245-
// MSABI: call i1 @llvm.coro.end
245+
// MSABI: call void @llvm.coro.end
246246
// MSABI: call void @"??1MSParm@@QEAA@XZ"(ptr{{.*}} %[[ParamAlloca]])
247247
}

llvm/docs/Coroutines.rst

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ The LLVM IR for this coroutine looks like this:
303303
call void @free(ptr %mem)
304304
br label %suspend
305305
suspend:
306-
%unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
306+
call void @llvm.coro.end(ptr %hdl, i1 false, token none)
307307
ret ptr %hdl
308308
}
309309
@@ -637,7 +637,7 @@ store the current value produced by a coroutine.
637637
call void @free(ptr %mem)
638638
br label %suspend
639639
suspend:
640-
%unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
640+
call void @llvm.coro.end(ptr %hdl, i1 false, token none)
641641
ret ptr %hdl
642642
}
643643
@@ -806,7 +806,7 @@ The LLVM IR for a coroutine using a Coroutine with a custom ABI looks like:
806806
call void @free(ptr %mem)
807807
br label %suspend
808808
suspend:
809-
%unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
809+
call void @llvm.coro.end(ptr %hdl, i1 false, token none)
810810
ret ptr %hdl
811811
}
812812
@@ -1444,7 +1444,7 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine.
14441444
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14451445
::
14461446

1447-
declare i1 @llvm.coro.end(ptr <handle>, i1 <unwind>, token <result.token>)
1447+
declare void @llvm.coro.end(ptr <handle>, i1 <unwind>, token <result.token>)
14481448

14491449
Overview:
14501450
"""""""""
@@ -1502,8 +1502,9 @@ For landingpad based exception model, it is expected that frontend uses the
15021502
.. code-block:: llvm
15031503
15041504
ehcleanup:
1505-
%InResumePart = call i1 @llvm.coro.end(ptr null, i1 true, token none)
1506-
br i1 %InResumePart, label %eh.resume, label %cleanup.cont
1505+
call void @llvm.coro.end(ptr null, i1 true, token none)
1506+
%InRamp = call i1 @llvm.coro.is_in_ramp()
1507+
br i1 %InRamp, label %cleanup.cont, label %eh.resume
15071508
15081509
cleanup.cont:
15091510
; rest of the cleanup
@@ -1515,10 +1516,10 @@ For landingpad based exception model, it is expected that frontend uses the
15151516
%lpad.val29 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
15161517
resume { ptr, i32 } %lpad.val29
15171518
1518-
The `CoroSpit` pass replaces `coro.end` with ``True`` in the resume functions,
1519-
thus leading to immediate unwind to the caller, whereas in start function it
1520-
is replaced with ``False``, thus allowing to proceed to the rest of the cleanup
1521-
code that is only needed during initial invocation of the coroutine.
1519+
The `CoroSpit` pass replaces `coro.is_in_ramp` with ``True`` in the ramp functions,
1520+
thus allowing to proceed to the rest of the cleanup code that is only needed during
1521+
initial invocation of the coroutine. Otherwise, it is replaced with ``False``,
1522+
thus leading to immediate unwind to the caller.
15221523

15231524
For Windows Exception handling model, a frontend should attach a funclet bundle
15241525
referring to an enclosing cleanuppad as follows:
@@ -1527,7 +1528,7 @@ referring to an enclosing cleanuppad as follows:
15271528
15281529
ehcleanup:
15291530
%tok = cleanuppad within none []
1530-
%unused = call i1 @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %tok) ]
1531+
call void @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %tok) ]
15311532
cleanupret from %tok unwind label %RestOfTheCleanup
15321533
15331534
The `CoroSplit` pass, if the funclet bundle is present, will insert
@@ -1592,7 +1593,7 @@ The number of arguments must match the return type of the continuation function:
15921593
15931594
cleanup:
15941595
%tok = call token (...) @llvm.coro.end.results(i8 %val)
1595-
call i1 @llvm.coro.end(ptr %hdl, i1 0, token %tok)
1596+
call void @llvm.coro.end(ptr %hdl, i1 0, token %tok)
15961597
unreachable
15971598
15981599
...
@@ -1604,7 +1605,7 @@ The number of arguments must match the return type of the continuation function:
16041605
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16051606
::
16061607

1607-
declare i1 @llvm.coro.end.async(ptr <handle>, i1 <unwind>, ...)
1608+
declare void @llvm.coro.end.async(ptr <handle>, i1 <unwind>, ...)
16081609

16091610
Overview:
16101611
"""""""""
@@ -1635,10 +1636,10 @@ the function call.
16351636

16361637
.. code-block:: llvm
16371638
1638-
call i1 (ptr, i1, ...) @llvm.coro.end.async(
1639-
ptr %hdl, i1 0,
1640-
ptr @must_tail_call_return,
1641-
ptr %ctxt, ptr %task, ptr %actor)
1639+
call void (ptr, i1, ...) @llvm.coro.end.async(
1640+
ptr %hdl, i1 0,
1641+
ptr @must_tail_call_return,
1642+
ptr %ctxt, ptr %task, ptr %actor)
16421643
unreachable
16431644
16441645
.. _coro.suspend:
@@ -2117,6 +2118,30 @@ Example:
21172118
%hdl.result = ... ; get address of returned coroutine handle
21182119
ret ptr %hdl.result
21192120
2121+
'llvm.coro.is_in_ramp' Intrinsic
2122+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2123+
::
2124+
2125+
declare i1 @llvm.coro.is_in_ramp()
2126+
2127+
Overview:
2128+
"""""""""
2129+
2130+
The '``llvm.coro.is_in_ramp``' intrinsic returns a bool value that marks coroutine ramp
2131+
function and resume/destroy function.
2132+
2133+
Arguments:
2134+
""""""""""
2135+
2136+
None
2137+
2138+
Semantics:
2139+
""""""""""
2140+
2141+
The `CoroSpit` pass replaces `coro.is_in_ramp` with ``True`` ramp functions.
2142+
Otherwise, it is replaced with ``False``, allowing the frontend to separate
2143+
ramp function and resume/destroy function.
2144+
21202145
Coroutine Transformation Passes
21212146
===============================
21222147
CoroEarly

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,12 +1775,13 @@ def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
17751775
[IntrReadMem, IntrArgMemOnly,
17761776
ReadOnly<ArgIndex<1>>,
17771777
NoCapture<ArgIndex<1>>]>;
1778-
def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty, llvm_token_ty], []>;
1778+
def int_coro_end : Intrinsic<[], [llvm_ptr_ty, llvm_i1_ty, llvm_token_ty], []>;
17791779
def int_coro_end_results : Intrinsic<[llvm_token_ty], [llvm_vararg_ty]>;
17801780
def int_coro_end_async
1781-
: Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty, llvm_vararg_ty], []>;
1781+
: Intrinsic<[], [llvm_ptr_ty, llvm_i1_ty, llvm_vararg_ty], []>;
17821782

17831783
def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
1784+
def int_coro_is_in_ramp : Intrinsic<[llvm_i1_ty], [], [IntrNoMem], "llvm.coro.is_in_ramp">;
17841785
def int_coro_noop : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
17851786
def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>;
17861787
def int_coro_align : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>;

llvm/include/llvm/Transforms/Coroutines/CoroInstr.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,18 @@ class CoroFrameInst : public IntrinsicInst {
428428
}
429429
};
430430

431+
/// This represents the llvm.coro.is_in_ramp instruction.
432+
class CoroIsInRampInst : public IntrinsicInst {
433+
public:
434+
// Methods to support type inquiry through isa, cast, and dyn_cast:
435+
static bool classof(const IntrinsicInst *I) {
436+
return I->getIntrinsicID() == Intrinsic::coro_is_in_ramp;
437+
}
438+
static bool classof(const Value *V) {
439+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
440+
}
441+
};
442+
431443
/// This represents the llvm.coro.free instruction.
432444
class CoroFreeInst : public IntrinsicInst {
433445
enum { IdArg, FrameArg };

llvm/include/llvm/Transforms/Coroutines/CoroShape.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ enum class ABI {
5353
struct Shape {
5454
CoroBeginInst *CoroBegin = nullptr;
5555
SmallVector<AnyCoroEndInst *, 4> CoroEnds;
56+
SmallVector<CoroIsInRampInst *, 2> CoroIsInRampInsts;
5657
SmallVector<CoroSizeInst *, 2> CoroSizes;
5758
SmallVector<CoroAlignInst *, 2> CoroAligns;
5859
SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends;
@@ -65,6 +66,7 @@ struct Shape {
6566
void clear() {
6667
CoroBegin = nullptr;
6768
CoroEnds.clear();
69+
CoroIsInRampInsts.clear();
6870
CoroSizes.clear();
6971
CoroAligns.clear();
7072
CoroSuspends.clear();

llvm/lib/Transforms/Coroutines/CoroCleanup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ bool Lowerer::lower(Function &F) {
7575
case Intrinsic::coro_subfn_addr:
7676
lowerSubFn(Builder, cast<CoroSubFnInst>(II));
7777
break;
78-
case Intrinsic::coro_end:
7978
case Intrinsic::coro_suspend_retcon:
79+
case Intrinsic::coro_is_in_ramp:
8080
if (IsPrivateAndUnprocessed) {
8181
II->replaceAllUsesWith(PoisonValue::get(II->getType()));
8282
} else

0 commit comments

Comments
 (0)