diff options
Diffstat (limited to 'lib/MC/MCParser/AsmParser.cpp')
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 277 |
1 files changed, 229 insertions, 48 deletions
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 16487579abfc..2d61cac62585 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -14,7 +14,6 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -30,6 +29,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -122,6 +122,9 @@ private: int64_t CppHashLineNumber; SMLoc CppHashLoc; + /// AssemblerDialect. ~OU means unset value and use value provided by MAI. + unsigned AssemblerDialect; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); @@ -143,9 +146,20 @@ public: virtual MCAsmLexer &getLexer() { return Lexer; } virtual MCContext &getContext() { return Ctx; } virtual MCStreamer &getStreamer() { return Out; } + virtual unsigned getAssemblerDialect() { + if (AssemblerDialect == ~0U) + return MAI.getAssemblerDialect(); + else + return AssemblerDialect; + } + virtual void setAssemblerDialect(unsigned i) { + AssemblerDialect = i; + } - virtual bool Warning(SMLoc L, const Twine &Msg); - virtual bool Error(SMLoc L, const Twine &Msg); + virtual bool Warning(SMLoc L, const Twine &Msg, + ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()); + virtual bool Error(SMLoc L, const Twine &Msg, + ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()); const AsmToken &Lex(); @@ -171,14 +185,17 @@ private: void HandleMacroExit(); void PrintMacroInstantiations(); - void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type, - bool ShowLine = true) const { - SrcMgr.PrintMessage(Loc, Msg, Type, ShowLine); + void PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, + ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()) const { + SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); } static void DiagHandler(const SMDiagnostic &Diag, void *Context); /// EnterIncludeFile - Enter the specified file. This returns true on failure. bool EnterIncludeFile(const std::string &Filename); + /// ProcessIncbinFile - Process the specified file for the .incbin directive. + /// This returns true on failure. + bool ProcessIncbinFile(const std::string &Filename); /// \brief Reset the current lexer position to that given by \arg Loc. The /// current token is not set; clients should ensure Lex() is called @@ -225,6 +242,7 @@ private: bool ParseDirectiveAbort(); // ".abort" bool ParseDirectiveInclude(); // ".include" + bool ParseDirectiveIncbin(); // ".incbin" bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" // ".ifdef" or ".ifndef", depending on expect_defined @@ -295,6 +313,12 @@ public: &GenericAsmParser::ParseDirectiveCFIRestoreState>(".cfi_restore_state"); AddDirectiveHandler< &GenericAsmParser::ParseDirectiveCFISameValue>(".cfi_same_value"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIRestore>(".cfi_restore"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIEscape>(".cfi_escape"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFISignalFrame>(".cfi_signal_frame"); // Macro directives. AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( @@ -328,6 +352,9 @@ public: bool ParseDirectiveCFIRememberState(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveCFIRestoreState(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveCFISameValue(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIRestore(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIEscape(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFISignalFrame(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); @@ -352,7 +379,8 @@ AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, const MCAsmInfo &_MAI) : Lexer(_MAI), Ctx(_Ctx), Out(_Out), MAI(_MAI), SrcMgr(_SM), GenericParser(new GenericAsmParser), PlatformParser(0), - CurBuffer(0), MacrosEnabled(true), CppHashLineNumber(0) { + CurBuffer(0), MacrosEnabled(true), CppHashLineNumber(0), + AssemblerDialect(~0U) { // Save the old handler. SavedDiagHandler = SrcMgr.getDiagHandler(); SavedDiagContext = SrcMgr.getDiagContext(); @@ -395,21 +423,21 @@ void AsmParser::PrintMacroInstantiations() { // Print the active macro instantiation stack. for (std::vector<MacroInstantiation*>::const_reverse_iterator it = ActiveMacros.rbegin(), ie = ActiveMacros.rend(); it != ie; ++it) - PrintMessage((*it)->InstantiationLoc, "while in macro instantiation", - "note"); + PrintMessage((*it)->InstantiationLoc, SourceMgr::DK_Note, + "while in macro instantiation"); } -bool AsmParser::Warning(SMLoc L, const Twine &Msg) { +bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { if (FatalAssemblerWarnings) - return Error(L, Msg); - PrintMessage(L, Msg, "warning"); + return Error(L, Msg, Ranges); + PrintMessage(L, SourceMgr::DK_Warning, Msg, Ranges); PrintMacroInstantiations(); return false; } -bool AsmParser::Error(SMLoc L, const Twine &Msg) { +bool AsmParser::Error(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { HadError = true; - PrintMessage(L, Msg, "error"); + PrintMessage(L, SourceMgr::DK_Error, Msg, Ranges); PrintMacroInstantiations(); return true; } @@ -427,6 +455,21 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) { return false; } +/// Process the specified .incbin file by seaching for it in the include paths +/// then just emiting the byte contents of the file to the streamer. This +/// returns true on failure. +bool AsmParser::ProcessIncbinFile(const std::string &Filename) { + std::string IncludedFile; + int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); + if (NewBuf == -1) + return true; + + // Pick up the bytes from the file and emit them. + getStreamer().EmitBytes(SrcMgr.getMemoryBuffer(NewBuf)->getBuffer(), + DEFAULT_ADDRSPACE); + return false; +} + void AsmParser::JumpToLoc(SMLoc Loc) { CurBuffer = SrcMgr.FindBufferContainingLoc(Loc); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer()); @@ -462,6 +505,17 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { HadError = false; AsmCond StartingCondState = TheCondState; + // If we are generating dwarf for assembly source files save the initial text + // section and generate a .file directive. + if (getContext().getGenDwarfForAssembly()) { + getContext().setGenDwarfSection(getStreamer().getCurrentSection()); + MCSymbol *SectionStartSym = getContext().CreateTempSymbol(); + getStreamer().EmitLabel(SectionStartSym); + getContext().setGenDwarfSectionStartSym(SectionStartSym); + getStreamer().EmitDwarfFileDirective(getContext().nextGenDwarfFileNumber(), + StringRef(), SrcMgr.getMemoryBuffer(CurBuffer)->getBufferIdentifier()); + } + // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { if (!ParseStatement()) continue; @@ -501,8 +555,9 @@ 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. - PrintMessage(getLexer().getLoc(), "assembler local symbol '" + - Sym->getName() + "' not defined", "error", false); + PrintMessage(getLexer().getLoc(), SourceMgr::DK_Error, + "assembler local symbol '" + Sym->getName() + + "' not defined"); } } @@ -749,8 +804,7 @@ AsmParser::ApplyModifierToExpr(const MCExpr *E, } } - assert(0 && "Invalid expression kind!"); - return 0; + llvm_unreachable("Invalid expression kind!"); } /// ParseExpression - Parse an expression and return it. @@ -787,7 +841,6 @@ bool AsmParser::ParseExpression(const MCExpr *&Res, SMLoc &EndLoc) { if (!ModifiedRes) { return TokError("invalid modifier '" + getTok().getIdentifier() + "' (no symbols present)"); - return true; } Res = ModifiedRes; @@ -1036,6 +1089,12 @@ bool AsmParser::ParseStatement() { // Emit the label. Out.EmitLabel(Sym); + // 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()) + MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(), + IDLoc); + // Consume any end of statement token, if present, to avoid spurious // AddBlankLine calls(). if (Lexer.is(AsmToken::EndOfStatement)) { @@ -1163,6 +1222,8 @@ bool AsmParser::ParseStatement() { return ParseDirectiveAbort(); if (IDVal == ".include") return ParseDirectiveInclude(); + if (IDVal == ".incbin") + return ParseDirectiveIncbin(); if (IDVal == ".code16") return TokError(Twine(IDVal) + " not supported yet"); @@ -1205,7 +1266,19 @@ bool AsmParser::ParseStatement() { } OS << "]"; - PrintMessage(IDLoc, OS.str(), "note"); + PrintMessage(IDLoc, SourceMgr::DK_Note, OS.str()); + } + + // If we are generating dwarf for assembly source files and the current + // section is the initial text section then generate a .loc directive for + // the instruction. + if (!HadError && getContext().getGenDwarfForAssembly() && + getContext().getGenDwarfSection() == getStreamer().getCurrentSection() ) { + getStreamer().EmitDwarfLocDirective(getContext().getGenDwarfFileNumber(), + SrcMgr.FindLineNumber(IDLoc, CurBuffer), + 0, DWARF2_LINE_DEFAULT_IS_STMT ? + DWARF2_FLAG_IS_STMT : 0, 0, 0, + StringRef()); } // If parsing succeeded, match the instruction. @@ -1294,7 +1367,7 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { if (Parser->SavedDiagHandler) Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext); else - Diag.Print(0, OS); + Diag.print(0, OS); return; } @@ -1309,19 +1382,15 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { int LineNo = Parser->CppHashLineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo); - SMDiagnostic NewDiag(*Diag.getSourceMgr(), - Diag.getLoc(), - Filename, - LineNo, - Diag.getColumnNo(), - Diag.getMessage(), - Diag.getLineContents(), - Diag.getShowLine()); + SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), + Filename, LineNo, Diag.getColumnNo(), + Diag.getKind(), Diag.getMessage(), + Diag.getLineContents(), Diag.getRanges()); if (Parser->SavedDiagHandler) Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext); else - NewDiag.Print(0, OS); + NewDiag.print(0, OS); } bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body, @@ -1458,6 +1527,11 @@ bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc, } Lex(); } + // If there weren't any arguments, erase the token vector so everything + // else knows that. Leaving around the vestigal empty token list confuses + // things. + if (MacroArguments.size() == 1 && MacroArguments.back().empty()) + MacroArguments.clear(); // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. @@ -1495,23 +1569,27 @@ void AsmParser::HandleMacroExit() { ActiveMacros.pop_back(); } -static void MarkUsed(const MCExpr *Value) { +static bool IsUsedIn(const MCSymbol *Sym, const MCExpr *Value) { switch (Value->getKind()) { - case MCExpr::Binary: - MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getLHS()); - MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getRHS()); + case MCExpr::Binary: { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr*>(Value); + return IsUsedIn(Sym, BE->getLHS()) || IsUsedIn(Sym, BE->getRHS()); break; + } case MCExpr::Target: case MCExpr::Constant: - break; + return false; case MCExpr::SymbolRef: { - static_cast<const MCSymbolRefExpr*>(Value)->getSymbol().setUsed(true); - break; + const MCSymbol &S = static_cast<const MCSymbolRefExpr*>(Value)->getSymbol(); + if (S.isVariable()) + return IsUsedIn(Sym, S.getVariableValue()); + return &S == Sym; } case MCExpr::Unary: - MarkUsed(static_cast<const MCUnaryExpr*>(Value)->getSubExpr()); - break; + return IsUsedIn(Sym, static_cast<const MCUnaryExpr*>(Value)->getSubExpr()); } + + llvm_unreachable("Unknown expr kind!"); } bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { @@ -1522,7 +1600,9 @@ bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { if (ParseExpression(Value)) return true; - MarkUsed(Value); + // Note: we don't count b as used in "a = b". This is to allow + // a = b + // b = c if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); @@ -1544,8 +1624,12 @@ bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) + if (IsUsedIn(Sym, Value)) + return Error(EqualLoc, "Recursive use of '" + Name + "'"); + else if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) ; // Allow redefinitions of undefined symbols only used in directives. + else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) + ; // Allow redefinitions of variables that haven't yet been used. else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) return Error(EqualLoc, "redefinition of '" + Name + "'"); else if (!Sym->isVariable()) @@ -1912,6 +1996,7 @@ bool AsmParser::ParseDirectiveOrg() { CheckForValidSection(); const MCExpr *Offset; + SMLoc Loc = getTok().getLoc(); if (ParseExpression(Offset)) return true; @@ -1931,9 +2016,11 @@ bool AsmParser::ParseDirectiveOrg() { Lex(); - // FIXME: Only limited forms of relocatable expressions are accepted here, it - // has to be relative to the current section. - getStreamer().EmitValueToOffset(Offset, FillExpr); + // Only limited forms of relocatable expressions are accepted here, it + // has to be relative to the current section. The streamer will return + // 'true' if the expression wasn't evaluatable. + if (getStreamer().EmitValueToOffset(Offset, FillExpr)) + return Error(Loc, "expected assembly-time absolute expression"); return false; } @@ -2178,6 +2265,31 @@ bool AsmParser::ParseDirectiveInclude() { return false; } +/// ParseDirectiveIncbin +/// ::= .incbin "filename" +bool AsmParser::ParseDirectiveIncbin() { + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '.incbin' directive"); + + std::string Filename = getTok().getString(); + SMLoc IncbinLoc = getLexer().getLoc(); + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.incbin' directive"); + + // Strip the quotes. + Filename = Filename.substr(1, Filename.size()-2); + + // Attempt to process the included file. + if (ProcessIncbinFile(Filename)) { + Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); + return true; + } + + return false; +} + /// ParseDirectiveIf /// ::= .if expression bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { @@ -2305,7 +2417,8 @@ bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { } /// ParseDirectiveFile -/// ::= .file [number] string +/// ::= .file [number] filename +/// ::= .file number directory filename bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { // FIXME: I'm not sure what this is. int64_t FileNumber = -1; @@ -2321,17 +2434,35 @@ bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::String)) return TokError("unexpected token in '.file' directive"); - StringRef Filename = getTok().getString(); - Filename = Filename.substr(1, Filename.size()-2); + // Usually the directory and filename together, otherwise just the directory. + StringRef Path = getTok().getString(); + Path = Path.substr(1, Path.size()-2); Lex(); + StringRef Directory; + StringRef Filename; + if (getLexer().is(AsmToken::String)) { + if (FileNumber == -1) + return TokError("explicit path specified, but no file number"); + Filename = getTok().getString(); + Filename = Filename.substr(1, Filename.size()-2); + Directory = Path; + Lex(); + } else { + Filename = Path; + } + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.file' directive"); if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { - if (getStreamer().EmitDwarfFileDirective(FileNumber, Filename)) + if (getContext().getGenDwarfForAssembly() == true) + Error(DirectiveLoc, "input can't have .file dwarf directives when -g is " + "used to generate dwarf debug info for assembly code"); + + if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename)) Error(FileNumberLoc, "file number already allocated"); } @@ -2719,6 +2850,56 @@ bool GenericAsmParser::ParseDirectiveCFISameValue(StringRef IDVal, return false; } +/// ParseDirectiveCFIRestore +/// ::= .cfi_restore register +bool GenericAsmParser::ParseDirectiveCFIRestore(StringRef IDVal, + SMLoc DirectiveLoc) { + int64_t Register = 0; + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + getStreamer().EmitCFIRestore(Register); + + return false; +} + +/// ParseDirectiveCFIEscape +/// ::= .cfi_escape expression[,...] +bool GenericAsmParser::ParseDirectiveCFIEscape(StringRef IDVal, + SMLoc DirectiveLoc) { + std::string Values; + int64_t CurrValue; + if (getParser().ParseAbsoluteExpression(CurrValue)) + return true; + + Values.push_back((uint8_t)CurrValue); + + while (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getParser().ParseAbsoluteExpression(CurrValue)) + return true; + + Values.push_back((uint8_t)CurrValue); + } + + getStreamer().EmitCFIEscape(Values); + return false; +} + +/// ParseDirectiveCFISignalFrame +/// ::= .cfi_signal_frame +bool GenericAsmParser::ParseDirectiveCFISignalFrame(StringRef Directive, + SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token in '" + Directive + "' directive"); + + getStreamer().EmitCFISignalFrame(); + + return false; +} + /// ParseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off |