Skip to content

Commit 3e24f4b

Browse files
[CIR] Emit CIR builtins: coroAlloc, coroBegin, and coroSize
1 parent 228dae7 commit 3e24f4b

File tree

6 files changed

+112
-11
lines changed

6 files changed

+112
-11
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,9 @@ struct MissingFeatures {
149149
static bool zeroSizeRecordMembers() { return false; }
150150

151151
// Coroutines
152-
static bool coroAllocBuiltinCall() { return false; }
153-
static bool coroBeginBuiltinCall() { return false; }
154152
static bool coroEndBuiltinCall() { return false; }
155-
static bool coroSizeBuiltinCall() { return false; }
156153
static bool coroutineFrame() { return false; }
154+
static bool emitBodyAndFallthrough() { return false; }
157155

158156
// Various handling of deferred processing in CIRGenModule.
159157
static bool cgmRelease() { return false; }

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
449449
}
450450
case Builtin::BI__builtin_coro_free:
451451
case Builtin::BI__builtin_coro_size: {
452-
cgm.errorNYI(e->getSourceRange(),
453-
"BI__builtin_coro_free, BI__builtin_coro_size NYI");
454-
assert(!cir::MissingFeatures::coroSizeBuiltinCall());
455-
return getUndefRValue(e->getType());
452+
GlobalDecl gd{fd};
453+
mlir::Type ty = cgm.getTypes().getFunctionType(
454+
cgm.getTypes().arrangeGlobalDeclaration(gd));
455+
const auto *nd = cast<NamedDecl>(gd.getDecl());
456+
cir::FuncOp fnOp =
457+
cgm.getOrCreateCIRFunction(nd->getName(), ty, gd, /*ForVTable=*/false,
458+
/*DontDefer=*/false);
459+
fnOp.setBuiltin(true);
460+
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp), e,
461+
returnValue);
456462
}
457463
}
458464

clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/AST/StmtCXX.h"
1616
#include "clang/Basic/TargetInfo.h"
1717
#include "clang/CIR/Dialect/IR/CIRTypes.h"
18+
#include "clang/CIR/MissingFeatures.h"
1819

1920
using namespace clang;
2021
using namespace clang::CIRGen;
@@ -23,6 +24,9 @@ struct clang::CIRGen::CGCoroData {
2324
// Stores the __builtin_coro_id emitted in the function so that we can supply
2425
// it as the first argument to other builtins.
2526
cir::CallOp coroId = nullptr;
27+
28+
// Stores the result of __builtin_coro_begin call.
29+
mlir::Value coroBegin = nullptr;
2630
};
2731

2832
// Defining these here allows to keep CGCoroData private to this file.
@@ -63,6 +67,48 @@ cir::CallOp CIRGenFunction::emitCoroIDBuiltinCall(mlir::Location loc,
6367
nullPtr, nullPtr, nullPtr});
6468
}
6569

70+
cir::CallOp CIRGenFunction::emitCoroAllocBuiltinCall(mlir::Location loc) {
71+
cir::BoolType boolTy = builder.getBoolTy();
72+
cir::IntType int32Ty = builder.getUInt32Ty();
73+
74+
mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroAlloc);
75+
76+
cir::FuncOp fnOp;
77+
if (!builtin) {
78+
fnOp = cgm.createCIRBuiltinFunction(loc, cgm.builtinCoroAlloc,
79+
cir::FuncType::get({int32Ty}, boolTy),
80+
/*FD=*/nullptr);
81+
assert(fnOp && "should always succeed");
82+
} else {
83+
fnOp = cast<cir::FuncOp>(builtin);
84+
}
85+
86+
return builder.createCallOp(
87+
loc, fnOp, mlir::ValueRange{curCoro.data->coroId.getResult()});
88+
}
89+
90+
cir::CallOp
91+
CIRGenFunction::emitCoroBeginBuiltinCall(mlir::Location loc,
92+
mlir::Value coroframeAddr) {
93+
cir::IntType int32Ty = builder.getUInt32Ty();
94+
mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroBegin);
95+
96+
cir::FuncOp fnOp;
97+
if (!builtin) {
98+
fnOp = cgm.createCIRBuiltinFunction(
99+
loc, cgm.builtinCoroBegin,
100+
cir::FuncType::get({int32Ty, VoidPtrTy}, VoidPtrTy),
101+
/*FD=*/nullptr);
102+
assert(fnOp && "should always succeed");
103+
} else {
104+
fnOp = cast<cir::FuncOp>(builtin);
105+
}
106+
107+
return builder.createCallOp(
108+
loc, fnOp,
109+
mlir::ValueRange{curCoro.data->coroId.getResult(), coroframeAddr});
110+
}
111+
66112
mlir::LogicalResult
67113
CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
68114
mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
@@ -73,10 +119,39 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
73119
cir::CallOp coroId = emitCoroIDBuiltinCall(openCurlyLoc, nullPtrCst);
74120
createCoroData(*this, curCoro, coroId);
75121

