diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 |
commit | b915e9e0fc85ba6f398b3fab0db6a81a8913af94 (patch) | |
tree | 98b8f811c7aff2547cab8642daf372d6c59502fb /lib/MC | |
parent | 6421cca32f69ac849537a3cff78c352195e99f1b (diff) | |
download | src-b915e9e0fc85ba6f398b3fab0db6a81a8913af94.tar.gz src-b915e9e0fc85ba6f398b3fab0db6a81a8913af94.zip |
Vendor import of llvm trunk r290819:vendor/llvm/llvm-trunk-r290819
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=311116
svn path=/vendor/llvm/llvm-trunk-r290819/; revision=311117; tag=vendor/llvm/llvm-trunk-r290819
Diffstat (limited to 'lib/MC')
39 files changed, 1853 insertions, 1094 deletions
diff --git a/lib/MC/ConstantPools.cpp b/lib/MC/ConstantPools.cpp index 17a23d063b7d..9608c2c656b7 100644 --- a/lib/MC/ConstantPools.cpp +++ b/lib/MC/ConstantPools.cpp @@ -36,10 +36,20 @@ void ConstantPool::emitEntries(MCStreamer &Streamer) { const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context, unsigned Size, SMLoc Loc) { + const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Value); + + // Check if there is existing entry for the same constant. If so, reuse it. + auto Itr = C ? CachedEntries.find(C->getValue()) : CachedEntries.end(); + if (Itr != CachedEntries.end()) + return Itr->second; + MCSymbol *CPEntryLabel = Context.createTempSymbol(); Entries.push_back(ConstantPoolEntry(CPEntryLabel, Value, Size, Loc)); - return MCSymbolRefExpr::create(CPEntryLabel, Context); + const auto SymRef = MCSymbolRefExpr::create(CPEntryLabel, Context); + if (C) + CachedEntries[C->getValue()] = SymRef; + return SymRef; } bool ConstantPool::empty() { return Entries.empty(); } @@ -79,7 +89,7 @@ void AssemblerConstantPools::emitAll(MCStreamer &Streamer) { } void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) { - MCSection *Section = Streamer.getCurrentSection().first; + MCSection *Section = Streamer.getCurrentSectionOnly(); if (ConstantPool *CP = getConstantPool(Section)) { emitConstantPool(Streamer, Section, *CP); } @@ -88,7 +98,7 @@ void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) { const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer, const MCExpr *Expr, unsigned Size, SMLoc Loc) { - MCSection *Section = Streamer.getCurrentSection().first; + MCSection *Section = Streamer.getCurrentSectionOnly(); return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext(), Size, Loc); } diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index dc21b48ca6f6..a8c88dda6936 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -568,25 +568,27 @@ bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, // If we change such a relocation to use the section, the linker would think // that it pointed to another string and subtracting 42 at runtime will // produce the wrong value. - auto &Sec = cast<MCSectionELF>(Sym->getSection()); - unsigned Flags = Sec.getFlags(); - if (Flags & ELF::SHF_MERGE) { - if (C != 0) - return true; + if (Sym->isInSection()) { + auto &Sec = cast<MCSectionELF>(Sym->getSection()); + unsigned Flags = Sec.getFlags(); + if (Flags & ELF::SHF_MERGE) { + if (C != 0) + return true; - // It looks like gold has a bug (http://sourceware.org/PR16794) and can - // only handle section relocations to mergeable sections if using RELA. - if (!hasRelocationAddend()) + // It looks like gold has a bug (http://sourceware.org/PR16794) and can + // only handle section relocations to mergeable sections if using RELA. + if (!hasRelocationAddend()) + return true; + } + + // Most TLS relocations use a got, so they need the symbol. Even those that + // are just an offset (@tpoff), require a symbol in gold versions before + // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed + // http://sourceware.org/PR16773. + if (Flags & ELF::SHF_TLS) return true; } - // Most TLS relocations use a got, so they need the symbol. Even those that - // are just an offset (@tpoff), require a symbol in gold versions before - // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed - // http://sourceware.org/PR16773. - if (Flags & ELF::SHF_TLS) - return true; - // If the symbol is a thumb function the final relocation must set the lowest // bit. With a symbol that is done by just having the symbol have that bit // set, so we would lose the bit if we relocated with the section. @@ -1127,7 +1129,7 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1]; - getStream() << StrTabBuilder.data(); + StrTabBuilder.write(getStream()); return StrtabSection; } diff --git a/lib/MC/MCAsmBackend.cpp b/lib/MC/MCAsmBackend.cpp index b868b9d48896..570f764f6642 100644 --- a/lib/MC/MCAsmBackend.cpp +++ b/lib/MC/MCAsmBackend.cpp @@ -34,6 +34,10 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"FK_GPRel_2", 0, 16, 0}, {"FK_GPRel_4", 0, 32, 0}, {"FK_GPRel_8", 0, 64, 0}, + {"FK_DTPRel_4", 0, 32, 0}, + {"FK_DTPRel_8", 0, 64, 0}, + {"FK_TPRel_4", 0, 32, 0}, + {"FK_TPRel_8", 0, 64, 0}, {"FK_SecRel_1", 0, 8, 0}, {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index 4a05175fdec3..3eb8f50de5a8 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -31,7 +31,6 @@ MCAsmInfo::MCAsmInfo() { HasSubsectionsViaSymbols = false; HasMachoZeroFillDirective = false; HasMachoTBSSDirective = false; - HasStaticCtorDtorReferenceInStaticMode = false; MaxInstLength = 4; MinInstAlignment = 1; DollarIsPC = false; diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index fc60313dd6b2..e95cf488cd30 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -76,7 +76,6 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. HasMachoZeroFillDirective = true; // Uses .zerofill HasMachoTBSSDirective = true; // Uses .tbss - HasStaticCtorDtorReferenceInStaticMode = true; // FIXME: Change this once MC is the system assembler. HasAggressiveSymbolFolding = false; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index ef2f7810deaa..817009a65363 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" @@ -99,7 +100,7 @@ public: /// file if applicable as a QoI issue to make the output of the compiler /// more readable. This only affects the MCAsmStreamer, and only when /// verbose assembly output is enabled. - void AddComment(const Twine &T) override; + void AddComment(const Twine &T, bool EOL = true) override; /// AddEncodingComment - Add a comment showing the encoding of an instruction. void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &); @@ -149,8 +150,8 @@ public: void EndCOFFSymbolDef() override; void EmitCOFFSafeSEH(MCSymbol const *Symbol) override; void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; - void EmitCOFFSecRel32(MCSymbol const *Symbol) override; - void emitELFSize(MCSymbolELF *Symbol, const MCExpr *Value) override; + void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; + void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -180,6 +181,11 @@ public: void EmitSLEB128Value(const MCExpr *Value) override; + void EmitDTPRel32Value(const MCExpr *Value) override; + void EmitDTPRel64Value(const MCExpr *Value) override; + void EmitTPRel32Value(const MCExpr *Value) override; + void EmitTPRel64Value(const MCExpr *Value) override; + void EmitGPRel64Value(const MCExpr *Value) override; void EmitGPRel32Value(const MCExpr *Value) override; @@ -203,7 +209,8 @@ public: unsigned MaxBytesToEmit = 0) override; void emitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0) override; + unsigned char Value, + SMLoc Loc) override; void EmitFileDirective(StringRef Filename) override; unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, @@ -215,16 +222,21 @@ public: StringRef FileName) override; MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override; - unsigned EmitCVFileDirective(unsigned FileNo, StringRef Filename) override; + bool EmitCVFileDirective(unsigned FileNo, StringRef Filename) override; + bool EmitCVFuncIdDirective(unsigned FuncId) override; + bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc, + unsigned IAFile, unsigned IALine, + unsigned IACol, SMLoc Loc) override; void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, - StringRef FileName) override; + StringRef FileName, SMLoc Loc) override; void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart, const MCSymbol *FnEnd) override; - void EmitCVInlineLinetableDirective( - unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, - ArrayRef<unsigned> SecondaryFunctionIds) override; + void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, + unsigned SourceFileId, + unsigned SourceLineNum, + const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym) override; void EmitCVDefRangeDirective( ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, StringRef FixedSizePortion) override; @@ -289,12 +301,14 @@ public: /// file if applicable as a QoI issue to make the output of the compiler /// more readable. This only affects the MCAsmStreamer, and only when /// verbose assembly output is enabled. -void MCAsmStreamer::AddComment(const Twine &T) { +/// By deafult EOL is set to true so that each comment goes on its own line. +void MCAsmStreamer::AddComment(const Twine &T, bool EOL) { if (!IsVerboseAsm) return; T.toVector(CommentToEmit); - // Each comment goes on its own line. - CommentToEmit.push_back('\n'); + + if (EOL) + CommentToEmit.push_back('\n'); // Place comment in a new line. } void MCAsmStreamer::EmitCommentsAndEOL() { @@ -357,9 +371,10 @@ void MCAsmStreamer::addExplicitComment(const Twine &T) { ExplicitCommentToEmit.append("\t"); ExplicitCommentToEmit.append(c.str()); } else if (c.front() == '#') { - // # are comments for ## commentString. Output extra #. - ExplicitCommentToEmit.append("\t#"); - ExplicitCommentToEmit.append(c.str()); + + ExplicitCommentToEmit.append("\t"); + ExplicitCommentToEmit.append(MAI->getCommentString()); + ExplicitCommentToEmit.append(c.slice(1, c.size()).str()); } else assert(false && "Unexpected Assembly Comment"); // full line comments immediately output @@ -602,13 +617,15 @@ void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { EmitEOL(); } -void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { +void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) { OS << "\t.secrel32\t"; Symbol->print(OS, MAI); + if (Offset != 0) + OS << '+' << Offset; EmitEOL(); } -void MCAsmStreamer::emitELFSize(MCSymbolELF *Symbol, const MCExpr *Value) { +void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; Symbol->print(OS, MAI); @@ -737,7 +754,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { } void MCAsmStreamer::EmitBytes(StringRef Data) { - assert(getCurrentSection().first && + assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); if (Data.empty()) return; @@ -782,7 +799,7 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) { void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { assert(Size <= 8 && "Invalid size"); - assert(getCurrentSection().first && + assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); const char *Directive = nullptr; switch (Size) { @@ -855,6 +872,34 @@ void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { EmitEOL(); } +void MCAsmStreamer::EmitDTPRel64Value(const MCExpr *Value) { + assert(MAI->getDTPRel64Directive() != nullptr); + OS << MAI->getDTPRel64Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitDTPRel32Value(const MCExpr *Value) { + assert(MAI->getDTPRel32Directive() != nullptr); + OS << MAI->getDTPRel32Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitTPRel64Value(const MCExpr *Value) { + assert(MAI->getTPRel64Directive() != nullptr); + OS << MAI->getTPRel64Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitTPRel32Value(const MCExpr *Value) { + assert(MAI->getTPRel32Directive() != nullptr); + OS << MAI->getTPRel32Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { assert(MAI->getGPRel64Directive() != nullptr); OS << MAI->getGPRel64Directive(); @@ -971,7 +1016,8 @@ void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, } void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset, - unsigned char Value) { + unsigned char Value, + SMLoc Loc) { // FIXME: Verify that Offset is associated with the current section. OS << ".org "; Offset->print(OS, MAI); @@ -1068,29 +1114,43 @@ MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) { return MCStreamer::getDwarfLineTableSymbol(0); } -unsigned MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, - StringRef Filename) { - if (!getContext().getCVFile(Filename, FileNo)) - return 0; +bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { + if (!getContext().getCVContext().addFile(FileNo, Filename)) + return false; OS << "\t.cv_file\t" << FileNo << ' '; PrintQuotedString(Filename, OS); EmitEOL(); + return true; +} - return FileNo; +bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) { + OS << "\t.cv_func_id " << FuncId << '\n'; + return MCStreamer::EmitCVFuncIdDirective(FuncId); +} + +bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, + unsigned IAFunc, + unsigned IAFile, + unsigned IALine, unsigned IACol, + SMLoc Loc) { + OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc + << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n'; + return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, + IALine, IACol, Loc); } void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, - StringRef FileName) { + StringRef FileName, SMLoc Loc) { OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " " << Column; if (PrologueEnd) OS << " prologue_end"; - unsigned OldIsStmt = getContext().getCurrentCVLoc().isStmt(); + unsigned OldIsStmt = getContext().getCVContext().getCurrentCVLoc().isStmt(); if (IsStmt != OldIsStmt) { OS << " is_stmt "; @@ -1102,12 +1162,12 @@ void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, if (IsVerboseAsm) { OS.PadToColumn(MAI->getCommentColumn()); - OS << MAI->getCommentString() << ' ' << FileName << ':' - << Line << ':' << Column; + OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':' + << Column; } EmitEOL(); this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, - PrologueEnd, IsStmt, FileName); + PrologueEnd, IsStmt, FileName, Loc); } void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, @@ -1121,24 +1181,19 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId, this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd); } -void MCAsmStreamer::EmitCVInlineLinetableDirective( - unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, - ArrayRef<unsigned> SecondaryFunctionIds) { +void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, + unsigned SourceFileId, + unsigned SourceLineNum, + const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym) { OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId << ' ' << SourceLineNum << ' '; FnStartSym->print(OS, MAI); OS << ' '; FnEndSym->print(OS, MAI); - if (!SecondaryFunctionIds.empty()) { - OS << " contains"; - for (unsigned SecondaryFunctionId : SecondaryFunctionIds) - OS << ' ' << SecondaryFunctionId; - } EmitEOL(); this->MCStreamer::EmitCVInlineLinetableDirective( - PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym, - SecondaryFunctionIds); + PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); } void MCAsmStreamer::EmitCVDefRangeDirective( @@ -1531,8 +1586,9 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst, } } -void MCAsmStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { - assert(getCurrentSection().first && +void MCAsmStreamer::EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + assert(getCurrentSectionOnly() && "Cannot emit contents before setting section!"); // Show the encoding in a comment if we have a code emitter. diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 7a42108ceaf3..83fcec92e2b5 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -278,22 +278,29 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); MCValue Value; - if (!OF.getOffset().evaluateAsValue(Value, Layout)) - report_fatal_error("expected assembly-time absolute expression"); + if (!OF.getOffset().evaluateAsValue(Value, Layout)) { + getContext().reportError(OF.getLoc(), + "expected assembly-time absolute expression"); + return 0; + } - // FIXME: We need a way to communicate this error. uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t TargetLocation = Value.getConstant(); if (const MCSymbolRefExpr *A = Value.getSymA()) { uint64_t Val; - if (!Layout.getSymbolOffset(A->getSymbol(), Val)) - report_fatal_error("expected absolute expression"); + if (!Layout.getSymbolOffset(A->getSymbol(), Val)) { + getContext().reportError(OF.getLoc(), "expected absolute expression"); + return 0; + } TargetLocation += Val; } int64_t Size = TargetLocation - FragmentOffset; - if (Size < 0 || Size >= 0x40000000) - report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + - "' (at offset '" + Twine(FragmentOffset) + "')"); + if (Size < 0 || Size >= 0x40000000) { + getContext().reportError( + OF.getLoc(), "invalid .org offset '" + Twine(TargetLocation) + + "' (at offset '" + Twine(FragmentOffset) + "')"); + return 0; + } return Size; } @@ -575,8 +582,8 @@ void MCAssembler::writeSectionData(const MCSection *Sec, // into a virtual section. This is to support clients which use standard // directives to fill the contents of virtual sections. const MCDataFragment &DF = cast<MCDataFragment>(F); - assert(DF.fixup_begin() == DF.fixup_end() && - "Cannot have fixups in virtual section!"); + if (DF.fixup_begin() != DF.fixup_end()) + report_fatal_error("cannot have fixups in virtual section!"); for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) if (DF.getContents()[i]) { if (auto *ELFSec = dyn_cast<const MCSectionELF>(Sec)) @@ -660,7 +667,8 @@ void MCAssembler::layout(MCAsmLayout &Layout) { // Layout until everything fits. while (layoutOnce(Layout)) - continue; + if (getContext().hadError()) + return; DEBUG_WITH_TYPE("mc-dump", { llvm::errs() << "assembler backend - post-relaxation\n--\n"; @@ -912,7 +920,9 @@ bool MCAssembler::layoutOnce(MCAsmLayout &Layout) { void MCAssembler::finishLayout(MCAsmLayout &Layout) { // The layout is done. Mark every fragment as valid. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { - Layout.getFragmentOffset(&*Layout.getSectionOrder()[i]->rbegin()); + MCSection &Section = *Layout.getSectionOrder()[i]; + Layout.getFragmentOffset(&*Section.rbegin()); + computeFragmentSize(Layout, *Section.rbegin()); } getBackend().finishLayout(*this, Layout); } diff --git a/lib/MC/MCCodeView.cpp b/lib/MC/MCCodeView.cpp index 65cff41abebe..3773542cf8a2 100644 --- a/lib/MC/MCCodeView.cpp +++ b/lib/MC/MCCodeView.cpp @@ -65,6 +65,50 @@ bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { return true; } +bool CodeViewContext::recordFunctionId(unsigned FuncId) { + if (FuncId >= Functions.size()) + Functions.resize(FuncId + 1); + + // Return false if this function info was already allocated. + if (!Functions[FuncId].isUnallocatedFunctionInfo()) + return false; + + // Mark this as an allocated normal function, and leave the rest alone. + Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel; + return true; +} + +bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, + unsigned IAFile, unsigned IALine, + unsigned IACol) { + if (FuncId >= Functions.size()) + Functions.resize(FuncId + 1); + + // Return false if this function info was already allocated. + if (!Functions[FuncId].isUnallocatedFunctionInfo()) + return false; + + MCCVFunctionInfo::LineInfo InlinedAt; + InlinedAt.File = IAFile; + InlinedAt.Line = IALine; + InlinedAt.Col = IACol; + + // Mark this as an inlined call site and record call site line info. + MCCVFunctionInfo *Info = &Functions[FuncId]; + Info->ParentFuncIdPlusOne = IAFunc + 1; + Info->InlinedAt = InlinedAt; + + // Walk up the call chain adding this function id to the InlinedAtMap of all + // transitive callers until we hit a real function. + while (Info->isInlinedCallSite()) { + InlinedAt = Info->InlinedAt; + Info = getCVFunctionInfo(Info->getParentFuncId()); + Info->InlinedAtMap[FuncId] = InlinedAt; + } + + return true; +} + MCDataFragment *CodeViewContext::getStringTableFragment() { if (!StrTabFragment) { StrTabFragment = new MCDataFragment(); @@ -156,7 +200,7 @@ void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4); OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); OS.EmitLabel(LineBegin); - OS.EmitCOFFSecRel32(FuncBegin); + OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0); OS.EmitCOFFSectionIndex(FuncBegin); // Actual line info. @@ -237,15 +281,17 @@ static uint32_t encodeSignedNumber(uint32_t Data) { return Data << 1; } -void CodeViewContext::emitInlineLineTableForFunction( - MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId, - unsigned SourceLineNum, const MCSymbol *FnStartSym, - const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds) { +void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS, + unsigned PrimaryFunctionId, + unsigned SourceFileId, + unsigned SourceLineNum, + const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym) { // Create and insert a fragment into the current section that will be encoded // later. - new MCCVInlineLineTableFragment( - PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym, - SecondaryFunctionIds, OS.getCurrentSectionOnly()); + new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId, + SourceLineNum, FnStartSym, FnEndSym, + OS.getCurrentSectionOnly()); } void CodeViewContext::emitDefRange( @@ -280,69 +326,92 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, size_t LocBegin; size_t LocEnd; std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId); - for (unsigned SecondaryId : Frag.SecondaryFuncs) { - auto Extent = getLineExtent(SecondaryId); + + // Include all child inline call sites in our .cv_loc extent. + MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId); + for (auto &KV : SiteInfo->InlinedAtMap) { + unsigned ChildId = KV.first; + auto Extent = getLineExtent(ChildId); LocBegin = std::min(LocBegin, Extent.first); LocEnd = std::max(LocEnd, Extent.second); } + if (LocBegin >= LocEnd) return; ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd); if (Locs.empty()) return; - SmallSet<unsigned, 8> InlinedFuncIds; - InlinedFuncIds.insert(Frag.SiteFuncId); - InlinedFuncIds.insert(Frag.SecondaryFuncs.begin(), Frag.SecondaryFuncs.end()); - // Make an artificial start location using the function start and the inlinee // lines start location information. All deltas start relative to this // location. MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front())); StartLoc.setFileNum(Frag.StartFileId); StartLoc.setLine(Frag.StartLineNum); - const MCCVLineEntry *LastLoc = &StartLoc; bool HaveOpenRange = false; + const MCSymbol *LastLabel = Frag.getFnStartSym(); + MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc; + LastSourceLoc.File = Frag.StartFileId; + LastSourceLoc.Line = Frag.StartLineNum; + SmallVectorImpl<char> &Buffer = Frag.getContents(); Buffer.clear(); // Clear old contents if we went through relaxation. for (const MCCVLineEntry &Loc : Locs) { - if (!InlinedFuncIds.count(Loc.getFunctionId())) { - // We've hit a cv_loc not attributed to this inline call site. Use this - // label to end the PC range. - if (HaveOpenRange) { - unsigned Length = - computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel()); - compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); - compressAnnotation(Length, Buffer); + // Exit early if our line table would produce an oversized InlineSiteSym + // record. Account for the ChangeCodeLength annotation emitted after the + // loop ends. + constexpr uint32_t InlineSiteSize = 12; + constexpr uint32_t AnnotationSize = 8; + size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize; + if (Buffer.size() >= MaxBufferSize) + break; + + if (Loc.getFunctionId() == Frag.SiteFuncId) { + CurSourceLoc.File = Loc.getFileNum(); + CurSourceLoc.Line = Loc.getLine(); + } else { + auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId()); + if (I != SiteInfo->InlinedAtMap.end()) { + // This .cv_loc is from a child inline call site. Use the source + // location of the inlined call site instead of the .cv_loc directive + // source location. + CurSourceLoc = I->second; + } else { + // We've hit a cv_loc not attributed to this inline call site. Use this + // label to end the PC range. + if (HaveOpenRange) { + unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); + compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); + compressAnnotation(Length, Buffer); + LastLabel = Loc.getLabel(); + } + HaveOpenRange = false; + continue; } - HaveOpenRange = false; - continue; } - // If we've already opened the function and we're at an indirectly inlined - // location, continue until the next directly inlined location. - bool DirectlyInlined = Loc.getFunctionId() == Frag.SiteFuncId; - if (!DirectlyInlined && HaveOpenRange) + // Skip this .cv_loc if we have an open range and this isn't a meaningful + // source location update. The current table format does not support column + // info, so we can skip updates for those. + if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File && + CurSourceLoc.Line == LastSourceLoc.Line) continue; + HaveOpenRange = true; - if (Loc.getFileNum() != LastLoc->getFileNum()) { + if (CurSourceLoc.File != LastSourceLoc.File) { // File ids are 1 based, and each file checksum table entry is 8 bytes // long. See emitFileChecksums above. - unsigned FileOffset = 8 * (Loc.getFileNum() - 1); + unsigned FileOffset = 8 * (CurSourceLoc.File - 1); compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); compressAnnotation(FileOffset, Buffer); } - int LineDelta = Loc.getLine() - LastLoc->getLine(); - if (LineDelta == 0) - continue; - + int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line; unsigned EncodedLineDelta = encodeSignedNumber(LineDelta); - unsigned CodeDelta = - computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel()); - if (CodeDelta == 0) { + unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); + if (CodeDelta == 0 && LineDelta != 0) { compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); compressAnnotation(EncodedLineDelta, Buffer); } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) { @@ -355,29 +424,29 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, compressAnnotation(Operand, Buffer); } else { // Otherwise use the separate line and code deltas. - compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); - compressAnnotation(EncodedLineDelta, Buffer); + if (LineDelta != 0) { + compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); + compressAnnotation(EncodedLineDelta, Buffer); + } compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer); compressAnnotation(CodeDelta, Buffer); } - LastLoc = &Loc; + LastLabel = Loc.getLabel(); + LastSourceLoc = CurSourceLoc; } assert(HaveOpenRange); unsigned EndSymLength = - computeLabelDiff(Layout, LastLoc->getLabel(), Frag.getFnEndSym()); + computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym()); unsigned LocAfterLength = ~0U; ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); if (!LocAfter.empty()) { // Only try to compute this difference if we're in the same section. const MCCVLineEntry &Loc = LocAfter[0]; - if (&Loc.getLabel()->getSection(false) == - &LastLoc->getLabel()->getSection(false)) { - LocAfterLength = - computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel()); - } + if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false)) + LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); } compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); @@ -393,16 +462,41 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, Fixups.clear(); raw_svector_ostream OS(Contents); - // Write down each range where the variable is defined. + // Compute all the sizes up front. + SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes; + const MCSymbol *LastLabel = nullptr; for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) { + unsigned GapSize = + LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0; unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second); + GapAndRangeSizes.push_back({GapSize, RangeSize}); + LastLabel = Range.second; + } + + // Write down each range where the variable is defined. + for (size_t I = 0, E = Frag.getRanges().size(); I != E;) { + // If the range size of multiple consecutive ranges is under the max, + // combine the ranges and emit some gaps. + const MCSymbol *RangeBegin = Frag.getRanges()[I].first; + unsigned RangeSize = GapAndRangeSizes[I].second; + size_t J = I + 1; + for (; J != E; ++J) { + unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second; + if (RangeSize + GapAndRangeSize > MaxDefRange) + break; + RangeSize += GapAndRangeSize; + } + unsigned NumGaps = J - I - 1; + + support::endian::Writer<support::little> LEWriter(OS); + unsigned Bias = 0; // We must split the range into chunks of MaxDefRange, this is a fundamental // limitation of the file format. do { uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize); - const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx); + const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx); const MCBinaryExpr *BE = MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx); MCValue Res; @@ -413,8 +507,8 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, StringRef FixedSizePortion = Frag.getFixedSizePortion(); // Our record is a fixed sized prefix and a LocalVariableAddrRange that we // are artificially constructing. - size_t RecordSize = - FixedSizePortion.size() + sizeof(LocalVariableAddrRange); + size_t RecordSize = FixedSizePortion.size() + + sizeof(LocalVariableAddrRange) + 4 * NumGaps; // Write out the recrod size. support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize); // Write out the fixed size prefix. @@ -427,12 +521,25 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2)); Contents.resize(Contents.size() + 2); // Fixup for section index. // Write down the range's extent. - support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk); + LEWriter.write<uint16_t>(Chunk); // Move on to the next range. Bias += Chunk; RangeSize -= Chunk; } while (RangeSize > 0); + + // Emit the gaps afterwards. + assert((NumGaps == 0 || Bias < MaxDefRange) && + "large ranges should not have gaps"); + unsigned GapStartOffset = GapAndRangeSizes[I].second; + for (++I; I != J; ++I) { + unsigned GapSize, RangeSize; + assert(I < GapAndRangeSizes.size()); + std::tie(GapSize, RangeSize) = GapAndRangeSizes[I]; + LEWriter.write<uint16_t>(GapStartOffset); + LEWriter.write<uint16_t>(RangeSize); + GapStartOffset += GapSize + RangeSize; + } } } @@ -442,7 +549,8 @@ void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, // a line entry made for it is made. // void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { - if (!MCOS->getContext().getCVLocSeen()) + CodeViewContext &CVC = MCOS->getContext().getCVContext(); + if (!CVC.getCVLocSeen()) return; // Create a symbol at in the current section for use in the line entry. @@ -451,14 +559,14 @@ void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { MCOS->EmitLabel(LineSym); // Get the current .loc info saved in the context. - const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc(); + const MCCVLoc &CVLoc = CVC.getCurrentCVLoc(); // Create a (local) line entry with the symbol and the current .loc info. MCCVLineEntry LineEntry(LineSym, CVLoc); // clear CVLocSeen saying the current .loc info is now used. - MCOS->getContext().clearCVLocSeen(); + CVC.clearCVLocSeen(); // Add the line entry to this section's entries. - MCOS->getContext().getCVContext().addLineEntry(LineEntry); + CVC.addLineEntry(LineEntry); } diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 47ed1ca3add5..4798991ceed6 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -125,15 +125,15 @@ MCSymbol *MCContext::getOrCreateSymbol(const Twine &Name) { } MCSymbolELF *MCContext::getOrCreateSectionSymbol(const MCSectionELF &Section) { - MCSymbolELF *&Sym = SectionSymbols[&Section]; + MCSymbol *&Sym = SectionSymbols[&Section]; if (Sym) - return Sym; + return cast<MCSymbolELF>(Sym); StringRef Name = Section.getSectionName(); auto NameIter = UsedNames.insert(std::make_pair(Name, false)).first; Sym = new (&*NameIter, *this) MCSymbolELF(&*NameIter, /*isTemporary*/ false); - return Sym; + return cast<MCSymbolELF>(Sym); } MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName, @@ -173,7 +173,7 @@ MCSymbol *MCContext::createSymbol(StringRef Name, bool AlwaysAddSuffix, if (CanBeUnnamed && !UseNamesOnTempLabels) return createSymbolImpl(nullptr, true); - // Determine whether this is an user writter assembler temporary or normal + // Determine whether this is a user written assembler temporary or normal // label, if used. bool IsTemporary = CanBeUnnamed; if (AllowTemporaryLabels && !IsTemporary) @@ -260,6 +260,13 @@ MCSymbol *MCContext::lookupSymbol(const Twine &Name) const { return Symbols.lookup(NameRef); } +void MCContext::setSymbolValue(MCStreamer &Streamer, + StringRef Sym, + uint64_t Val) { + auto Symbol = getOrCreateSymbol(Sym); + Streamer.EmitAssignment(Symbol, MCConstantExpr::create(Val, *this)); +} + //===----------------------------------------------------------------------===// // Section Management //===----------------------------------------------------------------------===// @@ -361,7 +368,9 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, StringRef CachedName = Entry.first.SectionName; SectionKind Kind; - if (Flags & ELF::SHF_EXECINSTR) + if (Flags & ELF::SHF_ARM_PURECODE) + Kind = SectionKind::getExecuteOnly(); + else if (Flags & ELF::SHF_EXECINSTR) Kind = SectionKind::getText(); else Kind = SectionKind::getReadOnly(); @@ -494,14 +503,6 @@ CodeViewContext &MCContext::getCVContext() { return *CVContext.get(); } -unsigned MCContext::getCVFile(StringRef FileName, unsigned FileNumber) { - return getCVContext().addFile(FileNumber, FileName) ? FileNumber : 0; -} - -bool MCContext::isValidCVFileNumber(unsigned FileNumber) { - return getCVContext().isValidFileNumber(FileNumber); -} - //===----------------------------------------------------------------------===// // Error Reporting //===----------------------------------------------------------------------===// diff --git a/lib/MC/MCDisassembler/Disassembler.cpp b/lib/MC/MCDisassembler/Disassembler.cpp index 21e8748b797a..aa5072743bdf 100644 --- a/lib/MC/MCDisassembler/Disassembler.cpp +++ b/lib/MC/MCDisassembler/Disassembler.cpp @@ -9,6 +9,9 @@ #include "Disassembler.h" #include "llvm-c/Disassembler.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -16,12 +19,19 @@ #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCInstrItineraries.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSchedule.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetRegistry.h" +#include <cassert> +#include <cstddef> +#include <cstring> using namespace llvm; @@ -116,7 +126,7 @@ LLVMDisasmContextRef LLVMCreateDisasm(const char *TT, void *DisInfo, // LLVMDisasmDispose() disposes of the disassembler specified by the context. // void LLVMDisasmDispose(LLVMDisasmContextRef DCR){ - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); delete DC; } @@ -128,7 +138,7 @@ static void emitComments(LLVMDisasmContext *DC, StringRef Comments = DC->CommentsToEmit.str(); // Get the default information for printing a comment. const MCAsmInfo *MAI = DC->getAsmInfo(); - const char *CommentBegin = MAI->getCommentString(); + StringRef CommentBegin = MAI->getCommentString(); unsigned CommentColumn = MAI->getCommentColumn(); bool IsFirst = true; while (!Comments.empty()) { @@ -211,7 +221,6 @@ static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) { return Latency; } - /// \brief Emits latency information in DC->CommentStream for \p Inst, based /// on the information available in \p DC. static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) { @@ -239,7 +248,7 @@ static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) { size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, uint64_t BytesSize, uint64_t PC, char *OutString, size_t OutStringSize){ - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject. ArrayRef<uint8_t> Data(Bytes, BytesSize); @@ -288,21 +297,21 @@ size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, // int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){ if (Options & LLVMDisassembler_Option_UseMarkup){ - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); MCInstPrinter *IP = DC->getIP(); - IP->setUseMarkup(1); + IP->setUseMarkup(true); DC->addOptions(LLVMDisassembler_Option_UseMarkup); Options &= ~LLVMDisassembler_Option_UseMarkup; } if (Options & LLVMDisassembler_Option_PrintImmHex){ - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); MCInstPrinter *IP = DC->getIP(); - IP->setPrintImmHex(1); + IP->setPrintImmHex(true); DC->addOptions(LLVMDisassembler_Option_PrintImmHex); Options &= ~LLVMDisassembler_Option_PrintImmHex; } if (Options & LLVMDisassembler_Option_AsmPrinterVariant){ - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); // Try to set up the new instruction printer. const MCAsmInfo *MAI = DC->getAsmInfo(); const MCInstrInfo *MII = DC->getInstrInfo(); @@ -318,14 +327,14 @@ int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){ } } if (Options & LLVMDisassembler_Option_SetInstrComments) { - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); MCInstPrinter *IP = DC->getIP(); IP->setCommentStream(DC->CommentStream); DC->addOptions(LLVMDisassembler_Option_SetInstrComments); Options &= ~LLVMDisassembler_Option_SetInstrComments; } if (Options & LLVMDisassembler_Option_PrintLatency) { - LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); DC->addOptions(LLVMDisassembler_Option_PrintLatency); Options &= ~LLVMDisassembler_Option_PrintLatency; } diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 54b2c918c849..a7551a3283a3 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -122,7 +122,8 @@ EmitDwarfLineTable(MCObjectStreamer *MCOS, MCSection *Section, MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); MCOS->EmitULEB128IntValue(Column); } - if (Discriminator != LineEntry.getDiscriminator()) { + if (Discriminator != LineEntry.getDiscriminator() && + MCOS->getContext().getDwarfVersion() >= 4) { Discriminator = LineEntry.getDiscriminator(); unsigned Size = getULEB128Size(Discriminator); MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); @@ -916,7 +917,7 @@ void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS, MCContext &context = MCOS->getContext(); // We won't create dwarf labels for symbols in sections that we are not // generating debug info for. - if (!context.getGenDwarfSectionSyms().count(MCOS->getCurrentSection().first)) + if (!context.getGenDwarfSectionSyms().count(MCOS->getCurrentSectionOnly())) return; // The dwarf label's name does not have the symbol name's leading diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 7d858c306d2e..0ef1b2a8bdca 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -329,8 +329,8 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, ->setSize(MCConstantExpr::create(Size, getContext())); } -void MCELFStreamer::emitELFSize(MCSymbolELF *Symbol, const MCExpr *Value) { - Symbol->setSize(Value); +void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + cast<MCSymbolELF>(Symbol)->setSize(Value); } void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 6f90ff843bd0..bcc43a54d620 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -129,12 +129,10 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const { llvm_unreachable("Invalid expression kind!"); } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCExpr::dump() const { dbgs() << *this; dbgs() << '\n'; } -#endif /* *** */ @@ -277,6 +275,10 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_Hexagon_IE: return "IE"; case VK_Hexagon_IE_GOT: return "IEGOT"; case VK_WebAssembly_FUNCTION: return "FUNCTION"; + case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; + case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; + case VK_AMDGPU_REL32_LO: return "rel32@lo"; + case VK_AMDGPU_REL32_HI: return "rel32@hi"; } llvm_unreachable("Invalid variant kind"); } @@ -374,6 +376,10 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("prel31", VK_ARM_PREL31) .Case("sbrel", VK_ARM_SBREL) .Case("tlsldo", VK_ARM_TLSLDO) + .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) + .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) + .Case("rel32@lo", VK_AMDGPU_REL32_LO) + .Case("rel32@hi", VK_AMDGPU_REL32_HI) .Default(VK_Invalid); } diff --git a/lib/MC/MCFragment.cpp b/lib/MC/MCFragment.cpp index 1eb1d2996cb1..8ff8f8aba1c1 100644 --- a/lib/MC/MCFragment.cpp +++ b/lib/MC/MCFragment.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCFragment.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" @@ -231,13 +232,7 @@ uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler, /* *** */ -void ilist_node_traits<MCFragment>::deleteNode(MCFragment *V) { - V->destroy(); -} - -MCFragment::MCFragment() : Kind(FragmentType(~0)), HasInstructions(false), - AlignToBundleEnd(false), BundlePadding(0) { -} +void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); } MCFragment::~MCFragment() { } @@ -315,7 +310,6 @@ raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) { } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCFragment::dump() { raw_ostream &OS = llvm::errs(); @@ -475,4 +469,3 @@ LLVM_DUMP_METHOD void MCAssembler::dump() { } OS << "]>\n"; } -#endif diff --git a/lib/MC/MCInst.cpp b/lib/MC/MCInst.cpp index 16bc597cf3a2..2da8ecc4ff6a 100644 --- a/lib/MC/MCInst.cpp +++ b/lib/MC/MCInst.cpp @@ -34,12 +34,10 @@ void MCOperand::print(raw_ostream &OS) const { OS << ">"; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCOperand::dump() const { print(dbgs()); dbgs() << "\n"; } -#endif void MCInst::print(raw_ostream &OS) const { OS << "<MCInst " << getOpcode(); @@ -65,9 +63,7 @@ void MCInst::dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer, OS << ">"; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCInst::dump() const { print(dbgs()); dbgs() << "\n"; } -#endif diff --git a/lib/MC/MCLabel.cpp b/lib/MC/MCLabel.cpp index d973fc93b98c..b443cbbbf43e 100644 --- a/lib/MC/MCLabel.cpp +++ b/lib/MC/MCLabel.cpp @@ -16,8 +16,6 @@ void MCLabel::print(raw_ostream &OS) const { OS << '"' << getInstance() << '"'; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCLabel::dump() const { print(dbgs()); } -#endif diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index d05bcea14c98..8fd71f62e4e5 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -177,20 +177,6 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { MachO::S_THREAD_LOCAL_VARIABLE_POINTERS, SectionKind::getMetadata()); - if (!PositionIndependent) { - StaticCtorSection = Ctx->getMachOSection("__TEXT", "__constructor", 0, - SectionKind::getData()); - StaticDtorSection = Ctx->getMachOSection("__TEXT", "__destructor", 0, - SectionKind::getData()); - } else { - StaticCtorSection = Ctx->getMachOSection("__DATA", "__mod_init_func", - MachO::S_MOD_INIT_FUNC_POINTERS, - SectionKind::getData()); - StaticDtorSection = Ctx->getMachOSection("__DATA", "__mod_term_func", - MachO::S_MOD_TERM_FUNC_POINTERS, - SectionKind::getData()); - } - // Exception Handling. LSDASection = Ctx->getMachOSection("__TEXT", "__gcc_except_tab", 0, SectionKind::getReadOnlyWithRel()); @@ -311,6 +297,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { if (Ctx->getAsmInfo()->getExceptionHandlingType() == ExceptionHandling::ARM) break; // Fallthrough if not using EHABI + LLVM_FALLTHROUGH; case Triple::ppc: case Triple::x86: PersonalityEncoding = PositionIndependent @@ -395,6 +382,14 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { dwarf::DW_EH_PE_sdata4; // We don't support PC-relative LSDA references in GAS so we use the default // DW_EH_PE_absptr for those. + + // FreeBSD must be explicit about the data size and using pcrel since it's + // assembler/linker won't do the automatic conversion that the Linux tools + // do. + if (T.isOSFreeBSD()) { + PersonalityEncoding |= dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + } break; case Triple::ppc64: case Triple::ppc64le: @@ -498,12 +493,6 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { Ctx->getELFSection(".rodata.cst32", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 32, ""); - StaticCtorSection = Ctx->getELFSection(".ctors", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | ELF::SHF_WRITE); - - StaticDtorSection = Ctx->getELFSection(".dtors", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | ELF::SHF_WRITE); - // Exception Handling Sections. // FIXME: We're emitting LSDA info into a readonly section on ELF, even though @@ -621,26 +610,6 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { ".rdata", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); - if (T.isKnownWindowsMSVCEnvironment() || T.isWindowsItaniumEnvironment()) { - StaticCtorSection = - Ctx->getCOFFSection(".CRT$XCU", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ, - SectionKind::getReadOnly()); - StaticDtorSection = - Ctx->getCOFFSection(".CRT$XTX", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ, - SectionKind::getReadOnly()); - } else { - StaticCtorSection = Ctx->getCOFFSection( - ".ctors", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getData()); - StaticDtorSection = Ctx->getCOFFSection( - ".dtors", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getData()); - } - // FIXME: We're emitting LSDA info into a readonly section on COFF, even // though it contains relocatable pointers. In PIC mode, this is probably a // big runtime hit for C++ apps. Either the contents of the LSDA need to be diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index d2ac0f50261d..cae5c1f8d156 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" @@ -127,7 +128,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, flushPendingLabels(DF, DF->getContents().size()); MCCVLineEntry::Make(this); - MCDwarfLineEntry::Make(this, getCurrentSection().first); + MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // Avoid fixups when possible. int64_t AbsValue; @@ -235,7 +236,7 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst, // Now that a machine instruction has been assembled into this section, make // a line entry for any .loc directive that has been seen. MCCVLineEntry::Make(this); - MCDwarfLineEntry::Make(this, getCurrentSection().first); + MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // If this instruction doesn't need relaxation, just emit it as data. MCAssembler &Assembler = getAssembler(); @@ -304,7 +305,7 @@ void MCObjectStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, StringRef FileName) { // In case we see two .loc directives in a row, make sure the // first one gets a line entry. - MCDwarfLineEntry::Make(this, getCurrentSection().first); + MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, Isa, Discriminator, FileName); @@ -368,13 +369,13 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, - StringRef FileName) { + StringRef FileName, SMLoc Loc) { // In case we see two .cv_loc directives in a row, make sure the // first one gets a line entry. MCCVLineEntry::Make(this); this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, - PrologueEnd, IsStmt, FileName); + PrologueEnd, IsStmt, FileName, Loc); } void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId, @@ -387,14 +388,12 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId, void MCObjectStreamer::EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, - ArrayRef<unsigned> SecondaryFunctionIds) { + const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) { getContext().getCVContext().emitInlineLineTableForFunction( *this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, - FnEndSym, SecondaryFunctionIds); + FnEndSym); this->MCStreamer::EmitCVInlineLinetableDirective( - PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym, - SecondaryFunctionIds); + PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); } void MCObjectStreamer::EmitCVDefRangeDirective( @@ -414,7 +413,7 @@ void MCObjectStreamer::EmitCVFileChecksumsDirective() { void MCObjectStreamer::EmitBytes(StringRef Data) { MCCVLineEntry::Make(this); - MCDwarfLineEntry::Make(this, getCurrentSection().first); + MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); @@ -429,7 +428,7 @@ void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, insert(new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit)); // Update the maximum alignment on the current section if necessary. - MCSection *CurSec = getCurrentSection().first; + MCSection *CurSec = getCurrentSectionOnly(); if (ByteAlignment > CurSec->getAlignment()) CurSec->setAlignment(ByteAlignment); } @@ -441,8 +440,49 @@ void MCObjectStreamer::EmitCodeAlignment(unsigned ByteAlignment, } void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - insert(new MCOrgFragment(*Offset, Value)); + unsigned char Value, + SMLoc Loc) { + insert(new MCOrgFragment(*Offset, Value, Loc)); +} + +// Associate DTPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitDTPRel32Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_DTPRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +// Associate DTPRel64 fixup with data and resize data area +void MCObjectStreamer::EmitDTPRel64Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_DTPRel_8)); + DF->getContents().resize(DF->getContents().size() + 8, 0); +} + +// Associate TPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitTPRel32Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_TPRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +// Associate TPRel64 fixup with data and resize data area +void MCObjectStreamer::EmitTPRel64Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_TPRel_8)); + DF->getContents().resize(DF->getContents().size() + 8, 0); } // Associate GPRel32 fixup with data and resize data area @@ -455,7 +495,7 @@ void MCObjectStreamer::EmitGPRel32Value(const MCExpr *Value) { DF->getContents().resize(DF->getContents().size() + 4, 0); } -// Associate GPRel32 fixup with data and resize data area +// Associate GPRel64 fixup with data and resize data area void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); @@ -491,9 +531,7 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, } void MCObjectStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) { - const MCSection *Sec = getCurrentSection().first; - (void)Sec; - assert(Sec && "need a section"); + assert(getCurrentSectionOnly() && "need a section"); insert(new MCFillFragment(FillValue, NumBytes)); } diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index d56071aea4df..87ecf9e0227f 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -12,19 +12,28 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/SaveAndRestore.h" +#include <cassert> #include <cctype> -#include <cerrno> #include <cstdio> -#include <cstdlib> +#include <cstring> +#include <string> +#include <tuple> +#include <utility> + using namespace llvm; -AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) { - CurPtr = nullptr; - IsAtStartOfLine = true; - IsAtStartOfStatement = true; +AsmLexer::AsmLexer(const MCAsmInfo &MAI) + : MAI(MAI), CurPtr(nullptr), IsAtStartOfLine(true), + IsAtStartOfStatement(true), IsParsingMSInlineAsm(false), + IsPeeking(false) { AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); } @@ -133,6 +142,7 @@ static bool IsIdentifierChar(char c, bool AllowAt) { return isalnum(c) || c == '_' || c == '$' || c == '.' || (c == '@' && AllowAt) || c == '?'; } + AsmToken AsmLexer::LexIdentifier() { // Check for floating point literals. if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { @@ -171,12 +181,19 @@ AsmToken AsmLexer::LexSlash() { // C Style comment. ++CurPtr; // skip the star. + const char *CommentTextStart = CurPtr; while (CurPtr != CurBuf.end()) { switch (*CurPtr++) { case '*': // End of the comment? if (*CurPtr != '/') break; + // If we have a CommentConsumer, notify it about the comment. + if (CommentConsumer) { + CommentConsumer->HandleComment( + SMLoc::getFromPointer(CommentTextStart), + StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); + } ++CurPtr; // End the */. return AsmToken(AsmToken::Comment, StringRef(TokStart, CurPtr - TokStart)); @@ -192,12 +209,20 @@ AsmToken AsmLexer::LexLineComment() { // comment. While it would be nicer to leave this two tokens, // backwards compatability with TargetParsers makes keeping this in this form // better. + const char *CommentTextStart = CurPtr; int CurChar = getNextChar(); while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) CurChar = getNextChar(); + // If we have a CommentConsumer, notify it about the comment. + if (CommentConsumer) { + CommentConsumer->HandleComment( + SMLoc::getFromPointer(CommentTextStart), + StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); + } + IsAtStartOfLine = true; - // Whis is a whole line comment. leave newline + // This is a whole line comment. leave newline if (IsAtStartOfStatement) return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, CurPtr - TokStart)); @@ -222,7 +247,7 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { const char *FirstHex = nullptr; const char *LookAhead = CurPtr; - while (1) { + while (true) { if (isdigit(*LookAhead)) { ++LookAhead; } else if (isxdigit(*LookAhead)) { @@ -255,6 +280,45 @@ static AsmToken intToken(StringRef Ref, APInt &Value) /// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] /// Decimal integer: [1-9][0-9]* AsmToken AsmLexer::LexDigit() { + // MASM-flavor binary integer: [01]+[bB] + // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH] + if (IsParsingMSInlineAsm && isdigit(CurPtr[-1])) { + const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ? + CurPtr - 1 : nullptr; + const char *OldCurPtr = CurPtr; + while (isxdigit(*CurPtr)) { + if (*CurPtr != '0' && *CurPtr != '1' && !FirstNonBinary) + FirstNonBinary = CurPtr; + ++CurPtr; + } + + unsigned Radix = 0; + if (*CurPtr == 'h' || *CurPtr == 'H') { + // hexadecimal number + ++CurPtr; + Radix = 16; + } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr && + (*FirstNonBinary == 'b' || *FirstNonBinary == 'B')) + Radix = 2; + + if (Radix == 2 || Radix == 16) { + StringRef Result(TokStart, CurPtr - TokStart); + APInt Value(128, 0, true); + + if (Result.drop_back().getAsInteger(Radix, Value)) + return ReturnError(TokStart, Radix == 2 ? "invalid binary number" : + "invalid hexdecimal number"); + + // MSVC accepts and ignores type suffices on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(Result, Value); + } + + // octal/decimal integers, or floating point numbers, fall through + CurPtr = OldCurPtr; + } + // Decimal integer: [1-9][0-9]* if (CurPtr[-1] != '0' || CurPtr[0] == '.') { unsigned Radix = doLookAhead(CurPtr, 10); @@ -283,7 +347,7 @@ AsmToken AsmLexer::LexDigit() { return intToken(Result, Value); } - if ((*CurPtr == 'b') || (*CurPtr == 'B')) { + if (!IsParsingMSInlineAsm && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { ++CurPtr; // See if we actually have "0b" as part of something like "jmp 0b\n" if (!isdigit(CurPtr[0])) { @@ -332,7 +396,7 @@ AsmToken AsmLexer::LexDigit() { return ReturnError(TokStart, "invalid hexadecimal number"); // Consume the optional [hH]. - if (*CurPtr == 'h' || *CurPtr == 'H') + if (!IsParsingMSInlineAsm && (*CurPtr == 'h' || *CurPtr == 'H')) ++CurPtr; // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL @@ -397,7 +461,6 @@ AsmToken AsmLexer::LexSingleQuote() { return AsmToken(AsmToken::Integer, Res, Value); } - /// LexQuote: String: "..." AsmToken AsmLexer::LexQuote() { int CurChar = getNextChar(); @@ -439,17 +502,15 @@ StringRef AsmLexer::LexUntilEndOfLine() { size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, bool ShouldSkipSpace) { - const char *SavedTokStart = TokStart; - const char *SavedCurPtr = CurPtr; - bool SavedAtStartOfLine = IsAtStartOfLine; - bool SavedAtStartOfStatement = IsAtStartOfStatement; - bool SavedSkipSpace = SkipSpace; - + SaveAndRestore<const char *> SavedTokenStart(TokStart); + SaveAndRestore<const char *> SavedCurPtr(CurPtr); + SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine); + SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement); + SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace); + SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true); std::string SavedErr = getErr(); SMLoc SavedErrLoc = getErrLoc(); - SkipSpace = ShouldSkipSpace; - size_t ReadCount; for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) { AsmToken Token = LexToken(); @@ -461,27 +522,20 @@ size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, } SetError(SavedErrLoc, SavedErr); - - SkipSpace = SavedSkipSpace; - IsAtStartOfLine = SavedAtStartOfLine; - IsAtStartOfStatement = SavedAtStartOfStatement; - CurPtr = SavedCurPtr; - TokStart = SavedTokStart; - return ReadCount; } bool AsmLexer::isAtStartOfComment(const char *Ptr) { - const char *CommentString = MAI.getCommentString(); + StringRef CommentString = MAI.getCommentString(); - if (CommentString[1] == '\0') + if (CommentString.size() == 1) return CommentString[0] == Ptr[0]; - // FIXME: special case for the bogus "##" comment string in X86MCAsmInfoDarwin + // Allow # preprocessor commments also be counted as comments for "##" cases if (CommentString[1] == '#') return CommentString[0] == Ptr[0]; - return strncmp(Ptr, CommentString, strlen(CommentString)) == 0; + return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0; } bool AsmLexer::isAtStatementSeparator(const char *Ptr) { @@ -494,7 +548,7 @@ AsmToken AsmLexer::LexToken() { // This always consumes at least one character. int CurChar = getNextChar(); - if (CurChar == '#' && IsAtStartOfStatement) { + if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) { // If this starts with a '#', this may be a cpp // hash directive and otherwise a line comment. AsmToken TokenBuf[2]; @@ -600,7 +654,46 @@ AsmToken AsmLexer::LexToken() { return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); } return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); - case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); + case '%': + if (MAI.hasMipsExpressions()) { + AsmToken::TokenKind Operator; + unsigned OperatorLength; + + std::tie(Operator, OperatorLength) = + StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>( + StringRef(CurPtr)) + .StartsWith("call16", {AsmToken::PercentCall16, 7}) + .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8}) + .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8}) + .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10}) + .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10}) + .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9}) + .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7}) + .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7}) + .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9}) + .StartsWith("got_page", {AsmToken::PercentGot_Page, 9}) + .StartsWith("gottprel", {AsmToken::PercentGottprel, 9}) + .StartsWith("got", {AsmToken::PercentGot, 4}) + .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7}) + .StartsWith("higher", {AsmToken::PercentHigher, 7}) + .StartsWith("highest", {AsmToken::PercentHighest, 8}) + .StartsWith("hi", {AsmToken::PercentHi, 3}) + .StartsWith("lo", {AsmToken::PercentLo, 3}) + .StartsWith("neg", {AsmToken::PercentNeg, 4}) + .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9}) + .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9}) + .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6}) + .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7}) + .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9}) + .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9}) + .Default({AsmToken::Percent, 1}); + + if (Operator != AsmToken::Percent) { + CurPtr += OperatorLength - 1; + return AsmToken(Operator, StringRef(TokStart, OperatorLength)); + } + } + return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); case '/': IsAtStartOfStatement = OldIsAtStartOfStatement; return LexSlash(); diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 1548aee84227..da54155b3b9d 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -12,42 +12,69 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/APFloat.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/AsmCond.h" #include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCAsmParserUtils.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> #include <cctype> +#include <cstddef> +#include <cstdint> #include <deque> +#include <memory> +#include <sstream> #include <string> +#include <tuple> +#include <utility> #include <vector> + using namespace llvm; MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {} +static cl::opt<unsigned> AsmMacroMaxNestingDepth( + "asm-macro-max-nesting-depth", cl::init(20), cl::Hidden, + cl::desc("The maximum nesting depth allowed for assembly macros.")); + namespace { + /// \brief Helper types for tracking macro definitions. typedef std::vector<AsmToken> MCAsmMacroArgument; typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments; @@ -113,6 +140,7 @@ struct ParseStatementInfo { class AsmParser : public MCAsmParser { AsmParser(const AsmParser &) = delete; void operator=(const AsmParser &) = delete; + private: AsmLexer Lexer; MCContext &Ctx; @@ -150,9 +178,6 @@ private: /// \brief Keeps track of how many .macro's have been instantiated. unsigned NumOfMacroInstantiations; - /// Flag tracking whether any errors have been encountered. - unsigned HadError : 1; - /// The values from the last parsed cpp hash file line comment if any. struct CppHashInfoTy { StringRef Filename; @@ -206,6 +231,9 @@ public: MCAsmLexer &getLexer() override { return Lexer; } MCContext &getContext() override { return Ctx; } MCStreamer &getStreamer() override { return Out; } + + CodeViewContext &getCVContext() { return Ctx.getCVContext(); } + unsigned getAssemblerDialect() override { if (AssemblerDialect == ~0U) return MAI.getAssemblerDialect(); @@ -216,16 +244,16 @@ public: AssemblerDialect = i; } - void Note(SMLoc L, const Twine &Msg, - ArrayRef<SMRange> Ranges = None) override; - bool Warning(SMLoc L, const Twine &Msg, - ArrayRef<SMRange> Ranges = None) override; - bool Error(SMLoc L, const Twine &Msg, - ArrayRef<SMRange> Ranges = None) override; + void Note(SMLoc L, const Twine &Msg, SMRange Range = None) override; + bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) override; + bool printError(SMLoc L, const Twine &Msg, SMRange Range = None) override; const AsmToken &Lex() override; - void setParsingInlineAsm(bool V) override { ParsingInlineAsm = V; } + void setParsingInlineAsm(bool V) override { + ParsingInlineAsm = V; + Lexer.setParsingMSInlineAsm(V); + } bool isParsingInlineAsm() override { return ParsingInlineAsm; } bool parseMSInlineAsm(void *AsmLoc, std::string &AsmString, @@ -244,39 +272,20 @@ public: SMLoc &EndLoc) override; bool parseAbsoluteExpression(int64_t &Res) override; + /// \brief Parse a floating point expression using the float \p Semantics + /// and set \p Res to the value. + bool parseRealValue(const fltSemantics &Semantics, APInt &Res); + /// \brief Parse an identifier or string (as a quoted identifier) /// and set \p Res to the identifier contents. bool parseIdentifier(StringRef &Res) override; void eatToEndOfStatement() override; - void checkForValidSection() override; - - bool getTokenLoc(SMLoc &Loc) { - Loc = getTok().getLoc(); - return false; - } - - /// parseToken - If current token has the specified kind, eat it and - /// return success. Otherwise, emit the specified error and return failure. - bool parseToken(AsmToken::TokenKind T, const Twine &ErrMsg) { - if (getTok().getKind() != T) - return TokError(ErrMsg); - Lex(); - return false; - } - - bool parseIntToken(int64_t &V, const Twine &ErrMsg) { - if (getTok().getKind() != AsmToken::Integer) - return TokError(ErrMsg); - V = getTok().getIntVal(); - Lex(); - return false; - } + bool checkForValidSection() override; /// } private: - bool parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites); @@ -326,29 +335,19 @@ private: void printMacroInstantiations(); void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, - ArrayRef<SMRange> Ranges = None) const { + SMRange Range = None) const { + ArrayRef<SMRange> Ranges(Range); SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); } static void DiagHandler(const SMDiagnostic &Diag, void *Context); - bool check(bool P, SMLoc Loc, const Twine &Msg) { - if (P) - return Error(Loc, Msg); - return false; - } - - bool check(bool P, const Twine &Msg) { - if (P) - return TokError(Msg); - return false; - } - /// \brief Enter the specified file. This returns true on failure. bool enterIncludeFile(const std::string &Filename); /// \brief Process the specified file for the .incbin directive. /// This returns true on failure. - bool processIncbinFile(const std::string &Filename); + bool processIncbinFile(const std::string &Filename, int64_t Skip = 0, + const MCExpr *Count = nullptr, SMLoc Loc = SMLoc()); /// \brief Reset the current lexer position to that given by \p Loc. The /// current token is not set; clients should ensure Lex() is called @@ -379,12 +378,18 @@ private: bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc); + bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName); + bool parseCVFileId(int64_t &FileId, StringRef DirectiveName); + // Generic (target and platform independent) directive parsing. enum DirectiveKind { DK_NO_DIRECTIVE, // Placeholder DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT, DK_RELOC, DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA, + DK_DC, DK_DC_A, DK_DC_B, DK_DC_D, DK_DC_L, DK_DC_S, DK_DC_W, DK_DC_X, + DK_DCB, DK_DCB_B, DK_DCB_D, DK_DCB_L, DK_DCB_S, DK_DCB_W, DK_DCB_X, + DK_DS, DK_DS_B, DK_DS_D, DK_DS_L, DK_DS_P, DK_DS_S, DK_DS_W, DK_DS_X, DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW, DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR, DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK, @@ -397,8 +402,9 @@ private: DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF, DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF, DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, - DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE, - DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS, + DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE, + DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, + DK_CV_FILECHECKSUMS, DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA, DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER, DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA, @@ -419,9 +425,11 @@ private: // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" - bool parseDirectiveValue(unsigned Size); // ".byte", ".long", ... - bool parseDirectiveOctaValue(); // ".octa" - bool parseDirectiveRealValue(const fltSemantics &); // ".single", ... + bool parseDirectiveValue(StringRef IDVal, + unsigned Size); // ".byte", ".long", ... + bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ... + bool parseDirectiveRealValue(StringRef IDVal, + const fltSemantics &); // ".single", ... bool parseDirectiveFill(); // ".fill" bool parseDirectiveZero(); // ".zero" // ".set", ".equ", ".equiv" @@ -436,9 +444,11 @@ private: bool parseDirectiveLoc(); bool parseDirectiveStabs(); - // ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable", - // ".cv_def_range" + // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable", + // ".cv_inline_linetable", ".cv_def_range" bool parseDirectiveCVFile(); + bool parseDirectiveCVFuncId(); + bool parseDirectiveCVInlineSiteId(); bool parseDirectiveCVLoc(); bool parseDirectiveCVLinetable(); bool parseDirectiveCVInlineLinetable(); @@ -484,6 +494,12 @@ private: // ".space", ".skip" bool parseDirectiveSpace(StringRef IDVal); + // ".dcb" + bool parseDirectiveDCB(StringRef IDVal, unsigned Size); + bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &); + // ".ds" + bool parseDirectiveDS(StringRef IDVal, unsigned Size); + // .sleb128 (Signed=true) and .uleb128 (Signed=false) bool parseDirectiveLEB128(bool Signed); @@ -542,7 +558,8 @@ private: void initializeDirectiveKindMap(); }; -} + +} // end anonymous namespace namespace llvm { @@ -550,7 +567,7 @@ extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); extern MCAsmParserExtension *createCOFFAsmParser(); -} +} // end namespace llvm enum { DEFAULT_ADDRSPACE = 0 }; @@ -558,8 +575,9 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI) : Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM), PlatformParser(nullptr), CurBuffer(SM.getMainFileID()), - MacrosEnabledFlag(true), HadError(false), CppHashInfo(), - AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false) { + MacrosEnabledFlag(true), CppHashInfo(), AssemblerDialect(~0U), + IsDarwin(false), ParsingInlineAsm(false) { + HadError = false; // Save the old handler. SavedDiagHandler = SrcMgr.getDiagHandler(); SavedDiagContext = SrcMgr.getDiagContext(); @@ -602,24 +620,25 @@ void AsmParser::printMacroInstantiations() { "while in macro instantiation"); } -void AsmParser::Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { - printMessage(L, SourceMgr::DK_Note, Msg, Ranges); +void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) { + printPendingErrors(); + printMessage(L, SourceMgr::DK_Note, Msg, Range); printMacroInstantiations(); } -bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { +bool AsmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) { if(getTargetParser().getTargetOptions().MCNoWarn) return false; if (getTargetParser().getTargetOptions().MCFatalWarnings) - return Error(L, Msg, Ranges); - printMessage(L, SourceMgr::DK_Warning, Msg, Ranges); + return Error(L, Msg, Range); + printMessage(L, SourceMgr::DK_Warning, Msg, Range); printMacroInstantiations(); return false; } -bool AsmParser::Error(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { +bool AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) { HadError = true; - printMessage(L, SourceMgr::DK_Error, Msg, Ranges); + printMessage(L, SourceMgr::DK_Error, Msg, Range); printMacroInstantiations(); return true; } @@ -639,7 +658,8 @@ bool AsmParser::enterIncludeFile(const std::string &Filename) { /// Process the specified .incbin file by searching for it in the include paths /// then just emitting the byte contents of the file to the streamer. This /// returns true on failure. -bool AsmParser::processIncbinFile(const std::string &Filename) { +bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, + const MCExpr *Count, SMLoc Loc) { std::string IncludedFile; unsigned NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); @@ -647,7 +667,17 @@ bool AsmParser::processIncbinFile(const std::string &Filename) { return true; // Pick up the bytes from the file and emit them. - getStreamer().EmitBytes(SrcMgr.getMemoryBuffer(NewBuf)->getBuffer()); + StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer(); + Bytes = Bytes.drop_front(Skip); + if (Count) { + int64_t Res; + if (!Count->evaluateAsAbsolute(Res)) + return Error(Loc, "expected absolute expression"); + if (Res < 0) + return Warning(Loc, "negative count has no effect"); + Bytes = Bytes.take_front(Res); + } + getStreamer().EmitBytes(Bytes); return false; } @@ -688,7 +718,6 @@ const AsmToken &AsmParser::Lex() { } } - return *tok; } @@ -706,7 +735,7 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // If we are generating dwarf for assembly source files save the initial text // section and generate a .file directive. if (getContext().getGenDwarfForAssembly()) { - MCSection *Sec = getStreamer().getCurrentSection().first; + MCSection *Sec = getStreamer().getCurrentSectionOnly(); if (!Sec->getBeginSymbol()) { MCSymbol *SectionStartSym = getContext().createTempSymbol(); getStreamer().EmitLabel(SectionStartSym); @@ -725,30 +754,38 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { if (!parseStatement(Info, nullptr)) continue; - // If we've failed, but on a Error Token, but did not consume it in - // favor of a better message, emit it now. - if (Lexer.getTok().is(AsmToken::Error)) { + // If we have a Lexer Error we are on an Error Token. Load in Lexer Error + // for printing ErrMsg via Lex() only if no (presumably better) parser error + // exists. + if (!hasPendingError() && Lexer.getTok().is(AsmToken::Error)) { Lex(); } - // We had an error, validate that one was emitted and recover by skipping to - // the next line. - assert(HadError && "Parse statement returned an error, but none emitted!"); - eatToEndOfStatement(); + // parseStatement returned true so may need to emit an error. + printPendingErrors(); + + // Skipping to the next line if needed. + if (!getLexer().isAtStartOfStatement()) + eatToEndOfStatement(); } + // All errors should have been emitted. + assert(!hasPendingError() && "unexpected error from parseStatement"); + + getTargetParser().flushPendingInstructions(getStreamer()); + if (TheCondState.TheCond != StartingCondState.TheCond || TheCondState.Ignore != StartingCondState.Ignore) - return TokError("unmatched .ifs or .elses"); - + printError(getTok().getLoc(), "unmatched .ifs or .elses"); // Check to see there are no empty DwarfFile slots. const auto &LineTables = getContext().getMCDwarfLineTables(); if (!LineTables.empty()) { unsigned Index = 0; for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) { if (File.Name.empty() && Index != 0) - TokError("unassigned file number: " + Twine(Index) + - " for .file directives"); + printError(getTok().getLoc(), "unassigned file number: " + + Twine(Index) + + " for .file directives"); ++Index; } } @@ -768,9 +805,8 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // 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. - HadError |= - Error(getTok().getLoc(), "assembler local symbol '" + - Sym->getName() + "' not defined"); + printError(getTok().getLoc(), "assembler local symbol '" + + Sym->getName() + "' not defined"); } } @@ -781,7 +817,7 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Reset the state of any "# line file" directives we've seen to the // context as it was at the diagnostic site. CppHashInfo = std::get<1>(LocSym); - HadError |= Error(std::get<0>(LocSym), "directional label undefined"); + printError(std::get<0>(LocSym), "directional label undefined"); } } } @@ -794,11 +830,13 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { return HadError || getContext().hadError(); } -void AsmParser::checkForValidSection() { - if (!ParsingInlineAsm && !getStreamer().getCurrentSection().first) { - TokError("expected section directive before assembly directive"); +bool AsmParser::checkForValidSection() { + if (!ParsingInlineAsm && !getStreamer().getCurrentSectionOnly()) { Out.InitSections(false); + return Error(getTok().getLoc(), + "expected section directive before assembly directive"); } + return false; } /// \brief Throw away the rest of the line for testing purposes. @@ -888,8 +926,10 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { case AsmToken::Identifier: { StringRef Identifier; if (parseIdentifier(Identifier)) { - if (FirstTokenKind == AsmToken::Dollar) { + // We may have failed but $ may be a valid token. + if (getTok().is(AsmToken::Dollar)) { if (Lexer.getMAI().getDollarIsPC()) { + Lex(); // This is a '$' reference, which references the current PC. Emit a // temporary label to the streamer and refer to it. MCSymbol *Sym = Ctx.createTempSymbol(); @@ -933,6 +973,9 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // This is a symbol reference. StringRef SymbolName = Identifier; + if (SymbolName.empty()) + return true; + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; // Lookup the symbol variant if used. @@ -999,7 +1042,7 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } case AsmToken::Real: { - APFloat RealVal(APFloat::IEEEdouble, getTok().getString()); + APFloat RealVal(APFloat::IEEEdouble(), getTok().getString()); uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); Res = MCConstantExpr::create(IntVal, getContext()); EndLoc = Lexer.getTok().getEndLoc(); @@ -1042,6 +1085,43 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { return true; Res = MCUnaryExpr::createNot(Res, getContext()); return false; + // MIPS unary expression operators. The lexer won't generate these tokens if + // MCAsmInfo::HasMipsExpressions is false for the target. + case AsmToken::PercentCall16: + case AsmToken::PercentCall_Hi: + case AsmToken::PercentCall_Lo: + case AsmToken::PercentDtprel_Hi: + case AsmToken::PercentDtprel_Lo: + case AsmToken::PercentGot: + case AsmToken::PercentGot_Disp: + case AsmToken::PercentGot_Hi: + case AsmToken::PercentGot_Lo: + case AsmToken::PercentGot_Ofst: + case AsmToken::PercentGot_Page: + case AsmToken::PercentGottprel: + case AsmToken::PercentGp_Rel: + case AsmToken::PercentHi: + case AsmToken::PercentHigher: + case AsmToken::PercentHighest: + case AsmToken::PercentLo: + case AsmToken::PercentNeg: + case AsmToken::PercentPcrel_Hi: + case AsmToken::PercentPcrel_Lo: + case AsmToken::PercentTlsgd: + case AsmToken::PercentTlsldm: + case AsmToken::PercentTprel_Hi: + case AsmToken::PercentTprel_Lo: + Lex(); // Eat the operator. + if (Lexer.isNot(AsmToken::LParen)) + return TokError("expected '(' after operator"); + Lex(); // Eat the operator. + if (parseExpression(Res, EndLoc)) + return true; + if (Lexer.isNot(AsmToken::RParen)) + return TokError("expected ')'"); + Lex(); // Eat the operator. + Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx); + return !Res; } } @@ -1356,7 +1436,7 @@ unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, /// Res contains the LHS of the expression on input. bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc) { - while (1) { + while (true) { MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); @@ -1390,6 +1470,7 @@ bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, /// ::= Label* Identifier OperandList* EndOfStatement bool AsmParser::parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI) { + assert(!hasPendingError() && "parseStatement started with pending error"); // Eat initial spaces and comments while (Lexer.is(AsmToken::Space)) Lex(); @@ -1401,6 +1482,16 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, Lex(); return false; } + if (Lexer.is(AsmToken::Hash)) { + // Seeing a hash here means that it was an end-of-line comment in + // an asm syntax where hash's are not comment and the previous + // statement parser did not check the end of statement. Relex as + // EndOfStatement. + StringRef CommentStr = parseStringToEndOfStatement(); + Lexer.Lex(); + Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); + return false; + } // Statements always start with an identifier. AsmToken ID = getTok(); SMLoc IDLoc = ID.getLoc(); @@ -1412,15 +1503,19 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, if (Lexer.is(AsmToken::Integer)) { LocalLabelVal = getTok().getIntVal(); if (LocalLabelVal < 0) { - if (!TheCondState.Ignore) - return TokError("unexpected token at start of statement"); + if (!TheCondState.Ignore) { + Lex(); // always eat a token + return Error(IDLoc, "unexpected token at start of statement"); + } IDVal = ""; } else { IDVal = getTok().getString(); Lex(); // Consume the integer token to be used as an identifier token. if (Lexer.getKind() != AsmToken::Colon) { - if (!TheCondState.Ignore) - return TokError("unexpected token at start of statement"); + if (!TheCondState.Ignore) { + Lex(); // always eat a token + return Error(IDLoc, "unexpected token at start of statement"); + } } } } else if (Lexer.is(AsmToken::Dot)) { @@ -1437,8 +1532,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, Lex(); IDVal = "}"; } else if (parseIdentifier(IDVal)) { - if (!TheCondState.Ignore) - return TokError("unexpected token at start of statement"); + if (!TheCondState.Ignore) { + Lex(); // always eat a token + return Error(IDLoc, "unexpected token at start of statement"); + } IDVal = ""; } @@ -1500,7 +1597,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, case AsmToken::Colon: { if (!getTargetParser().isLabel(ID)) break; - checkForValidSection(); + if (checkForValidSection()) + return true; // identifier ':' -> Label. Lex(); @@ -1534,6 +1632,16 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, if (!Sym->isUndefined() || Sym->isVariable()) return Error(IDLoc, "invalid symbol redefinition"); + // End of Labels should be treated as end of line for lexing + // purposes but that information is not available to the Lexer who + // does not understand Labels. This may cause us to see a Hash + // here instead of a preprocessor line comment. + if (getTok().is(AsmToken::Hash)) { + StringRef CommentStr = parseStringToEndOfStatement(); + Lexer.Lex(); + Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); + } + // Consume any end of statement token, if present, to avoid spurious // AddBlankLine calls(). if (getTok().is(AsmToken::EndOfStatement)) { @@ -1552,8 +1660,6 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, getTargetParser().onLabelParsed(Sym); - - return false; } @@ -1590,9 +1696,22 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // manner, or at least have a default behavior that's shared between // all targets and platforms. - // First query the target-specific parser. It will return 'true' if it - // isn't interested in this directive. - if (!getTargetParser().ParseDirective(ID)) + getTargetParser().flushPendingInstructions(getStreamer()); + + SMLoc StartTokLoc = getTok().getLoc(); + bool TPDirectiveReturn = getTargetParser().ParseDirective(ID); + + if (hasPendingError()) + return true; + // Currently the return value should be true if we are + // uninterested but as this is at odds with the standard parsing + // convention (return true = error) we have instances of a parsed + // directive that fails returning true as an error. Catch these + // cases as best as possible errors here. + if (TPDirectiveReturn && StartTokLoc != getTok().getLoc()) + return true; + // Return if we did some parsing or believe we succeeded. + if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc()) return false; // Next, check the extension directive map to see if any extension has @@ -1618,25 +1737,34 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, case DK_STRING: return parseDirectiveAscii(IDVal, true); case DK_BYTE: - return parseDirectiveValue(1); + case DK_DC_B: + return parseDirectiveValue(IDVal, 1); + case DK_DC: + case DK_DC_W: case DK_SHORT: case DK_VALUE: case DK_2BYTE: - return parseDirectiveValue(2); + return parseDirectiveValue(IDVal, 2); case DK_LONG: case DK_INT: case DK_4BYTE: - return parseDirectiveValue(4); + case DK_DC_L: + return parseDirectiveValue(IDVal, 4); case DK_QUAD: case DK_8BYTE: - return parseDirectiveValue(8); + return parseDirectiveValue(IDVal, 8); + case DK_DC_A: + return parseDirectiveValue(IDVal, + getContext().getAsmInfo()->getPointerSize()); case DK_OCTA: - return parseDirectiveOctaValue(); + return parseDirectiveOctaValue(IDVal); case DK_SINGLE: case DK_FLOAT: - return parseDirectiveRealValue(APFloat::IEEEsingle); + case DK_DC_S: + return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle()); case DK_DOUBLE: - return parseDirectiveRealValue(APFloat::IEEEdouble); + case DK_DC_D: + return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble()); case DK_ALIGN: { bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); return parseDirectiveAlign(IsPow2, /*ExprSize=*/1); @@ -1731,6 +1859,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveStabs(); case DK_CV_FILE: return parseDirectiveCVFile(); + case DK_CV_FUNC_ID: + return parseDirectiveCVFuncId(); + case DK_CV_INLINE_SITE_ID: + return parseDirectiveCVInlineSiteId(); case DK_CV_LOC: return parseDirectiveCVLoc(); case DK_CV_LINETABLE: @@ -1805,6 +1937,34 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveWarning(IDLoc); case DK_RELOC: return parseDirectiveReloc(IDLoc); + case DK_DCB: + case DK_DCB_W: + return parseDirectiveDCB(IDVal, 2); + case DK_DCB_B: + return parseDirectiveDCB(IDVal, 1); + case DK_DCB_D: + return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble()); + case DK_DCB_L: + return parseDirectiveDCB(IDVal, 4); + case DK_DCB_S: + return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle()); + case DK_DC_X: + case DK_DCB_X: + return TokError(Twine(IDVal) + + " not currently supported for this target"); + case DK_DS: + case DK_DS_W: + return parseDirectiveDS(IDVal, 2); + case DK_DS_B: + return parseDirectiveDS(IDVal, 1); + case DK_DS_D: + return parseDirectiveDS(IDVal, 8); + case DK_DS_L: + case DK_DS_S: + return parseDirectiveDS(IDVal, 4); + case DK_DS_P: + case DK_DS_X: + return parseDirectiveDS(IDVal, 12); } return Error(IDLoc, "unknown directive"); @@ -1821,14 +1981,15 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, if (ParsingInlineAsm && (IDVal == "even")) Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4); - checkForValidSection(); + if (checkForValidSection()) + return true; // Canonicalize the opcode to lower case. std::string OpcodeStr = IDVal.lower(); ParseInstructionInfo IInfo(Info.AsmRewrites); - bool HadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID, - Info.ParsedOperands); - Info.ParseError = HadError; + bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID, + Info.ParsedOperands); + Info.ParseError = ParseHadError; // Dump the parsed representation, if requested. if (getShowParsedOperands()) { @@ -1845,11 +2006,15 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, printMessage(IDLoc, SourceMgr::DK_Note, OS.str()); } + // Fail even if ParseInstruction erroneously returns false. + if (hasPendingError() || ParseHadError) + return true; + // If we are generating dwarf for the current section then generate a .loc // directive for the instruction. - if (!HadError && getContext().getGenDwarfForAssembly() && + if (!ParseHadError && getContext().getGenDwarfForAssembly() && getContext().getGenDwarfSectionSyms().count( - getStreamer().getCurrentSection().first)) { + getStreamer().getCurrentSectionOnly())) { unsigned Line; if (ActiveMacros.empty()) Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); @@ -1889,15 +2054,13 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, } // If parsing succeeded, match the instruction. - if (!HadError) { + if (!ParseHadError) { uint64_t ErrorInfo; - getTargetParser().MatchAndEmitInstruction(IDLoc, Info.Opcode, - Info.ParsedOperands, Out, - ErrorInfo, ParsingInlineAsm); + if (getTargetParser().MatchAndEmitInstruction(IDLoc, Info.Opcode, + Info.ParsedOperands, Out, + ErrorInfo, ParsingInlineAsm)) + return true; } - - // Don't skip the rest of the line, the instruction parser is responsible for - // that. return false; } @@ -1933,6 +2096,7 @@ bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) { "Lexing Cpp line comment: Expected String"); StringRef Filename = getTok().getString(); Lex(); + // Get rid of the enclosing quotes. Filename = Filename.substr(1, Filename.size() - 2); @@ -2158,6 +2322,7 @@ static bool isOperator(AsmToken::TokenKind kind) { } namespace { + class AsmLexerSkipSpaceRAII { public: AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) { @@ -2171,7 +2336,8 @@ public: private: AsmLexer &Lexer; }; -} + +} // end anonymous namespace bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) { @@ -2190,7 +2356,7 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) { bool SpaceEaten; - for (;;) { + while (true) { SpaceEaten = false; if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) return TokError("unexpected token in macro instantiation"); @@ -2265,27 +2431,19 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, MCAsmMacroParameter FA; if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) { - if (parseIdentifier(FA.Name)) { - Error(IDLoc, "invalid argument identifier for formal argument"); - eatToEndOfStatement(); - return true; - } + if (parseIdentifier(FA.Name)) + return Error(IDLoc, "invalid argument identifier for formal argument"); + + if (Lexer.isNot(AsmToken::Equal)) + return TokError("expected '=' after formal parameter identifier"); - if (Lexer.isNot(AsmToken::Equal)) { - TokError("expected '=' after formal parameter identifier"); - eatToEndOfStatement(); - return true; - } Lex(); NamedParametersFound = true; } - if (NamedParametersFound && FA.Name.empty()) { - Error(IDLoc, "cannot mix positional and keyword arguments"); - eatToEndOfStatement(); - return true; - } + if (NamedParametersFound && FA.Name.empty()) + return Error(IDLoc, "cannot mix positional and keyword arguments"); bool Vararg = HasVararg && Parameter == (NParameters - 1); if (parseMacroArgument(FA.Value, Vararg)) @@ -2300,10 +2458,8 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, if (FAI >= NParameters) { assert(M && "expected macro to be defined"); - Error(IDLoc, - "parameter named '" + FA.Name + "' does not exist for macro '" + - M->Name + "'"); - return true; + return Error(IDLoc, "parameter named '" + FA.Name + + "' does not exist for macro '" + M->Name + "'"); } PI = FAI; } @@ -2359,10 +2515,17 @@ void AsmParser::defineMacro(StringRef Name, MCAsmMacro Macro) { void AsmParser::undefineMacro(StringRef Name) { MacroMap.erase(Name); } bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { - // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate - // this, although we should protect against infinite loops. - if (ActiveMacros.size() == 20) - return TokError("macros cannot be nested more than 20 levels deep"); + // Arbitrarily limit macro nesting depth (default matches 'as'). We can + // eliminate this, although we should protect against infinite loops. + unsigned MaxNestingDepth = AsmMacroMaxNestingDepth; + if (ActiveMacros.size() == MaxNestingDepth) { + std::ostringstream MaxNestingDepthError; + MaxNestingDepthError << "macros cannot be nested more than " + << MaxNestingDepth << " levels deep." + << " Use -asm-macro-max-nesting-depth to increase " + "this limit."; + return TokError(MaxNestingDepthError.str()); + } MCAsmMacroArguments A; if (parseMacroArguments(M, A)) @@ -2446,14 +2609,19 @@ bool AsmParser::parseIdentifier(StringRef &Res) { SMLoc PrefixLoc = getLexer().getLoc(); // Consume the prefix character, and check for a following identifier. - Lexer.Lex(); // Lexer's Lex guarantees consecutive token. - if (Lexer.isNot(AsmToken::Identifier)) + + AsmToken Buf[1]; + Lexer.peekTokens(Buf, false); + + if (Buf[0].isNot(AsmToken::Identifier)) return true; // We have a '$' or '@' followed by an identifier, make sure they are adjacent. - if (PrefixLoc.getPointer() + 1 != getTok().getLoc().getPointer()) + if (PrefixLoc.getPointer() + 1 != Buf[0].getLoc().getPointer()) return true; + // eat $ or @ + Lexer.Lex(); // Lexer's Lex guarantees consecutive token. // Construct the joined identifier and consume the token. Res = StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1); @@ -2477,17 +2645,15 @@ bool AsmParser::parseIdentifier(StringRef &Res) { /// ::= .set identifier ',' expression bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) { StringRef Name; - - if (check(parseIdentifier(Name), - "expected identifier after '" + Twine(IDVal) + "'") || - parseToken(AsmToken::Comma, "unexpected token in '" + Twine(IDVal) + "'")) - return true; - - return parseAssignment(Name, allow_redef, true); + if (check(parseIdentifier(Name), "expected identifier") || + parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; } bool AsmParser::parseEscapedString(std::string &Data) { - assert(getLexer().is(AsmToken::String) && "Unexpected current token!"); + if (check(getTok().isNot(AsmToken::String), "expected string")) + return true; Data = ""; StringRef Str = getTok().getStringContents(); @@ -2548,30 +2714,18 @@ bool AsmParser::parseEscapedString(std::string &Data) { /// parseDirectiveAscii: /// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ] bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - checkForValidSection(); - - for (;;) { - std::string Data; - if (check(getTok().isNot(AsmToken::String), - "expected string in '" + Twine(IDVal) + "' directive") || - parseEscapedString(Data)) - return true; - - getStreamer().EmitBytes(Data); - if (ZeroTerminated) - getStreamer().EmitBytes(StringRef("\0", 1)); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (parseToken(AsmToken::Comma, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - } - } + auto parseOp = [&]() -> bool { + std::string Data; + if (checkForValidSection() || parseEscapedString(Data)) + return true; + getStreamer().EmitBytes(Data); + if (ZeroTerminated) + getStreamer().EmitBytes(StringRef("\0", 1)); + return false; + }; - Lex(); + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } @@ -2582,11 +2736,12 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { const MCExpr *Expr = nullptr; SMLoc OffsetLoc = Lexer.getTok().getLoc(); + int64_t OffsetValue; + // We can only deal with constant expressions at the moment. + if (parseExpression(Offset)) return true; - // We can only deal with constant expressions at the moment. - int64_t OffsetValue; if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc, "expression is not a constant value") || check(OffsetValue < 0, OffsetLoc, "expression is negative") || @@ -2610,162 +2765,141 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { } if (parseToken(AsmToken::EndOfStatement, - "unexpected token in .reloc directive") || - check(getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc), - NameLoc, "unknown relocation name")) - return true; + "unexpected token in .reloc directive")) + return true; + + if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc)) + return Error(NameLoc, "unknown relocation name"); + return false; } /// parseDirectiveValue /// ::= (.byte | .short | ... ) [ expression (, expression)* ] -bool AsmParser::parseDirectiveValue(unsigned Size) { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - checkForValidSection(); - - 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)) { - 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); - } else - getStreamer().EmitValue(Value, Size, ExprLoc); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - // FIXME: Improve diagnostic. - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - } - } +bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { + auto parseOp = [&]() -> bool { + const MCExpr *Value; + SMLoc ExprLoc = getLexer().getLoc(); + if (checkForValidSection() || parseExpression(Value)) + return true; + // Special case constant expressions to match code generator. + 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, "out of range literal value"); + getStreamer().EmitIntValue(IntValue, Size); + } else + getStreamer().EmitValue(Value, Size, ExprLoc); + return false; + }; - Lex(); + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } /// ParseDirectiveOctaValue /// ::= .octa [ hexconstant (, hexconstant)* ] -bool AsmParser::parseDirectiveOctaValue() { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - checkForValidSection(); - - for (;;) { - if (getTok().is(AsmToken::Error)) - return true; - if (getTok().isNot(AsmToken::Integer) && getTok().isNot(AsmToken::BigNum)) - return TokError("unknown token in expression"); - SMLoc ExprLoc = getLexer().getLoc(); - APInt IntValue = getTok().getAPIntVal(); - Lex(); +bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) { + auto parseOp = [&]() -> bool { + if (checkForValidSection()) + return true; + if (getTok().isNot(AsmToken::Integer) && getTok().isNot(AsmToken::BigNum)) + return TokError("unknown token in expression"); + SMLoc ExprLoc = getTok().getLoc(); + APInt IntValue = getTok().getAPIntVal(); + uint64_t hi, lo; + Lex(); + if (!IntValue.isIntN(128)) + return Error(ExprLoc, "out of range literal value"); + if (!IntValue.isIntN(64)) { + hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); + lo = IntValue.getLoBits(64).getZExtValue(); + } else { + hi = 0; + lo = IntValue.getZExtValue(); + } + if (MAI.isLittleEndian()) { + getStreamer().EmitIntValue(lo, 8); + getStreamer().EmitIntValue(hi, 8); + } else { + getStreamer().EmitIntValue(hi, 8); + getStreamer().EmitIntValue(lo, 8); + } + return false; + }; - uint64_t hi, lo; - if (IntValue.isIntN(64)) { - hi = 0; - lo = IntValue.getZExtValue(); - } else if (IntValue.isIntN(128)) { - // It might actually have more than 128 bits, but the top ones are zero. - hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); - lo = IntValue.getLoBits(64).getZExtValue(); - } else - return Error(ExprLoc, "literal value out of range for directive"); - - if (MAI.isLittleEndian()) { - getStreamer().EmitIntValue(lo, 8); - getStreamer().EmitIntValue(hi, 8); - } else { - getStreamer().EmitIntValue(hi, 8); - getStreamer().EmitIntValue(lo, 8); - } + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} - if (getLexer().is(AsmToken::EndOfStatement)) - break; +bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { + // We don't truly support arithmetic on floating point expressions, so we + // have to manually parse unary prefixes. + bool IsNeg = false; + if (getLexer().is(AsmToken::Minus)) { + Lexer.Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) + Lexer.Lex(); - // FIXME: Improve diagnostic. - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - } - } + if (Lexer.is(AsmToken::Error)) + return TokError(Lexer.getErr()); + if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) && + Lexer.isNot(AsmToken::Identifier)) + return TokError("unexpected token in directive"); + // Convert to an APFloat. + APFloat Value(Semantics); + StringRef IDVal = getTok().getString(); + if (getLexer().is(AsmToken::Identifier)) { + if (!IDVal.compare_lower("infinity") || !IDVal.compare_lower("inf")) + Value = APFloat::getInf(Semantics); + else if (!IDVal.compare_lower("nan")) + Value = APFloat::getNaN(Semantics, false, ~0); + else + return TokError("invalid floating point literal"); + } else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) == + APFloat::opInvalidOp) + return TokError("invalid floating point literal"); + if (IsNeg) + Value.changeSign(); + + // Consume the numeric token. Lex(); + + Res = Value.bitcastToAPInt(); + return false; } /// parseDirectiveRealValue /// ::= (.single | .double) [ expression (, expression)* ] -bool AsmParser::parseDirectiveRealValue(const fltSemantics &Semantics) { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - checkForValidSection(); - - for (;;) { - // We don't truly support arithmetic on floating point expressions, so we - // have to manually parse unary prefixes. - bool IsNeg = false; - if (getLexer().is(AsmToken::Minus)) { - Lexer.Lex(); - IsNeg = true; - } else if (getLexer().is(AsmToken::Plus)) - Lexer.Lex(); - - if (Lexer.is(AsmToken::Error)) - return TokError(Lexer.getErr()); - if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) && - Lexer.isNot(AsmToken::Identifier)) - return TokError("unexpected token in directive"); - - // Convert to an APFloat. - APFloat Value(Semantics); - StringRef IDVal = getTok().getString(); - if (getLexer().is(AsmToken::Identifier)) { - if (!IDVal.compare_lower("infinity") || !IDVal.compare_lower("inf")) - Value = APFloat::getInf(Semantics); - else if (!IDVal.compare_lower("nan")) - Value = APFloat::getNaN(Semantics, false, ~0); - else - return TokError("invalid floating point literal"); - } else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) == - APFloat::opInvalidOp) - return TokError("invalid floating point literal"); - if (IsNeg) - Value.changeSign(); - - // Consume the numeric token. - Lex(); - - // Emit the value as an integer. - APInt AsInt = Value.bitcastToAPInt(); - getStreamer().EmitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - - if (Lexer.is(AsmToken::EndOfStatement)) - break; - - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - } - } +bool AsmParser::parseDirectiveRealValue(StringRef IDVal, + const fltSemantics &Semantics) { + auto parseOp = [&]() -> bool { + APInt AsInt; + if (checkForValidSection() || parseRealValue(Semantics, AsInt)) + return true; + getStreamer().EmitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + return false; + }; - Lex(); + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } /// parseDirectiveZero /// ::= .zero expression bool AsmParser::parseDirectiveZero() { - checkForValidSection(); - SMLoc NumBytesLoc = Lexer.getLoc(); const MCExpr *NumBytes; - if (parseExpression(NumBytes)) + if (checkForValidSection() || parseExpression(NumBytes)) return true; int64_t Val = 0; @@ -2786,32 +2920,29 @@ bool AsmParser::parseDirectiveZero() { /// parseDirectiveFill /// ::= .fill expression [ , expression [ , expression ] ] bool AsmParser::parseDirectiveFill() { - checkForValidSection(); - SMLoc NumValuesLoc = Lexer.getLoc(); const MCExpr *NumValues; - if (parseExpression(NumValues)) + if (checkForValidSection() || parseExpression(NumValues)) return true; int64_t FillSize = 1; int64_t FillExpr = 0; SMLoc SizeLoc, ExprLoc; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma, "unexpected token in '.fill' directive") || - getTokenLoc(SizeLoc) || parseAbsoluteExpression(FillSize)) + if (parseOptionalToken(AsmToken::Comma)) { + SizeLoc = getTok().getLoc(); + if (parseAbsoluteExpression(FillSize)) return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma, - "unexpected token in '.fill' directive") || - getTokenLoc(ExprLoc) || parseAbsoluteExpression(FillExpr) || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.fill' directive")) + if (parseOptionalToken(AsmToken::Comma)) { + ExprLoc = getTok().getLoc(); + if (parseAbsoluteExpression(FillExpr)) return true; } } + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.fill' directive")) + return true; if (FillSize < 0) { Warning(SizeLoc, "'.fill' directive with negative size has no effect"); @@ -2833,73 +2964,64 @@ bool AsmParser::parseDirectiveFill() { /// parseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::parseDirectiveOrg() { - checkForValidSection(); - const MCExpr *Offset; - if (parseExpression(Offset)) + SMLoc OffsetLoc = Lexer.getLoc(); + if (checkForValidSection() || parseExpression(Offset)) return true; // Parse optional fill expression. int64_t FillExpr = 0; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma, "unexpected token in '.org' directive") || - parseAbsoluteExpression(FillExpr)) - return true; - } + if (parseOptionalToken(AsmToken::Comma)) + if (parseAbsoluteExpression(FillExpr)) + return addErrorSuffix(" in '.org' directive"); + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.org' directive"); - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.org' directive")) - return true; - - getStreamer().emitValueToOffset(Offset, FillExpr); + getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc); return false; } /// parseDirectiveAlign /// ::= {.align, ...} expression [ , expression [ , expression ]] bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { - checkForValidSection(); - SMLoc AlignmentLoc = getLexer().getLoc(); int64_t Alignment; - if (parseAbsoluteExpression(Alignment)) - return true; - SMLoc MaxBytesLoc; bool HasFillExpr = false; int64_t FillExpr = 0; int64_t MaxBytesToFill = 0; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - - // The fill expression can be omitted while specifying a maximum number of - // alignment bytes, e.g: - // .align 3,,4 - if (getTok().isNot(AsmToken::Comma)) { - HasFillExpr = true; - if (parseAbsoluteExpression(FillExpr)) - return true; - } - if (getTok().isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma, "unexpected token in directive") || - getTokenLoc(MaxBytesLoc) || parseAbsoluteExpression(MaxBytesToFill)) - return true; + auto parseAlign = [&]() -> bool { + if (checkForValidSection() || parseAbsoluteExpression(Alignment)) + return true; + if (parseOptionalToken(AsmToken::Comma)) { + // The fill expression can be omitted while specifying a maximum number of + // alignment bytes, e.g: + // .align 3,,4 + if (getTok().isNot(AsmToken::Comma)) { + HasFillExpr = true; + if (parseAbsoluteExpression(FillExpr)) + return true; + } + if (parseOptionalToken(AsmToken::Comma)) + if (parseTokenLoc(MaxBytesLoc) || + parseAbsoluteExpression(MaxBytesToFill)) + return true; } - } + return parseToken(AsmToken::EndOfStatement); + }; - if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive")) - return true; + if (parseAlign()) + return addErrorSuffix(" in directive"); - if (!HasFillExpr) - FillExpr = 0; + // Always emit an alignment here even if we thrown an error. + bool ReturnVal = false; // Compute alignment in bytes. if (IsPow2) { // FIXME: Diagnose overflow. if (Alignment >= 32) { - Error(AlignmentLoc, "invalid alignment value"); + ReturnVal |= Error(AlignmentLoc, "invalid alignment value"); Alignment = 31; } @@ -2911,13 +3033,14 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { if (Alignment == 0) Alignment = 1; if (!isPowerOf2_64(Alignment)) - Error(AlignmentLoc, "alignment must be a power of 2"); + ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2"); } // Diagnose non-sensical max bytes to align. if (MaxBytesLoc.isValid()) { if (MaxBytesToFill < 1) { - Error(MaxBytesLoc, "alignment directive can never be satisfied in this " + ReturnVal |= Error(MaxBytesLoc, + "alignment directive can never be satisfied in this " "many bytes, ignoring maximum bytes expression"); MaxBytesToFill = 0; } @@ -2931,7 +3054,7 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { // Check whether we should use optimal code alignment for this .align // directive. - const MCSection *Section = getStreamer().getCurrentSection().first; + const MCSection *Section = getStreamer().getCurrentSectionOnly(); assert(Section && "must have section to emit alignment"); bool UseCodeAlign = Section->UseCodeAlign(); if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && @@ -2943,7 +3066,7 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { MaxBytesToFill); } - return false; + return ReturnVal; } /// parseDirectiveFile @@ -2997,7 +3120,7 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { getContext().setGenDwarfForAssembly(false); else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename) == 0) - Error(FileNumberLoc, "file number already allocated"); + return Error(FileNumberLoc, "file number already allocated"); } return false; @@ -3007,7 +3130,7 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { /// ::= .line [number] bool AsmParser::parseDirectiveLine() { int64_t LineNumber; - if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().is(AsmToken::Integer)) { if (parseIntToken(LineNumber, "unexpected token in '.line' directive")) return true; (void)LineNumber; @@ -3056,65 +3179,61 @@ bool AsmParser::parseDirectiveLoc() { unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; unsigned Isa = 0; int64_t Discriminator = 0; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - for (;;) { - if (getLexer().is(AsmToken::EndOfStatement)) - break; - StringRef Name; - SMLoc Loc = getTok().getLoc(); - if (parseIdentifier(Name)) - return TokError("unexpected token in '.loc' directive"); - - if (Name == "basic_block") - Flags |= DWARF2_FLAG_BASIC_BLOCK; - else if (Name == "prologue_end") - Flags |= DWARF2_FLAG_PROLOGUE_END; - else if (Name == "epilogue_begin") - Flags |= DWARF2_FLAG_EPILOGUE_BEGIN; - else if (Name == "is_stmt") { - Loc = getTok().getLoc(); - const MCExpr *Value; - if (parseExpression(Value)) - return true; - // The expression must be the constant 0 or 1. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { - int Value = MCE->getValue(); - if (Value == 0) - Flags &= ~DWARF2_FLAG_IS_STMT; - else if (Value == 1) - Flags |= DWARF2_FLAG_IS_STMT; - else - return Error(Loc, "is_stmt value not 0 or 1"); - } else { - return Error(Loc, "is_stmt value not the constant value of 0 or 1"); - } - } else if (Name == "isa") { - Loc = getTok().getLoc(); - const MCExpr *Value; - if (parseExpression(Value)) - return true; - // The expression must be a constant greater or equal to 0. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { - int Value = MCE->getValue(); - if (Value < 0) - return Error(Loc, "isa number less than zero"); - Isa = Value; - } else { - return Error(Loc, "isa number not a constant value"); - } - } else if (Name == "discriminator") { - if (parseAbsoluteExpression(Discriminator)) - return true; + auto parseLocOp = [&]() -> bool { + StringRef Name; + SMLoc Loc = getTok().getLoc(); + if (parseIdentifier(Name)) + return TokError("unexpected token in '.loc' directive"); + + if (Name == "basic_block") + Flags |= DWARF2_FLAG_BASIC_BLOCK; + else if (Name == "prologue_end") + Flags |= DWARF2_FLAG_PROLOGUE_END; + else if (Name == "epilogue_begin") + Flags |= DWARF2_FLAG_EPILOGUE_BEGIN; + else if (Name == "is_stmt") { + Loc = getTok().getLoc(); + const MCExpr *Value; + if (parseExpression(Value)) + return true; + // The expression must be the constant 0 or 1. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { + int Value = MCE->getValue(); + if (Value == 0) + Flags &= ~DWARF2_FLAG_IS_STMT; + else if (Value == 1) + Flags |= DWARF2_FLAG_IS_STMT; + else + return Error(Loc, "is_stmt value not 0 or 1"); } else { - return Error(Loc, "unknown sub-directive in '.loc' directive"); + return Error(Loc, "is_stmt value not the constant value of 0 or 1"); } - - if (getLexer().is(AsmToken::EndOfStatement)) - break; + } else if (Name == "isa") { + Loc = getTok().getLoc(); + const MCExpr *Value; + if (parseExpression(Value)) + return true; + // The expression must be a constant greater or equal to 0. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { + int Value = MCE->getValue(); + if (Value < 0) + return Error(Loc, "isa number less than zero"); + Isa = Value; + } else { + return Error(Loc, "isa number not a constant value"); + } + } else if (Name == "discriminator") { + if (parseAbsoluteExpression(Discriminator)) + return true; + } else { + return Error(Loc, "unknown sub-directive in '.loc' directive"); } - } - Lex(); + return false; + }; + + if (parseMany(parseLocOp, false /*hasComma*/)) + return true; getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags, Isa, Discriminator, StringRef()); @@ -3144,11 +3263,113 @@ bool AsmParser::parseDirectiveCVFile() { // directory. Allow the strings to have escaped octal character sequence. parseEscapedString(Filename) || parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cv_file' directive") || - check(getStreamer().EmitCVFileDirective(FileNumber, Filename) == 0, - FileNumberLoc, "file number already allocated")) + "unexpected token in '.cv_file' directive")) return true; + if (!getStreamer().EmitCVFileDirective(FileNumber, Filename)) + return Error(FileNumberLoc, "file number already allocated"); + + return false; +} + +bool AsmParser::parseCVFunctionId(int64_t &FunctionId, + StringRef DirectiveName) { + SMLoc Loc; + return parseTokenLoc(Loc) || + parseIntToken(FunctionId, "expected function id in '" + DirectiveName + + "' directive") || + check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc, + "expected function id within range [0, UINT_MAX)"); +} + +bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) { + SMLoc Loc; + return parseTokenLoc(Loc) || + parseIntToken(FileNumber, "expected integer in '" + DirectiveName + + "' directive") || + check(FileNumber < 1, Loc, "file number less than one in '" + + DirectiveName + "' directive") || + check(!getCVContext().isValidFileNumber(FileNumber), Loc, + "unassigned file number in '" + DirectiveName + "' directive"); +} + +/// parseDirectiveCVFuncId +/// ::= .cv_func_id FunctionId +/// +/// Introduces a function ID that can be used with .cv_loc. +bool AsmParser::parseDirectiveCVFuncId() { + SMLoc FunctionIdLoc = getTok().getLoc(); + int64_t FunctionId; + + if (parseCVFunctionId(FunctionId, ".cv_func_id") || + parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_func_id' directive")) + return true; + + if (!getStreamer().EmitCVFuncIdDirective(FunctionId)) + return Error(FunctionIdLoc, "function id already allocated"); + + return false; +} + +/// parseDirectiveCVInlineSiteId +/// ::= .cv_inline_site_id FunctionId +/// "within" IAFunc +/// "inlined_at" IAFile IALine [IACol] +/// +/// Introduces a function ID that can be used with .cv_loc. Includes "inlined +/// at" source location information for use in the line table of the caller, +/// whether the caller is a real function or another inlined call site. +bool AsmParser::parseDirectiveCVInlineSiteId() { + SMLoc FunctionIdLoc = getTok().getLoc(); + int64_t FunctionId; + int64_t IAFunc; + int64_t IAFile; + int64_t IALine; + int64_t IACol = 0; + + // FunctionId + if (parseCVFunctionId(FunctionId, ".cv_inline_site_id")) + return true; + + // "within" + if (check((getLexer().isNot(AsmToken::Identifier) || + getTok().getIdentifier() != "within"), + "expected 'within' identifier in '.cv_inline_site_id' directive")) + return true; + Lex(); + + // IAFunc + if (parseCVFunctionId(IAFunc, ".cv_inline_site_id")) + return true; + + // "inlined_at" + if (check((getLexer().isNot(AsmToken::Identifier) || + getTok().getIdentifier() != "inlined_at"), + "expected 'inlined_at' identifier in '.cv_inline_site_id' " + "directive") ) + return true; + Lex(); + + // IAFile IALine + if (parseCVFileId(IAFile, ".cv_inline_site_id") || + parseIntToken(IALine, "expected line number after 'inlined_at'")) + return true; + + // [IACol] + if (getLexer().is(AsmToken::Integer)) { + IACol = getTok().getIntVal(); + Lex(); + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_inline_site_id' directive")) + return true; + + if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, + IALine, IACol, FunctionIdLoc)) + return Error(FunctionIdLoc, "function id already allocated"); + return false; } @@ -3160,18 +3381,11 @@ bool AsmParser::parseDirectiveCVFile() { /// third number is a column position (zero if not specified). The remaining /// optional items are .loc sub-directives. bool AsmParser::parseDirectiveCVLoc() { + SMLoc DirectiveLoc = getTok().getLoc(); SMLoc Loc; int64_t FunctionId, FileNumber; - if (getTokenLoc(Loc) || - parseIntToken(FunctionId, "unexpected token in '.cv_loc' directive") || - check(FunctionId < 0, Loc, - "function id less than zero in '.cv_loc' directive") || - getTokenLoc(Loc) || - parseIntToken(FileNumber, "expected integer in '.cv_loc' directive") || - check(FileNumber < 1, Loc, - "file number less than one in '.cv_loc' directive") || - check(!getContext().isValidCVFileNumber(FileNumber), Loc, - "unassigned file number in '.cv_loc' directive")) + if (parseCVFunctionId(FunctionId, ".cv_loc") || + parseCVFileId(FileNumber, ".cv_loc")) return true; int64_t LineNumber = 0; @@ -3192,12 +3406,12 @@ bool AsmParser::parseDirectiveCVLoc() { bool PrologueEnd = false; uint64_t IsStmt = 0; - while (getLexer().isNot(AsmToken::EndOfStatement)) { + + auto parseOp = [&]() -> bool { StringRef Name; SMLoc Loc = getTok().getLoc(); if (parseIdentifier(Name)) return TokError("unexpected token in '.cv_loc' directive"); - if (Name == "prologue_end") PrologueEnd = true; else if (Name == "is_stmt") { @@ -3215,11 +3429,15 @@ bool AsmParser::parseDirectiveCVLoc() { } else { return Error(Loc, "unknown sub-directive in '.cv_loc' directive"); } - } - Lex(); + return false; + }; + + if (parseMany(parseOp, false /*hasComma*/)) + return true; getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber, - ColumnPos, PrologueEnd, IsStmt, StringRef()); + ColumnPos, PrologueEnd, IsStmt, StringRef(), + DirectiveLoc); return false; } @@ -3229,18 +3447,15 @@ bool AsmParser::parseDirectiveCVLinetable() { int64_t FunctionId; StringRef FnStartName, FnEndName; SMLoc Loc = getTok().getLoc(); - if (parseIntToken(FunctionId, - "expected Integer in '.cv_linetable' directive") || - check(FunctionId < 0, Loc, - "function id less than zero in '.cv_linetable' directive") || + if (parseCVFunctionId(FunctionId, ".cv_linetable") || parseToken(AsmToken::Comma, "unexpected token in '.cv_linetable' directive") || - getTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, - "expected identifier in directive") || + parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, + "expected identifier in directive") || parseToken(AsmToken::Comma, "unexpected token in '.cv_linetable' directive") || - getTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, - "expected identifier in directive")) + parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, + "expected identifier in directive")) return true; MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName); @@ -3252,52 +3467,29 @@ bool AsmParser::parseDirectiveCVLinetable() { /// parseDirectiveCVInlineLinetable /// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd -/// ("contains" SecondaryFunctionId+)? bool AsmParser::parseDirectiveCVInlineLinetable() { int64_t PrimaryFunctionId, SourceFileId, SourceLineNum; StringRef FnStartName, FnEndName; SMLoc Loc = getTok().getLoc(); - if (parseIntToken( - PrimaryFunctionId, - "expected PrimaryFunctionId in '.cv_inline_linetable' directive") || - check(PrimaryFunctionId < 0, Loc, - "function id less than zero in '.cv_inline_linetable' directive") || - getTokenLoc(Loc) || + if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") || + parseTokenLoc(Loc) || parseIntToken( SourceFileId, "expected SourceField in '.cv_inline_linetable' directive") || check(SourceFileId <= 0, Loc, "File id less than zero in '.cv_inline_linetable' directive") || - getTokenLoc(Loc) || + parseTokenLoc(Loc) || parseIntToken( SourceLineNum, "expected SourceLineNum in '.cv_inline_linetable' directive") || check(SourceLineNum < 0, Loc, "Line number less than zero in '.cv_inline_linetable' directive") || - getTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, - "expected identifier in directive") || - getTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, - "expected identifier in directive")) + parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, + "expected identifier in directive") || + parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, + "expected identifier in directive")) return true; - SmallVector<unsigned, 8> SecondaryFunctionIds; - if (getLexer().is(AsmToken::Identifier)) { - if (getTok().getIdentifier() != "contains") - return TokError( - "unexpected identifier in '.cv_inline_linetable' directive"); - Lex(); - - while (getLexer().isNot(AsmToken::EndOfStatement)) { - int64_t SecondaryFunctionId = getTok().getIntVal(); - if (SecondaryFunctionId < 0) - return TokError( - "function id less than zero in '.cv_inline_linetable' directive"); - Lex(); - - SecondaryFunctionIds.push_back(SecondaryFunctionId); - } - } - if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement")) return true; @@ -3305,7 +3497,7 @@ bool AsmParser::parseDirectiveCVInlineLinetable() { MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName); getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, - FnEndSym, SecondaryFunctionIds); + FnEndSym); return false; } @@ -3388,12 +3580,12 @@ bool AsmParser::parseDirectiveCFISections() { /// ::= .cfi_startproc [simple] bool AsmParser::parseDirectiveCFIStartProc() { StringRef Simple; - if (getLexer().isNot(AsmToken::EndOfStatement)) - if (parseIdentifier(Simple) || Simple != "simple") - return TokError("unexpected token in .cfi_startproc directive"); - - if (parseToken(AsmToken::EndOfStatement, "Expected end of statement")) - return true; + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (check(parseIdentifier(Simple) || Simple != "simple", + "unexpected token") || + parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.cfi_startproc' directive"); + } getStreamer().EmitCFIStartProc(!Simple.empty()); return false; @@ -3728,7 +3920,7 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { AsmToken EndToken, StartToken = getTok(); unsigned MacroDepth = 0; // Lex the macro definition. - for (;;) { + while (true) { // Ignore Lexing errors in macros. while (Lexer.is(AsmToken::Error)) { Lexer.Lex(); @@ -3924,14 +4116,16 @@ bool AsmParser::parseDirectiveEndMacro(StringRef Directive) { bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { StringRef Name; SMLoc Loc; - if (getTokenLoc(Loc) || check(parseIdentifier(Name), Loc, - "expected identifier in '.purgem' directive") || + if (parseTokenLoc(Loc) || + check(parseIdentifier(Name), Loc, + "expected identifier in '.purgem' directive") || parseToken(AsmToken::EndOfStatement, - "unexpected token in '.purgem' directive") || - check(!lookupMacro(Name), DirectiveLoc, - "macro '" + Name + "' is not defined")) + "unexpected token in '.purgem' directive")) return true; + if (!lookupMacro(Name)) + return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); + undefineMacro(Name); return false; } @@ -3939,13 +4133,11 @@ bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { /// parseDirectiveBundleAlignMode /// ::= {.bundle_align_mode} expression bool AsmParser::parseDirectiveBundleAlignMode() { - checkForValidSection(); - // Expect a single argument: an expression that evaluates to a constant // in the inclusive range 0-30. SMLoc ExprLoc = getLexer().getLoc(); int64_t AlignSizePow2; - if (parseAbsoluteExpression(AlignSizePow2) || + if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) || parseToken(AsmToken::EndOfStatement, "unexpected token after expression " "in '.bundle_align_mode' " "directive") || @@ -3962,25 +4154,24 @@ bool AsmParser::parseDirectiveBundleAlignMode() { /// parseDirectiveBundleLock /// ::= {.bundle_lock} [align_to_end] bool AsmParser::parseDirectiveBundleLock() { - checkForValidSection(); + if (checkForValidSection()) + return true; bool AlignToEnd = false; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - StringRef Option; - SMLoc Loc = getTok().getLoc(); - const char *kInvalidOptionError = - "invalid option for '.bundle_lock' directive"; + StringRef Option; + SMLoc Loc = getTok().getLoc(); + const char *kInvalidOptionError = + "invalid option for '.bundle_lock' directive"; + if (!parseOptionalToken(AsmToken::EndOfStatement)) { if (check(parseIdentifier(Option), Loc, kInvalidOptionError) || check(Option != "align_to_end", Loc, kInvalidOptionError) || - check(getTok().isNot(AsmToken::EndOfStatement), Loc, - "unexpected token after '.bundle_lock' directive option")) + parseToken(AsmToken::EndOfStatement, + "unexpected token after '.bundle_lock' directive option")) return true; AlignToEnd = true; } - Lex(); - getStreamer().EmitBundleLock(AlignToEnd); return false; } @@ -3988,9 +4179,8 @@ bool AsmParser::parseDirectiveBundleLock() { /// parseDirectiveBundleLock /// ::= {.bundle_lock} bool AsmParser::parseDirectiveBundleUnlock() { - checkForValidSection(); - - if (parseToken(AsmToken::EndOfStatement, + if (checkForValidSection() || + parseToken(AsmToken::EndOfStatement, "unexpected token in '.bundle_unlock' directive")) return true; @@ -4001,28 +4191,119 @@ bool AsmParser::parseDirectiveBundleUnlock() { /// parseDirectiveSpace /// ::= (.skip | .space) expression [ , expression ] bool AsmParser::parseDirectiveSpace(StringRef IDVal) { - checkForValidSection(); SMLoc NumBytesLoc = Lexer.getLoc(); const MCExpr *NumBytes; - if (parseExpression(NumBytes)) + if (checkForValidSection() || parseExpression(NumBytes)) return true; int64_t FillExpr = 0; - if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (parseOptionalToken(AsmToken::Comma)) + if (parseAbsoluteExpression(FillExpr)) + return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); - if (parseToken(AsmToken::Comma, - "unexpected token in '" + Twine(IDVal) + "' directive") || - parseAbsoluteExpression(FillExpr)) - return true; + // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. + getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc); + + return false; +} + +/// parseDirectiveDCB +/// ::= .dcb.{b, l, w} expression, expression +bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) { + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::Comma, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + 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)) { + 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"); + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().EmitIntValue(IntValue, Size); + } else { + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().EmitValue(Value, Size, ExprLoc); } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; - // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. - getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc); + return false; +} + +/// parseDirectiveRealDCB +/// ::= .dcb.{d, s} expression, expression +bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) { + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::Comma, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + APInt AsInt; + if (parseRealValue(Semantics, AsInt)) + return true; + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().EmitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + + return false; +} + +/// parseDirectiveDS +/// ::= .ds.{b, d, l, p, s, w, x} expression +bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) { + + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().emitFill(Size, 0); return false; } @@ -4030,25 +4311,22 @@ bool AsmParser::parseDirectiveSpace(StringRef IDVal) { /// parseDirectiveLEB128 /// ::= (.sleb128 | .uleb128) [ expression (, expression)* ] bool AsmParser::parseDirectiveLEB128(bool Signed) { - checkForValidSection(); - const MCExpr *Value; + if (checkForValidSection()) + return true; - for (;;) { + auto parseOp = [&]() -> bool { + const MCExpr *Value; if (parseExpression(Value)) return true; - if (Signed) getStreamer().EmitSLEB128Value(Value); else getStreamer().EmitULEB128Value(Value); + return false; + }; - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - } - Lex(); + if (parseMany(parseOp)) + return addErrorSuffix(" in directive"); return false; } @@ -4056,39 +4334,32 @@ bool AsmParser::parseDirectiveLEB128(bool Signed) { /// parseDirectiveSymbolAttribute /// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) { - if (getLexer().isNot(AsmToken::EndOfStatement)) { - for (;;) { - StringRef Name; - SMLoc Loc = getTok().getLoc(); - - if (parseIdentifier(Name)) - return Error(Loc, "expected identifier in directive"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - // Assembler local symbols don't make any sense here. Complain loudly. - if (Sym->isTemporary()) - return Error(Loc, "non-local symbol required in directive"); - - if (!getStreamer().EmitSymbolAttribute(Sym, Attr)) - return Error(Loc, "unable to emit symbol attribute"); + auto parseOp = [&]() -> bool { + StringRef Name; + SMLoc Loc = getTok().getLoc(); + if (parseIdentifier(Name)) + return Error(Loc, "expected identifier"); + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - if (getLexer().is(AsmToken::EndOfStatement)) - break; + // Assembler local symbols don't make any sense here. Complain loudly. + if (Sym->isTemporary()) + return Error(Loc, "non-local symbol required"); - if (parseToken(AsmToken::Comma, "unexpected token in directive")) - return true; - } - } + if (!getStreamer().EmitSymbolAttribute(Sym, Attr)) + return Error(Loc, "unable to emit symbol attribute"); + return false; + }; - Lex(); + if (parseMany(parseOp)) + return addErrorSuffix(" in directive"); return false; } /// parseDirectiveComm /// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] bool AsmParser::parseDirectiveComm(bool IsLocal) { - checkForValidSection(); + if (checkForValidSection()) + return true; SMLoc IDLoc = getLexer().getLoc(); StringRef Name; @@ -4128,10 +4399,9 @@ bool AsmParser::parseDirectiveComm(bool IsLocal) { } } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.comm' or '.lcomm' directive"); - - Lex(); + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.comm' or '.lcomm' directive")) + return true; // NOTE: a size of zero for a .comm should create a undefined symbol // but a size of .lcomm creates a bss symbol of size zero. @@ -4171,9 +4441,9 @@ bool AsmParser::parseDirectiveAbort() { return true; if (Str.empty()) - Error(Loc, ".abort detected. Assembly stopping."); + return Error(Loc, ".abort detected. Assembly stopping."); else - Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); // FIXME: Actually abort assembly here. return false; @@ -4201,20 +4471,43 @@ bool AsmParser::parseDirectiveInclude() { } /// parseDirectiveIncbin -/// ::= .incbin "filename" +/// ::= .incbin "filename" [ , skip [ , count ] ] bool AsmParser::parseDirectiveIncbin() { // Allow the strings to have escaped octal character sequence. std::string Filename; SMLoc IncbinLoc = getTok().getLoc(); if (check(getTok().isNot(AsmToken::String), "expected string in '.incbin' directive") || - parseEscapedString(Filename) || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.incbin' directive") || - // Attempt to process the included file. - check(processIncbinFile(Filename), IncbinLoc, - "Could not find incbin file '" + Filename + "'")) + parseEscapedString(Filename)) + return true; + + int64_t Skip = 0; + const MCExpr *Count = nullptr; + SMLoc SkipLoc, CountLoc; + if (parseOptionalToken(AsmToken::Comma)) { + // The skip expression can be omitted while specifying the count, e.g: + // .incbin "filename",,4 + if (getTok().isNot(AsmToken::Comma)) { + if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip)) + return true; + } + if (parseOptionalToken(AsmToken::Comma)) { + CountLoc = getTok().getLoc(); + if (parseExpression(Count)) + return true; + } + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.incbin' directive")) + return true; + + if (check(Skip < 0, SkipLoc, "skip is negative")) return true; + + // Attempt to process the included file. + if (processIncbinFile(Filename, Skip, Count, CountLoc)) + return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); return false; } @@ -4317,11 +4610,8 @@ bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) { bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) { if (Lexer.isNot(AsmToken::String)) { if (ExpectEqual) - TokError("expected string parameter for '.ifeqs' directive"); - else - TokError("expected string parameter for '.ifnes' directive"); - eatToEndOfStatement(); - return true; + return TokError("expected string parameter for '.ifeqs' directive"); + return TokError("expected string parameter for '.ifnes' directive"); } StringRef String1 = getTok().getStringContents(); @@ -4329,22 +4619,17 @@ bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) { if (Lexer.isNot(AsmToken::Comma)) { if (ExpectEqual) - TokError("expected comma after first string for '.ifeqs' directive"); - else - TokError("expected comma after first string for '.ifnes' directive"); - eatToEndOfStatement(); - return true; + return TokError( + "expected comma after first string for '.ifeqs' directive"); + return TokError("expected comma after first string for '.ifnes' directive"); } Lex(); if (Lexer.isNot(AsmToken::String)) { if (ExpectEqual) - TokError("expected string parameter for '.ifeqs' directive"); - else - TokError("expected string parameter for '.ifnes' directive"); - eatToEndOfStatement(); - return true; + return TokError("expected string parameter for '.ifeqs' directive"); + return TokError("expected string parameter for '.ifnes' directive"); } StringRef String2 = getTok().getStringContents(); @@ -4389,8 +4674,8 @@ bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) { if (TheCondState.TheCond != AsmCond::IfCond && TheCondState.TheCond != AsmCond::ElseIfCond) - Error(DirectiveLoc, "Encountered a .elseif that doesn't follow a .if or " - " an .elseif"); + return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an" + " .if or an .elseif"); TheCondState.TheCond = AsmCond::ElseIfCond; bool LastIgnoreState = false; @@ -4404,10 +4689,10 @@ bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) { if (parseAbsoluteExpression(ExprValue)) return true; - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.elseif' directive"); + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.elseif' directive")) + return true; - Lex(); TheCondState.CondMet = ExprValue; TheCondState.Ignore = !TheCondState.CondMet; } @@ -4424,8 +4709,8 @@ bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) { if (TheCondState.TheCond != AsmCond::IfCond && TheCondState.TheCond != AsmCond::ElseIfCond) - Error(DirectiveLoc, "Encountered a .else that doesn't follow a .if or an " - ".elseif"); + return Error(DirectiveLoc, "Encountered a .else that doesn't follow " + " an .if or an .elseif"); TheCondState.TheCond = AsmCond::ElseCond; bool LastIgnoreState = false; if (!TheCondStack.empty()) @@ -4446,7 +4731,7 @@ bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) { return true; while (Lexer.isNot(AsmToken::Eof)) - Lex(); + Lexer.Lex(); return false; } @@ -4467,18 +4752,14 @@ bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) { StringRef Message = ".error directive invoked in source file"; if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (Lexer.isNot(AsmToken::String)) { - TokError(".error argument must be a string"); - eatToEndOfStatement(); - return true; - } + if (Lexer.isNot(AsmToken::String)) + return TokError(".error argument must be a string"); Message = getTok().getStringContents(); Lex(); } - Error(L, Message); - return true; + return Error(L, Message); } /// parseDirectiveWarning @@ -4492,19 +4773,19 @@ bool AsmParser::parseDirectiveWarning(SMLoc L) { } StringRef Message = ".warning directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (Lexer.isNot(AsmToken::String)) { - TokError(".warning argument must be a string"); - eatToEndOfStatement(); - return true; - } + + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::String)) + return TokError(".warning argument must be a string"); Message = getTok().getStringContents(); Lex(); + if (parseToken(AsmToken::EndOfStatement, + "expected end of statement in '.warning' directive")) + return true; } - Warning(L, Message); - return false; + return Warning(L, Message); } /// parseDirectiveEndIf @@ -4515,8 +4796,8 @@ bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) { return true; if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty()) - Error(DirectiveLoc, "Encountered a .endif that doesn't follow a .if or " - ".else"); + return Error(DirectiveLoc, "Encountered a .endif that doesn't follow " + "an .if or .else"); if (!TheCondStack.empty()) { TheCondState = TheCondStack.back(); TheCondStack.pop_back(); @@ -4610,9 +4891,11 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".loc"] = DK_LOC; DirectiveKindMap[".stabs"] = DK_STABS; DirectiveKindMap[".cv_file"] = DK_CV_FILE; + DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID; DirectiveKindMap[".cv_loc"] = DK_CV_LOC; DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE; DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE; + DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID; DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE; DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE; DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS; @@ -4649,16 +4932,39 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; DirectiveKindMap[".reloc"] = DK_RELOC; + DirectiveKindMap[".dc"] = DK_DC; + DirectiveKindMap[".dc.a"] = DK_DC_A; + DirectiveKindMap[".dc.b"] = DK_DC_B; + DirectiveKindMap[".dc.d"] = DK_DC_D; + DirectiveKindMap[".dc.l"] = DK_DC_L; + DirectiveKindMap[".dc.s"] = DK_DC_S; + DirectiveKindMap[".dc.w"] = DK_DC_W; + DirectiveKindMap[".dc.x"] = DK_DC_X; + DirectiveKindMap[".dcb"] = DK_DCB; + DirectiveKindMap[".dcb.b"] = DK_DCB_B; + DirectiveKindMap[".dcb.d"] = DK_DCB_D; + DirectiveKindMap[".dcb.l"] = DK_DCB_L; + DirectiveKindMap[".dcb.s"] = DK_DCB_S; + DirectiveKindMap[".dcb.w"] = DK_DCB_W; + DirectiveKindMap[".dcb.x"] = DK_DCB_X; + DirectiveKindMap[".ds"] = DK_DS; + DirectiveKindMap[".ds.b"] = DK_DS_B; + DirectiveKindMap[".ds.d"] = DK_DS_D; + DirectiveKindMap[".ds.l"] = DK_DS_L; + DirectiveKindMap[".ds.p"] = DK_DS_P; + DirectiveKindMap[".ds.s"] = DK_DS_S; + DirectiveKindMap[".ds.w"] = DK_DS_W; + DirectiveKindMap[".ds.x"] = DK_DS_X; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { AsmToken EndToken, StartToken = getTok(); unsigned NestLevel = 0; - for (;;) { + while (true) { // Check whether we have reached the end of the file. if (getLexer().is(AsmToken::Eof)) { - Error(DirectiveLoc, "no matching '.endr' in definition"); + printError(DirectiveLoc, "no matching '.endr' in definition"); return nullptr; } @@ -4675,7 +4981,8 @@ MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { EndToken = getTok(); Lex(); if (Lexer.isNot(AsmToken::EndOfStatement)) { - TokError("unexpected token in '.endr' directive"); + printError(getTok().getLoc(), + "unexpected token in '.endr' directive"); return nullptr; } break; @@ -4725,7 +5032,6 @@ bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) { int64_t Count; if (!CountExpr->evaluateAsAbsolute(Count)) { - eatToEndOfStatement(); return Error(CountLoc, "unexpected token in '" + Dir + "' directive"); } @@ -4928,11 +5234,16 @@ bool AsmParser::parseMSInlineAsm( continue; ParseStatementInfo Info(&AsmStrRewrites); - if (parseStatement(Info, &SI)) - return true; + bool StatementErr = parseStatement(Info, &SI); - if (Info.ParseError) + if (StatementErr || Info.ParseError) { + // Emit pending errors if any exist. + printPendingErrors(); return true; + } + + // No pending error should exist here. + assert(!hasPendingError() && "unexpected error from parseStatement"); if (Info.Opcode == ~0U) continue; @@ -5158,20 +5469,15 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, SMLoc EqualLoc = Parser.getTok().getLoc(); if (Parser.parseExpression(Value)) { - Parser.TokError("missing expression"); - Parser.eatToEndOfStatement(); - return true; + return Parser.TokError("missing expression"); } // Note: we don't count b as used in "a = b". This is to allow // a = b // b = c - if (Parser.getTok().isNot(AsmToken::EndOfStatement)) - return Parser.TokError("unexpected token in assignment"); - - // Eat the end of statement marker. - Parser.Lex(); + if (Parser.parseToken(AsmToken::EndOfStatement)) + return true; // Validate that the LHS is allowed to be a variable (either it has not been // used as a symbol, or it is an absolute symbol). @@ -5197,7 +5503,7 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, "invalid reassignment of non-absolute variable '" + Name + "'"); } else if (Name == ".") { - Parser.getStreamer().emitValueToOffset(Value, 0); + Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc); return false; } else Sym = Parser.getContext().getOrCreateSymbol(Name); @@ -5207,8 +5513,8 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, return false; } -} // namespace MCParserUtils -} // namespace llvm +} // end namespace MCParserUtils +} // end namespace llvm /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp index 653627ad8dca..f4114795a92d 100644 --- a/lib/MC/MCParser/COFFAsmParser.cpp +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -41,7 +41,8 @@ class COFFAsmParser : public MCAsmParserExtension { COFF::COMDATType Type); bool ParseSectionName(StringRef &SectionName); - bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags); + bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, + unsigned *Flags); void Initialize(MCAsmParser &Parser) override { // Call the base implementation. @@ -155,17 +156,19 @@ static SectionKind computeSectionKind(unsigned Flags) { return SectionKind::getData(); } -bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) { +bool COFFAsmParser::ParseSectionFlags(StringRef SectionName, + StringRef FlagsString, unsigned *Flags) { enum { - None = 0, - Alloc = 1 << 0, - Code = 1 << 1, - Load = 1 << 2, - InitData = 1 << 3, - Shared = 1 << 4, - NoLoad = 1 << 5, - NoRead = 1 << 6, - NoWrite = 1 << 7 + None = 0, + Alloc = 1 << 0, + Code = 1 << 1, + Load = 1 << 2, + InitData = 1 << 3, + Shared = 1 << 4, + NoLoad = 1 << 5, + NoRead = 1 << 6, + NoWrite = 1 << 7, + Discardable = 1 << 8, }; bool ReadOnlyRemoved = false; @@ -198,6 +201,10 @@ bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) { SecFlags &= ~Load; break; + case 'D': // discardable + SecFlags |= Discardable; + break; + case 'r': // read-only ReadOnlyRemoved = false; SecFlags |= NoWrite; @@ -249,6 +256,9 @@ bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) { *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; if (SecFlags & NoLoad) *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; + if ((SecFlags & Discardable) || + MCSectionCOFF::isImplicitlyDiscardable(SectionName)) + *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; if ((SecFlags & NoRead) == 0) *Flags |= COFF::IMAGE_SCN_MEM_READ; if ((SecFlags & NoWrite) == 0) @@ -326,7 +336,8 @@ bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { // a: Ignored. // b: BSS section (uninitialized data) // d: data section (initialized data) -// n: Discardable section +// n: "noload" section (removed by linker) +// D: Discardable section // r: Readable section // s: Shared section // w: Writable section @@ -353,7 +364,7 @@ bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { StringRef FlagsStr = getTok().getStringContents(); Lex(); - if (ParseSectionFlags(FlagsStr, &Flags)) + if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) return true; } @@ -444,13 +455,26 @@ bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { if (getParser().parseIdentifier(SymbolID)) return TokError("expected identifier in directive"); + int64_t Offset = 0; + SMLoc OffsetLoc; + if (getLexer().is(AsmToken::Plus)) { + OffsetLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Offset)) + return true; + } + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); + if (Offset < 0 || Offset > UINT32_MAX) + return Error(OffsetLoc, + "invalid '.secrel32' directive offset, can't be less " + "than zero or greater than UINT32_MAX"); + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); Lex(); - getStreamer().EmitCOFFSecRel32(Symbol); + getStreamer().EmitCOFFSecRel32(Symbol, Offset); return false; } @@ -514,8 +538,8 @@ bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { if (parseCOMDATType(Type)) return true; - const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( - getStreamer().getCurrentSection().first); + const MCSectionCOFF *Current = + static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) return Error(Loc, "cannot make section associative with .linkonce"); diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index 37515d9c074d..94aa70ef0326 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -37,7 +37,7 @@ class DarwinAsmParser : public MCAsmParserExtension { getParser().addDirectiveHandler(Directive, Handler); } - bool parseSectionSwitch(const char *Segment, const char *Section, + bool parseSectionSwitch(StringRef Segment, StringRef Section, unsigned TAA = 0, unsigned ImplicitAlign = 0, unsigned StubSize = 0); @@ -389,8 +389,7 @@ public: } // end anonymous namespace -bool DarwinAsmParser::parseSectionSwitch(const char *Segment, - const char *Section, +bool DarwinAsmParser::parseSectionSwitch(StringRef Segment, StringRef Section, unsigned TAA, unsigned Align, unsigned StubSize) { if (getLexer().isNot(AsmToken::EndOfStatement)) @@ -469,8 +468,8 @@ bool DarwinAsmParser::parseDirectiveDesc(StringRef, SMLoc) { /// parseDirectiveIndirectSymbol /// ::= .indirect_symbol identifier bool DarwinAsmParser::parseDirectiveIndirectSymbol(StringRef, SMLoc Loc) { - const MCSectionMachO *Current = static_cast<const MCSectionMachO*>( - getStreamer().getCurrentSection().first); + const MCSectionMachO *Current = static_cast<const MCSectionMachO *>( + getStreamer().getCurrentSectionOnly()); MachO::SectionType SectionType = Current->getType(); if (SectionType != MachO::S_NON_LAZY_SYMBOL_POINTERS && SectionType != MachO::S_LAZY_SYMBOL_POINTERS && @@ -615,7 +614,7 @@ bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) { TAA, TAAParsed, StubSize); if (!ErrorStr.empty()) - return Error(Loc, ErrorStr.c_str()); + return Error(Loc, ErrorStr); // Issue a warning if the target is not powerpc and Section is a *coal* section. Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple(); @@ -700,7 +699,7 @@ bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { if (!OS) { std::error_code EC; auto NewOS = llvm::make_unique<raw_fd_ostream>( - SecureLogFile, EC, sys::fs::F_Append | sys::fs::F_Text); + StringRef(SecureLogFile), EC, sys::fs::F_Append | sys::fs::F_Text); if (EC) return Error(IDLoc, Twine("can't open secure log file: ") + SecureLogFile + " (" + EC.message() + ")"); diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index 47d19a824d19..8d7ba0d03362 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -264,6 +264,10 @@ bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { unsigned flags = 0; + // If a valid numerical value is set for the section flag, use it verbatim + if (!flagsStr.getAsInteger(0, flags)) + return flags; + for (char i : flagsStr) { switch (i) { case 'a': @@ -293,6 +297,9 @@ static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { case 'd': flags |= ELF::XCORE_SHF_DP_SECTION; break; + case 'y': + flags |= ELF::SHF_ARM_PURECODE; + break; case 'G': flags |= ELF::SHF_GROUP; break; diff --git a/lib/MC/MCParser/MCAsmLexer.cpp b/lib/MC/MCParser/MCAsmLexer.cpp index d95cd12accbc..63c0daba09a0 100644 --- a/lib/MC/MCParser/MCAsmLexer.cpp +++ b/lib/MC/MCParser/MCAsmLexer.cpp @@ -12,7 +12,9 @@ using namespace llvm; -MCAsmLexer::MCAsmLexer() : TokStart(nullptr), SkipSpace(true) { +MCAsmLexer::MCAsmLexer() + : TokStart(nullptr), SkipSpace(true), IsAtStartOfStatement(true), + CommentConsumer(nullptr) { CurTok.emplace_back(AsmToken::Space, StringRef()); } diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp index dc7a3f00840f..98f4daf972d6 100644 --- a/lib/MC/MCParser/MCAsmParser.cpp +++ b/lib/MC/MCParser/MCAsmParser.cpp @@ -17,8 +17,9 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; -MCAsmParser::MCAsmParser() : TargetParser(nullptr), ShowParsedOperands(0) { -} +MCAsmParser::MCAsmParser() + : TargetParser(nullptr), ShowParsedOperands(0), HadError(false), + PendingErrors() {} MCAsmParser::~MCAsmParser() { } @@ -33,18 +34,109 @@ const AsmToken &MCAsmParser::getTok() const { return getLexer().getTok(); } -bool MCAsmParser::TokError(const Twine &Msg, ArrayRef<SMRange> Ranges) { - Error(getLexer().getLoc(), Msg, Ranges); +bool MCAsmParser::parseTokenLoc(SMLoc &Loc) { + Loc = getTok().getLoc(); + return false; +} + +bool MCAsmParser::parseEOL(const Twine &Msg) { + if (getTok().getKind() == AsmToken::Hash) { + StringRef CommentStr = parseStringToEndOfStatement(); + getLexer().Lex(); + getLexer().UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); + } + if (getTok().getKind() != AsmToken::EndOfStatement) + return Error(getTok().getLoc(), Msg); + Lex(); + return false; +} + +bool MCAsmParser::parseToken(AsmToken::TokenKind T, const Twine &Msg) { + if (T == AsmToken::EndOfStatement) + return parseEOL(Msg); + if (getTok().getKind() != T) + return Error(getTok().getLoc(), Msg); + Lex(); + return false; +} + +bool MCAsmParser::parseIntToken(int64_t &V, const Twine &Msg) { + if (getTok().getKind() != AsmToken::Integer) + return TokError(Msg); + V = getTok().getIntVal(); + Lex(); + return false; +} + +bool MCAsmParser::parseOptionalToken(AsmToken::TokenKind T) { + bool Present = (getTok().getKind() == T); + // if token is EOL and current token is # this is an EOL comment. + if (getTok().getKind() == AsmToken::Hash && T == AsmToken::EndOfStatement) + Present = true; + if (Present) + parseToken(T); + return Present; +} + +bool MCAsmParser::check(bool P, const Twine &Msg) { + return check(P, getTok().getLoc(), Msg); +} + +bool MCAsmParser::check(bool P, SMLoc Loc, const Twine &Msg) { + if (P) + return Error(Loc, Msg); + return false; +} + +bool MCAsmParser::TokError(const Twine &Msg, SMRange Range) { + return Error(getLexer().getLoc(), Msg, Range); +} + +bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) { + HadError = true; + + MCPendingError PErr; + PErr.Loc = L; + Msg.toVector(PErr.Msg); + PErr.Range = Range; + PendingErrors.push_back(PErr); + + // If we threw this parsing error after a lexing error, this should + // supercede the lexing error and so we remove it from the Lexer + // before it can propagate + if (getTok().is(AsmToken::Error)) + getLexer().Lex(); + return true; +} + +bool MCAsmParser::addErrorSuffix(const Twine &Suffix) { + // Make sure lexing errors have propagated to the parser. + if (getTok().is(AsmToken::Error)) + Lex(); + for (auto &PErr : PendingErrors) + Suffix.toVector(PErr.Msg); return true; } +bool MCAsmParser::parseMany(std::function<bool()> parseOne, bool hasComma) { + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + while (1) { + if (parseOne()) + return true; + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + if (hasComma && parseToken(AsmToken::Comma)) + return true; + } + return false; +} + bool MCAsmParser::parseExpression(const MCExpr *&Res) { SMLoc L; return parseExpression(Res, L); } LLVM_DUMP_METHOD void MCParsedAsmOperand::dump() const { -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) dbgs() << " " << *this; -#endif } diff --git a/lib/MC/MCRegisterInfo.cpp b/lib/MC/MCRegisterInfo.cpp index c76bb646c126..ea117f3caa85 100644 --- a/lib/MC/MCRegisterInfo.cpp +++ b/lib/MC/MCRegisterInfo.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -62,6 +64,8 @@ int MCRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { const DwarfLLVMRegPair *M = isEH ? EHL2DwarfRegs : L2DwarfRegs; unsigned Size = isEH ? EHL2DwarfRegsSize : L2DwarfRegsSize; + if (!M) + return -1; DwarfLLVMRegPair Key = { RegNum, 0 }; const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); if (I == M+Size || I->FromReg != RegNum) @@ -73,6 +77,8 @@ int MCRegisterInfo::getLLVMRegNum(unsigned RegNum, bool isEH) const { const DwarfLLVMRegPair *M = isEH ? EHDwarf2LRegs : Dwarf2LRegs; unsigned Size = isEH ? EHDwarf2LRegsSize : Dwarf2LRegsSize; + if (!M) + return -1; DwarfLLVMRegPair Key = { RegNum, 0 }; const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); assert(I != M+Size && I->FromReg == RegNum && "Invalid RegNum"); diff --git a/lib/MC/MCSection.cpp b/lib/MC/MCSection.cpp index 32e4cce4f68c..9064cdf2f319 100644 --- a/lib/MC/MCSection.cpp +++ b/lib/MC/MCSection.cpp @@ -85,7 +85,6 @@ MCSection::getSubsectionInsertionPoint(unsigned Subsection) { return IP; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCSection::dump() { raw_ostream &OS = llvm::errs(); @@ -98,12 +97,3 @@ LLVM_DUMP_METHOD void MCSection::dump() { } OS << "]>"; } -#endif - -MCSection::iterator MCSection::begin() { return Fragments.begin(); } - -MCSection::iterator MCSection::end() { return Fragments.end(); } - -MCSection::reverse_iterator MCSection::rbegin() { return Fragments.rbegin(); } - -MCSection::reverse_iterator MCSection::rend() { return Fragments.rend(); } diff --git a/lib/MC/MCSectionCOFF.cpp b/lib/MC/MCSectionCOFF.cpp index b8373f40b8be..f2dd47d81b7e 100644 --- a/lib/MC/MCSectionCOFF.cpp +++ b/lib/MC/MCSectionCOFF.cpp @@ -64,6 +64,9 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, OS << 'n'; if (getCharacteristics() & COFF::IMAGE_SCN_MEM_SHARED) OS << 's'; + if ((getCharacteristics() & COFF::IMAGE_SCN_MEM_DISCARDABLE) && + !isImplicitlyDiscardable(SectionName)) + OS << 'D'; OS << '"'; if (getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) { diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index 5a0bb7fe986f..587b28f71b7d 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -110,6 +110,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, OS << 'c'; if (Flags & ELF::XCORE_SHF_DP_SECTION) OS << 'd'; + if (Flags & ELF::SHF_ARM_PURECODE) + OS << 'y'; OS << '"'; diff --git a/lib/MC/MCSectionMachO.cpp b/lib/MC/MCSectionMachO.cpp index 879c6e5ff932..c2a772fdbdac 100644 --- a/lib/MC/MCSectionMachO.cpp +++ b/lib/MC/MCSectionMachO.cpp @@ -17,10 +17,10 @@ using namespace llvm; /// types. This *must* be kept in order with and stay synchronized with the /// section type list. static const struct { - const char *AssemblerName, *EnumName; + StringRef AssemblerName, EnumName; } SectionTypeDescriptors[MachO::LAST_KNOWN_SECTION_TYPE+1] = { { "regular", "S_REGULAR" }, // 0x00 - { nullptr, "S_ZEROFILL" }, // 0x01 + { StringRef(), "S_ZEROFILL" }, // 0x01 { "cstring_literals", "S_CSTRING_LITERALS" }, // 0x02 { "4byte_literals", "S_4BYTE_LITERALS" }, // 0x03 { "8byte_literals", "S_8BYTE_LITERALS" }, // 0x04 @@ -31,11 +31,11 @@ static const struct { { "mod_init_funcs", "S_MOD_INIT_FUNC_POINTERS" }, // 0x09 { "mod_term_funcs", "S_MOD_TERM_FUNC_POINTERS" }, // 0x0A { "coalesced", "S_COALESCED" }, // 0x0B - { nullptr, /*FIXME??*/ "S_GB_ZEROFILL" }, // 0x0C + { StringRef(), /*FIXME??*/ "S_GB_ZEROFILL" }, // 0x0C { "interposing", "S_INTERPOSING" }, // 0x0D { "16byte_literals", "S_16BYTE_LITERALS" }, // 0x0E - { nullptr, /*FIXME??*/ "S_DTRACE_DOF" }, // 0x0F - { nullptr, /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" }, // 0x10 + { StringRef(), /*FIXME??*/ "S_DTRACE_DOF" }, // 0x0F + { StringRef(), /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" }, // 0x10 { "thread_local_regular", "S_THREAD_LOCAL_REGULAR" }, // 0x11 { "thread_local_zerofill", "S_THREAD_LOCAL_ZEROFILL" }, // 0x12 { "thread_local_variables", "S_THREAD_LOCAL_VARIABLES" }, // 0x13 @@ -51,7 +51,7 @@ static const struct { /// by attribute, instead it is searched. static const struct { unsigned AttrFlag; - const char *AssemblerName, *EnumName; + StringRef AssemblerName, EnumName; } SectionAttrDescriptors[] = { #define ENTRY(ASMNAME, ENUM) \ { MachO::ENUM, ASMNAME, #ENUM }, @@ -62,11 +62,11 @@ ENTRY("no_dead_strip", S_ATTR_NO_DEAD_STRIP) ENTRY("live_support", S_ATTR_LIVE_SUPPORT) ENTRY("self_modifying_code", S_ATTR_SELF_MODIFYING_CODE) ENTRY("debug", S_ATTR_DEBUG) -ENTRY(nullptr /*FIXME*/, S_ATTR_SOME_INSTRUCTIONS) -ENTRY(nullptr /*FIXME*/, S_ATTR_EXT_RELOC) -ENTRY(nullptr /*FIXME*/, S_ATTR_LOC_RELOC) +ENTRY(StringRef() /*FIXME*/, S_ATTR_SOME_INSTRUCTIONS) +ENTRY(StringRef() /*FIXME*/, S_ATTR_EXT_RELOC) +ENTRY(StringRef() /*FIXME*/, S_ATTR_LOC_RELOC) #undef ENTRY - { 0, "none", nullptr }, // used if section has no attributes but has a stub size + { 0, "none", StringRef() }, // used if section has no attributes but has a stub size }; MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section, @@ -105,7 +105,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, assert(SectionType <= MachO::LAST_KNOWN_SECTION_TYPE && "Invalid SectionType specified!"); - if (SectionTypeDescriptors[SectionType].AssemblerName) { + if (!SectionTypeDescriptors[SectionType].AssemblerName.empty()) { OS << ','; OS << SectionTypeDescriptors[SectionType].AssemblerName; } else { @@ -138,7 +138,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, SectionAttrs &= ~SectionAttrDescriptors[i].AttrFlag; OS << Separator; - if (SectionAttrDescriptors[i].AssemblerName) + if (!SectionAttrDescriptors[i].AssemblerName.empty()) OS << SectionAttrDescriptors[i].AssemblerName; else OS << "<<" << SectionAttrDescriptors[i].EnumName << ">>"; @@ -212,8 +212,7 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. auto TypeDescriptor = std::find_if( std::begin(SectionTypeDescriptors), std::end(SectionTypeDescriptors), [&](decltype(*SectionTypeDescriptors) &Descriptor) { - return Descriptor.AssemblerName && - SectionType == Descriptor.AssemblerName; + return SectionType == Descriptor.AssemblerName; }); // If we didn't find the section type, reject it. @@ -241,8 +240,7 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. auto AttrDescriptorI = std::find_if( std::begin(SectionAttrDescriptors), std::end(SectionAttrDescriptors), [&](decltype(*SectionAttrDescriptors) &Descriptor) { - return Descriptor.AssemblerName && - SectionAttr.trim() == Descriptor.AssemblerName; + return SectionAttr.trim() == Descriptor.AssemblerName; }); if (AttrDescriptorI == std::end(SectionAttrDescriptors)) return "mach-o section specifier has invalid attribute"; diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 6c8828f71ba2..fb28f856f671 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -124,7 +125,23 @@ void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, if (!IsSectionRelative) EmitValueImpl(MCSymbolRefExpr::create(Sym, getContext()), Size); else - EmitCOFFSecRel32(Sym); + EmitCOFFSecRel32(Sym, /*Offset=*/0); +} + +void MCStreamer::EmitDTPRel64Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitDTPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitTPRel64Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitTPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); } void MCStreamer::EmitGPRel64Value(const MCExpr *Value) { @@ -199,26 +216,58 @@ void MCStreamer::EnsureValidDwarfFrame() { report_fatal_error("No open frame"); } -unsigned MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { - return getContext().getCVFile(Filename, FileNo); +bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) { + return getContext().getCVContext().addFile(FileNo, Filename); +} + +bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) { + return getContext().getCVContext().recordFunctionId(FunctionId); +} + +bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId, + unsigned IAFunc, unsigned IAFile, + unsigned IALine, unsigned IACol, + SMLoc Loc) { + if (getContext().getCVContext().getCVFunctionInfo(IAFunc) == nullptr) { + getContext().reportError(Loc, "parent function id not introduced by " + ".cv_func_id or .cv_inline_site_id"); + return true; + } + + return getContext().getCVContext().recordInlinedCallSiteId( + FunctionId, IAFunc, IAFile, IALine, IACol); } void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, - StringRef FileName) { - getContext().setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, - IsStmt); + StringRef FileName, SMLoc Loc) { + CodeViewContext &CVC = getContext().getCVContext(); + MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FunctionId); + if (!FI) + return getContext().reportError( + Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id"); + + // Track the section + if (FI->Section == nullptr) + FI->Section = getCurrentSectionOnly(); + else if (FI->Section != getCurrentSectionOnly()) + return getContext().reportError( + Loc, + "all .cv_loc directives for a function must be in the same section"); + + CVC.setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt); } void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin, const MCSymbol *End) {} -void MCStreamer::EmitCVInlineLinetableDirective( - unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, - const MCSymbol *FnStartSym, const MCSymbol *FnEndSym, - ArrayRef<unsigned> SecondaryFunctionIds) {} +void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId, + unsigned SourceFileId, + unsigned SourceLineNum, + const MCSymbol *FnStartSym, + const MCSymbol *FnEndSym) {} void MCStreamer::EmitCVDefRangeDirective( ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, @@ -243,7 +292,7 @@ void MCStreamer::AssignFragment(MCSymbol *Symbol, MCFragment *Fragment) { void MCStreamer::EmitLabel(MCSymbol *Symbol) { assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(getCurrentSection().first && "Cannot emit before setting section!"); + assert(getCurrentSectionOnly() && "Cannot emit before setting section!"); assert(!Symbol->getFragment() && "Unexpected fragment on symbol data!"); Symbol->setFragment(&getCurrentSectionOnly()->getDummyFragment()); @@ -292,13 +341,17 @@ void MCStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { Frame.End = (MCSymbol *) 1; } -MCSymbol *MCStreamer::EmitCFICommon() { - EnsureValidDwarfFrame(); - MCSymbol *Label = getContext().createTempSymbol(); +MCSymbol *MCStreamer::EmitCFILabel() { + MCSymbol *Label = getContext().createTempSymbol("cfi", true); EmitLabel(Label); return Label; } +MCSymbol *MCStreamer::EmitCFICommon() { + EnsureValidDwarfFrame(); + return EmitCFILabel(); +} + void MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { MCSymbol *Label = EmitCFICommon(); MCCFIInstruction Instruction = @@ -455,8 +508,7 @@ void MCStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol) { if (CurrentWinFrameInfo && !CurrentWinFrameInfo->End) report_fatal_error("Starting a function before ending the previous one!"); - MCSymbol *StartProc = getContext().createTempSymbol(); - EmitLabel(StartProc); + MCSymbol *StartProc = EmitCFILabel(); WinFrameInfos.push_back(new WinEH::FrameInfo(Symbol, StartProc)); CurrentWinFrameInfo = WinFrameInfos.back(); @@ -468,16 +520,14 @@ void MCStreamer::EmitWinCFIEndProc() { if (CurrentWinFrameInfo->ChainedParent) report_fatal_error("Not all chained regions terminated!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); CurrentWinFrameInfo->End = Label; } void MCStreamer::EmitWinCFIStartChained() { EnsureValidWinFrameInfo(); - MCSymbol *StartProc = getContext().createTempSymbol(); - EmitLabel(StartProc); + MCSymbol *StartProc = EmitCFILabel(); WinFrameInfos.push_back(new WinEH::FrameInfo(CurrentWinFrameInfo->Function, StartProc, CurrentWinFrameInfo)); @@ -490,8 +540,7 @@ void MCStreamer::EmitWinCFIEndChained() { if (!CurrentWinFrameInfo->ChainedParent) report_fatal_error("End of a chained region outside a chained region!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); CurrentWinFrameInfo->End = Label; CurrentWinFrameInfo = @@ -555,8 +604,7 @@ void MCStreamer::EmitSyntaxDirective() {} void MCStreamer::EmitWinCFIPushReg(unsigned Register) { EnsureValidWinFrameInfo(); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(Label, Register); CurrentWinFrameInfo->Instructions.push_back(Inst); @@ -571,8 +619,7 @@ void MCStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset) { if (Offset > 240) report_fatal_error("Frame offset must be less than or equal to 240!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SetFPReg(Label, Register, Offset); @@ -587,8 +634,7 @@ void MCStreamer::EmitWinCFIAllocStack(unsigned Size) { if (Size & 7) report_fatal_error("Misaligned stack allocation!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::Alloc(Label, Size); CurrentWinFrameInfo->Instructions.push_back(Inst); @@ -599,8 +645,7 @@ void MCStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset) { if (Offset & 7) report_fatal_error("Misaligned saved register offset!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol(Label, Register, Offset); @@ -612,8 +657,7 @@ void MCStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset) { if (Offset & 0x0F) report_fatal_error("Misaligned saved vector register offset!"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM(Label, Register, Offset); @@ -625,8 +669,7 @@ void MCStreamer::EmitWinCFIPushFrame(bool Code) { if (CurrentWinFrameInfo->Instructions.size() > 0) report_fatal_error("If present, PushMachFrame must be the first UOP"); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); WinEH::Instruction Inst = Win64EH::Instruction::PushMachFrame(Label, Code); CurrentWinFrameInfo->Instructions.push_back(Inst); @@ -635,8 +678,7 @@ void MCStreamer::EmitWinCFIPushFrame(bool Code) { void MCStreamer::EmitWinCFIEndProlog() { EnsureValidWinFrameInfo(); - MCSymbol *Label = getContext().createTempSymbol(); - EmitLabel(Label); + MCSymbol *Label = EmitCFILabel(); CurrentWinFrameInfo->PrologEnd = Label; } @@ -647,8 +689,7 @@ void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { } -void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { -} +void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {} /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is @@ -756,7 +797,7 @@ void MCStreamer::EndCOFFSymbolDef() {} void MCStreamer::EmitFileDirective(StringRef Filename) {} void MCStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {} void MCStreamer::EmitCOFFSymbolType(int Type) {} -void MCStreamer::emitELFSize(MCSymbolELF *Symbol, const MCExpr *Value) {} +void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} void MCStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, @@ -778,7 +819,8 @@ void MCStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned MaxBytesToEmit) {} void MCStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) {} -void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value) {} +void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, + SMLoc Loc) {} void MCStreamer::EmitBundleAlignMode(unsigned AlignPow2) {} void MCStreamer::EmitBundleLock(bool AlignToEnd) {} void MCStreamer::FinishImpl() {} diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp index 2ddece6bddce..20d985df7ea0 100644 --- a/lib/MC/MCSymbol.cpp +++ b/lib/MC/MCSymbol.cpp @@ -31,10 +31,9 @@ void *MCSymbol::operator new(size_t s, const StringMapEntry<bool> *Name, // For safety, ensure that the alignment of a pointer is enough for an // MCSymbol. This also ensures we don't need padding between the name and // symbol. - static_assert((unsigned)AlignOf<MCSymbol>::Alignment <= - AlignOf<NameEntryStorageTy>::Alignment, + static_assert((unsigned)alignof(MCSymbol) <= alignof(NameEntryStorageTy), "Bad alignment of MCSymbol"); - void *Storage = Ctx.allocate(Size, alignOf<NameEntryStorageTy>()); + void *Storage = Ctx.allocate(Size, alignof(NameEntryStorageTy)); NameEntryStorageTy *Start = static_cast<NameEntryStorageTy*>(Storage); NameEntryStorageTy *End = Start + (Name ? 1 : 0); return End; @@ -76,6 +75,4 @@ void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const { OS << '"'; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCSymbol::dump() const { dbgs() << *this; } -#endif diff --git a/lib/MC/MCTargetOptions.cpp b/lib/MC/MCTargetOptions.cpp index 465622715526..419210537eea 100644 --- a/lib/MC/MCTargetOptions.cpp +++ b/lib/MC/MCTargetOptions.cpp @@ -14,10 +14,12 @@ namespace llvm { MCTargetOptions::MCTargetOptions() : SanitizeAddress(false), MCRelaxAll(false), MCNoExecStack(false), - MCFatalWarnings(false), MCNoWarn(false), MCSaveTempLabels(false), + MCFatalWarnings(false), MCNoWarn(false), MCNoDeprecatedWarn(false), + MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), - ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), - DwarfVersion(0), ABIName() {} + MCPIECopyRelocations(false), ShowMCEncoding(false), + ShowMCInst(false), AsmVerbose(false), + PreserveAsmComments(true), DwarfVersion(0), ABIName() {} StringRef MCTargetOptions::getABIName() const { return ABIName; diff --git a/lib/MC/MCValue.cpp b/lib/MC/MCValue.cpp index 32a6adbf224e..c1336d6d1b49 100644 --- a/lib/MC/MCValue.cpp +++ b/lib/MC/MCValue.cpp @@ -37,11 +37,9 @@ void MCValue::print(raw_ostream &OS) const { OS << " + " << getConstant(); } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCValue::dump() const { print(dbgs()); } -#endif MCSymbolRefExpr::VariantKind MCValue::getAccessVariant() const { const MCSymbolRefExpr *B = getSymB(); diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index e39271949d94..c4b35f5db9b4 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -422,7 +422,7 @@ void MachObjectWriter::writeLinkerOptionsLoadCommand( uint64_t BytesWritten = sizeof(MachO::linker_option_command); for (const std::string &Option : Options) { // Write each string, including the null byte. - writeBytes(Option.c_str(), Option.size() + 1); + writeBytes(Option, Option.size() + 1); BytesWritten += Option.size() + 1; } @@ -882,7 +882,7 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, sizeof(MachO::nlist_64) : sizeof(MachO::nlist)); writeSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, - StringTableOffset, StringTable.data().size()); + StringTableOffset, StringTable.getSize()); writeDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, FirstExternalSymbol, NumExternalSymbols, @@ -977,7 +977,7 @@ void MachObjectWriter::writeObject(MCAssembler &Asm, writeNlist(Entry, Layout); // Write the string table. - getStream() << StringTable.data(); + StringTable.write(getStream()); } } diff --git a/lib/MC/StringTableBuilder.cpp b/lib/MC/StringTableBuilder.cpp index 9d95952a6d30..1a501bcafc12 100644 --- a/lib/MC/StringTableBuilder.cpp +++ b/lib/MC/StringTableBuilder.cpp @@ -9,15 +9,18 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" #include <vector> using namespace llvm; -StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment) - : K(K), Alignment(Alignment) { +StringTableBuilder::~StringTableBuilder() {} + +void StringTableBuilder::initSize() { // Account for leading bytes in table so that offsets returned from add are // correct. switch (K) { @@ -26,19 +29,46 @@ StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment) break; case MachO: case ELF: + // Start the table with a NUL byte. Size = 1; break; case WinCOFF: + // Make room to write the table size later. Size = 4; break; } } -typedef std::pair<CachedHash<StringRef>, size_t> StringPair; +StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment) + : K(K), Alignment(Alignment) { + initSize(); +} + +void StringTableBuilder::write(raw_ostream &OS) const { + assert(isFinalized()); + SmallString<0> Data; + Data.resize(getSize()); + write((uint8_t *)&Data[0]); + OS << Data; +} + +typedef std::pair<CachedHashStringRef, size_t> StringPair; + +void StringTableBuilder::write(uint8_t *Buf) const { + assert(isFinalized()); + for (const StringPair &P : StringIndexMap) { + StringRef Data = P.first.val(); + if (!Data.empty()) + memcpy(Buf + P.second, Data.data(), Data.size()); + } + if (K != WinCOFF) + return; + support::endian::write32le(Buf, Size); +} // Returns the character at Pos from end of a string. static int charTailAt(StringPair *P, size_t Pos) { - StringRef S = P->first.Val; + StringRef S = P->first.val(); if (Pos >= S.size()) return -1; return (unsigned char)S[S.size() - Pos - 1]; @@ -86,106 +116,69 @@ void StringTableBuilder::finalizeInOrder() { } void StringTableBuilder::finalizeStringTable(bool Optimize) { - typedef std::pair<CachedHash<StringRef>, size_t> StringOffsetPair; - std::vector<StringOffsetPair *> Strings; - Strings.reserve(StringIndexMap.size()); - for (StringOffsetPair &P : StringIndexMap) - Strings.push_back(&P); - - if (!Strings.empty()) { - // If we're optimizing, sort by name. If not, sort by previously assigned - // offset. - if (Optimize) { - multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0); - } else { - std::sort(Strings.begin(), Strings.end(), - [](const StringOffsetPair *LHS, const StringOffsetPair *RHS) { - return LHS->second < RHS->second; - }); - } - } + Finalized = true; - switch (K) { - case RAW: - break; - case ELF: - case MachO: - // Start the table with a NUL byte. - StringTable += '\x00'; - break; - case WinCOFF: - // Make room to write the table size later. - StringTable.append(4, '\x00'); - break; - } + if (Optimize) { + std::vector<StringPair *> Strings; + Strings.reserve(StringIndexMap.size()); + for (StringPair &P : StringIndexMap) + Strings.push_back(&P); - StringRef Previous; - for (StringOffsetPair *P : Strings) { - StringRef S = P->first.Val; - if (K == WinCOFF) - assert(S.size() > COFF::NameSize && "Short string in COFF string table!"); - - if (Optimize && Previous.endswith(S)) { - size_t Pos = StringTable.size() - S.size() - (K != RAW); - if (!(Pos & (Alignment - 1))) { - P->second = Pos; - continue; - } + if (!Strings.empty()) { + // If we're optimizing, sort by name. If not, sort by previously assigned + // offset. + multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0); } - if (Optimize) { - size_t Start = alignTo(StringTable.size(), Alignment); - P->second = Start; - StringTable.append(Start - StringTable.size(), '\0'); - } else { - assert(P->second == StringTable.size() && - "different strtab offset after finalization"); - } + initSize(); + + StringRef Previous; + for (StringPair *P : Strings) { + StringRef S = P->first.val(); + if (Previous.endswith(S)) { + size_t Pos = Size - S.size() - (K != RAW); + if (!(Pos & (Alignment - 1))) { + P->second = Pos; + continue; + } + } - StringTable += S; - if (K != RAW) - StringTable += '\x00'; - Previous = S; - } + Size = alignTo(Size, Alignment); + P->second = Size; - switch (K) { - case RAW: - case ELF: - break; - case MachO: - // Pad to multiple of 4. - while (StringTable.size() % 4) - StringTable += '\x00'; - break; - case WinCOFF: - // Write the table size in the first word. - assert(StringTable.size() <= std::numeric_limits<uint32_t>::max()); - uint32_t Size = static_cast<uint32_t>(StringTable.size()); - support::endian::write<uint32_t, support::little, support::unaligned>( - StringTable.data(), Size); - break; + Size += S.size(); + if (K != RAW) + ++Size; + Previous = S; + } } - Size = StringTable.size(); + if (K == MachO) + Size = alignTo(Size, 4); // Pad to multiple of 4. } void StringTableBuilder::clear() { - StringTable.clear(); + Finalized = false; StringIndexMap.clear(); } -size_t StringTableBuilder::getOffset(StringRef S) const { +size_t StringTableBuilder::getOffset(CachedHashStringRef S) const { assert(isFinalized()); auto I = StringIndexMap.find(S); assert(I != StringIndexMap.end() && "String is not in table!"); return I->second; } -size_t StringTableBuilder::add(StringRef S) { +size_t StringTableBuilder::add(CachedHashStringRef S) { + if (K == WinCOFF) + assert(S.size() > COFF::NameSize && "Short string in COFF string table!"); + assert(!isFinalized()); - size_t Start = alignTo(Size, Alignment); - auto P = StringIndexMap.insert(std::make_pair(S, Start)); - if (P.second) + auto P = StringIndexMap.insert(std::make_pair(S, 0)); + if (P.second) { + size_t Start = alignTo(Size, Alignment); + P.first->second = Start; Size = Start + S.size() + (K != RAW); + } return P.first->second; } diff --git a/lib/MC/SubtargetFeature.cpp b/lib/MC/SubtargetFeature.cpp index a97cd1db6932..32f06f8a7d6a 100644 --- a/lib/MC/SubtargetFeature.cpp +++ b/lib/MC/SubtargetFeature.cpp @@ -282,13 +282,11 @@ void SubtargetFeatures::print(raw_ostream &OS) const { OS << "\n"; } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// dump - Dump feature info. /// LLVM_DUMP_METHOD void SubtargetFeatures::dump() const { print(dbgs()); } -#endif /// Adds the default features for the specified target triple. /// diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index f316a5af387d..afc5c6a14d11 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -34,7 +34,6 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/JamCRC.h" -#include "llvm/Support/TimeValue.h" #include <cstdio> #include <ctime> @@ -792,7 +791,7 @@ void WinCOFFObjectWriter::recordRelocation( } } - // The fixed value never makes sense for section indicies, ignore it. + // The fixed value never makes sense for section indices, ignore it. if (Fixup.getKind() == FK_SecRel_2) FixedValue = 0; @@ -1082,7 +1081,7 @@ void WinCOFFObjectWriter::writeObject(MCAssembler &Asm, if (Symbol->getIndex() != -1) WriteSymbol(*Symbol); - getStream().write(Strings.data().data(), Strings.data().size()); + Strings.write(getStream()); } MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index 5c6407ef1e5c..6383d8794030 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -195,11 +195,20 @@ void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { DF->getContents().resize(DF->getContents().size() + 2, 0); } -void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { +void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, + uint64_t Offset) { MCDataFragment *DF = getOrCreateDataFragment(); - const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); - MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_4); + // Create Symbol A for the relocation relative reference. + const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext()); + // Add the constant offset, if given. + if (Offset) + MCE = MCBinaryExpr::createAdd( + MCE, MCConstantExpr::create(Offset, getContext()), getContext()); + // Build the secrel32 relocation. + MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_SecRel_4); + // Record the relocation. DF->getFixups().push_back(Fixup); + // Emit 4 bytes (zeros) to the object file. DF->getContents().resize(DF->getContents().size() + 4, 0); } |