Skip to content

Commit

Permalink
X86: Emit an ABI compliant prologue and epilogue for Win64
Browse files Browse the repository at this point in the history
Win64 has specific contraints on what valid prologues and epilogues look
like.  This constraint is born from the flexibility and descriptiveness
of Win64's unwind opcodes.

Prologues previously emitted by LLVM could not be represented by the
unwind opcodes, preventing operations powered by stack unwinding to
successfully work.

Differential Revision: http://reviews.llvm.org/D7520

llvm-svn: 228641
  • Loading branch information
majnemer committed Feb 10, 2015
1 parent 01fc176 commit 93c22a4
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 97 deletions.
211 changes: 132 additions & 79 deletions llvm/lib/Target/X86/X86FrameLowering.cpp
Expand Up @@ -484,6 +484,35 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
}
}

static unsigned calculateSetFPREG(uint64_t SPAdjust) {
// Win64 ABI has a less restrictive limitation of 240; 128 works equally well
// and might require smaller successive adjustments.
const uint64_t Win64MaxSEHOffset = 128;
uint64_t SEHFrameOffset = std::min(SPAdjust, Win64MaxSEHOffset);
// Win64 ABI requires 16-byte alignment for the UWOP_SET_FPREG opcode.
return static_cast<unsigned>(RoundUpToAlignment(SEHFrameOffset, 16));
}

// If we're forcing a stack realignment we can't rely on just the frame
// info, we need to know the ABI stack alignment as well in case we
// have a call out. Otherwise just make sure we have some alignment - we'll
// go with the minimum SlotSize.
static uint64_t calculateMaxStackAlign(const MachineFunction &MF) {
const MachineFrameInfo *MFI = MF.getFrameInfo();
uint64_t MaxAlign = MFI->getMaxAlignment(); // Desired stack alignment.
const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
const X86RegisterInfo *RegInfo = STI.getRegisterInfo();
unsigned SlotSize = RegInfo->getSlotSize();
unsigned StackAlign = STI.getFrameLowering()->getStackAlignment();
if (ForceStackAlign) {
if (MFI->hasCalls())
MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign;
else if (MaxAlign < SlotSize)
MaxAlign = SlotSize;
}
return MaxAlign;
}

/// emitPrologue - Push callee-saved registers onto the stack, which
/// automatically adjust the stack pointer. Adjust the stack pointer to allocate
/// space for local variables. Also emit labels used by the exception handler to
Expand Down Expand Up @@ -578,7 +607,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
const TargetInstrInfo &TII = *STI.getInstrInfo();
MachineModuleInfo &MMI = MF.getMMI();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
uint64_t MaxAlign = MFI->getMaxAlignment(); // Desired stack alignment.
uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
uint64_t StackSize = MFI->getStackSize(); // Number of bytes to allocate.
bool HasFP = hasFP(MF);
bool Is64Bit = STI.is64Bit();
Expand All @@ -591,7 +620,6 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
bool NeedsDwarfCFI =
!IsWinEH && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry());
bool UseLEA = STI.useLeaForSP();
unsigned StackAlign = getStackAlignment();
unsigned SlotSize = RegInfo->getSlotSize();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
const unsigned MachineFramePtr =
Expand All @@ -602,19 +630,11 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
unsigned BasePtr = RegInfo->getBaseRegister();
DebugLoc DL;

// If we're forcing a stack realignment we can't rely on just the frame
// info, we need to know the ABI stack alignment as well in case we
// have a call out. Otherwise just make sure we have some alignment - we'll
// go with the minimum SlotSize.
if (ForceStackAlign) {
if (MFI->hasCalls())
MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign;
else if (MaxAlign < SlotSize)
MaxAlign = SlotSize;
}

// Add RETADDR move area to callee saved frame size.
int TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta();
if (TailCallReturnAddrDelta && IsWinEH)
report_fatal_error("Can't handle guaranteed tail call under win64 yet");

