Skip to content

Commit eb1b356

Browse files
[Clang] Introduce [[clang::coro_await_elidable]]
1 parent 971a1ac commit eb1b356

25 files changed

+373
-130
lines changed

clang/include/clang/AST/ExprCXX.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5074,18 +5074,19 @@ class CoroutineSuspendExpr : public Expr {
50745074
enum SubExpr { Operand, Common, Ready, Suspend, Resume, Count };
50755075

50765076
Stmt *SubExprs[SubExpr::Count];
5077-
OpaqueValueExpr *OpaqueValue = nullptr;
5077+
OpaqueValueExpr *CommonExprOpaqueValue = nullptr;
5078+
OpaqueValueExpr *InplaceCallOpaqueValue = nullptr;
50785079

50795080
public:
50805081
// These types correspond to the three C++ 'await_suspend' return variants
50815082
enum class SuspendReturnType { SuspendVoid, SuspendBool, SuspendHandle };
50825083

50835084
CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Operand,
50845085
Expr *Common, Expr *Ready, Expr *Suspend, Expr *Resume,
5085-
OpaqueValueExpr *OpaqueValue)
5086+
OpaqueValueExpr *CommonExprOpaqueValue)
50865087
: Expr(SC, Resume->getType(), Resume->getValueKind(),
50875088
Resume->getObjectKind()),
5088-
KeywordLoc(KeywordLoc), OpaqueValue(OpaqueValue) {
5089+
KeywordLoc(KeywordLoc), CommonExprOpaqueValue(CommonExprOpaqueValue) {
50895090
SubExprs[SubExpr::Operand] = Operand;
50905091
SubExprs[SubExpr::Common] = Common;
50915092
SubExprs[SubExpr::Ready] = Ready;
@@ -5120,7 +5121,16 @@ class CoroutineSuspendExpr : public Expr {
51205121
}
51215122

51225123
/// getOpaqueValue - Return the opaque value placeholder.
5123-
OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }
5124+
OpaqueValueExpr *getCommonExprOpaqueValue() const {
5125+
return CommonExprOpaqueValue;
5126+
}
5127+
5128+
OpaqueValueExpr *getInplaceCallOpaqueValue() const {
5129+
return InplaceCallOpaqueValue;
5130+
}
5131+
void setInplaceCallOpaqueValue(OpaqueValueExpr *E) {
5132+
InplaceCallOpaqueValue = E;
5133+
}
51245134

51255135
Expr *getReadyExpr() const {
51265136
return static_cast<Expr*>(SubExprs[SubExpr::Ready]);
@@ -5186,9 +5196,9 @@ class CoawaitExpr : public CoroutineSuspendExpr {
51865196
public:
51875197
CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Common,
51885198
Expr *Ready, Expr *Suspend, Expr *Resume,
5189-
OpaqueValueExpr *OpaqueValue, bool IsImplicit = false)
5199+
OpaqueValueExpr *CommonExprOpaqueValue, bool IsImplicit = false)
51905200
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Common,
5191-
Ready, Suspend, Resume, OpaqueValue) {
5201+
Ready, Suspend, Resume, CommonExprOpaqueValue) {
51925202
CoawaitBits.IsImplicit = IsImplicit;
51935203
}
51945204

@@ -5267,9 +5277,9 @@ class CoyieldExpr : public CoroutineSuspendExpr {
52675277
public:
52685278
CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Common,
52695279
Expr *Ready, Expr *Suspend, Expr *Resume,
5270-
OpaqueValueExpr *OpaqueValue)
5280+
OpaqueValueExpr *CommonExprOpaqueValue)
52715281
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Common,
5272-
Ready, Suspend, Resume, OpaqueValue) {}
5282+
Ready, Suspend, Resume, CommonExprOpaqueValue) {}
52735283
CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand,
52745284
Expr *Common)
52755285
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand,

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,14 @@ def CoroDisableLifetimeBound : InheritableAttr {
12201220
let SimpleHandler = 1;
12211221
}
12221222

1223+
def CoroAwaitElidable : InheritableAttr {
1224+
let Spellings = [Clang<"coro_await_elidable">];
1225+
let Subjects = SubjectList<[CXXRecord]>;
1226+
let LangOpts = [CPlusPlus];
1227+
let Documentation = [CoroAwaitElidableDoc];
1228+
let SimpleHandler = 1;
1229+
}
1230+
12231231
// OSObject-based attributes.
12241232
def OSConsumed : InheritableParamAttr {
12251233
let Spellings = [Clang<"os_consumed">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8119,6 +8119,33 @@ but do not pass them to the underlying coroutine or pass them by value.
81198119
}];
81208120
}
81218121

