Skip to content

Commit

Permalink
Re-apply r211399, "Generate native unwind info on Win64" with a fix t…
Browse files Browse the repository at this point in the history
…o ignore SEH pseudo ops in X86 JIT emitter.

--
This patch enables LLVM to emit Win64-native unwind info rather than
DWARF CFI.  It handles all corner cases (I hope), including stack
realignment.

Because the unwind info is not flexible enough to describe stack frames
with a gap of unknown size in the middle, such as the one caused by
stack realignment, I modified register spilling code to place all spills
into the fixed frame slots, so that they can be accessed relative to the
frame pointer.

Patch by Vadim Chugunov!

Reviewed By: rnk

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

llvm-svn: 211691
  • Loading branch information
chapuni committed Jun 25, 2014
1 parent 3cf5c9d commit 1db5995
Show file tree
Hide file tree
Showing 20 changed files with 636 additions and 207 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/MachineFrameInfo.h
Expand Up @@ -484,6 +484,9 @@ class MachineFrameInfo {
///
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool Immutable);

/// CreateFixedSpillStackObject - Create a spill slot at a fixed location
/// on the stack. Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);

/// isFixedObjectIndex - Returns true if the specified index corresponds to a
/// fixed stack object.
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCAsmInfo.h
Expand Up @@ -481,6 +481,7 @@ class MCAsmInfo {
bool isExceptionHandlingDwarf() const {
return (ExceptionsType == ExceptionHandling::DwarfCFI ||
ExceptionsType == ExceptionHandling::ARM ||
// Win64 handler data still uses DWARF LSDA encoding.
ExceptionsType == ExceptionHandling::Win64);
}
bool doesDwarfUseRelocationsAcrossSections() const {
Expand Down
13 changes: 13 additions & 0 deletions llvm/include/llvm/Target/TargetFrameLowering.h
Expand Up @@ -93,6 +93,19 @@ class TargetFrameLowering {
/// stack pointer.
virtual bool isFPCloseToIncomingSP() const { return true; }

/// assignCalleeSavedSpillSlots - Allows target to override spill slot
/// assignment logic. If implemented, assignCalleeSavedSpillSlots() should
/// assign frame slots to all CSI entries and return true. If this method
/// returns false, spill slots will be assigned using generic implementation.
/// assignCalleeSavedSpillSlots() may add, delete or rearrange elements of
/// CSI.
virtual bool
assignCalleeSavedSpillSlots(MachineFunction &MF,
const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const {
return false;
}

/// getCalleeSavedSpillSlots - This method returns a pointer to an array of
/// pairs, that contains an entry for each callee saved register that must be
/// spilled to a particular stack location if it is spilled.
Expand Down
13 changes: 3 additions & 10 deletions llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
Expand Up @@ -77,9 +77,9 @@ void Win64Exception::beginFunction(const MachineFunction *MF) {
if (!shouldEmitPersonality)
return;

MCSymbol *GCCHandlerSym =
Asm->GetExternalSymbolSymbol("_GCC_specific_handler");
Asm->OutStreamer.EmitWin64EHHandler(GCCHandlerSym, true, true);
const MCSymbol *PersHandlerSym =
TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
Asm->OutStreamer.EmitWin64EHHandler(PersHandlerSym, true, true);

Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
Asm->getFunctionNumber()));
Expand All @@ -98,15 +98,8 @@ void Win64Exception::endFunction(const MachineFunction *) {
MMI->TidyLandingPads();

if (shouldEmitPersonality) {
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
const MCSymbol *Sym =
TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);

Asm->OutStreamer.PushSection();
Asm->OutStreamer.EmitWin64EHHandlerData();
Asm->OutStreamer.EmitValue(MCSymbolRefExpr::Create(Sym, Asm->OutContext),
4);
emitExceptionTable();
Asm->OutStreamer.PopSection();
}
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/CodeGen/MachineFunction.cpp
Expand Up @@ -578,6 +578,21 @@ int MachineFrameInfo::CreateFixedObject(uint64_t Size, int64_t SPOffset,
return -++NumFixedObjects;
}

/// CreateFixedSpillStackObject - Create a spill slot at a fixed location
/// on the stack. Returns an index with a negative value.
int MachineFrameInfo::CreateFixedSpillStackObject(uint64_t Size,
int64_t SPOffset) {
unsigned StackAlign = getFrameLowering()->getStackAlignment();
unsigned Align = MinAlign(SPOffset, StackAlign);
Align = clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
!RealignOption,
Align, getFrameLowering()->getStackAlignment());
Objects.insert(Objects.begin(), StackObject(Size, Align, SPOffset,
/*Immutable*/ true,
/*isSS*/ true,
/*Alloca*/ nullptr));
return -++NumFixedObjects;
}

BitVector
MachineFrameInfo::getPristineRegs(const MachineBasicBlock *MBB) const {
Expand Down
87 changes: 46 additions & 41 deletions llvm/lib/CodeGen/PrologEpilogInserter.cpp
Expand Up @@ -268,51 +268,56 @@ void PEI::calculateCalleeSavedRegisters(MachineFunction &F) {
}
}

if (CSI.empty())
return; // Early exit if no callee saved registers are modified!

unsigned NumFixedSpillSlots;
const TargetFrameLowering::SpillSlot *FixedSpillSlots =
TFI->getCalleeSavedSpillSlots(NumFixedSpillSlots);
if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI)) {
// If target doesn't implement this, use generic code.

if (CSI.empty())
return; // Early exit if no callee saved registers are modified!

unsigned NumFixedSpillSlots;
const TargetFrameLowering::SpillSlot *FixedSpillSlots =
TFI->getCalleeSavedSpillSlots(NumFixedSpillSlots);

// Now that we know which registers need to be saved and restored, allocate
// stack slots for them.
for (std::vector<CalleeSavedInfo>::iterator I = CSI.begin(), E = CSI.end();
I != E; ++I) {
unsigned Reg = I->getReg();
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);

int FrameIdx;
if (RegInfo->hasReservedSpillSlot(F, Reg, FrameIdx)) {
I->setFrameIdx(FrameIdx);
continue;
}

// Now that we know which registers need to be saved and restored, allocate
// stack slots for them.
for (std::vector<CalleeSavedInfo>::iterator
I = CSI.begin(), E = CSI.end(); I != E; ++I) {
unsigned Reg = I->getReg();
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
// Check to see if this physreg must be spilled to a particular stack slot
// on this target.
const TargetFrameLowering::SpillSlot *FixedSlot = FixedSpillSlots;
while (FixedSlot != FixedSpillSlots + NumFixedSpillSlots &&
FixedSlot->Reg != Reg)
++FixedSlot;

if (FixedSlot == FixedSpillSlots + NumFixedSpillSlots) {
// Nope, just spill it anywhere convenient.
unsigned Align = RC->getAlignment();
unsigned StackAlign = TFI->getStackAlignment();

// We may not be able to satisfy the desired alignment specification of
// the TargetRegisterClass if the stack alignment is smaller. Use the
// min.
Align = std::min(Align, StackAlign);
FrameIdx = MFI->CreateStackObject(RC->getSize(), Align, true);
if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx;
if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx;
} else {
// Spill it to the stack where we must.
FrameIdx =
MFI->CreateFixedSpillStackObject(RC->getSize(), FixedSlot->Offset);
}

int FrameIdx;
if (RegInfo->hasReservedSpillSlot(F, Reg, FrameIdx)) {
I->setFrameIdx(FrameIdx);
continue;
}

// Check to see if this physreg must be spilled to a particular stack slot
// on this target.
const TargetFrameLowering::SpillSlot *FixedSlot = FixedSpillSlots;
while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots &&
FixedSlot->Reg != Reg)
++FixedSlot;

if (FixedSlot == FixedSpillSlots + NumFixedSpillSlots) {
// Nope, just spill it anywhere convenient.
unsigned Align = RC->getAlignment();
unsigned StackAlign = TFI->getStackAlignment();

// We may not be able to satisfy the desired alignment specification of
// the TargetRegisterClass if the stack alignment is smaller. Use the
// min.
Align = std::min(Align, StackAlign);
FrameIdx = MFI->CreateStackObject(RC->getSize(), Align, true);
if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx;
if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx;
} else {
// Spill it to the stack where we must.
FrameIdx = MFI->CreateFixedObject(RC->getSize(), FixedSlot->Offset, true);
}

I->setFrameIdx(FrameIdx);
}