if (TailCallReturnAddrDelta < 0)
X86FI->setCalleeSavedFrameSize(
X86FI->getCalleeSavedFrameSize() - TailCallReturnAddrDelta);
Expand Down Expand Up @@ -689,7 +709,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
// Callee-saved registers are pushed on stack before the stack
// is realigned.
FrameSize -= X86FI->getCalleeSavedFrameSize();
NumBytes = (FrameSize + MaxAlign - 1) / MaxAlign * MaxAlign;
NumBytes = RoundUpToAlignment(FrameSize, MaxAlign);
} else {
NumBytes = FrameSize - X86FI->getCalleeSavedFrameSize();
}
Expand Down Expand Up @@ -728,11 +748,14 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
.setMIFlag(MachineInstr::FrameSetup);
}

// Update EBP with the new base value.
BuildMI(MBB, MBBI, DL,
TII.get(Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr), FramePtr)
.addReg(StackPtr)
.setMIFlag(MachineInstr::FrameSetup);
if (!IsWinEH) {
// Update EBP with the new base value.
BuildMI(MBB, MBBI, DL,
TII.get(Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr),
FramePtr)
.addReg(StackPtr)
.setMIFlag(MachineInstr::FrameSetup);
}

if (NeedsDwarfCFI) {
// Mark effective beginning of when frame pointer becomes valid.
Expand Down Expand Up @@ -781,15 +804,16 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {

// Realign stack after we pushed callee-saved registers (so that we'll be
// able to calculate their offsets from the frame pointer).
if (RegInfo->needsStackRealignment(MF)) {
// Don't do this for Win64, it needs to realign the stack after the prologue.
if (!IsWinEH && RegInfo->needsStackRealignment(MF)) {
assert(HasFP && "There should be a frame pointer if stack is realigned.");
uint64_t Val = -MaxAlign;
MachineInstr *MI =
BuildMI(MBB, MBBI, DL,
TII.get(getANDriOpcode(Uses64BitFramePtr, Val)), StackPtr)
.addReg(StackPtr)
.addImm(Val)
.setMIFlag(MachineInstr::FrameSetup);
BuildMI(MBB, MBBI, DL, TII.get(getANDriOpcode(Uses64BitFramePtr, Val)),
StackPtr)
.addReg(StackPtr)
.addImm(Val)
.setMIFlag(MachineInstr::FrameSetup);

// The EFLAGS implicit def is dead.
MI->getOperand(3).setIsDead();
Expand Down Expand Up @@ -867,50 +891,28 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
UseLEA, TII, *RegInfo);
}

if (NeedsWinEH && NumBytes)
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlloc))
.addImm(NumBytes)
.setMIFlag(MachineInstr::FrameSetup);

int SEHFrameOffset = 0;
if (NeedsWinEH) {
if (HasFP) {
// We need to set frame base offset low enough such that all saved
// register offsets would be positive relative to it, but we can't
// just use NumBytes, because .seh_setframe offset must be <=240.
// So we pretend to have only allocated enough space to spill the
// non-volatile registers.
// We don't care about the rest of stack allocation, because unwinder
// will restore SP to (BP - SEHFrameOffset)
for (const CalleeSavedInfo &Info : MFI->getCalleeSavedInfo()) {
int offset = MFI->getObjectOffset(Info.getFrameIdx());
SEHFrameOffset = std::max(SEHFrameOffset, std::abs(offset));
}
SEHFrameOffset += SEHFrameOffset % 16; // ensure alignmant

// This only needs to account for XMM spill slots, GPR slots
// are covered by the .seh_pushreg's emitted above.
unsigned Size = SEHFrameOffset - X86FI->getCalleeSavedFrameSize();
if (Size) {
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlloc))
.addImm(Size)
.setMIFlag(MachineInstr::FrameSetup);
}
if (IsWinEH && HasFP) {
SEHFrameOffset = calculateSetFPREG(NumBytes);
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), FramePtr),
StackPtr, false, SEHFrameOffset);

if (NeedsWinEH)
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
.addImm(FramePtr)
.addImm(SEHFrameOffset)
.setMIFlag(MachineInstr::FrameSetup);
} else {
// SP will be the base register for restoring XMMs
if (NumBytes) {
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlloc))
.addImm(NumBytes)
.setMIFlag(MachineInstr::FrameSetup);
}
}
}