8122+
def CoroAwaitElidableDoc : Documentation {
8123+
let Category = DocCatDecl;
8124+
let Content = [{
8125+
The ``[[clang::coro_await_elidable]]`` is a class attribute which can be applied
8126+
to a coroutine return type.
8127+
8128+
When a coroutine function that returns such a type calls another coroutine function,
8129+
the compiler performs heap allocation elision when the call to the coroutine function
8130+
is immediately co_awaited as a prvalue.
8131+
8132+
Example:
8133+
```
8134+
class [[clang::coro_await_elidable]] Task { ... };
8135+
8136+
Task foo();
8137+
Task bar() {
8138+
co_await foo(); // foo()'s coroutine frame on this line is elidable
8139+
auto t = foo(); // foo()'s coroutine frame on this line is NOT elidable
8140+
co_await t;
8141+
}
8142+
```
8143+
The behavior is undefined if the caller coroutine is destroyed earlier than the
8144+
callee coroutine.
8145+
8146+
}];
8147+
}
8148+
81228149
def CountedByDocs : Documentation {
81238150
let Category = DocCatField;
81248151
let Content = [{
@@ -8278,4 +8305,3 @@ Declares that a function potentially allocates heap memory, and prevents any pot
82788305
of ``nonallocating`` by the compiler.
82798306
}];
82808307
}
8281-

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,8 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
11631163
}
11641164

11651165
RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
1166-
ReturnValueSlot ReturnValue) {
1166+
ReturnValueSlot ReturnValue,
1167+
llvm::CallBase **CallOrInvoke) {
11671168
const auto *BPT = E->getCallee()->getType()->castAs<BlockPointerType>();
11681169
llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee());
11691170
llvm::Type *GenBlockTy = CGM.getGenericBlockLiteralType();
@@ -1220,7 +1221,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
12201221
CGCallee Callee(CGCalleeInfo(), Func);
12211222

12221223
// And call the block.
1223-
return EmitCall(FnInfo, Callee, ReturnValue, Args);
1224+
return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke);
12241225
}
12251226

12261227
Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {

clang/lib/CodeGen/CGCUDARuntime.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ CGCUDARuntime::~CGCUDARuntime() {}
2525

2626
RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
2727
const CUDAKernelCallExpr *E,
28-
ReturnValueSlot ReturnValue) {
28+
ReturnValueSlot ReturnValue,
29+
llvm::CallBase **CallOrInvoke) {
2930
llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok");
3031
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end");
3132

@@ -35,7 +36,7 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
3536

3637
eval.begin(CGF);
3738
CGF.EmitBlock(ConfigOKBlock);
38-
CGF.EmitSimpleCallExpr(E, ReturnValue);
39+
CGF.EmitSimpleCallExpr(E, ReturnValue, CallOrInvoke);
3940
CGF.EmitBranch(ContBlock);
4041

4142
CGF.EmitBlock(ContBlock);

clang/lib/CodeGen/CGCUDARuntime.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/IR/GlobalValue.h"
2222

2323
namespace llvm {
24+
class CallBase;
2425
class Function;
2526
class GlobalVariable;
2627
}
@@ -82,9 +83,10 @@ class CGCUDARuntime {
8283
CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {}
8384
virtual ~CGCUDARuntime();
8485

85-
virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
86-
const CUDAKernelCallExpr *E,
87-
ReturnValueSlot ReturnValue);
86+
virtual RValue
87+
EmitCUDAKernelCallExpr(CodeGenFunction &CGF, const CUDAKernelCallExpr *E,
88+
ReturnValueSlot ReturnValue,
89+
llvm::CallBase **CallOrInvoke = nullptr);
8890

8991
/// Emits a kernel launch stub.
9092
virtual void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) = 0;

clang/lib/CodeGen/CGCXXABI.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,11 @@ class CGCXXABI {
485485
llvm::PointerUnion<const CXXDeleteExpr *, const CXXMemberCallExpr *>;
486486

487487
/// Emit the ABI-specific virtual destructor call.
488-
virtual llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
489-
const CXXDestructorDecl *Dtor,
490-
CXXDtorType DtorType,
491-
Address This,
492-
DeleteOrMemberCallExpr E) = 0;
488+
virtual llvm::Value *
489+
EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
490+
CXXDtorType DtorType, Address This,
491+
DeleteOrMemberCallExpr E,
492+
llvm::CallBase **CallOrInvoke) = 0;
493493

494494
virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
495495
GlobalDecl GD,

clang/lib/CodeGen/CGClass.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,15 +2192,11 @@ static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
21922192
return true;
21932193
}
21942194

