[WinEH] Fix ESP management with 32-bit __CxxFrameHandler3
authorReid Kleckner <rnk@google.com>
Fri, 13 Nov 2015 21:27:00 +0000 (21:27 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 13 Nov 2015 21:27:00 +0000 (21:27 +0000)
The C++ EH personality automatically restores ESP from the C++ EH
registration node after a catchret. I mistakenly thought it was like
SEH, which does not restore ESP.

It makes sense for C++ EH to differ from SEH here because SEH does not
use funclets for catches, and does not allow catching inside of finally.
C++ EH may need to unwind through multiple catch funclets and eventually
catchret to some outer funclet. Therefore, the runtime has to keep track
of which ESP to use with catchret, rather than having the compiler
reload it manually.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253084 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/X86ExpandPseudo.cpp
lib/Target/X86/X86FrameLowering.cpp
test/CodeGen/X86/catchret-fallthrough.ll
test/CodeGen/X86/win-catchpad-csrs.ll
test/CodeGen/X86/win-catchpad.ll

index 9e5a51c4da1c39986befadf105d4369e405cf1d4..6015d3465de3f1d642e8abca5b7a3da112507e1c 100644 (file)
@@ -19,6 +19,7 @@
 #include "X86InstrInfo.h"
 #include "X86MachineFunctionInfo.h"
 #include "X86Subtarget.h"
+#include "llvm/Analysis/LibCallSemantics.h"
 #include "llvm/CodeGen/Passes.h" // For IDs of passes that are preserved.
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -144,7 +145,9 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
 
   case X86::EH_RESTORE: {
     // Restore ESP and EBP, and optionally ESI if required.
-    X86FL->restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/true);
+    bool IsSEH = isAsynchronousEHPersonality(classifyEHPersonality(
+        MBB.getParent()->getFunction()->getPersonalityFn()));
+    X86FL->restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/IsSEH);
     MBBI->eraseFromParent();
     return true;
   }
index 302fc93674452406750d6ff52189d3cdb4b772a3..394151b0b06f4ef72d60d49c6d9f29a373673838 100644 (file)
@@ -1246,6 +1246,19 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
   } else if (IsFunclet && STI.is32Bit()) {
     // Reset EBP / ESI to something good for funclets.
     MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
+    // If we're a catch funclet, we can be returned to via catchret. Save ESP
+    // into the registration node so that the runtime will restore it for us.
+    if (!MBB.isCleanupFuncletEntry()) {
+      assert(classifyEHPersonality(Fn->getPersonalityFn()) ==
+             EHPersonality::MSVC_CXX);
+      unsigned FrameReg;
+      int FI = MMI.getWinEHFuncInfo(Fn).EHRegNodeFrameIndex;
+      int64_t EHRegOffset = getFrameIndexReference(MF, FI, FrameReg);
+      // ESP is the first field, so no extra displacement is needed.
+      addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), FrameReg,
+                   false, EHRegOffset)
+          .addReg(X86::ESP);
+    }
   }
 
   while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) {
index 497f6fb3a9d8c472a87404acf6321da020ddc82f..f732566d0cbfbb68a1b990e9ec897ea2a3ff852c 100644 (file)
@@ -41,6 +41,5 @@ nrvo.skipdtor:                                    ; preds = %invoke.cont.3, %inv
 ; CHECK-NOT: jmp
 ; CHECK-NOT: movl {{.*}}, %esp
 ; CHECK: retl
-; CHECK: movl {{.*}}, %esp
 ; CHECK: addl $12, %ebp
 ; CHECK: jmp LBB0_{{.*}}
index f759a4ef0d96754a681f7e768a0c9000626ef42f..b6b4a9319b09fb70cca188bb3498dfcc590b8d5d 100644 (file)
@@ -67,7 +67,6 @@ catchendblock:                                    ; preds = %catch,
 ; X86: retl
 
 ; X86: [[restorebb:LBB0_[0-9]+]]:
-; X86: movl -16(%ebp), %esp
 ; X86: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
index 826fae522a30d9921063b321776ac2129af561cd..d9c8307cb083c88b2b2052012d050fc8b4742ee0 100644 (file)
@@ -66,6 +66,7 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 }
 
 ; X86-LABEL: _try_catch_catch:
+; X86: movl %esp, -[[sp_offset:[0-9]+]](%ebp)
 ; X86: movl $0, -{{[0-9]+}}(%ebp)
 ; X86: leal -[[local_offs:[0-9]+]](%ebp), %[[addr_reg:[a-z]+]]
 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
@@ -76,15 +77,13 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 
 ; X86: [[restorebb1:LBB0_[0-9]+]]: # Block address taken
 ; X86-NEXT:                        # %invoke.cont.2
-; X86: movl -16(%ebp), %esp
-; X86: addl $12, %ebp
+; X86-NEXT: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
 ; FIXME: These should be de-duplicated.
 ; X86: [[restorebb2:LBB0_[0-9]+]]: # Block address taken
 ; X86-NEXT:                        # %invoke.cont.3
-; X86: movl -16(%ebp), %esp
-; X86: addl $12, %ebp
+; X86-NEXT: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
 ; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
@@ -92,6 +91,7 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86: pushl %ebp
 ; X86: subl $8, %esp
 ; X86: addl $12, %ebp
+; X86: movl %esp, -[[sp_offset]](%ebp)
 ; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
 ; X86: movl -32(%ebp), %[[e_reg:[a-z]+]]
 ; X86: movl $1, -{{[0-9]+}}(%ebp)
@@ -108,6 +108,7 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86: pushl %ebp
 ; X86: subl $8, %esp
 ; X86: addl $12, %ebp
+; X86: movl %esp, -[[sp_offset]](%ebp)
 ; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
 ; X86: movl $1, -{{[0-9]+}}(%ebp)
 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
@@ -258,8 +259,7 @@ catchendblock:
 
 ; X86: [[restorebb:LBB1_[0-9]+]]: # Block address taken
 ; X86-NEXT:                       # %catch.done
-; X86: movl -16(%ebp), %esp
-; X86: addl $12, %ebp
+; X86-NEXT: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
 ; X86: "?catch$[[catchdispbb:[0-9]+]]@?0?branch_to_normal_dest@4HA":