https://github.com/vsytch created
https://github.com/llvm/llvm-project/pull/222472
Implement the remaining C++ coroutine intrinsics and builtins in ClangIR:
- Add `CIR_Coro{Save,Suspend,Resume,Destroy,Done,Noop,Align}Op` operations in
`CIROps.td` with TableGen DirectToLLVM lowering (`llvmOp` mappings).
- Implement codegen for
`__builtin_coro_{resume,destroy,done,noop,align,suspend}` and add integral
casting for `__builtin_coro_size` and `__builtin_coro_align`.
- Emit the `"presplitcoroutine"` passthrough function attribute when lowering
coroutine functions in DirectToLLVM.
- Update `cir::FuncOp::verify()` to accept flattened coroutine functions
containing `cir.coro.intrinsic.suspend` (where `cir.coro.body` has been
lowered).
- Enable the TODO coroutine builtin tests in `coro-builtins.cpp` and add a
DirectToLLVM lowering test in `coro-intrinsics.cir`.
>From 2a2fc6d14a044ed7b3da604a8a29dfc4fb7d273c Mon Sep 17 00:00:00 2001
From: Vlad Sytchenko <[email protected]>
Date: Wed, 9 Sep 2026 22:46:02 +0000
Subject: [PATCH] [CIR] Add coroutine intrinsics, builtins, and DirectToLLVM
lowering
Implement the remaining C++ coroutine intrinsics and builtins in ClangIR:
- Add CIR_Coro{Save,Suspend,Resume,Destroy,Done,Noop,Align}Op operations in
CIROps.td with TableGen DirectToLLVM lowering (llvmOp mappings).
- Implement codegen for __builtin_coro_{resume,destroy,done,noop,align,suspend}
and add integral casting for __builtin_coro_size and __builtin_coro_align.
- Emit the "presplitcoroutine" passthrough function attribute when lowering
coroutine functions in DirectToLLVM.
- Update cir::FuncOp::verify() to accept flattened coroutine functions
containing cir.coro.intrinsic.suspend (where cir.coro.body has been lowered).
- Enable the TODO coroutine builtin tests in coro-builtins.cpp and add a
DirectToLLVM lowering test in coro-intrinsics.cir.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 101 ++++++++++++++++++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 ++++---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 40 +++++++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 6 ++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 9 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 22 +++-
.../CIR/CodeGenCoroutines/coro-builtins.cpp | 32 ++++--
clang/test/CIR/Lowering/coro-intrinsics.cir | 52 +++++++++
8 files changed, 269 insertions(+), 32 deletions(-)
create mode 100644 clang/test/CIR/Lowering/coro-intrinsics.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d1047ab88b942..50823fe636552 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5019,6 +5019,107 @@ def CIR_CoroPromiseOp : CIR_CoroIntrinsicOp<"promise",
let llvmOp = "CoroPromiseOp";
}
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic SaveOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSaveOp : CIR_CoroIntrinsicOp<"save",
+ (ins CIR_VoidPtrType:$handle),
+ (outs Token:$result), [TokenProducerTrait]> {
+ let summary = "Represents llvm.coro.save";
+ let description = [{
+ Saves the state of a coroutine identified by `handle` for a subsequent
+ suspension point, producing a token consumed by `coro.intrinsic.suspend`.
+ }];
+ let llvmOp = "CoroSaveOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic SuspendOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroSuspendOp : CIR_CoroIntrinsicOp<"suspend",
+ (ins Token:$save, CIR_AnyBoolType:$final_suspend),
+ (outs CIR_SInt8:$result), [TokenConsumerTrait]> {
+ let summary = "Represents llvm.coro.suspend";
+ let description = [{
+ Marks a coroutine suspension point. Consumes the token `save` produced
+ by `coro.intrinsic.save` (or `cir.token.none`) and a boolean flag
+ `final_suspend` indicating whether this is the final suspension point.
+ Returns an 8-bit signed integer indicating whether the coroutine should
+ suspend (`-1`), resume (`0`), or destroy (`1`).
+ }];
+ let llvmOp = "CoroSuspendOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic ResumeOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroResumeOp : CIR_CoroIntrinsicOp<"resume",
+ (ins CIR_VoidPtrType:$handle), (outs)> {
+ let summary = "Represents llvm.coro.resume";
+ let description = [{
+ Resumes a suspended coroutine given its frame pointer `handle`.
+ }];
+ let llvmOp = "CoroResumeOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic DestroyOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroDestroyOp : CIR_CoroIntrinsicOp<"destroy",
+ (ins CIR_VoidPtrType:$handle), (outs)> {
+ let summary = "Represents llvm.coro.destroy";
+ let description = [{
+ Destroys a suspended coroutine given its frame pointer `handle`.
+ }];
+ let llvmOp = "CoroDestroyOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic DoneOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroDoneOp : CIR_CoroIntrinsicOp<"done",
+ (ins CIR_VoidPtrType:$handle),
+ (outs CIR_AnyBoolType:$result)> {
+ let summary = "Represents llvm.coro.done";
+ let description = [{
+ Checks whether a suspended coroutine identified by `handle` is at its
+ final suspension point.
+ }];
+ let llvmOp = "CoroDoneOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic NoopOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroNoopOp : CIR_CoroIntrinsicOp<"noop",
+ (ins), (outs CIR_VoidPtrType:$result)> {
+ let summary = "Represents llvm.coro.noop";
+ let description = [{
+ Returns the coroutine handle for a coroutine that does nothing when resumed
+ or destroyed.
+ }];
+ let llvmOp = "CoroNoopOp";
+}
+
+//===----------------------------------------------------------------------===//
+// Coroutine intrinsic AlignOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroAlignOp : CIR_CoroIntrinsicOp<"align",
+ (ins), (outs CIR_UInt64:$result)> {
+ let summary = "Represents llvm.coro.align";
+ let description = [{
+ Returns the required alignment, in bytes, of the coroutine frame.
+ }];
+ let llvmOp = "CoroAlignOp";
+}
+
//===----------------------------------------------------------------------===//
// CopyOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index d4c17d3c5f24f..291f10e59ecae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1735,24 +1735,27 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return RValue::get(emitCoroEndBuiltinCall(e).getResult());
case Builtin::BI__builtin_coro_promise:
return RValue::get(emitCoroPromiseBuiltinCall(e).getResult());
- case Builtin::BI__builtin_coro_resume:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_resume NYI");
- return getUndefRValue(e->getType());
+ case Builtin::BI__builtin_coro_resume: {
+ emitCoroResumeBuiltinCall(e);
+ return RValue::get(nullptr);
+ }
case Builtin::BI__builtin_coro_noop:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_noop NYI");
- return getUndefRValue(e->getType());
- case Builtin::BI__builtin_coro_destroy:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_destroy NYI");
- return getUndefRValue(e->getType());
+ return RValue::get(emitCoroNoopBuiltinCall(e).getResult());
+ case Builtin::BI__builtin_coro_destroy: {
+ emitCoroDestroyBuiltinCall(e);
+ return RValue::get(nullptr);
+ }
case Builtin::BI__builtin_coro_done:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_done NYI");
- return getUndefRValue(e->getType());
+ return RValue::get(emitCoroDoneBuiltinCall(e).getResult());
case Builtin::BI__builtin_coro_suspend:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_suspend NYI");
- return getUndefRValue(e->getType());
- case Builtin::BI__builtin_coro_align:
- cgm.errorNYI(e->getSourceRange(), "BI__builtin_coro_align NYI");
- return getUndefRValue(e->getType());
+ return RValue::get(emitCoroSuspendBuiltinCall(e).getResult());
+ case Builtin::BI__builtin_coro_align: {
+ mlir::Value align = emitCoroAlignBuiltinCall(e).getResult();
+ mlir::Type expectedTy = convertType(e->getType());
+ if (align.getType() != expectedTy)
+ align = builder.createIntCast(align, expectedTy);
+ return RValue::get(align);
+ }
case Builtin::BI__builtin_coro_frame: {
return emitCoroutineFrame();
@@ -1764,7 +1767,11 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
}
case Builtin::BI__builtin_coro_size: {
- return RValue::get(emitCoroSizeBuiltinCall(e).getResult());
+ mlir::Value size = emitCoroSizeBuiltinCall(e).getResult();
+ mlir::Type expectedTy = convertType(e->getType());
+ if (size.getType() != expectedTy)
+ size = builder.createIntCast(size, expectedTy);
+ return RValue::get(size);
}
case Builtin::BI__builtin_constant_p: {
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 7004f2d7750e6..a57d1151b84bb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -321,6 +321,46 @@ CIRGenFunction::emitCoroPromiseBuiltinCall(const CallExpr
*e) {
return coroPromise;
}
+cir::CoroResumeOp CIRGenFunction::emitCoroResumeBuiltinCall(const CallExpr *e)
{
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ mlir::Value handle = emitScalarExpr(e->getArg(0));
+ return cir::CoroResumeOp::create(cgm.getBuilder(), loc, handle);
+}
+
+cir::CoroDestroyOp
+CIRGenFunction::emitCoroDestroyBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ mlir::Value handle = emitScalarExpr(e->getArg(0));
+ return cir::CoroDestroyOp::create(cgm.getBuilder(), loc, handle);
+}
+
+cir::CoroDoneOp CIRGenFunction::emitCoroDoneBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ mlir::Value handle = emitScalarExpr(e->getArg(0));
+ return cir::CoroDoneOp::create(cgm.getBuilder(), loc,
+ convertType(e->getType()), handle);
+}
+
+cir::CoroNoopOp CIRGenFunction::emitCoroNoopBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ return cir::CoroNoopOp::create(cgm.getBuilder(), loc,
+ convertType(e->getType()));
+}
+
+cir::CoroAlignOp CIRGenFunction::emitCoroAlignBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ return cir::CoroAlignOp::create(cgm.getBuilder(), loc);
+}
+
+cir::CoroSuspendOp
+CIRGenFunction::emitCoroSuspendBuiltinCall(const CallExpr *e) {
+ mlir::Location loc = getLoc(e->getBeginLoc());
+ CIRGenBuilderTy &builder = cgm.getBuilder();
+ mlir::Value saveToken = cir::TokenNoneOp::create(builder, loc);
+ mlir::Value finalSuspend = emitScalarExpr(e->getArg(0));
+ return cir::CoroSuspendOp::create(builder, loc, saveToken, finalSuspend);
+}
+
static mlir::LogicalResult
coroutineBodyExceptionHelper(CIRGenFunction &cgf, const CoroutineBodyStmt &s) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 8547a77e86faf..f5264c785f81c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1916,6 +1916,12 @@ class CIRGenFunction : public CIRGenTypeCache {
cir::CoroAllocOp emitCoroAllocBuiltinCall(const CallExpr *e);
cir::CoroBeginOp emitCoroBeginBuiltinCall(const CallExpr *e);
cir::CoroPromiseOp emitCoroPromiseBuiltinCall(const CallExpr *e);
+ cir::CoroResumeOp emitCoroResumeBuiltinCall(const CallExpr *e);
+ cir::CoroDestroyOp emitCoroDestroyBuiltinCall(const CallExpr *e);
+ cir::CoroDoneOp emitCoroDoneBuiltinCall(const CallExpr *e);
+ cir::CoroNoopOp emitCoroNoopBuiltinCall(const CallExpr *e);
+ cir::CoroAlignOp emitCoroAlignBuiltinCall(const CallExpr *e);
+ cir::CoroSuspendOp emitCoroSuspendBuiltinCall(const CallExpr *e);
cir::CoroSizeOp emitCoroSizeBuiltinCall(const CallExpr *e);
cir::CoroFreeOp emitCoroFreeBuiltin(const CallExpr *e);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 113c687970534..82f5520ccf673 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2853,10 +2853,13 @@ mlir::LogicalResult cir::FuncOp::verify() {
if (!isDeclaration() && getCoroutine()) {
bool foundAwait = false;
+ bool foundCoroSuspend = false;
int coroBodyCount = 0;
this->walk([&](Operation *op) {
- if (auto await = dyn_cast<AwaitOp>(op)) {
+ if (isa<AwaitOp>(op)) {
foundAwait = true;
+ } else if (isa<CoroSuspendOp>(op)) {
+ foundCoroSuspend = true;
} else if (isa<CoroBodyOp>(op)) {
coroBodyCount++;
if (coroBodyCount > 1) {
@@ -2865,10 +2868,10 @@ mlir::LogicalResult cir::FuncOp::verify() {
}
return mlir::WalkResult::advance();
});
- if (!foundAwait)
+ if (!foundAwait && !foundCoroSuspend)
return emitOpError()
<< "coroutine body must use at least one cir.await op";
- if (coroBodyCount != 1)
+ if (coroBodyCount > 1 || (coroBodyCount != 1 && !foundCoroSuspend))
return emitOpError()
<< "coroutine function must have exactly one cir.body op";
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6761da8be6491..eec77588ddba5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2813,9 +2813,25 @@ mlir::LogicalResult
CIRToLLVMFuncOpLowering::matchAndRewrite(
// function attribute, so route it through the `passthrough` array. The MLIR
// LLVM IR translator forwards `passthrough` entries to LLVM IR as function
// attributes.
- if (op->hasAttr(CIRDialect::getStrictFPAttrName()))
- fn.setPassthroughAttr(rewriter.getArrayAttr(
- {rewriter.getStringAttr(CIRDialect::getStrictFPAttrName())}));
+ if (auto passthrough = op->getAttrOfType<mlir::ArrayAttr>("passthrough"))
+ fn.setPassthroughAttr(passthrough);
+
+ if (op->hasAttr(CIRDialect::getStrictFPAttrName())) {
+ llvm::SmallVector<mlir::Attribute, 2> passthroughAttrs;
+ if (auto existing = fn.getPassthroughAttr())
+ passthroughAttrs.append(existing.begin(), existing.end());
+ passthroughAttrs.push_back(
+ rewriter.getStringAttr(CIRDialect::getStrictFPAttrName()));
+ fn.setPassthroughAttr(rewriter.getArrayAttr(passthroughAttrs));
+ }
+
+ if (op.getCoroutine()) {
+ llvm::SmallVector<mlir::Attribute, 2> passthroughAttrs;
+ if (auto existing = fn.getPassthroughAttr())
+ passthroughAttrs.append(existing.begin(), existing.end());
+ passthroughAttrs.push_back(rewriter.getStringAttr("presplitcoroutine"));
+ fn.setPassthroughAttr(rewriter.getArrayAttr(passthroughAttrs));
+ }
if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
index 564dc4e49a9cf..c21d7bbac0b65 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-builtins.cpp
@@ -29,8 +29,13 @@ void f(int n) {
// LLVM: call i1 @llvm.coro.alloc(token %[[COROID]])
- // TODO
- //__builtin_coro_noop();
+ __builtin_coro_noop();
+ // CIR: cir.coro.intrinsic.noop() : () -> !cir.ptr<!void>
+ // LLVM: call ptr @llvm.coro.noop()
+
+ __builtin_coro_align();
+ // CIR: cir.coro.intrinsic.align() : () -> !u64i
+ // LLVM: call i64 @llvm.coro.align.i64()
__builtin_coro_begin(myAlloc(__builtin_coro_size()));
// TODO(CIR): Support both variants of the coroutine size intrinsic, matching
@@ -44,14 +49,17 @@ void f(int n) {
// LLVM: %[[MEM:.*]] = call noundef ptr @_Z7myAllocx(i64 noundef %[[SIZE]])
// LLVM: %[[FRAME:.*]] = call ptr @llvm.coro.begin(token %[[COROID]], ptr
%[[MEM]])
- // TODO(CIR):
- //__builtin_coro_resume(__builtin_coro_frame());
+ __builtin_coro_resume(__builtin_coro_frame());
+ // CIR: cir.coro.intrinsic.resume(%[[FRAME]]) : (!cir.ptr<!void>) -> ()
+ // LLVM: call void @llvm.coro.resume(ptr %[[FRAME]])
- // TODO(CIR):
- //__builtin_coro_destroy(__builtin_coro_frame());
+ __builtin_coro_destroy(__builtin_coro_frame());
+ // CIR: cir.coro.intrinsic.destroy(%[[FRAME]]) : (!cir.ptr<!void>) -> ()
+ // LLVM: call void @llvm.coro.destroy(ptr %[[FRAME]])
- // TODO(CIR):
- //__builtin_coro_done(__builtin_coro_frame());
+ __builtin_coro_done(__builtin_coro_frame());
+ // CIR: cir.coro.intrinsic.done(%[[FRAME]]) : (!cir.ptr<!void>) -> !cir.bool
+ // LLVM: call i1 @llvm.coro.done(ptr %[[FRAME]])
__builtin_coro_promise(__builtin_coro_frame(), 48, 0);
// CIR: %[[ALIGN:.*]] = cir.const #cir.int<48> : !s32i
@@ -72,6 +80,10 @@ void f(int n) {
// LLVM: call void @llvm.coro.end(ptr %[[FRAME]], i1 false, token none)
- // TODO(CIR):
- //__builtin_coro_suspend(1);
+ __builtin_coro_suspend(1);
+ // CIR: %[[TK_SAVE:.*]] = cir.token.none
+ // CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+ // CIR: %[[SUSP_FINAL:.*]] = cir.cast int_to_bool %[[ONE]] : !s32i ->
!cir.bool
+ // CIR: cir.coro.intrinsic.suspend(%[[TK_SAVE]], %[[SUSP_FINAL]]) : (token,
!cir.bool) -> !s8i
+ // LLVM: call i8 @llvm.coro.suspend(token none, i1 true)
}
diff --git a/clang/test/CIR/Lowering/coro-intrinsics.cir
b/clang/test/CIR/Lowering/coro-intrinsics.cir
new file mode 100644
index 0000000000000..c2dc430458844
--- /dev/null
+++ b/clang/test/CIR/Lowering/coro-intrinsics.cir
@@ -0,0 +1,52 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR
+// RUN: cir-translate %s -cir-to-llvmir --disable-cc-lowering | FileCheck %s
-check-prefix=LLVM
+
+!void = !cir.void
+!s8i = !cir.int<s, 8>
+!u64i = !cir.int<u, 64>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ cir.func @test_coro_intrinsics(%arg0: !cir.ptr<!void>) {
+ %save = cir.coro.intrinsic.save(%arg0) : (!cir.ptr<!void>) -> token
+ %false = cir.const #cir.bool<false> : !cir.bool
+ %susp = cir.coro.intrinsic.suspend(%save, %false) : (token, !cir.bool) ->
!s8i
+ cir.coro.intrinsic.resume(%arg0) : (!cir.ptr<!void>) -> ()
+ cir.coro.intrinsic.destroy(%arg0) : (!cir.ptr<!void>) -> ()
+ %done = cir.coro.intrinsic.done(%arg0) : (!cir.ptr<!void>) -> !cir.bool
+ %noop = cir.coro.intrinsic.noop() : () -> !cir.ptr<!void>
+ %align = cir.coro.intrinsic.align() : () -> !u64i
+ cir.return
+ }
+
+ cir.func coroutine @test_coro_func(%arg0: !cir.ptr<!void>) {
+ %save = cir.coro.intrinsic.save(%arg0) : (!cir.ptr<!void>) -> token
+ %false = cir.const #cir.bool<false> : !cir.bool
+ %susp = cir.coro.intrinsic.suspend(%save, %false) : (token, !cir.bool) ->
!s8i
+ cir.return
+ }
+}
+
+// MLIR-LABEL: llvm.func @test_coro_intrinsics(%arg0: !llvm.ptr)
+// MLIR: %[[SAVE:.*]] = llvm.intr.coro.save %arg0 : (!llvm.ptr) -> token
+// MLIR: %[[FALSE:.*]] = llvm.mlir.constant(false) : i1
+// MLIR: %[[SUSP:.*]] = llvm.intr.coro.suspend %[[SAVE]], %[[FALSE]] : i8
+// MLIR: llvm.intr.coro.resume %arg0 : !llvm.ptr
+// MLIR: llvm.intr.coro.destroy %arg0 : !llvm.ptr
+// MLIR: %[[DONE:.*]] = llvm.intr.coro.done %arg0 : (!llvm.ptr) -> i1
+// MLIR: %[[NOOP:.*]] = llvm.intr.coro.noop : !llvm.ptr
+// MLIR: %[[ALIGN:.*]] = llvm.intr.coro.align : i64
+
+// MLIR-LABEL: llvm.func @test_coro_func(%arg0: !llvm.ptr)
+// MLIR-SAME: passthrough = ["presplitcoroutine"]
+
+// LLVM-LABEL: define void @test_coro_intrinsics(ptr %0)
+// LLVM: %[[SAVE:.*]] = call token @llvm.coro.save(ptr %0)
+// LLVM: %[[SUSP:.*]] = call i8 @llvm.coro.suspend(token %[[SAVE]], i1 false)
+// LLVM: call void @llvm.coro.resume(ptr %0)
+// LLVM: call void @llvm.coro.destroy(ptr %0)
+// LLVM: %[[DONE:.*]] = call i1 @llvm.coro.done(ptr %0)
+// LLVM: %[[NOOP:.*]] = call ptr @llvm.coro.noop()
+// LLVM: %[[ALIGN:.*]] = call i64 @llvm.coro.align.i64()
+
+// LLVM: define void @test_coro_func(ptr %0) #[[CORO_ATTR:[0-9]+]]
+// LLVM: attributes #[[CORO_ATTR]] = {{.*}}presplitcoroutine
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits