diff options
-rw-r--r-- | llvm/lib/Target/X86/X86ExpandPseudo.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 54 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.h | 14 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 42 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.h | 3 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86InstrCompiler.td | 22 |
6 files changed, 90 insertions, 52 deletions
diff --git a/llvm/lib/Target/X86/X86ExpandPseudo.cpp b/llvm/lib/Target/X86/X86ExpandPseudo.cpp index 6a5a28e546f..9e5a51c4da1 100644 --- a/llvm/lib/Target/X86/X86ExpandPseudo.cpp +++ b/llvm/lib/Target/X86/X86ExpandPseudo.cpp @@ -141,6 +141,13 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB, // 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?"); } diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index ad83344b327..b69a001a0b5 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1091,7 +1091,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, 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(MachineFunction &MF, 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(MachineFunction &MF, } 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()) diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h index 35bafb532b4..6975d250296 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.h +++ b/llvm/lib/Target/X86/X86FrameLowering.h @@ -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; }; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index d13d0510a0c..c9218a17a0b 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -21338,6 +21338,46 @@ X86TargetLowering::EmitLoweredWinAlloca(MachineInstr *MI, } 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::EmitInstrWithCustomInserter(MachineInstr *MI, 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); diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h index 714e6b1bd34..6bd7ef9a3b5 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -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; diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td index 3e16eedfe70..f35fd5c1388 100644 --- a/llvm/lib/Target/X86/X86InstrCompiler.td +++ b/llvm/lib/Target/X86/X86InstrCompiler.td @@ -152,13 +152,25 @@ def EH_RETURN64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr), } -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), |