[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