// Skip the rest of register spilling code
while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
++MBBI;

// Emit SEH info for non-GPRs
if (NeedsWinEH) {
for (const CalleeSavedInfo &Info : MFI->getCalleeSavedInfo()) {
unsigned Reg = Info.getReg();
Expand All @@ -931,6 +933,23 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF) const {
.setMIFlag(MachineInstr::FrameSetup);
}

// Realign stack after we spilled callee-saved registers (so that we'll be
// able to calculate their offsets from the frame pointer).
// Win64 requires aligning the stack after the prologue.
if (IsWinEH && RegInfo->needsStackRealignment(MF)) {
assert(HasFP && "There should be a frame pointer if stack is realigned.");
uint64_t Val = -MaxAlign;
MachineInstr *MI =
BuildMI(MBB, MBBI, DL, TII.get(getANDriOpcode(Uses64BitFramePtr, Val)),
StackPtr)
.addReg(StackPtr)
.addImm(Val)
.setMIFlag(MachineInstr::FrameSetup);

// The EFLAGS implicit def is dead.
MI->getOperand(3).setIsDead();
}

// If we need a base pointer, set it up here. It's whatever the value
// of the stack pointer is at this point. Any variable size objects
// will be allocated after this, so we can still use the base pointer
Expand Down Expand Up @@ -986,7 +1005,6 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
const bool Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64();
const bool Is64BitILP32 = STI.isTarget64BitILP32();
bool UseLEA = STI.useLeaForSP();
unsigned StackAlign = getStackAlignment();
unsigned SlotSize = RegInfo->getSlotSize();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
unsigned MachineFramePtr =
Expand Down Expand Up @@ -1017,21 +1035,10 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,

// Get the number of bytes to allocate from the FrameInfo.
uint64_t StackSize = MFI->getStackSize();
uint64_t MaxAlign = MFI->getMaxAlignment();
uint64_t MaxAlign = calculateMaxStackAlign(MF);
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
uint64_t NumBytes = 0;

// If we're forcing a stack realignment we can't rely on just the frame
// info, we need to know the ABI stack alignment as well in case we
// have a call out. Otherwise just make sure we have some alignment - we'll
// go with the minimum.
if (ForceStackAlign) {
if (MFI->hasCalls())
MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign;
else
MaxAlign = MaxAlign ? MaxAlign : 4;
}

if (hasFP(MF)) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
Expand All @@ -1050,6 +1057,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
} else {
NumBytes = StackSize - CSSize;
}
uint64_t SEHStackAllocAmt = NumBytes;

