Skip to content

Commit c1fe663

Browse files
committed
[Coroutines] Replace coro.outside.frame metadata with an intrinsic
Metadata should not be "load bearing", i.e. required for correctness, since optimizations are not required to preserve it. Therefore, turn this into an intrinsic instead. This is follow-up to #127653.
1 parent 71389e5 commit c1fe663

File tree

15 files changed

+121
-48
lines changed

15 files changed

+121
-48
lines changed

clang/lib/CodeGen/CGCoroutine.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,8 @@ 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(
713+
CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_outside_frame), {GroAlloca});
714714

715715
// Remember the top of EHStack before emitting the cleanup.
716716
auto old_top = CGF.EHStack.stable_begin();
@@ -863,10 +863,9 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
863863
// in the MSVC C++ ABI, are appropriately destroyed after setting up the
864864
// coroutine.
865865
Address ParmAddr = GetAddrOfLocalVar(Parm);
866-
if (auto *ParmAlloca =
867-
dyn_cast<llvm::AllocaInst>(ParmAddr.getBasePointer())) {
868-
ParmAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame,
869-
llvm::MDNode::get(CGM.getLLVMContext(), {}));
866+
if (auto *PA = dyn_cast<llvm::AllocaInst>(ParmAddr.getBasePointer())) {
867+
Builder.CreateCall(
868+
CGM.getIntrinsic(llvm::Intrinsic::coro_outside_frame), {PA});
870869
}
871870
}
872871
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: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ void consume(int,int,int,int) noexcept;
7272
// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy10TrivialABI(i32 noundef %val, ptr noundef %[[MoParam:.+]], ptr noundef %[[McParam:.+]], i32 %[[TrivialParam:.+]]) #0 personality ptr @__gxx_personality_v0
7373
void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) {
7474
// CHECK: %[[TrivialAlloca:.+]] = alloca %struct.TrivialABI,
75-
// CHECK-SAME: !coro.outside.frame
7675
// CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly,
7776
// CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy,
7877
// CHECK: %[[TrivialCopy:.+]] = alloca %struct.TrivialABI,
7978
// CHECK: store i32 %val, ptr %[[ValAddr:.+]]
8079

8180
// CHECK: call ptr @llvm.coro.begin(
81+
// CHECK: @llvm.coro.outside.frame(ptr %[[TrivialAlloca]])
8282
// CHECK: call void @_ZN8MoveOnlyC1EOS_(ptr {{[^,]*}} %[[MoCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[MoParam]])
8383
// CHECK-NEXT: call void @llvm.lifetime.start.p0(
8484
// CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(ptr {{[^,]*}} %[[McCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[McParam]]) #
@@ -226,13 +226,12 @@ void consume(int) noexcept;
226226
// may be destroyed before the destructor call.
227227
void msabi(MSParm p) {
228228
// MSABI: define{{.*}} void @"?msabi@@YAXUMSParm@@@Z"(i32 %[[Param:.+]])
229-
230-
// The parameter's local alloca is marked not part of the frame.
231229
// MSABI: %[[ParamAlloca:.+]] = alloca %struct.MSParm
232-
// MSABI-SAME: !coro.outside.frame
233-
234230
// MSABI: %[[ParamCopy:.+]] = alloca %struct.MSParm
235231

232+
// The parameter's local alloca is marked not part of the frame.
233+
// MSABI: call void @llvm.coro.outside.frame(ptr %[[ParamAlloca]])
234+
236235
consume(p.val);
237236
// The parameter's copy is used by the coroutine.
238237
// MSABI: %[[ValPtr:.+]] = getelementptr inbounds nuw %struct.MSParm, ptr %[[ParamCopy]], i32 0, i32 0

llvm/docs/Coroutines.rst

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,37 @@ 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+
Signifies that an alloca shouldn't be promoted to the coroutine frame.
1657+
1658+
Arguments:
1659+
""""""""""
1660+
1661+
An alloca that should remain outside the coroutine frame.
1662+
1663+
Semantics:
1664+
""""""""""
1665+
1666+
Calling `@llvm.coro.outside.frame` with an alloca signifies that the alloca
1667+
should not be promoted to the coroutine frame. This allows the frontend to
1668+
ensure that e.g. callee-destructed parameters are allocated on the stack of the
1669+
ramp function, and thus available until the function returns.
1670+
1671+
The intrinsic should only be used in presplit coroutines, and is consumed by
1672+
the CoroSplit pass.
1673+
1674+
16441675
.. _coro.suspend:
16451676
.. _suspend points:
16461677

@@ -2179,25 +2210,6 @@ or deallocations that may be guarded by `@llvm.coro.alloc` and `@llvm.coro.free`
21792210
CoroAnnotationElidePass performs the heap elision when possible. Note that for
21802211
recursive or mutually recursive functions this elision is usually not possible.
21812212

2182-
Metadata
2183-
========
2184-
2185-
'``coro.outside.frame``' Metadata
2186-
---------------------------------
2187-
2188-
``coro.outside.frame`` metadata may be attached to an alloca instruction to
2189-
to signify that it shouldn't be promoted to the coroutine frame, useful for
2190-
filtering allocas out by the frontend when emitting internal control mechanisms.
2191-
Additionally, this metadata is only used as a flag, so the associated
2192-
node must be empty.
2193-
2194-
.. code-block:: text
2195-
2196-
%__coro_gro = alloca %struct.GroType, align 1, !coro.outside.frame !0
2197-
2198-
...
2199-
!0 = !{}
2200-
22012213
Areas Requiring Attention
22022214
=========================
22032215
#. When coro.suspend returns -1, the coroutine is suspended, and it's possible

llvm/docs/ReleaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ Changes to the CodeGen infrastructure
145145
Changes to the Metadata Info
146146
---------------------------------
147147

148+
* The `coro.outside.frame` metadata has been replaced by [an intrinsic with the
149+
same name](coro.outside.frame). The old metadata is still parsed but has no
150+
effect.
151+
148152
Changes to the Debug Info
149153
---------------------------------
150154

llvm/include/llvm/IR/FixedMetadataKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ LLVM_FIXED_MD_KIND(MD_callsite, "callsite", 35)
5050
LLVM_FIXED_MD_KIND(MD_kcfi_type, "kcfi_type", 36)
5151
LLVM_FIXED_MD_KIND(MD_pcsections, "pcsections", 37)
5252
LLVM_FIXED_MD_KIND(MD_DIAssignID, "DIAssignID", 38)
53-
LLVM_FIXED_MD_KIND(MD_coro_outside_frame, "coro.outside.frame", 39)
53+
LLVM_FIXED_MD_KIND(MD_coro_outside_frame_DEPRECATED,
54+
"coro.outside.frame", 39) // Preserved for compatibility.
5455
LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40)
5556
LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41)

llvm/include/llvm/IR/Intrinsics.td

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

17831784
// Coroutine Manipulation Intrinsics.
17841785

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); }
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 is not 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();

0 commit comments

Comments
 (0)