diff options
Diffstat (limited to 'lib/MC/MCParser/AsmParser.cpp')
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 578 |
1 files changed, 493 insertions, 85 deletions
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index b67c769..6f2e85e 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -19,6 +19,8 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCParser/AsmCond.h" #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" @@ -35,6 +37,8 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include <cctype> +#include <set> +#include <string> #include <vector> using namespace llvm; @@ -42,12 +46,14 @@ static cl::opt<bool> FatalAssemblerWarnings("fatal-assembler-warnings", cl::desc("Consider warnings as error")); +MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {} + namespace { /// \brief Helper class for tracking macro definitions. typedef std::vector<AsmToken> MacroArgument; typedef std::vector<MacroArgument> MacroArguments; -typedef StringRef MacroParameter; +typedef std::pair<StringRef, MacroArgument> MacroParameter; typedef std::vector<MacroParameter> MacroParameters; struct Macro { @@ -80,12 +86,34 @@ public: MemoryBuffer *I); }; +//struct AsmRewrite; +struct ParseStatementInfo { + /// ParsedOperands - The parsed operands from the last parsed statement. + SmallVector<MCParsedAsmOperand*, 8> ParsedOperands; + + /// Opcode - The opcode from the last parsed instruction. + unsigned Opcode; + + SmallVectorImpl<AsmRewrite> *AsmRewrites; + + ParseStatementInfo() : Opcode(~0U), AsmRewrites(0) {} + ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites) + : Opcode(~0), AsmRewrites(rewrites) {} + + ~ParseStatementInfo() { + // Free any parsed operands. + for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) + delete ParsedOperands[i]; + ParsedOperands.clear(); + } +}; + /// \brief The concrete assembly parser instance. class AsmParser : public MCAsmParser { friend class GenericAsmParser; - AsmParser(const AsmParser &); // DO NOT IMPLEMENT - void operator=(const AsmParser &); // DO NOT IMPLEMENT + AsmParser(const AsmParser &) LLVM_DELETED_FUNCTION; + void operator=(const AsmParser &) LLVM_DELETED_FUNCTION; private: AsmLexer Lexer; MCContext &Ctx; @@ -126,20 +154,27 @@ private: StringRef CppHashFilename; int64_t CppHashLineNumber; SMLoc CppHashLoc; + int CppHashBuf; /// AssemblerDialect. ~OU means unset value and use value provided by MAI. unsigned AssemblerDialect; + /// IsDarwin - is Darwin compatibility enabled? + bool IsDarwin; + + /// ParsingInlineAsm - Are we parsing ms-style inline assembly? + bool ParsingInlineAsm; + public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); - ~AsmParser(); + virtual ~AsmParser(); virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false); - void AddDirectiveHandler(MCAsmParserExtension *Object, - StringRef Directive, - DirectiveHandler Handler) { + virtual void AddDirectiveHandler(MCAsmParserExtension *Object, + StringRef Directive, + DirectiveHandler Handler) { DirectiveMap[Directive] = std::make_pair(Object, Handler); } @@ -166,7 +201,19 @@ public: virtual bool Error(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = ArrayRef<SMRange>()); - const AsmToken &Lex(); + virtual const AsmToken &Lex(); + + void setParsingInlineAsm(bool V) { ParsingInlineAsm = V; } + bool isParsingInlineAsm() { return ParsingInlineAsm; } + + bool ParseMSInlineAsm(void *AsmLoc, std::string &AsmString, + unsigned &NumOutputs, unsigned &NumInputs, + SmallVectorImpl<std::pair<void *,bool> > &OpDecls, + SmallVectorImpl<std::string> &Constraints, + SmallVectorImpl<std::string> &Clobbers, + const MCInstrInfo *MII, + const MCInstPrinter *IP, + MCAsmParserSemaCallback &SI); bool ParseExpression(const MCExpr *&Res); virtual bool ParseExpression(const MCExpr *&Res, SMLoc &EndLoc); @@ -178,7 +225,7 @@ public: private: void CheckForValidSection(); - bool ParseStatement(); + bool ParseStatement(ParseStatementInfo &Info); void EatToEndOfLine(); bool ParseCppHashLineFilenameComment(const SMLoc &L); @@ -202,26 +249,28 @@ private: /// This returns true on failure. bool ProcessIncbinFile(const std::string &Filename); - /// \brief Reset the current lexer position to that given by \arg Loc. The + /// \brief Reset the current lexer position to that given by \p Loc. The /// current token is not set; clients should ensure Lex() is called /// subsequently. void JumpToLoc(SMLoc Loc); - void EatToEndOfStatement(); + virtual void EatToEndOfStatement(); - bool ParseMacroArgument(MacroArgument &MA); + bool ParseMacroArgument(MacroArgument &MA, + AsmToken::TokenKind &ArgumentDelimiter); bool ParseMacroArguments(const Macro *M, MacroArguments &A); /// \brief 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(); + virtual StringRef ParseStringToEndOfStatement(); /// \brief 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 ParseAssignment(StringRef Name, bool allow_redef, + bool NoDeadStrip = false); bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); @@ -229,8 +278,8 @@ private: bool ParseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc); /// ParseIdentifier - Parse an identifier or string (as a quoted identifier) - /// and set \arg Res to the identifier contents. - bool ParseIdentifier(StringRef &Res); + /// and set \p Res to the identifier contents. + virtual bool ParseIdentifier(StringRef &Res); // Directive Parsing. @@ -282,6 +331,9 @@ private: bool ParseDirectiveIrp(SMLoc DirectiveLoc); // ".irp" bool ParseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc" bool ParseDirectiveEndr(SMLoc DirectiveLoc); // ".endr" + + // "_emit" + bool ParseDirectiveEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info); }; /// \brief Generic implementations of directive handling, etc. which is shared @@ -406,8 +458,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), - AssemblerDialect(~0U) { + CurBuffer(0), MacrosEnabled(true), CppHashLineNumber(0), + AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false) { // Save the old handler. SavedDiagHandler = SrcMgr.getDiagHandler(); SavedDiagContext = SrcMgr.getDiagContext(); @@ -428,6 +480,7 @@ AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, } else if (_MAI.hasSubsectionsViaSymbols()) { PlatformParser = createDarwinAsmParser(); PlatformParser->Initialize(*this); + IsDarwin = true; } else { PlatformParser = createELFAsmParser(); PlatformParser->Initialize(*this); @@ -545,7 +598,8 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { - if (!ParseStatement()) continue; + ParseStatementInfo Info; + if (!ParseStatement(Info)) continue; // We had an error, validate that one was emitted and recover by skipping to // the next line. @@ -598,7 +652,7 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { } void AsmParser::CheckForValidSection() { - if (!getStreamer().getCurrentSection()) { + if (!ParsingInlineAsm && !getStreamer().getCurrentSection()) { TokError("expected section directive before assembly directive"); Out.SwitchSection(Ctx.getMachOSection( "__TEXT", "__text", @@ -1024,14 +1078,11 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, } } - - - /// ParseStatement: /// ::= EndOfStatement /// ::= Label* Directive ...Operands... EndOfStatement /// ::= Label* Identifier OperandList* EndOfStatement -bool AsmParser::ParseStatement() { +bool AsmParser::ParseStatement(ParseStatementInfo &Info) { if (Lexer.is(AsmToken::EndOfStatement)) { Out.AddBlankLine(); Lex(); @@ -1150,7 +1201,7 @@ bool AsmParser::ParseStatement() { return false; } - return ParseStatement(); + return false; } case AsmToken::Equal: @@ -1304,26 +1355,30 @@ bool AsmParser::ParseStatement() { return Error(IDLoc, "unknown directive"); } + // _emit + if (ParsingInlineAsm && IDVal == "_emit") + return ParseDirectiveEmit(IDLoc, Info); + CheckForValidSection(); // Canonicalize the opcode to lower case. - SmallString<128> Opcode; + SmallString<128> OpcodeStr; for (unsigned i = 0, e = IDVal.size(); i != e; ++i) - Opcode.push_back(tolower(IDVal[i])); + OpcodeStr.push_back(tolower(IDVal[i])); - SmallVector<MCParsedAsmOperand*, 8> ParsedOperands; - bool HadError = getTargetParser().ParseInstruction(Opcode.str(), IDLoc, - ParsedOperands); + ParseInstructionInfo IInfo(Info.AsmRewrites); + bool HadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr.str(), + IDLoc,Info.ParsedOperands); // Dump the parsed representation, if requested. if (getShowParsedOperands()) { SmallString<256> Str; raw_svector_ostream OS(Str); OS << "parsed instruction: ["; - for (unsigned i = 0; i != ParsedOperands.size(); ++i) { + for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) { if (i != 0) OS << ", "; - ParsedOperands[i]->print(OS); + Info.ParsedOperands[i]->print(OS); } OS << "]"; @@ -1335,21 +1390,38 @@ bool AsmParser::ParseStatement() { // the instruction. if (!HadError && getContext().getGenDwarfForAssembly() && getContext().getGenDwarfSection() == getStreamer().getCurrentSection() ) { + + unsigned Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); + + // If we previously parsed a cpp hash file line comment then make sure the + // current Dwarf File is for the CppHashFilename if not then emit the + // Dwarf File table for it and adjust the line number for the .loc. + const std::vector<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + if (CppHashFilename.size() != 0) { + if(MCDwarfFiles[getContext().getGenDwarfFileNumber()]->getName() != + CppHashFilename) + getStreamer().EmitDwarfFileDirective( + getContext().nextGenDwarfFileNumber(), StringRef(), CppHashFilename); + + unsigned CppHashLocLineNo = SrcMgr.FindLineNumber(CppHashLoc,CppHashBuf); + Line = CppHashLineNumber - 1 + (Line - CppHashLocLineNo); + } + getStreamer().EmitDwarfLocDirective(getContext().getGenDwarfFileNumber(), - SrcMgr.FindLineNumber(IDLoc, CurBuffer), - 0, DWARF2_LINE_DEFAULT_IS_STMT ? + Line, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0, StringRef()); } // If parsing succeeded, match the instruction. - if (!HadError) - HadError = getTargetParser().MatchAndEmitInstruction(IDLoc, ParsedOperands, - Out); - - // Free any parsed operands. - for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) - delete ParsedOperands[i]; + if (!HadError) { + unsigned ErrorInfo; + HadError = getTargetParser().MatchAndEmitInstruction(IDLoc, Info.Opcode, + Info.ParsedOperands, + Out, ErrorInfo, + ParsingInlineAsm); + } // Don't skip the rest of the line, the instruction parser is responsible for // that. @@ -1394,6 +1466,7 @@ bool AsmParser::ParseCppHashLineFilenameComment(const SMLoc &L) { CppHashLoc = L; CppHashFilename = Filename; CppHashLineNumber = LineNumber; + CppHashBuf = CurBuffer; // Ignore any trailing characters, they're just comment. EatToEndOfLine(); @@ -1454,6 +1527,14 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { NewDiag.print(0, OS); } +// FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The +// difference being that that function accepts '@' as part of identifiers and +// we can't do that. AsmLexer.cpp should probably be changed to handle +// '@' as a special case when needed. +static bool isIdentifierChar(char c) { + return isalnum(c) || c == '_' || c == '$' || c == '.'; +} + bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, const MacroParameters &Parameters, const MacroArguments &A, @@ -1462,6 +1543,8 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, if (NParameters != 0 && NParameters != A.size()) return Error(L, "Wrong number of arguments"); + // A macro without parameters is handled differently on Darwin: + // gas accepts no arguments and does no substitutions while (!Body.empty()) { // Scan for the next substitution. std::size_t End = Body.size(), Pos = 0; @@ -1518,25 +1601,33 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, Pos += 2; } else { unsigned I = Pos + 1; - while (isalnum(Body[I]) && I + 1 != End) + while (isIdentifierChar(Body[I]) && I + 1 != End) ++I; const char *Begin = Body.data() + Pos +1; StringRef Argument(Begin, I - (Pos +1)); unsigned Index = 0; for (; Index < NParameters; ++Index) - if (Parameters[Index] == Argument) + if (Parameters[Index].first == Argument) break; - // FIXME: We should error at the macro definition. - if (Index == NParameters) - return Error(L, "Parameter not found"); - - for (MacroArgument::const_iterator it = A[Index].begin(), - ie = A[Index].end(); it != ie; ++it) - OS << it->getString(); + if (Index == NParameters) { + if (Body[Pos+1] == '(' && Body[Pos+2] == ')') + Pos += 3; + else { + OS << '\\' << Argument; + Pos = I; + } + } else { + for (MacroArgument::const_iterator it = A[Index].begin(), + ie = A[Index].end(); it != ie; ++it) + if (it->getKind() == AsmToken::String) + OS << it->getStringContents(); + else + OS << it->getString(); - Pos += 1 + Argument.size(); + Pos += 1 + Argument.size(); + } } // Update the scan point. Body = Body.substr(Pos); @@ -1551,24 +1642,97 @@ MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, { } +static bool IsOperator(AsmToken::TokenKind kind) +{ + switch (kind) + { + default: + return false; + case AsmToken::Plus: + case AsmToken::Minus: + case AsmToken::Tilde: + case AsmToken::Slash: + case AsmToken::Star: + case AsmToken::Dot: + case AsmToken::Equal: + case AsmToken::EqualEqual: + case AsmToken::Pipe: + case AsmToken::PipePipe: + case AsmToken::Caret: + case AsmToken::Amp: + case AsmToken::AmpAmp: + case AsmToken::Exclaim: + case AsmToken::ExclaimEqual: + case AsmToken::Percent: + case AsmToken::Less: + case AsmToken::LessEqual: + case AsmToken::LessLess: + case AsmToken::LessGreater: + case AsmToken::Greater: + case AsmToken::GreaterEqual: + case AsmToken::GreaterGreater: + return true; + } +} + /// ParseMacroArgument - Extract AsmTokens for a macro argument. /// This is used for both default macro parameter values and the /// arguments in macro invocations -bool AsmParser::ParseMacroArgument(MacroArgument &MA) { +bool AsmParser::ParseMacroArgument(MacroArgument &MA, + AsmToken::TokenKind &ArgumentDelimiter) { unsigned ParenLevel = 0; + unsigned AddTokens = 0; - for (;;) { - SMLoc LastTokenLoc; + // gas accepts arguments separated by whitespace, except on Darwin + if (!IsDarwin) + Lexer.setSkipSpace(false); - if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) + for (;;) { + if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) { + Lexer.setSkipSpace(true); return TokError("unexpected token in macro instantiation"); + } + + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) { + // Spaces and commas cannot be mixed to delimit parameters + if (ArgumentDelimiter == AsmToken::Eof) + ArgumentDelimiter = AsmToken::Comma; + else if (ArgumentDelimiter != AsmToken::Comma) { + Lexer.setSkipSpace(true); + return TokError("expected ' ' for macro argument separator"); + } + break; + } + + if (Lexer.is(AsmToken::Space)) { + Lex(); // Eat spaces + + // Spaces can delimit parameters, but could also be part an expression. + // If the token after a space is an operator, add the token and the next + // one into this argument + if (ArgumentDelimiter == AsmToken::Space || + ArgumentDelimiter == AsmToken::Eof) { + if (IsOperator(Lexer.getKind())) { + // Check to see whether the token is used as an operator, + // or part of an identifier + const char *NextChar = getTok().getEndLoc().getPointer() + 1; + if (*NextChar == ' ') + AddTokens = 2; + } + + if (!AddTokens && ParenLevel == 0) { + if (ArgumentDelimiter == AsmToken::Eof && + !IsOperator(Lexer.getKind())) + ArgumentDelimiter = AsmToken::Space; + break; + } + } + } // HandleMacroEntry relies on not advancing the lexer here // to be able to fill in the remaining default parameter values if (Lexer.is(AsmToken::EndOfStatement)) break; - if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) - break; // Adjust the current parentheses level. if (Lexer.is(AsmToken::LParen)) @@ -1578,16 +1742,23 @@ bool AsmParser::ParseMacroArgument(MacroArgument &MA) { // Append the token to the current argument list. MA.push_back(getTok()); + if (AddTokens) + AddTokens--; Lex(); } + + Lexer.setSkipSpace(true); if (ParenLevel != 0) - return TokError("unbalanced parenthesises in macro argument"); + return TokError("unbalanced parentheses in macro argument"); return false; } // Parse the macro instantiation arguments. bool AsmParser::ParseMacroArguments(const Macro *M, MacroArguments &A) { const unsigned NParameters = M ? M->Parameters.size() : 0; + // Argument delimiter is initially unknown. It will be set by + // ParseMacroArgument() + AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; // Parse two kinds of macro invocations: // - macros defined without any parameters accept an arbitrary number of them @@ -1596,13 +1767,30 @@ bool AsmParser::ParseMacroArguments(const Macro *M, MacroArguments &A) { ++Parameter) { MacroArgument MA; - if (ParseMacroArgument(MA)) + if (ParseMacroArgument(MA, ArgumentDelimiter)) return true; - A.push_back(MA); + if (!MA.empty() || !NParameters) + A.push_back(MA); + else if (NParameters) { + if (!M->Parameters[Parameter].second.empty()) + A.push_back(M->Parameters[Parameter].second); + } - if (Lexer.is(AsmToken::EndOfStatement)) + // At the end of the statement, fill in remaining arguments that have + // default values. If there aren't any, then the next argument is + // required but missing + if (Lexer.is(AsmToken::EndOfStatement)) { + if (NParameters && Parameter < NParameters - 1) { + if (M->Parameters[Parameter + 1].second.empty()) + return TokError("macro argument '" + + Twine(M->Parameters[Parameter + 1].first) + + "' is missing"); + else + continue; + } return false; + } if (Lexer.is(AsmToken::Comma)) Lex(); @@ -1691,7 +1879,8 @@ static bool IsUsedIn(const MCSymbol *Sym, const MCExpr *Value) { llvm_unreachable("Unknown expr kind!"); } -bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { +bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef, + bool NoDeadStrip) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -1746,6 +1935,9 @@ bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { // Do the assignment. Out.EmitAssignment(Sym, Value); + if (NoDeadStrip) + Out.EmitSymbolAttribute(Sym, MCSA_NoDeadStrip); + return false; } @@ -1803,7 +1995,7 @@ bool AsmParser::ParseDirectiveSet(StringRef IDVal, bool allow_redef) { return TokError("unexpected token in '" + Twine(IDVal) + "'"); Lex(); - return ParseAssignment(Name, allow_redef); + return ParseAssignment(Name, allow_redef, true); } bool AsmParser::ParseEscapedString(std::string &Data) { @@ -2274,8 +2466,13 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { if (ParseAbsoluteExpression(Pow2Alignment)) return true; + LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType(); + if (IsLocal && LCOMM == LCOMM::NoAlignment) + return Error(Pow2AlignmentLoc, "alignment not supported on this target"); + // If this target takes alignments in bytes (not log) validate and convert. - if (Lexer.getMAI().getAlignmentIsInBytes()) { + if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) || + (IsLocal && LCOMM == LCOMM::ByteAlignment)) { if (!isPowerOf2_64(Pow2Alignment)) return Error(Pow2AlignmentLoc, "alignment must be a power of 2"); Pow2Alignment = Log2_64(Pow2Alignment); @@ -2303,13 +2500,9 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { if (!Sym->isUndefined()) return Error(IDLoc, "invalid symbol redefinition"); - // '.lcomm' is equivalent to '.zerofill'. // Create the Symbol as a common or local common with Size and Pow2Alignment if (IsLocal) { - getStreamer().EmitZerofill(Ctx.getMachOSection( - "__DATA", "__bss", MCSectionMachO::S_ZEROFILL, - 0, SectionKind::getBSS()), - Sym, Size, 1 << Pow2Alignment); + getStreamer().EmitLocalCommonSymbol(Sym, Size, 1 << Pow2Alignment); return false; } @@ -3073,25 +3266,33 @@ bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, SMLoc DirectiveLoc) { StringRef Name; if (getParser().ParseIdentifier(Name)) - return TokError("expected identifier in directive"); + return TokError("expected identifier in '.macro' directive"); MacroParameters Parameters; + // Argument delimiter is initially unknown. It will be set by + // ParseMacroArgument() + AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; if (getLexer().isNot(AsmToken::EndOfStatement)) { - for(;;) { - StringRef Parameter; - if (getParser().ParseIdentifier(Parameter)) - return TokError("expected identifier in directive"); + for (;;) { + MacroParameter Parameter; + if (getParser().ParseIdentifier(Parameter.first)) + return TokError("expected identifier in '.macro' directive"); + + if (getLexer().is(AsmToken::Equal)) { + Lex(); + if (getParser().ParseMacroArgument(Parameter.second, ArgumentDelimiter)) + return true; + } + Parameters.push_back(Parameter); - if (getLexer().isNot(AsmToken::Comma)) + if (getLexer().is(AsmToken::Comma)) + Lex(); + else if (getLexer().is(AsmToken::EndOfStatement)) break; - Lex(); } } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.macro' directive"); - // Eat the end of statement. Lex(); @@ -3296,7 +3497,7 @@ bool AsmParser::ParseDirectiveIrp(SMLoc DirectiveLoc) { MacroParameters Parameters; MacroParameter Parameter; - if (ParseIdentifier(Parameter)) + if (ParseIdentifier(Parameter.first)) return TokError("expected identifier in '.irp' directive"); Parameters.push_back(Parameter); @@ -3323,9 +3524,8 @@ bool AsmParser::ParseDirectiveIrp(SMLoc DirectiveLoc) { SmallString<256> Buf; raw_svector_ostream OS(Buf); - for (std::vector<MacroArgument>::iterator i = A.begin(), e = A.end(); i != e; - ++i) { - std::vector<MacroArgument> Args; + for (MacroArguments::iterator i = A.begin(), e = A.end(); i != e; ++i) { + MacroArguments Args; Args.push_back(*i); if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc())) @@ -3343,7 +3543,7 @@ bool AsmParser::ParseDirectiveIrpc(SMLoc DirectiveLoc) { MacroParameters Parameters; MacroParameter Parameter; - if (ParseIdentifier(Parameter)) + if (ParseIdentifier(Parameter.first)) return TokError("expected identifier in '.irpc' directive"); Parameters.push_back(Parameter); @@ -3393,7 +3593,7 @@ bool AsmParser::ParseDirectiveIrpc(SMLoc DirectiveLoc) { bool AsmParser::ParseDirectiveEndr(SMLoc DirectiveLoc) { if (ActiveMacros.empty()) - return TokError("unexpected '.endr' directive, no current .rept"); + return TokError("unmatched '.endr' directive"); // The only .repl that should get here are the ones created by // InstantiateMacroLikeBody. @@ -3403,6 +3603,214 @@ bool AsmParser::ParseDirectiveEndr(SMLoc DirectiveLoc) { return false; } +bool AsmParser::ParseDirectiveEmit(SMLoc IDLoc, ParseStatementInfo &Info) { + const MCExpr *Value; + SMLoc ExprLoc = getLexer().getLoc(); + if (ParseExpression(Value)) + return true; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); + if (!MCE) + return Error(ExprLoc, "unexpected expression in _emit"); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(8, IntValue) && !isIntN(8, IntValue)) + return Error(ExprLoc, "literal value out of range for directive"); + + Info.AsmRewrites->push_back(AsmRewrite(AOK_Emit, IDLoc, 5)); + return false; +} + +bool AsmParser::ParseMSInlineAsm(void *AsmLoc, std::string &AsmString, + unsigned &NumOutputs, unsigned &NumInputs, + SmallVectorImpl<std::pair<void *, bool> > &OpDecls, + SmallVectorImpl<std::string> &Constraints, + SmallVectorImpl<std::string> &Clobbers, + const MCInstrInfo *MII, + const MCInstPrinter *IP, + MCAsmParserSemaCallback &SI) { + SmallVector<void *, 4> InputDecls; + SmallVector<void *, 4> OutputDecls; + SmallVector<bool, 4> InputDeclsOffsetOf; + SmallVector<bool, 4> OutputDeclsOffsetOf; + SmallVector<std::string, 4> InputConstraints; + SmallVector<std::string, 4> OutputConstraints; + std::set<std::string> ClobberRegs; + + SmallVector<struct AsmRewrite, 4> AsmStrRewrites; + + // Prime the lexer. + Lex(); + + // While we have input, parse each statement. + unsigned InputIdx = 0; + unsigned OutputIdx = 0; + while (getLexer().isNot(AsmToken::Eof)) { + ParseStatementInfo Info(&AsmStrRewrites); + if (ParseStatement(Info)) + return true; + + if (Info.Opcode != ~0U) { + const MCInstrDesc &Desc = MII->get(Info.Opcode); + + // Build the list of clobbers, outputs and inputs. + for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) { + MCParsedAsmOperand *Operand = Info.ParsedOperands[i]; + + // Immediate. + if (Operand->isImm()) { + if (Operand->needAsmRewrite()) + AsmStrRewrites.push_back(AsmRewrite(AOK_ImmPrefix, + Operand->getStartLoc())); + continue; + } + + // Register operand. + if (Operand->isReg() && !Operand->isOffsetOf()) { + unsigned NumDefs = Desc.getNumDefs(); + // Clobber. + if (NumDefs && Operand->getMCOperandNum() < NumDefs) { + std::string Reg; + raw_string_ostream OS(Reg); + IP->printRegName(OS, Operand->getReg()); + ClobberRegs.insert(StringRef(OS.str())); + } + continue; + } + + // Expr/Input or Output. + unsigned Size; + void *OpDecl = SI.LookupInlineAsmIdentifier(Operand->getName(), AsmLoc, + Size); + if (OpDecl) { + bool isOutput = (i == 1) && Desc.mayStore(); + if (!Operand->isOffsetOf() && Operand->needSizeDirective()) + AsmStrRewrites.push_back(AsmRewrite(AOK_SizeDirective, + Operand->getStartLoc(), + /*Len*/0, + Operand->getMemSize())); + if (isOutput) { + std::string Constraint = "="; + ++InputIdx; + OutputDecls.push_back(OpDecl); + OutputDeclsOffsetOf.push_back(Operand->isOffsetOf()); + Constraint += Operand->getConstraint().str(); + OutputConstraints.push_back(Constraint); + AsmStrRewrites.push_back(AsmRewrite(AOK_Output, + Operand->getStartLoc(), + Operand->getNameLen())); + } else { + InputDecls.push_back(OpDecl); + InputDeclsOffsetOf.push_back(Operand->isOffsetOf()); + InputConstraints.push_back(Operand->getConstraint().str()); + AsmStrRewrites.push_back(AsmRewrite(AOK_Input, + Operand->getStartLoc(), + Operand->getNameLen())); + } + } + } + } + } + + // Set the number of Outputs and Inputs. + NumOutputs = OutputDecls.size(); + NumInputs = InputDecls.size(); + + // Set the unique clobbers. + for (std::set<std::string>::iterator I = ClobberRegs.begin(), + E = ClobberRegs.end(); I != E; ++I) + Clobbers.push_back(*I); + + // Merge the various outputs and inputs. Output are expected first. + if (NumOutputs || NumInputs) { + unsigned NumExprs = NumOutputs + NumInputs; + OpDecls.resize(NumExprs); + Constraints.resize(NumExprs); + // FIXME: Constraints are hard coded to 'm', but we need an 'r' + // constraint for offsetof. This needs to be cleaned up! + for (unsigned i = 0; i < NumOutputs; ++i) { + OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsOffsetOf[i]); + Constraints[i] = OutputDeclsOffsetOf[i] ? "=r" : OutputConstraints[i]; + } + for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) { + OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsOffsetOf[i]); + Constraints[j] = InputDeclsOffsetOf[i] ? "r" : InputConstraints[i]; + } + } + + // Build the IR assembly string. + std::string AsmStringIR; + AsmRewriteKind PrevKind = AOK_Imm; + raw_string_ostream OS(AsmStringIR); + const char *Start = SrcMgr.getMemoryBuffer(0)->getBufferStart(); + for (SmallVectorImpl<struct AsmRewrite>::iterator + I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) { + const char *Loc = (*I).Loc.getPointer(); + + AsmRewriteKind Kind = (*I).Kind; + + // Emit everything up to the immediate/expression. If the previous rewrite + // was a size directive, then this has already been done. + if (PrevKind != AOK_SizeDirective) + OS << StringRef(Start, Loc - Start); + PrevKind = Kind; + + // Skip the original expression. + if (Kind == AOK_Skip) { + Start = Loc + (*I).Len; + continue; + } + + // Rewrite expressions in $N notation. + switch (Kind) { + default: break; + case AOK_Imm: + OS << Twine("$$"); + OS << (*I).Val; + break; + case AOK_ImmPrefix: + OS << Twine("$$"); + break; + case AOK_Input: + OS << '$'; + OS << InputIdx++; + break; + case AOK_Output: + OS << '$'; + OS << OutputIdx++; + break; + case AOK_SizeDirective: + switch((*I).Val) { + default: break; + case 8: OS << "byte ptr "; break; + case 16: OS << "word ptr "; break; + case 32: OS << "dword ptr "; break; + case 64: OS << "qword ptr "; break; + case 80: OS << "xword ptr "; break; + case 128: OS << "xmmword ptr "; break; + case 256: OS << "ymmword ptr "; break; + } + break; + case AOK_Emit: + OS << ".byte"; + break; + case AOK_DotOperator: + OS << (*I).Val; + break; + } + + // Skip the original expression. + if (Kind != AOK_SizeDirective) + Start = Loc + (*I).Len; + } + + // Emit the remainder of the asm string. + const char *AsmEnd = SrcMgr.getMemoryBuffer(0)->getBufferEnd(); + if (Start != AsmEnd) + OS << StringRef(Start, AsmEnd - Start); + + AsmString = OS.str(); + return false; +} + /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, |