[llvm] r252266 - [WinEH] Split EH_RESTORE out of CATCHRET for 32-bit EH

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 5 17:49:06 PST 2015


Author: rnk
Date: Thu Nov  5 19:49:05 2015
New Revision: 252266

URL: http://llvm.org/viewvc/llvm-project?rev=252266&view=rev
Log:
[WinEH] Split EH_RESTORE out of CATCHRET for 32-bit EH

This adds the EH_RESTORE x86 pseudo instr, which is responsible for
restoring the stack pointers: EBP and ESP, and ESI if stack realignment
is involved. We only need this on 32-bit x86, because on x64 the runtime
restores CSRs for us.

Previously we had to keep the CATCHRET instruction around during SEH so
that we could convince X86FrameLowering to restore our frame pointers.
Now we can split these instructions earlier.

This was confusing, because we had a return instruction which wasn't
really a return and was ultimately going to be removed by
X86FrameLowering. This change also simplifies X86FrameLowering, which
really shouldn't be building new MBBs.

No observable functional change currently, but with the new register
mask stuff in D14407, CATCHRET will become a register allocator barrier,
and our existing tests rely on us having reasonable register allocation
around SEH.

Modified:
    llvm/trunk/lib/Target/X86/X86ExpandPseudo.cpp
    llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
    llvm/trunk/lib/Target/X86/X86FrameLowering.h
    llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
    llvm/trunk/lib/Target/X86/X86ISelLowering.h
    llvm/trunk/lib/Target/X86/X86InstrCompiler.td

Modified: llvm/trunk/lib/Target/X86/X86ExpandPseudo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ExpandPseudo.cpp?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ExpandPseudo.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ExpandPseudo.cpp Thu Nov  5 19:49:05 2015
@@ -141,6 +141,13 @@ bool X86ExpandPseudo::ExpandMI(MachineBa
     // The EH_RETURN pseudo is really removed during the MC Lowering.
     return true;
   }
