From 5038ce85da400d9a3a24a5f52922c713589dfdda Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 21 Sep 2023 09:13:27 +0200 Subject: [PATCH 1/3] [X86] Add test for #66984 (NFC) (cherry picked from commit 8b4e29b35d21b079e8b30244cbbfc4d4bc4a29d4) --- llvm/test/CodeGen/X86/stack-coloring-seh.ll | 109 ++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 llvm/test/CodeGen/X86/stack-coloring-seh.ll diff --git a/llvm/test/CodeGen/X86/stack-coloring-seh.ll b/llvm/test/CodeGen/X86/stack-coloring-seh.ll new file mode 100644 index 000000000000..3995bfa8101d --- /dev/null +++ b/llvm/test/CodeGen/X86/stack-coloring-seh.ll @@ -0,0 +1,109 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3 +; RUN: llc -mtriple=i686-windows-msvc < %s | FileCheck %s + +@type_info = external global ptr + +; FIXME: This is a miscompile. +define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { +; CHECK-LABEL: pr66984: +; CHECK: # %bb.0: # %bb +; CHECK-NEXT: pushl %ebp +; CHECK-NEXT: movl %esp, %ebp +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: pushl %edi +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: subl $20, %esp +; CHECK-NEXT: movl %esp, -28(%ebp) +; CHECK-NEXT: movl $-1, -16(%ebp) +; CHECK-NEXT: leal -24(%ebp), %eax +; CHECK-NEXT: movl $___ehhandler$pr66984, -20(%ebp) +; CHECK-NEXT: movl %fs:0, %ecx +; CHECK-NEXT: movl %ecx, -24(%ebp) +; CHECK-NEXT: movl %eax, %fs:0 +; CHECK-NEXT: movl $1, -16(%ebp) +; CHECK-NEXT: calll _throw +; CHECK-NEXT: # %bb.1: # %bb14 +; CHECK-NEXT: LBB0_3: # Block address taken +; CHECK-NEXT: # %bb17 +; CHECK-NEXT: addl $12, %ebp +; CHECK-NEXT: jmp LBB0_4 +; CHECK-NEXT: LBB0_4: # %exit +; CHECK-NEXT: $ehgcr_0_4: +; CHECK-NEXT: movl -24(%ebp), %eax +; CHECK-NEXT: movl %eax, %fs:0 +; CHECK-NEXT: addl $20, %esp +; CHECK-NEXT: popl %esi +; CHECK-NEXT: popl %edi +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: popl %ebp +; CHECK-NEXT: retl +; CHECK-NEXT: .def "?catch$2@?0?pr66984@4HA"; +; CHECK-NEXT: .scl 3; +; CHECK-NEXT: .type 32; +; CHECK-NEXT: .endef +; CHECK-NEXT: .p2align 4, 0x90 +; CHECK-NEXT: "?catch$2@?0?pr66984@4HA": +; CHECK-NEXT: LBB0_2: # %bb17 +; CHECK-NEXT: pushl %ebp +; CHECK-NEXT: addl $12, %ebp +; CHECK-NEXT: movl %esp, -28(%ebp) +; CHECK-NEXT: movl -32(%ebp), %ecx +; CHECK-NEXT: movl $2, -16(%ebp) +; CHECK-NEXT: calll _cleanup +; CHECK-NEXT: movl $LBB0_3, %eax +; CHECK-NEXT: popl %ebp +; CHECK-NEXT: retl # CATCHRET +; CHECK-NEXT: .def "?dtor$5@?0?pr66984@4HA"; +; CHECK-NEXT: .scl 3; +; CHECK-NEXT: .type 32; +; CHECK-NEXT: .endef +; CHECK-NEXT: .p2align 4, 0x90 +; CHECK-NEXT: "?dtor$5@?0?pr66984@4HA": +; CHECK-NEXT: LBB0_5: # %bb8 +; CHECK-NEXT: pushl %ebp +; CHECK-NEXT: addl $12, %ebp +; CHECK-NEXT: movl 8(%ebp), %eax +; CHECK-NEXT: movl %eax, -32(%ebp) +; CHECK-NEXT: leal -32(%ebp), %ecx +; CHECK-NEXT: calll _foo +; CHECK-NEXT: popl %ebp +; CHECK-NEXT: retl # CLEANUPRET +; CHECK-NEXT: Lfunc_end0: +bb: + %a1 = alloca ptr, align 4 + %a2 = alloca ptr, align 4 + call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a2) + invoke void @throw() + to label %bb14 unwind label %bb8 + +bb8: ; preds = %bb7 + %i9 = cleanuppad within none [] + call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a1) + store ptr %arg, ptr %a1, align 4 + call fastcc void @foo(ptr %a1) [ "funclet"(token %i9) ] + call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a1) + cleanupret from %i9 unwind label %bb15 + +bb14: ; preds = %bb7 + unreachable + +bb15: ; preds = %bb13, %bb5 + %cs = catchswitch within none [label %bb17] unwind to caller + +bb17: ; preds = %bb15 + %cp = catchpad within %cs [ptr @type_info, i32 8, ptr %a2] + %p = load ptr, ptr %a2, align 4 + call fastcc void @cleanup(ptr %p) [ "funclet"(token %cp) ] + catchret from %cp to label %exit + +exit: + call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a2) + ret void +} + +declare i32 @__CxxFrameHandler3(...) +declare void @throw() +declare void @cleanup(ptr) +declare void @foo(ptr) +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) From f95cccd18dee894d4ad28286a0abd5b4d91d8258 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 21 Sep 2023 09:13:27 +0200 Subject: [PATCH 2/3] [StackColoring] Handle SEH catch object stack slots conservatively The write to the SEH catch object happens before cleanuppads are executed, while the first reference to the object will typically be in a catchpad. If we make use of first-use analysis, we may end up allocating an alloca used inside the cleanuppad and the catch object at the same stack offset, which would be incorrect. https://reviews.llvm.org/D86673 was a previous attempt to fix it. It used the heuristic "a slot loaded in a WinEH pad and never written" to detect catch objects. However, because it checks for more than one load (while probably more than zero was intended), the fix does not actually work. The general approach also seems dubious to me, so this patch reverts that change entirely, and instead marks all catch object slots as conservative (i.e. excluded from first-use analysis) based on the WinEHFuncInfo. As far as I can tell we don't need any heuristics here, we know exactly which slots are affected. Fixes https://github.com/llvm/llvm-project/issues/66984. (cherry picked from commit b3cb4f069c2cb99bdae68d6906156af20e76314f) --- llvm/lib/CodeGen/StackColoring.cpp | 61 ++++--------------- ...oloring-seh.ll => stack-coloring-wineh.ll} | 8 +-- 2 files changed, 17 insertions(+), 52 deletions(-) rename llvm/test/CodeGen/X86/{stack-coloring-seh.ll => stack-coloring-wineh.ll} (95%) diff --git a/llvm/lib/CodeGen/StackColoring.cpp b/llvm/lib/CodeGen/StackColoring.cpp index 66b9086e1d88..10597daff54f 100644 --- a/llvm/lib/CodeGen/StackColoring.cpp +++ b/llvm/lib/CodeGen/StackColoring.cpp @@ -370,37 +370,6 @@ STATISTIC(EscapedAllocas, "Number of allocas that escaped the lifetime region"); // If in RPO ordering chosen to walk the CFG we happen to visit the b[k] // before visiting the memcpy block (which will contain the lifetime start // for "b" then it will appear that 'b' has a degenerate lifetime. -// -// Handle Windows Exception with LifetimeStartOnFirstUse: -// ----------------- -// -// There was a bug for using LifetimeStartOnFirstUse in win32. -// class Type1 { -// ... -// ~Type1(){ write memory;} -// } -// ... -// try{ -// Type1 V -// ... -// } catch (Type2 X){ -// ... -// } -// For variable X in catch(X), we put point pX=&(&X) into ConservativeSlots -// to prevent using LifetimeStartOnFirstUse. Because pX may merged with -// object V which may call destructor after implicitly writing pX. All these -// are done in C++ EH runtime libs (through CxxThrowException), and can't -// obviously check it in IR level. -// -// The loader of pX, without obvious writing IR, is usually the first LOAD MI -// in EHPad, Some like: -// bb.x.catch.i (landing-pad, ehfunclet-entry): -// ; predecessors: %bb... -// successors: %bb... -// %n:gr32 = MOV32rm %stack.pX ... -// ... -// The Type2** %stack.pX will only be written in EH runtime libs, so we -// check the StoreSlots to screen it out. namespace { @@ -462,9 +431,6 @@ class StackColoring : public MachineFunctionPass { /// slots lifetime-start-on-first-use is disabled). BitVector ConservativeSlots; - /// Record the FI slots referenced by a 'may write to memory'. - BitVector StoreSlots; - /// Number of iterations taken during data flow analysis. unsigned NumIterations; @@ -660,13 +626,10 @@ unsigned StackColoring::collectMarkers(unsigned NumSlot) { InterestingSlots.resize(NumSlot); ConservativeSlots.clear(); ConservativeSlots.resize(NumSlot); - StoreSlots.clear(); - StoreSlots.resize(NumSlot); // number of start and end lifetime ops for each slot SmallVector NumStartLifetimes(NumSlot, 0); SmallVector NumEndLifetimes(NumSlot, 0); - SmallVector NumLoadInCatchPad(NumSlot, 0); // Step 1: collect markers and populate the "InterestingSlots" // and "ConservativeSlots" sets. @@ -722,13 +685,6 @@ unsigned StackColoring::collectMarkers(unsigned NumSlot) { if (! BetweenStartEnd.test(Slot)) { ConservativeSlots.set(Slot); } - // Here we check the StoreSlots to screen catch point out. For more - // information, please refer "Handle Windows Exception with - // LifetimeStartOnFirstUse" at the head of this file. - if (MI.mayStore()) - StoreSlots.set(Slot); - if (MF->getWinEHFuncInfo() && MBB->isEHPad() && MI.mayLoad()) - NumLoadInCatchPad[Slot] += 1; } } } @@ -739,14 +695,23 @@ unsigned StackColoring::collectMarkers(unsigned NumSlot) { return 0; } - // 1) PR27903: slots with multiple start or end lifetime ops are not + // PR27903: slots with multiple start or end lifetime ops are not // safe to enable for "lifetime-start-on-first-use". - // 2) And also not safe for variable X in catch(X) in windows. for (unsigned slot = 0; slot < NumSlot; ++slot) { - if (NumStartLifetimes[slot] > 1 || NumEndLifetimes[slot] > 1 || - (NumLoadInCatchPad[slot] > 1 && !StoreSlots.test(slot))) + if (NumStartLifetimes[slot] > 1 || NumEndLifetimes[slot] > 1) ConservativeSlots.set(slot); } + + // The write to the catch object by the personality function is not propely + // modeled in IR: It happens before any cleanuppads are executed, even if the + // first mention of the catch object is in a catchpad. As such, mark catch + // object slots as conservative, so they are excluded from first-use analysis. + if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo()) + for (WinEHTryBlockMapEntry &TBME : EHInfo->TryBlockMap) + for (WinEHHandlerType &H : TBME.HandlerArray) + if (H.CatchObj.FrameIndex != std::numeric_limits::max()) + ConservativeSlots.set(H.CatchObj.FrameIndex); + LLVM_DEBUG(dumpBV("Conservative slots", ConservativeSlots)); // Step 2: compute begin/end sets for each block diff --git a/llvm/test/CodeGen/X86/stack-coloring-seh.ll b/llvm/test/CodeGen/X86/stack-coloring-wineh.ll similarity index 95% rename from llvm/test/CodeGen/X86/stack-coloring-seh.ll rename to llvm/test/CodeGen/X86/stack-coloring-wineh.ll index 3995bfa8101d..892c81a12dc1 100644 --- a/llvm/test/CodeGen/X86/stack-coloring-seh.ll +++ b/llvm/test/CodeGen/X86/stack-coloring-wineh.ll @@ -3,7 +3,7 @@ @type_info = external global ptr -; FIXME: This is a miscompile. +; Make sure %a1 and %a2 don't share the same stack offset. define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { ; CHECK-LABEL: pr66984: ; CHECK: # %bb.0: # %bb @@ -12,7 +12,7 @@ define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { ; CHECK-NEXT: pushl %ebx ; CHECK-NEXT: pushl %edi ; CHECK-NEXT: pushl %esi -; CHECK-NEXT: subl $20, %esp +; CHECK-NEXT: subl $24, %esp ; CHECK-NEXT: movl %esp, -28(%ebp) ; CHECK-NEXT: movl $-1, -16(%ebp) ; CHECK-NEXT: leal -24(%ebp), %eax @@ -31,7 +31,7 @@ define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { ; CHECK-NEXT: $ehgcr_0_4: ; CHECK-NEXT: movl -24(%ebp), %eax ; CHECK-NEXT: movl %eax, %fs:0 -; CHECK-NEXT: addl $20, %esp +; CHECK-NEXT: addl $24, %esp ; CHECK-NEXT: popl %esi ; CHECK-NEXT: popl %edi ; CHECK-NEXT: popl %ebx @@ -47,7 +47,7 @@ define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { ; CHECK-NEXT: pushl %ebp ; CHECK-NEXT: addl $12, %ebp ; CHECK-NEXT: movl %esp, -28(%ebp) -; CHECK-NEXT: movl -32(%ebp), %ecx +; CHECK-NEXT: movl -36(%ebp), %ecx ; CHECK-NEXT: movl $2, -16(%ebp) ; CHECK-NEXT: calll _cleanup ; CHECK-NEXT: movl $LBB0_3, %eax From 21f613313852b25d2002ddcd9489abbb9931310b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 22 Sep 2023 12:25:56 +0200 Subject: [PATCH 3/3] [StackColoring] Handle fixed object index This is a followup to #66988. The implementation there did not account for the possibility of the catch object frame index referrring to a fixed object, which is the case on win64. (cherry picked from commit aa70f4d8cf8f09a2997773156289b16d6a16ec01) --- llvm/lib/CodeGen/StackColoring.cpp | 3 +- llvm/test/CodeGen/X86/stack-coloring-wineh.ll | 211 ++++++++++++------ 2 files changed, 148 insertions(+), 66 deletions(-) diff --git a/llvm/lib/CodeGen/StackColoring.cpp b/llvm/lib/CodeGen/StackColoring.cpp index 10597daff54f..3453b718b453 100644 --- a/llvm/lib/CodeGen/StackColoring.cpp +++ b/llvm/lib/CodeGen/StackColoring.cpp @@ -709,7 +709,8 @@ unsigned StackColoring::collectMarkers(unsigned NumSlot) { if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo()) for (WinEHTryBlockMapEntry &TBME : EHInfo->TryBlockMap) for (WinEHHandlerType &H : TBME.HandlerArray) - if (H.CatchObj.FrameIndex != std::numeric_limits::max()) + if (H.CatchObj.FrameIndex != std::numeric_limits::max() && + H.CatchObj.FrameIndex >= 0) ConservativeSlots.set(H.CatchObj.FrameIndex); LLVM_DEBUG(dumpBV("Conservative slots", ConservativeSlots)); diff --git a/llvm/test/CodeGen/X86/stack-coloring-wineh.ll b/llvm/test/CodeGen/X86/stack-coloring-wineh.ll index 892c81a12dc1..79057e0ea78d 100644 --- a/llvm/test/CodeGen/X86/stack-coloring-wineh.ll +++ b/llvm/test/CodeGen/X86/stack-coloring-wineh.ll @@ -1,74 +1,155 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3 -; RUN: llc -mtriple=i686-windows-msvc < %s | FileCheck %s +; RUN: llc -mtriple=i686-windows-msvc < %s | FileCheck %s --check-prefix=I686 +; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s --check-prefix=X86_64 @type_info = external global ptr ; Make sure %a1 and %a2 don't share the same stack offset. define void @pr66984(ptr %arg) personality ptr @__CxxFrameHandler3 { -; CHECK-LABEL: pr66984: -; CHECK: # %bb.0: # %bb -; CHECK-NEXT: pushl %ebp -; CHECK-NEXT: movl %esp, %ebp -; CHECK-NEXT: pushl %ebx -; CHECK-NEXT: pushl %edi -; CHECK-NEXT: pushl %esi -; CHECK-NEXT: subl $24, %esp -; CHECK-NEXT: movl %esp, -28(%ebp) -; CHECK-NEXT: movl $-1, -16(%ebp) -; CHECK-NEXT: leal -24(%ebp), %eax -; CHECK-NEXT: movl $___ehhandler$pr66984, -20(%ebp) -; CHECK-NEXT: movl %fs:0, %ecx -; CHECK-NEXT: movl %ecx, -24(%ebp) -; CHECK-NEXT: movl %eax, %fs:0 -; CHECK-NEXT: movl $1, -16(%ebp) -; CHECK-NEXT: calll _throw -; CHECK-NEXT: # %bb.1: # %bb14 -; CHECK-NEXT: LBB0_3: # Block address taken -; CHECK-NEXT: # %bb17 -; CHECK-NEXT: addl $12, %ebp -; CHECK-NEXT: jmp LBB0_4 -; CHECK-NEXT: LBB0_4: # %exit -; CHECK-NEXT: $ehgcr_0_4: -; CHECK-NEXT: movl -24(%ebp), %eax -; CHECK-NEXT: movl %eax, %fs:0 -; CHECK-NEXT: addl $24, %esp -; CHECK-NEXT: popl %esi -; CHECK-NEXT: popl %edi -; CHECK-NEXT: popl %ebx -; CHECK-NEXT: popl %ebp -; CHECK-NEXT: retl -; CHECK-NEXT: .def "?catch$2@?0?pr66984@4HA"; -; CHECK-NEXT: .scl 3; -; CHECK-NEXT: .type 32; -; CHECK-NEXT: .endef -; CHECK-NEXT: .p2align 4, 0x90 -; CHECK-NEXT: "?catch$2@?0?pr66984@4HA": -; CHECK-NEXT: LBB0_2: # %bb17 -; CHECK-NEXT: pushl %ebp -; CHECK-NEXT: addl $12, %ebp -; CHECK-NEXT: movl %esp, -28(%ebp) -; CHECK-NEXT: movl -36(%ebp), %ecx -; CHECK-NEXT: movl $2, -16(%ebp) -; CHECK-NEXT: calll _cleanup -; CHECK-NEXT: movl $LBB0_3, %eax -; CHECK-NEXT: popl %ebp -; CHECK-NEXT: retl # CATCHRET -; CHECK-NEXT: .def "?dtor$5@?0?pr66984@4HA"; -; CHECK-NEXT: .scl 3; -; CHECK-NEXT: .type 32; -; CHECK-NEXT: .endef -; CHECK-NEXT: .p2align 4, 0x90 -; CHECK-NEXT: "?dtor$5@?0?pr66984@4HA": -; CHECK-NEXT: LBB0_5: # %bb8 -; CHECK-NEXT: pushl %ebp -; CHECK-NEXT: addl $12, %ebp -; CHECK-NEXT: movl 8(%ebp), %eax -; CHECK-NEXT: movl %eax, -32(%ebp) -; CHECK-NEXT: leal -32(%ebp), %ecx -; CHECK-NEXT: calll _foo -; CHECK-NEXT: popl %ebp -; CHECK-NEXT: retl # CLEANUPRET -; CHECK-NEXT: Lfunc_end0: +; I686-LABEL: pr66984: +; I686: # %bb.0: # %bb +; I686-NEXT: pushl %ebp +; I686-NEXT: movl %esp, %ebp +; I686-NEXT: pushl %ebx +; I686-NEXT: pushl %edi +; I686-NEXT: pushl %esi +; I686-NEXT: subl $24, %esp +; I686-NEXT: movl %esp, -28(%ebp) +; I686-NEXT: movl $-1, -16(%ebp) +; I686-NEXT: leal -24(%ebp), %eax +; I686-NEXT: movl $___ehhandler$pr66984, -20(%ebp) +; I686-NEXT: movl %fs:0, %ecx +; I686-NEXT: movl %ecx, -24(%ebp) +; I686-NEXT: movl %eax, %fs:0 +; I686-NEXT: movl $1, -16(%ebp) +; I686-NEXT: calll _throw +; I686-NEXT: # %bb.1: # %bb14 +; I686-NEXT: LBB0_3: # Block address taken +; I686-NEXT: # %bb17 +; I686-NEXT: addl $12, %ebp +; I686-NEXT: jmp LBB0_4 +; I686-NEXT: LBB0_4: # %exit +; I686-NEXT: $ehgcr_0_4: +; I686-NEXT: movl -24(%ebp), %eax +; I686-NEXT: movl %eax, %fs:0 +; I686-NEXT: addl $24, %esp +; I686-NEXT: popl %esi +; I686-NEXT: popl %edi +; I686-NEXT: popl %ebx +; I686-NEXT: popl %ebp +; I686-NEXT: retl +; I686-NEXT: .def "?catch$2@?0?pr66984@4HA"; +; I686-NEXT: .scl 3; +; I686-NEXT: .type 32; +; I686-NEXT: .endef +; I686-NEXT: .p2align 4, 0x90 +; I686-NEXT: "?catch$2@?0?pr66984@4HA": +; I686-NEXT: LBB0_2: # %bb17 +; I686-NEXT: pushl %ebp +; I686-NEXT: addl $12, %ebp +; I686-NEXT: movl %esp, -28(%ebp) +; I686-NEXT: movl -36(%ebp), %ecx +; I686-NEXT: movl $2, -16(%ebp) +; I686-NEXT: calll _cleanup +; I686-NEXT: movl $LBB0_3, %eax +; I686-NEXT: popl %ebp +; I686-NEXT: retl # CATCHRET +; I686-NEXT: .def "?dtor$5@?0?pr66984@4HA"; +; I686-NEXT: .scl 3; +; I686-NEXT: .type 32; +; I686-NEXT: .endef +; I686-NEXT: .p2align 4, 0x90 +; I686-NEXT: "?dtor$5@?0?pr66984@4HA": +; I686-NEXT: LBB0_5: # %bb8 +; I686-NEXT: pushl %ebp +; I686-NEXT: addl $12, %ebp +; I686-NEXT: movl 8(%ebp), %eax +; I686-NEXT: movl %eax, -32(%ebp) +; I686-NEXT: leal -32(%ebp), %ecx +; I686-NEXT: calll _foo +; I686-NEXT: popl %ebp +; I686-NEXT: retl # CLEANUPRET +; I686-NEXT: Lfunc_end0: +; +; X86_64-LABEL: pr66984: +; X86_64: # %bb.0: # %bb +; X86_64-NEXT: pushq %rbp +; X86_64-NEXT: .seh_pushreg %rbp +; X86_64-NEXT: subq $64, %rsp +; X86_64-NEXT: .seh_stackalloc 64 +; X86_64-NEXT: leaq {{[0-9]+}}(%rsp), %rbp +; X86_64-NEXT: .seh_setframe %rbp, 64 +; X86_64-NEXT: .seh_endprologue +; X86_64-NEXT: movq $-2, -16(%rbp) +; X86_64-NEXT: movq %rcx, {{[-0-9]+}}(%r{{[sb]}}p) # 8-byte Spill +; X86_64-NEXT: .Ltmp0: +; X86_64-NEXT: callq throw +; X86_64-NEXT: .Ltmp1: +; X86_64-NEXT: # %bb.1: # %bb14 +; X86_64-NEXT: .LBB0_3: # Block address taken +; X86_64-NEXT: # %exit +; X86_64-NEXT: $ehgcr_0_3: +; X86_64-NEXT: nop +; X86_64-NEXT: addq $64, %rsp +; X86_64-NEXT: popq %rbp +; X86_64-NEXT: retq +; X86_64-NEXT: .seh_handlerdata +; X86_64-NEXT: .long ($cppxdata$pr66984)@IMGREL +; X86_64-NEXT: .text +; X86_64-NEXT: .seh_endproc +; X86_64-NEXT: .def "?catch$2@?0?pr66984@4HA"; +; X86_64-NEXT: .scl 3; +; X86_64-NEXT: .type 32; +; X86_64-NEXT: .endef +; X86_64-NEXT: .p2align 4, 0x90 +; X86_64-NEXT: "?catch$2@?0?pr66984@4HA": +; X86_64-NEXT: .seh_proc "?catch$2@?0?pr66984@4HA" +; X86_64-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except +; X86_64-NEXT: .LBB0_2: # %bb17 +; X86_64-NEXT: movq %rdx, {{[0-9]+}}(%rsp) +; X86_64-NEXT: pushq %rbp +; X86_64-NEXT: .seh_pushreg %rbp +; X86_64-NEXT: subq $32, %rsp +; X86_64-NEXT: .seh_stackalloc 32 +; X86_64-NEXT: leaq 64(%rdx), %rbp +; X86_64-NEXT: .seh_endprologue +; X86_64-NEXT: movq -8(%rbp), %rcx +; X86_64-NEXT: callq cleanup +; X86_64-NEXT: leaq .LBB0_3(%rip), %rax +; X86_64-NEXT: addq $32, %rsp +; X86_64-NEXT: popq %rbp +; X86_64-NEXT: retq # CATCHRET +; X86_64-NEXT: .seh_handlerdata +; X86_64-NEXT: .long ($cppxdata$pr66984)@IMGREL +; X86_64-NEXT: .text +; X86_64-NEXT: .seh_endproc +; X86_64-NEXT: .def "?dtor$4@?0?pr66984@4HA"; +; X86_64-NEXT: .scl 3; +; X86_64-NEXT: .type 32; +; X86_64-NEXT: .endef +; X86_64-NEXT: .p2align 4, 0x90 +; X86_64-NEXT: "?dtor$4@?0?pr66984@4HA": +; X86_64-NEXT: .seh_proc "?dtor$4@?0?pr66984@4HA" +; X86_64-NEXT: .LBB0_4: # %bb8 +; X86_64-NEXT: movq %rdx, {{[0-9]+}}(%rsp) +; X86_64-NEXT: pushq %rbp +; X86_64-NEXT: .seh_pushreg %rbp +; X86_64-NEXT: subq $32, %rsp +; X86_64-NEXT: .seh_stackalloc 32 +; X86_64-NEXT: leaq 64(%rdx), %rbp +; X86_64-NEXT: .seh_endprologue +; X86_64-NEXT: movq {{[-0-9]+}}(%r{{[sb]}}p), %rax # 8-byte Reload +; X86_64-NEXT: movq %rax, -32(%rbp) +; X86_64-NEXT: leaq -32(%rbp), %rcx +; X86_64-NEXT: callq foo +; X86_64-NEXT: nop +; X86_64-NEXT: addq $32, %rsp +; X86_64-NEXT: popq %rbp +; X86_64-NEXT: retq # CLEANUPRET +; X86_64-NEXT: .Lfunc_end0: +; X86_64-NEXT: .seh_handlerdata +; X86_64-NEXT: .text +; X86_64-NEXT: .seh_endproc bb: %a1 = alloca ptr, align 4 %a2 = alloca ptr, align 4