MFI->setCalleeSavedInfo(CSI);
Expand Down
15 changes: 10 additions & 5 deletions llvm/lib/MC/MCObjectFileInfo.cpp
Expand Up @@ -649,11 +649,16 @@ void MCObjectFileInfo::InitCOFFMCObjectFileInfo(Triple T) {
// though it contains relocatable pointers. In PIC mode, this is probably a
// big runtime hit for C++ apps. Either the contents of the LSDA need to be
// adjusted or this should be a data section.
LSDASection =
Ctx->getCOFFSection(".gcc_except_table",
COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
COFF::IMAGE_SCN_MEM_READ,
SectionKind::getReadOnly());
assert(T.isOSWindows() && "Windows is the only supported COFF target");
if (T.getArch() == Triple::x86_64) {
// On Windows 64 with SEH, the LSDA is emitted into the .xdata section
LSDASection = 0;
} else {
LSDASection = Ctx->getCOFFSection(".gcc_except_table",
COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
COFF::IMAGE_SCN_MEM_READ,
SectionKind::getReadOnly());
}

// Debug info.
COFFDebugSymbolsSection =
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Expand Up @@ -504,6 +504,8 @@ void MCStreamer::EmitWin64EHSetFrame(unsigned Register, unsigned Offset) {
report_fatal_error("Frame register and offset already specified!");
if (Offset & 0x0F)
report_fatal_error("Misaligned frame pointer offset!");
if (Offset > 240)
report_fatal_error("Frame offset must be less than or equal to 240!");
MCSymbol *Label = getContext().CreateTempSymbol();
MCWin64EHInstruction Inst(Win64EH::UOP_SetFPReg, Label, Register, Offset);
EmitLabel(Label);
Expand Down
12 changes: 8 additions & 4 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
Expand Up @@ -143,8 +143,11 @@ getNonexecutableStackSection(MCContext &Ctx) const {
void X86MCAsmInfoMicrosoft::anchor() { }

X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
if (Triple.getArch() == Triple::x86_64)
if (Triple.getArch() == Triple::x86_64) {
PrivateGlobalPrefix = ".L";
PointerSize = 8;
ExceptionsType = ExceptionHandling::Win64;
}

AssemblerDialect = AsmWriterFlavor;

Expand All @@ -158,17 +161,18 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
void X86MCAsmInfoGNUCOFF::anchor() { }

X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
assert(Triple.isOSWindows() && "Windows is the only supported COFF target");
if (Triple.getArch() == Triple::x86_64) {
PrivateGlobalPrefix = ".L";
PointerSize = 8;
ExceptionsType = ExceptionHandling::Win64;
} else {
ExceptionsType = ExceptionHandling::DwarfCFI;
}

AssemblerDialect = AsmWriterFlavor;

TextAlignFillValue = 0x90;

// Exceptions handling
ExceptionsType = ExceptionHandling::DwarfCFI;

UseIntegratedAssembler = true;
}
10 changes: 10 additions & 0 deletions llvm/lib/Target/X86/X86CodeEmitter.cpp
Expand Up @@ -1131,6 +1131,16 @@ void Emitter<CodeEmitter>::emitInstruction(MachineInstr &MI,
case TargetOpcode::IMPLICIT_DEF:
case TargetOpcode::KILL:
break;

case X86::SEH_PushReg:
case X86::SEH_SaveReg:
case X86::SEH_SaveXMM:
case X86::SEH_StackAlloc:
case X86::SEH_SetFrame:
case X86::SEH_PushFrame:
case X86::SEH_EndPrologue:
break;

case X86::MOVPC32r: {
// This emits the "call" portion of this pseudo instruction.
MCE.emitByte(BaseOpcode);
Expand Down

0 comments on commit 1db5995

Please sign in to comment.