[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:03 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-coroutines
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