diff options
Diffstat (limited to 'lib/MC/MCParser/AsmParser.cpp')
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 421 |
1 files changed, 245 insertions, 176 deletions
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 2259136c6ec4..39a760826d96 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -50,6 +50,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" @@ -79,32 +80,11 @@ static cl::opt<unsigned> AsmMacroMaxNestingDepth( namespace { -/// \brief Helper types for tracking macro definitions. +/// Helper types for tracking macro definitions. typedef std::vector<AsmToken> MCAsmMacroArgument; typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments; -struct MCAsmMacroParameter { - StringRef Name; - MCAsmMacroArgument Value; - bool Required = false; - bool Vararg = false; - - MCAsmMacroParameter() = default; -}; - -typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters; - -struct MCAsmMacro { - StringRef Name; - StringRef Body; - MCAsmMacroParameters Parameters; - -public: - MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P) - : Name(N), Body(B), Parameters(std::move(P)) {} -}; - -/// \brief Helper class for storing information about an active macro +/// Helper class for storing information about an active macro /// instantiation. struct MacroInstantiation { /// The location of the instantiation. @@ -124,13 +104,13 @@ public: }; struct ParseStatementInfo { - /// \brief The parsed operands from the last parsed statement. + /// The parsed operands from the last parsed statement. SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands; - /// \brief The opcode from the last parsed instruction. + /// The opcode from the last parsed instruction. unsigned Opcode = ~0U; - /// \brief Was there an error parsing the inline assembly? + /// Was there an error parsing the inline assembly? bool ParseError = false; SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr; @@ -140,7 +120,7 @@ struct ParseStatementInfo { : AsmRewrites(rewrites) {} }; -/// \brief The concrete assembly parser instance. +/// The concrete assembly parser instance. class AsmParser : public MCAsmParser { private: AsmLexer Lexer; @@ -159,24 +139,21 @@ private: AsmCond TheCondState; std::vector<AsmCond> TheCondStack; - /// \brief maps directive names to handler methods in parser + /// maps directive names to handler methods in parser /// extensions. Extensions register themselves in this map by calling /// addDirectiveHandler. StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap; - /// \brief Map of currently defined macros. - StringMap<MCAsmMacro> MacroMap; - - /// \brief Stack of active macro instantiations. + /// Stack of active macro instantiations. std::vector<MacroInstantiation*> ActiveMacros; - /// \brief List of bodies of anonymous macros. + /// List of bodies of anonymous macros. std::deque<MCAsmMacro> MacroLikeBodies; /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabledFlag : 1; - /// \brief Keeps track of how many .macro's have been instantiated. + /// Keeps track of how many .macro's have been instantiated. unsigned NumOfMacroInstantiations; /// The values from the last parsed cpp hash file line comment if any. @@ -188,26 +165,21 @@ private: }; CppHashInfoTy CppHashInfo; - /// \brief List of forward directional labels for diagnosis at the end. + /// List of forward directional labels for diagnosis at the end. SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels; - /// When generating dwarf for assembly source files we need to calculate the - /// logical line number based on the last parsed cpp hash file line comment - /// and current line. Since this is slow and messes up the SourceMgr's - /// cache we save the last info we queried with SrcMgr.FindLineNumber(). - SMLoc LastQueryIDLoc; - unsigned LastQueryBuffer; - unsigned LastQueryLine; - /// AssemblerDialect. ~OU means unset value and use value provided by MAI. unsigned AssemblerDialect = ~0U; - /// \brief is Darwin compatibility enabled? + /// is Darwin compatibility enabled? bool IsDarwin = false; - /// \brief Are we parsing ms-style inline assembly? + /// Are we parsing ms-style inline assembly? bool ParsingInlineAsm = false; + /// Did we already inform the user about inconsistent MD5 usage? + bool ReportedInconsistentMD5 = false; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); @@ -274,11 +246,11 @@ public: SMLoc &EndLoc) override; bool parseAbsoluteExpression(int64_t &Res) override; - /// \brief Parse a floating point expression using the float \p Semantics + /// 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) + /// 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; @@ -302,39 +274,28 @@ private: ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable, SMLoc L); - /// \brief Are macros enabled in the parser? + /// Are macros enabled in the parser? bool areMacrosEnabled() {return MacrosEnabledFlag;} - /// \brief Control a flag in the parser that enables or disables macros. + /// Control a flag in the parser that enables or disables macros. void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;} - /// \brief Lookup a previously defined macro. - /// \param Name Macro name. - /// \returns Pointer to macro. NULL if no such macro was defined. - const MCAsmMacro* lookupMacro(StringRef Name); - - /// \brief Define a new macro with the given name and information. - void defineMacro(StringRef Name, MCAsmMacro Macro); - - /// \brief Undefine a macro. If no such macro was defined, it's a no-op. - void undefineMacro(StringRef Name); - - /// \brief Are we inside a macro instantiation? + /// Are we inside a macro instantiation? bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} - /// \brief Handle entry to macro instantiation. + /// Handle entry to macro instantiation. /// /// \param M The macro. /// \param NameLoc Instantiation location. bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc); - /// \brief Handle exit from macro instantiation. + /// Handle exit from macro instantiation. void handleMacroExit(); - /// \brief Extract AsmTokens for a macro argument. + /// Extract AsmTokens for a macro argument. bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg); - /// \brief Parse all macro arguments for a given macro. + /// Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A); void printMacroInstantiations(); @@ -345,15 +306,20 @@ private: } static void DiagHandler(const SMDiagnostic &Diag, void *Context); - /// \brief Enter the specified file. This returns true on failure. + /// Should we emit DWARF describing this assembler source? (Returns false if + /// the source has .file directives, which means we don't want to generate + /// info describing the assembler source itself.) + bool enabledGenDwarfForAssembly(); + + /// Enter the specified file. This returns true on failure. bool enterIncludeFile(const std::string &Filename); - /// \brief Process the specified file for the .incbin directive. + /// Process the specified file for the .incbin directive. /// This returns true on failure. 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 + /// Reset the current lexer position to that given by \p Loc. The /// current token is not set; clients should ensure Lex() is called /// subsequently. /// @@ -361,17 +327,17 @@ private: /// location. void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0); - /// \brief Parse up to the end of statement and a return the contents from the + /// Parse up to the end of statement and a return the contents from the /// current token until the end of the statement; the current token on exit /// will be either the EndOfStatement or EOF. StringRef parseStringToEndOfStatement() override; - /// \brief Parse until the end of a statement or a comma is encountered, + /// Parse until the end of a statement or a comma is encountered, /// return the contents from the current token up to the end or comma. StringRef parseStringToComma(); bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false); + bool NoDeadStrip = false, bool AllowExtendedExpr = false); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); @@ -540,10 +506,12 @@ private: DK_ERROR, DK_WARNING, DK_PRINT, + DK_ADDRSIG, + DK_ADDRSIG_SYM, DK_END }; - /// \brief Maps directive name --> DirectiveKind enum, for + /// Maps directive name --> DirectiveKind enum, for /// directives parsed by this class. StringMap<DirectiveKind> DirectiveKindMap; @@ -632,7 +600,7 @@ private: // .sleb128 (Signed=true) and .uleb128 (Signed=false) bool parseDirectiveLEB128(bool Signed); - /// \brief Parse a directive like ".globl" which + /// Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr); @@ -688,6 +656,10 @@ private: // .print <double-quotes-string> bool parseDirectivePrint(SMLoc DirectiveLoc); + // Directives to support address-significance tables. + bool parseDirectiveAddrsig(); + bool parseDirectiveAddrsigSym(); + void initializeDirectiveKindMap(); }; @@ -728,7 +700,10 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, PlatformParser.reset(createELFAsmParser()); break; case MCObjectFileInfo::IsWasm: - llvm_unreachable("Wasm parsing not supported yet"); + // TODO: WASM will need its own MCAsmParserExtension implementation, but + // for now we can re-use the ELF one, since the directives can be the + // same for now. + PlatformParser.reset(createELFAsmParser()); break; } @@ -808,7 +783,7 @@ bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, Bytes = Bytes.drop_front(Skip); if (Count) { int64_t Res; - if (!Count->evaluateAsAbsolute(Res)) + if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(Loc, "expected absolute expression"); if (Res < 0) return Warning(Loc, "negative count has no effect"); @@ -858,6 +833,19 @@ const AsmToken &AsmParser::Lex() { return *tok; } +bool AsmParser::enabledGenDwarfForAssembly() { + // Check whether the user specified -g. + if (!getContext().getGenDwarfForAssembly()) + return false; + // If we haven't encountered any .file directives (which would imply that + // the assembler source was produced with debug info already) then emit one + // describing the assembler source file itself. + if (getContext().getGenDwarfFileNumber() == 0) + getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( + 0, StringRef(), getContext().getMainFileName())); + return true; +} + bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Create the initial section, if requested. if (!NoInitialTextSection) @@ -871,7 +859,9 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { SmallVector<AsmRewrite, 4> AsmStrRewrites; // If we are generating dwarf for assembly source files save the initial text - // section and generate a .file directive. + // section. (Don't use enabledGenDwarfForAssembly() here, as we aren't + // emitting any actual debug info yet and haven't had a chance to parse any + // embedded .file directives.) if (getContext().getGenDwarfForAssembly()) { MCSection *Sec = getStreamer().getCurrentSectionOnly(); if (!Sec->getBeginSymbol()) { @@ -882,8 +872,6 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { bool InsertResult = getContext().addGenDwarfSection(Sec); assert(InsertResult && ".text section should not have debug info yet"); (void)InsertResult; - getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( - 0, StringRef(), getContext().getMainFileName())); } // While we have input, parse each statement. @@ -977,7 +965,7 @@ bool AsmParser::checkForValidSection() { return false; } -/// \brief Throw away the rest of the line for testing purposes. +/// Throw away the rest of the line for testing purposes. void AsmParser::eatToEndOfStatement() { while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); @@ -1008,7 +996,7 @@ StringRef AsmParser::parseStringToComma() { return StringRef(Start, End - Start); } -/// \brief Parse a paren expression and return it. +/// Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. /// /// parenexpr ::= expr) @@ -1023,7 +1011,7 @@ bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } -/// \brief Parse a bracket expression and return it. +/// Parse a bracket expression and return it. /// NOTE: This assumes the leading '[' has already been consumed. /// /// bracketexpr ::= expr] @@ -1037,7 +1025,7 @@ bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } -/// \brief Parse a primary expression and return it. +/// Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol /// primaryexpr ::= number @@ -1133,13 +1121,17 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. - if (Sym->isVariable() && - isa<MCConstantExpr>(Sym->getVariableValue(/*SetUsed*/ false))) { - if (Variant) - return Error(EndLoc, "unexpected modifier on variable reference"); - - Res = Sym->getVariableValue(/*SetUsed*/ false); - return false; + if (Sym->isVariable()) { + auto V = Sym->getVariableValue(/*SetUsed*/ false); + bool DoInline = isa<MCConstantExpr>(V); + if (auto TV = dyn_cast<MCTargetExpr>(V)) + DoInline = TV->inlineAssignedExpr(); + if (DoInline) { + if (Variant) + return Error(EndLoc, "unexpected modifier on variable reference"); + Res = Sym->getVariableValue(/*SetUsed*/ false); + return false; + } } // Otherwise create a symbol ref. @@ -1329,7 +1321,7 @@ AsmParser::applyModifierToExpr(const MCExpr *E, /// the End argument will be filled with the last location pointed to the '>' /// character. -/// There is a gap between the AltMacro's documentation and the single quote implementation. +/// There is a gap between the AltMacro's documentation and the single quote implementation. /// GCC does not fully support this feature and so we will not support it. /// TODO: Adding single quote as a string. bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { @@ -1349,7 +1341,7 @@ bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { return false; } -/// \brief creating a string without the escape characters '!'. +/// creating a string without the escape characters '!'. void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) { if (AltMacroStr[Pos] == '!') @@ -1358,7 +1350,7 @@ void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { } } -/// \brief Parse an expression and return it. +/// Parse an expression and return it. /// /// expr ::= expr &&,|| expr -> lowest. /// expr ::= expr |,^,&,! expr @@ -1398,7 +1390,8 @@ bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { Lex(); } - // Try to constant fold it up front, if possible. + // Try to constant fold it up front, if possible. Do not exploit + // assembler here. int64_t Value; if (Res->evaluateAsAbsolute(Value)) Res = MCConstantExpr::create(Value, getContext()); @@ -1439,7 +1432,7 @@ bool AsmParser::parseAbsoluteExpression(int64_t &Res) { if (parseExpression(Expr)) return true; - if (!Expr->evaluateAsAbsolute(Res)) + if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(StartLoc, "expected absolute expression"); return false; @@ -1606,7 +1599,7 @@ unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, : getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr); } -/// \brief Parse all binary operators with precedence >= 'Precedence'. +/// Parse all binary operators with precedence >= 'Precedence'. /// Res contains the LHS of the expression on input. bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc) { @@ -1818,7 +1811,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // If we are generating dwarf for assembly source files then gather the // info to make a dwarf label entry for this label if needed. - if (getContext().getGenDwarfForAssembly()) + if (enabledGenDwarfForAssembly()) MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(), IDLoc); @@ -1833,7 +1826,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true); + return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true); default: // Normal instruction or directive. break; @@ -1841,7 +1834,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // If macros are enabled, check to see if this is a macro instantiation. if (areMacrosEnabled()) - if (const MCAsmMacro *M = lookupMacro(IDVal)) { + if (const MCAsmMacro *M = getContext().lookupMacro(IDVal)) { return handleMacroEntry(M, IDLoc); } @@ -2140,6 +2133,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveDS(IDVal, 12); case DK_PRINT: return parseDirectivePrint(IDLoc); + case DK_ADDRSIG: + return parseDirectiveAddrsig(); + case DK_ADDRSIG_SYM: + return parseDirectiveAddrsigSym(); } return Error(IDLoc, "unknown directive"); @@ -2187,7 +2184,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, // If we are generating dwarf for the current section then generate a .loc // directive for the instruction. - if (!ParseHadError && getContext().getGenDwarfForAssembly() && + if (!ParseHadError && enabledGenDwarfForAssembly() && getContext().getGenDwarfSectionSyms().count( getStreamer().getCurrentSectionOnly())) { unsigned Line; @@ -2205,20 +2202,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, 0, StringRef(), CppHashInfo.Filename); getContext().setGenDwarfFileNumber(FileNumber); - // Since SrcMgr.FindLineNumber() is slow and messes up the SourceMgr's - // cache with the different Loc from the call above we save the last - // info we queried here with SrcMgr.FindLineNumber(). - unsigned CppHashLocLineNo; - if (LastQueryIDLoc == CppHashInfo.Loc && - LastQueryBuffer == CppHashInfo.Buf) - CppHashLocLineNo = LastQueryLine; - else { - CppHashLocLineNo = - SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); - LastQueryLine = CppHashLocLineNo; - LastQueryIDLoc = CppHashInfo.Loc; - LastQueryBuffer = CppHashInfo.Buf; - } + unsigned CppHashLocLineNo = + SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); } @@ -2240,7 +2225,7 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, } // Parse and erase curly braces marking block start/end -bool +bool AsmParser::parseCurlyBlockScope(SmallVectorImpl<AsmRewrite> &AsmStrRewrites) { // Identify curly brace marking block start/end if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly)) @@ -2283,7 +2268,7 @@ bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) { return false; } -/// \brief will use the last parsed cpp hash line filename comment +/// will use the last parsed cpp hash line filename comment /// for the Filename and LineNo if any in the diagnostic. void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { const AsmParser *Parser = static_cast<const AsmParser *>(Context); @@ -2648,7 +2633,8 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, Lex(); if (parseExpression(AbsoluteExp, EndLoc)) return false; - if (!AbsoluteExp->evaluateAsAbsolute(Value)) + if (!AbsoluteExp->evaluateAsAbsolute(Value, + getStreamer().getAssemblerPtr())) return Error(StrLoc, "expected absolute expression"); const char *StrChar = StrLoc.getPointer(); const char *EndChar = EndLoc.getPointer(); @@ -2720,17 +2706,6 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, return TokError("too many positional arguments"); } -const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) { - StringMap<MCAsmMacro>::iterator I = MacroMap.find(Name); - return (I == MacroMap.end()) ? nullptr : &I->getValue(); -} - -void AsmParser::defineMacro(StringRef Name, MCAsmMacro Macro) { - MacroMap.insert(std::make_pair(Name, std::move(Macro))); -} - -void AsmParser::undefineMacro(StringRef Name) { MacroMap.erase(Name); } - bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { // Arbitrarily limit macro nesting depth (default matches 'as'). We can // eliminate this, although we should protect against infinite loops. @@ -2791,11 +2766,11 @@ void AsmParser::handleMacroExit() { } bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip) { + bool NoDeadStrip, bool AllowExtendedExpr) { MCSymbol *Sym; const MCExpr *Value; if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value)) + Value, AllowExtendedExpr)) return true; if (!Sym) { @@ -2959,8 +2934,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { if (parseExpression(Offset)) return true; - if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc, - "expression is not a constant value") || + if (check(!Offset->evaluateAsAbsolute(OffsetValue, + getStreamer().getAssemblerPtr()), + OffsetLoc, "expression is not a constant value") || check(OffsetValue < 0, OffsetLoc, "expression is negative") || parseToken(AsmToken::Comma, "expected comma") || check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) @@ -2985,7 +2961,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { "unexpected token in .reloc directive")) return true; - if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc)) + const MCTargetAsmParser &MCT = getTargetParser(); + const MCSubtargetInfo &STI = MCT.getSTI(); + if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc, STI)) return Error(NameLoc, "unknown relocation name"); return false; @@ -3016,6 +2994,25 @@ bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { return false; } +static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) { + if (Asm.getTok().isNot(AsmToken::Integer) && + Asm.getTok().isNot(AsmToken::BigNum)) + return Asm.TokError("unknown token in expression"); + SMLoc ExprLoc = Asm.getTok().getLoc(); + APInt IntValue = Asm.getTok().getAPIntVal(); + Asm.Lex(); + if (!IntValue.isIntN(128)) + return Asm.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(); + } + return false; +} + /// ParseDirectiveOctaValue /// ::= .octa [ hexconstant (, hexconstant)* ] @@ -3023,21 +3020,9 @@ 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 (parseHexOcta(*this, hi, lo)) + return true; if (MAI.isLittleEndian()) { getStreamer().EmitIntValue(lo, 8); getStreamer().EmitIntValue(hi, 8); @@ -3294,21 +3279,20 @@ bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { } /// parseDirectiveFile -/// ::= .file [number] filename -/// ::= .file number directory filename +/// ::= .file filename +/// ::= .file number [directory] filename [md5 checksum] [source source-text] bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { // FIXME: I'm not sure what this is. int64_t FileNumber = -1; - SMLoc FileNumberLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Integer)) { FileNumber = getTok().getIntVal(); Lex(); - if (FileNumber < 1) - return TokError("file number less than one"); + if (FileNumber < 0) + return TokError("negative file number"); } - std::string Path = getTok().getString(); + std::string Path; // Usually the directory and filename together, otherwise just the directory. // Allow the strings to have escaped octal character sequence. @@ -3331,20 +3315,79 @@ bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { Filename = Path; } - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.file' directive")) - return true; + uint64_t MD5Hi, MD5Lo; + bool HasMD5 = false; + + Optional<StringRef> Source; + bool HasSource = false; + std::string SourceString; + + while (!parseOptionalToken(AsmToken::EndOfStatement)) { + StringRef Keyword; + if (check(getTok().isNot(AsmToken::Identifier), + "unexpected token in '.file' directive") || + parseIdentifier(Keyword)) + return true; + if (Keyword == "md5") { + HasMD5 = true; + if (check(FileNumber == -1, + "MD5 checksum specified, but no file number") || + parseHexOcta(*this, MD5Hi, MD5Lo)) + return true; + } else if (Keyword == "source") { + HasSource = true; + if (check(FileNumber == -1, + "source specified, but no file number") || + check(getTok().isNot(AsmToken::String), + "unexpected token in '.file' directive") || + parseEscapedString(SourceString)) + return true; + } else { + return TokError("unexpected token in '.file' directive"); + } + } + + // In case there is a -g option as well as debug info from directive .file, + // we turn off the -g option, directly use the existing debug info instead. + // Also reset any implicit ".file 0" for the assembler source. + if (Ctx.getGenDwarfForAssembly()) { + Ctx.getMCDwarfLineTable(0).resetRootFile(); + Ctx.setGenDwarfForAssembly(false); + } if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { - // If there is -g option as well as debug info from directive file, - // we turn off -g option, directly use the existing debug info instead. - if (getContext().getGenDwarfForAssembly()) - getContext().setGenDwarfForAssembly(false); - else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename) == - 0) - return Error(FileNumberLoc, "file number already allocated"); + MD5::MD5Result *CKMem = nullptr; + if (HasMD5) { + CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); + for (unsigned i = 0; i != 8; ++i) { + CKMem->Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8)); + CKMem->Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8)); + } + } + if (HasSource) { + char *SourceBuf = static_cast<char *>(Ctx.allocate(SourceString.size())); + memcpy(SourceBuf, SourceString.data(), SourceString.size()); + Source = StringRef(SourceBuf, SourceString.size()); + } + if (FileNumber == 0) { + if (Ctx.getDwarfVersion() < 5) + return Warning(DirectiveLoc, "file 0 not supported prior to DWARF-5"); + getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source); + } else { + Expected<unsigned> FileNumOrErr = getStreamer().tryEmitDwarfFileDirective( + FileNumber, Directory, Filename, CKMem, Source); + if (!FileNumOrErr) + return Error(DirectiveLoc, toString(FileNumOrErr.takeError())); + FileNumber = FileNumOrErr.get(); + } + // Alert the user if there are some .file directives with MD5 and some not. + // But only do that once. + if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) { + ReportedInconsistentMD5 = true; + return Warning(DirectiveLoc, "inconsistent use of MD5 checksums"); + } } return false; @@ -3378,7 +3421,7 @@ bool AsmParser::parseDirectiveLoc() { int64_t FileNumber = 0, LineNumber = 0; SMLoc Loc = getTok().getLoc(); if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") || - check(FileNumber < 1, Loc, + check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc, "file number less than one in '.loc' directive") || check(!getContext().isValidDwarfFileNumber(FileNumber), Loc, "unassigned file number in '.loc' directive")) @@ -3862,7 +3905,7 @@ bool AsmParser::parseDirectiveCFIEndProc() { return false; } -/// \brief parse register name or number. +/// parse register name or number. bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc) { unsigned RegNo; @@ -4249,7 +4292,7 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { eatToEndOfStatement(); } - if (lookupMacro(Name)) { + if (getContext().lookupMacro(Name)) { return Error(DirectiveLoc, "macro '" + Name + "' is already defined"); } @@ -4257,7 +4300,10 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { const char *BodyEnd = EndToken.getLoc().getPointer(); StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); checkForBadMacro(DirectiveLoc, Name, Body, Parameters); - defineMacro(Name, MCAsmMacro(Name, Body, std::move(Parameters))); + MCAsmMacro Macro(Name, Body, std::move(Parameters)); + DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n"; + Macro.dump()); + getContext().defineMacro(Name, std::move(Macro)); return false; } @@ -4416,10 +4462,12 @@ bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { "unexpected token in '.purgem' directive")) return true; - if (!lookupMacro(Name)) + if (!getContext().lookupMacro(Name)) return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); - undefineMacro(Name); + getContext().undefineMacro(Name); + DEBUG_WITH_TYPE("asm-macros", dbgs() + << "Un-defining macro: " << Name << "\n"); return false; } @@ -5253,6 +5301,8 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".ds.w"] = DK_DS_W; DirectiveKindMap[".ds.x"] = DK_DS_X; DirectiveKindMap[".print"] = DK_PRINT; + DirectiveKindMap[".addrsig"] = DK_ADDRSIG; + DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -5267,7 +5317,8 @@ MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { } if (Lexer.is(AsmToken::Identifier) && - (getTok().getIdentifier() == ".rept" || + (getTok().getIdentifier() == ".rep" || + getTok().getIdentifier() == ".rept" || getTok().getIdentifier() == ".irp" || getTok().getIdentifier() == ".irpc")) { ++NestLevel; @@ -5329,7 +5380,7 @@ bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) { return true; int64_t Count; - if (!CountExpr->evaluateAsAbsolute(Count)) { + if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) { return Error(CountLoc, "unexpected token in '" + Dir + "' directive"); } @@ -5492,6 +5543,21 @@ bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { return false; } +bool AsmParser::parseDirectiveAddrsig() { + getStreamer().EmitAddrsig(); + return false; +} + +bool AsmParser::parseDirectiveAddrsigSym() { + StringRef Name; + if (check(parseIdentifier(Name), + "expected identifier in '.addrsig_sym' directive")) + return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().EmitAddrsigSym(Sym); + return false; +} + // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, @@ -5773,14 +5839,17 @@ static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value) { + const MCExpr *&Value, bool AllowExtendedExpr) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Parser.getTok().getLoc(); - - if (Parser.parseExpression(Value)) { - return Parser.TokError("missing expression"); - } + SMLoc EndLoc; + if (AllowExtendedExpr) { + if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) { + return Parser.TokError("missing expression"); + } + } else if (Parser.parseExpression(Value, EndLoc)) + return Parser.TokError("missing expression"); // Note: we don't count b as used in "a = b". This is to allow // a = b @@ -5826,7 +5895,7 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, } // end namespace MCParserUtils } // end namespace llvm -/// \brief Create an MCAsmParser instance. +/// Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { |