Skip to content

Commit 26e2610

Browse files
committed
introduce and use an @llvm.coro.outside.frame intrinsic instead
1 parent 4605efb commit 26e2610

File tree

11 files changed

+120
-17
lines changed

11 files changed

+120
-17
lines changed

clang/lib/CodeGen/CGCoroutine.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,7 @@ struct GetReturnObjectManager {
709709
auto *GroAlloca = dyn_cast_or_null<llvm::AllocaInst>(
710710
GroEmission.getOriginalAllocatedAddress().getPointer());
711711
assert(GroAlloca && "expected alloca to be emitted");
712-
GroAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame,
713-
llvm::MDNode::get(CGF.CGM.getLLVMContext(), {}));
712+
Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_outside_frame), {GroAlloca});
714713

715714
// Remember the top of EHStack before emitting the cleanup.
716715
auto old_top = CGF.EHStack.stable_begin();
@@ -859,10 +858,8 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
859858
// If the original param is in an alloca, exclude it from the coroutine
860859
// frame. The parameter copy will be part of the frame.
861860
Address ParmAddr = GetAddrOfLocalVar(Parm);
862-
if (auto *ParmAlloca =
863-
dyn_cast<llvm::AllocaInst>(ParmAddr.getBasePointer())) {
864-
ParmAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame,
865-
llvm::MDNode::get(CGM.getLLVMContext(), {}));
861+
if (auto *ParmAlloca = dyn_cast<llvm::AllocaInst>(ParmAddr.getBasePointer())) {
862+
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::coro_outside_frame), {ParmAlloca});
866863
}
867864
}
868865
for (auto *PM : S.getParamMoves()) {

clang/test/CodeGenCoroutines/coro-gro.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ void doSomething() noexcept;
3030
int f() {
3131
// CHECK: %[[RetVal:.+]] = alloca i32
3232
// CHECK: %[[GroActive:.+]] = alloca i1
33-
// CHECK: %[[CoroGro:.+]] = alloca %struct.GroType, {{.*}} !coro.outside.frame ![[OutFrameMetadata:.+]]
33+
// CHECK: %[[CoroGro:.+]] = alloca %struct.GroType
3434

3535
// CHECK: %[[Size:.+]] = call i64 @llvm.coro.size.i64()
3636
// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef %[[Size]])
3737
// CHECK: store i1 false, ptr %[[GroActive]]
38+
// CHECK: call void @llvm.coro.outside.frame(ptr %[[CoroGro]])
3839
// CHECK: call void @_ZNSt16coroutine_traitsIiJEE12promise_typeC1Ev(
3940
// CHECK: call void @_ZNSt16coroutine_traitsIiJEE12promise_type17get_return_objectEv({{.*}} %[[CoroGro]]
4041
// CHECK: store i1 true, ptr %[[GroActive]]
@@ -106,4 +107,3 @@ invoker g() {
106107
// CHECK: call void @_ZN7invoker15invoker_promise17get_return_objectEv({{.*}} %[[AggRes]]
107108
co_return;
108109
}
109-
// CHECK: ![[OutFrameMetadata]] = !{}

clang/test/CodeGenCoroutines/coro-params.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,13 @@ void consume(int,int,int,int) noexcept;
7171
// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy10TrivialABI(i32 noundef %val, ptr noundef %[[MoParam:.+]], ptr noundef %[[McParam:.+]], i32 %[[TrivialParam:.+]]) #0 personality ptr @__gxx_personality_v0
7272
void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) {
7373
// CHECK: %[[TrivialAlloca:.+]] = alloca %struct.TrivialABI,
74-
// CHECK-SAME: !coro.outside.frame
7574
// CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly,
7675
// CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy,
7776
// CHECK: %[[TrivialCopy:.+]] = alloca %struct.TrivialABI,
7877
// CHECK: store i32 %val, ptr %[[ValAddr:.+]]
7978

8079
// CHECK: call ptr @llvm.coro.begin(
80+
// CHECK: @llvm.coro.outside.frame(ptr %[[TrivialAlloca]])
8181
// CHECK: call void @_ZN8MoveOnlyC1EOS_(ptr {{[^,]*}} %[[MoCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[MoParam]])
8282
// CHECK-NEXT: call void @llvm.lifetime.start.p0(
8383
// CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(ptr {{[^,]*}} %[[McCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[McParam]]) #

llvm/docs/Coroutines.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,30 @@ the function call.
16411641
ptr %ctxt, ptr %task, ptr %actor)
16421642
unreachable
16431643
1644+
1645+
.. _coro.outside.frame:
1646+
1647+
'llvm.coro.outside.frame' Intrinsic
1648+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1649+
::
1650+
1651+
declare void @llvm.coro.outside.frame(ptr %p)
1652+
1653+
Overview:
1654+
"""""""""
1655+
1656+
TODO
1657+
1658+
Arguments:
1659+
""""""""""
1660+
1661+
TODO
1662+
1663+
Semantics:
1664+
""""""""""
1665+
1666+
TODO
1667+
16441668
.. _coro.suspend:
16451669
.. _suspend points:
16461670

@@ -2185,6 +2209,7 @@ Metadata
21852209
'``coro.outside.frame``' Metadata
21862210
---------------------------------
21872211

2212+
TODO: Deprecate/remove
21882213
``coro.outside.frame`` metadata may be attached to an alloca instruction to
21892214
to signify that it shouldn't be promoted to the coroutine frame, useful for
21902215
filtering allocas out by the frontend when emitting internal control mechanisms.

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,7 @@ def int_coro_alloca_alloc : Intrinsic<[llvm_token_ty],
17781778
[llvm_anyint_ty, llvm_i32_ty], []>;
17791779
def int_coro_alloca_get : Intrinsic<[llvm_ptr_ty], [llvm_token_ty], []>;
17801780
def int_coro_alloca_free : Intrinsic<[], [llvm_token_ty], []>;
1781+
def int_coro_outside_frame : Intrinsic<[], [llvm_ptr_ty], []>;
17811782

17821783
// Coroutine Manipulation Intrinsics.
17831784

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,22 @@ class CoroAllocaFreeInst : public IntrinsicInst {
796796
}
797797
};
798798

799+
/// This represents the llvm.coro.outside.frame instruction.
800+
class CoroOutsideFrameInst : public IntrinsicInst {
801+
enum { PtrArg };
802+
803+
public:
804+
Value *getPtr() const { return getArgOperand(PtrArg); } // XXX: Could we require it to be an alloca?
805+
806+
// Methods to support type inquiry through isa, cast, and dyn_cast:
807+
static bool classof(const IntrinsicInst *I) {
808+
return I->getIntrinsicID() == Intrinsic::coro_outside_frame;
809+
}
810+
static bool classof(const Value *V) {
811+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
812+
}
813+
};
814+
799815
} // End namespace llvm.
800816

801817
#endif // LLVM_TRANSFORMS_COROUTINES_COROINSTR_H

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct Shape {
5757
SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends;
5858
SmallVector<CoroAwaitSuspendInst *, 4> CoroAwaitSuspends;
5959
SmallVector<CallInst *, 2> SymmetricTransfers;
60+
SmallVector<CoroOutsideFrameInst *, 8> OutsideFrames;
6061

6162
// Values invalidated by replaceSwiftErrorOps()
6263
SmallVector<CallInst *, 2> SwiftErrorOps;
@@ -69,6 +70,7 @@ struct Shape {
6970
CoroSuspends.clear();
7071
CoroAwaitSuspends.clear();
7172
SymmetricTransfers.clear();
73+
OutsideFrames.clear();
7274

7375
SwiftErrorOps.clear();
7476

llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,7 +2015,13 @@ static void doSplitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
20152015
simplifySuspendPoints(Shape);
20162016

20172017
normalizeCoroutine(F, Shape, TTI);
2018+
20182019
ABI.buildCoroutineFrame(OptimizeFrame);
2020+
2021+
// @llvm.coro.outside.frame no longer needed after the frame has been built.
2022+
for (Instruction *I : Shape.OutsideFrames)
2023+
I->eraseFromParent();
2024+
20192025
replaceFrameSizeAndAlignment(Shape);
20202026

20212027
bool isNoSuspendCoroutine = Shape.CoroSuspends.empty();

llvm/lib/Transforms/Coroutines/Coroutines.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ void coro::Shape::analyze(Function &F,
286286
}
287287
}
288288
break;
289+
case Intrinsic::coro_outside_frame:
290+
OutsideFrames.push_back(cast<CoroOutsideFrameInst>(II));
291+
break;
289292
}
290293
}
291294
}

llvm/lib/Transforms/Coroutines/SpillUtils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,17 @@ static void collectFrameAlloca(AllocaInst *AI, const coro::Shape &Shape,
426426
if (AI == Shape.SwitchLowering.PromiseAlloca)
427427
return;
428428

429+
// TODO: Deprecate/remove.
429430
// The __coro_gro alloca should outlive the promise, make sure we
430431
// keep it outside the frame.
431432
if (AI->hasMetadata(LLVMContext::MD_coro_outside_frame))
432433
return;
433434

435+
for (const CoroOutsideFrameInst *I : Shape.OutsideFrames) {
436+
if (I->getPtr() == AI)
437+
return;
438+
}
439+
434440
// The code that uses lifetime.start intrinsic does not work for functions
435441
// with loops without exit. Disable it on ABIs we know to generate such
436442
// code.

0 commit comments

Comments
 (0)