+
+  case X86::EH_RESTORE: {
+    // Restore ESP and EBP, and optionally ESI if required.
+    X86FL->restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/true);
+    MBBI->eraseFromParent();
+    return true;
+  }
   }
   llvm_unreachable("Previous switch has a fallthrough?");
 }

Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.cpp?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Thu Nov  5 19:49:05 2015
@@ -1091,7 +1091,7 @@ void X86FrameLowering::emitEpilogue(Mach
   bool NeedsWinCFI =
       IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry();
   bool IsFunclet = isFuncletReturnInstr(MBBI);
-  MachineBasicBlock *RestoreMBB = nullptr;
+  MachineBasicBlock *TargetMBB = nullptr;
 
   // Get the number of bytes to allocate from the FrameInfo.
   uint64_t StackSize = MFI->getStackSize();
@@ -1100,45 +1100,19 @@ void X86FrameLowering::emitEpilogue(Mach
   uint64_t NumBytes = 0;
 
   if (MBBI->getOpcode() == X86::CATCHRET) {
+    // SEH shouldn't use catchret.
+    assert(!isAsynchronousEHPersonality(
+               classifyEHPersonality(MF.getFunction()->getPersonalityFn())) &&
+           "SEH should not use CATCHRET");
+
     NumBytes = getWinEHFuncletFrameSize(MF);
     assert(hasFP(MF) && "EH funclets without FP not yet implemented");
-    MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
-
-    // If this is SEH, this isn't really a funclet return.
-    bool IsSEH = isAsynchronousEHPersonality(
-        classifyEHPersonality(MF.getFunction()->getPersonalityFn()));
-    if (IsSEH) {
-      if (STI.is32Bit())
-        restoreWin32EHStackPointers(MBB, MBBI, DL, /*RestoreSP=*/true);
-      BuildMI(MBB, MBBI, DL, TII.get(X86::JMP_4)).addMBB(TargetMBB);
-      MBBI->eraseFromParent();
-      return;
-    }
-
-    // For 32-bit, create a new block for the restore code.
-    RestoreMBB = TargetMBB;
-    if (STI.is32Bit()) {
-      RestoreMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
-      MF.insert(TargetMBB->getIterator(), RestoreMBB);
-      MBB.removeSuccessor(TargetMBB);
-      MBB.addSuccessor(RestoreMBB);
-      RestoreMBB->addSuccessor(TargetMBB);
-      MBBI->getOperand(0).setMBB(RestoreMBB);
-    }
+    TargetMBB = MBBI->getOperand(0).getMBB();
 
     // Pop EBP.
     BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
             MachineFramePtr)
         .setMIFlag(MachineInstr::FrameDestroy);
-
-    // Insert frame restoration code in a new block.
-    if (STI.is32Bit()) {
-      auto RestoreMBBI = RestoreMBB->begin();
-      restoreWin32EHStackPointers(*RestoreMBB, RestoreMBBI, DL,
-                                  /*RestoreSP=*/true);
-      BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
-          .addMBB(TargetMBB);
-    }
   } else if (MBBI->getOpcode() == X86::CLEANUPRET) {
     NumBytes = getWinEHFuncletFrameSize(MF);
     assert(hasFP(MF) && "EH funclets without FP not yet implemented");
@@ -1178,26 +1152,26 @@ void X86FrameLowering::emitEpilogue(Mach
   }
   MachineBasicBlock::iterator FirstCSPop = MBBI;
 
-  if (RestoreMBB) {
+  if (TargetMBB) {
     // Fill EAX/RAX with the address of the target block.
     unsigned ReturnReg = STI.is64Bit() ? X86::RAX : X86::EAX;
     if (STI.is64Bit()) {
-      // LEA64r RestoreMBB(%rip), %rax
+      // LEA64r TargetMBB(%rip), %rax
       BuildMI(MBB, FirstCSPop, DL, TII.get(X86::LEA64r), ReturnReg)
           .addReg(X86::RIP)
           .addImm(0)
           .addReg(0)
-          .addMBB(RestoreMBB)
+          .addMBB(TargetMBB)
           .addReg(0);
     } else {
-      // MOV32ri $RestoreMBB, %eax
+      // MOV32ri $TargetMBB, %eax
       BuildMI(MBB, FirstCSPop, DL, TII.get(X86::MOV32ri))
           .addReg(ReturnReg)
-          .addMBB(RestoreMBB);
+          .addMBB(TargetMBB);
     }
-    // Record that we've taken the address of RestoreMBB and no longer just
+    // Record that we've taken the address of TargetMBB and no longer just
     // reference it in a terminator.
-    RestoreMBB->setHasAddressTaken();
+    TargetMBB->setHasAddressTaken();
   }
 
   if (MBBI != MBB.end())

Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.h?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.h (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.h Thu Nov  5 19:49:05 2015
@@ -129,6 +129,13 @@ public:
   void BuildCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
                 DebugLoc DL, MCCFIInstruction CFIInst) const;
 
+  /// Sets up EBP and optionally ESI based on the incoming EBP value.  Only
+  /// needed for 32-bit. Used in funclet prologues and at catchret destinations.
+  MachineBasicBlock::iterator
+  restoreWin32EHStackPointers(MachineBasicBlock &MBB,
+                              MachineBasicBlock::iterator MBBI, DebugLoc DL,
+                              bool RestoreSP = false) const;
+
 private:
   uint64_t calculateMaxStackAlign(const MachineFunction &MF) const;
 
@@ -148,13 +155,6 @@ private:
                                            DebugLoc DL, int64_t Offset,
                                            bool InEpilogue) const;
 
-  /// Sets up EBP and optionally ESI based on the incoming EBP value.  Only
-  /// needed for 32-bit. Used in funclet prologues and at catchret destinations.
-  MachineBasicBlock::iterator
-  restoreWin32EHStackPointers(MachineBasicBlock &MBB,
-                              MachineBasicBlock::iterator MBBI, DebugLoc DL,
-                              bool RestoreSP = false) const;
-
   unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
 };
 

Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Thu Nov  5 19:49:05 2015
@@ -21338,6 +21338,46 @@ X86TargetLowering::EmitLoweredWinAlloca(
 }
 
 MachineBasicBlock *
+X86TargetLowering::EmitLoweredCatchRet(MachineInstr *MI,
+                                       MachineBasicBlock *BB) const {
+  MachineFunction *MF = BB->getParent();
+  const Constant *PerFn = MF->getFunction()->getPersonalityFn();
+  bool IsSEH = isAsynchronousEHPersonality(classifyEHPersonality(PerFn));
+  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
+  MachineBasicBlock *TargetMBB = MI->getOperand(0).getMBB();
+  DebugLoc DL = MI->getDebugLoc();
+
+  // SEH does not outline catch bodies into funclets. Turn CATCHRETs into
+  // JMP_4s, possibly with some extra restoration code for 32-bit EH.
+  if (IsSEH) {
+    if (Subtarget->is32Bit())
+      BuildMI(*BB, MI, DL, TII.get(X86::EH_RESTORE));
+    BuildMI(*BB, MI, DL, TII.get(X86::JMP_4)).addMBB(TargetMBB);
+    MI->eraseFromParent();
+    return BB;
+  }
+
+  // Only 32-bit EH needs to worry about manually restoring stack pointers.
+  if (!Subtarget->is32Bit())
+    return BB;
+
+  // C++ EH creates a new target block to hold the restore code, and wires up
+  // the new block to the return destination with a normal JMP_4.
+  MachineBasicBlock *RestoreMBB =
+      MF->CreateMachineBasicBlock(BB->getBasicBlock());
+  MF->insert(TargetMBB->getIterator(), RestoreMBB);
+  BB->removeSuccessor(TargetMBB);
+  BB->addSuccessor(RestoreMBB);
+  RestoreMBB->addSuccessor(TargetMBB);
+  MI->getOperand(0).setMBB(RestoreMBB);
+
+  auto RestoreMBBI = RestoreMBB->begin();
+  BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::EH_RESTORE));
+  BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4)).addMBB(TargetMBB);
+  return BB;
+}
+
+MachineBasicBlock *
 X86TargetLowering::EmitLoweredTLSCall(MachineInstr *MI,
                                       MachineBasicBlock *BB) const {
   // This is pretty easy.  We're taking the value that we received from
@@ -21717,6 +21757,8 @@ X86TargetLowering::EmitInstrWithCustomIn
     return BB;
   case X86::WIN_ALLOCA:
     return EmitLoweredWinAlloca(MI, BB);
+  case X86::CATCHRET:
+    return EmitLoweredCatchRet(MI, BB);
   case X86::SEG_ALLOCA_32:
   case X86::SEG_ALLOCA_64:
     return EmitLoweredSegAlloca(MI, BB);

Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.h?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.h (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.h Thu Nov  5 19:49:05 2015
@@ -1088,6 +1088,9 @@ namespace llvm {
     MachineBasicBlock *EmitLoweredWinAlloca(MachineInstr *MI,
                                               MachineBasicBlock *BB) const;
 
+    MachineBasicBlock *EmitLoweredCatchRet(MachineInstr *MI,
+                                           MachineBasicBlock *BB) const;
+
     MachineBasicBlock *EmitLoweredSegAlloca(MachineInstr *MI,
                                             MachineBasicBlock *BB) const;
 

Modified: llvm/trunk/lib/Target/X86/X86InstrCompiler.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrCompiler.td?rev=252266&r1=252265&r2=252266&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrCompiler.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrCompiler.td Thu Nov  5 19:49:05 2015
@@ -152,13 +152,25 @@ def EH_RETURN64   : I<0xC3, RawFrm, (out
 
 }
 
-let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
-def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst, brtarget32:$from),
-                 "# CATCHRET",
-                 [(catchret bb:$dst, bb:$from)]>;
-def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
+let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
+    isCodeGenOnly = 1, isReturn = 1 in {
+  def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
+
+  // CATCHRET needs a custom inserter for SEH nonsense.
+  let usesCustomInserter = 1 in
+    def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst, brtarget32:$from),
+                     "# CATCHRET",
+                     [(catchret bb:$dst, bb:$from)]>;
 }
 
+// This instruction is responsible for re-establishing stack pointers after an
+// exception has been caught and we are rejoining normal control flow in the
+// parent function or funclet. It generally sets ESP and EBP, and optionally
+// ESI. It is only needed for 32-bit WinEH, as the runtime restores CSRs for us
+// elsewhere.
+let hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1 in
+def EH_RESTORE : I<0, Pseudo, (outs), (ins), "# EH_RESTORE", []>;
+
 let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
     usesCustomInserter = 1 in {
   def EH_SjLj_SetJmp32  : I<0, Pseudo, (outs GR32:$dst), (ins i32mem:$buf),




More information about the llvm-commits mailing list