[clang] [CIR] Initial support for emitting coroutine body (PR #161616)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 2 16:46:31 PDT 2025
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/161616
>From 860bfd20d7e05005a2d0fdea96908d99a9e8fcfc Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 1 Oct 2025 21:09:53 -0500
Subject: [PATCH 1/4] [CIR] Initial support for emitting coroutine body
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 17 +++
clang/include/clang/CIR/MissingFeatures.h | 7 ++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 25 ++++
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 85 +++++++++++++
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 3 +
clang/lib/CIR/CodeGen/CIRGenFunction.h | 18 +++
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 9 ++
clang/lib/CIR/CodeGen/CIRGenModule.h | 7 ++
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 1 +
clang/lib/CIR/CodeGen/CMakeLists.txt | 1 +
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 13 ++
clang/test/CIR/CodeGen/coro-task.cpp | 123 +++++++++++++++++++
12 files changed, 309 insertions(+)
create mode 100644 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
create mode 100644 clang/test/CIR/CodeGen/coro-task.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0a78492aa9a86..3c79d9c501a39 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2341,6 +2341,12 @@ def CIR_FuncOp : CIR_Op<"func", [
The function linkage information is specified by `linkage`, as defined by
`GlobalLinkageKind` attribute.
+ A compiler builtin function must be marked as `builtin` for further
+ processing when lowering from CIR.
+
+ The `coroutine` keyword is used to mark coroutine function, which requires
+ at least one `cir.await` instruction to be used in its body.
+
The `lambda` translates to a C++ `operator()` that implements a lambda, this
allow callsites to make certain assumptions about the real function nature
when writing analysis.
@@ -2362,11 +2368,22 @@ def CIR_FuncOp : CIR_Op<"func", [
// Linkage information
cir.func linkonce_odr @some_method(...)
```
+ // Builtin function
+ cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool
+ // Coroutine
+ cir.func coroutine @_Z10silly_taskv() -> !CoroTask {
+ ...
+ cir.await(...)
+ ...
+ }
+ ```
}];
let arguments = (ins SymbolNameAttr:$sym_name,
CIR_VisibilityAttr:$global_visibility,
TypeAttrOf<CIR_FuncType>:$function_type,
+ UnitAttr:$builtin,
+ UnitAttr:$coroutine,
UnitAttr:$lambda,
UnitAttr:$no_proto,
UnitAttr:$dso_local,
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 7a6c084f51cd7..1d9f37ea295f4 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -137,6 +137,13 @@ struct MissingFeatures {
static bool recordZeroInitPadding() { return false; }
static bool zeroSizeRecordMembers() { return false; }
+ // Coroutines
+ static bool coroAllocBuiltinCall() { return false; }
+ static bool coroBeginBuiltinCall() { return false; }
+ static bool coroEndBuiltinCall() { return false; }
+ static bool coroSizeBuiltinCall() { return false; }
+ static bool coroutineFrame() { return false; }
+
// Various handling of deferred processing in CIRGenModule.
static bool cgmRelease() { return false; }
static bool deferredVtables() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index cf17de144f4d9..512e1b2aa0e86 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -428,6 +428,31 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
return emitUnaryFPBuiltin<cir::ATanOp>(*this, *e);
case Builtin::BI__builtin_elementwise_cos:
return emitUnaryFPBuiltin<cir::CosOp>(*this, *e);
+ case Builtin::BI__builtin_coro_id:
+ case Builtin::BI__builtin_coro_promise:
+ case Builtin::BI__builtin_coro_resume:
+ case Builtin::BI__builtin_coro_noop:
+ case Builtin::BI__builtin_coro_destroy:
+ case Builtin::BI__builtin_coro_done:
+ case Builtin::BI__builtin_coro_alloc:
+ case Builtin::BI__builtin_coro_begin:
+ case Builtin::BI__builtin_coro_end:
+ case Builtin::BI__builtin_coro_suspend:
+ case Builtin::BI__builtin_coro_align:
+ llvm_unreachable("BI__builtin_coro_id like NYI");
+
+ case Builtin::BI__builtin_coro_frame: {
+ cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_frame NYI");
+ assert(!cir::MissingFeatures::coroutineFrame());
+ return getUndefRValue(e->getType());
+ }
+ case Builtin::BI__builtin_coro_free:
+ case Builtin::BI__builtin_coro_size: {
+ cgm.errorNYI(e->getSourceRange(),
+ "BI__builtin_coro_free, BI__builtin_coro_size NYI");
+ assert(!cir::MissingFeatures::coroSizeBuiltinCall());
+ return getUndefRValue(e->getType());
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
new file mode 100644
index 0000000000000..ee43c221c3cd6
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -0,0 +1,85 @@
+//===----- CGCoroutine.cpp - Emit CIR Code for C++ coroutines -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with C++ code generation of coroutines.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenFunction.h"
+#include "mlir/Support/LLVM.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+struct clang::CIRGen::CGCoroData {
+ // Stores the __builtin_coro_id emitted in the function so that we can supply
+ // it as the first argument to other builtins.
+ cir::CallOp coroId = nullptr;
+};
+
+// Defining these here allows to keep CGCoroData private to this file.
+CIRGenFunction::CGCoroInfo::CGCoroInfo() {}
+CIRGenFunction::CGCoroInfo::~CGCoroInfo() {}
+
+static void createCoroData(CIRGenFunction &cgf,
+ CIRGenFunction::CGCoroInfo &curCoro,
+ cir::CallOp coroId) {
+ if (curCoro.data) {
+ llvm_unreachable("EmitCoroutineBodyStatement called twice?");
+ return;
+ }
+
+ curCoro.data = std::unique_ptr<CGCoroData>(new CGCoroData);
+ curCoro.data->coroId = coroId;
+}
+
+cir::CallOp CIRGenFunction::emitCoroIDBuiltinCall(mlir::Location loc,
+ mlir::Value nullPtr) {
+ cir::IntType int32Ty = builder.getUInt32Ty();
+
+ const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
+ unsigned newAlign = ti.getNewAlign() / ti.getCharWidth();
+
+ mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroId);
+
+ cir::FuncOp fnOp;
+ if (!builtin) {
+ fnOp = cgm.createCIRBuiltinFunction(
+ loc, cgm.builtinCoroId,
+ cir::FuncType::get({int32Ty, VoidPtrTy, VoidPtrTy, VoidPtrTy}, int32Ty),
+ /*FD=*/nullptr);
+ assert(fnOp && "should always succeed");
+ } else
+ fnOp = cast<cir::FuncOp>(builtin);
+
+ return builder.createCallOp(loc, fnOp,
+ mlir::ValueRange{builder.getUInt32(newAlign, loc),
+ nullPtr, nullPtr, nullPtr});
+}
+
+mlir::LogicalResult
+CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
+ mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
+ cir::ConstantOp nullPtrCst = builder.getNullPtr(VoidPtrTy, openCurlyLoc);
+
+ cir::FuncOp fn = curFn;
+ assert(fn && "other callables are NYI");
+ fn.setCoroutine(true);
+ cir::CallOp coroId = emitCoroIDBuiltinCall(openCurlyLoc, nullPtrCst);
+ createCoroData(*this, curCoro, coroId);
+
+ assert(!cir::MissingFeatures::coroAllocBuiltinCall());
+
+ assert(!cir::MissingFeatures::coroBeginBuiltinCall());
+
+ assert(!cir::MissingFeatures::generateDebugInfo());
+ return mlir::success();
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index b26b4f2500579..27ee6decbed4d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -342,6 +342,9 @@ void CIRGenFunction::LexicalScope::cleanup() {
cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
CIRGenBuilderTy &builder = cgf.getBuilder();
+ // If we are on a coroutine, add the coro_end builtin call.
+ assert(!cir::MissingFeatures::coroEndBuiltinCall());
+
auto fn = dyn_cast<cir::FuncOp>(cgf.curFn);
assert(fn && "emitReturn from non-function");
if (!fn.getFunctionType().hasVoidReturn()) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c0ed8b4006ec5..aeedd0ce05fe8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -47,6 +47,8 @@ class LoopOp;
namespace clang::CIRGen {
+struct CGCoroData;
+
class CIRGenFunction : public CIRGenTypeCache {
public:
CIRGenModule &cgm;
@@ -66,6 +68,18 @@ class CIRGenFunction : public CIRGenTypeCache {
/// The compiler-generated variable that holds the return value.
std::optional<mlir::Value> fnRetAlloca;
+ // Holds coroutine data if the current function is a coroutine. We use a
+ // wrapper to manage its lifetime, so that we don't have to define CGCoroData
+ // in this header.
+ struct CGCoroInfo {
+ std::unique_ptr<CGCoroData> data;
+ CGCoroInfo();
+ ~CGCoroInfo();
+ };
+ CGCoroInfo curCoro;
+
+ bool isCoroutine() const { return curCoro.data != nullptr; }
+
/// The temporary alloca to hold the return value. This is
/// invalid iff the function has no return value.
Address returnValue = Address::invalid();
@@ -1174,6 +1188,10 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitConstructorBody(FunctionArgList &args);
+ mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s);
+ cir::CallOp emitCoroEndBuiltinCall(mlir::Location loc, mlir::Value nullPtr);
+ cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr);
+
void emitDestroy(Address addr, QualType type, Destroyer *destroyer);
void emitDestructorBody(FunctionArgList &args);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 2bd2729f0b0fb..f5facfa970253 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2065,6 +2065,15 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
return func;
}
+cir::FuncOp
+CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,
+ cir::FuncType ty,
+ const clang::FunctionDecl *fd) {
+ cir::FuncOp fnOp = createCIRFunction(loc, name, ty, fd);
+ fnOp.setBuiltin(true);
+ return fnOp;
+}
+
mlir::SymbolTable::Visibility
CIRGenModule::getMLIRVisibility(cir::GlobalOp op) {
// MLIR doesn't accept public symbols declarations (only
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 2c4c6dd14e2ff..d252bc0379ef7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -473,6 +473,13 @@ class CIRGenModule : public CIRGenTypeCache {
cir::FuncType funcType,
const clang::FunctionDecl *funcDecl);
+ /// Create a CIR function with builtin attribute set.
+ cir::FuncOp createCIRBuiltinFunction(mlir::Location loc, llvm::StringRef name,
+ cir::FuncType ty,
+ const clang::FunctionDecl *fd);
+
+ static constexpr const char *builtinCoroId = "__builtin_coro_id";
+
/// Given a builtin id for a function like "__builtin_fabsf", return a
/// Function* for "fabsf".
cir::FuncOp getBuiltinLibFunction(const FunctionDecl *fd, unsigned builtinID);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 644c383693e37..0b8f8bfdfb046 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -197,6 +197,7 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
case Stmt::SEHLeaveStmtClass:
case Stmt::SYCLKernelCallStmtClass:
case Stmt::CoroutineBodyStmtClass:
+ return emitCoroutineBody(cast<CoroutineBodyStmt>(*s));
case Stmt::CoreturnStmtClass:
case Stmt::CXXTryStmtClass:
case Stmt::IndirectGotoStmtClass:
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 3ebf460f7d34c..36db4bd9bab25 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangCIR
CIRGenCall.cpp
CIRGenClass.cpp
CIRGenCleanup.cpp
+ CIRGenCoroutine.cpp
CIRGenCXX.cpp
CIRGenCXXABI.cpp
CIRGenBuiltin.cpp
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 6b5cc808e9a29..fba094f42414f 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1632,12 +1632,19 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
llvm::SMLoc loc = parser.getCurrentLocation();
mlir::Builder &builder = parser.getBuilder();
+ mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);
+ mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);
mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);
mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);
mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
mlir::StringAttr visibilityNameAttr = getGlobalVisibilityAttrName(state.name);
mlir::StringAttr dsoLocalNameAttr = getDsoLocalAttrName(state.name);
+ if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref())))
+ state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr());
+ if (::mlir::succeeded(
+ parser.parseOptionalKeyword(coroutineNameAttr.strref())))
+ state.addAttribute(coroutineNameAttr, parser.getBuilder().getUnitAttr());
if (::mlir::succeeded(parser.parseOptionalKeyword(lambdaNameAttr.strref())))
state.addAttribute(lambdaNameAttr, parser.getBuilder().getUnitAttr());
if (parser.parseOptionalKeyword(noProtoNameAttr).succeeded())
@@ -1747,6 +1754,12 @@ mlir::Region *cir::FuncOp::getCallableRegion() {
}
void cir::FuncOp::print(OpAsmPrinter &p) {
+ if (getBuiltin())
+ p << " builtin";
+
+ if (getCoroutine())
+ p << " coroutine";
+
if (getLambda())
p << " lambda";
diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp
new file mode 100644
index 0000000000000..1fc7d77be2bce
--- /dev/null
+++ b/clang/test/CIR/CodeGen/coro-task.cpp
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+
+namespace std {
+
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T &> { typedef T type; };
+template<typename T> struct remove_reference<T &&> { typedef T type; };
+
+template<typename T>
+typename remove_reference<T>::type &&move(T &&t) noexcept;
+
+template <class Ret, typename... T>
+struct coroutine_traits { using promise_type = typename Ret::promise_type; };
+
+template <class Promise = void>
+struct coroutine_handle {
+ static coroutine_handle from_address(void *) noexcept;
+};
+template <>
+struct coroutine_handle<void> {
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+ static coroutine_handle from_address(void *);
+};
+
+struct suspend_always {
+ bool await_ready() noexcept { return false; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
+};
+
+struct suspend_never {
+ bool await_ready() noexcept { return true; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
+};
+
+} // namespace std
+
+namespace folly {
+namespace coro {
+
+using std::suspend_always;
+using std::suspend_never;
+using std::coroutine_handle;
+
+using SemiFuture = int;
+
+template<class T>
+struct Task {
+ struct promise_type {
+ Task<T> get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_value(T);
+ void unhandled_exception();
+ auto yield_value(Task<T>) noexcept { return final_suspend(); }
+ };
+ bool await_ready() noexcept { return false; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ T await_resume();
+};
+
+template<>
+struct Task<void> {
+ struct promise_type {
+ Task<void> get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ void unhandled_exception() noexcept;
+ auto yield_value(Task<void>) noexcept { return final_suspend(); }
+ };
+ bool await_ready() noexcept { return false; }
+ void await_suspend(coroutine_handle<>) noexcept {}
+ void await_resume() noexcept {}
+ SemiFuture semi();
+};
+
+// FIXME: add CIRGen support here.
+// struct blocking_wait_fn {
+// template <typename T>
+// T operator()(Task<T>&& awaitable) const {
+// return T();
+// }
+// };
+
+// inline constexpr blocking_wait_fn blocking_wait{};
+// static constexpr blocking_wait_fn const& blockingWait = blocking_wait;
+
+struct co_invoke_fn {
+ template <typename F, typename... A>
+ Task<void> operator()(F&& f, A&&... a) const {
+ return Task<void>();
+ }
+};
+
+co_invoke_fn co_invoke;
+
+}} // namespace folly::coro
+
+// CIR-DAG: ![[VoidTask:.*]] = !cir.record<struct "folly::coro::Task<void>" padded {!u8i}>
+
+// CIR: module {{.*}} {
+// CIR-NEXT: cir.global external @_ZN5folly4coro9co_invokeE = #cir.zero : !rec_folly3A3Acoro3A3Aco_invoke_fn
+
+// CIR: cir.func builtin private @__builtin_coro_id(!u32i, !cir.ptr<!void>, !cir.ptr<!void>, !cir.ptr<!void>) -> !u32i
+
+using VoidTask = folly::coro::Task<void>;
+
+VoidTask silly_task() {
+ co_await std::suspend_always();
+}
+
+// CIR: cir.func coroutine dso_local @_Z10silly_taskv() -> ![[VoidTask]]
+// CHECK: %[[#VoidTaskAddr:]] = cir.alloca ![[VoidTask]], {{.*}}, ["__retval"]
+
+// Get coroutine id with __builtin_coro_id.
+
+// CIR: %[[NullPtr:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR: %[[Align:.*]] = cir.const #cir.int<16> : !u32i
+// CIR: %[[CoroId:.*]] = cir.call @__builtin_coro_id(%[[Align]], %[[NullPtr]], %[[NullPtr]], %[[NullPtr]])
>From b9fdcce5f8bb10b2bf6f33b5cb330048b6206876 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 1 Oct 2025 22:42:45 -0500
Subject: [PATCH 2/4] Fix issues after rebase
---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index ee43c221c3cd6..bc42ab1ebfb38 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -70,7 +70,7 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
cir::ConstantOp nullPtrCst = builder.getNullPtr(VoidPtrTy, openCurlyLoc);
- cir::FuncOp fn = curFn;
+ auto fn = dyn_cast<cir::FuncOp>(curFn);
assert(fn && "other callables are NYI");
fn.setCoroutine(true);
cir::CallOp coroId = emitCoroIDBuiltinCall(openCurlyLoc, nullPtrCst);
>From 03d718c0d49c22b1a7e7b7b09c791323f7772440 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 2 Oct 2025 16:55:30 -0500
Subject: [PATCH 3/4] Apply review feedback
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 13 +++++--------
clang/test/CIR/IR/func.cir | 11 +++++++++++
4 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 3c79d9c501a39..7f2e55d14b51c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2344,7 +2344,7 @@ def CIR_FuncOp : CIR_Op<"func", [
A compiler builtin function must be marked as `builtin` for further
processing when lowering from CIR.
- The `coroutine` keyword is used to mark coroutine function, which requires
+ The `coroutine` keyword is used to mark a coroutine function, which requires
at least one `cir.await` instruction to be used in its body.
The `lambda` translates to a C++ `operator()` that implements a lambda, this
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 512e1b2aa0e86..6b85fb8eabc33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -439,7 +439,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_coro_end:
case Builtin::BI__builtin_coro_suspend:
case Builtin::BI__builtin_coro_align:
- llvm_unreachable("BI__builtin_coro_id like NYI");
+ llvm_unreachable("Error NYI");
case Builtin::BI__builtin_coro_frame: {
cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_frame NYI");
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index bc42ab1ebfb38..c25cce4ab33b3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -32,12 +32,9 @@ CIRGenFunction::CGCoroInfo::~CGCoroInfo() {}
static void createCoroData(CIRGenFunction &cgf,
CIRGenFunction::CGCoroInfo &curCoro,
cir::CallOp coroId) {
- if (curCoro.data) {
- llvm_unreachable("EmitCoroutineBodyStatement called twice?");
- return;
- }
+ assert(!curCoro.data && "EmitCoroutineBodyStatement called twice?");
- curCoro.data = std::unique_ptr<CGCoroData>(new CGCoroData);
+ curCoro.data = std::make_unique<CGCoroData>();
curCoro.data->coroId = coroId;
}
@@ -57,8 +54,9 @@ cir::CallOp CIRGenFunction::emitCoroIDBuiltinCall(mlir::Location loc,
cir::FuncType::get({int32Ty, VoidPtrTy, VoidPtrTy, VoidPtrTy}, int32Ty),
/*FD=*/nullptr);
assert(fnOp && "should always succeed");
- } else
+ } else {
fnOp = cast<cir::FuncOp>(builtin);
+ }
return builder.createCallOp(loc, fnOp,
mlir::ValueRange{builder.getUInt32(newAlign, loc),
@@ -70,8 +68,7 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
cir::ConstantOp nullPtrCst = builder.getNullPtr(VoidPtrTy, openCurlyLoc);
- auto fn = dyn_cast<cir::FuncOp>(curFn);
- assert(fn && "other callables are NYI");
+ auto fn = mlir::cast<cir::FuncOp>(curFn);
fn.setCoroutine(true);
cir::CallOp coroId = emitCoroIDBuiltinCall(openCurlyLoc, nullPtrCst);
createCoroData(*this, curCoro, coroId);
diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir
index 0e9a92fcf8201..48c8510fd9a87 100644
--- a/clang/test/CIR/IR/func.cir
+++ b/clang/test/CIR/IR/func.cir
@@ -99,4 +99,15 @@ cir.func @ullfunc() -> !u64i {
// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !u64i
// CHECK: cir.return %[[VAL:.*]] : !u64i
// CHECK: }
+
+cir.func coroutine @coro() {
+ cir.return
+}
+// CHECK: cir.func{{.*}} coroutine @coro()
+
+cir.func builtin @builtin() {
+ cir.return
+}
+// CHECK: cir.func{{.*}} builtin @builtin()
+
}
>From b14cfc3bc10cd98b51955c1cc606eebce1f686f3 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 2 Oct 2025 18:46:00 -0500
Subject: [PATCH 4/4] Replace llvm_unreachable with errorNYI
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 6b85fb8eabc33..4cfa91e09efb4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -439,7 +439,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_coro_end:
case Builtin::BI__builtin_coro_suspend:
case Builtin::BI__builtin_coro_align:
- llvm_unreachable("Error NYI");
+ cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_id like NYI");
+ return getUndefRValue(e->getType());
case Builtin::BI__builtin_coro_frame: {
cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_frame NYI");
More information about the cfe-commits
mailing list