summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/X86/X86FrameLowering.cpp144
-rw-r--r--llvm/lib/Target/X86/X86FrameLowering.h7
-rw-r--r--llvm/lib/Target/X86/X86InstrCompiler.td2
-rw-r--r--llvm/lib/Target/X86/X86MCInstLower.cpp3
-rw-r--r--llvm/lib/Target/X86/X86WinEHState.cpp11
5 files changed, 154 insertions, 13 deletions
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index 3b544d561a5..a2f9efb5aa0 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -23,6 +23,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -88,7 +89,7 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF) const {
MFI->hasVarSizedObjects() ||
MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() ||
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
- MMI.callsUnwindInit() || MMI.callsEHReturn() ||
+ MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() ||
MFI->hasStackMap() || MFI->hasPatchPoint());
}
@@ -695,7 +696,40 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
uint64_t NumBytes = 0;
int stackGrowth = -SlotSize;
- if (HasFP) {
+ if (MBB.isEHFuncletEntry()) {
+ assert(STI.isOSWindows() && "funclets only supported on Windows");
+
+ // Set up the FramePtr and BasePtr physical registers using the address
+ // passed as EBP or RDX by the MSVC EH runtime.
+ if (STI.is32Bit()) {
+ MBBI = restoreWin32EHFrameAndBasePtr(MBB, MBBI, DL);
+ } else {
+ // FIXME: Add SEH directives.
+ NeedsWinCFI = false;
+ // Immediately spill RDX into the home slot. The runtime cares about this.
+ unsigned RDX = Uses64BitFramePtr ? X86::RDX : X86::EDX;
+ // MOV64mr %rdx, 16(%rsp)
+ unsigned MOVmr = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr;
+ addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(MOVmr)),
+ StackPtr, true, 16)
+ .addReg(RDX)
+ .setMIFlag(MachineInstr::FrameSetup);
+ // PUSH64r %rbp
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))
+ .addReg(MachineFramePtr, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ // MOV64rr %rdx, %rbp
+ unsigned MOVrr = Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr;
+ BuildMI(MBB, MBBI, DL, TII.get(MOVrr), FramePtr)
+ .addReg(RDX)
+ .setMIFlag(MachineInstr::FrameSetup);
+ assert(!TRI->hasBasePointer(MF) &&
+ "x64 funclets with base ptrs not yet implemented");
+ }
+
+ // For EH funclets, only allocate enough space for outgoing calls.
+ NumBytes = MFI->getMaxCallFrameSize();
+ } else if (HasFP) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
// If required, include space for extra hidden slot for stashing base pointer.
@@ -956,10 +990,11 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
// it recovers the frame pointer from the base pointer rather than the
// other way around.
unsigned Opm = Uses64BitFramePtr ? X86::MOV64mr : X86::MOV32mr;
- unsigned IgnoredFrameReg;
- addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), BasePtr, true,
- getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(),
- IgnoredFrameReg))
+ unsigned UsedReg;
+ int Offset =
+ getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
+ assert(UsedReg == BasePtr);
+ addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opm)), UsedReg, true, Offset)
.addReg(FramePtr)
.setMIFlag(MachineInstr::FrameSetup);
}
@@ -991,6 +1026,17 @@ bool X86FrameLowering::canUseLEAForSPInEpilogue(
return !MF.getTarget().getMCAsmInfo()->usesWindowsCFI() || hasFP(MF);
}
+static bool isFuncletReturnInstr(MachineInstr *MI) {
+ switch (MI->getOpcode()) {
+ case X86::CATCHRET:
+ case X86::CATCHRET64:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("impossible");
+}
+
void X86FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
@@ -1016,7 +1062,16 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
uint64_t NumBytes = 0;
- if (hasFP(MF)) {
+ if (isFuncletReturnInstr(MBBI)) {
+ NumBytes = MFI->getMaxCallFrameSize();
+
+ if (Is64Bit) {
+ assert(hasFP(MF) && "win64 EH funclets without FP not yet implemented");
+ // POP64r %rbp
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
+ MachineFramePtr);
+ }
+ } else if (hasFP(MF)) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
NumBytes = FrameSize - CSSize;
@@ -1331,6 +1386,11 @@ bool X86FrameLowering::spillCalleeSavedRegisters(
const TargetRegisterInfo *TRI) const {
DebugLoc DL = MBB.findDebugLoc(MI);
+ // Don't save CSRs in 32-bit EH funclets. The caller saves EBX, EBP, ESI, EDI
+ // for us, and there are no XMM CSRs on Win32.
+ if (MBB.isEHFuncletEntry() && STI.is32Bit() && STI.isOSWindows())
+ return true;
+
// Push GPRs. It increases frame size.
unsigned Opc = STI.is64Bit() ? X86::PUSH64r : X86::PUSH32r;
for (unsigned i = CSI.size(); i != 0; --i) {
@@ -1372,6 +1432,11 @@ bool X86FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
if (CSI.empty())
return false;
+ // Don't restore CSRs in 32-bit EH funclets. Matches
+ // spillCalleeSavedRegisters.
+ if (isFuncletReturnInstr(MI) && STI.is32Bit() && STI.isOSWindows())
+ return true;
+
DebugLoc DL = MBB.findDebugLoc(MI);
// Reload XMMs from stack frame.
@@ -1423,8 +1488,16 @@ void X86FrameLowering::determineCalleeSaves(MachineFunction &MF,
}
// Spill the BasePtr if it's used.
- if (TRI->hasBasePointer(MF))
+ if (TRI->hasBasePointer(MF)) {
SavedRegs.set(TRI->getBaseRegister());
+
+ // Allocate a spill slot for EBP if we have a base pointer and EH funclets.
+ if (MF.getMMI().hasEHFunclets()) {
+ int FI = MFI->CreateSpillStackObject(SlotSize, SlotSize);
+ X86FI->setHasSEHFramePtrSave(true);
+ X86FI->setSEHFramePtrSaveIndex(FI);
+ }
+ }
}
static bool
@@ -1976,3 +2049,58 @@ bool X86FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
// safe to insert the epilogue here.
return !terminatorsNeedFlagsAsInput(MBB);
}
+
+MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHFrameAndBasePtr(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ DebugLoc DL) const {
+ assert(STI.isTargetWindowsMSVC() && "funclets only supported in MSVC env");
+ assert(STI.isTargetWin32() && "EBP/ESI restoration only required on win32");
+ assert(STI.is32Bit() && !Uses64BitFramePtr &&
+ "restoring EBP/ESI on non-32-bit target");
+
+ MachineFunction &MF = *MBB.getParent();
+ unsigned FramePtr = TRI->getFrameRegister(MF);
+ unsigned BasePtr = TRI->getBaseRegister();
+ MachineModuleInfo &MMI = MF.getMMI();
+ const Function *Fn = MF.getFunction();
+ WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn);
+ X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ // FIXME: Don't set FrameSetup flag in catchret case.
+
+ int FI = FuncInfo.EHRegNodeFrameIndex;
+ unsigned UsedReg;
+ int EHRegOffset = getFrameIndexReference(MF, FI, UsedReg);
+ int EHRegSize = MFI->getObjectSize(FI);
+ int EndOffset = -EHRegOffset - EHRegSize;
+ assert(EndOffset >= 0 &&
+ "end of registration object above normal EBP position!");
+ if (UsedReg == FramePtr) {
+ // ADD $offset, %ebp
+ assert(UsedReg == FramePtr);
+ unsigned ADDri = getADDriOpcode(false, EndOffset);
+ BuildMI(MBB, MBBI, DL, TII.get(ADDri), FramePtr)
+ .addReg(FramePtr)
+ .addImm(EndOffset)
+ .setMIFlag(MachineInstr::FrameSetup)
+ ->getOperand(3)
+ .setIsDead();
+ } else {
+ assert(UsedReg == BasePtr);
+ // LEA offset(%ebp), %esi
+ addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA32r), BasePtr),
+ FramePtr, false, EndOffset)
+ .setMIFlag(MachineInstr::FrameSetup);
+ // MOV32mr SavedEBPOffset(%esi), %ebp
+ assert(X86FI->getHasSEHFramePtrSave());
+ int Offset =
+ getFrameIndexReference(MF, X86FI->getSEHFramePtrSaveIndex(), UsedReg);
+ assert(UsedReg == BasePtr);
+ addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32mr)), UsedReg, true,
+ Offset)
+ .addReg(FramePtr)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+ return MBBI;
+}
diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h
index dd83928b46c..7cbd18bd4d0 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.h
+++ b/llvm/lib/Target/X86/X86FrameLowering.h
@@ -154,6 +154,13 @@ private:
MachineBasicBlock::iterator MBBI,
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
+ restoreWin32EHFrameAndBasePtr(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ DebugLoc DL) const;
};
} // End llvm namespace
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 18c8d7d61f3..4798474cecb 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -152,7 +152,7 @@ def EH_RETURN64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
}
-let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1 in {
+let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
"ret{l}\t# CATCHRET",
[(X86catchret GR32:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index b0010308f05..88a6d00f4cc 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -531,7 +531,8 @@ ReSimplify:
break;
}
- case X86::CATCHRET: {
+ case X86::CATCHRET:
+ case X86::CATCHRET64: {
OutMI = MCInst();
OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
break;
diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp
index 19f574ad746..ccec7743b3b 100644
--- a/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -179,6 +179,8 @@ bool WinEHStatePass::runOnFunction(Function &F) {
WinEHFuncInfo &FuncInfo =
*(MMI ? &MMI->getWinEHFuncInfo(&F) : FuncInfoPtr.get());
+ FuncInfo.EHRegNode = RegNode;
+
switch (Personality) {
default: llvm_unreachable("unexpected personality function");
case EHPersonality::MSVC_CXX:
@@ -494,9 +496,12 @@ void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode,
// Insert calls to llvm.x86.seh.restoreframe at catchret destinations.
if (auto *CR = dyn_cast<CatchReturnInst>(BB.getTerminator())) {
- //llvm::errs() << "BB: " << BB << '\n';
- //llvm::errs() << "CR->getSuccessor(): " << *CR->getSuccessor() << '\n';
- IRBuilder<> Builder(CR->getSuccessor()->begin());
+ Instruction *Start = CR->getSuccessor()->begin();
+ assert(!isa<PHINode>(Start) &&
+ "winehprepare failed to demote phi after catchret");
+ if (match(Start, m_Intrinsic<Intrinsic::x86_seh_restoreframe>()))
+ continue;
+ IRBuilder<> Builder(Start);
Builder.CreateCall(RestoreFrame, {});
}
}
OpenPOWER on IntegriCloud