[llvm-branch-commits] [llvm] release/22.x: [CoroSplit] Never collect allocas used by catchpad into frame (#186728) (PR #193917)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Apr 24 01:21:02 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: llvmbot

<details>
<summary>Changes</summary>

Backport 80603c6672226cb48798bd60120c8f859dbeca19

Requested by: @<!-- -->NewSigma

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


7 Files Affected:

- (modified) llvm/docs/Coroutines.rst (+3) 
- (modified) llvm/docs/LangRef.rst (+3-2) 
- (modified) llvm/lib/FuzzMutate/RandomIRBuilder.cpp (+5) 
- (modified) llvm/lib/IR/Verifier.cpp (+7) 
- (modified) llvm/lib/Transforms/Coroutines/SpillUtils.cpp (+7) 
- (added) llvm/test/Transforms/Coroutines/coro-alloca-10.ll (+66) 
- (modified) llvm/unittests/FuzzMutate/StrategiesTest.cpp (+2-1) 


``````````diff
diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst
index 0e6b49c84acee..9fa403e68e13b 100644
--- a/llvm/docs/Coroutines.rst
+++ b/llvm/docs/Coroutines.rst
@@ -2252,4 +2252,7 @@ Areas Requiring Attention
 #. Make required changes to make sure that coroutine optimizations work with
    LTO.
 
+#. In Windows EH, exception objects must be allocated on the stack (see :ref:wineh for details).
+   We identify an exception object as an alloca that has `catchpad` users.
+
 #. More tests, more tests, more tests
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index be752b42ea412..1e0293f67e833 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13825,8 +13825,9 @@ ensures that each ``catchpad`` has exactly one predecessor block, and it always
 terminates in a ``catchswitch``.
 
 The ``args`` correspond to whatever information the personality routine
-requires to determine if this is an appropriate handler for the exception. Control
-will transfer to the ``catchpad`` if this is the first appropriate handler for
+requires to determine if this is an appropriate handler for the exception.
+Each operand must be an alloca or a constant.
+Control will transfer to the ``catchpad`` if this is the first appropriate handler for
 the exception.
 
 The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
index 8b034137e4702..87392c2e69299 100644
--- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
+++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
@@ -332,6 +332,11 @@ static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
       return false;
     return !Callee->hasParamAttribute(OperandNo, Attribute::ImmArg);
   }
+  case Instruction::CatchPad:
+    // Argument operand must be alloca or constant
+    if (!isa<Constant>(Replacement) && !isa<AllocaInst>(Replacement))
+      return false;
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index bb552861130d2..bdca6800eddfe 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4911,6 +4911,13 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) {
   Check(&*BB->getFirstNonPHIIt() == &CPI,
         "CatchPadInst not the first non-PHI instruction in the block.", &CPI);
 
+  Check(llvm::all_of(CPI.arg_operands(),
+                     [](Use &U) {
+                       auto *V = U.get();
+                       return isa<Constant>(V) || isa<AllocaInst>(V);
+                     }),
+        "Argument operand must be alloca or constant.", &CPI);
+
   visitEHPadPredecessors(CPI);
   visitFuncletPadInst(CPI);
 }
diff --git a/llvm/lib/Transforms/Coroutines/SpillUtils.cpp b/llvm/lib/Transforms/Coroutines/SpillUtils.cpp
index 81fe0c9acd413..05abccf0f9a97 100644
--- a/llvm/lib/Transforms/Coroutines/SpillUtils.cpp
+++ b/llvm/lib/Transforms/Coroutines/SpillUtils.cpp
@@ -180,6 +180,13 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
     handleAlias(I);
   }
 
