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/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 { 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..a5fb67d59edd1 --- /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 nuw [[FN_FRAME:%.*]], ptr [[HDL]], i32 0, i32 1 +; 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 nuw [[FN_FRAME]], ptr [[HDL]], i32 0, i32 2 +; 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)