Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -741,6 +741,10 @@ bool isCFIInstruction() const { return getOpcode() == TargetOpcode::CFI_INSTRUCTION; } + bool isFPOInstruction() const { + return getOpcode() == TargetOpcode::FPO_INSTRUCTION; + } + // True if the instruction represents a position in the function. bool isPosition() const { return isLabel() || isCFIInstruction(); } Index: include/llvm/CodeGen/MachineModuleInfo.h =================================================================== --- include/llvm/CodeGen/MachineModuleInfo.h +++ include/llvm/CodeGen/MachineModuleInfo.h @@ -47,6 +47,16 @@ namespace llvm { +struct MCWinFPOEntry { + MCWinFPOEntry(SmallString<64> str) : str(str) { + } + SmallString<64> str; + // XXX: If we move this out of here into the main function + // we can make this const and save space + MCSymbol *Label; +}; + + //===----------------------------------------------------------------------===// // Forward declarations. class Constant; @@ -127,6 +137,8 @@ /// by debug and exception handling consumers. std::vector FrameInstructions; + std::vector FPOEntries; + /// LandingPads - List of LandingPadInfo describing the landing pad /// information in the current function. std::vector LandingPads; @@ -281,6 +293,18 @@ return FrameInstructions.size() - 1; } + /// \brief Returns a reference to a list of fpo entries in the current + /// function. + std::vector &getFPOEntries() { + return FPOEntries; + } + + unsigned LLVM_ATTRIBUTE_UNUSED_RESULT + addFPOEntry(const MCWinFPOEntry &FPOEntry) { + FPOEntries.push_back(FPOEntry); + return FPOEntries.size() - 1; + } + /// getAddrLabelSymbol - Return the symbol to be used for the specified basic /// block when its address is taken. This cannot be its normal LBB label /// because the block may be accessed outside its containing function. Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -20,6 +20,7 @@ #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCWinEH.h" +#include "llvm/MC/MCWinFPO.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" #include @@ -165,6 +166,7 @@ MCSymbol *EmitCFICommon(); std::vector WinFrameInfos; + std::vector WinFPOs; WinEH::FrameInfo *CurrentWinFrameInfo; void EnsureValidWinFrameInfo(); @@ -219,7 +221,6 @@ ArrayRef getWinFrameInfos() const { return WinFrameInfos; } - void generateCompactUnwindEncodings(MCAsmBackend *MAB); /// \name Assembly File Formatting. @@ -679,9 +680,12 @@ virtual void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except); virtual void EmitWinEHHandlerData(); - /// \brief Emit the given \p Instruction into the current section. + /// EmitInstruction - Emit the given @p Instruction into the current + /// section. virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); + //virtual void EmitWinFPOInfo(int64_t FPOEntry); + /// \brief Set the bundle alignment mode from now on in the section. /// The argument is the power of 2 to which the alignment is set. The /// value 0 means turn the bundle alignment off. Index: include/llvm/Support/COFF.h =================================================================== --- include/llvm/Support/COFF.h +++ include/llvm/Support/COFF.h @@ -660,6 +660,7 @@ DEBUG_LINE_TABLE_SUBSECTION = 0xF2, DEBUG_STRING_TABLE_SUBSECTION = 0xF3, DEBUG_INDEX_SUBSECTION = 0xF4, + DEBUG_FPO_SUBSECTION = 0xF5, // Symbol subsections are split into records of different types. DEBUG_SYMBOL_TYPE_PROC_START = 0x1147, Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -881,6 +881,14 @@ let hasSideEffects = 0; let hasCtrlDep = 1; } + +def FPO_INSTRUCTION : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins i64imm:$id); + let AsmString = ""; + let hasCtrlDep = 1; + let isNotDuplicable = 1; +} } //===----------------------------------------------------------------------===// Index: include/llvm/Target/TargetOpcodes.h =================================================================== --- include/llvm/Target/TargetOpcodes.h +++ include/llvm/Target/TargetOpcodes.h @@ -122,6 +122,7 @@ /// label. Created by the llvm.frameallocate intrinsic. It has two arguments: /// the symbol for the label and the frame index of the stack allocation. FRAME_ALLOC = 21, + FPO_INSTRUCTION = 20, }; } // end namespace TargetOpcode } // end namespace llvm Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h =================================================================== --- lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h +++ lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h @@ -38,6 +38,7 @@ struct FunctionInfo { SmallVector Instrs; MCSymbol *End; + SmallVector FPOEntries; FunctionInfo() : End(nullptr) {} } *CurFn; @@ -111,6 +112,10 @@ void emitDebugInfoForFunction(const Function *GV); + void emitFPOSegment(const MCWinFPOEntry *entry, bool entrypoint, const MCSymbol *Fn, const MCSymbol *From, const MCSymbol *To); + void emitFrameInfo(const MCSymbol *Fn, const FunctionInfo &FI); + + void recordFPOEntry(MCWinFPOEntry *Entry); public: WinCodeViewLineTables(AsmPrinter *Asm); Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp +++ lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp @@ -78,6 +78,17 @@ return StringRef(Result); } +void WinCodeViewLineTables::recordFPOEntry(MCWinFPOEntry *Entry) +{ + assert(CurFn); + MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol(); + Asm->OutStreamer->EmitLabel(MCL); + Entry->Label = MCL; + CurFn->FPOEntries.push_back(Entry); + auto back = CurFn->FPOEntries.back(); + FileNameRegistry.add(back->str); +} + void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL, const MachineFunction *MF) { const MDNode *Scope = DL.getScope(); @@ -178,6 +189,78 @@ Streamer.EmitValue(AddrDelta, Size); } + +void WinCodeViewLineTables::emitFPOSegment(const MCWinFPOEntry *entry, bool entrypoint, const MCSymbol *Fn, const MCSymbol *From, const MCSymbol *To) +{ +/* We should be able to set LocalsSize, ParamSize, MaxStackSize, SavedRegSize and PrologSize + all to 0 without any real problems. */ + //FPOSegment [ + //Start: 0x0 + EmitLabelDiff(*Asm->OutStreamer, Fn, From); + //CodeSize: 0x14 + EmitLabelDiff(*Asm->OutStreamer, From, To); + //LocalsSize: 0x0 // often 0 but not always + Asm->EmitInt32(0); + //ParamsSize: 0x0 // ParamsSize stays the same for nested blocks + Asm->EmitInt32(0); + //MaxStackSize: 0x0 // always seems to be 0 + Asm->EmitInt32(0); + //ProgramStr: $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $ + //Asm->EmitInt32(0); + Asm->EmitInt32(FileNameRegistry.Infos[entry->str].StartOffset); +// PrologSize is how much of the prolog is in the current block +// i.e. if the PrologSize is 9 bytes and the second block begins at byte 5 it will have +// a prolog size of 4 bytes + //PrologSize: 0x3 + Asm->EmitInt16(0); + //SavedRegSize: 0x0 // This goes up predictably + Asm->EmitInt16(0); + /*Flags [ (0x4) + FPO_FUNCTION_ENTRY (0x4) + ]*/ + Asm->EmitInt32(entrypoint ? 0x4 : 0); + //] +} + + +void WinCodeViewLineTables::emitFrameInfo(const MCSymbol *Fn, const FunctionInfo &FI) +{ + Asm->OutStreamer->AddComment("FPO subsection"); + Asm->EmitInt32(COFF::DEBUG_FPO_SUBSECTION); + MCSymbol *FPOBegin = Asm->MMI->getContext().createTempSymbol(), + *FPOEnd = Asm->MMI->getContext().createTempSymbol(); + EmitLabelDiff(*Asm->OutStreamer, FPOBegin, FPOEnd); + Asm->OutStreamer->EmitLabel(FPOBegin); + + // Identify the function this subsection is for. +/* + for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I) + emitDebugInfoForFunction(VisitedFunctions[I]); +*/ + + bool start = true; + // Frame.begin is no good. We need the actual function + // Frame.begin just points to some random label + Asm->OutStreamer->EmitCOFFSecRel32(Fn); + for (auto entry = FI.FPOEntries.begin(); entry != FI.FPOEntries.end(); ) { + auto next = entry+1; + MCSymbol *end; + if (next == FI.FPOEntries.end()) { + end = FI.End; + } else { + end = (*next)->Label; + } + emitFPOSegment(*entry, start, Fn, (*entry)->Label, end); + start = false; + entry = next; + } + + Asm->OutStreamer->EmitLabel(FPOEnd); + Asm->OutStreamer->AddComment("FPO end subsection"); + +} + + void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) { // For each function there is a separate subsection // which holds the PC to file:line table. @@ -189,6 +272,8 @@ return; assert(FI.End && "Don't know where the function ends?"); + emitFrameInfo(Fn, FI); + StringRef GVName = GV->getName(); StringRef FuncName; if (auto *SP = getDISubprogram(GV)) @@ -200,6 +285,7 @@ // the symbols subsection until Clang gives us what we need. if (GVName.startswith("\01?")) FuncName = GVName.substr(1); + // Emit a symbol subsection, required by VS2012+ to find function boundaries. MCSymbol *SymbolsBegin = Asm->MMI->getContext().createTempSymbol(), *SymbolsEnd = Asm->MMI->getContext().createTempSymbol(); @@ -370,6 +456,12 @@ } void WinCodeViewLineTables::beginInstruction(const MachineInstr *MI) { + if (MI->isFPOInstruction()) { + auto &Entries = Asm->MMI->getFPOEntries(); + int64_t FPOIndex = MI->getOperand(0).getImm(); + recordFPOEntry(&Entries[FPOIndex]); + return; + } // Ignore DBG_VALUE locations and function prologue. if (!Asm || MI->isDebugValue() || MI->getFlag(MachineInstr::FrameSetup)) return; Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCWin64EH.h" +#include "llvm/MC/MCWinFPO.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -583,6 +583,7 @@ // Not necessarily synonymous with IsWin64. bool IsWinEH = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool NeedsWinEH = IsWinEH && Fn->needsUnwindTableEntry(); + bool NeedsWinFPO = true; bool NeedsDwarfCFI = !IsWinEH && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry()); bool UseLEA = STI.useLeaForSP(); @@ -682,11 +683,31 @@ // Update the frame offset adjustment. MFI->setOffsetAdjustment(-NumBytes); + if (NeedsWinFPO) { + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(SmallString<64>("$eip $esp ^ ="))); + + // XXX: we could use FPO_Push and FPO_Pop to get the stack like semantics + // that FPO instructions support + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + + // Save EBP/RBP into the appropriate stack slot. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64r : X86::PUSH32r)) .addReg(MachineFramePtr, RegState::Kill) .setMIFlag(MachineInstr::FrameSetup); + if (NeedsWinFPO) { + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(SmallString<64>("$eip $esp 4 - ^ ="))); + + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + + if (NeedsDwarfCFI) { // Mark the place where EBP/RBP was saved. // Define the current CFA rule to use the provided offset. @@ -720,6 +741,16 @@ .setMIFlag(MachineInstr::FrameSetup); } + if (NeedsWinFPO) { + + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(SmallString<64>("$eip $ebp 4 - ^ ="))); + + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + + if (NeedsDwarfCFI) { // Mark effective beginning of when frame pointer becomes valid. // Define the current CFA to use the EBP/RBP register. @@ -759,6 +790,29 @@ StackOffset += stackGrowth; } + if (!HasFP && NeedsDwarfCFI) { + // Mark callee-saved push instruction. + // Define the current CFA rule to use the provided offset. + assert(StackSize); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, StackOffset)); + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + StackOffset += stackGrowth; + } + + if (NeedsWinFPO) { + SmallString<64> Buffer; + llvm::raw_svector_ostream Stream(Buffer); + Stream << "$eip $ebp " << StackOffset << " - ^ ="; + + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(Buffer)); + + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + if (NeedsWinEH) { BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)).addImm(Reg).setMIFlag( MachineInstr::FrameSetup); @@ -962,6 +1016,22 @@ if (PushedRegs) emitCalleeSavedFrameMoves(MBB, MBBI, DL); } + if (((!HasFP && NumBytes) || PushedRegs) && NeedsWinFPO) { + // Mark end of stack pointer adjustment. + if (!HasFP && NumBytes) { + // Define the current CFA rule to use the provided offset. + SmallString<64> Buffer; + llvm::raw_svector_ostream Stream(Buffer); + Stream << "$eip $ebp " << (-StackSize + stackGrowth) << " - ^ ="; + + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(Buffer)); + + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + } + } bool X86FrameLowering::canUseLEAForSPInEpilogue( @@ -1001,6 +1071,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineModuleInfo &MMI = MF.getMMI(); X86MachineFunctionInfo *X86FI = MF.getInfo(); const X86Subtarget &STI = MF.getSubtarget(); const X86RegisterInfo *RegInfo = STI.getRegisterInfo(); @@ -1034,6 +1105,7 @@ // in canUseAsEpilogue. assert((UseLEAForSP || !terminatorsNeedFlagsAsInput(MBB)) && "We shouldn't have allowed this insertion point"); + bool NeedsWinFPO = true; // Get the number of bytes to allocate from the FrameInfo. uint64_t StackSize = MFI->getStackSize(); @@ -1054,6 +1126,22 @@ // Pop EBP. BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), MachineFramePtr); + unsigned DwarfStackPtr = RegInfo->getDwarfRegNum(StackPtr, true); + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfa(nullptr, DwarfStackPtr, NumBytes - (Is64Bit ? 8 : 4))); + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + if (NeedsWinFPO) { + int StringIndex = MMI.addFPOEntry(MCWinFPOEntry(SmallString<64>("$eip $esp ^ ="))); + + // XXX: we could use FPO_Push and FPO_Pop to get the stack like semantics + // that FPO instructions support + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::FPO_INSTRUCTION)) + .addImm(StringIndex) + .setMIFlag(MachineInstr::FrameSetup); + } + } else { NumBytes = StackSize - CSSize; } Index: utils/TableGen/CodeGenTarget.cpp =================================================================== --- utils/TableGen/CodeGenTarget.cpp +++ utils/TableGen/CodeGenTarget.cpp @@ -297,7 +297,7 @@ "IMPLICIT_DEF", "SUBREG_TO_REG", "COPY_TO_REGCLASS", "DBG_VALUE", "REG_SEQUENCE", "COPY", "BUNDLE", "LIFETIME_START", "LIFETIME_END", "STACKMAP", "PATCHPOINT", "LOAD_STACK_GUARD", - "STATEPOINT", "FRAME_ALLOC", + "STATEPOINT", "FRAME_ALLOC", "FPO_INSTRUCTION", nullptr}; const auto &Insts = getInstructions(); for (const char *const *p = FixedInstrs; *p; ++p) {