+  void visitCatchPadInst(CatchPadInst &I) {
+    // Windows EH requires exception objects allocated on the stack,
+    // shortcut the traversal and keep it on stack.
+    ShouldLiveOnFrame = false;
+    Base::Worklist.clear();
+  }
+
   void visitInsertElementInst(InsertElementInst &I) {
     enqueueUsers(I);
     handleAlias(I);
diff --git a/llvm/test/Transforms/Coroutines/coro-alloca-10.ll b/llvm/test/Transforms/Coroutines/coro-alloca-10.ll
new file mode 100644
index 0000000000000..12e2a921aa769
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-alloca-10.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; Test that catchpad is specially handled. Do not collect exception object into coroutine frame.
+; RUN: opt < %s -passes='coro-split,simplifycfg,early-cse' -S | FileCheck %s
+
+define void @fn() presplitcoroutine personality i32 0 {
+; CHECK-LABEL: define void @fn() personality i32 0 {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[EXCEPTION_OBJ_RELOAD_ADDR:%.*]] = alloca ptr, align 8
+; CHECK-NEXT:    [[ID:%.*]] = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr @fn.resumers)
+; CHECK-NEXT:    [[MEM:%.*]] = call noalias nonnull ptr @malloc(i64 24)
+; CHECK-NEXT:    [[HDL:%.*]] = call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[MEM]])
+; CHECK-NEXT:    store ptr @fn.resume, ptr [[HDL]], align 8
+; CHECK-NEXT:    [[DESTROY_ADDR:%.*]] = getelementptr inbounds i8, ptr [[HDL]], i64 8
+; CHECK-NEXT:    store ptr @fn.destroy, ptr [[DESTROY_ADDR]], align 8
+; CHECK-NEXT:    store ptr null, ptr [[EXCEPTION_OBJ_RELOAD_ADDR]], align 8
+; CHECK-NEXT:    [[INDEX_ADDR4:%.*]] = getelementptr inbounds i8, ptr [[HDL]], i64 16
+; CHECK-NEXT:    store i1 false, ptr [[INDEX_ADDR4]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %exception.obj = alloca ptr, align 8
+  %id = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr null)
+  %size = call i64 @llvm.coro.size.i64()
+  %mem = call noalias nonnull ptr @malloc(i64 %size)
+  %hdl = call ptr @llvm.coro.begin(token %id, ptr %mem)
+  store ptr null, ptr %exception.obj, align 8
+  br label %while
+
+while:
+  %save = call token @llvm.coro.save(ptr null)
+  %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
+  switch i8 %suspend, label %coro.ret [
+  i8 0, label %await.ready
+  ]
+
+await.ready:
+  invoke void @throw()
+  to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch:
+  %switch = catchswitch within none [label %catch] unwind label %ehcleanup
+
+catch:
+  %pad = catchpad within %switch [ptr null, i32 8, ptr %exception.obj]
+  invoke void @use(ptr %exception.obj) [ "funclet"(token %pad) ]
+  to label %catch.ret unwind label %ehcleanup
+
+catch.ret:
+  catchret from %pad to label %while
+
+ehcleanup:
+  %cleanup = cleanuppad within none []
+  call void @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %cleanup) ]
+  cleanupret from %cleanup unwind to caller
+
+coro.ret:
+  call void @llvm.coro.end(ptr null, i1 false, token none)
+  ret void
+
+unreachable:
+  unreachable
+}
+
+declare ptr @malloc(i64)
+declare void @throw()
+declare void @use(ptr)
diff --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
index fd91066b994a5..278cce20119c6 100644
--- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp
+++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp
@@ -733,11 +733,12 @@ TEST(AllStrategies, SkipEHPad) {
   StringRef Source = "\n\
     define void @f(i32 %x) personality ptr @__CxxFrameHandler3 { \n\
     entry: \n\
+      %I = alloca i32, align 4 \n\
       invoke void @g() to label %try.cont unwind label %catch.dispatch \n\
     catch.dispatch: \n\
       %0 = catchswitch within none [label %catch] unwind to caller \n\
     catch: \n\
-      %1 = catchpad within %0 [ptr null, i32 64, ptr null] \n\
+      %1 = catchpad within %0 [ptr null, i32 64, ptr %I] \n\
       catchret from %1 to label %try.cont \n\
     try.cont: \n\
       ret void \n\

``````````

</details>


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


More information about the llvm-branch-commits mailing list