2195-
void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
2196-
CXXCtorType Type,
2197-
bool ForVirtualBase,
2198-
bool Delegating,
2199-
Address This,
2200-
CallArgList &Args,
2201-
AggValueSlot::Overlap_t Overlap,
2202-
SourceLocation Loc,
2203-
bool NewPointerIsChecked) {
2195+
void CodeGenFunction::EmitCXXConstructorCall(
2196+
const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase,
2197+
bool Delegating, Address This, CallArgList &Args,
2198+
AggValueSlot::Overlap_t Overlap, SourceLocation Loc,
2199+
bool NewPointerIsChecked, llvm::CallBase **CallOrInvoke) {
22042200
const CXXRecordDecl *ClassDecl = D->getParent();
22052201

22062202
if (!NewPointerIsChecked)
@@ -2248,7 +2244,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
22482244
const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
22492245
Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
22502246
CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type));
2251-
EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc);
2247+
EmitCall(Info, Callee, ReturnValueSlot(), Args, CallOrInvoke, false, Loc);
22522248

22532249
// Generate vtable assumptions if we're constructing a complete object
22542250
// with a vtable. We don't do this for base subobjects for two reasons:

clang/lib/CodeGen/CGCoroutine.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212

1313
#include "CGCleanup.h"
1414
#include "CodeGenFunction.h"
15-
#include "llvm/ADT/ScopeExit.h"
15+
#include "clang/AST/ExprCXX.h"
1616
#include "clang/AST/StmtCXX.h"
1717
#include "clang/AST/StmtVisitor.h"
18+
#include "llvm/ADT/ScopeExit.h"
19+
#include "llvm/IR/Intrinsics.h"
1820

1921
using namespace clang;
2022
using namespace CodeGen;
@@ -223,12 +225,22 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
223225
CoroutineSuspendExpr const &S,
224226
AwaitKind Kind, AggValueSlot aggSlot,
225227
bool ignoreResult, bool forLValue) {
226-
auto *E = S.getCommonExpr();
228+
auto &Builder = CGF.Builder;
227229

228-
auto CommonBinder =
229-
CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
230-
auto UnbindCommonOnExit =
231-
llvm::make_scope_exit([&] { CommonBinder.unbind(CGF); });
230+
// If S.getInplaceCallOpaqueValue() is null, we don't have a nested opaque
231+
// value for common expression.
232+
std::optional<CodeGenFunction::OpaqueValueMapping> OperandMapping;
233+
if (auto *CallOV = S.getInplaceCallOpaqueValue()) {
234+
auto *CE = cast<CallExpr>(CallOV->getSourceExpr());
235+
llvm::CallBase *CallOrInvoke = nullptr;
236+
LValue CallResult = CGF.EmitCallExprLValue(CE, &CallOrInvoke);
237+
if (CallOrInvoke)
238+
CallOrInvoke->addFnAttr(llvm::Attribute::CoroMustElide);
239+
240+
OperandMapping.emplace(CGF, CallOV, CallResult);
241+
}
242+
CodeGenFunction::OpaqueValueMapping BindCommon(CGF,
243+
S.getCommonExprOpaqueValue());
232244

233245
auto Prefix = buildSuspendPrefixStr(Coro, Kind);
234246
BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready"));
@@ -241,7 +253,6 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
241253
// Otherwise, emit suspend logic.
242254
CGF.EmitBlock(SuspendBlock);
243255

244-
auto &Builder = CGF.Builder;
245256
llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save);
246257
auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy);
247258
auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr});
@@ -256,7 +267,8 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
256267

257268
SmallVector<llvm::Value *, 3> SuspendIntrinsicCallArgs;
258269
SuspendIntrinsicCallArgs.push_back(
259-
CGF.getOrCreateOpaqueLValueMapping(S.getOpaqueValue()).getPointer(CGF));
270+
CGF.getOrCreateOpaqueLValueMapping(S.getCommonExprOpaqueValue())
271+
.getPointer(CGF));
260272

261273
SuspendIntrinsicCallArgs.push_back(CGF.CurCoro.Data->CoroBegin);
262274
SuspendIntrinsicCallArgs.push_back(SuspendWrapper);
@@ -455,7 +467,7 @@ CodeGenFunction::generateAwaitSuspendWrapper(Twine const &CoroName,
455467
Builder.CreateLoad(GetAddrOfLocalVar(&FrameDecl));
456468

457469
auto AwaiterBinder = CodeGenFunction::OpaqueValueMappingData::bind(
458-
*this, S.getOpaqueValue(), AwaiterLValue);
470+
*this, S.getCommonExprOpaqueValue(), AwaiterLValue);
459471

460472
auto *SuspendRet = EmitScalarExpr(S.getSuspendExpr());
461473

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5443,24 +5443,25 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
54435443
//===--------------------------------------------------------------------===//
54445444

