diff options
Diffstat (limited to 'lib/Target/X86/MCTargetDesc')
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp | 26 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86BaseInfo.h | 22 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp | 12 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp | 13 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp | 11 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp | 180 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h | 36 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp | 13 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86TargetStreamer.h | 34 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp | 9 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp | 31 | ||||
| -rw-r--r-- | lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp | 415 |
13 files changed, 686 insertions, 119 deletions
diff --git a/lib/Target/X86/MCTargetDesc/CMakeLists.txt b/lib/Target/X86/MCTargetDesc/CMakeLists.txt index 33df9ec7dcde..8d0d9fa1215c 100644 --- a/lib/Target/X86/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/X86/MCTargetDesc/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_library(LLVMX86Desc X86MCCodeEmitter.cpp X86MachObjectWriter.cpp X86ELFObjectWriter.cpp - X86WinCOFFStreamer.cpp X86WinCOFFObjectWriter.cpp + X86WinCOFFStreamer.cpp + X86WinCOFFTargetStreamer.cpp ) diff --git a/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp index 733eac7c0321..78385ae1877b 100644 --- a/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ b/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -20,12 +20,9 @@ #include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSectionCOFF.h" -#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -76,7 +73,7 @@ class X86AsmBackend : public MCAsmBackend { public: X86AsmBackend(const Target &T, StringRef CPU) : MCAsmBackend(), CPU(CPU), - MaxNopLength((CPU == "slm") ? 7 : 15) { + MaxNopLength((CPU == "slm" || CPU == "silvermont") ? 7 : 15) { HasNopl = CPU != "generic" && CPU != "i386" && CPU != "i486" && CPU != "i586" && CPU != "pentium" && CPU != "pentium-mmx" && CPU != "i686" && CPU != "k6" && CPU != "k6-2" && CPU != "k6-3" && @@ -389,7 +386,8 @@ public: ELFX86_32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_386); } }; @@ -399,7 +397,8 @@ public: ELFX86_X32AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_X86_64); } @@ -410,7 +409,8 @@ public: ELFX86_IAMCUAsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ false, OSABI, ELF::EM_IAMCU); } @@ -421,7 +421,8 @@ public: ELFX86_64AsmBackend(const Target &T, uint8_t OSABI, StringRef CPU) : ELFX86AsmBackend(T, OSABI, CPU) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86ELFObjectWriter(OS, /*IsELF64*/ true, OSABI, ELF::EM_X86_64); } }; @@ -443,7 +444,8 @@ public: .Default(MCAsmBackend::getFixupKind(Name)); } - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86WinCOFFObjectWriter(OS, Is64Bit); } }; @@ -804,7 +806,8 @@ public: StringRef CPU) : DarwinX86AsmBackend(T, MRI, CPU, false) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86MachObjectWriter(OS, /*Is64Bit=*/false, MachO::CPU_TYPE_I386, MachO::CPU_SUBTYPE_I386_ALL); @@ -824,7 +827,8 @@ public: StringRef CPU, MachO::CPUSubTypeX86 st) : DarwinX86AsmBackend(T, MRI, CPU, true), Subtype(st) {} - MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override { return createX86MachObjectWriter(OS, /*Is64Bit=*/true, MachO::CPU_TYPE_X86_64, Subtype); } diff --git a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h index d8953da4abb2..07cc488d047e 100644 --- a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -51,6 +51,18 @@ namespace X86 { TO_ZERO = 3, CUR_DIRECTION = 4 }; + + /// The constants to describe instr prefixes if there are + enum IPREFIXES { + IP_NO_PREFIX = 0, + IP_HAS_OP_SIZE = 1, + IP_HAS_AD_SIZE = 2, + IP_HAS_REPEAT_NE = 4, + IP_HAS_REPEAT = 8, + IP_HAS_LOCK = 16, + NO_SCHED_INFO = 32 // Don't add sched comment to the current instr because + // it was already added + }; } // end namespace X86; /// X86II - This namespace holds all of the target specific flags that @@ -356,13 +368,15 @@ namespace X86II { // OpSize - OpSizeFixed implies instruction never needs a 0x66 prefix. // OpSize16 means this is a 16-bit instruction and needs 0x66 prefix in // 32-bit mode. OpSize32 means this is a 32-bit instruction needs a 0x66 - // prefix in 16-bit mode. + // prefix in 16-bit mode. OpSizeIgnore means that the instruction may + // take a optional 0x66 byte but should not emit with one. OpSizeShift = 7, OpSizeMask = 0x3 << OpSizeShift, - OpSizeFixed = 0 << OpSizeShift, - OpSize16 = 1 << OpSizeShift, - OpSize32 = 2 << OpSizeShift, + OpSizeFixed = 0 << OpSizeShift, + OpSize16 = 1 << OpSizeShift, + OpSize32 = 2 << OpSizeShift, + OpSizeIgnore = 3 << OpSizeShift, // AsSize - AdSizeX implies this instruction determines its need of 0x67 // prefix from a normal ModRM memory operand. The other types indicate that diff --git a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp index 4da4eebec038..4cdbae4d0d96 100644 --- a/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include <cassert> @@ -297,10 +298,9 @@ unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind); } -MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS, - bool IsELF64, uint8_t OSABI, - uint16_t EMachine) { - MCELFObjectTargetWriter *MOTW = - new X86ELFObjectWriter(IsELF64, OSABI, EMachine); - return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true); +std::unique_ptr<MCObjectWriter> +llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS, bool IsELF64, + uint8_t OSABI, uint16_t EMachine) { + auto MOTW = llvm::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); + return createELFObjectWriter(std::move(MOTW), OS, /*IsLittleEndian=*/true); } diff --git a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp index 1538a515f419..fa7c352a1b63 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp @@ -13,10 +13,7 @@ #include "X86MCAsmInfo.h" #include "llvm/ADT/Triple.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Support/CommandLine.h" using namespace llvm; @@ -27,11 +24,11 @@ enum AsmWriterFlavorTy { ATT = 0, Intel = 1 }; -static cl::opt<AsmWriterFlavorTy> -AsmWriterFlavor("x86-asm-syntax", cl::init(ATT), - cl::desc("Choose style of code to emit from X86 backend:"), - cl::values(clEnumValN(ATT, "att", "Emit AT&T-style assembly"), - clEnumValN(Intel, "intel", "Emit Intel-style assembly"))); +static cl::opt<AsmWriterFlavorTy> AsmWriterFlavor( + "x86-asm-syntax", cl::init(ATT), cl::Hidden, + cl::desc("Choose style of code to emit from X86 backend:"), + cl::values(clEnumValN(ATT, "att", "Emit AT&T-style assembly"), + clEnumValN(Intel, "intel", "Emit Intel-style assembly"))); static cl::opt<bool> MarkedJTDataRegions("mark-data-regions", cl::init(true), diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 10e2bbc64d3c..a7059c6914df 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -380,7 +380,7 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op, return X86::reloc_riprel_4byte_movq_load; case X86::CALL64m: case X86::JMP64m: - case X86::TEST64rm: + case X86::TEST64mr: case X86::ADC64rm: case X86::ADD64rm: case X86::AND64rm: @@ -1108,7 +1108,7 @@ bool X86MCCodeEmitter::emitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, EmitByte(0x66, CurByte, OS); // Emit the LOCK opcode prefix. - if (TSFlags & X86II::LOCK) + if (TSFlags & X86II::LOCK || MI.getFlags() & X86::IP_HAS_LOCK) EmitByte(0xF0, CurByte, OS); switch (TSFlags & X86II::OpPrefixMask) { @@ -1130,6 +1130,8 @@ bool X86MCCodeEmitter::emitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, EmitByte(0x40 | REX, CurByte, OS); Ret = true; } + } else { + assert(!(TSFlags & X86II::REX_W) && "REX.W requires 64bit mode."); } // 0x0F escape code must be emitted just before the opcode. @@ -1159,6 +1161,7 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS, unsigned Opcode = MI.getOpcode(); const MCInstrDesc &Desc = MCII.get(Opcode); uint64_t TSFlags = Desc.TSFlags; + unsigned Flags = MI.getFlags(); // Pseudo instructions don't get encoded. if ((TSFlags & X86II::FormMask) == X86II::Pseudo) @@ -1194,8 +1197,10 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS, MI, OS); // Emit the repeat opcode prefix as needed. - if (TSFlags & X86II::REP) + if (TSFlags & X86II::REP || Flags & X86::IP_HAS_REPEAT) EmitByte(0xF3, CurByte, OS); + if (Flags & X86::IP_HAS_REPEAT_NE) + EmitByte(0xF2, CurByte, OS); // Emit the address size opcode prefix as needed. bool need_address_override; diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp index 22cb0fac33cb..cdd43478baed 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -16,6 +16,7 @@ #include "InstPrinter/X86IntelInstPrinter.h" #include "X86MCAsmInfo.h" #include "llvm/ADT/Triple.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" @@ -72,52 +73,128 @@ void X86_MC::initLLVMToSEHAndCVRegMapping(MCRegisterInfo *MRI) { MRI->mapLLVMRegToSEHReg(Reg, SEH); } - // These CodeView registers are numbered sequentially starting at value 1. - static const MCPhysReg LowCVRegs[] = { - X86::AL, X86::CL, X86::DL, X86::BL, X86::AH, X86::CH, - X86::DH, X86::BH, X86::AX, X86::CX, X86::DX, X86::BX, - X86::SP, X86::BP, X86::SI, X86::DI, X86::EAX, X86::ECX, - X86::EDX, X86::EBX, X86::ESP, X86::EBP, X86::ESI, X86::EDI, - }; - unsigned CVLowRegStart = 1; - for (unsigned I = 0; I < array_lengthof(LowCVRegs); ++I) - MRI->mapLLVMRegToCVReg(LowCVRegs[I], I + CVLowRegStart); - - MRI->mapLLVMRegToCVReg(X86::EFLAGS, 34); + // Mapping from CodeView to MC register id. + static const struct { + codeview::RegisterId CVReg; + MCPhysReg Reg; + } RegMap[] = { + { codeview::RegisterId::AL, X86::AL}, + { codeview::RegisterId::CL, X86::CL}, + { codeview::RegisterId::DL, X86::DL}, + { codeview::RegisterId::BL, X86::BL}, + { codeview::RegisterId::AH, X86::AH}, + { codeview::RegisterId::CH, X86::CH}, + { codeview::RegisterId::DH, X86::DH}, + { codeview::RegisterId::BH, X86::BH}, + { codeview::RegisterId::AX, X86::AX}, + { codeview::RegisterId::CX, X86::CX}, + { codeview::RegisterId::DX, X86::DX}, + { codeview::RegisterId::BX, X86::BX}, + { codeview::RegisterId::SP, X86::SP}, + { codeview::RegisterId::BP, X86::BP}, + { codeview::RegisterId::SI, X86::SI}, + { codeview::RegisterId::DI, X86::DI}, + { codeview::RegisterId::EAX, X86::EAX}, + { codeview::RegisterId::ECX, X86::ECX}, + { codeview::RegisterId::EDX, X86::EDX}, + { codeview::RegisterId::EBX, X86::EBX}, + { codeview::RegisterId::ESP, X86::ESP}, + { codeview::RegisterId::EBP, X86::EBP}, + { codeview::RegisterId::ESI, X86::ESI}, + { codeview::RegisterId::EDI, X86::EDI}, - // The x87 registers start at 128 and are numbered sequentially. - unsigned FP0Start = 128; - for (unsigned I = 0; I < 8; ++I) - MRI->mapLLVMRegToCVReg(X86::FP0 + I, FP0Start + I); + { codeview::RegisterId::EFLAGS, X86::EFLAGS}, - // The low 8 XMM registers start at 154 and are numbered sequentially. - unsigned CVXMM0Start = 154; - for (unsigned I = 0; I < 8; ++I) - MRI->mapLLVMRegToCVReg(X86::XMM0 + I, CVXMM0Start + I); + { codeview::RegisterId::ST0, X86::FP0}, + { codeview::RegisterId::ST1, X86::FP1}, + { codeview::RegisterId::ST2, X86::FP2}, + { codeview::RegisterId::ST3, X86::FP3}, + { codeview::RegisterId::ST4, X86::FP4}, + { codeview::RegisterId::ST5, X86::FP5}, + { codeview::RegisterId::ST6, X86::FP6}, + { codeview::RegisterId::ST7, X86::FP7}, - // The high 8 XMM registers start at 252 and are numbered sequentially. - unsigned CVXMM8Start = 252; - for (unsigned I = 0; I < 8; ++I) - MRI->mapLLVMRegToCVReg(X86::XMM8 + I, CVXMM8Start + I); + { codeview::RegisterId::XMM0, X86::XMM0}, + { codeview::RegisterId::XMM1, X86::XMM1}, + { codeview::RegisterId::XMM2, X86::XMM2}, + { codeview::RegisterId::XMM3, X86::XMM3}, + { codeview::RegisterId::XMM4, X86::XMM4}, + { codeview::RegisterId::XMM5, X86::XMM5}, + { codeview::RegisterId::XMM6, X86::XMM6}, + { codeview::RegisterId::XMM7, X86::XMM7}, - // FIXME: XMM16 and above from AVX512 not yet documented. + { codeview::RegisterId::XMM8, X86::XMM8}, + { codeview::RegisterId::XMM9, X86::XMM9}, + { codeview::RegisterId::XMM10, X86::XMM10}, + { codeview::RegisterId::XMM11, X86::XMM11}, + { codeview::RegisterId::XMM12, X86::XMM12}, + { codeview::RegisterId::XMM13, X86::XMM13}, + { codeview::RegisterId::XMM14, X86::XMM14}, + { codeview::RegisterId::XMM15, X86::XMM15}, - // AMD64 registers start at 324 and count up. - unsigned CVX64RegStart = 324; - static const MCPhysReg CVX64Regs[] = { - X86::SIL, X86::DIL, X86::BPL, X86::SPL, X86::RAX, X86::RBX, - X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RBP, X86::RSP, - X86::R8, X86::R9, X86::R10, X86::R11, X86::R12, X86::R13, - X86::R14, X86::R15, X86::R8B, X86::R9B, X86::R10B, X86::R11B, - X86::R12B, X86::R13B, X86::R14B, X86::R15B, X86::R8W, X86::R9W, - X86::R10W, X86::R11W, X86::R12W, X86::R13W, X86::R14W, X86::R15W, - X86::R8D, X86::R9D, X86::R10D, X86::R11D, X86::R12D, X86::R13D, - X86::R14D, X86::R15D, X86::YMM0, X86::YMM1, X86::YMM2, X86::YMM3, - X86::YMM4, X86::YMM5, X86::YMM6, X86::YMM7, X86::YMM8, X86::YMM9, - X86::YMM10, X86::YMM11, X86::YMM12, X86::YMM13, X86::YMM14, X86::YMM15, + { codeview::RegisterId::SIL, X86::SIL}, + { codeview::RegisterId::DIL, X86::DIL}, + { codeview::RegisterId::BPL, X86::BPL}, + { codeview::RegisterId::SPL, X86::SPL}, + { codeview::RegisterId::RAX, X86::RAX}, + { codeview::RegisterId::RBX, X86::RBX}, + { codeview::RegisterId::RCX, X86::RCX}, + { codeview::RegisterId::RDX, X86::RDX}, + { codeview::RegisterId::RSI, X86::RSI}, + { codeview::RegisterId::RDI, X86::RDI}, + { codeview::RegisterId::RBP, X86::RBP}, + { codeview::RegisterId::RSP, X86::RSP}, + { codeview::RegisterId::R8, X86::R8}, + { codeview::RegisterId::R9, X86::R9}, + { codeview::RegisterId::R10, X86::R10}, + { codeview::RegisterId::R11, X86::R11}, + { codeview::RegisterId::R12, X86::R12}, + { codeview::RegisterId::R13, X86::R13}, + { codeview::RegisterId::R14, X86::R14}, + { codeview::RegisterId::R15, X86::R15}, + { codeview::RegisterId::R8B, X86::R8B}, + { codeview::RegisterId::R9B, X86::R9B}, + { codeview::RegisterId::R10B, X86::R10B}, + { codeview::RegisterId::R11B, X86::R11B}, + { codeview::RegisterId::R12B, X86::R12B}, + { codeview::RegisterId::R13B, X86::R13B}, + { codeview::RegisterId::R14B, X86::R14B}, + { codeview::RegisterId::R15B, X86::R15B}, + { codeview::RegisterId::R8W, X86::R8W}, + { codeview::RegisterId::R9W, X86::R9W}, + { codeview::RegisterId::R10W, X86::R10W}, + { codeview::RegisterId::R11W, X86::R11W}, + { codeview::RegisterId::R12W, X86::R12W}, + { codeview::RegisterId::R13W, X86::R13W}, + { codeview::RegisterId::R14W, X86::R14W}, + { codeview::RegisterId::R15W, X86::R15W}, + { codeview::RegisterId::R8D, X86::R8D}, + { codeview::RegisterId::R9D, X86::R9D}, + { codeview::RegisterId::R10D, X86::R10D}, + { codeview::RegisterId::R11D, X86::R11D}, + { codeview::RegisterId::R12D, X86::R12D}, + { codeview::RegisterId::R13D, X86::R13D}, + { codeview::RegisterId::R14D, X86::R14D}, + { codeview::RegisterId::R15D, X86::R15D}, + { codeview::RegisterId::AMD64_YMM0, X86::YMM0}, + { codeview::RegisterId::AMD64_YMM1, X86::YMM1}, + { codeview::RegisterId::AMD64_YMM2, X86::YMM2}, + { codeview::RegisterId::AMD64_YMM3, X86::YMM3}, + { codeview::RegisterId::AMD64_YMM4, X86::YMM4}, + { codeview::RegisterId::AMD64_YMM5, X86::YMM5}, + { codeview::RegisterId::AMD64_YMM6, X86::YMM6}, + { codeview::RegisterId::AMD64_YMM7, X86::YMM7}, + { codeview::RegisterId::AMD64_YMM8, X86::YMM8}, + { codeview::RegisterId::AMD64_YMM9, X86::YMM9}, + { codeview::RegisterId::AMD64_YMM10, X86::YMM10}, + { codeview::RegisterId::AMD64_YMM11, X86::YMM11}, + { codeview::RegisterId::AMD64_YMM12, X86::YMM12}, + { codeview::RegisterId::AMD64_YMM13, X86::YMM13}, + { codeview::RegisterId::AMD64_YMM14, X86::YMM14}, + { codeview::RegisterId::AMD64_YMM15, X86::YMM15}, }; - for (unsigned I = 0; I < array_lengthof(CVX64Regs); ++I) - MRI->mapLLVMRegToCVReg(CVX64Regs[I], CVX64RegStart + I); + for (unsigned I = 0; I < array_lengthof(RegMap); ++I) + MRI->mapLLVMRegToCVReg(RegMap[I].Reg, static_cast<int>(RegMap[I].CVReg)); } MCSubtargetInfo *X86_MC::createX86MCSubtargetInfo(const Triple &TT, @@ -198,18 +275,6 @@ static MCAsmInfo *createX86MCAsmInfo(const MCRegisterInfo &MRI, return MAI; } -static void adjustCodeGenOpts(const Triple &TT, Reloc::Model RM, - CodeModel::Model &CM) { - bool is64Bit = TT.getArch() == Triple::x86_64; - - // For static codegen, if we're not already set, use Small codegen. - if (CM == CodeModel::Default) - CM = CodeModel::Small; - else if (CM == CodeModel::JITDefault) - // 64-bit JIT places everything in the same buffer except external funcs. - CM = is64Bit ? CodeModel::Large : CodeModel::Small; -} - static MCInstPrinter *createX86MCInstPrinter(const Triple &T, unsigned SyntaxVariant, const MCAsmInfo &MAI, @@ -238,9 +303,6 @@ extern "C" void LLVMInitializeX86TargetMC() { // Register the MC asm info. RegisterMCAsmInfoFn X(*T, createX86MCAsmInfo); - // Register the MC codegen info. - RegisterMCAdjustCodeGenOptsFn Y(*T, adjustCodeGenOpts); - // Register the MC instruction info. TargetRegistry::RegisterMCInstrInfo(*T, createX86MCInstrInfo); @@ -257,7 +319,13 @@ extern "C" void LLVMInitializeX86TargetMC() { // Register the code emitter. TargetRegistry::RegisterMCCodeEmitter(*T, createX86MCCodeEmitter); - // Register the object streamer. + // Register the obj target streamer. + TargetRegistry::RegisterObjectTargetStreamer(*T, + createX86ObjectTargetStreamer); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(*T, createX86AsmTargetStreamer); + TargetRegistry::RegisterCOFFStreamer(*T, createX86WinCOFFStreamer); // Register the MCInstPrinter. diff --git a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h index f73e734b9b0e..c5859b600ad2 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h +++ b/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h @@ -77,25 +77,41 @@ MCAsmBackend *createX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI, const Triple &TT, StringRef CPU, const MCTargetOptions &Options); +/// Implements X86-only directives for assembly emission. +MCTargetStreamer *createX86AsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, + bool isVerboseAsm); + +/// Implements X86-only directives for object files. +MCTargetStreamer *createX86ObjectTargetStreamer(MCStreamer &OS, + const MCSubtargetInfo &STI); + /// Construct an X86 Windows COFF machine code streamer which will generate /// PE/COFF format object files. /// /// Takes ownership of \p AB and \p CE. -MCStreamer *createX86WinCOFFStreamer(MCContext &C, MCAsmBackend &AB, - raw_pwrite_stream &OS, MCCodeEmitter *CE, - bool RelaxAll, bool IncrementalLinkerCompatible); +MCStreamer *createX86WinCOFFStreamer(MCContext &C, + std::unique_ptr<MCAsmBackend> &&AB, + raw_pwrite_stream &OS, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll, + bool IncrementalLinkerCompatible); /// Construct an X86 Mach-O object writer. -MCObjectWriter *createX86MachObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, - uint32_t CPUType, - uint32_t CPUSubtype); +std::unique_ptr<MCObjectWriter> createX86MachObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit, + uint32_t CPUType, + uint32_t CPUSubtype); /// Construct an X86 ELF object writer. -MCObjectWriter *createX86ELFObjectWriter(raw_pwrite_stream &OS, bool IsELF64, - uint8_t OSABI, uint16_t EMachine); +std::unique_ptr<MCObjectWriter> createX86ELFObjectWriter(raw_pwrite_stream &OS, + bool IsELF64, + uint8_t OSABI, + uint16_t EMachine); /// Construct an X86 Win COFF object writer. -MCObjectWriter *createX86WinCOFFObjectWriter(raw_pwrite_stream &OS, - bool Is64Bit); +std::unique_ptr<MCObjectWriter> +createX86WinCOFFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit); /// Returns the sub or super register of a specific X86 register. /// e.g. getX86SubSuperRegister(X86::EAX, 16) returns X86::AX. diff --git a/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp index 8f2017e990c5..965f7de809b3 100644 --- a/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp @@ -597,11 +597,10 @@ void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE); } -MCObjectWriter *llvm::createX86MachObjectWriter(raw_pwrite_stream &OS, - bool Is64Bit, uint32_t CPUType, - uint32_t CPUSubtype) { - return createMachObjectWriter(new X86MachObjectWriter(Is64Bit, - CPUType, - CPUSubtype), - OS, /*IsLittleEndian=*/true); +std::unique_ptr<MCObjectWriter> +llvm::createX86MachObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, + uint32_t CPUType, uint32_t CPUSubtype) { + return createMachObjectWriter( + llvm::make_unique<X86MachObjectWriter>(Is64Bit, CPUType, CPUSubtype), OS, + /*IsLittleEndian=*/true); } diff --git a/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h b/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h new file mode 100644 index 000000000000..8d38cd32b82c --- /dev/null +++ b/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h @@ -0,0 +1,34 @@ +//===- X86TargetStreamer.h ------------------------------*- C++ -*---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H +#define LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H + +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +/// X86 target streamer implementing x86-only assembly directives. +class X86TargetStreamer : public MCTargetStreamer { +public: + X86TargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} + + virtual bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize, + SMLoc L = {}) = 0; + virtual bool emitFPOEndPrologue(SMLoc L = {}) = 0; + virtual bool emitFPOEndProc(SMLoc L = {}) = 0; + virtual bool emitFPOData(const MCSymbol *ProcSym, SMLoc L = {}) = 0; + virtual bool emitFPOPushReg(unsigned Reg, SMLoc L = {}) = 0; + virtual bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L = {}) = 0; + virtual bool emitFPOSetFrame(unsigned Reg, SMLoc L = {}) = 0; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp b/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp index 807f7a6ddb19..5139bb46b561 100644 --- a/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCWinCOFFObjectWriter.h" #include "llvm/Support/ErrorHandling.h" @@ -104,8 +105,8 @@ unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx, llvm_unreachable("Unsupported COFF machine type."); } -MCObjectWriter *llvm::createX86WinCOFFObjectWriter(raw_pwrite_stream &OS, - bool Is64Bit) { - MCWinCOFFObjectTargetWriter *MOTW = new X86WinCOFFObjectWriter(Is64Bit); - return createWinCOFFObjectWriter(MOTW, OS); +std::unique_ptr<MCObjectWriter> +llvm::createX86WinCOFFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit) { + auto MOTW = llvm::make_unique<X86WinCOFFObjectWriter>(Is64Bit); + return createWinCOFFObjectWriter(std::move(MOTW), OS); } diff --git a/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp b/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp index d04511873b46..5b1357ae4a7b 100644 --- a/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp +++ b/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "X86MCTargetDesc.h" +#include "X86TargetStreamer.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCWin64EH.h" #include "llvm/MC/MCWinCOFFStreamer.h" @@ -17,17 +20,18 @@ namespace { class X86WinCOFFStreamer : public MCWinCOFFStreamer { Win64EH::UnwindEmitter EHStreamer; public: - X86WinCOFFStreamer(MCContext &C, MCAsmBackend &AB, MCCodeEmitter *CE, - raw_pwrite_stream &OS) - : MCWinCOFFStreamer(C, AB, *CE, OS) {} + X86WinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB, + std::unique_ptr<MCCodeEmitter> CE, raw_pwrite_stream &OS) + : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), OS) {} - void EmitWinEHHandlerData() override; + void EmitWinEHHandlerData(SMLoc Loc) override; void EmitWindowsUnwindTables() override; + void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) override; void FinishImpl() override; }; -void X86WinCOFFStreamer::EmitWinEHHandlerData() { - MCStreamer::EmitWinEHHandlerData(); +void X86WinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) { + MCStreamer::EmitWinEHHandlerData(Loc); // We have to emit the unwind info now, because this directive // actually switches to the .xdata section! @@ -40,6 +44,12 @@ void X86WinCOFFStreamer::EmitWindowsUnwindTables() { EHStreamer.Emit(*this); } +void X86WinCOFFStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) { + X86TargetStreamer *XTS = + static_cast<X86TargetStreamer *>(getTargetStreamer()); + XTS->emitFPOData(ProcSym, Loc); +} + void X86WinCOFFStreamer::FinishImpl() { EmitFrames(nullptr); EmitWindowsUnwindTables(); @@ -48,11 +58,14 @@ void X86WinCOFFStreamer::FinishImpl() { } } -MCStreamer *llvm::createX86WinCOFFStreamer(MCContext &C, MCAsmBackend &AB, +MCStreamer *llvm::createX86WinCOFFStreamer(MCContext &C, + std::unique_ptr<MCAsmBackend> &&AB, raw_pwrite_stream &OS, - MCCodeEmitter *CE, bool RelaxAll, + std::unique_ptr<MCCodeEmitter> &&CE, + bool RelaxAll, bool IncrementalLinkerCompatible) { - X86WinCOFFStreamer *S = new X86WinCOFFStreamer(C, AB, CE, OS); + X86WinCOFFStreamer *S = + new X86WinCOFFStreamer(C, std::move(AB), std::move(CE), OS); S->getAssembler().setRelaxAll(RelaxAll); S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible); return S; diff --git a/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp b/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp new file mode 100644 index 000000000000..093dab4f2f96 --- /dev/null +++ b/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp @@ -0,0 +1,415 @@ +//===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "X86MCTargetDesc.h" +#include "X86TargetStreamer.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/MC/MCCodeView.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +/// Implements Windows x86-only directives for assembly emission. +class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer { + formatted_raw_ostream &OS; + MCInstPrinter &InstPrinter; + +public: + X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter &InstPrinter) + : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {} + + bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize, + SMLoc L) override; + bool emitFPOEndPrologue(SMLoc L) override; + bool emitFPOEndProc(SMLoc L) override; + bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; + bool emitFPOPushReg(unsigned Reg, SMLoc L) override; + bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; +}; + +/// Represents a single FPO directive. +struct FPOInstruction { + MCSymbol *Label; + enum Operation { + PushReg, + StackAlloc, + SetFrame, + } Op; + unsigned RegOrOffset; +}; + +struct FPOData { + const MCSymbol *Function = nullptr; + MCSymbol *Begin = nullptr; + MCSymbol *PrologueEnd = nullptr; + MCSymbol *End = nullptr; + unsigned ParamsSize = 0; + + SmallVector<FPOInstruction, 5> Instructions; +}; + +/// Implements Windows x86-only directives for object emission. +class X86WinCOFFTargetStreamer : public X86TargetStreamer { + /// Map from function symbol to its FPO data. + DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData; + + /// Current FPO data created by .cv_fpo_proc. + std::unique_ptr<FPOData> CurFPOData; + + bool haveOpenFPOData() { return !!CurFPOData; } + + /// Diagnoses an error at L if we are not in an FPO prologue. Return true on + /// error. + bool checkInFPOPrologue(SMLoc L); + + MCSymbol *emitFPOLabel(); + + MCContext &getContext() { return getStreamer().getContext(); } + +public: + X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {} + + bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize, + SMLoc L) override; + bool emitFPOEndPrologue(SMLoc L) override; + bool emitFPOEndProc(SMLoc L) override; + bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; + bool emitFPOPushReg(unsigned Reg, SMLoc L) override; + bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; +}; +} // end namespace + +bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym, + unsigned ParamsSize, SMLoc L) { + OS << "\t.cv_fpo_proc\t"; + ProcSym->print(OS, getStreamer().getContext().getAsmInfo()); + OS << ' ' << ParamsSize << '\n'; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) { + OS << "\t.cv_fpo_endprologue\n"; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) { + OS << "\t.cv_fpo_endproc\n"; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym, + SMLoc L) { + OS << "\t.cv_fpo_data\t"; + ProcSym->print(OS, getStreamer().getContext().getAsmInfo()); + OS << '\n'; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) { + OS << "\t.cv_fpo_pushreg\t"; + InstPrinter.printRegName(OS, Reg); + OS << '\n'; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, + SMLoc L) { + OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n'; + return false; +} + +bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) { + OS << "\t.cv_fpo_setframe\t"; + InstPrinter.printRegName(OS, Reg); + OS << '\n'; + return false; +} + +bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) { + if (!haveOpenFPOData() || CurFPOData->PrologueEnd) { + getContext().reportError( + L, + "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue"); + return true; + } + return false; +} + +MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() { + MCSymbol *Label = getContext().createTempSymbol("cfi", true); + getStreamer().EmitLabel(Label); + return Label; +} + +bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym, + unsigned ParamsSize, SMLoc L) { + if (haveOpenFPOData()) { + getContext().reportError( + L, "opening new .cv_fpo_proc before closing previous frame"); + return true; + } + CurFPOData = llvm::make_unique<FPOData>(); + CurFPOData->Function = ProcSym; + CurFPOData->Begin = emitFPOLabel(); + CurFPOData->ParamsSize = ParamsSize; + return false; +} + +bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) { + if (!haveOpenFPOData()) { + getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc"); + return true; + } + if (!CurFPOData->PrologueEnd) { + // Complain if there were prologue setup instructions but no end prologue. + if (!CurFPOData->Instructions.empty()) { + getContext().reportError(L, "missing .cv_fpo_endprologue"); + CurFPOData->Instructions.clear(); + } + + // Claim there is a zero-length prologue to make the label math work out + // later. + CurFPOData->PrologueEnd = CurFPOData->Begin; + } + + CurFPOData->End = emitFPOLabel(); + const MCSymbol *Fn = CurFPOData->Function; + AllFPOData.insert({Fn, std::move(CurFPOData)}); + return false; +} + +bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + FPOInstruction Inst; + Inst.Label = emitFPOLabel(); + Inst.Op = FPOInstruction::SetFrame; + Inst.RegOrOffset = Reg; + CurFPOData->Instructions.push_back(Inst); + return false; +} + +bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + FPOInstruction Inst; + Inst.Label = emitFPOLabel(); + Inst.Op = FPOInstruction::PushReg; + Inst.RegOrOffset = Reg; + CurFPOData->Instructions.push_back(Inst); + return false; +} + +bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + FPOInstruction Inst; + Inst.Label = emitFPOLabel(); + Inst.Op = FPOInstruction::StackAlloc; + Inst.RegOrOffset = StackAlloc; + CurFPOData->Instructions.push_back(Inst); + return false; +} + +bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + CurFPOData->PrologueEnd = emitFPOLabel(); + return false; +} + +namespace { +struct RegSaveOffset { + RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {} + + unsigned Reg = 0; + unsigned Offset = 0; +}; + +struct FPOStateMachine { + explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {} + + const FPOData *FPO = nullptr; + unsigned FrameReg = 0; + unsigned FrameRegOff = 0; + unsigned CurOffset = 0; + unsigned LocalSize = 0; + unsigned SavedRegSize = 0; + unsigned Flags = 0; // FIXME: Set HasSEH / HasEH. + + SmallString<128> FrameFunc; + + SmallVector<RegSaveOffset, 4> RegSaveOffsets; + + void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label); +}; +} // end namespace + +static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) { + return Printable([MRI, LLVMReg](raw_ostream &OS) { + switch (LLVMReg) { + // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP, + // but the format seems to support more than that, so we emit them. + case X86::EAX: OS << "$eax"; break; + case X86::EBX: OS << "$ebx"; break; + case X86::ECX: OS << "$ecx"; break; + case X86::EDX: OS << "$edx"; break; + case X86::EDI: OS << "$edi"; break; + case X86::ESI: OS << "$esi"; break; + case X86::ESP: OS << "$esp"; break; + case X86::EBP: OS << "$ebp"; break; + case X86::EIP: OS << "$eip"; break; + // Otherwise, get the codeview register number and print $N. + default: + OS << '$' << MRI->getCodeViewRegNum(LLVMReg); + break; + } + }); +} + +void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) { + unsigned CurFlags = Flags; + if (Label == FPO->Begin) + CurFlags |= FrameData::IsFunctionStart; + + // Compute the new FrameFunc string. + FrameFunc.clear(); + raw_svector_ostream FuncOS(FrameFunc); + const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo(); + if (FrameReg) { + // CFA is FrameReg + FrameRegOff. + FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff + << " + = "; + } else { + // The address of return address is ESP + CurOffset, but we use .raSearch to + // match MSVC. This seems to ask the debugger to subtract some combination + // of LocalSize and SavedRegSize from ESP and grovel around in that memory + // to find the address of a plausible return address. + FuncOS << "$T0 .raSearch = "; + } + + // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4. + FuncOS << "$eip $T0 ^ = $esp $T0 4 + = "; + + // Each saved register is stored at an unchanging negative CFA offset. + for (RegSaveOffset RO : RegSaveOffsets) + FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = "; + + // Add it to the CV string table. + CodeViewContext &CVCtx = OS.getContext().getCVContext(); + unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second; + + // MSVC has only ever been observed to emit a MaxStackSize of zero. + unsigned MaxStackSize = 0; + + // The FrameData record format is: + // ulittle32_t RvaStart; + // ulittle32_t CodeSize; + // ulittle32_t LocalSize; + // ulittle32_t ParamsSize; + // ulittle32_t MaxStackSize; + // ulittle32_t FrameFunc; // String table offset + // ulittle16_t PrologSize; + // ulittle16_t SavedRegsSize; + // ulittle32_t Flags; + + OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart + OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4); // CodeSize + OS.EmitIntValue(LocalSize, 4); + OS.EmitIntValue(FPO->ParamsSize, 4); + OS.EmitIntValue(MaxStackSize, 4); + OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc + OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2); + OS.EmitIntValue(SavedRegSize, 2); + OS.EmitIntValue(CurFlags, 4); +} + +/// Compute and emit the real CodeView FrameData subsection. +bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) { + MCStreamer &OS = getStreamer(); + MCContext &Ctx = OS.getContext(); + + auto I = AllFPOData.find(ProcSym); + if (I == AllFPOData.end()) { + Ctx.reportError(L, Twine("no FPO data found for symbol ") + + ProcSym->getName()); + return true; + } + const FPOData *FPO = I->second.get(); + assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label"); + + MCSymbol *FrameBegin = Ctx.createTempSymbol(), + *FrameEnd = Ctx.createTempSymbol(); + + OS.EmitIntValue(unsigned(DebugSubsectionKind::FrameData), 4); + OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4); + OS.EmitLabel(FrameBegin); + + // Start with the RVA of the function in question. + OS.EmitValue(MCSymbolRefExpr::create(FPO->Function, + MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx), + 4); + + // Emit a sequence of FrameData records. + FPOStateMachine FSM(FPO); + + FSM.emitFrameDataRecord(OS, FPO->Begin); + for (const FPOInstruction &Inst : FPO->Instructions) { + switch (Inst.Op) { + case FPOInstruction::PushReg: + FSM.CurOffset += 4; + FSM.SavedRegSize += 4; + FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset}); + break; + case FPOInstruction::SetFrame: + FSM.FrameReg = Inst.RegOrOffset; + FSM.FrameRegOff = FSM.CurOffset; + break; + case FPOInstruction::StackAlloc: + FSM.CurOffset += Inst.RegOrOffset; + FSM.LocalSize += Inst.RegOrOffset; + // No need to emit FrameData for stack allocations with a frame pointer. + if (FSM.FrameReg) + continue; + break; + } + FSM.emitFrameDataRecord(OS, Inst.Label); + } + + OS.EmitValueToAlignment(4, 0); + OS.EmitLabel(FrameEnd); + return false; +} + +MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter *InstPrinter, + bool IsVerboseAsm) { + // FIXME: This makes it so we textually assemble COFF directives on ELF. + // That's kind of nonsensical. + return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter); +} + +MCTargetStreamer * +llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + // No need to register a target streamer. + if (!STI.getTargetTriple().isOSBinFormatCOFF()) + return nullptr; + // Registers itself to the MCStreamer. + return new X86WinCOFFTargetStreamer(S); +} |
