[clang] [CIR] Replace coroutine unit attrs on FuncOp with a CoroutineKind enum attr (PR #234817)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 22 19:14:16 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Andres-Salamanca

<details>
<summary>Changes</summary>

Follow-up to #<!-- -->203802. `cir.func` used two independent unit attributes, `coroutine` and`flattened_coroutine`, to track whether a function is a coroutine and whether its body has been flattened. Nothing prevented both from being set at once, and `FlattenCFG` had to clear one and set the other by hand. Replace them with a single optional `coroutine_kind` attribute backed by a new `CoroutineKind` enum (`coroutine`, `flattened_coroutine`).

---
Full diff: https://github.com/llvm/llvm-project/pull/234817.diff


5 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+30) 
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+1-2) 
- (modified) clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp (+1-1) 
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+17-17) 
- (modified) clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp (+1-2) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index b3cc021989fde..54158e5b77d84 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1852,6 +1852,36 @@ def CIR_FuncInfoAttr : AnyAttrOf<[
   CIR_FuncIdentityAttr
 ], "function information attribute">;
 
+
+//===----------------------------------------------------------------------===//
+// CoroutineKindAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_CoroutineKind : CIR_I32Enum<"CoroutineKind", "coroutine kind", [
+  I32EnumCase<"Coroutine", 0, "coroutine">,
+  I32EnumCase<"FlattenedCoroutine", 1, "flattened_coroutine">
+]>;
+
+def CIR_CoroutineKindAttr : CIR_EnumAttr<CIR_CoroutineKind, "coroutine_kind"> {
+  let description = [{
+    Marks a `cir.func` as a coroutine and records which form its body
+    is in. A function without this attribute is not a coroutine.
+
+    - `coroutine`: the body still holds the structured `cir.coroutine` op
+      (and its `cir.await` / `cir.co_return` children), as emitted by CIRGen.
+    - `flattened_coroutine`: FlattenCFG has inlined those regions into plain
+      blocks. The function no longer contains a `cir.coroutine` op, but is
+      still a coroutine for the purposes of LLVM lowering.
+
+    On `cir.func` it is printed as a bare keyword:
+
+    ```mlir
+    cir.func coroutine @f() { ... }
+    cir.func flattened_coroutine @f() { ... }
+    ```
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // BitFieldDeclAttr
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 571231462236f..f22c15aea680a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4386,8 +4386,7 @@ def CIR_FuncOp : CIR_Op<"func", [
     >:$global_visibility,
     TypeAttrOf<CIR_FuncType>:$function_type,
     UnitAttr:$builtin,
-    UnitAttr:$coroutine,
-    UnitAttr:$flattened_coroutine,
+    OptionalAttr<CIR_CoroutineKindAttr>:$coroutine_kind,
     OptionalAttr<CIR_InlineKindAttr>:$inline_kind,
     UnitAttr:$lambda,
     UnitAttr:$no_proto,
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 0122d8a377b39..538db6747cf0b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -340,7 +340,7 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
   cir::ConstantOp nullPtrCst = builder.getNullPtr(voidPtrTy, openCurlyLoc);
 
   auto fn = mlir::cast<cir::FuncOp>(curFn);
-  fn.setCoroutine(true);
+  fn.setCoroutineKind(cir::CoroutineKind::Coroutine);
   const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
   unsigned newAlign = ti.getNewAlign() / ti.getCharWidth();
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7dcd0e9fefe29..838ea1e953e9b 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2923,9 +2923,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
   mlir::Builder &builder = parser.getBuilder();
 
   mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);
-  mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);
-  mlir::StringAttr flattenedCoroutineNameAttr =
-      getFlattenedCoroutineAttrName(state.name);
+  mlir::StringAttr coroutineKindNameAttr = getCoroutineKindAttrName(state.name);
   mlir::StringAttr inlineKindNameAttr = getInlineKindAttrName(state.name);
   mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);
   mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);
@@ -2939,14 +2937,19 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
 
   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(flattenedCoroutineNameAttr.strref())))
-    state.addAttribute(flattenedCoroutineNameAttr,
-                       parser.getBuilder().getUnitAttr());
+
+  // Parse optional coroutine kind attribute
+  {
+    static constexpr llvm::StringRef keywords[] = {"coroutine",
+                                                   "flattened_coroutine"};
+    llvm::StringRef keyword;
+    if (parser.parseOptionalKeyword(&keyword, keywords).succeeded())
+      state.addAttribute(
+          coroutineKindNameAttr,
+          cir::CoroutineKindAttr::get(builder.getContext(),
+                                      *cir::symbolizeCoroutineKind(keyword)));
+  }
+
   // Parse optional inline kind attribute
   cir::InlineKindAttr inlineKindAttr;
   if (failed(parseInlineKindAttr(parser, inlineKindAttr)))
@@ -3289,11 +3292,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
   if (getBuiltin())
     p << " builtin";
 
-  if (getCoroutine())
-    p << " coroutine";
-
-  if (getFlattenedCoroutine())
-    p << " flattened_coroutine";
+  if (std::optional<cir::CoroutineKind> coroKind = getCoroutineKind())
+    p << ' ' << cir::stringifyCoroutineKind(*coroKind);
 
   printInlineKindAttr(p, getInlineKindAttr());
 
@@ -3392,7 +3392,7 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
 
 mlir::LogicalResult cir::FuncOp::verify() {
 
-  if (!isDeclaration() && getCoroutine()) {
+  if (!isDeclaration() && getCoroutineKind() == cir::CoroutineKind::Coroutine) {
     int coroutineOpCount = 0;
     this->walk([&](Operation *op) {
       if (isa<CoroutineOp>(op)) {
diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
index 87115ff26ed59..0bcdb90571f27 100644
--- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
@@ -2324,8 +2324,7 @@ class CIRCoroutineFlattening : public mlir::OpRewritePattern<cir::CoroutineOp> {
     // The coroutine regions have been flattened, so the original coroutine
     // attribute no longer verifies. Preserve the information that this function
     // originated from a coroutine for LLVM lowering.
-    func.setCoroutine(false);
-    func.setFlattenedCoroutine(true);
+    func.setCoroutineKind(cir::CoroutineKind::FlattenedCoroutine);
 
     rewriter.eraseOp(coroOp);
     return mlir::success();

``````````

</details>


https://github.com/llvm/llvm-project/pull/234817


More information about the cfe-commits mailing list