[llvm] e32f8e5 - [Windows EH] Fix the order of Nested try-catches in $tryMap$ table
Ten Tzen via llvm-commits
llvm-commits at lists.llvm.org
Fri May 15 22:05:31 PDT 2020
Author: Ten Tzen
Date: 2020-05-15T22:03:43-07:00
New Revision: e32f8e5d4ae88c2934f310f3f8a762f969bc6793
URL: https://github.com/llvm/llvm-project/commit/e32f8e5d4ae88c2934f310f3f8a762f969bc6793
DIFF: https://github.com/llvm/llvm-project/commit/e32f8e5d4ae88c2934f310f3f8a762f969bc6793.diff
LOG: [Windows EH] Fix the order of Nested try-catches in $tryMap$ table
This bug is exposed by Test7 of ehthrow.cxx in MSVC EH suite where
a rethrow occurs in a try-catch inside a catch (i.e., a nested Catch
handlers). See the test code in
https://github.com/microsoft/compiler-tests/blob/master/eh/ehthrow.cxx#L346
When an object is rethrown in a Catch handler, the copy-ctor of this
object must be executed after the destructions of live objects, but
BEFORE the dtors of live objects in parent handlers.
Today Windows 64-bit runtime (__CxxFrameHandler3 & 4) expects nested Catch
handers
are stored in pre-order (outer first, inner next) in $tryMap$ table, so
that given a State, its Catch's beginning State can be properly
retrieved. The Catch beginning state (which is also the ending State) is
the State where rethrown object's copy-ctor must take place.
LLVM currently stores nested catch handlers in post-ordering because
it's the natural way to compute the highest State in Catch.
The fix is to simply store TryCatch handler in pre-order, but update
Catch's highest State after child Catches are all processed.
Differential Revision: https://reviews.llvm.org/D79474?id=263919
Added:
llvm/test/CodeGen/AArch64/win-catchpad-nested-cxx.ll
Modified:
llvm/lib/CodeGen/WinEHPrepare.cpp
llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index c9c1bf84ab30..bd03984f2079 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -263,6 +263,16 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
// 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 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
}
}
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
index 000000000000..e3e439101b5e
--- /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 at 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 at 4HA"
+; CHECK-NEXT: .word 0
+
+; CHECK: $ip2state$try_in_catch:
+; CHECK-NEXT: .word .Lfunc_begin0 at IMGREL
+; CHECK-NEXT: .word -1
+; CHECK-NEXT: .word .Ltmp0 at IMGREL
+; CHECK-NEXT: .word 0
+; CHECK-NEXT: .word .Ltmp1 at IMGREL
+; CHECK-NEXT: .word -1
+; CHECK-NEXT: .word "?catch$2@?0?try_in_catch at 4HA"@IMGREL
+; CHECK-NEXT: .word 1
+; CHECK-NEXT: .word .Ltmp2 at IMGREL
+; CHECK-NEXT: .word 2
+; CHECK-NEXT: .word .Ltmp3 at IMGREL
+; CHECK-NEXT: .word 1
+; CHECK-NEXT: .word "?catch$4@?0?try_in_catch at 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
index ac4598385cd1..a95d99fd465b 100644
--- a/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll
+++ b/llvm/test/CodeGen/X86/win-catchpad-nested-cxx.ll
@@ -62,17 +62,29 @@ handler2:
; 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
More information about the llvm-commits
mailing list