summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/X86/X86ExpandPseudo.cpp7
-rw-r--r--llvm/lib/Target/X86/X86FrameLowering.cpp54
-rw-r--r--llvm/lib/Target/X86/X86FrameLowering.h14
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp42
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.h3
-rw-r--r--llvm/lib/Target/X86/X86InstrCompiler.td22
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),
OpenPOWER on IntegriCloud