76-
assert(!cir::MissingFeatures::coroAllocBuiltinCall());
77-
78-
assert(!cir::MissingFeatures::coroBeginBuiltinCall());
122+
// Backend is allowed to elide memory allocations, to help it, emit
123+
// auto mem = coro.alloc() ? 0 : ... allocation code ...;
124+
cir::CallOp coroAlloc = emitCoroAllocBuiltinCall(openCurlyLoc);
125+
126+
// Initialize address of coroutine frame to null
127+
CanQualType astVoidPtrTy = cgm.getASTContext().VoidPtrTy;
128+
mlir::Type allocaTy = convertTypeForMem(astVoidPtrTy);
129+
Address coroFrame =
130+
createTempAlloca(allocaTy, getContext().getTypeAlignInChars(astVoidPtrTy),
131+
openCurlyLoc, "__coro_frame_addr",
132+
/*ArraySize=*/nullptr);
133+
134+
mlir::Value storeAddr = coroFrame.getPointer();
135+
builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
136+
cir::IfOp::create(
137+
builder, openCurlyLoc, coroAlloc.getResult(),
138+
/*withElseRegion=*/false,
139+
/*thenBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
140+
builder.CIRBaseBuilderTy::createStore(
141+
loc, emitScalarExpr(s.getAllocate()), storeAddr);
142+
builder.create<cir::YieldOp>(loc);
143+
});
144+
curCoro.data->coroBegin =
145+
emitCoroBeginBuiltinCall(
146+
openCurlyLoc,
147+
builder.create<cir::LoadOp>(openCurlyLoc, allocaTy, storeAddr))
148+
.getResult();
149+
150+
// Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
151+
if (s.getReturnStmtOnAllocFailure())
152+
cgm.errorNYI("NYI");
79153

80154
assert(!cir::MissingFeatures::generateDebugInfo());
155+
assert(!cir::MissingFeatures::emitBodyAndFallthrough());
81156
return mlir::success();
82157
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,9 @@ class CIRGenFunction : public CIRGenTypeCache {
12521252
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s);
12531253
cir::CallOp emitCoroEndBuiltinCall(mlir::Location loc, mlir::Value nullPtr);
12541254
cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr);
1255+
cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc);
1256+
cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc,
1257+
mlir::Value coroframeAddr);
12551258

12561259
void emitDestroy(Address addr, QualType type, Destroyer *destroyer);
12571260

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@ class CIRGenModule : public CIRGenTypeCache {
496496
bool assumeConvergent = false);
497497

498498
static constexpr const char *builtinCoroId = "__builtin_coro_id";
499+
static constexpr const char *builtinCoroAlloc = "__builtin_coro_alloc";
500+
static constexpr const char *builtinCoroBegin = "__builtin_coro_begin";
499501

500502
/// Given a builtin id for a function like "__builtin_fabsf", return a
501503
/// Function* for "fabsf".

clang/test/CIR/CodeGen/coro-task.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ co_invoke_fn co_invoke;
106106
// CIR-NEXT: cir.global external @_ZN5folly4coro9co_invokeE = #cir.zero : !rec_folly3A3Acoro3A3Aco_invoke_fn
107107

108108
// CIR: cir.func builtin private @__builtin_coro_id(!u32i, !cir.ptr<!void>, !cir.ptr<!void>, !cir.ptr<!void>) -> !u32i
109+
// CIR: cir.func builtin private @__builtin_coro_alloc(!u32i) -> !cir.bool
110+
// CIR: cir.func builtin private @__builtin_coro_size() -> !u64i
111+
// CIR: cir.func builtin private @__builtin_coro_begin(!u32i, !cir.ptr<!void>) -> !cir.ptr<!void>
109112

110113
using VoidTask = folly::coro::Task<void>;
111114

@@ -114,10 +117,24 @@ VoidTask silly_task() {
114117
}
115118

116119
// CIR: cir.func coroutine dso_local @_Z10silly_taskv() -> ![[VoidTask]]
117-
// CHECK: %[[#VoidTaskAddr:]] = cir.alloca ![[VoidTask]], {{.*}}, ["__retval"]
120+
// CIR: %[[VoidTaskAddr:.*]] = cir.alloca ![[VoidTask]], {{.*}}, ["__retval"]
121+
// CIR: %[[SavedFrameAddr:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["__coro_frame_addr"]
118122

119123
// Get coroutine id with __builtin_coro_id.
120124

121125
// CIR: %[[NullPtr:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
122126
// CIR: %[[Align:.*]] = cir.const #cir.int<16> : !u32i
123127
// CIR: %[[CoroId:.*]] = cir.call @__builtin_coro_id(%[[Align]], %[[NullPtr]], %[[NullPtr]], %[[NullPtr]])
128+
129+
// Perform allocation calling operator 'new' depending on __builtin_coro_alloc and
130+
// call __builtin_coro_begin for the final coroutine frame address.
131+
132+
// CIR: %[[ShouldAlloc:.*]] = cir.call @__builtin_coro_alloc(%[[CoroId]]) : (!u32i) -> !cir.bool
133+
// CIR: cir.store{{.*}} %[[NullPtr]], %[[SavedFrameAddr]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
134+
// CIR: cir.if %[[ShouldAlloc]] {
135+
// CIR: %[[CoroSize:.*]] = cir.call @__builtin_coro_size() : () -> !u64i
136+
// CIR: %[[AllocAddr:.*]] = cir.call @_Znwm(%[[CoroSize]]) : (!u64i) -> !cir.ptr<!void>
137+
// CIR: cir.store{{.*}} %[[AllocAddr]], %[[SavedFrameAddr]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
138+
// CIR: }
139+
// CIR: %[[Load0:.*]] = cir.load{{.*}} %[[SavedFrameAddr]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
140+
// CIR: %[[CoroFrameAddr:.*]] = cir.call @__builtin_coro_begin(%[[CoroId]], %[[Load0]])

0 commit comments

Comments
 (0)