[llvm] [CoroEarly] Add presplitcoroutine when frontend misses it (PR #169866)

Weibo He via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 30 17:27:27 PST 2025


https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/169866

>From 0e63018ab054e467c18deb67cd647a7fbbf41e1c Mon Sep 17 00:00:00 2001
From: NewSigma <NewSigma at 163.com>
Date: Fri, 28 Nov 2025 11:11:12 +0800
Subject: [PATCH 1/2] [CoroEarly] Add presplitcoroutine when frontend misses it

---
 llvm/lib/Transforms/Coroutines/CoroEarly.cpp | 116 ++++++++++---------
 1 file changed, 59 insertions(+), 57 deletions(-)

diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
index cdb58523d1e0e..a84fdad071303 100644
--- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
@@ -204,64 +204,66 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
       continue;
 
     switch (CB->getIntrinsicID()) {
-      default:
-        continue;
-      case Intrinsic::coro_begin:
-      case Intrinsic::coro_begin_custom_abi:
-        if (CoroBegin)
-          report_fatal_error(
-              "coroutine should have exactly one defining @llvm.coro.begin");
-        CoroBegin = cast<CoroBeginInst>(&I);
-        break;
-      case Intrinsic::coro_free:
-        CoroFrees.push_back(cast<CoroFreeInst>(&I));
-        break;
-      case Intrinsic::coro_suspend:
-        // Make sure that final suspend point is not duplicated as CoroSplit
-        // pass expects that there is at most one final suspend point.
-        if (cast<CoroSuspendInst>(&I)->isFinal())
-          CB->setCannotDuplicate();
-        HasCoroSuspend = true;
-        break;
-      case Intrinsic::coro_end_async:
-      case Intrinsic::coro_end:
-        // Make sure that fallthrough coro.end is not duplicated as CoroSplit
-        // pass expects that there is at most one fallthrough coro.end.
-        if (cast<AnyCoroEndInst>(&I)->isFallthrough())
-          CB->setCannotDuplicate();
-        break;
-      case Intrinsic::coro_noop:
-        lowerCoroNoop(cast<IntrinsicInst>(&I));
-        break;
-      case Intrinsic::coro_id:
-        if (auto *CII = cast<CoroIdInst>(&I)) {
-          if (CII->getInfo().isPreSplit()) {
-            assert(F.isPresplitCoroutine() &&
-                   "The frontend uses Switch-Resumed ABI should emit "
-                   "\"presplitcoroutine\" attribute for the coroutine.");
-            setCannotDuplicate(CII);
-            CII->setCoroutineSelf();
-            CoroId = cast<CoroIdInst>(&I);
-          }
+    default:
+      continue;
+    case Intrinsic::coro_begin:
+    case Intrinsic::coro_begin_custom_abi:
+      if (CoroBegin)
+        report_fatal_error(
+            "coroutine should have exactly one defining @llvm.coro.begin");
+      CoroBegin = cast<CoroBeginInst>(&I);
+      break;
+    case Intrinsic::coro_free:
+      CoroFrees.push_back(cast<CoroFreeInst>(&I));
+      break;
+    case Intrinsic::coro_suspend:
+      // Make sure that final suspend point is not duplicated as CoroSplit
+      // pass expects that there is at most one final suspend point.
+      if (cast<CoroSuspendInst>(&I)->isFinal())
+        CB->setCannotDuplicate();
+      HasCoroSuspend = true;
+      break;
+    case Intrinsic::coro_end_async:
+    case Intrinsic::coro_end:
+      // Make sure that fallthrough coro.end is not duplicated as CoroSplit
+      // pass expects that there is at most one fallthrough coro.end.
+      if (cast<AnyCoroEndInst>(&I)->isFallthrough())
+        CB->setCannotDuplicate();
+      break;
+    case Intrinsic::coro_noop:
+      lowerCoroNoop(cast<IntrinsicInst>(&I));
+      break;
+    case Intrinsic::coro_id:
+      if (auto *CII = cast<CoroIdInst>(&I)) {
+        if (CII->getInfo().isPreSplit()) {
+          // The frontend uses Switch-Resumed ABI should emit
+          // `presplitcoroutine` attribute for the coroutine.
+          if (!F.isPresplitCoroutine())
+            F.setPresplitCoroutine();
+
+          setCannotDuplicate(CII);
+          CII->setCoroutineSelf();
+          CoroId = cast<CoroIdInst>(&I);
         }
-        break;
-      case Intrinsic::coro_id_retcon:
-      case Intrinsic::coro_id_retcon_once:
-      case Intrinsic::coro_id_async:
-        F.setPresplitCoroutine();
-        break;
-      case Intrinsic::coro_resume:
-        lowerResumeOrDestroy(*CB, CoroSubFnInst::ResumeIndex);
-        break;
-      case Intrinsic::coro_destroy:
-        lowerResumeOrDestroy(*CB, CoroSubFnInst::DestroyIndex);
-        break;
-      case Intrinsic::coro_promise:
-        lowerCoroPromise(cast<CoroPromiseInst>(&I));
-        break;
-      case Intrinsic::coro_done:
-        lowerCoroDone(cast<IntrinsicInst>(&I));
-        break;
+      }
+      break;
+    case Intrinsic::coro_id_retcon:
+    case Intrinsic::coro_id_retcon_once:
+    case Intrinsic::coro_id_async:
+      F.setPresplitCoroutine();
+      break;
+    case Intrinsic::coro_resume:
+      lowerResumeOrDestroy(*CB, CoroSubFnInst::ResumeIndex);
+      break;
+    case Intrinsic::coro_destroy:
+      lowerResumeOrDestroy(*CB, CoroSubFnInst::DestroyIndex);
+      break;
+    case Intrinsic::coro_promise:
+      lowerCoroPromise(cast<CoroPromiseInst>(&I));
+      break;
+    case Intrinsic::coro_done:
+      lowerCoroDone(cast<IntrinsicInst>(&I));
+      break;
     }
   }
 

>From 4a738e6e2cb5fb4cb2c8ceea6a0624fde6c3f489 Mon Sep 17 00:00:00 2001
From: NewSigma <NewSigma at 163.com>
Date: Sat, 29 Nov 2025 10:51:49 +0800
Subject: [PATCH 2/2] Add test

---
 .../Coroutines/coro-early-presplit.ll           | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 llvm/test/Transforms/Coroutines/coro-early-presplit.ll

diff --git a/llvm/test/Transforms/Coroutines/coro-early-presplit.ll b/llvm/test/Transforms/Coroutines/coro-early-presplit.ll
new file mode 100644
index 0000000000000..7f7af060d51a8
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-early-presplit.ll
@@ -0,0 +1,17 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; Check that coro-early can infer presplitcoroutine attribute
+; RUN: opt < %s -passes='module(coro-early)' -S | FileCheck %s
+
+define void @f() {
+; CHECK-LABEL: define void @f(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr @f, ptr null)
+; CHECK-NEXT:    ret void
+;
+entry:
+  call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
+  ret void
+}
+
+; CHECK: attributes #0 = { presplitcoroutine }



More information about the llvm-commits mailing list