[CoroSplit] Never collect allocas used by catchpad into frame#186728
Conversation
|
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-coroutines Author: Weibo He (NewSigma) ChangesWe use Close #143235 Close #153949 Close #182584 Full diff: https://github.com/llvm/llvm-project/pull/186728.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Coroutines/SpillUtils.cpp b/llvm/lib/Transforms/Coroutines/SpillUtils.cpp
index 81fe0c9acd413..34efb4ebf469b 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) {
+ // Catch scope cannot contain suspension points, shortcut the traversal and
+ // keep exception object 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)
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) lldb-apilldb-api.functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.pyIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
|
The CI failure seems unrelated. |
|
Thanks for the code review, @ChuanqiXu9 @efriedma-quic . I will wait two days before landing it. |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/21753 Here is the relevant piece of the build log for the reference |
…86728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close llvm#143235 Close llvm#153949 Close llvm#182584
…86728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close llvm#143235 Close llvm#153949 Close llvm#182584
|
This fix resolves a reproducible segfault in clang‑cl when throwing exceptions inside coroutines. |
|
/cherry-pick 80603c6 |
|
/pull-request #193917 |
…86728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close llvm#143235 Close llvm#153949 Close llvm#182584
…86728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close llvm#143235 Close llvm#153949 Close llvm#182584
…86728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close llvm#143235 Close llvm#153949 Close llvm#182584
|
many thanks for this fix :) |
|
+1, huge thanks! I just updated from clang 22.1.3 to clang 22.1.7 and was able to remove quite a few |
Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used.
This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas.
Close #143235 Close #153949 Close #182584