// Skip the callee-saved pop instructions.
while (MBBI != MBB.begin()) {
Expand Down Expand Up @@ -1077,7 +1085,12 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
if (RegInfo->needsStackRealignment(MF) || MFI->hasVarSizedObjects()) {
if (RegInfo->needsStackRealignment(MF))
MBBI = FirstCSPop;
if (CSSize != 0) {
if (IsWinEH) {
unsigned SEHFrameOffset = calculateSetFPREG(SEHStackAllocAmt);
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), StackPtr),
FramePtr, false, SEHStackAllocAmt - SEHFrameOffset);
--MBBI;
} else if (CSSize != 0) {
unsigned Opc = getLEArOpcode(Uses64BitFramePtr);
addRegOffset(BuildMI(MBB, MBBI, DL, TII.get(Opc), StackPtr),
FramePtr, false, -CSSize);
Expand Down Expand Up @@ -1195,36 +1208,76 @@ int X86FrameLowering::getFrameIndexOffset(const MachineFunction &MF,
const X86RegisterInfo *RegInfo =
MF.getSubtarget<X86Subtarget>().getRegisterInfo();
const MachineFrameInfo *MFI = MF.getFrameInfo();
// Offset will hold the offset from the stack pointer at function entry to the
// object.
// We need to factor in additional offsets applied during the prologue to the
// frame, base, and stack pointer depending on which is used.
int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea();
const X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
uint64_t StackSize = MFI->getStackSize();
unsigned SlotSize = RegInfo->getSlotSize();
bool HasFP = hasFP(MF);
bool IsWinEH = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
int64_t FPDelta = 0;

if (IsWinEH) {
uint64_t NumBytes = 0;
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
// If required, include space for extra hidden slot for stashing base pointer.
if (X86FI->getRestoreBasePointer())
FrameSize += SlotSize;
uint64_t SEHStackAllocAmt = StackSize;
if (RegInfo->needsStackRealignment(MF)) {
// Callee-saved registers are pushed on stack before the stack
// is realigned.
FrameSize -= CSSize;

uint64_t MaxAlign =
calculateMaxStackAlign(MF); // Desired stack alignment.
NumBytes = RoundUpToAlignment(FrameSize, MaxAlign);
SEHStackAllocAmt = RoundUpToAlignment(SEHStackAllocAmt, 16);
} else {
NumBytes = FrameSize - CSSize;
}
uint64_t SEHFrameOffset = calculateSetFPREG(NumBytes);
// FPDelta is the offset from the "traditional" FP location of the old base
// pointer followed by return address and the location required by the
// restricted Win64 prologue.
// Add FPDelta to all offsets below that go through the frame pointer.
FPDelta = SEHStackAllocAmt - SEHFrameOffset;
}


if (RegInfo->hasBasePointer(MF)) {
assert (hasFP(MF) && "VLAs and dynamic stack realign, but no FP?!");
assert(HasFP && "VLAs and dynamic stack realign, but no FP?!");
if (FI < 0) {
// Skip the saved EBP.
return Offset + RegInfo->getSlotSize();
return Offset + SlotSize + FPDelta;
} else {
assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0);
return Offset + StackSize;
}
} else if (RegInfo->needsStackRealignment(MF)) {
if (FI < 0) {
// Skip the saved EBP.
return Offset + RegInfo->getSlotSize();
return Offset + SlotSize + FPDelta;
} else {
assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0);
return Offset + StackSize;
}
// FIXME: Support tail calls
} else {
if (!hasFP(MF))
if (!HasFP)
return Offset + StackSize;
if (IsWinEH)
return Offset + FPDelta;

// Skip the saved EBP.
Offset += RegInfo->getSlotSize();
Offset += SlotSize;

// Skip the RETADDR move area
const X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
int TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta();
if (TailCallReturnAddrDelta < 0)
Offset -= TailCallReturnAddrDelta;
Expand Down Expand Up @@ -1959,8 +2012,8 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
// We need to keep the stack aligned properly. To do this, we round the
// amount of space needed for the outgoing arguments up to the next
// alignment boundary.
unsigned StackAlign = STI.getFrameLowering()->getStackAlignment();
Amount = (Amount + StackAlign - 1) / StackAlign * StackAlign;
unsigned StackAlign = getStackAlignment();
Amount = RoundUpToAlignment(Amount, StackAlign);

MachineInstr *New = nullptr;

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/X86/frameaddr.ll
@@ -1,7 +1,7 @@
; RUN: llc < %s -march=x86 | FileCheck %s --check-prefix=CHECK-32
; RUN: llc < %s -march=x86 -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-32
; RUN: llc < %s -march=x86-64 | FileCheck %s --check-prefix=CHECK-64
; RUN: llc < %s -march=x86-64 -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-64
; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s --check-prefix=CHECK-64
; RUN: llc < %s -mtriple=x86_64-unknown -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-64
; RUN: llc < %s -mtriple=x86_64-gnux32 | FileCheck %s --check-prefix=CHECK-X32ABI
; RUN: llc < %s -mtriple=x86_64-gnux32 -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-X32ABI
; RUN: llc < %s -mtriple=x86_64-nacl | FileCheck %s --check-prefix=CHECK-NACL64
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/X86/gcc_except_table.ll
Expand Up @@ -15,7 +15,7 @@ define i32 @main() uwtable optsize ssp {

; MINGW64: .seh_proc
; MINGW64: .seh_handler __gxx_personality_v0
; MINGW64: .seh_setframe 5, 0
; MINGW64: .seh_setframe 5, 32
; MINGW64: callq _Unwind_Resume
; MINGW64: .seh_handlerdata
; MINGW64: GCC_except_table0:
Expand Down

0 comments on commit 93c22a4

Please sign in to comment.