[llvm] [CoroSplit] Fix infinite loop in CoroSplit (PR #185599)

Felipe de Azevedo Piovezan via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 11 01:12:01 PDT 2026


https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/185599

>From 5c452f3a490d319445e748f01a5bce61dfcab1c1 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Tue, 10 Mar 2026 07:35:54 +0000
Subject: [PATCH 1/2] [CoroSplit] Fix infinite loop in CoroSplit

Optimized code may generate an uncoditional branch to the same BB.
---
 llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 587f581ded8d5..95eabd043ea1e 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -818,8 +818,9 @@ static void updateScopeLine(Instruction *ActiveSuspend,
   BasicBlock::iterator Successor = ActiveSuspend->getNextNode()->getIterator();
   // Corosplit splits the BB around ActiveSuspend, so the meaningful
   // instructions are not in the same BB.
-  while (auto *Branch = dyn_cast_or_null<BranchInst>(Successor)) {
-    if (!Branch->isUnconditional())
+  for (unsigned Repeat = 0; Repeat < 2; Repeat++) {
+    auto *Branch = dyn_cast_or_null<BranchInst>(Successor);
+    if (!Branch || !Branch->isUnconditional())
       break;
     Successor = Branch->getSuccessor(0)->getFirstNonPHIOrDbg();
   }

>From 0f4079411a5d719fca4b278e35fc11db1dca6b0b Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Wed, 11 Mar 2026 08:11:23 +0000
Subject: [PATCH 2/2] fixup! add test

---
 .../Coroutines/coro-retcon-infinite-loop.ll   | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 llvm/test/Transforms/Coroutines/coro-retcon-infinite-loop.ll

diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-infinite-loop.ll b/llvm/test/Transforms/Coroutines/coro-retcon-infinite-loop.ll
new file mode 100644
index 0000000000000..00d3610453942
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-retcon-infinite-loop.ll
@@ -0,0 +1,62 @@
+; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s
+
+@"coroutineTwc" = global <{ i32, i32, i64 }> <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @"coroutine" to i64), i64 ptrtoint (ptr @"coroutineTwc" to i64)) to i32), i32 0, i64 51979 }>, align 8
+
+; This test ensures CoroSplit will not loop infinitely in the presence of an
+; infinite loop in the IR, but it will still split the coroutine.
+;CHECK: define .*coroutine(
+;CHECK: @coroutine.resume
+define swiftcc { ptr, ptr } @coroutine(ptr noalias %0, ptr %1, ptr swiftself %2) #0 !dbg !39 {
+entry:
+  %3 = call token @llvm.coro.id.retcon.once(i32 -1, i32 16, ptr %0, ptr @"$s4test1SVSiIetMIlYl_TC", ptr @_swift_coro_alloc, ptr @_swift_coro_dealloc), !dbg !48
+  %4 = call ptr @llvm.coro.begin(token %3, ptr null), !dbg !48
+  call swiftcc void @"$s4test6FINISHyyF"(), !dbg !50
+  %.member_int = getelementptr inbounds nuw <{ <{ i64 }> }>, ptr %2, i32 0, i32 0, !dbg !51
+  %5 = call ptr (...) @llvm.coro.suspend.retcon.p0(ptr %.member_int), !dbg !52 ; [debug line = 11:7]
+  br label %loop
+
+loop:
+  br label %loop
+
+coro.end:
+  call void @llvm.coro.end(ptr %4, i1 false, token none), !dbg !54
+  unreachable, !dbg !54
+}
+
+declare swiftcc void @"$s4test6FINISHyyF"()
+declare swiftcc ptr @_swift_coro_alloc(i64) #3
+declare swiftcc void @_swift_coro_dealloc(ptr) #3
+declare swiftcc ptr @_swift_coro_alloc_frame(ptr, ptr, i64, i64) #3
+declare swiftcc void @_swift_coro_dealloc_frame(ptr, ptr, ptr) #3
+declare swiftcc void @"$s4test1SVSiIetMIlYl_TC"(ptr noalias, ptr)
+
+attributes #0 = { noinline presplitcoroutine }
+attributes #3 = { noinline nounwind }
+
+!llvm.module.flags = !{!7, !8, !9, !10, !11}
+!llvm.dbg.cu = !{!17}
+
+!7 = !{i32 7, !"Dwarf Version", i32 5}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{i32 8, !"PIC Level", i32 2}
+!11 = !{i32 7, !"uwtable", i32 1}
+!17 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !18, producer: "Swift", isOptimized: false, emissionKind: FullDebug)
+!18 = !DIFile(filename: "test.ll", directory: "/")
+!39 = distinct !DISubprogram(name: "COMPUTED_PROPERTY.yielding_mutate", linkageName: "coroutine", scope: !40, file: !18, line: 9, type: !41, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !17, declaration: !44, retainedNodes: !45)
+!40 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !18, size: 64, runtimeLang: DW_LANG_Swift, identifier: "$s4test1SVD")
+!41 = !DISubroutineType(types: !42)
+!42 = !{!43, !40}
+!43 = !DICompositeType(tag: DW_TAG_structure_type, name: "$sytD", flags: DIFlagFwdDecl, runtimeLang: DW_LANG_Swift, identifier: "$sytD")
+!44 = !DISubprogram(name: "COMPUTED_PROPERTY.yielding_mutate", linkageName: "coroutine", scope: !40, file: !18, line: 9, type: !41, scopeLine: 9, spFlags: 0)
+!45 = !{!46}
+!46 = !DILocalVariable(name: "self", arg: 1, scope: !39, file: !18, line: 9, type: !40, flags: DIFlagArtificial)
+!47 = !DILocation(line: 9, column: 14, scope: !39)
+!48 = !DILocation(line: 0, scope: !39)
+!50 = !DILocation(line: 10, column: 7, scope: !39)
+!51 = !DILocation(line: 11, column: 13, scope: !39)
+!52 = !DILocation(line: 11, column: 7, scope: !39)
+!53 = !DILocation(line: 12, column: 7, scope: !39)
+!54 = !DILocation(line: 0, scope: !55)
+!55 = !DILexicalBlockFile(scope: !39, file: !56, discriminator: 0)
+!56 = !DIFile(filename: "<compiler-generated>", directory: "/")



More information about the llvm-commits mailing list