54455445
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
5446-
ReturnValueSlot ReturnValue) {
5446+
ReturnValueSlot ReturnValue,
5447+
llvm::CallBase **CallOrInvoke) {
54475448
// Builtins never have block type.
54485449
if (E->getCallee()->getType()->isBlockPointerType())
5449-
return EmitBlockCallExpr(E, ReturnValue);
5450+
return EmitBlockCallExpr(E, ReturnValue, CallOrInvoke);
54505451

54515452
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
5452-
return EmitCXXMemberCallExpr(CE, ReturnValue);
5453+
return EmitCXXMemberCallExpr(CE, ReturnValue, CallOrInvoke);
54535454

54545455
if (const auto *CE = dyn_cast<CUDAKernelCallExpr>(E))
5455-
return EmitCUDAKernelCallExpr(CE, ReturnValue);
5456+
return EmitCUDAKernelCallExpr(CE, ReturnValue, CallOrInvoke);
54565457

54575458
// A CXXOperatorCallExpr is created even for explicit object methods, but
54585459
// these should be treated like static function call.
54595460
if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
54605461
if (const auto *MD =
54615462
dyn_cast_if_present<CXXMethodDecl>(CE->getCalleeDecl());
54625463
MD && MD->isImplicitObjectMemberFunction())
5463-
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
5464+
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue, CallOrInvoke);
54645465

54655466
CGCallee callee = EmitCallee(E->getCallee());
54665467

@@ -5473,14 +5474,17 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
54735474
return EmitCXXPseudoDestructorExpr(callee.getPseudoDestructorExpr());
54745475
}
54755476

5476-
return EmitCall(E->getCallee()->getType(), callee, E, ReturnValue);
5477+
return EmitCall(E->getCallee()->getType(), callee, E, ReturnValue,
5478+
/*Chain=*/nullptr, CallOrInvoke);
54775479
}
54785480

54795481
/// Emit a CallExpr without considering whether it might be a subclass.
54805482
RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
5481-
ReturnValueSlot ReturnValue) {
5483+
ReturnValueSlot ReturnValue,
5484+
llvm::CallBase **CallOrInvoke) {
54825485
CGCallee Callee = EmitCallee(E->getCallee());
5483-
return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue);
5486+
return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue,
5487+
/*Chain=*/nullptr, CallOrInvoke);
54845488
}
54855489

54865490
// Detect the unusual situation where an inline version is shadowed by a
@@ -5684,8 +5688,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
56845688
llvm_unreachable("bad evaluation kind");
56855689
}
56865690

5687-
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
5688-
RValue RV = EmitCallExpr(E);
5691+
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E,
5692+
llvm::CallBase **CallOrInvoke) {
5693+
RValue RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke);
56895694

56905695
if (!RV.isScalar())
56915696
return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
@@ -5808,9 +5813,11 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
58085813
AlignmentSource::Decl);
58095814
}
58105815

5811-
RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee,
5812-
const CallExpr *E, ReturnValueSlot ReturnValue,
5813-
llvm::Value *Chain) {
5816+
RValue CodeGenFunction::EmitCall(QualType CalleeType,
5817+
const CGCallee &OrigCallee, const CallExpr *E,
5818+
ReturnValueSlot ReturnValue,
5819+
llvm::Value *Chain,
5820+
llvm::CallBase **CallOrInvoke) {
58145821
// Get the actual function type. The callee type will always be a pointer to
58155822
// function type or a block pointer type.
58165823
assert(CalleeType->isFunctionPointerType() &&
@@ -6030,8 +6037,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
60306037
Address(Handle, Handle->getType(), CGM.getPointerAlign()));
60316038
Callee.setFunctionPointer(Stub);
60326039
}
6033-
llvm::CallBase *CallOrInvoke = nullptr;
6034-
RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke,
6040+
llvm::CallBase *LocalCallOrInvoke = nullptr;
6041+
RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &LocalCallOrInvoke,
60356042
E == MustTailCall, E->getExprLoc());
60366043

60376044
// Generate function declaration DISuprogram in order to be used
@@ -6040,11 +6047,13 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
60406047
if (auto *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
60416048
FunctionArgList Args;
60426049
QualType ResTy = BuildFunctionArgList(CalleeDecl, Args);
6043-
DI->EmitFuncDeclForCallSite(CallOrInvoke,
6050+
DI->EmitFuncDeclForCallSite(LocalCallOrInvoke,
60446051
DI->getFunctionType(CalleeDecl, ResTy, Args),
60456052
CalleeDecl);
60466053
}
60476054
}
6055+
if (CallOrInvoke)
6056+
*CallOrInvoke = LocalCallOrInvoke;
60486057

60496058
return Call;
60506059
}

0 commit comments

Comments
 (0)