diff options
Diffstat (limited to 'contrib/llvm/lib/MC')
23 files changed, 1511 insertions, 1752 deletions
diff --git a/contrib/llvm/lib/MC/MCAsmInfo.cpp b/contrib/llvm/lib/MC/MCAsmInfo.cpp index 73b259e..502b60b 100644 --- a/contrib/llvm/lib/MC/MCAsmInfo.cpp +++ b/contrib/llvm/lib/MC/MCAsmInfo.cpp @@ -23,6 +23,9 @@ using namespace llvm; MCAsmInfo::MCAsmInfo() { + PointerSize = 4; + IsLittleEndian = true; + StackGrowsUp = false; HasSubsectionsViaSymbols = false; HasMachoZeroFillDirective = false; HasMachoTBSSDirective = false; @@ -78,6 +81,7 @@ MCAsmInfo::MCAsmInfo() { DwarfRequiresRelocationForSectionOffset = true; DwarfSectionOffsetDirective = 0; DwarfUsesLabelOffsetForRanges = true; + DwarfRegNumForCFI = false; HasMicrosoftFastStdCallMangling = false; AsmTransCBE = 0; diff --git a/contrib/llvm/lib/MC/MCAsmStreamer.cpp b/contrib/llvm/lib/MC/MCAsmStreamer.cpp index e8b09fc..d5d08e8 100644 --- a/contrib/llvm/lib/MC/MCAsmStreamer.cpp +++ b/contrib/llvm/lib/MC/MCAsmStreamer.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -33,8 +34,10 @@ using namespace llvm; namespace { class MCAsmStreamer : public MCStreamer { +protected: formatted_raw_ostream &OS; const MCAsmInfo &MAI; +private: OwningPtr<MCInstPrinter> InstPrinter; OwningPtr<MCCodeEmitter> Emitter; OwningPtr<TargetAsmBackend> AsmBackend; @@ -134,7 +137,8 @@ public: virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, - const MCSymbol *Label); + const MCSymbol *Label, + unsigned PointerSize); virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label); @@ -361,9 +365,9 @@ void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, - const MCSymbol *Label) { - EmitDwarfSetLineAddr(LineDelta, Label, - getContext().getTargetAsmInfo().getPointerSize()); + const MCSymbol *Label, + unsigned PointerSize) { + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); } void MCAsmStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, @@ -600,7 +604,7 @@ void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, int64_t IntValue; if (!Value->EvaluateAsAbsolute(IntValue)) report_fatal_error("Don't know how to emit this value."); - if (getContext().getTargetAsmInfo().isLittleEndian()) { + if (getContext().getAsmInfo().isLittleEndian()) { EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace); EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace); } else { @@ -822,9 +826,9 @@ void MCAsmStreamer::EmitCFIEndProc() { } void MCAsmStreamer::EmitRegisterName(int64_t Register) { - if (InstPrinter) { - const TargetAsmInfo &asmInfo = getContext().getTargetAsmInfo(); - unsigned LLVMRegister = asmInfo.getLLVMRegNum(Register, true); + if (InstPrinter && !MAI.useDwarfRegNumForCFI()) { + const TargetAsmInfo &TAI = getContext().getTargetAsmInfo(); + unsigned LLVMRegister = TAI.getLLVMRegNum(Register, true); InstPrinter->printRegName(OS, LLVMRegister); } else { OS << Register; @@ -1085,7 +1089,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { } } - // FIXME: Node the fixup comments for Thumb2 are completely bogus since the + // FIXME: Note the fixup comments for Thumb2 are completely bogus since the // high order halfword of a 32-bit Thumb2 instruction is emitted first. OS << "encoding: ["; for (unsigned i = 0, e = Code.size(); i != e; ++i) { @@ -1120,7 +1124,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { unsigned Bit = (Code[i] >> j) & 1; unsigned FixupBit; - if (getContext().getTargetAsmInfo().isLittleEndian()) + if (getContext().getAsmInfo().isLittleEndian()) FixupBit = i * 8 + j; else FixupBit = i * 8 + (7-j); @@ -1241,13 +1245,12 @@ void MCAsmStreamer::Finish() { if (!UseCFI) EmitFrames(false); } - MCStreamer *llvm::createAsmStreamer(MCContext &Context, formatted_raw_ostream &OS, bool isVerboseAsm, bool useLoc, - bool useCFI, - MCInstPrinter *IP, MCCodeEmitter *CE, - TargetAsmBackend *TAB, bool ShowInst) { + bool useCFI, MCInstPrinter *IP, + MCCodeEmitter *CE, TargetAsmBackend *TAB, + bool ShowInst) { return new MCAsmStreamer(Context, OS, isVerboseAsm, useLoc, useCFI, IP, CE, TAB, ShowInst); } diff --git a/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp index 6e636f0..5480b4b 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -40,6 +40,7 @@ LLVMDisasmContextRef LLVMCreateDisasm(const char *TripleName, void *DisInfo, llvm::InitializeAllTargetInfos(); // FIXME: We shouldn't need to initialize the Target(Machine)s. llvm::InitializeAllTargets(); + llvm::InitializeAllMCAsmInfos(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); @@ -50,16 +51,18 @@ LLVMDisasmContextRef LLVMCreateDisasm(const char *TripleName, void *DisInfo, assert(TheTarget && "Unable to create target!"); // Get the assembler info needed to setup the MCContext. - const MCAsmInfo *MAI = TheTarget->createAsmInfo(TripleName); + const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(TripleName); assert(MAI && "Unable to create target asm info!"); // Package up features to be passed to target/subtarget std::string FeaturesStr; + std::string CPU; // FIXME: We shouldn't need to do this (and link in codegen). // When we split this out, we should do it in a way that makes // it straightforward to switch subtargets on the fly. - TargetMachine *TM = TheTarget->createTargetMachine(TripleName, FeaturesStr); + TargetMachine *TM = TheTarget->createTargetMachine(TripleName, CPU, + FeaturesStr); assert(TM && "Unable to create target machine!"); // Get the target assembler info needed to setup the context. @@ -77,7 +80,7 @@ LLVMDisasmContextRef LLVMCreateDisasm(const char *TripleName, void *DisInfo, // Set up the instruction printer. int AsmPrinterVariant = MAI->getAssemblerDialect(); - MCInstPrinter *IP = TheTarget->createMCInstPrinter(*TM, AsmPrinterVariant, + MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant, *MAI); assert(IP && "Unable to create instruction printer!"); diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp index 91c5284..bdd99af 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp +++ b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -23,6 +23,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" @@ -106,6 +107,7 @@ void EDDisassembler::initialize() { InitializeAllTargetInfos(); InitializeAllTargets(); + InitializeAllMCAsmInfos(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); InitializeAllDisassemblers(); @@ -167,11 +169,11 @@ EDDisassembler::EDDisassembler(CPUKey &key) : if (!Tgt) return; + std::string CPU; std::string featureString; - - TargetMachine.reset(Tgt->createTargetMachine(tripleString, + TargetMachine.reset(Tgt->createTargetMachine(tripleString, CPU, featureString)); - + const TargetRegisterInfo *registerInfo = TargetMachine->getRegisterInfo(); if (!registerInfo) @@ -179,11 +181,11 @@ EDDisassembler::EDDisassembler(CPUKey &key) : initMaps(*registerInfo); - AsmInfo.reset(Tgt->createAsmInfo(tripleString)); + AsmInfo.reset(Tgt->createMCAsmInfo(tripleString)); if (!AsmInfo) return; - + Disassembler.reset(Tgt->createMCDisassembler()); if (!Disassembler) @@ -193,8 +195,7 @@ EDDisassembler::EDDisassembler(CPUKey &key) : InstString.reset(new std::string); InstStream.reset(new raw_string_ostream(*InstString)); - InstPrinter.reset(Tgt->createMCInstPrinter(*TargetMachine, LLVMSyntaxVariant, - *AsmInfo)); + InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo)); if (!InstPrinter) return; @@ -372,8 +373,11 @@ int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, OwningPtr<MCAsmParser> genericParser(createMCAsmParser(*Tgt, sourceMgr, context, *streamer, *AsmInfo)); - OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(*genericParser, - *TargetMachine)); + + StringRef triple = tripleFromArch(Key.Arch); + OwningPtr<MCSubtargetInfo> STI(Tgt->createMCSubtargetInfo(triple, "", "")); + OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(*STI, + *genericParser)); AsmToken OpcodeToken = genericParser->Lex(); AsmToken NextToken = genericParser->Lex(); // consume next token, because specificParser expects us to diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h index 2fcc09d..11d69c1 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h +++ b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h @@ -41,6 +41,7 @@ class MCInstPrinter; class MCInst; class MCParsedAsmOperand; class MCStreamer; +class MCSubtargetInfo; template <typename T> class SmallVectorImpl; class SourceMgr; class Target; diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h b/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h index ad57282..e43ad16 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h +++ b/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h @@ -25,8 +25,11 @@ enum OperandTypes { kOperandTypeARMBranchTarget, kOperandTypeARMSoReg, kOperandTypeARMSoImm, + kOperandTypeARMRotImm, kOperandTypeARMSoImm2Part, kOperandTypeARMPredicate, + kOperandTypeAddrModeImm12, + kOperandTypeLdStSOReg, kOperandTypeARMAddrMode2, kOperandTypeARMAddrMode2Offset, kOperandTypeARMAddrMode3, @@ -38,13 +41,20 @@ enum OperandTypes { kOperandTypeARMAddrMode7, kOperandTypeARMAddrModePC, kOperandTypeARMRegisterList, + kOperandTypeARMDPRRegisterList, + kOperandTypeARMSPRRegisterList, kOperandTypeARMTBAddrMode, kOperandTypeThumbITMask, - kOperandTypeThumbAddrModeS1, - kOperandTypeThumbAddrModeS2, - kOperandTypeThumbAddrModeS4, + kOperandTypeThumbAddrModeRegS1, + kOperandTypeThumbAddrModeRegS2, + kOperandTypeThumbAddrModeRegS4, + kOperandTypeThumbAddrModeImmS1, + kOperandTypeThumbAddrModeImmS2, + kOperandTypeThumbAddrModeImmS4, kOperandTypeThumbAddrModeRR, kOperandTypeThumbAddrModeSP, + kOperandTypeThumbAddrModePC, + kOperandTypeThumb2AddrModeReg, kOperandTypeThumb2SoReg, kOperandTypeThumb2SoImm, kOperandTypeThumb2AddrModeImm8, @@ -52,8 +62,7 @@ enum OperandTypes { kOperandTypeThumb2AddrModeImm12, kOperandTypeThumb2AddrModeSoReg, kOperandTypeThumb2AddrModeImm8s4, - kOperandTypeThumb2AddrModeImm8s4Offset, - kOperandTypeThumb2AddrModeReg + kOperandTypeThumb2AddrModeImm8s4Offset }; enum OperandFlags { diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp index 492bb08..6a4e56f 100644 --- a/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp +++ b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp @@ -61,11 +61,14 @@ EDOperand::EDOperand(const EDDisassembler &disassembler, switch (operandType) { default: case kOperandTypeARMRegisterList: + case kOperandTypeARMDPRRegisterList: + case kOperandTypeARMSPRRegisterList: break; case kOperandTypeImmediate: case kOperandTypeRegister: case kOperandTypeARMBranchTarget: case kOperandTypeARMSoImm: + case kOperandTypeARMRotImm: case kOperandTypeThumb2SoImm: case kOperandTypeARMSoImm2Part: case kOperandTypeARMPredicate: @@ -78,6 +81,7 @@ EDOperand::EDOperand(const EDDisassembler &disassembler, numMCOperands = 1; break; case kOperandTypeThumb2SoReg: + case kOperandTypeAddrModeImm12: case kOperandTypeARMAddrMode2Offset: case kOperandTypeARMAddrMode3Offset: case kOperandTypeARMAddrMode4: @@ -86,17 +90,22 @@ EDOperand::EDOperand(const EDDisassembler &disassembler, case kOperandTypeThumb2AddrModeImm8: case kOperandTypeThumb2AddrModeImm12: case kOperandTypeThumb2AddrModeImm8s4: + case kOperandTypeThumbAddrModeImmS1: + case kOperandTypeThumbAddrModeImmS2: + case kOperandTypeThumbAddrModeImmS4: case kOperandTypeThumbAddrModeRR: case kOperandTypeThumbAddrModeSP: + case kOperandTypeThumbAddrModePC: numMCOperands = 2; break; case kOperandTypeARMSoReg: + case kOperandTypeLdStSOReg: case kOperandTypeARMAddrMode2: case kOperandTypeARMAddrMode3: case kOperandTypeThumb2AddrModeSoReg: - case kOperandTypeThumbAddrModeS1: - case kOperandTypeThumbAddrModeS2: - case kOperandTypeThumbAddrModeS4: + case kOperandTypeThumbAddrModeRegS1: + case kOperandTypeThumbAddrModeRegS2: + case kOperandTypeThumbAddrModeRegS4: case kOperandTypeARMAddrMode6Offset: numMCOperands = 3; break; @@ -270,9 +279,9 @@ int EDOperand::isMemory() { case kOperandTypeARMAddrMode7: case kOperandTypeARMAddrModePC: case kOperandTypeARMBranchTarget: - case kOperandTypeThumbAddrModeS1: - case kOperandTypeThumbAddrModeS2: - case kOperandTypeThumbAddrModeS4: + case kOperandTypeThumbAddrModeRegS1: + case kOperandTypeThumbAddrModeRegS2: + case kOperandTypeThumbAddrModeRegS4: case kOperandTypeThumbAddrModeRR: case kOperandTypeThumbAddrModeSP: case kOperandTypeThumb2SoImm: diff --git a/contrib/llvm/lib/MC/MCDwarf.cpp b/contrib/llvm/lib/MC/MCDwarf.cpp index 13cb81a..ad86db1 100644 --- a/contrib/llvm/lib/MC/MCDwarf.cpp +++ b/contrib/llvm/lib/MC/MCDwarf.cpp @@ -7,22 +7,21 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/FoldingSet.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDwarf.h" -#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectWriter.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetAsmBackend.h" #include "llvm/Target/TargetAsmInfo.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" using namespace llvm; // Given a special op, return the address skip amount (in units of @@ -30,28 +29,27 @@ using namespace llvm; #define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) // The maximum address skip amount that can be encoded with a special op. -#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) // First special line opcode - leave room for the standard opcodes. // Note: If you want to change this, you'll have to update the // "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). -#define DWARF2_LINE_OPCODE_BASE 13 +#define DWARF2_LINE_OPCODE_BASE 13 // Minimum line offset in a special line info. opcode. This value // was chosen to give a reasonable range of values. -#define DWARF2_LINE_BASE -5 +#define DWARF2_LINE_BASE -5 // Range of line offsets in a special line info. opcode. -# define DWARF2_LINE_RANGE 14 +#define DWARF2_LINE_RANGE 14 // Define the architecture-dependent minimum instruction length (in bytes). // This value should be rather too small than too big. -# define DWARF2_LINE_MIN_INSN_LENGTH 1 +#define DWARF2_LINE_MIN_INSN_LENGTH 1 // Note: when DWARF2_LINE_MIN_INSN_LENGTH == 1 which is the current setting, // this routine is a nop and will be optimized away. -static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) -{ +static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) { if (DWARF2_LINE_MIN_INSN_LENGTH == 1) return AddrDelta; if (AddrDelta % DWARF2_LINE_MIN_INSN_LENGTH != 0) { @@ -174,7 +172,9 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // At this point we want to emit/create the sequence to encode the delta in // line numbers and the increment of the address from the previous Label // and the current Label. - MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + const MCAsmInfo &asmInfo = MCOS->getContext().getAsmInfo(); + MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label, + asmInfo.getPointerSize()); LastLine = it->getLine(); LastLabel = Label; @@ -198,7 +198,9 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // Switch back the the dwarf line section. MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); - MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd); + const MCAsmInfo &asmInfo = MCOS->getContext().getAsmInfo(); + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd, + asmInfo.getPointerSize()); } // @@ -291,7 +293,7 @@ void MCDwarfFileTable::Emit(MCStreamer *MCOS) { const std::vector<const MCSection *> &MCLineSectionOrder = MCOS->getContext().getMCLineSectionOrder(); for (std::vector<const MCSection*>::const_iterator it = - MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; + MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; ++it) { const MCSection *Sec = *it; const MCLineSection *Line = MCLineSections.lookup(Sec); @@ -354,10 +356,7 @@ void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, OS << char(dwarf::DW_LNS_const_add_pc); else { OS << char(dwarf::DW_LNS_advance_pc); - SmallString<32> Tmp; - raw_svector_ostream OSE(Tmp); - MCObjectWriter::EncodeULEB128(AddrDelta, OSE); - OS << OSE.str(); + MCObjectWriter::EncodeULEB128(AddrDelta, OS); } OS << char(dwarf::DW_LNS_extended_op); OS << char(1); @@ -432,25 +431,24 @@ void MCDwarfFile::dump() const { static int getDataAlignmentFactor(MCStreamer &streamer) { MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const MCAsmInfo &asmInfo = context.getAsmInfo(); int size = asmInfo.getPointerSize(); - if (asmInfo.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp) + if (asmInfo.isStackGrowthDirectionUp()) return size; - else - return -size; + else + return -size; } static unsigned getSizeForEncoding(MCStreamer &streamer, unsigned symbolEncoding) { MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); unsigned format = symbolEncoding & 0x0f; switch (format) { default: assert(0 && "Unknown Encoding"); case dwarf::DW_EH_PE_absptr: case dwarf::DW_EH_PE_signed: - return asmInfo.getPointerSize(); + return context.getAsmInfo().getPointerSize(); case dwarf::DW_EH_PE_udata2: case dwarf::DW_EH_PE_sdata2: return 2; @@ -464,13 +462,14 @@ static unsigned getSizeForEncoding(MCStreamer &streamer, } static void EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol, - unsigned symbolEncoding) { + unsigned symbolEncoding, const char *comment = 0) { MCContext &context = streamer.getContext(); const MCAsmInfo &asmInfo = context.getAsmInfo(); const MCExpr *v = asmInfo.getExprForFDESymbol(&symbol, symbolEncoding, streamer); unsigned size = getSizeForEncoding(streamer, symbolEncoding); + if (streamer.isVerboseAsm() && comment) streamer.AddComment(comment); streamer.EmitAbsValue(v, size); } @@ -486,11 +485,11 @@ static void EmitPersonality(MCStreamer &streamer, const MCSymbol &symbol, } static const MachineLocation TranslateMachineLocation( - const TargetAsmInfo &AsmInfo, + const TargetAsmInfo &TAI, const MachineLocation &Loc) { unsigned Reg = Loc.getReg() == MachineLocation::VirtualFP ? MachineLocation::VirtualFP : - unsigned(AsmInfo.getDwarfRegNum(Loc.getReg(), true)); + unsigned(TAI.getDwarfRegNum(Loc.getReg(), true)); const MachineLocation &NewLoc = Loc.isReg() ? MachineLocation(Reg) : MachineLocation(Reg, Loc.getOffset()); return NewLoc; @@ -503,13 +502,18 @@ namespace { bool UsingCFI; bool IsEH; const MCSymbol *SectionStart; - public: FrameEmitterImpl(bool usingCFI, bool isEH, const MCSymbol *sectionStart) : CFAOffset(0), CIENum(0), UsingCFI(usingCFI), IsEH(isEH), SectionStart(sectionStart) { } + /// EmitCompactUnwind - Emit the unwind information in a compact way. If + /// we're successful, return 'true'. Otherwise, return 'false' and it will + /// emit the normal CIE and FDE. + bool EmitCompactUnwind(MCStreamer &streamer, + const MCDwarfFrameInfo &frame); + const MCSymbol &EmitCIE(MCStreamer &streamer, const MCSymbol *personality, unsigned personalityEncoding, @@ -524,11 +528,46 @@ namespace { void EmitCFIInstruction(MCStreamer &Streamer, const MCCFIInstruction &Instr); }; + +} // end anonymous namespace + +static void EmitEncodingByte(MCStreamer &Streamer, unsigned Encoding, + StringRef Prefix) { + if (Streamer.isVerboseAsm()) { + const char *EncStr = 0; + switch (Encoding) { + default: EncStr = "<unknown encoding>"; + case dwarf::DW_EH_PE_absptr: EncStr = "absptr"; + case dwarf::DW_EH_PE_omit: EncStr = "omit"; + case dwarf::DW_EH_PE_pcrel: EncStr = "pcrel"; + case dwarf::DW_EH_PE_udata4: EncStr = "udata4"; + case dwarf::DW_EH_PE_udata8: EncStr = "udata8"; + case dwarf::DW_EH_PE_sdata4: EncStr = "sdata4"; + case dwarf::DW_EH_PE_sdata8: EncStr = "sdata8"; + case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata4: EncStr = "pcrel udata4"; + case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata4: EncStr = "pcrel sdata4"; + case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata8: EncStr = "pcrel udata8"; + case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata8: EncStr = "pcrel sdata8"; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata4: + EncStr = "indirect pcrel udata4"; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata4: + EncStr = "indirect pcrel sdata4"; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata8: + EncStr = "indirect pcrel udata8"; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata8: + EncStr = "indirect pcrel sdata8"; + } + + Streamer.AddComment(Twine(Prefix) + " = " + EncStr); + } + + Streamer.EmitIntValue(Encoding, 1); } void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, const MCCFIInstruction &Instr) { int dataAlignmentFactor = getDataAlignmentFactor(Streamer); + bool VerboseAsm = Streamer.isVerboseAsm(); switch (Instr.getOperation()) { case MCCFIInstruction::Move: @@ -540,9 +579,13 @@ void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, // If advancing cfa. if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { if (Src.getReg() == MachineLocation::VirtualFP) { + if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_offset"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); } else { + if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + + Twine(Src.getReg())); Streamer.EmitULEB128IntValue(Src.getReg()); } @@ -551,47 +594,62 @@ void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, else CFAOffset = -Src.getOffset(); + if (VerboseAsm) Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); Streamer.EmitULEB128IntValue(CFAOffset); return; } if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { assert(Dst.isReg() && "Machine move not supported yet."); + if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_register"); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Dst.getReg())); Streamer.EmitULEB128IntValue(Dst.getReg()); return; } unsigned Reg = Src.getReg(); - int Offset = Dst.getOffset(); if (IsRelative) Offset -= CFAOffset; Offset = Offset / dataAlignmentFactor; if (Offset < 0) { + if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended_sf"); Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitSLEB128IntValue(Offset); } else if (Reg < 64) { + if (VerboseAsm) Streamer.AddComment(Twine("DW_CFA_offset + Reg(") + + Twine(Reg) + ")"); Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitULEB128IntValue(Offset); } else { + if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended"); Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); Streamer.EmitULEB128IntValue(Offset); } return; } case MCCFIInstruction::Remember: + if (VerboseAsm) Streamer.AddComment("DW_CFA_remember_state"); Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); return; case MCCFIInstruction::Restore: + if (VerboseAsm) Streamer.AddComment("DW_CFA_restore_state"); Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); return; case MCCFIInstruction::SameValue: { unsigned Reg = Instr.getDestination().getReg(); + if (VerboseAsm) Streamer.AddComment("DW_CFA_same_value"); Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); return; } @@ -614,6 +672,7 @@ void FrameEmitterImpl::EmitCFIInstructions(MCStreamer &streamer, if (BaseLabel && Label) { MCSymbol *ThisSym = Label; if (ThisSym != BaseLabel) { + if (streamer.isVerboseAsm()) streamer.AddComment("DW_CFA_advance_loc4"); streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym); BaseLabel = ThisSym; } @@ -623,40 +682,128 @@ void FrameEmitterImpl::EmitCFIInstructions(MCStreamer &streamer, } } +/// EmitCompactUnwind - Emit the unwind information in a compact way. If we're +/// successful, return 'true'. Otherwise, return 'false' and it will emit the +/// normal CIE and FDE. +bool FrameEmitterImpl::EmitCompactUnwind(MCStreamer &Streamer, + const MCDwarfFrameInfo &Frame) { +#if 1 + return false; +#else + MCContext &Context = Streamer.getContext(); + const TargetAsmInfo &TAI = Context.getTargetAsmInfo(); + bool VerboseAsm = Streamer.isVerboseAsm(); + + // range-start range-length compact-unwind-enc personality-func lsda + // _foo LfooEnd-_foo 0x00000023 0 0 + // _bar LbarEnd-_bar 0x00000025 __gxx_personality except_tab1 + // + // .section __LD,__compact_unwind,regular,debug + // + // # compact unwind for _foo + // .quad _foo + // .set L1,LfooEnd-_foo + // .long L1 + // .long 0x01010001 + // .quad 0 + // .quad 0 + // + // # compact unwind for _bar + // .quad _bar + // .set L2,LbarEnd-_bar + // .long L2 + // .long 0x01020011 + // .quad __gxx_personality + // .quad except_tab1 + + uint32_t Encoding = + TAI.getCompactUnwindEncoding(Frame.Instructions, + getDataAlignmentFactor(Streamer), IsEH); + if (!Encoding) return false; + + // The encoding needs to know we have an LSDA. + if (Frame.Lsda) + Encoding |= 0x40000000; + + Streamer.SwitchSection(TAI.getCompactUnwindSection()); + + // Range Start + unsigned FDEEncoding = TAI.getFDEEncoding(UsingCFI); + unsigned Size = getSizeForEncoding(Streamer, FDEEncoding); + if (VerboseAsm) Streamer.AddComment("Range Start"); + Streamer.EmitSymbolValue(Frame.Function, Size); + + // Range Length + const MCExpr *Range = MakeStartMinusEndExpr(Streamer, *Frame.Begin, + *Frame.End, 0); + if (VerboseAsm) Streamer.AddComment("Range Length"); + Streamer.EmitAbsValue(Range, 4); + + // Compact Encoding + Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_udata4); + if (VerboseAsm) Streamer.AddComment(Twine("Compact Unwind Encoding: 0x") + + Twine(llvm::utohexstr(Encoding))); + Streamer.EmitIntValue(Encoding, Size); + + // Personality Function + Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_absptr); + if (VerboseAsm) Streamer.AddComment("Personality Function"); + if (Frame.Personality) + Streamer.EmitSymbolValue(Frame.Personality, Size); + else + Streamer.EmitIntValue(0, Size); // No personality fn + + // LSDA + Size = getSizeForEncoding(Streamer, Frame.LsdaEncoding); + if (VerboseAsm) Streamer.AddComment("LSDA"); + if (Frame.Lsda) + Streamer.EmitSymbolValue(Frame.Lsda, Size); + else + Streamer.EmitIntValue(0, Size); // No LSDA + + return true; +#endif +} + const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, const MCSymbol *personality, unsigned personalityEncoding, const MCSymbol *lsda, unsigned lsdaEncoding) { MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const TargetAsmInfo &TAI = context.getTargetAsmInfo(); + bool verboseAsm = streamer.isVerboseAsm(); MCSymbol *sectionStart; - if (asmInfo.isFunctionEHFrameSymbolPrivate() || !IsEH) + if (TAI.isFunctionEHFrameSymbolPrivate() || !IsEH) sectionStart = context.CreateTempSymbol(); else sectionStart = context.GetOrCreateSymbol(Twine("EH_frame") + Twine(CIENum)); + streamer.EmitLabel(sectionStart); CIENum++; - MCSymbol *sectionEnd = streamer.getContext().CreateTempSymbol(); + MCSymbol *sectionEnd = context.CreateTempSymbol(); // Length const MCExpr *Length = MakeStartMinusEndExpr(streamer, *sectionStart, *sectionEnd, 4); - streamer.EmitLabel(sectionStart); + if (verboseAsm) streamer.AddComment("CIE Length"); streamer.EmitAbsValue(Length, 4); // CIE ID unsigned CIE_ID = IsEH ? 0 : -1; + if (verboseAsm) streamer.AddComment("CIE ID Tag"); streamer.EmitIntValue(CIE_ID, 4); // Version + if (verboseAsm) streamer.AddComment("DW_CIE_VERSION"); streamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1); // Augmentation String SmallString<8> Augmentation; if (IsEH) { + if (verboseAsm) streamer.AddComment("CIE Augmentation"); Augmentation += "z"; if (personality) Augmentation += "P"; @@ -668,13 +815,16 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, streamer.EmitIntValue(0, 1); // Code Alignment Factor + if (verboseAsm) streamer.AddComment("CIE Code Alignment Factor"); streamer.EmitULEB128IntValue(1); // Data Alignment Factor + if (verboseAsm) streamer.AddComment("CIE Data Alignment Factor"); streamer.EmitSLEB128IntValue(getDataAlignmentFactor(streamer)); // Return Address Register - streamer.EmitULEB128IntValue(asmInfo.getDwarfRARegNum(true)); + if (verboseAsm) streamer.AddComment("CIE Return Address Column"); + streamer.EmitULEB128IntValue(TAI.getDwarfRARegNum(true)); // Augmentation Data Length (optional) @@ -691,32 +841,38 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, // Encoding of the FDE pointers augmentationLength += 1; + if (verboseAsm) streamer.AddComment("Augmentation Size"); streamer.EmitULEB128IntValue(augmentationLength); // Augmentation Data (optional) if (personality) { // Personality Encoding - streamer.EmitIntValue(personalityEncoding, 1); + EmitEncodingByte(streamer, personalityEncoding, + "Personality Encoding"); // Personality + if (verboseAsm) streamer.AddComment("Personality"); EmitPersonality(streamer, *personality, personalityEncoding); } + if (lsda) - streamer.EmitIntValue(lsdaEncoding, 1); // LSDA Encoding + EmitEncodingByte(streamer, lsdaEncoding, "LSDA Encoding"); + // Encoding of the FDE pointers - streamer.EmitIntValue(asmInfo.getFDEEncoding(UsingCFI), 1); + EmitEncodingByte(streamer, TAI.getFDEEncoding(UsingCFI), + "FDE Encoding"); } // Initial Instructions - const std::vector<MachineMove> Moves = asmInfo.getInitialFrameState(); + const std::vector<MachineMove> &Moves = TAI.getInitialFrameState(); std::vector<MCCFIInstruction> Instructions; for (int i = 0, n = Moves.size(); i != n; ++i) { MCSymbol *Label = Moves[i].getLabel(); const MachineLocation &Dst = - TranslateMachineLocation(asmInfo, Moves[i].getDestination()); + TranslateMachineLocation(TAI, Moves[i].getDestination()); const MachineLocation &Src = - TranslateMachineLocation(asmInfo, Moves[i].getSource()); + TranslateMachineLocation(TAI, Moves[i].getSource()); MCCFIInstruction Inst(Label, Dst, Src); Instructions.push_back(Inst); } @@ -724,7 +880,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, EmitCFIInstructions(streamer, Instructions, NULL); // Padding - streamer.EmitValueToAlignment(IsEH ? 4 : asmInfo.getPointerSize()); + streamer.EmitValueToAlignment(IsEH + ? 4 : context.getAsmInfo().getPointerSize()); streamer.EmitLabel(sectionEnd); return *sectionStart; @@ -736,17 +893,19 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, MCContext &context = streamer.getContext(); MCSymbol *fdeStart = context.CreateTempSymbol(); MCSymbol *fdeEnd = context.CreateTempSymbol(); - const TargetAsmInfo &TAsmInfo = context.getTargetAsmInfo(); + const TargetAsmInfo &TAI = context.getTargetAsmInfo(); + bool verboseAsm = streamer.isVerboseAsm(); - if (!TAsmInfo.isFunctionEHFrameSymbolPrivate() && IsEH) { - MCSymbol *EHSym = context.GetOrCreateSymbol( - frame.Function->getName() + Twine(".eh")); + if (!TAI.isFunctionEHFrameSymbolPrivate() && IsEH) { + MCSymbol *EHSym = + context.GetOrCreateSymbol(frame.Function->getName() + Twine(".eh")); streamer.EmitEHSymAttributes(frame.Function, EHSym); streamer.EmitLabel(EHSym); } // Length const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0); + if (verboseAsm) streamer.AddComment("FDE Length"); streamer.EmitAbsValue(Length, 4); streamer.EmitLabel(fdeStart); @@ -756,6 +915,7 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, if (IsEH) { const MCExpr *offset = MakeStartMinusEndExpr(streamer, cieStart, *fdeStart, 0); + if (verboseAsm) streamer.AddComment("FDE CIE Offset"); streamer.EmitAbsValue(offset, 4); } else if (!asmInfo.doesDwarfRequireRelocationForSectionOffset()) { const MCExpr *offset = MakeStartMinusEndExpr(streamer, *SectionStart, @@ -764,18 +924,20 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, } else { streamer.EmitSymbolValue(&cieStart, 4); } - unsigned fdeEncoding = TAsmInfo.getFDEEncoding(UsingCFI); + + unsigned fdeEncoding = TAI.getFDEEncoding(UsingCFI); unsigned size = getSizeForEncoding(streamer, fdeEncoding); // PC Begin unsigned PCBeginEncoding = IsEH ? fdeEncoding : (unsigned)dwarf::DW_EH_PE_absptr; unsigned PCBeginSize = getSizeForEncoding(streamer, PCBeginEncoding); - EmitSymbol(streamer, *frame.Begin, PCBeginEncoding); + EmitSymbol(streamer, *frame.Begin, PCBeginEncoding, "FDE initial location"); // PC Range const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, *frame.End, 0); + if (verboseAsm) streamer.AddComment("FDE address range"); streamer.EmitAbsValue(Range, size); if (IsEH) { @@ -785,11 +947,13 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, if (frame.Lsda) augmentationLength += getSizeForEncoding(streamer, frame.LsdaEncoding); + if (verboseAsm) streamer.AddComment("Augmentation size"); streamer.EmitULEB128IntValue(augmentationLength); // Augmentation Data if (frame.Lsda) - EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding); + EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding, + "Language Specific Data Area"); } // Call Frame Instructions @@ -843,39 +1007,47 @@ namespace llvm { }; } -void MCDwarfFrameEmitter::Emit(MCStreamer &streamer, - bool usingCFI, - bool isEH) { - MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); - const MCSection §ion = isEH ? - *asmInfo.getEHFrameSection() : *asmInfo.getDwarfFrameSection(); - streamer.SwitchSection(§ion); - MCSymbol *SectionStart = context.CreateTempSymbol(); - streamer.EmitLabel(SectionStart); - - MCSymbol *fdeEnd = NULL; +void MCDwarfFrameEmitter::Emit(MCStreamer &Streamer, + bool UsingCFI, + bool IsEH) { + MCContext &Context = Streamer.getContext(); + const TargetAsmInfo &TAI = Context.getTargetAsmInfo(); + const MCSection &Section = IsEH ? *TAI.getEHFrameSection() : + *TAI.getDwarfFrameSection(); + Streamer.SwitchSection(&Section); + MCSymbol *SectionStart = Context.CreateTempSymbol(); + Streamer.EmitLabel(SectionStart); + + MCSymbol *FDEEnd = NULL; DenseMap<CIEKey, const MCSymbol*> CIEStarts; - FrameEmitterImpl Emitter(usingCFI, isEH, SectionStart); + FrameEmitterImpl Emitter(UsingCFI, IsEH, SectionStart); const MCSymbol *DummyDebugKey = NULL; - for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) { - const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i); - CIEKey key(frame.Personality, frame.PersonalityEncoding, - frame.LsdaEncoding); - const MCSymbol *&cieStart = isEH ? CIEStarts[key] : DummyDebugKey; - if (!cieStart) - cieStart = &Emitter.EmitCIE(streamer, frame.Personality, - frame.PersonalityEncoding, frame.Lsda, - frame.LsdaEncoding); - fdeEnd = Emitter.EmitFDE(streamer, *cieStart, frame); + for (unsigned i = 0, n = Streamer.getNumFrameInfos(); i < n; ++i) { + const MCDwarfFrameInfo &Frame = Streamer.getFrameInfo(i); + if (IsEH && TAI.getCompactUnwindSection() && + Emitter.EmitCompactUnwind(Streamer, Frame)) { + FDEEnd = NULL; + continue; + } + + CIEKey Key(Frame.Personality, Frame.PersonalityEncoding, + Frame.LsdaEncoding); + const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey; + if (!CIEStart) + CIEStart = &Emitter.EmitCIE(Streamer, Frame.Personality, + Frame.PersonalityEncoding, Frame.Lsda, + Frame.LsdaEncoding); + + FDEEnd = Emitter.EmitFDE(Streamer, *CIEStart, Frame); + if (i != n - 1) - streamer.EmitLabel(fdeEnd); + Streamer.EmitLabel(FDEEnd); } - streamer.EmitValueToAlignment(asmInfo.getPointerSize()); - if (fdeEnd) - streamer.EmitLabel(fdeEnd); + Streamer.EmitValueToAlignment(Context.getAsmInfo().getPointerSize()); + if (FDEEnd) + Streamer.EmitLabel(FDEEnd); } void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &Streamer, diff --git a/contrib/llvm/lib/MC/MCELFStreamer.cpp b/contrib/llvm/lib/MC/MCELFStreamer.cpp index bbb2789..49340ed 100644 --- a/contrib/llvm/lib/MC/MCELFStreamer.cpp +++ b/contrib/llvm/lib/MC/MCELFStreamer.cpp @@ -26,7 +26,6 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" -#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; diff --git a/contrib/llvm/lib/MC/MCELFStreamer.h b/contrib/llvm/lib/MC/MCELFStreamer.h index db34d58..855e7e9 100644 --- a/contrib/llvm/lib/MC/MCELFStreamer.h +++ b/contrib/llvm/lib/MC/MCELFStreamer.h @@ -138,137 +138,3 @@ private: } // end llvm namespace #endif -//===- lib/MC/MCELFStreamer.h - ELF Object Output -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file assembles .s files and emits ELF .o object files. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MC_MCELFSTREAMER_H -#define LLVM_MC_MCELFSTREAMER_H - -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/MC/MCAssembler.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCObjectStreamer.h" -#include "llvm/MC/MCSectionELF.h" - -namespace llvm { - -class MCELFStreamer : public MCObjectStreamer { -public: - MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *Emitter) - : MCObjectStreamer(Context, TAB, OS, Emitter) {} - - ~MCELFStreamer() {} - - /// @name MCStreamer Interface - /// @{ - - virtual void InitSections(); - virtual void ChangeSection(const MCSection *Section); - virtual void EmitLabel(MCSymbol *Symbol); - virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); - virtual void EmitThumbFunc(MCSymbol *Func); - virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); - virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); - virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); - virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - assert(0 && "ELF doesn't support this directive"); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolStorageClass(int StorageClass) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolType(int Type) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EndCOFFSymbolDef() { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - SD.setSize(Value); - } - - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); - - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, - unsigned Size = 0, unsigned ByteAlignment = 0) { - assert(0 && "ELF doesn't support this directive"); - } - virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment = 0) { - assert(0 && "ELF doesn't support this directive"); - } - virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, - unsigned ValueSize = 1, - unsigned MaxBytesToEmit = 0); - virtual void EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit = 0); - - virtual void EmitFileDirective(StringRef Filename); - - virtual void Finish(); - -private: - virtual void EmitInstToFragment(const MCInst &Inst); - virtual void EmitInstToData(const MCInst &Inst); - - void fixSymbolsInTLSFixups(const MCExpr *expr); - - struct LocalCommon { - MCSymbolData *SD; - uint64_t Size; - unsigned ByteAlignment; - }; - std::vector<LocalCommon> LocalCommons; - - SmallPtrSet<MCSymbol *, 16> BindingExplicitlySet; - /// @} - void SetSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind) { - SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); - } - - void SetSectionData() { - SetSection(".data", ELF::SHT_PROGBITS, - ELF::SHF_WRITE |ELF::SHF_ALLOC, - SectionKind::getDataRel()); - EmitCodeAlignment(4, 0); - } - void SetSectionText() { - SetSection(".text", ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | - ELF::SHF_ALLOC, SectionKind::getText()); - EmitCodeAlignment(4, 0); - } - void SetSectionBss() { - SetSection(".bss", ELF::SHT_NOBITS, - ELF::SHF_WRITE | - ELF::SHF_ALLOC, SectionKind::getBSS()); - EmitCodeAlignment(4, 0); - } -}; - -} // end llvm namespace - -#endif diff --git a/contrib/llvm/lib/MC/MCLoggingStreamer.cpp b/contrib/llvm/lib/MC/MCLoggingStreamer.cpp index 46ea9b8..309752e 100644 --- a/contrib/llvm/lib/MC/MCLoggingStreamer.cpp +++ b/contrib/llvm/lib/MC/MCLoggingStreamer.cpp @@ -85,9 +85,11 @@ public: virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, - const MCSymbol *Label) { + const MCSymbol *Label, + unsigned PointerSize) { LogCall("EmitDwarfAdvanceLineAddr"); - return Child->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + return Child->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label, + PointerSize); } virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp index 12aeb4f..1b21249 100644 --- a/contrib/llvm/lib/MC/MCMachOStreamer.cpp +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -24,7 +24,6 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" -#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; diff --git a/contrib/llvm/lib/MC/MCNullStreamer.cpp b/contrib/llvm/lib/MC/MCNullStreamer.cpp index f38b822..9577af0 100644 --- a/contrib/llvm/lib/MC/MCNullStreamer.cpp +++ b/contrib/llvm/lib/MC/MCNullStreamer.cpp @@ -44,7 +44,8 @@ namespace { virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, - const MCSymbol *Label) {} + const MCSymbol *Label, + unsigned PointerSize) {} virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} diff --git a/contrib/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm/lib/MC/MCObjectStreamer.cpp index e230c53..8635aac 100644 --- a/contrib/llvm/lib/MC/MCObjectStreamer.cpp +++ b/contrib/llvm/lib/MC/MCObjectStreamer.cpp @@ -18,7 +18,6 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetAsmBackend.h" -#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -197,9 +196,9 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, - const MCSymbol *Label) { + const MCSymbol *Label, + unsigned PointerSize) { if (!LastLabel) { - int PointerSize = getContext().getTargetAsmInfo().getPointerSize(); EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); return; } diff --git a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp index 4f55cea..0c181f3 100644 --- a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCDwarf.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" @@ -84,6 +85,7 @@ private: AsmLexer Lexer; MCContext &Ctx; MCStreamer &Out; + const MCAsmInfo &MAI; SourceMgr &SrcMgr; MCAsmParserExtension *GenericParser; MCAsmParserExtension *PlatformParser; @@ -135,7 +137,7 @@ public: virtual MCContext &getContext() { return Ctx; } virtual MCStreamer &getStreamer() { return Out; } - virtual bool Warning(SMLoc L, const Twine &Meg); + virtual bool Warning(SMLoc L, const Twine &Msg); virtual bool Error(SMLoc L, const Twine &Msg); const AsmToken &Lex(); @@ -160,8 +162,9 @@ private: void HandleMacroExit(); void PrintMacroInstantiations(); - void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type) const { - SrcMgr.PrintMessage(Loc, Msg, Type); + void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type, + bool ShowLine = true) const { + SrcMgr.PrintMessage(Loc, Msg, Type, ShowLine); } /// EnterIncludeFile - Enter the specified file. This returns true on failure. @@ -337,7 +340,7 @@ enum { DEFAULT_ADDRSPACE = 0 }; AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, const MCAsmInfo &_MAI) - : Lexer(_MAI), Ctx(_Ctx), Out(_Out), SrcMgr(_SM), + : Lexer(_MAI), Ctx(_Ctx), Out(_Out), MAI(_MAI), SrcMgr(_SM), GenericParser(new GenericAsmParser), PlatformParser(0), CurBuffer(0), MacrosEnabled(true) { Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); @@ -466,6 +469,29 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { TokError("unassigned file number: " + Twine(i) + " for .file directives"); } + // Check to see that all assembler local symbols were actually defined. + // Targets that don't do subsections via symbols may not want this, though, + // so conservatively exclude them. Only do this if we're finalizing, though, + // as otherwise we won't necessarilly have seen everything yet. + if (!NoFinalize && MAI.hasSubsectionsViaSymbols()) { + const MCContext::SymbolTable &Symbols = getContext().getSymbols(); + for (MCContext::SymbolTable::const_iterator i = Symbols.begin(), + e = Symbols.end(); + i != e; ++i) { + MCSymbol *Sym = i->getValue(); + // Variable symbols may not be marked as defined, so check those + // explicitly. If we know it's a variable, we have a definition for + // the purposes of this check. + if (Sym->isTemporary() && !Sym->isVariable() && !Sym->isDefined()) + // FIXME: We would really like to refer back to where the symbol was + // first referenced for a source location. We need to add something + // to track that. Currently, we just point to the end of the file. + PrintMessage(getLexer().getLoc(), "assembler local symbol '" + + Sym->getName() + "' not defined", "error", false); + } + } + + // Finalize the output stream if there are no errors and if the client wants // us to. if (!HadError && !NoFinalize) @@ -1121,7 +1147,7 @@ bool AsmParser::ParseStatement() { if (IDVal == ".weak_def_can_be_hidden") return ParseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate); - if (IDVal == ".comm") + if (IDVal == ".comm" || IDVal == ".common") return ParseDirectiveComm(/*IsLocal=*/false); if (IDVal == ".lcomm") return ParseDirectiveComm(/*IsLocal=*/true); @@ -1168,7 +1194,7 @@ bool AsmParser::ParseStatement() { for (unsigned i = 0; i != ParsedOperands.size(); ++i) { if (i != 0) OS << ", "; - ParsedOperands[i]->dump(OS); + ParsedOperands[i]->print(OS); } OS << "]"; @@ -1587,13 +1613,18 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) { for (;;) { const MCExpr *Value; + SMLoc ExprLoc = getLexer().getLoc(); if (ParseExpression(Value)) return true; // Special case constant expressions to match code generator. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) - getStreamer().EmitIntValue(MCE->getValue(), Size, DEFAULT_ADDRSPACE); - else + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { + assert(Size <= 8 && "Invalid size"); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) + return Error(ExprLoc, "literal value out of range for directive"); + getStreamer().EmitIntValue(IntValue, Size, DEFAULT_ADDRSPACE); + } else getStreamer().EmitValue(Value, Size, DEFAULT_ADDRSPACE); if (getLexer().is(AsmToken::EndOfStatement)) diff --git a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp index 64f6355..66ad384 100644 --- a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -401,14 +401,14 @@ bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { SMLoc startLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Percent)) { - const TargetAsmInfo &asmInfo = getContext().getTargetAsmInfo(); + const TargetAsmInfo &TAI = getContext().getTargetAsmInfo(); SMLoc endLoc; unsigned LLVMRegNo; if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) return true; // Check that this is a non-volatile register. - const unsigned *NVRegs = asmInfo.getCalleeSavedRegs(); + const unsigned *NVRegs = TAI.getCalleeSavedRegs(); unsigned i; for (i = 0; NVRegs[i] != 0; ++i) if (NVRegs[i] == LLVMRegNo) @@ -416,7 +416,7 @@ bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { if (NVRegs[i] == 0) return Error(startLoc, "expected non-volatile register"); - int SEHRegNo = asmInfo.getSEHRegNum(LLVMRegNo); + int SEHRegNo = TAI.getSEHRegNum(LLVMRegNo); if (SEHRegNo < 0) return Error(startLoc,"register can't be represented in SEH unwind info"); RegNo = SEHRegNo; diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp index 70295ef..4030e41 100644 --- a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -12,6 +12,8 @@ #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" #include "llvm/Target/TargetAsmParser.h" using namespace llvm; @@ -41,4 +43,6 @@ bool MCAsmParser::ParseExpression(const MCExpr *&Res) { return ParseExpression(Res, L); } - +void MCParsedAsmOperand::dump() const { + dbgs() << " " << *this; +} diff --git a/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp index 8d43c21..512f6b0 100644 --- a/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp @@ -10,8 +10,8 @@ #include "llvm/Target/TargetAsmParser.h" using namespace llvm; -TargetAsmParser::TargetAsmParser(const Target &T) - : TheTarget(T), AvailableFeatures(0) +TargetAsmParser::TargetAsmParser() + : AvailableFeatures(0) { } diff --git a/contrib/llvm/lib/MC/MCStreamer.cpp b/contrib/llvm/lib/MC/MCStreamer.cpp index ae3ed0f..6e96b78 100644 --- a/contrib/llvm/lib/MC/MCStreamer.cpp +++ b/contrib/llvm/lib/MC/MCStreamer.cpp @@ -15,7 +15,6 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetAsmInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include <cstdlib> @@ -81,7 +80,7 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && "Invalid size"); char buf[8]; - const bool isLittleEndian = Context.getTargetAsmInfo().isLittleEndian(); + const bool isLittleEndian = Context.getAsmInfo().isLittleEndian(); for (unsigned i = 0; i != Size; ++i) { unsigned index = isLittleEndian ? i : (Size - i - 1); buf[i] = uint8_t(Value >> (index * 8)); diff --git a/contrib/llvm/lib/MC/MCSubtargetInfo.cpp b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp new file mode 100644 index 0000000..86dc108 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp @@ -0,0 +1,96 @@ +//===-- MCSubtargetInfo.cpp - Subtarget Information -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; + +void +MCSubtargetInfo::InitMCSubtargetInfo(StringRef TT, StringRef CPU, StringRef FS, + const SubtargetFeatureKV *PF, + const SubtargetFeatureKV *PD, + const SubtargetInfoKV *PI, + const InstrStage *IS, + const unsigned *OC, + const unsigned *FP, + unsigned NF, unsigned NP) { + TargetTriple = TT; + ProcFeatures = PF; + ProcDesc = PD; + ProcItins = PI; + Stages = IS; + OperandCycles = OC; + ForwardingPathes = FP; + NumFeatures = NF; + NumProcs = NP; + + SubtargetFeatures Features(FS); + FeatureBits = Features.getFeatureBits(CPU, ProcDesc, NumProcs, + ProcFeatures, NumFeatures); +} + + +/// ReInitMCSubtargetInfo - Change CPU (and optionally supplemented with +/// feature string) and recompute feature bits. +uint64_t MCSubtargetInfo::ReInitMCSubtargetInfo(StringRef CPU, StringRef FS) { + SubtargetFeatures Features(FS); + FeatureBits = Features.getFeatureBits(CPU, ProcDesc, NumProcs, + ProcFeatures, NumFeatures); + return FeatureBits; +} + +/// ToggleFeature - Toggle a feature and returns the re-computed feature +/// bits. This version does not change the implied bits. +uint64_t MCSubtargetInfo::ToggleFeature(uint64_t FB) { + FeatureBits ^= FB; + return FeatureBits; +} + +/// ToggleFeature - Toggle a feature and returns the re-computed feature +/// bits. This version will also change all implied bits. +uint64_t MCSubtargetInfo::ToggleFeature(StringRef FS) { + SubtargetFeatures Features; + FeatureBits = Features.ToggleFeature(FeatureBits, FS, + ProcFeatures, NumFeatures); + return FeatureBits; +} + + +InstrItineraryData +MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const { + assert(ProcItins && "Instruction itineraries information not available!"); + +#ifndef NDEBUG + for (size_t i = 1; i < NumProcs; i++) { + assert(strcmp(ProcItins[i - 1].Key, ProcItins[i].Key) < 0 && + "Itineraries table is not sorted"); + } +#endif + + // Find entry + SubtargetInfoKV KV; + KV.Key = CPU.data(); + const SubtargetInfoKV *Found = + std::lower_bound(ProcItins, ProcItins+NumProcs, KV); + if (Found == ProcItins+NumProcs || StringRef(Found->Key) != CPU) { + errs() << "'" << CPU + << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + return InstrItineraryData(); + } + + return InstrItineraryData(Stages, OperandCycles, ForwardingPathes, + (InstrItinerary *)Found->Value); +} diff --git a/contrib/llvm/lib/MC/MCWin64EH.cpp b/contrib/llvm/lib/MC/MCWin64EH.cpp index 9453f5c..e698384 100644 --- a/contrib/llvm/lib/MC/MCWin64EH.cpp +++ b/contrib/llvm/lib/MC/MCWin64EH.cpp @@ -225,9 +225,9 @@ void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, // Switch sections (the static function above is meant to be called from // here and from Emit(). MCContext &context = streamer.getContext(); - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const TargetAsmInfo &TAI = context.getTargetAsmInfo(); const MCSection *xdataSect = - asmInfo.getWin64EHTableSection(GetSectionSuffix(info->Function)); + TAI.getWin64EHTableSection(GetSectionSuffix(info->Function)); streamer.SwitchSection(xdataSect); llvm::EmitUnwindInfo(streamer, info); @@ -236,11 +236,11 @@ void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) { MCContext &context = streamer.getContext(); // Emit the unwind info structs first. - const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const TargetAsmInfo &TAI = context.getTargetAsmInfo(); for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); const MCSection *xdataSect = - asmInfo.getWin64EHTableSection(GetSectionSuffix(info.Function)); + TAI.getWin64EHTableSection(GetSectionSuffix(info.Function)); streamer.SwitchSection(xdataSect); llvm::EmitUnwindInfo(streamer, &info); } @@ -248,7 +248,7 @@ void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) { for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); const MCSection *pdataSect = - asmInfo.getWin64EHFuncTableSection(GetSectionSuffix(info.Function)); + TAI.getWin64EHFuncTableSection(GetSectionSuffix(info.Function)); streamer.SwitchSection(pdataSect); EmitRuntimeFunction(streamer, &info); } diff --git a/contrib/llvm/lib/MC/MachObjectWriter.cpp b/contrib/llvm/lib/MC/MachObjectWriter.cpp index f049b1c..69efe23 100644 --- a/contrib/llvm/lib/MC/MachObjectWriter.cpp +++ b/contrib/llvm/lib/MC/MachObjectWriter.cpp @@ -23,34 +23,12 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetAsmBackend.h" -// FIXME: Gross. -#include "../Target/ARM/ARMFixupKinds.h" -#include "../Target/X86/X86FixupKinds.h" - #include <vector> using namespace llvm; using namespace llvm::object; -// FIXME: this has been copied from (or to) X86AsmBackend.cpp -static unsigned getFixupKindLog2Size(unsigned Kind) { - switch (Kind) { - default: - llvm_unreachable("invalid fixup kind!"); - case FK_PCRel_1: - case FK_Data_1: return 0; - case FK_PCRel_2: - case FK_Data_2: return 1; - case FK_PCRel_4: - // FIXME: Remove these!!! - case X86::reloc_riprel_4byte: - case X86::reloc_riprel_4byte_movq_load: - case X86::reloc_signed_4byte: - case FK_Data_4: return 2; - case FK_Data_8: return 3; - } -} - -static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { +bool MachObjectWriter:: +doesSymbolRequireExternRelocation(const MCSymbolData *SD) { // Undefined symbols are always extern. if (SD->Symbol->isUndefined()) return true; @@ -64,1557 +42,740 @@ static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { return false; } -namespace { - -class MachObjectWriter : public MCObjectWriter { - /// MachSymbolData - Helper struct for containing some precomputed information - /// on symbols. - struct MachSymbolData { - MCSymbolData *SymbolData; - uint64_t StringIndex; - uint8_t SectionIndex; +bool MachObjectWriter:: +MachSymbolData::operator<(const MachSymbolData &RHS) const { + return SymbolData->getSymbol().getName() < + RHS.SymbolData->getSymbol().getName(); +} - // Support lexicographic sorting. - bool operator<(const MachSymbolData &RHS) const { - return SymbolData->getSymbol().getName() < - RHS.SymbolData->getSymbol().getName(); - } - }; +bool MachObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo( + (MCFixupKind) Kind); - /// The target specific Mach-O writer instance. - llvm::OwningPtr<MCMachObjectTargetWriter> TargetObjectWriter; + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; +} - /// @name Relocation Data - /// @{ +uint64_t MachObjectWriter::getFragmentAddress(const MCFragment *Fragment, + const MCAsmLayout &Layout) const { + return getSectionAddress(Fragment->getParent()) + + Layout.getFragmentOffset(Fragment); +} - llvm::DenseMap<const MCSectionData*, - std::vector<macho::RelocationEntry> > Relocations; - llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase; +uint64_t MachObjectWriter::getSymbolAddress(const MCSymbolData* SD, + const MCAsmLayout &Layout) const { + const MCSymbol &S = SD->getSymbol(); + + // If this is a variable, then recursively evaluate now. + if (S.isVariable()) { + MCValue Target; + if (!S.getVariableValue()->EvaluateAsRelocatable(Target, Layout)) + report_fatal_error("unable to evaluate offset for variable '" + + S.getName() + "'"); + + // Verify that any used symbols are defined. + if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined()) + report_fatal_error("unable to evaluate offset to undefined symbol '" + + Target.getSymA()->getSymbol().getName() + "'"); + if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined()) + report_fatal_error("unable to evaluate offset to undefined symbol '" + + Target.getSymB()->getSymbol().getName() + "'"); + + uint64_t Address = Target.getConstant(); + if (Target.getSymA()) + Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( + Target.getSymA()->getSymbol()), Layout); + if (Target.getSymB()) + Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( + Target.getSymB()->getSymbol()), Layout); + return Address; + } - /// @} - /// @name Symbol Table Data - /// @{ + return getSectionAddress(SD->getFragment()->getParent()) + + Layout.getSymbolOffset(SD); +} - SmallString<256> StringTable; - std::vector<MachSymbolData> LocalSymbolData; - std::vector<MachSymbolData> ExternalSymbolData; - std::vector<MachSymbolData> UndefinedSymbolData; +uint64_t MachObjectWriter::getPaddingSize(const MCSectionData *SD, + const MCAsmLayout &Layout) const { + uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD); + unsigned Next = SD->getLayoutOrder() + 1; + if (Next >= Layout.getSectionOrder().size()) + return 0; + + const MCSectionData &NextSD = *Layout.getSectionOrder()[Next]; + if (NextSD.getSection().isVirtualSection()) + return 0; + return OffsetToAlignment(EndAddr, NextSD.getAlignment()); +} - /// @} +void MachObjectWriter::WriteHeader(unsigned NumLoadCommands, + unsigned LoadCommandsSize, + bool SubsectionsViaSymbols) { + uint32_t Flags = 0; -private: - /// @name Utility Methods - /// @{ + if (SubsectionsViaSymbols) + Flags |= macho::HF_SubsectionsViaSymbols; - bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { - const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo( - (MCFixupKind) Kind); + // struct mach_header (28 bytes) or + // struct mach_header_64 (32 bytes) - return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; - } + uint64_t Start = OS.tell(); + (void) Start; - /// @} + Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32); - SectionAddrMap SectionAddress; - uint64_t getSectionAddress(const MCSectionData* SD) const { - return SectionAddress.lookup(SD); - } - uint64_t getSymbolAddress(const MCSymbolData* SD, - const MCAsmLayout &Layout) const { - const MCSymbol &S = SD->getSymbol(); - - // If this is a variable, then recursively evaluate now. - if (S.isVariable()) { - MCValue Target; - if (!S.getVariableValue()->EvaluateAsRelocatable(Target, Layout)) - report_fatal_error("unable to evaluate offset for variable '" + - S.getName() + "'"); - - // Verify that any used symbols are defined. - if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined()) - report_fatal_error("unable to evaluate offset to undefined symbol '" + - Target.getSymA()->getSymbol().getName() + "'"); - if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined()) - report_fatal_error("unable to evaluate offset to undefined symbol '" + - Target.getSymB()->getSymbol().getName() + "'"); - - uint64_t Address = Target.getConstant(); - if (Target.getSymA()) - Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( - Target.getSymA()->getSymbol()), Layout); - if (Target.getSymB()) - Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( - Target.getSymB()->getSymbol()), Layout); - return Address; - } + Write32(TargetObjectWriter->getCPUType()); + Write32(TargetObjectWriter->getCPUSubtype()); - return getSectionAddress(SD->getFragment()->getParent()) + - Layout.getSymbolOffset(SD); - } - uint64_t getFragmentAddress(const MCFragment *Fragment, - const MCAsmLayout &Layout) const { - return getSectionAddress(Fragment->getParent()) + - Layout.getFragmentOffset(Fragment); - } + Write32(macho::HFT_Object); + Write32(NumLoadCommands); + Write32(LoadCommandsSize); + Write32(Flags); + if (is64Bit()) + Write32(0); // reserved - uint64_t getPaddingSize(const MCSectionData *SD, - const MCAsmLayout &Layout) const { - uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD); - unsigned Next = SD->getLayoutOrder() + 1; - if (Next >= Layout.getSectionOrder().size()) - return 0; - - const MCSectionData &NextSD = *Layout.getSectionOrder()[Next]; - if (NextSD.getSection().isVirtualSection()) - return 0; - return OffsetToAlignment(EndAddr, NextSD.getAlignment()); - } + assert(OS.tell() - Start == + (is64Bit() ? macho::Header64Size : macho::Header32Size)); +} -public: - MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS, - bool _IsLittleEndian) - : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) { +/// WriteSegmentLoadCommand - Write a segment load command. +/// +/// \arg NumSections - The number of sections in this segment. +/// \arg SectionDataSize - The total size of the sections. +void MachObjectWriter::WriteSegmentLoadCommand(unsigned NumSections, + uint64_t VMSize, + uint64_t SectionDataStartOffset, + uint64_t SectionDataSize) { + // struct segment_command (56 bytes) or + // struct segment_command_64 (72 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + unsigned SegmentLoadCommandSize = + is64Bit() ? macho::SegmentLoadCommand64Size: + macho::SegmentLoadCommand32Size; + Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment); + Write32(SegmentLoadCommandSize + + NumSections * (is64Bit() ? macho::Section64Size : + macho::Section32Size)); + + WriteBytes("", 16); + if (is64Bit()) { + Write64(0); // vmaddr + Write64(VMSize); // vmsize + Write64(SectionDataStartOffset); // file offset + Write64(SectionDataSize); // file size + } else { + Write32(0); // vmaddr + Write32(VMSize); // vmsize + Write32(SectionDataStartOffset); // file offset + Write32(SectionDataSize); // file size } + Write32(0x7); // maxprot + Write32(0x7); // initprot + Write32(NumSections); + Write32(0); // flags - /// @name Target Writer Proxy Accessors - /// @{ + assert(OS.tell() - Start == SegmentLoadCommandSize); +} - bool is64Bit() const { return TargetObjectWriter->is64Bit(); } - bool isARM() const { - uint32_t CPUType = TargetObjectWriter->getCPUType() & ~mach::CTFM_ArchMask; - return CPUType == mach::CTM_ARM; +void MachObjectWriter::WriteSection(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCSectionData &SD, + uint64_t FileOffset, + uint64_t RelocationsStart, + unsigned NumRelocations) { + uint64_t SectionSize = Layout.getSectionAddressSize(&SD); + + // The offset is unused for virtual sections. + if (SD.getSection().isVirtualSection()) { + assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); + FileOffset = 0; } - /// @} - - void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, - bool SubsectionsViaSymbols) { - uint32_t Flags = 0; - - if (SubsectionsViaSymbols) - Flags |= macho::HF_SubsectionsViaSymbols; - - // struct mach_header (28 bytes) or - // struct mach_header_64 (32 bytes) - - uint64_t Start = OS.tell(); - (void) Start; - - Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32); - - Write32(TargetObjectWriter->getCPUType()); - Write32(TargetObjectWriter->getCPUSubtype()); - - Write32(macho::HFT_Object); - Write32(NumLoadCommands); - Write32(LoadCommandsSize); - Write32(Flags); - if (is64Bit()) - Write32(0); // reserved - - assert(OS.tell() - Start == - (is64Bit() ? macho::Header64Size : macho::Header32Size)); + // struct section (68 bytes) or + // struct section_64 (80 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection()); + WriteBytes(Section.getSectionName(), 16); + WriteBytes(Section.getSegmentName(), 16); + if (is64Bit()) { + Write64(getSectionAddress(&SD)); // address + Write64(SectionSize); // size + } else { + Write32(getSectionAddress(&SD)); // address + Write32(SectionSize); // size } + Write32(FileOffset); + + unsigned Flags = Section.getTypeAndAttributes(); + if (SD.hasInstructions()) + Flags |= MCSectionMachO::S_ATTR_SOME_INSTRUCTIONS; + + assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); + Write32(Log2_32(SD.getAlignment())); + Write32(NumRelocations ? RelocationsStart : 0); + Write32(NumRelocations); + Write32(Flags); + Write32(IndirectSymBase.lookup(&SD)); // reserved1 + Write32(Section.getStubSize()); // reserved2 + if (is64Bit()) + Write32(0); // reserved3 + + assert(OS.tell() - Start == (is64Bit() ? macho::Section64Size : + macho::Section32Size)); +} - /// WriteSegmentLoadCommand - Write a segment load command. - /// - /// \arg NumSections - The number of sections in this segment. - /// \arg SectionDataSize - The total size of the sections. - void WriteSegmentLoadCommand(unsigned NumSections, - uint64_t VMSize, - uint64_t SectionDataStartOffset, - uint64_t SectionDataSize) { - // struct segment_command (56 bytes) or - // struct segment_command_64 (72 bytes) - - uint64_t Start = OS.tell(); - (void) Start; - - unsigned SegmentLoadCommandSize = - is64Bit() ? macho::SegmentLoadCommand64Size: - macho::SegmentLoadCommand32Size; - Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment); - Write32(SegmentLoadCommandSize + - NumSections * (is64Bit() ? macho::Section64Size : - macho::Section32Size)); - - WriteBytes("", 16); - if (is64Bit()) { - Write64(0); // vmaddr - Write64(VMSize); // vmsize - Write64(SectionDataStartOffset); // file offset - Write64(SectionDataSize); // file size - } else { - Write32(0); // vmaddr - Write32(VMSize); // vmsize - Write32(SectionDataStartOffset); // file offset - Write32(SectionDataSize); // file size - } - Write32(0x7); // maxprot - Write32(0x7); // initprot - Write32(NumSections); - Write32(0); // flags +void MachObjectWriter::WriteSymtabLoadCommand(uint32_t SymbolOffset, + uint32_t NumSymbols, + uint32_t StringTableOffset, + uint32_t StringTableSize) { + // struct symtab_command (24 bytes) - assert(OS.tell() - Start == SegmentLoadCommandSize); - } + uint64_t Start = OS.tell(); + (void) Start; - void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCSectionData &SD, uint64_t FileOffset, - uint64_t RelocationsStart, unsigned NumRelocations) { - uint64_t SectionSize = Layout.getSectionAddressSize(&SD); + Write32(macho::LCT_Symtab); + Write32(macho::SymtabLoadCommandSize); + Write32(SymbolOffset); + Write32(NumSymbols); + Write32(StringTableOffset); + Write32(StringTableSize); - // The offset is unused for virtual sections. - if (SD.getSection().isVirtualSection()) { - assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); - FileOffset = 0; - } + assert(OS.tell() - Start == macho::SymtabLoadCommandSize); +} - // struct section (68 bytes) or - // struct section_64 (80 bytes) +void MachObjectWriter::WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, + uint32_t NumLocalSymbols, + uint32_t FirstExternalSymbol, + uint32_t NumExternalSymbols, + uint32_t FirstUndefinedSymbol, + uint32_t NumUndefinedSymbols, + uint32_t IndirectSymbolOffset, + uint32_t NumIndirectSymbols) { + // struct dysymtab_command (80 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + Write32(macho::LCT_Dysymtab); + Write32(macho::DysymtabLoadCommandSize); + Write32(FirstLocalSymbol); + Write32(NumLocalSymbols); + Write32(FirstExternalSymbol); + Write32(NumExternalSymbols); + Write32(FirstUndefinedSymbol); + Write32(NumUndefinedSymbols); + Write32(0); // tocoff + Write32(0); // ntoc + Write32(0); // modtaboff + Write32(0); // nmodtab + Write32(0); // extrefsymoff + Write32(0); // nextrefsyms + Write32(IndirectSymbolOffset); + Write32(NumIndirectSymbols); + Write32(0); // extreloff + Write32(0); // nextrel + Write32(0); // locreloff + Write32(0); // nlocrel + + assert(OS.tell() - Start == macho::DysymtabLoadCommandSize); +} - uint64_t Start = OS.tell(); - (void) Start; +void MachObjectWriter::WriteNlist(MachSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &Data = *MSD.SymbolData; + const MCSymbol &Symbol = Data.getSymbol(); + uint8_t Type = 0; + uint16_t Flags = Data.getFlags(); + uint32_t Address = 0; - const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection()); - WriteBytes(Section.getSectionName(), 16); - WriteBytes(Section.getSegmentName(), 16); - if (is64Bit()) { - Write64(getSectionAddress(&SD)); // address - Write64(SectionSize); // size + // Set the N_TYPE bits. See <mach-o/nlist.h>. + // + // FIXME: Are the prebound or indirect fields possible here? + if (Symbol.isUndefined()) + Type = macho::STT_Undefined; + else if (Symbol.isAbsolute()) + Type = macho::STT_Absolute; + else + Type = macho::STT_Section; + + // FIXME: Set STAB bits. + + if (Data.isPrivateExtern()) + Type |= macho::STF_PrivateExtern; + + // Set external bit. + if (Data.isExternal() || Symbol.isUndefined()) + Type |= macho::STF_External; + + // Compute the symbol address. + if (Symbol.isDefined()) { + if (Symbol.isAbsolute()) { + Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue(); } else { - Write32(getSectionAddress(&SD)); // address - Write32(SectionSize); // size + Address = getSymbolAddress(&Data, Layout); + } + } else if (Data.isCommon()) { + // Common symbols are encoded with the size in the address + // field, and their alignment in the flags. + Address = Data.getCommonSize(); + + // Common alignment is packed into the 'desc' bits. + if (unsigned Align = Data.getCommonAlignment()) { + unsigned Log2Size = Log2_32(Align); + assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); + if (Log2Size > 15) + report_fatal_error("invalid 'common' alignment '" + + Twine(Align) + "'"); + // FIXME: Keep this mask with the SymbolFlags enumeration. + Flags = (Flags & 0xF0FF) | (Log2Size << 8); } - Write32(FileOffset); - - unsigned Flags = Section.getTypeAndAttributes(); - if (SD.hasInstructions()) - Flags |= MCSectionMachO::S_ATTR_SOME_INSTRUCTIONS; - - assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); - Write32(Log2_32(SD.getAlignment())); - Write32(NumRelocations ? RelocationsStart : 0); - Write32(NumRelocations); - Write32(Flags); - Write32(IndirectSymBase.lookup(&SD)); // reserved1 - Write32(Section.getStubSize()); // reserved2 - if (is64Bit()) - Write32(0); // reserved3 - - assert(OS.tell() - Start == (is64Bit() ? macho::Section64Size : - macho::Section32Size)); } - void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, - uint32_t StringTableOffset, - uint32_t StringTableSize) { - // struct symtab_command (24 bytes) + // struct nlist (12 bytes) - uint64_t Start = OS.tell(); - (void) Start; + Write32(MSD.StringIndex); + Write8(Type); + Write8(MSD.SectionIndex); - Write32(macho::LCT_Symtab); - Write32(macho::SymtabLoadCommandSize); - Write32(SymbolOffset); - Write32(NumSymbols); - Write32(StringTableOffset); - Write32(StringTableSize); - - assert(OS.tell() - Start == macho::SymtabLoadCommandSize); - } - - void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, - uint32_t NumLocalSymbols, - uint32_t FirstExternalSymbol, - uint32_t NumExternalSymbols, - uint32_t FirstUndefinedSymbol, - uint32_t NumUndefinedSymbols, - uint32_t IndirectSymbolOffset, - uint32_t NumIndirectSymbols) { - // struct dysymtab_command (80 bytes) - - uint64_t Start = OS.tell(); - (void) Start; - - Write32(macho::LCT_Dysymtab); - Write32(macho::DysymtabLoadCommandSize); - Write32(FirstLocalSymbol); - Write32(NumLocalSymbols); - Write32(FirstExternalSymbol); - Write32(NumExternalSymbols); - Write32(FirstUndefinedSymbol); - Write32(NumUndefinedSymbols); - Write32(0); // tocoff - Write32(0); // ntoc - Write32(0); // modtaboff - Write32(0); // nmodtab - Write32(0); // extrefsymoff - Write32(0); // nextrefsyms - Write32(IndirectSymbolOffset); - Write32(NumIndirectSymbols); - Write32(0); // extreloff - Write32(0); // nextrel - Write32(0); // locreloff - Write32(0); // nlocrel - - assert(OS.tell() - Start == macho::DysymtabLoadCommandSize); - } - - void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) { - MCSymbolData &Data = *MSD.SymbolData; - const MCSymbol &Symbol = Data.getSymbol(); - uint8_t Type = 0; - uint16_t Flags = Data.getFlags(); - uint32_t Address = 0; + // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' + // value. + Write16(Flags); + if (is64Bit()) + Write64(Address); + else + Write32(Address); +} - // Set the N_TYPE bits. See <mach-o/nlist.h>. - // - // FIXME: Are the prebound or indirect fields possible here? - if (Symbol.isUndefined()) - Type = macho::STT_Undefined; - else if (Symbol.isAbsolute()) - Type = macho::STT_Absolute; - else - Type = macho::STT_Section; - - // FIXME: Set STAB bits. - - if (Data.isPrivateExtern()) - Type |= macho::STF_PrivateExtern; - - // Set external bit. - if (Data.isExternal() || Symbol.isUndefined()) - Type |= macho::STF_External; - - // Compute the symbol address. - if (Symbol.isDefined()) { - if (Symbol.isAbsolute()) { - Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue(); - } else { - Address = getSymbolAddress(&Data, Layout); - } - } else if (Data.isCommon()) { - // Common symbols are encoded with the size in the address - // field, and their alignment in the flags. - Address = Data.getCommonSize(); - - // Common alignment is packed into the 'desc' bits. - if (unsigned Align = Data.getCommonAlignment()) { - unsigned Log2Size = Log2_32(Align); - assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); - if (Log2Size > 15) - report_fatal_error("invalid 'common' alignment '" + - Twine(Align) + "'"); - // FIXME: Keep this mask with the SymbolFlags enumeration. - Flags = (Flags & 0xF0FF) | (Log2Size << 8); - } - } +void MachObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + TargetObjectWriter->RecordRelocation(this, Asm, Layout, Fragment, Fixup, + Target, FixedValue); +} - // struct nlist (12 bytes) +void MachObjectWriter::BindIndirectSymbols(MCAssembler &Asm) { + // This is the point where 'as' creates actual symbols for indirect symbols + // (in the following two passes). It would be easier for us to do this sooner + // when we see the attribute, but that makes getting the order in the symbol + // table much more complicated than it is worth. + // + // FIXME: Revisit this when the dust settles. - Write32(MSD.StringIndex); - Write8(Type); - Write8(MSD.SectionIndex); + // Bind non lazy symbol pointers first. + unsigned IndirectIndex = 0; + for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { + const MCSectionMachO &Section = + cast<MCSectionMachO>(it->SectionData->getSection()); - // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' - // value. - Write16(Flags); - if (is64Bit()) - Write64(Address); - else - Write32(Address); - } + if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) + continue; - // FIXME: We really need to improve the relocation validation. Basically, we - // want to implement a separate computation which evaluates the relocation - // entry as the linker would, and verifies that the resultant fixup value is - // exactly what the encoder wanted. This will catch several classes of - // problems: - // - // - Relocation entry bugs, the two algorithms are unlikely to have the same - // exact bug. - // - // - Relaxation issues, where we forget to relax something. - // - // - Input errors, where something cannot be correctly encoded. 'as' allows - // these through in many cases. + // Initialize the section indirect symbol base, if necessary. + if (!IndirectSymBase.count(it->SectionData)) + IndirectSymBase[it->SectionData] = IndirectIndex; - static bool isFixupKindRIPRel(unsigned Kind) { - return Kind == X86::reloc_riprel_4byte || - Kind == X86::reloc_riprel_4byte_movq_load; + Asm.getOrCreateSymbolData(*it->Symbol); } - void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); - unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); - - // See <reloc.h>. - uint32_t FixupOffset = - Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - uint32_t FixupAddress = - getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); - int64_t Value = 0; - unsigned Index = 0; - unsigned IsExtern = 0; - unsigned Type = 0; - - Value = Target.getConstant(); - - if (IsPCRel) { - // Compensate for the relocation offset, Darwin x86_64 relocations only - // have the addend and appear to have attempted to define it to be the - // actual expression addend without the PCrel bias. However, instructions - // with data following the relocation are not accommodated for (see comment - // below regarding SIGNED{1,2,4}), so it isn't exactly that either. - Value += 1LL << Log2Size; - } - if (Target.isAbsolute()) { // constant - // SymbolNum of 0 indicates the absolute section. - Type = macho::RIT_X86_64_Unsigned; - Index = 0; - - // FIXME: I believe this is broken, I don't think the linker can - // understand it. I think it would require a local relocation, but I'm not - // sure if that would work either. The official way to get an absolute - // PCrel relocation is to use an absolute symbol (which we don't support - // yet). - if (IsPCRel) { - IsExtern = 1; - Type = macho::RIT_X86_64_Branch; - } - } else if (Target.getSymB()) { // A - B + constant - const MCSymbol *A = &Target.getSymA()->getSymbol(); - MCSymbolData &A_SD = Asm.getSymbolData(*A); - const MCSymbolData *A_Base = Asm.getAtom(&A_SD); - - const MCSymbol *B = &Target.getSymB()->getSymbol(); - MCSymbolData &B_SD = Asm.getSymbolData(*B); - const MCSymbolData *B_Base = Asm.getAtom(&B_SD); - - // Neither symbol can be modified. - if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || - Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) - report_fatal_error("unsupported relocation of modified symbol"); - - // We don't support PCrel relocations of differences. Darwin 'as' doesn't - // implement most of these correctly. - if (IsPCRel) - report_fatal_error("unsupported pc-relative relocation of difference"); - - // The support for the situation where one or both of the symbols would - // require a local relocation is handled just like if the symbols were - // external. This is certainly used in the case of debug sections where - // the section has only temporary symbols and thus the symbols don't have - // base symbols. This is encoded using the section ordinal and - // non-extern relocation entries. - - // Darwin 'as' doesn't emit correct relocations for this (it ends up with - // a single SIGNED relocation); reject it for now. Except the case where - // both symbols don't have a base, equal but both NULL. - if (A_Base == B_Base && A_Base) - report_fatal_error("unsupported relocation with identical base"); - - Value += getSymbolAddress(&A_SD, Layout) - - (A_Base == NULL ? 0 : getSymbolAddress(A_Base, Layout)); - Value -= getSymbolAddress(&B_SD, Layout) - - (B_Base == NULL ? 0 : getSymbolAddress(B_Base, Layout)); - - if (A_Base) { - Index = A_Base->getIndex(); - IsExtern = 1; - } - else { - Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; - IsExtern = 0; - } - Type = macho::RIT_X86_64_Unsigned; - - macho::RelocationEntry MRE; - MRE.Word0 = FixupOffset; - MRE.Word1 = ((Index << 0) | - (IsPCRel << 24) | - (Log2Size << 25) | - (IsExtern << 27) | - (Type << 28)); - Relocations[Fragment->getParent()].push_back(MRE); - - if (B_Base) { - Index = B_Base->getIndex(); - IsExtern = 1; - } - else { - Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; - IsExtern = 0; - } - Type = macho::RIT_X86_64_Subtractor; - } else { - const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); - MCSymbolData &SD = Asm.getSymbolData(*Symbol); - const MCSymbolData *Base = Asm.getAtom(&SD); - - // Relocations inside debug sections always use local relocations when - // possible. This seems to be done because the debugger doesn't fully - // understand x86_64 relocation entries, and expects to find values that - // have already been fixed up. - if (Symbol->isInSection()) { - const MCSectionMachO &Section = static_cast<const MCSectionMachO&>( - Fragment->getParent()->getSection()); - if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG)) - Base = 0; - } + // Then lazy symbol pointers and symbol stubs. + IndirectIndex = 0; + for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { + const MCSectionMachO &Section = + cast<MCSectionMachO>(it->SectionData->getSection()); - // x86_64 almost always uses external relocations, except when there is no - // symbol to use as a base address (a local symbol with no preceding - // non-local symbol). - if (Base) { - Index = Base->getIndex(); - IsExtern = 1; - - // Add the local offset, if needed. - if (Base != &SD) - Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); - } else if (Symbol->isInSection() && !Symbol->isVariable()) { - // The index is the section ordinal (1-based). - Index = SD.getFragment()->getParent()->getOrdinal() + 1; - IsExtern = 0; - Value += getSymbolAddress(&SD, Layout); - - if (IsPCRel) - Value -= FixupAddress + (1 << Log2Size); - } else if (Symbol->isVariable()) { - const MCExpr *Value = Symbol->getVariableValue(); - int64_t Res; - bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, SectionAddress); - if (isAbs) { - FixedValue = Res; - return; - } else { - report_fatal_error("unsupported relocation of variable '" + - Symbol->getName() + "'"); - } - } else { - report_fatal_error("unsupported relocation of undefined symbol '" + - Symbol->getName() + "'"); - } + if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) + continue; - MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); - if (IsPCRel) { - if (IsRIPRel) { - if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { - // x86_64 distinguishes movq foo@GOTPCREL so that the linker can - // rewrite the movq to an leaq at link time if the symbol ends up in - // the same linkage unit. - if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) - Type = macho::RIT_X86_64_GOTLoad; - else - Type = macho::RIT_X86_64_GOT; - } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { - Type = macho::RIT_X86_64_TLV; - } else if (Modifier != MCSymbolRefExpr::VK_None) { - report_fatal_error("unsupported symbol modifier in relocation"); - } else { - Type = macho::RIT_X86_64_Signed; - - // The Darwin x86_64 relocation format has a problem where it cannot - // encode an address (L<foo> + <constant>) which is outside the atom - // containing L<foo>. Generally, this shouldn't occur but it does - // happen when we have a RIPrel instruction with data following the - // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel - // adjustment Darwin x86_64 uses, the offset is still negative and - // the linker has no way to recognize this. - // - // To work around this, Darwin uses several special relocation types - // to indicate the offsets. However, the specification or - // implementation of these seems to also be incomplete; they should - // adjust the addend as well based on the actual encoded instruction - // (the additional bias), but instead appear to just look at the - // final offset. - switch (-(Target.getConstant() + (1LL << Log2Size))) { - case 1: Type = macho::RIT_X86_64_Signed1; break; - case 2: Type = macho::RIT_X86_64_Signed2; break; - case 4: Type = macho::RIT_X86_64_Signed4; break; - } - } - } else { - if (Modifier != MCSymbolRefExpr::VK_None) - report_fatal_error("unsupported symbol modifier in branch " - "relocation"); - - Type = macho::RIT_X86_64_Branch; - } - } else { - if (Modifier == MCSymbolRefExpr::VK_GOT) { - Type = macho::RIT_X86_64_GOT; - } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { - // GOTPCREL is allowed as a modifier on non-PCrel instructions, in - // which case all we do is set the PCrel bit in the relocation entry; - // this is used with exception handling, for example. The source is - // required to include any necessary offset directly. - Type = macho::RIT_X86_64_GOT; - IsPCRel = 1; - } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { - report_fatal_error("TLVP symbol modifier should have been rip-rel"); - } else if (Modifier != MCSymbolRefExpr::VK_None) - report_fatal_error("unsupported symbol modifier in relocation"); - else - Type = macho::RIT_X86_64_Unsigned; - } - } + // Initialize the section indirect symbol base, if necessary. + if (!IndirectSymBase.count(it->SectionData)) + IndirectSymBase[it->SectionData] = IndirectIndex; - // x86_64 always writes custom values into the fixups. - FixedValue = Value; - - // struct relocation_info (8 bytes) - macho::RelocationEntry MRE; - MRE.Word0 = FixupOffset; - MRE.Word1 = ((Index << 0) | - (IsPCRel << 24) | - (Log2Size << 25) | - (IsExtern << 27) | - (Type << 28)); - Relocations[Fragment->getParent()].push_back(MRE); + // Set the symbol type to undefined lazy, but only on construction. + // + // FIXME: Do not hardcode. + bool Created; + MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created); + if (Created) + Entry.setFlags(Entry.getFlags() | 0x0001); } +} - void RecordScatteredRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - unsigned Log2Size, - uint64_t &FixedValue) { - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned Type = macho::RIT_Vanilla; - - // See <reloc.h>. - const MCSymbol *A = &Target.getSymA()->getSymbol(); - MCSymbolData *A_SD = &Asm.getSymbolData(*A); - - if (!A_SD->getFragment()) - report_fatal_error("symbol '" + A->getName() + - "' can not be undefined in a subtraction expression"); - - uint32_t Value = getSymbolAddress(A_SD, Layout); - uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); - FixedValue += SecAddr; - uint32_t Value2 = 0; - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); - - if (!B_SD->getFragment()) - report_fatal_error("symbol '" + B->getSymbol().getName() + - "' can not be undefined in a subtraction expression"); - - // Select the appropriate difference relocation type. - // - // Note that there is no longer any semantic difference between these two - // relocation types from the linkers point of view, this is done solely - // for pedantic compatibility with 'as'. - Type = A_SD->isExternal() ? (unsigned)macho::RIT_Difference : - (unsigned)macho::RIT_Generic_LocalDifference; - Value2 = getSymbolAddress(B_SD, Layout); - FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); - } - - // Relocations are written out in reverse order, so the PAIR comes first. - if (Type == macho::RIT_Difference || - Type == macho::RIT_Generic_LocalDifference) { - macho::RelocationEntry MRE; - MRE.Word0 = ((0 << 0) | - (macho::RIT_Pair << 24) | - (Log2Size << 28) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value2; - Relocations[Fragment->getParent()].push_back(MRE); +/// ComputeSymbolTable - Compute the symbol table data +/// +/// \param StringTable [out] - The string table data. +/// \param StringIndexMap [out] - Map from symbol names to offsets in the +/// string table. +void MachObjectWriter:: +ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, + std::vector<MachSymbolData> &LocalSymbolData, + std::vector<MachSymbolData> &ExternalSymbolData, + std::vector<MachSymbolData> &UndefinedSymbolData) { + // Build section lookup table. + DenseMap<const MCSection*, uint8_t> SectionIndexMap; + unsigned Index = 1; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) + SectionIndexMap[&it->getSection()] = Index; + assert(Index <= 256 && "Too many sections!"); + + // Index 0 is always the empty string. + StringMap<uint64_t> StringIndexMap; + StringTable += '\x00'; + + // Build the symbol arrays and the string table, but only for non-local + // symbols. + // + // The particular order that we collect the symbols and create the string + // table, then sort the symbols is chosen to match 'as'. Even though it + // doesn't matter for correctness, this is important for letting us diff .o + // files. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) + continue; + + if (!it->isExternal() && !Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; } - macho::RelocationEntry MRE; - MRE.Word0 = ((FixupOffset << 0) | - (Type << 24) | - (Log2Size << 28) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value; - Relocations[Fragment->getParent()].push_back(MRE); - } - - void RecordARMScatteredRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - unsigned Log2Size, - uint64_t &FixedValue) { - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned Type = macho::RIT_Vanilla; - - // See <reloc.h>. - const MCSymbol *A = &Target.getSymA()->getSymbol(); - MCSymbolData *A_SD = &Asm.getSymbolData(*A); - - if (!A_SD->getFragment()) - report_fatal_error("symbol '" + A->getName() + - "' can not be undefined in a subtraction expression"); - - uint32_t Value = getSymbolAddress(A_SD, Layout); - uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); - FixedValue += SecAddr; - uint32_t Value2 = 0; - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); - - if (!B_SD->getFragment()) - report_fatal_error("symbol '" + B->getSymbol().getName() + - "' can not be undefined in a subtraction expression"); - - // Select the appropriate difference relocation type. - Type = macho::RIT_Difference; - Value2 = getSymbolAddress(B_SD, Layout); - FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); - } + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; - // Relocations are written out in reverse order, so the PAIR comes first. - if (Type == macho::RIT_Difference || - Type == macho::RIT_Generic_LocalDifference) { - macho::RelocationEntry MRE; - MRE.Word0 = ((0 << 0) | - (macho::RIT_Pair << 24) | - (Log2Size << 28) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value2; - Relocations[Fragment->getParent()].push_back(MRE); + if (Symbol.isUndefined()) { + MSD.SectionIndex = 0; + UndefinedSymbolData.push_back(MSD); + } else if (Symbol.isAbsolute()) { + MSD.SectionIndex = 0; + ExternalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + ExternalSymbolData.push_back(MSD); } - - macho::RelocationEntry MRE; - MRE.Word0 = ((FixupOffset << 0) | - (Type << 24) | - (Log2Size << 28) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value; - Relocations[Fragment->getParent()].push_back(MRE); } - void RecordARMMovwMovtRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned Type = macho::RIT_ARM_Half; - - // See <reloc.h>. - const MCSymbol *A = &Target.getSymA()->getSymbol(); - MCSymbolData *A_SD = &Asm.getSymbolData(*A); - - if (!A_SD->getFragment()) - report_fatal_error("symbol '" + A->getName() + - "' can not be undefined in a subtraction expression"); - - uint32_t Value = getSymbolAddress(A_SD, Layout); - uint32_t Value2 = 0; - uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); - FixedValue += SecAddr; - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); - - if (!B_SD->getFragment()) - report_fatal_error("symbol '" + B->getSymbol().getName() + - "' can not be undefined in a subtraction expression"); - - // Select the appropriate difference relocation type. - Type = macho::RIT_ARM_HalfDifference; - Value2 = getSymbolAddress(B_SD, Layout); - FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); - } - - // Relocations are written out in reverse order, so the PAIR comes first. - // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: - // - // For these two r_type relocations they always have a pair following them - // and the r_length bits are used differently. The encoding of the - // r_length is as follows: - // low bit of r_length: - // 0 - :lower16: for movw instructions - // 1 - :upper16: for movt instructions - // high bit of r_length: - // 0 - arm instructions - // 1 - thumb instructions - // the other half of the relocated expression is in the following pair - // relocation entry in the the low 16 bits of r_address field. - unsigned ThumbBit = 0; - unsigned MovtBit = 0; - switch ((unsigned)Fixup.getKind()) { - default: break; - case ARM::fixup_arm_movt_hi16: - case ARM::fixup_arm_movt_hi16_pcrel: - MovtBit = 1; - break; - case ARM::fixup_t2_movt_hi16: - case ARM::fixup_t2_movt_hi16_pcrel: - MovtBit = 1; - // Fallthrough - case ARM::fixup_t2_movw_lo16: - case ARM::fixup_t2_movw_lo16_pcrel: - ThumbBit = 1; - break; - } + // Now add the data for local symbols. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) + continue; - if (Type == macho::RIT_ARM_HalfDifference) { - uint32_t OtherHalf = MovtBit - ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); + if (it->isExternal() || Symbol.isUndefined()) + continue; - macho::RelocationEntry MRE; - MRE.Word0 = ((OtherHalf << 0) | - (macho::RIT_Pair << 24) | - (MovtBit << 28) | - (ThumbBit << 29) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value2; - Relocations[Fragment->getParent()].push_back(MRE); + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; } - macho::RelocationEntry MRE; - MRE.Word0 = ((FixupOffset << 0) | - (Type << 24) | - (MovtBit << 28) | - (ThumbBit << 29) | - (IsPCRel << 30) | - macho::RF_Scattered); - MRE.Word1 = Value; - Relocations[Fragment->getParent()].push_back(MRE); - } + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; - void RecordTLVPRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && - !is64Bit() && - "Should only be called with a 32-bit TLVP relocation!"); - - unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); - uint32_t Value = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = 0; - - // Get the symbol data. - MCSymbolData *SD_A = &Asm.getSymbolData(Target.getSymA()->getSymbol()); - unsigned Index = SD_A->getIndex(); - - // We're only going to have a second symbol in pic mode and it'll be a - // subtraction from the picbase. For 32-bit pic the addend is the difference - // between the picbase and the next address. For 32-bit static the addend - // is zero. - if (Target.getSymB()) { - // If this is a subtraction then we're pcrel. - uint32_t FixupAddress = - getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); - MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); - IsPCRel = 1; - FixedValue = (FixupAddress - getSymbolAddress(SD_B, Layout) + - Target.getConstant()); - FixedValue += 1ULL << Log2Size; + if (Symbol.isAbsolute()) { + MSD.SectionIndex = 0; + LocalSymbolData.push_back(MSD); } else { - FixedValue = 0; + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + LocalSymbolData.push_back(MSD); } - - // struct relocation_info (8 bytes) - macho::RelocationEntry MRE; - MRE.Word0 = Value; - MRE.Word1 = ((Index << 0) | - (IsPCRel << 24) | - (Log2Size << 25) | - (1 << 27) | // Extern - (macho::RIT_Generic_TLV << 28)); // Type - Relocations[Fragment->getParent()].push_back(MRE); } - static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, - unsigned &Log2Size) { - RelocType = unsigned(macho::RIT_Vanilla); - Log2Size = ~0U; + // External and undefined symbols are required to be in lexicographic order. + std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + + // Set the symbol indices. + Index = 0; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + LocalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + ExternalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + UndefinedSymbolData[i].SymbolData->setIndex(Index++); + + // The string table is padded to a multiple of 4. + while (StringTable.size() % 4) + StringTable += '\x00'; +} - switch (Kind) { - default: - return false; +void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartAddress = 0; + const SmallVectorImpl<MCSectionData*> &Order = Layout.getSectionOrder(); + for (int i = 0, n = Order.size(); i != n ; ++i) { + const MCSectionData *SD = Order[i]; + StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + SectionAddress[SD] = StartAddress; + StartAddress += Layout.getSectionAddressSize(SD); + + // Explicitly pad the section to match the alignment requirements of the + // following one. This is for 'gas' compatibility, it shouldn't + /// strictly be necessary. + StartAddress += getPaddingSize(SD, Layout); + } +} - case FK_Data_1: - Log2Size = llvm::Log2_32(1); - return true; - case FK_Data_2: - Log2Size = llvm::Log2_32(2); - return true; - case FK_Data_4: - Log2Size = llvm::Log2_32(4); - return true; - case FK_Data_8: - Log2Size = llvm::Log2_32(8); - return true; +void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + computeSectionAddresses(Asm, Layout); - // Handle 24-bit branch kinds. - case ARM::fixup_arm_ldst_pcrel_12: - case ARM::fixup_arm_pcrel_10: - case ARM::fixup_arm_adr_pcrel_12: - case ARM::fixup_arm_condbranch: - case ARM::fixup_arm_uncondbranch: - RelocType = unsigned(macho::RIT_ARM_Branch24Bit); - // Report as 'long', even though that is not quite accurate. - Log2Size = llvm::Log2_32(4); - return true; + // Create symbol data for any indirect symbols. + BindIndirectSymbols(Asm); - // Handle Thumb branches. - case ARM::fixup_arm_thumb_br: - RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); - Log2Size = llvm::Log2_32(2); - return true; - - case ARM::fixup_arm_thumb_bl: - case ARM::fixup_arm_thumb_blx: - RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); - Log2Size = llvm::Log2_32(4); - return true; + // Compute symbol table information and bind symbol indices. + ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, + UndefinedSymbolData); +} - case ARM::fixup_arm_movt_hi16: - case ARM::fixup_arm_movt_hi16_pcrel: - case ARM::fixup_t2_movt_hi16: - case ARM::fixup_t2_movt_hi16_pcrel: - RelocType = unsigned(macho::RIT_ARM_HalfDifference); - // Report as 'long', even though that is not quite accurate. - Log2Size = llvm::Log2_32(4); - return true; +bool MachObjectWriter:: +IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + if (InSet) + return true; - case ARM::fixup_arm_movw_lo16: - case ARM::fixup_arm_movw_lo16_pcrel: - case ARM::fixup_t2_movw_lo16: - case ARM::fixup_t2_movw_lo16_pcrel: - RelocType = unsigned(macho::RIT_ARM_Half); - // Report as 'long', even though that is not quite accurate. - Log2Size = llvm::Log2_32(4); + // The effective address is + // addr(atom(A)) + offset(A) + // - addr(atom(B)) - offset(B) + // and the offsets are not relocatable, so the fixup is fully resolved when + // addr(atom(A)) - addr(atom(B)) == 0. + const MCSymbolData *A_Base = 0, *B_Base = 0; + + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + const MCSection &SecA = SA.getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + + if (IsPCRel) { + // The simple (Darwin, except on x86_64) way of dealing with this was to + // assume that any reference to a temporary symbol *must* be a temporary + // symbol in the same atom, unless the sections differ. Therefore, any PCrel + // relocation to a temporary symbol (in the same section) is fully + // resolved. This also works in conjunction with absolutized .set, which + // requires the compiler to use .set to absolutize the differences between + // symbols which the compiler knows to be assembly time constants, so we + // don't need to worry about considering symbol differences fully resolved. + + if (!Asm.getBackend().hasReliableSymbolDifference()) { + if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) + return false; return true; } + } else { + if (!TargetObjectWriter->useAggressiveSymbolFolding()) + return false; } - void RecordARMRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue) { - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned Log2Size; - unsigned RelocType = macho::RIT_Vanilla; - if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) { - report_fatal_error("unknown ARM fixup kind!"); - return; - } - // If this is a difference or a defined symbol plus an offset, then we need - // a scattered relocation entry. Differences always require scattered - // relocations. - if (Target.getSymB()) { - if (RelocType == macho::RIT_ARM_Half || - RelocType == macho::RIT_ARM_HalfDifference) - return RecordARMMovwMovtRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); - return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, Log2Size, FixedValue); - } + const MCFragment &FA = *Asm.getSymbolData(SA).getFragment(); - // Get the symbol data, if any. - MCSymbolData *SD = 0; - if (Target.getSymA()) - SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); + A_Base = FA.getAtom(); + if (!A_Base) + return false; - // FIXME: For other platforms, we need to use scattered relocations for - // internal relocations with offsets. If this is an internal relocation - // with an offset, it also needs a scattered relocation entry. - // - // Is this right for ARM? - uint32_t Offset = Target.getConstant(); - if (IsPCRel && RelocType == macho::RIT_Vanilla) - Offset += 1 << Log2Size; - if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) - return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, Target, - Log2Size, FixedValue); - - // See <reloc.h>. - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned Index = 0; - unsigned IsExtern = 0; - unsigned Type = 0; - - if (Target.isAbsolute()) { // constant - // FIXME! - report_fatal_error("FIXME: relocations to absolute targets " - "not yet implemented"); - } else { - // Resolve constant variables. - if (SD->getSymbol().isVariable()) { - int64_t Res; - if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( - Res, Layout, SectionAddress)) { - FixedValue = Res; - return; - } - } + B_Base = FB.getAtom(); + if (!B_Base) + return false; - // Check whether we need an external or internal relocation. - if (doesSymbolRequireExternRelocation(SD)) { - IsExtern = 1; - Index = SD->getIndex(); - // For external relocations, make sure to offset the fixup value to - // compensate for the addend of the symbol address, if it was - // undefined. This occurs with weak definitions, for example. - if (!SD->Symbol->isUndefined()) - FixedValue -= Layout.getSymbolOffset(SD); - } else { - // The index is the section ordinal (1-based). - const MCSectionData &SymSD = Asm.getSectionData( - SD->getSymbol().getSection()); - Index = SymSD.getOrdinal() + 1; - FixedValue += getSectionAddress(&SymSD); - } - if (IsPCRel) - FixedValue -= getSectionAddress(Fragment->getParent()); + // If the atoms are the same, they are guaranteed to have the same address. + if (A_Base == B_Base) + return true; - // The type is determined by the fixup kind. - Type = RelocType; - } + // Otherwise, we can't prove this is fully resolved. + return false; +} - // struct relocation_info (8 bytes) - macho::RelocationEntry MRE; - MRE.Word0 = FixupOffset; - MRE.Word1 = ((Index << 0) | - (IsPCRel << 24) | - (Log2Size << 25) | - (IsExtern << 27) | - (Type << 28)); - Relocations[Fragment->getParent()].push_back(MRE); +void MachObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { + unsigned NumSections = Asm.size(); + + // The section data starts after the header, the segment load command (and + // section headers) and the symbol table. + unsigned NumLoadCommands = 1; + uint64_t LoadCommandsSize = is64Bit() ? + macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size : + macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size; + + // Add the symbol table load command sizes, if used. + unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + + UndefinedSymbolData.size(); + if (NumSymbols) { + NumLoadCommands += 2; + LoadCommandsSize += (macho::SymtabLoadCommandSize + + macho::DysymtabLoadCommandSize); } - void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue) { - // FIXME: These needs to be factored into the target Mach-O writer. - if (isARM()) { - RecordARMRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); - return; - } - if (is64Bit()) { - RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); - return; - } - - unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); - unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); - - // If this is a 32-bit TLVP reloc it's handled a bit differently. - if (Target.getSymA() && - Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { - RecordTLVPRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); - return; - } - - // If this is a difference or a defined symbol plus an offset, then we need - // a scattered relocation entry. - // Differences always require scattered relocations. - if (Target.getSymB()) - return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, Log2Size, FixedValue); - - // Get the symbol data, if any. - MCSymbolData *SD = 0; - if (Target.getSymA()) - SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); - - // If this is an internal relocation with an offset, it also needs a - // scattered relocation entry. - uint32_t Offset = Target.getConstant(); - if (IsPCRel) - Offset += 1 << Log2Size; - if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) - return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, Log2Size, FixedValue); - - // See <reloc.h>. - uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned Index = 0; - unsigned IsExtern = 0; - unsigned Type = 0; - - if (Target.isAbsolute()) { // constant - // SymbolNum of 0 indicates the absolute section. - // - // FIXME: Currently, these are never generated (see code below). I cannot - // find a case where they are actually emitted. - Type = macho::RIT_Vanilla; - } else { - // Resolve constant variables. - if (SD->getSymbol().isVariable()) { - int64_t Res; - if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( - Res, Layout, SectionAddress)) { - FixedValue = Res; - return; - } - } - - // Check whether we need an external or internal relocation. - if (doesSymbolRequireExternRelocation(SD)) { - IsExtern = 1; - Index = SD->getIndex(); - // For external relocations, make sure to offset the fixup value to - // compensate for the addend of the symbol address, if it was - // undefined. This occurs with weak definitions, for example. - if (!SD->Symbol->isUndefined()) - FixedValue -= Layout.getSymbolOffset(SD); - } else { - // The index is the section ordinal (1-based). - const MCSectionData &SymSD = Asm.getSectionData( - SD->getSymbol().getSection()); - Index = SymSD.getOrdinal() + 1; - FixedValue += getSectionAddress(&SymSD); - } - if (IsPCRel) - FixedValue -= getSectionAddress(Fragment->getParent()); - - Type = macho::RIT_Vanilla; - } - - // struct relocation_info (8 bytes) - macho::RelocationEntry MRE; - MRE.Word0 = FixupOffset; - MRE.Word1 = ((Index << 0) | - (IsPCRel << 24) | - (Log2Size << 25) | - (IsExtern << 27) | - (Type << 28)); - Relocations[Fragment->getParent()].push_back(MRE); + // Compute the total size of the section data, as well as its file size and vm + // size. + uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size : + macho::Header32Size) + LoadCommandsSize; + uint64_t SectionDataSize = 0; + uint64_t SectionDataFileSize = 0; + uint64_t VMSize = 0; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + uint64_t Address = getSectionAddress(&SD); + uint64_t Size = Layout.getSectionAddressSize(&SD); + uint64_t FileSize = Layout.getSectionFileSize(&SD); + FileSize += getPaddingSize(&SD, Layout); + + VMSize = std::max(VMSize, Address + Size); + + if (SD.getSection().isVirtualSection()) + continue; + + SectionDataSize = std::max(SectionDataSize, Address + Size); + SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); } - void BindIndirectSymbols(MCAssembler &Asm) { - // This is the point where 'as' creates actual symbols for indirect symbols - // (in the following two passes). It would be easier for us to do this - // sooner when we see the attribute, but that makes getting the order in the - // symbol table much more complicated than it is worth. - // - // FIXME: Revisit this when the dust settles. + // The section data is padded to 4 bytes. + // + // FIXME: Is this machine dependent? + unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); + SectionDataFileSize += SectionDataPadding; + + // Write the prolog, starting with the header and load command... + WriteHeader(NumLoadCommands, LoadCommandsSize, + Asm.getSubsectionsViaSymbols()); + WriteSegmentLoadCommand(NumSections, VMSize, + SectionDataStart, SectionDataSize); + + // ... and then the section headers. + uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; + unsigned NumRelocs = Relocs.size(); + uint64_t SectionStart = SectionDataStart + getSectionAddress(it); + WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); + RelocTableEnd += NumRelocs * macho::RelocationInfoSize; + } - // Bind non lazy symbol pointers first. - unsigned IndirectIndex = 0; - for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { - const MCSectionMachO &Section = - cast<MCSectionMachO>(it->SectionData->getSection()); + // Write the symbol table load command, if used. + if (NumSymbols) { + unsigned FirstLocalSymbol = 0; + unsigned NumLocalSymbols = LocalSymbolData.size(); + unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; + unsigned NumExternalSymbols = ExternalSymbolData.size(); + unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; + unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); + unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); + unsigned NumSymTabSymbols = + NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; + uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; + uint64_t IndirectSymbolOffset = 0; + + // If used, the indirect symbols are written after the section data. + if (NumIndirectSymbols) + IndirectSymbolOffset = RelocTableEnd; + + // The symbol table is written after the indirect symbol data. + uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize; + + // The string table is written after symbol table. + uint64_t StringTableOffset = + SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size : + macho::Nlist32Size); + WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, + StringTableOffset, StringTable.size()); + + WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, + FirstExternalSymbol, NumExternalSymbols, + FirstUndefinedSymbol, NumUndefinedSymbols, + IndirectSymbolOffset, NumIndirectSymbols); + } - if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) - continue; + // Write the actual section data. + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + Asm.WriteSectionData(it, Layout); - // Initialize the section indirect symbol base, if necessary. - if (!IndirectSymBase.count(it->SectionData)) - IndirectSymBase[it->SectionData] = IndirectIndex; + uint64_t Pad = getPaddingSize(it, Layout); + for (unsigned int i = 0; i < Pad; ++i) + Write8(0); + } - Asm.getOrCreateSymbolData(*it->Symbol); - } + // Write the extra padding. + WriteZeros(SectionDataPadding); - // Then lazy symbol pointers and symbol stubs. - IndirectIndex = 0; - for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) { - const MCSectionMachO &Section = - cast<MCSectionMachO>(it->SectionData->getSection()); - - if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && - Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) - continue; - - // Initialize the section indirect symbol base, if necessary. - if (!IndirectSymBase.count(it->SectionData)) - IndirectSymBase[it->SectionData] = IndirectIndex; - - // Set the symbol type to undefined lazy, but only on construction. - // - // FIXME: Do not hardcode. - bool Created; - MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created); - if (Created) - Entry.setFlags(Entry.getFlags() | 0x0001); + // Write the relocation entries. + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + // Write the section relocation entries, in reverse order to match 'as' + // (approximately, the exact algorithm is more complicated than this). + std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + Write32(Relocs[e - i - 1].Word0); + Write32(Relocs[e - i - 1].Word1); } } - /// ComputeSymbolTable - Compute the symbol table data - /// - /// \param StringTable [out] - The string table data. - /// \param StringIndexMap [out] - Map from symbol names to offsets in the - /// string table. - void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, - std::vector<MachSymbolData> &LocalSymbolData, - std::vector<MachSymbolData> &ExternalSymbolData, - std::vector<MachSymbolData> &UndefinedSymbolData) { - // Build section lookup table. - DenseMap<const MCSection*, uint8_t> SectionIndexMap; - unsigned Index = 1; - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) - SectionIndexMap[&it->getSection()] = Index; - assert(Index <= 256 && "Too many sections!"); - - // Index 0 is always the empty string. - StringMap<uint64_t> StringIndexMap; - StringTable += '\x00'; - - // Build the symbol arrays and the string table, but only for non-local - // symbols. - // - // The particular order that we collect the symbols and create the string - // table, then sort the symbols is chosen to match 'as'. Even though it - // doesn't matter for correctness, this is important for letting us diff .o - // files. - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) { - const MCSymbol &Symbol = it->getSymbol(); - - // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(it->getSymbol())) - continue; - - if (!it->isExternal() && !Symbol.isUndefined()) - continue; - - uint64_t &Entry = StringIndexMap[Symbol.getName()]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Symbol.getName(); - StringTable += '\x00'; + // Write the symbol table data, if used. + if (NumSymbols) { + // Write the indirect symbol entries. + for (MCAssembler::const_indirect_symbol_iterator + it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it) { + // Indirect symbols in the non lazy symbol pointer section have some + // special handling. + const MCSectionMachO &Section = + static_cast<const MCSectionMachO&>(it->SectionData->getSection()); + if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { + // If this symbol is defined and internal, mark it as such. + if (it->Symbol->isDefined() && + !Asm.getSymbolData(*it->Symbol).isExternal()) { + uint32_t Flags = macho::ISF_Local; + if (it->Symbol->isAbsolute()) + Flags |= macho::ISF_Absolute; + Write32(Flags); + continue; + } } - MachSymbolData MSD; - MSD.SymbolData = it; - MSD.StringIndex = Entry; - - if (Symbol.isUndefined()) { - MSD.SectionIndex = 0; - UndefinedSymbolData.push_back(MSD); - } else if (Symbol.isAbsolute()) { - MSD.SectionIndex = 0; - ExternalSymbolData.push_back(MSD); - } else { - MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); - assert(MSD.SectionIndex && "Invalid section index!"); - ExternalSymbolData.push_back(MSD); - } + Write32(Asm.getSymbolData(*it->Symbol).getIndex()); } - // Now add the data for local symbols. - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) { - const MCSymbol &Symbol = it->getSymbol(); - - // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(it->getSymbol())) - continue; - - if (it->isExternal() || Symbol.isUndefined()) - continue; - - uint64_t &Entry = StringIndexMap[Symbol.getName()]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Symbol.getName(); - StringTable += '\x00'; - } - - MachSymbolData MSD; - MSD.SymbolData = it; - MSD.StringIndex = Entry; - - if (Symbol.isAbsolute()) { - MSD.SectionIndex = 0; - LocalSymbolData.push_back(MSD); - } else { - MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); - assert(MSD.SectionIndex && "Invalid section index!"); - LocalSymbolData.push_back(MSD); - } - } + // FIXME: Check that offsets match computed ones. - // External and undefined symbols are required to be in lexicographic order. - std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); - std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); - - // Set the symbol indices. - Index = 0; + // Write the symbol table entries. for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) - LocalSymbolData[i].SymbolData->setIndex(Index++); + WriteNlist(LocalSymbolData[i], Layout); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) - ExternalSymbolData[i].SymbolData->setIndex(Index++); + WriteNlist(ExternalSymbolData[i], Layout); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) - UndefinedSymbolData[i].SymbolData->setIndex(Index++); - - // The string table is padded to a multiple of 4. - while (StringTable.size() % 4) - StringTable += '\x00'; - } - - void computeSectionAddresses(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - uint64_t StartAddress = 0; - const SmallVectorImpl<MCSectionData*> &Order = Layout.getSectionOrder(); - for (int i = 0, n = Order.size(); i != n ; ++i) { - const MCSectionData *SD = Order[i]; - StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); - SectionAddress[SD] = StartAddress; - StartAddress += Layout.getSectionAddressSize(SD); - // Explicitly pad the section to match the alignment requirements of the - // following one. This is for 'gas' compatibility, it shouldn't - /// strictly be necessary. - StartAddress += getPaddingSize(SD, Layout); - } - } - - void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { - computeSectionAddresses(Asm, Layout); - - // Create symbol data for any indirect symbols. - BindIndirectSymbols(Asm); - - // Compute symbol table information and bind symbol indices. - ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, - UndefinedSymbolData); - } - - virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, - const MCSymbolData &DataA, - const MCFragment &FB, - bool InSet, - bool IsPCRel) const { - if (InSet) - return true; + WriteNlist(UndefinedSymbolData[i], Layout); - // The effective address is - // addr(atom(A)) + offset(A) - // - addr(atom(B)) - offset(B) - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) == 0. - const MCSymbolData *A_Base = 0, *B_Base = 0; - - const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); - const MCSection &SecA = SA.getSection(); - const MCSection &SecB = FB.getParent()->getSection(); - - if (IsPCRel) { - // The simple (Darwin, except on x86_64) way of dealing with this was to - // assume that any reference to a temporary symbol *must* be a temporary - // symbol in the same atom, unless the sections differ. Therefore, any - // PCrel relocation to a temporary symbol (in the same section) is fully - // resolved. This also works in conjunction with absolutized .set, which - // requires the compiler to use .set to absolutize the differences between - // symbols which the compiler knows to be assembly time constants, so we - // don't need to worry about considering symbol differences fully - // resolved. - - if (!Asm.getBackend().hasReliableSymbolDifference()) { - if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) - return false; - return true; - } - } else { - if (!TargetObjectWriter->useAggressiveSymbolFolding()) - return false; - } - - const MCFragment &FA = *Asm.getSymbolData(SA).getFragment(); - - A_Base = FA.getAtom(); - if (!A_Base) - return false; - - B_Base = FB.getAtom(); - if (!B_Base) - return false; - - // If the atoms are the same, they are guaranteed to have the same address. - if (A_Base == B_Base) - return true; - - // Otherwise, we can't prove this is fully resolved. - return false; + // Write the string table. + OS << StringTable.str(); } - - void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { - unsigned NumSections = Asm.size(); - - // The section data starts after the header, the segment load command (and - // section headers) and the symbol table. - unsigned NumLoadCommands = 1; - uint64_t LoadCommandsSize = is64Bit() ? - macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size : - macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size; - - // Add the symbol table load command sizes, if used. - unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + - UndefinedSymbolData.size(); - if (NumSymbols) { - NumLoadCommands += 2; - LoadCommandsSize += (macho::SymtabLoadCommandSize + - macho::DysymtabLoadCommandSize); - } - - // Compute the total size of the section data, as well as its file size and - // vm size. - uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size : - macho::Header32Size) + LoadCommandsSize; - uint64_t SectionDataSize = 0; - uint64_t SectionDataFileSize = 0; - uint64_t VMSize = 0; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; - uint64_t Address = getSectionAddress(&SD); - uint64_t Size = Layout.getSectionAddressSize(&SD); - uint64_t FileSize = Layout.getSectionFileSize(&SD); - FileSize += getPaddingSize(&SD, Layout); - - VMSize = std::max(VMSize, Address + Size); - - if (SD.getSection().isVirtualSection()) - continue; - - SectionDataSize = std::max(SectionDataSize, Address + Size); - SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize); - } - - // The section data is padded to 4 bytes. - // - // FIXME: Is this machine dependent? - unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); - SectionDataFileSize += SectionDataPadding; - - // Write the prolog, starting with the header and load command... - WriteHeader(NumLoadCommands, LoadCommandsSize, - Asm.getSubsectionsViaSymbols()); - WriteSegmentLoadCommand(NumSections, VMSize, - SectionDataStart, SectionDataSize); - - // ... and then the section headers. - uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; - unsigned NumRelocs = Relocs.size(); - uint64_t SectionStart = SectionDataStart + getSectionAddress(it); - WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); - RelocTableEnd += NumRelocs * macho::RelocationInfoSize; - } - - // Write the symbol table load command, if used. - if (NumSymbols) { - unsigned FirstLocalSymbol = 0; - unsigned NumLocalSymbols = LocalSymbolData.size(); - unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; - unsigned NumExternalSymbols = ExternalSymbolData.size(); - unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; - unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); - unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); - unsigned NumSymTabSymbols = - NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; - uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; - uint64_t IndirectSymbolOffset = 0; - - // If used, the indirect symbols are written after the section data. - if (NumIndirectSymbols) - IndirectSymbolOffset = RelocTableEnd; - - // The symbol table is written after the indirect symbol data. - uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize; - - // The string table is written after symbol table. - uint64_t StringTableOffset = - SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size : - macho::Nlist32Size); - WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, - StringTableOffset, StringTable.size()); - - WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, - FirstExternalSymbol, NumExternalSymbols, - FirstUndefinedSymbol, NumUndefinedSymbols, - IndirectSymbolOffset, NumIndirectSymbols); - } - - // Write the actual section data. - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - Asm.WriteSectionData(it, Layout); - - uint64_t Pad = getPaddingSize(it, Layout); - for (unsigned int i = 0; i < Pad; ++i) - Write8(0); - } - - // Write the extra padding. - WriteZeros(SectionDataPadding); - - // Write the relocation entries. - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - // Write the section relocation entries, in reverse order to match 'as' - // (approximately, the exact algorithm is more complicated than this). - std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; - for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { - Write32(Relocs[e - i - 1].Word0); - Write32(Relocs[e - i - 1].Word1); - } - } - - // Write the symbol table data, if used. - if (NumSymbols) { - // Write the indirect symbol entries. - for (MCAssembler::const_indirect_symbol_iterator - it = Asm.indirect_symbol_begin(), - ie = Asm.indirect_symbol_end(); it != ie; ++it) { - // Indirect symbols in the non lazy symbol pointer section have some - // special handling. - const MCSectionMachO &Section = - static_cast<const MCSectionMachO&>(it->SectionData->getSection()); - if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { - // If this symbol is defined and internal, mark it as such. - if (it->Symbol->isDefined() && - !Asm.getSymbolData(*it->Symbol).isExternal()) { - uint32_t Flags = macho::ISF_Local; - if (it->Symbol->isAbsolute()) - Flags |= macho::ISF_Absolute; - Write32(Flags); - continue; - } - } - - Write32(Asm.getSymbolData(*it->Symbol).getIndex()); - } - - // FIXME: Check that offsets match computed ones. - - // Write the symbol table entries. - for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) - WriteNlist(LocalSymbolData[i], Layout); - for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) - WriteNlist(ExternalSymbolData[i], Layout); - for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) - WriteNlist(UndefinedSymbolData[i], Layout); - - // Write the string table. - OS << StringTable.str(); - } - } -}; - } MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW, diff --git a/contrib/llvm/lib/MC/SubtargetFeature.cpp b/contrib/llvm/lib/MC/SubtargetFeature.cpp new file mode 100644 index 0000000..348cd4c --- /dev/null +++ b/contrib/llvm/lib/MC/SubtargetFeature.cpp @@ -0,0 +1,397 @@ +//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SubtargetFeature interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstdlib> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Static Helper Functions +//===----------------------------------------------------------------------===// + +/// hasFlag - Determine if a feature has a flag; '+' or '-' +/// +static inline bool hasFlag(const StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' or '-' flag + return Ch == '+' || Ch =='-'; +} + +/// StripFlag - Return string stripped of flag. +/// +static inline std::string StripFlag(const StringRef Feature) { + return hasFlag(Feature) ? Feature.substr(1) : Feature; +} + +/// isEnabled - Return true if enable flag; '+'. +/// +static inline bool isEnabled(const StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' for enabled + return Ch == '+'; +} + +/// PrependFlag - Return a string with a prepended flag; '+' or '-'. +/// +static inline std::string PrependFlag(const StringRef Feature, + bool IsEnabled) { + assert(!Feature.empty() && "Empty string"); + if (hasFlag(Feature)) + return Feature; + std::string Prefix = IsEnabled ? "+" : "-"; + Prefix += Feature; + return Prefix; +} + +/// Split - Splits a string of comma separated items in to a vector of strings. +/// +static void Split(std::vector<std::string> &V, const StringRef S) { + if (S.empty()) + return; + + // Start at beginning of string. + size_t Pos = 0; + while (true) { + // Find the next comma + size_t Comma = S.find(',', Pos); + // If no comma found then the rest of the string is used + if (Comma == std::string::npos) { + // Add string to vector + V.push_back(S.substr(Pos)); + break; + } + // Otherwise add substring to vector + V.push_back(S.substr(Pos, Comma - Pos)); + // Advance to next item + Pos = Comma + 1; + } +} + +/// Join a vector of strings to a string with a comma separating each element. +/// +static std::string Join(const std::vector<std::string> &V) { + // Start with empty string. + std::string Result; + // If the vector is not empty + if (!V.empty()) { + // Start with the first feature + Result = V[0]; + // For each successive feature + for (size_t i = 1; i < V.size(); i++) { + // Add a comma + Result += ","; + // Add the feature + Result += V[i]; + } + } + // Return the features string + return Result; +} + +/// Adding features. +void SubtargetFeatures::AddFeature(const StringRef String, + bool IsEnabled) { + // Don't add empty features + if (!String.empty()) { + // Convert to lowercase, prepend flag and add to vector + Features.push_back(PrependFlag(LowercaseString(String), IsEnabled)); + } +} + +/// Find KV in array using binary search. +template<typename T> const T *Find(const StringRef S, const T *A, size_t L) { + // Make the lower bound element we're looking for + T KV; + KV.Key = S.data(); + // Determine the end of the array + const T *Hi = A + L; + // Binary search the array + const T *F = std::lower_bound(A, Hi, KV); + // If not found then return NULL + if (F == Hi || StringRef(F->Key) != S) return NULL; + // Return the found array item + return F; +} + +/// getLongestEntryLength - Return the length of the longest entry in the table. +/// +static size_t getLongestEntryLength(const SubtargetFeatureKV *Table, + size_t Size) { + size_t MaxLen = 0; + for (size_t i = 0; i < Size; i++) + MaxLen = std::max(MaxLen, std::strlen(Table[i].Key)); + return MaxLen; +} + +/// Display help for feature choices. +/// +static void Help(const SubtargetFeatureKV *CPUTable, size_t CPUTableSize, + const SubtargetFeatureKV *FeatTable, size_t FeatTableSize) { + // Determine the length of the longest CPU and Feature entries. + unsigned MaxCPULen = getLongestEntryLength(CPUTable, CPUTableSize); + unsigned MaxFeatLen = getLongestEntryLength(FeatTable, FeatTableSize); + + // Print the CPU table. + errs() << "Available CPUs for this target:\n\n"; + for (size_t i = 0; i != CPUTableSize; i++) + errs() << " " << CPUTable[i].Key + << std::string(MaxCPULen - std::strlen(CPUTable[i].Key), ' ') + << " - " << CPUTable[i].Desc << ".\n"; + errs() << "\n"; + + // Print the Feature table. + errs() << "Available features for this target:\n\n"; + for (size_t i = 0; i != FeatTableSize; i++) + errs() << " " << FeatTable[i].Key + << std::string(MaxFeatLen - std::strlen(FeatTable[i].Key), ' ') + << " - " << FeatTable[i].Desc << ".\n"; + errs() << "\n"; + + errs() << "Use +feature to enable a feature, or -feature to disable it.\n" + << "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n"; + std::exit(1); +} + +//===----------------------------------------------------------------------===// +// SubtargetFeatures Implementation +//===----------------------------------------------------------------------===// + +SubtargetFeatures::SubtargetFeatures(const StringRef Initial) { + // Break up string into separate features + Split(Features, Initial); +} + + +std::string SubtargetFeatures::getString() const { + return Join(Features); +} + +/// SetImpliedBits - For each feature that is (transitively) implied by this +/// feature, set it. +/// +static +void SetImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + for (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + + if (FeatureEntry->Value == FE.Value) continue; + + if (FeatureEntry->Implies & FE.Value) { + Bits |= FE.Value; + SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } +} + +/// ClearImpliedBits - For each feature that (transitively) implies this +/// feature, clear it. +/// +static +void ClearImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + for (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + + if (FeatureEntry->Value == FE.Value) continue; + + if (FE.Implies & FeatureEntry->Value) { + Bits &= ~FE.Value; + ClearImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } +} + +/// ToggleFeature - Toggle a feature and returns the newly updated feature +/// bits. +uint64_t +SubtargetFeatures::ToggleFeature(uint64_t Bits, const StringRef Feature, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable, FeatureTableSize); + // If there is a match + if (FeatureEntry) { + if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) { + Bits &= ~FeatureEntry->Value; + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } else { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << Feature + << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } + + return Bits; +} + + +/// getFeatureBits - Get feature bits a CPU. +/// +uint64_t SubtargetFeatures::getFeatureBits(const StringRef CPU, + const SubtargetFeatureKV *CPUTable, + size_t CPUTableSize, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + if (!FeatureTableSize || !CPUTableSize) + return 0; + +#ifndef NDEBUG + for (size_t i = 1; i < CPUTableSize; i++) { + assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 && + "CPU table is not sorted"); + } + for (size_t i = 1; i < FeatureTableSize; i++) { + assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 && + "CPU features table is not sorted"); + } +#endif + uint64_t Bits = 0; // Resulting bits + + // Check if help is needed + if (CPU == "help") + Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); + + // Find CPU entry if CPU name is specified. + if (!CPU.empty()) { + const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable, CPUTableSize); + // If there is a match + if (CPUEntry) { + // Set base feature bits + Bits = CPUEntry->Value; + + // Set the feature implied by this CPU feature, if any. + for (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + if (CPUEntry->Value & FE.Value) + SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << CPU + << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + } + } + + // Iterate through each feature + for (size_t i = 0, E = Features.size(); i < E; i++) { + const StringRef Feature = Features[i]; + + // Check for help + if (Feature == "+help") + Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); + + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable, FeatureTableSize); + // If there is a match + if (FeatureEntry) { + // Enable/disable feature in bits + if (isEnabled(Feature)) { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } else { + Bits &= ~FeatureEntry->Value; + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << Feature + << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } + } + + return Bits; +} + +/// Get scheduling itinerary of a CPU. +void *SubtargetFeatures::getItinerary(const StringRef CPU, + const SubtargetInfoKV *Table, + size_t TableSize) { + assert(Table && "missing table"); +#ifndef NDEBUG + for (size_t i = 1; i < TableSize; i++) { + assert(strcmp(Table[i - 1].Key, Table[i].Key) < 0 && "Table is not sorted"); + } +#endif + + // Find entry + const SubtargetInfoKV *Entry = Find(CPU, Table, TableSize); + + if (Entry) { + return Entry->Value; + } else { + errs() << "'" << CPU + << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + return NULL; + } +} + +/// print - Print feature string. +/// +void SubtargetFeatures::print(raw_ostream &OS) const { + for (size_t i = 0, e = Features.size(); i != e; ++i) + OS << Features[i] << " "; + OS << "\n"; +} + +/// dump - Dump feature info. +/// +void SubtargetFeatures::dump() const { + print(dbgs()); +} + +/// getDefaultSubtargetFeatures - Return a string listing the features +/// associated with the target triple. +/// +/// FIXME: This is an inelegant way of specifying the features of a +/// subtarget. It would be better if we could encode this information +/// into the IR. See <rdar://5972456>. +/// +void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) { + if (Triple.getVendor() == Triple::Apple) { + if (Triple.getArch() == Triple::ppc) { + // powerpc-apple-* + AddFeature("altivec"); + } else if (Triple.getArch() == Triple::ppc64) { + // powerpc64-apple-* + AddFeature("64bit"); + AddFeature("altivec"); + } + } +} |