diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -263,6 +263,16 @@ // catchpads are separate funclets in C++ EH due to the way rethrow works. int TryHigh = CatchLow - 1; + + // MSVC FrameHandler3/4 on x64&Arm64 expect Catch Handlers in $tryMap$ + // stored in pre-order (outer first, inner next), not post-order + // Add to map here. Fix the CatchHigh after children are processed + const Module *Mod = BB->getParent()->getParent(); + bool IsPreOrder = Triple(Mod->getTargetTriple()).isArch64Bit(); + if (IsPreOrder) + addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchLow, Handlers); + unsigned TBMEIdx = FuncInfo.TryBlockMap.size() - 1; + for (const auto *CatchPad : Handlers) { FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; for (const User *U : CatchPad->users()) { @@ -283,7 +293,12 @@ } } int CatchHigh = FuncInfo.getLastStateNumber(); - addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); + // Now child Catches are processed, update CatchHigh + if (IsPreOrder) + FuncInfo.TryBlockMap[TBMEIdx].CatchHigh = CatchHigh; + else // PostOrder + addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); + LLVM_DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n'); LLVM_DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh << '\n'); diff --git a/llvm/test/CodeGen/AArch64/win-catchpad-nested-cxx.ll b/llvm/test/CodeGen/AArch64/win-catchpad-nested-cxx.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/win-catchpad-nested-cxx.ll @@ -0,0 +1,100 @@ +; RUN: llc -verify-machineinstrs -mtriple=aarch64-pc-windows-msvc < %s \ +; RUN: | FileCheck --check-prefix=CHECK %s + +; Loosely based on IR for this C++ source code: +; void f(int p); +; void try_in_catch() { +; try { +; f(1); +; } catch (...) { +; try { +; f(2); +; } catch (...) { +; f(3); +; } +; } +; } + +declare void @f(i32 %p) +declare i32 @__CxxFrameHandler3(...) + +define i32 @try_in_catch() personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @f(i32 1) + to label %try.cont unwind label %catch.dispatch.1 +try.cont: + ret i32 0 + +catch.dispatch.1: + %cs1 = catchswitch within none [label %handler1] unwind to caller +handler1: + %h1 = catchpad within %cs1 [i8* null, i32 64, i8* null] + invoke void @f(i32 2) [ "funclet"(token %h1) ] + to label %catchret1 unwind label %catch.dispatch.2 +catchret1: + catchret from %h1 to label %try.cont + +catch.dispatch.2: + %cs2 = catchswitch within %h1 [label %handler2] unwind to caller +handler2: + %h2 = catchpad within %cs2 [i8* null, i32 64, i8* null] + call void @f(i32 3) + catchret from %h2 to label %catchret1 +} + +; CHECK-LABEL: $cppxdata$try_in_catch: +; CHECK-NEXT: .word 429065506 +; CHECK-NEXT: .word 4 +; CHECK-NEXT: .word ($stateUnwindMap$try_in_catch) +; CHECK-NEXT: .word 2 +; CHECK-NEXT: .word ($tryMap$try_in_catch) +; ip2state num + ptr +; CHECK-NEXT: .word 7 +; CHECK-NEXT: .word ($ip2state$try_in_catch) +; unwindhelp offset +; CHECK-NEXT: .word -16 +; CHECK-NEXT: .word 0 +; EHFlags +; CHECK-NEXT: .word 1 + +; CHECK-LABEL: $tryMap$try_in_catch: +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word 3 +; CHECK-NEXT: .word 1 +; CHECK-NEXT: .word ($handlerMap$0$try_in_catch) +; CHECK-NEXT: .word 2 +; CHECK-NEXT: .word 2 +; CHECK-NEXT: .word 3 +; CHECK-NEXT: .word 1 +; CHECK-NEXT: .word ($handlerMap$1$try_in_catch) + +; CHECK: $handlerMap$0$try_in_catch: +; CHECK-NEXT: .word 64 +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word "?catch${{[0-9]+}}@?0?try_in_catch@4HA" +; CHECK-NEXT: .word 0 + +; CHECK: $handlerMap$1$try_in_catch: +; CHECK-NEXT: .word 64 +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word "?catch${{[0-9]+}}@?0?try_in_catch@4HA" +; CHECK-NEXT: .word 0 + +; CHECK: $ip2state$try_in_catch: +; CHECK-NEXT: .word .Lfunc_begin0@IMGREL +; CHECK-NEXT: .word -1 +; CHECK-NEXT: .word .Ltmp0@IMGREL +; CHECK-NEXT: .word 0 +; CHECK-NEXT: .word .Ltmp1@IMGREL +; CHECK-NEXT: .word -1 +; CHECK-NEXT: .word "?catch$2@?0?try_in_catch@4HA"@IMGREL +; CHECK-NEXT: .word 1 +; CHECK-NEXT: .word .Ltmp2@IMGREL +; CHECK-NEXT: .word 2 +; CHECK-NEXT: .word .Ltmp3@IMGREL +; CHECK-NEXT: .word 1 +; CHECK-NEXT: .word "?catch$4@?0?try_in_catch@4HA"@IMGREL +; CHECK-NEXT: .word 3 diff --git a/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll b/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll --- a/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll +++ b/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll @@ -62,17 +62,29 @@ ; EHFlags ; CHECK-NEXT: .long 1 -; CHECK: $tryMap$try_in_catch: -; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long 3 -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long ($handlerMap$0$try_in_catch) -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 3 -; CHECK-NEXT: .long 1 -; CHECK-NEXT: .long ($handlerMap$1$try_in_catch) +; X86-LABEL: $tryMap$try_in_catch: +; X86-NEXT: .long 2 +; X86-NEXT: .long 2 +; X86-NEXT: .long 3 +; X86-NEXT: .long 1 +; X86-NEXT: .long ($handlerMap$0$try_in_catch) +; X86-NEXT: .long 0 +; X86-NEXT: .long 0 +; X86-NEXT: .long 3 +; X86-NEXT: .long 1 +; X86-NEXT: .long ($handlerMap$1$try_in_catch) + +; X64-LABEL: $tryMap$try_in_catch: +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long 3 +; X64-NEXT: .long 1 +; X64-NEXT: .long ($handlerMap$0$try_in_catch) +; X64-NEXT: .long 2 +; X64-NEXT: .long 2 +; X64-NEXT: .long 3 +; X64-NEXT: .long 1 +; X64-NEXT: .long ($handlerMap$1$try_in_catch) ; CHECK: $handlerMap$0$try_in_catch: ; CHECK-NEXT: .long 64