[llvm] ee2c0f7 - [ms] [llvm-ml] Add a draft MASM parser
Mikael Holmén via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 19 23:48:41 PST 2020
Hi,
I noticed that gcc 7.0 warns on a few added unused functions:
[1030/4361] Building CXX object
lib/MC/MCParser/CMakeFiles/LLVMMCParser.dir/MasmParser.cpp.o
../lib/MC/MCParser/MasmParser.cpp:3965:6: warning: 'bool
{anonymous}::MasmParser::parseDirectiveMacrosOnOff(llvm::StringRef)'
defined but not used [-Wunused-function]
bool MasmParser::parseDirectiveMacrosOnOff(StringRef Directive) {
^~~~~~~~~~
../lib/MC/MCParser/MasmParser.cpp:985:11: warning: 'llvm::StringRef
{anonymous}::MasmParser::parseStringToComma()' defined but not used [-
Wunused-function]
StringRef MasmParser::parseStringToComma() {
^~~~~~~~~~
../lib/MC/MCParser/MasmParser.cpp:739:6: warning: 'bool
{anonymous}::MasmParser::processIncbinFile(const string&, int64_t,
const llvm::MCExpr*, llvm::SMLoc)' defined but not used [-Wunused-
function]
bool MasmParser::processIncbinFile(const std::string &Filename,
int64_t Skip,
^~~~~~~~~~
I suppose these functions will be used in follow up patches later on?
/Mikael
On Sun, 2020-02-16 at 09:31 -0800, Eric Astor via llvm-commits wrote:
> Author: Eric Astor
> Date: 2020-02-16T12:30:46-05:00
> New Revision: ee2c0f76d74cc03e54389926c9e626987e1408c3
>
> URL:
> https://github.com/llvm/llvm-project/commit/ee2c0f76d74cc03e54389926c9e626987e1408c3
> DIFF:
> https://github.com/llvm/llvm-project/commit/ee2c0f76d74cc03e54389926c9e626987e1408c3.diff
>
> LOG: [ms] [llvm-ml] Add a draft MASM parser
>
> Summary:
> Many directives are unavailable, and support for others may be
> limited.
>
> This first draft has preliminary support for:
> - conditional directives (including errors),
> - data allocation (unsigned types up to 8 bytes, and ALIGN),
> - equates/variables (numeric and text),
> - and procedure directives (without parameters),
> as well as COMMENT, ECHO, INCLUDE, INCLUDELIB, PUBLIC, and EXTERN.
> Text variables (aka text macros) are expanded in-place wherever the
> identifier occurs.
>
> We deliberately ignore all ml.exe processor directives.
>
> Prominent features not yet supported:
> - structs
> - macros (both procedures and functions)
> - procedures (with specified parameters)
> - substitution & expansion operators
>
> Conditional directives are complicated by the fact that "ifdef rax"
> is a valid way to check if a file is being assembled for a 64-bit x86
> processor; we add support for "ifdef <register>" in general, which
> requires adding a tryParseRegister method to all MCTargetAsmParsers.
> (Some targets require backtracking in the non-register case.)
>
> Reviewers: rnk, thakis
>
> Reviewed By: thakis
>
> Subscribers: kerbowa, merge_guards_bot, wuzish, arsenm, dschuff,
> jyknight, dylanmckay, sdardis, nemanjai, jvesely, mgorny, sbc100,
> jgravelle-google, hiraditya, aheejin, kbarton, fedor.sergeev, asb,
> rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay,
> zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult,
> the_o, PkmX, jocewei, jsji, Jim, s.egerton, pzheng, sameer.abuasal,
> apazos, luismarques, llvm-commits
>
> Tags: #llvm
>
> Differential Revision: https://reviews.llvm.org/D72680
>
> Added:
> llvm/lib/MC/MCParser/COFFMasmParser.cpp
> llvm/lib/MC/MCParser/MasmParser.cpp
> llvm/test/tools/llvm-ml/lit.local.cfg
>
> Modified:
> llvm/include/llvm/MC/MCAsmInfo.h
> llvm/include/llvm/MC/MCParser/AsmLexer.h
> llvm/include/llvm/MC/MCParser/MCAsmParser.h
> llvm/include/llvm/MC/MCStreamer.h
> llvm/include/llvm/MC/MCTargetOptions.h
> llvm/lib/MC/MCParser/AsmLexer.cpp
> llvm/lib/MC/MCParser/AsmParser.cpp
> llvm/lib/MC/MCParser/CMakeLists.txt
> llvm/lib/MC/MCParser/MCAsmParser.cpp
> llvm/lib/MC/MCTargetOptions.cpp
> llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
> llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.h
> llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
> llvm/test/tools/llvm-ml/basic.test
> llvm/tools/llvm-ml/llvm-ml.cpp
> llvm/utils/gn/secondary/llvm/lib/MC/MCParser/BUILD.gn
>
> Removed:
>
>
>
> #####################################################################
> ###########
> diff --git a/llvm/include/llvm/MC/MCAsmInfo.h
> b/llvm/include/llvm/MC/MCAsmInfo.h
> index 4ed1170f97ab..b4f7c350739a 100644
> --- a/llvm/include/llvm/MC/MCAsmInfo.h
> +++ b/llvm/include/llvm/MC/MCAsmInfo.h
> @@ -156,6 +156,10 @@ class MCAsmInfo {
> /// Defaults to false.
> bool AllowAtInName = false;
>
> + /// This is true if the assembler allows $ @ ? characters at the
> start of
> + /// symbol names. Defaults to false.
> + bool AllowSymbolAtNameStart = false;
> +
> /// If this is true, symbol names with invalid characters will be
> printed in
> /// quotes.
> bool SupportsQuotedNames = true;
> @@ -537,6 +541,7 @@ class MCAsmInfo {
> const char *getCode64Directive() const { return Code64Directive; }
> unsigned getAssemblerDialect() const { return AssemblerDialect; }
> bool doesAllowAtInName() const { return AllowAtInName; }
> + bool doesAllowSymbolAtNameStart() const { return
> AllowSymbolAtNameStart; }
> bool supportsNameQuoting() const { return SupportsQuotedNames; }
>
> bool doesSupportDataRegionDirectives() const {
>
> diff --git a/llvm/include/llvm/MC/MCParser/AsmLexer.h
> b/llvm/include/llvm/MC/MCParser/AsmLexer.h
> index b7294493b2f8..05b3695bc7a0 100644
> --- a/llvm/include/llvm/MC/MCParser/AsmLexer.h
> +++ b/llvm/include/llvm/MC/MCParser/AsmLexer.h
> @@ -30,6 +30,7 @@ class AsmLexer : public MCAsmLexer {
> bool IsAtStartOfLine = true;
> bool IsAtStartOfStatement = true;
> bool IsPeeking = false;
> + bool EndStatementAtEOF = true;
>
> protected:
> /// LexToken - Read the next token and return its code.
> @@ -41,7 +42,8 @@ class AsmLexer : public MCAsmLexer {
> AsmLexer &operator=(const AsmLexer &) = delete;
> ~AsmLexer() override;
>
> - void setBuffer(StringRef Buf, const char *ptr = nullptr);
> + void setBuffer(StringRef Buf, const char *ptr = nullptr,
> + bool EndStatementAtEOF = true);
>
> StringRef LexUntilEndOfStatement() override;
>
>
> diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParser.h
> b/llvm/include/llvm/MC/MCParser/MCAsmParser.h
> index da5653ee71d3..9d9091306c13 100644
> --- a/llvm/include/llvm/MC/MCParser/MCAsmParser.h
> +++ b/llvm/include/llvm/MC/MCParser/MCAsmParser.h
> @@ -250,6 +250,10 @@ class MCAsmParser {
> /// characters and return the string contents.
> virtual bool parseEscapedString(std::string &Data) = 0;
>
> + /// Parse an angle-bracket delimited string at the current
> position if one is
> + /// present, returning the string contents.
> + virtual bool parseAngleBracketString(std::string &Data) = 0;
> +
> /// Skip to the end of the current statement, for error recovery.
> virtual void eatToEndOfStatement() = 0;
>
> @@ -300,10 +304,14 @@ class MCAsmParser {
> SMLoc &EndLoc) = 0;
> };
>
> -/// Create an MCAsmParser instance.
> +/// Create an MCAsmParser instance for parsing assembly similar to
> gas syntax
> MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer
> &,
> const MCAsmInfo &, unsigned CB = 0);
>
> +/// Create an MCAsmParser instance for parsing Microsoft MASM-style
> assembly
> +MCAsmParser *createMCMasmParser(SourceMgr &, MCContext &, MCStreamer
> &,
> + const MCAsmInfo &, unsigned CB = 0);
> +
> } // end namespace llvm
>
> #endif // LLVM_MC_MCPARSER_MCASMPARSER_H
>
> diff --git a/llvm/include/llvm/MC/MCStreamer.h
> b/llvm/include/llvm/MC/MCStreamer.h
> index 989a553b660c..11f0bdfc4e59 100644
> --- a/llvm/include/llvm/MC/MCStreamer.h
> +++ b/llvm/include/llvm/MC/MCStreamer.h
> @@ -399,7 +399,7 @@ class MCStreamer {
> --I;
> MCSectionSubPair NewSection = I->first;
>
> - if (OldSection != NewSection)
> + if (NewSection.first && OldSection != NewSection)
> ChangeSection(NewSection.first, NewSection.second);
> SectionStack.pop_back();
> return true;
>
> diff --git a/llvm/include/llvm/MC/MCTargetOptions.h
> b/llvm/include/llvm/MC/MCTargetOptions.h
> index 51a5fc9aa26a..018c3374af3d 100644
> --- a/llvm/include/llvm/MC/MCTargetOptions.h
> +++ b/llvm/include/llvm/MC/MCTargetOptions.h
> @@ -56,6 +56,7 @@ class MCTargetOptions {
> int DwarfVersion = 0;
>
> std::string ABIName;
> + std::string AssemblyLanguage;
> std::string SplitDwarfFile;
>
> /// Additional paths to search for `.include` directives when
> using the
> @@ -68,6 +69,11 @@ class MCTargetOptions {
> /// textual name of the ABI that we want the backend to use, e.g.
> o32, or
> /// aapcs-linux.
> StringRef getABIName() const;
> +
> + /// getAssemblyLanguage - If this returns a non-empty string this
> represents
> + /// the textual name of the assembly language that we will use for
> this
> + /// target, e.g. masm.
> + StringRef getAssemblyLanguage() const;
> };
>
> } // end namespace llvm
>
> diff --git a/llvm/lib/MC/MCParser/AsmLexer.cpp
> b/llvm/lib/MC/MCParser/AsmLexer.cpp
> index 9155ae05d29d..5a571c7c0c0e 100644
> --- a/llvm/lib/MC/MCParser/AsmLexer.cpp
> +++ b/llvm/lib/MC/MCParser/AsmLexer.cpp
> @@ -36,7 +36,8 @@ AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI)
> {
>
> AsmLexer::~AsmLexer() = default;
>
> -void AsmLexer::setBuffer(StringRef Buf, const char *ptr) {
> +void AsmLexer::setBuffer(StringRef Buf, const char *ptr,
> + bool EndStatementAtEOF) {
> CurBuf = Buf;
>
> if (ptr)
> @@ -45,6 +46,7 @@ void AsmLexer::setBuffer(StringRef Buf, const char
> *ptr) {
> CurPtr = CurBuf.begin();
>
> TokStart = nullptr;
> + this->EndStatementAtEOF = EndStatementAtEOF;
> }
>
> /// ReturnError - Set the error to the specified string at the
> specified
> @@ -584,7 +586,7 @@ AsmToken AsmLexer::LexToken() {
>
> // If we're missing a newline at EOF, make sure we still get an
> // EndOfStatement token before the Eof token.
> - if (CurChar == EOF && !IsAtStartOfStatement) {
> + if (CurChar == EOF && !IsAtStartOfStatement && EndStatementAtEOF)
> {
> IsAtStartOfLine = true;
> IsAtStartOfStatement = true;
> return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart,
> 1));
> @@ -594,15 +596,24 @@ AsmToken AsmLexer::LexToken() {
> IsAtStartOfStatement = false;
> switch (CurChar) {
> default:
> - // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
> - if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
> - return LexIdentifier();
> + if (MAI.doesAllowSymbolAtNameStart()) {
> + // Handle Microsoft-style identifier: [a-zA-Z_$.@?][a-zA-Z0-
> 9_$.@?]*
> + if (!isDigit(CurChar) &&
> + IsIdentifierChar(CurChar, MAI.doesAllowAtInName()))
> + return LexIdentifier();
> + } else {
> + // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
> + if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
> + return LexIdentifier();
> + }
>
> // Unknown character, emit an error.
> return ReturnError(TokStart, "invalid character in input");
> case EOF:
> - IsAtStartOfLine = true;
> - IsAtStartOfStatement = true;
> + if (EndStatementAtEOF) {
> + IsAtStartOfLine = true;
> + IsAtStartOfStatement = true;
> + }
> return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
> case 0:
> case ' ':
>
> diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp
> b/llvm/lib/MC/MCParser/AsmParser.cpp
> index b7794cd4b75c..05c479abb69b 100644
> --- a/llvm/lib/MC/MCParser/AsmParser.cpp
> +++ b/llvm/lib/MC/MCParser/AsmParser.cpp
> @@ -6,7 +6,7 @@
> //
> //===---------------------------------------------------------------
> -------===//
> //
> -// This class implements the parser for assembly files.
> +// This class implements a parser for assembly files similar to gas
> syntax.
> //
> //===---------------------------------------------------------------
> -------===//
>
> @@ -74,9 +74,7 @@ using namespace llvm;
>
> MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default;
>
> -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."));
> +extern cl::opt<unsigned> AsmMacroMaxNestingDepth;
>
> namespace {
>
> @@ -645,6 +643,7 @@ class AsmParser : public MCAsmParser {
> bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else"
> bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif
> bool parseEscapedString(std::string &Data) override;
> + bool parseAngleBracketString(std::string &Data) override;
>
> const MCExpr *applyModifierToExpr(const MCExpr *E,
> MCSymbolRefExpr::VariantKind
> Variant);
> @@ -1365,7 +1364,7 @@ AsmParser::applyModifierToExpr(const MCExpr *E,
> /// implementation. GCC does not fully support this feature and so
> we will not
> /// support it.
> /// TODO: Adding single quote as a string.
> -static bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) {
> +static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {
> assert((StrLoc.getPointer() != nullptr) &&
> "Argument to the function cannot be a NULL value");
> const char *CharPtr = StrLoc.getPointer();
> @@ -1383,7 +1382,7 @@ static bool isAltmacroString(SMLoc &StrLoc,
> SMLoc &EndLoc) {
> }
>
> /// creating a string without the escape characters '!'.
> -static std::string altMacroString(StringRef AltMacroStr) {
> +static std::string angleBracketString(StringRef AltMacroStr) {
> std::string Res;
> for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {
> if (AltMacroStr[Pos] == '!')
> @@ -2497,7 +2496,7 @@ bool AsmParser::expandMacro(raw_svector_ostream
> &OS, StringRef Body,
> // is considered altMacroString!!!
> else if (AltMacroMode && Token.getString().front() ==
> '<' &&
> Token.is(AsmToken::String)) {
> - OS << altMacroString(Token.getStringContents());
> + OS << angleBracketString(Token.getStringContents());
> }
> // We expect no quotes around the string's contents when
> // parsing for varargs.
> @@ -2690,7 +2689,7 @@ bool AsmParser::parseMacroArguments(const
> MCAsmMacro *M,
> StringRef(StrChar, EndChar - StrChar),
> Value);
> FA.Value.push_back(newToken);
> } else if (AltMacroMode && Lexer.is(AsmToken::Less) &&
> - isAltmacroString(StrLoc, EndLoc)) {
> + isAngleBracketString(StrLoc, EndLoc)) {
> const char *StrChar = StrLoc.getPointer();
> const char *EndChar = EndLoc.getPointer();
> jumpToLoc(EndLoc, CurBuffer);
> @@ -2969,6 +2968,21 @@ bool AsmParser::parseEscapedString(std::string
> &Data) {
> return false;
> }
>
> +bool AsmParser::parseAngleBracketString(std::string &Data) {
> + SMLoc EndLoc, StartLoc = getTok().getLoc();
> + if (isAngleBracketString(StartLoc, EndLoc)) {
> + const char *StartChar = StartLoc.getPointer() + 1;
> + const char *EndChar = EndLoc.getPointer() - 1;
> + jumpToLoc(EndLoc, CurBuffer);
> + /// Eat from '<' to '>'
> + Lex();
> +
> + Data = angleBracketString(StringRef(StartChar, EndChar -
> StartChar));
> + return false;
> + }
> + return true;
> +}
> +
> /// parseDirectiveAscii:
> /// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
> bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool
> ZeroTerminated) {
>
> diff --git a/llvm/lib/MC/MCParser/CMakeLists.txt
> b/llvm/lib/MC/MCParser/CMakeLists.txt
> index 429670d39126..9165457c69b3 100644
> --- a/llvm/lib/MC/MCParser/CMakeLists.txt
> +++ b/llvm/lib/MC/MCParser/CMakeLists.txt
> @@ -2,12 +2,14 @@ add_llvm_component_library(LLVMMCParser
> AsmLexer.cpp
> AsmParser.cpp
> COFFAsmParser.cpp
> + COFFMasmParser.cpp
> DarwinAsmParser.cpp
> ELFAsmParser.cpp
> MCAsmLexer.cpp
> MCAsmParser.cpp
> MCAsmParserExtension.cpp
> MCTargetAsmParser.cpp
> + MasmParser.cpp
> WasmAsmParser.cpp
>
> ADDITIONAL_HEADER_DIRS
>
> diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
> b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
> new file mode 100644
> index 000000000000..b7c48e92961b
> --- /dev/null
> +++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
> @@ -0,0 +1,386 @@
> +//===- COFFMasmParser.cpp - COFF MASM Assembly Parser --------------
> -------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------
> -------===//
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/StringSwitch.h"
> +#include "llvm/ADT/Triple.h"
> +#include "llvm/ADT/Twine.h"
> +#include "llvm/BinaryFormat/COFF.h"
> +#include "llvm/MC/MCContext.h"
> +#include "llvm/MC/MCDirectives.h"
> +#include "llvm/MC/MCObjectFileInfo.h"
> +#include "llvm/MC/MCParser/MCAsmLexer.h"
> +#include "llvm/MC/MCParser/MCAsmParserExtension.h"
> +#include "llvm/MC/MCParser/MCAsmParserUtils.h"
> +#include "llvm/MC/MCParser/MCTargetAsmParser.h"
> +#include "llvm/MC/MCRegisterInfo.h"
> +#include "llvm/MC/MCSectionCOFF.h"
> +#include "llvm/MC/MCStreamer.h"
> +#include "llvm/MC/SectionKind.h"
> +#include "llvm/Support/SMLoc.h"
> +#include <cassert>
> +#include <cstdint>
> +#include <limits>
> +#include <utility>
> +
> +using namespace llvm;
> +
> +namespace {
> +
> +class COFFMasmParser : public MCAsmParserExtension {
> + template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
> + void addDirectiveHandler(StringRef Directive) {
> + MCAsmParser::ExtensionDirectiveHandler Handler =
> + std::make_pair(this, HandleDirective<COFFMasmParser,
> HandlerMethod>);
> + getParser().addDirectiveHandler(Directive, Handler);
> + }
> +
> + bool ParseSectionSwitch(StringRef Section, unsigned
> Characteristics,
> + SectionKind Kind);
> +
> + bool ParseSectionSwitch(StringRef Section, unsigned
> Characteristics,
> + SectionKind Kind, StringRef COMDATSymName,
> + COFF::COMDATType Type);
> +
> + bool ParseDirectiveProc(StringRef, SMLoc);
> + bool ParseDirectiveEndProc(StringRef, SMLoc);
> + bool ParseDirectiveSegment(StringRef, SMLoc);
> + bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
> + bool ParseDirectiveIncludelib(StringRef, SMLoc);
> +
> + bool IgnoreDirective(StringRef, SMLoc) {
> + while (!getLexer().is(AsmToken::EndOfStatement)) {
> + Lex();
> + }
> + return false;
> + }
> +
> + void Initialize(MCAsmParser &Parser) override {
> + // Call the base implementation.
> + MCAsmParserExtension::Initialize(Parser);
> +
> + // x64 directives
> + // .allocstack
> + // .endprolog
> + // .pushframe
> + // .pushreg
> + // .savereg
> + // .savexmm128
> + // .setframe
> +
> + // Code label directives
> + // label
> + // org
> +
> + // Conditional control flow directives
> + // .break
> + // .continue
> + // .else
> + // .elseif
> + // .endif
> + // .endw
> + // .if
> + // .repeat
> + // .until
> + // .untilcxz
> + // .while
> +
> + // Data allocation directives
> + // align
> + // byte/sbyte
> + // dword/sdword
> + // even
> + // fword
> + // qword
> + // real4
> + // real8
> + // real10
> + // tbyte
> + // word/sword
> +
> + // Listing control directives
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall"
> );
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif")
> ;
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacr
> o");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacr
> oall");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref")
> ;
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist")
> ;
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif
> ");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistma
> cro");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle"
> );
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond")
> ;
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
> +
> + // Macro directives
> + // endm
> + // exitm
> + // goto
> + // local
> + // macro
> + // purge
> +
> + // Miscellaneous directives
> + // alias
> + // assume
> + // .fpo
> + addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
> + "includelib");
> + // mmword
> + // option
> + // popcontext
> + // pushcontext
> + // .radix
> + // .safeseh
> + // xmmword
> + // ymmword
> +
> + // Procedure directives
> + addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("end
> p");
> + // invoke (32-bit only)
> + addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc")
> ;
> + // proto
> +
> + // Processor directives
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386P");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486P");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586P");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686P");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
> +
> + // Repeat blocks directives
> + // for
> + // forc
> + // goto
> + // repeat
> + // while
> +
> + // Scope directives
> + // comm
> + // externdef
> +
> + // Segment directives
> + // .alpha (32-bit only, order segments alphabetically)
> + // .dosseg (32-bit only, order segments in DOS convention)
> + // .seq (32-bit only, order segments sequentially)
> + addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("
> ends");
> + // group (32-bit only)
> + addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("seg
> ment");
> +
> + // Simplified segment directives
> + addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(
> ".code");
> + // .const
> + addDirectiveHandler<
> + &COFFMasmParser::ParseSectionDirectiveInitializedData>(".dat
> a");
> + addDirectiveHandler<
> + &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".d
> ata?");
> + // .exit
> + // .fardata
> + // .fardata?
> + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
> + // .stack
> + // .startup
> +
> + // String directives, written <name> <directive> <params>
> + // catstr (equivalent to <name> TEXTEQU <params>)
> + // instr (equivalent to <name> = @InStr(<params>))
> + // sizestr (equivalent to <name> = @SizeStr(<params>))
> + // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
> +
> + // Structure and record directives
> + // ends
> + // record
> + // struct
> + // typedef
> + // union
> + }
> +
> + bool ParseSectionDirectiveCode(StringRef, SMLoc) {
> + return ParseSectionSwitch(".text",
> + COFF::IMAGE_SCN_CNT_CODE
> + | COFF::IMAGE_SCN_MEM_EXECUTE
> + | COFF::IMAGE_SCN_MEM_READ,
> + SectionKind::getText());
> + }
> +
> + bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
> + return ParseSectionSwitch(".data",
> + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
> + | COFF::IMAGE_SCN_MEM_READ
> + | COFF::IMAGE_SCN_MEM_WRITE,
> + SectionKind::getData());
> + }
> +
> + bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
> + return ParseSectionSwitch(".bss",
> + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
> + | COFF::IMAGE_SCN_MEM_READ
> + | COFF::IMAGE_SCN_MEM_WRITE,
> + SectionKind::getBSS());
> + }
> +
> + StringRef CurrentProcedure;
> +
> +public:
> + COFFMasmParser() = default;
> +};
> +
> +} // end anonymous namespace.
> +
> +static SectionKind computeSectionKind(unsigned Flags) {
> + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
> + return SectionKind::getText();
> + if (Flags & COFF::IMAGE_SCN_MEM_READ &&
> + (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
> + return SectionKind::getReadOnly();
> + return SectionKind::getData();
> +}
> +
> +bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
> + unsigned Characteristics,
> + SectionKind Kind) {
> + return ParseSectionSwitch(Section, Characteristics, Kind, "",
> + (COFF::COMDATType)0);
> +}
> +
> +bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
> + unsigned Characteristics,
> + SectionKind Kind,
> + StringRef COMDATSymName,
> + COFF::COMDATType Type) {
> + if (getLexer().isNot(AsmToken::EndOfStatement))
> + return TokError("unexpected token in section switching
> directive");
> + Lex();
> +
> + getStreamer().SwitchSection(getContext().getCOFFSection(
> + Section, Characteristics, Kind, COMDATSymName, Type));
> +
> + return false;
> +}
> +
> +bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive,
> SMLoc Loc) {
> + StringRef SegmentName;
> + if (!getLexer().is(AsmToken::Identifier))
> + return TokError("expected identifier in directive");
> + SegmentName = getTok().getIdentifier();
> + Lex();
> +
> + StringRef SectionName = SegmentName;
> + SmallVector<char, 247> SectionNameVector;
> + unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
> + COFF::IMAGE_SCN_MEM_READ |
> COFF::IMAGE_SCN_MEM_WRITE;
> + if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
> + if (SegmentName.size() == 5) {
> + SectionName = ".text";
> + } else {
> + SectionName =
> + (".text$" +
> SegmentName.substr(6)).toStringRef(SectionNameVector);
> + }
> + Flags = COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE |
> + COFF::IMAGE_SCN_MEM_READ;
> + }
> + SectionKind Kind = computeSectionKind(Flags);
> + getStreamer().SwitchSection(getContext().getCOFFSection(
> + SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
> + return false;
> +}
> +
> +/// ParseDirectiveSegmentEnd
> +/// ::= identifier "ends"
> +bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive,
> SMLoc Loc) {
> + StringRef SegmentName;
> + if (!getLexer().is(AsmToken::Identifier))
> + return TokError("expected identifier in directive");
> + SegmentName = getTok().getIdentifier();
> +
> + // Ignore; no action necessary.
> + Lex();
> + return false;
> +}
> +
> +/// ParseDirectiveIncludelib
> +/// ::= "includelib" identifier
> +bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive,
> SMLoc Loc) {
> + StringRef Lib;
> + if (getParser().parseIdentifier(Lib))
> + return TokError("expected identifier in includelib directive");
> +
> + unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD |
> COFF::IMAGE_SCN_MEM_16BIT;
> + SectionKind Kind = computeSectionKind(Flags);
> + getStreamer().PushSection();
> + getStreamer().SwitchSection(getContext().getCOFFSection(
> + ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
> + getStreamer().emitBytes("/DEFAULTLIB:");
> + getStreamer().emitBytes(Lib);
> + getStreamer().emitBytes(" ");
> + getStreamer().PopSection();
> + return false;
> +}
> +
> +/// ParseDirectiveProc
> +/// TODO(epastor): Implement parameters and other attributes.
> +/// ::= label "proc" [[distance]]
> +/// statements
> +/// label "endproc"
> +bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc
> Loc) {
> + StringRef Label;
> + if (getParser().parseIdentifier(Label))
> + return Error(Loc, "expected identifier for procedure");
> + if (getLexer().is(AsmToken::Identifier)) {
> + StringRef nextVal = getTok().getString();
> + SMLoc nextLoc = getTok().getLoc();
> + if (nextVal.equals_lower("far")) {
> + // TODO(epastor): Handle far procedure definitions.
> + Lex();
> + return Error(nextLoc, "far procedure definitions not yet
> supported");
> + } else if (nextVal.equals_lower("near")) {
> + Lex();
> + nextVal = getTok().getString();
> + nextLoc = getTok().getLoc();
> + }
> + }
> + MCSymbol *Sym = getContext().getOrCreateSymbol(Label);
> +
> + // Define symbol as simple function
> + getStreamer().BeginCOFFSymbolDef(Sym);
> + getStreamer().EmitCOFFSymbolStorageClass(2);
> + getStreamer().EmitCOFFSymbolType(0x20);
> + getStreamer().EndCOFFSymbolDef();
> +
> + getStreamer().emitLabel(Sym, Loc);
> + CurrentProcedure = Label;
> + return false;
> +}
> +bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive,
> SMLoc Loc) {
> + StringRef Label;
> + SMLoc LabelLoc = getTok().getLoc();
> + if (getParser().parseIdentifier(Label))
> + return Error(LabelLoc, "expected identifier for procedure end");
> +
> + if (CurrentProcedure.empty())
> + return Error(Loc, "endp outside of procedure block");
> + else if (CurrentProcedure != Label)
> + return Error(LabelLoc, "endp does not match current procedure '"
> +
> + CurrentProcedure + "'");
> + return false;
> +}
> +
> +namespace llvm {
> +
> +MCAsmParserExtension *createCOFFMasmParser() { return new
> COFFMasmParser; }
> +
> +} // end namespace llvm
>
> diff --git a/llvm/lib/MC/MCParser/MCAsmParser.cpp
> b/llvm/lib/MC/MCParser/MCAsmParser.cpp
> index 41a1ee555d6f..c2fa7be56ad2 100644
> --- a/llvm/lib/MC/MCParser/MCAsmParser.cpp
> +++ b/llvm/lib/MC/MCParser/MCAsmParser.cpp
> @@ -13,6 +13,7 @@
> #include "llvm/MC/MCParser/MCAsmLexer.h"
> #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
> #include "llvm/MC/MCParser/MCTargetAsmParser.h"
> +#include "llvm/Support/CommandLine.h"
> #include "llvm/Support/Debug.h"
> #include "llvm/Support/SMLoc.h"
> #include "llvm/Support/raw_ostream.h"
> @@ -20,6 +21,10 @@
>
> using namespace llvm;
>
> +cl::opt<unsigned> AsmMacroMaxNestingDepth(
> + "asm-macro-max-nesting-depth", cl::init(20), cl::Hidden,
> + cl::desc("The maximum nesting depth allowed for assembly
> macros."));
> +
> MCAsmParser::MCAsmParser() {}
>
> MCAsmParser::~MCAsmParser() = default;
>
> diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp
> b/llvm/lib/MC/MCParser/MasmParser.cpp
> new file mode 100644
> index 000000000000..71691cb9e3a2
> --- /dev/null
> +++ b/llvm/lib/MC/MCParser/MasmParser.cpp
> @@ -0,0 +1,5566 @@
> +//===- AsmParser.cpp - Parser for Assembly Files -----------------
> ---------===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
> +//===---------------------------------------------------------------
> -------===//
> +//
> +// This class implements the parser for assembly files.
> +//
> +//===---------------------------------------------------------------
> -------===//
> +
> +#include "llvm/ADT/APFloat.h"
> +#include "llvm/ADT/APInt.h"
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/None.h"
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/SmallString.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include "llvm/ADT/StringMap.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/Twine.h"
> +#include "llvm/BinaryFormat/Dwarf.h"
> +#include "llvm/DebugInfo/CodeView/SymbolRecord.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/MCAsmParserExtension.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/MCSection.h"
> +#include "llvm/MC/MCStreamer.h"
> +#include "llvm/MC/MCSymbol.h"
> +#include "llvm/MC/MCTargetOptions.h"
> +#include "llvm/MC/MCValue.h"
> +#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"
> +#include "llvm/Support/SourceMgr.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include <algorithm>
> +#include <cassert>
> +#include <cctype>
> +#include <climits>
> +#include <cstddef>
> +#include <cstdint>
> +#include <deque>
> +#include <memory>
> +#include <sstream>
> +#include <string>
> +#include <tuple>
> +#include <utility>
> +#include <vector>
> +
> +using namespace llvm;
> +
> +extern cl::opt<unsigned> AsmMacroMaxNestingDepth;
> +
> +namespace {
> +
> +/// Helper types for tracking macro definitions.
> +typedef std::vector<AsmToken> MCAsmMacroArgument;
> +typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
> +
> +/// Helper class for storing information about an active macro
> +/// instantiation.
> +struct MacroInstantiation {
> + /// The location of the instantiation.
> + SMLoc InstantiationLoc;
> +
> + /// The buffer where parsing should resume upon instantiation
> completion.
> + unsigned ExitBuffer;
> +
> + /// The location where parsing should resume upon instantiation
> completion.
> + SMLoc ExitLoc;
> +
> + /// The depth of TheCondStack at the start of the instantiation.
> + size_t CondStackDepth;
> +};
> +
> +struct ParseStatementInfo {
> + /// The parsed operands from the last parsed statement.
> + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8>
> ParsedOperands;
> +
> + /// The opcode from the last parsed instruction.
> + unsigned Opcode = ~0U;
> +
> + /// Was there an error parsing the inline assembly?
> + bool ParseError = false;
> +
> + SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;
> +
> + ParseStatementInfo() = delete;
> + ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)
> + : AsmRewrites(rewrites) {}
> +};
> +
> +/// The concrete assembly parser instance.
> +// Note that this is a full MCAsmParser, not an
> MCAsmParserExtension!
> +// It's a peer of AsmParser, not of COFFAsmParser, WasmAsmParser,
> etc.
> +class MasmParser : public MCAsmParser {
> +private:
> + AsmLexer Lexer;
> + MCContext &Ctx;
> + MCStreamer &Out;
> + const MCAsmInfo &MAI;
> + SourceMgr &SrcMgr;
> + SourceMgr::DiagHandlerTy SavedDiagHandler;
> + void *SavedDiagContext;
> + std::unique_ptr<MCAsmParserExtension> PlatformParser;
> +
> + /// This is the current buffer index we're lexing from as managed
> by the
> + /// SourceMgr object.
> + unsigned CurBuffer;
> +
> + AsmCond TheCondState;
> + std::vector<AsmCond> TheCondStack;
> +
> + /// maps directive names to handler methods in parser
> + /// extensions. Extensions register themselves in this map by
> calling
> + /// addDirectiveHandler.
> + StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;
> +
> + /// maps assembly-time variable names to variables
> + struct Variable {
> + StringRef Name;
> + bool Redefinable = true;
> + bool IsText = false;
> + int64_t NumericValue = 0;
> + std::string TextValue;
> + };
> + StringMap<Variable> Variables;
> +
> + /// Stack of active macro instantiations.
> + std::vector<MacroInstantiation*> ActiveMacros;
> +
> + /// List of bodies of anonymous macros.
> + std::deque<MCAsmMacro> MacroLikeBodies;
> +
> + /// Boolean tracking whether macro substitution is enabled.
> + unsigned MacrosEnabledFlag : 1;
> +
> + /// 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.
> + struct CppHashInfoTy {
> + StringRef Filename;
> + int64_t LineNumber;
> + SMLoc Loc;
> + unsigned Buf;
> + CppHashInfoTy() : Filename(), LineNumber(0), Loc(), Buf(0) {}
> + };
> + CppHashInfoTy CppHashInfo;
> +
> + /// The filename from the first cpp hash file line comment, if
> any.
> + StringRef FirstCppHashFilename;
> +
> + /// List of forward directional labels for diagnosis at the end.
> + SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4>
> DirLabels;
> +
> + /// AssemblerDialect. ~OU means unset value and use value provided
> by MAI.
> + /// Defaults to 1U, meaning Intel.
> + unsigned AssemblerDialect = 1U;
> +
> + /// is Darwin compatibility enabled?
> + bool IsDarwin = false;
> +
> + /// Are we parsing ms-style inline assembly?
> + bool ParsingInlineAsm = false;
> +
> + /// Did we already inform the user about inconsistent MD5 usage?
> + bool ReportedInconsistentMD5 = false;
> +
> + // Is alt macro mode enabled.
> + bool AltMacroMode = false;
> +
> +public:
> + MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
> + const MCAsmInfo &MAI, unsigned CB);
> + MasmParser(const MasmParser &) = delete;
> + MasmParser &operator=(const MasmParser &) = delete;
> + ~MasmParser() override;
> +
> + bool Run(bool NoInitialTextSection, bool NoFinalize = false)
> override;
> +
> + void addDirectiveHandler(StringRef Directive,
> + ExtensionDirectiveHandler Handler)
> override {
> + ExtensionDirectiveMap[Directive] = Handler;
> + if (DirectiveKindMap.find(Directive) == DirectiveKindMap.end())
> {
> + DirectiveKindMap[Directive] = DK_HANDLER_DIRECTIVE;
> + }
> + }
> +
> + void addAliasForDirective(StringRef Directive, StringRef Alias)
> override {
> + DirectiveKindMap[Directive] = DirectiveKindMap[Alias];
> + }
> +
> + /// @name MCAsmParser Interface
> + /// {
> +
> + SourceMgr &getSourceManager() override { return SrcMgr; }
> + 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();
> + else
> + return AssemblerDialect;
> + }
> + void setAssemblerDialect(unsigned i) override {
> + AssemblerDialect = i;
> + }
> +
> + 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;
> + // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as
> binary and
> + // hex integer literals.
> + Lexer.setLexMasmIntegers(V);
> + }
> + bool isParsingInlineAsm() override { 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) override;
> +
> + bool parseExpression(const MCExpr *&Res);
> + bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
> + bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;
> + bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc)
> override;
> + bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr
> *&Res,
> + SMLoc &EndLoc) override;
> + bool parseAbsoluteExpression(int64_t &Res) override;
> +
> + /// Parse a floating point expression using the float \p Semantics
> + /// and set \p Res to the value.
> + bool parseRealValue(const fltSemantics &Semantics, APInt &Res);
> +
> + /// 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;
> +
> + bool checkForValidSection() override;
> +
> + /// }
> +
> +private:
> + bool parseStatement(ParseStatementInfo &Info,
> + MCAsmParserSemaCallback *SI);
> + bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>&
> AsmStrRewrites);
> + bool parseCppHashLineFilenameComment(SMLoc L);
> +
> + void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
> StringRef Body,
> + ArrayRef<MCAsmMacroParameter> Parameters);
> + bool expandMacro(raw_svector_ostream &OS, StringRef Body,
> + ArrayRef<MCAsmMacroParameter> Parameters,
> + ArrayRef<MCAsmMacroArgument> A, bool
> EnableAtPseudoVariable,
> + SMLoc L);
> +
> + /// Are macros enabled in the parser?
> + bool areMacrosEnabled() {return MacrosEnabledFlag;}
> +
> + /// Control a flag in the parser that enables or disables macros.
> + void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;}
> +
> + /// Are we inside a macro instantiation?
> + bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}
> +
> + /// Handle entry to macro instantiation.
> + ///
> + /// \param M The macro.
> + /// \param NameLoc Instantiation location.
> + bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc);
> +
> + /// Handle exit from macro instantiation.
> + void handleMacroExit();
> +
> + /// Extract AsmTokens for a macro argument.
> + bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg);
> +
> + /// Parse all macro arguments for a given macro.
> + bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments
> &A);
> +
> + void printMacroInstantiations();
> + void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine
> &Msg,
> + SMRange Range = None) const {
> + ArrayRef<SMRange> Ranges(Range);
> + SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);
> + }
> + static void DiagHandler(const SMDiagnostic &Diag, void *Context);
> +
> + /// 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);
> +
> + /// 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());
> +
> + /// Reset the current lexer position to that given by \p Loc. The
> + /// current token is not set; clients should ensure Lex() is
> called
> + /// subsequently.
> + ///
> + /// \param InBuffer If not 0, should be the known buffer id that
> contains the
> + /// location.
> + void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0);
> +
> + /// 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;
> +
> + /// 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 parseTextItem(std::string &Data);
> +
> + unsigned getBinOpPrecedence(AsmToken::TokenKind K,
> + MCBinaryExpr::Opcode &Kind);
> +
> + bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc
> &EndLoc);
> + bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);
> + bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);
> +
> + 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_HANDLER_DIRECTIVE,
> + DK_ASSIGN,
> + DK_EQU,
> + DK_TEXTEQU,
> + DK_ASCII,
> + DK_ASCIZ,
> + DK_STRING,
> + DK_BYTE,
> + DK_SBYTE,
> + DK_WORD,
> + DK_SWORD,
> + DK_DWORD,
> + DK_SDWORD,
> + DK_FWORD,
> + DK_QWORD,
> + DK_SQWORD,
> + DK_DB,
> + DK_DD,
> + DK_DQ,
> + DK_DW,
> + DK_REAL4,
> + DK_REAL8,
> + DK_ALIGN,
> + DK_ORG,
> + DK_ENDR,
> + DK_EXTERN,
> + DK_PUBLIC,
> + DK_COMM,
> + DK_COMMENT,
> + DK_INCLUDE,
> + DK_REPT,
> + DK_IRP,
> + DK_IRPC,
> + DK_IF,
> + DK_IFE,
> + DK_IFB,
> + DK_IFNB,
> + DK_IFDEF,
> + DK_IFNDEF,
> + DK_IFDIF,
> + DK_IFDIFI,
> + DK_IFIDN,
> + DK_IFIDNI,
> + DK_ELSEIF,
> + DK_ELSEIFE,
> + DK_ELSEIFB,
> + DK_ELSEIFNB,
> + DK_ELSEIFDEF,
> + DK_ELSEIFNDEF,
> + DK_ELSEIFDIF,
> + DK_ELSEIFDIFI,
> + DK_ELSEIFIDN,
> + DK_ELSEIFIDNI,
> + DK_ELSE,
> + DK_ENDIF,
> + DK_FILE,
> + DK_LINE,
> + DK_LOC,
> + DK_STABS,
> + 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_STRING,
> + DK_CV_FILECHECKSUMS,
> + DK_CV_FILECHECKSUM_OFFSET,
> + DK_CV_FPO_DATA,
> + 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,
> + DK_CFI_REMEMBER_STATE,
> + DK_CFI_RESTORE_STATE,
> + DK_CFI_SAME_VALUE,
> + DK_CFI_RESTORE,
> + DK_CFI_ESCAPE,
> + DK_CFI_RETURN_COLUMN,
> + DK_CFI_SIGNAL_FRAME,
> + DK_CFI_UNDEFINED,
> + DK_CFI_REGISTER,
> + DK_CFI_WINDOW_SAVE,
> + DK_CFI_B_KEY_FRAME,
> + DK_ALTMACRO,
> + DK_NOALTMACRO,
> + DK_MACRO,
> + DK_EXITM,
> + DK_ENDM,
> + DK_PURGEM,
> + DK_ERR,
> + DK_ERRB,
> + DK_ERRNB,
> + DK_ERRDEF,
> + DK_ERRNDEF,
> + DK_ERRDIF,
> + DK_ERRDIFI,
> + DK_ERRIDN,
> + DK_ERRIDNI,
> + DK_ERRE,
> + DK_ERRNZ,
> + DK_ECHO,
> + DK_END
> + };
> +
> + /// Maps directive name --> DirectiveKind enum, for
> + /// directives parsed by this class.
> + StringMap<DirectiveKind> DirectiveKindMap;
> +
> + // Codeview def_range type parsing.
> + enum CVDefRangeType {
> + CVDR_DEFRANGE = 0, // Placeholder
> + CVDR_DEFRANGE_REGISTER,
> + CVDR_DEFRANGE_FRAMEPOINTER_REL,
> + CVDR_DEFRANGE_SUBFIELD_REGISTER,
> + CVDR_DEFRANGE_REGISTER_REL
> + };
> +
> + /// Maps Codeview def_range types --> CVDefRangeType enum, for
> + /// Codeview def_range types parsed by this class.
> + StringMap<CVDefRangeType> CVDefRangeTypeMap;
> +
> + // ".ascii", ".asciz", ".string"
> + bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
> + bool parseDirectiveValue(StringRef IDVal,
> + unsigned Size); // "byte", "word",
> ...
> + bool parseDirectiveRealValue(StringRef IDVal,
> + const fltSemantics &); // "real4",
> ...
> +
> + // "=", "equ", "textequ"
> + bool parseDirectiveEquate(StringRef IDVal, StringRef Name,
> + DirectiveKind DirKind);
> +
> + bool parseDirectiveOrg(); // ".org"
> + bool parseDirectiveAlign(); // "align"
> +
> + // ".file", ".line", ".loc", ".stabs"
> + bool parseDirectiveFile(SMLoc DirectiveLoc);
> + bool parseDirectiveLine();
> + bool parseDirectiveLoc();
> + bool parseDirectiveStabs();
> +
> + // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc",
> ".cv_linetable",
> + // ".cv_inline_linetable", ".cv_def_range", ".cv_string"
> + bool parseDirectiveCVFile();
> + bool parseDirectiveCVFuncId();
> + bool parseDirectiveCVInlineSiteId();
> + bool parseDirectiveCVLoc();
> + bool parseDirectiveCVLinetable();
> + bool parseDirectiveCVInlineLinetable();
> + bool parseDirectiveCVDefRange();
> + bool parseDirectiveCVString();
> + bool parseDirectiveCVStringTable();
> + bool parseDirectiveCVFileChecksums();
> + bool parseDirectiveCVFileChecksumOffset();
> + bool parseDirectiveCVFPOData();
> +
> + // .cfi directives
> + bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIWindowSave();
> + bool parseDirectiveCFISections();
> + bool parseDirectiveCFIStartProc();
> + bool parseDirectiveCFIEndProc();
> + bool parseDirectiveCFIDefCfaOffset();
> + bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIAdjustCfaOffset();
> + bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);
> + bool parseDirectiveCFIRememberState();
> + bool parseDirectiveCFIRestoreState();
> + bool parseDirectiveCFISameValue(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIRestore(SMLoc DirectiveLoc);
> + bool parseDirectiveCFIEscape();
> + bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);
> + bool parseDirectiveCFISignalFrame();
> + bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
> +
> + // macro directives
> + bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
> + bool parseDirectiveExitMacro(StringRef Directive);
> + bool parseDirectiveEndMacro(StringRef Directive);
> + bool parseDirectiveMacro(SMLoc DirectiveLoc);
> + bool parseDirectiveMacrosOnOff(StringRef Directive);
> + // alternate macro mode directives
> + bool parseDirectiveAltmacro(StringRef Directive);
> +
> + /// Parse a directive like ".globl" which
> + /// accepts a single symbol (which should be a label or an
> external).
> + bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);
> +
> + bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"
> +
> + bool parseDirectiveComment(SMLoc DirectiveLoc); // "comment"
> +
> + bool parseDirectiveInclude(); // "include"
> +
> + // "if" or "ife"
> + bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);
> + // "ifb" or "ifnb", depending on ExpectBlank.
> + bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);
> + // "ifidn", "ifdif", "ifidni", or "ifdifi", depending on
> ExpectEqual and
> + // CaseInsensitive.
> + bool parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,
> + bool CaseInsensitive);
> + // "ifdef" or "ifndef", depending on expect_defined
> + bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);
> + // "elseif" or "elseife"
> + bool parseDirectiveElseIf(SMLoc DirectiveLoc, DirectiveKind
> DirKind);
> + // "elseifb" or "elseifnb", depending on ExpectBlank.
> + bool parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank);
> + // ".elseifdef" or ".elseifndef", depending on expect_defined
> + bool parseDirectiveElseIfdef(SMLoc DirectiveLoc, bool
> expect_defined);
> + // "elseifidn", "elseifdif", "elseifidni", or "elseifdifi",
> depending on
> + // ExpectEqual and CaseInsensitive.
> + bool parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,
> + bool CaseInsensitive);
> + bool parseDirectiveElse(SMLoc DirectiveLoc); // "else"
> + bool parseDirectiveEndIf(SMLoc DirectiveLoc); // "endif"
> + bool parseEscapedString(std::string &Data) override;
> + bool parseAngleBracketString(std::string &Data) override;
> +
> + // Macro-like directives
> + MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);
> + void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
> + raw_svector_ostream &OS);
> + bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive);
> + bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"
> + bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"
> + bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"
> +
> + // "_emit" or "__emit"
> + bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo
> &Info,
> + size_t Len);
> +
> + // "align"
> + bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo
> &Info);
> +
> + // "end"
> + bool parseDirectiveEnd(SMLoc DirectiveLoc);
> +
> + // ".err"
> + bool parseDirectiveError(SMLoc DirectiveLoc);
> + // ".errb" or ".errnb", depending on ExpectBlank.
> + bool parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank);
> + // ".errdef" or ".errndef", depending on ExpectBlank.
> + bool parseDirectiveErrorIfdef(SMLoc DirectiveLoc, bool
> ExpectDefined);
> + // ".erridn", ".errdif", ".erridni", or ".errdifi", depending on
> ExpectEqual
> + // and CaseInsensitive.
> + bool parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool
> ExpectEqual,
> + bool CaseInsensitive);
> + // ".erre" or ".errnz", depending on ExpectZero.
> + bool parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero);
> +
> + // "echo"
> + bool parseDirectiveEcho();
> +
> + void initializeDirectiveKindMap();
> + void initializeCVDefRangeTypeMap();
> +};
> +
> +} // end anonymous namespace
> +
> +namespace llvm {
> +
> +extern MCAsmParserExtension *createCOFFMasmParser();
> +
> +} // end namespace llvm
> +
> +enum { DEFAULT_ADDRSPACE = 0 };
> +
> +MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer
> &Out,
> + const MCAsmInfo &MAI, unsigned CB = 0)
> + : Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),
> + CurBuffer(CB ? CB : SM.getMainFileID()),
> MacrosEnabledFlag(true) {
> + HadError = false;
> + // Save the old handler.
> + SavedDiagHandler = SrcMgr.getDiagHandler();
> + SavedDiagContext = SrcMgr.getDiagContext();
> + // Set our own handler which calls the saved handler.
> + SrcMgr.setDiagHandler(DiagHandler, this);
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
> +
> + // Initialize the platform / file format parser.
> + switch (Ctx.getObjectFileInfo()->getObjectFileType()) {
> + case MCObjectFileInfo::IsCOFF:
> + PlatformParser.reset(createCOFFMasmParser());
> + break;
> + default:
> + report_fatal_error("llvm-ml currently supports only COFF
> output.");
> + break;
> + }
> +
> + initializeDirectiveKindMap();
> + PlatformParser->Initialize(*this);
> + initializeCVDefRangeTypeMap();
> +
> + NumOfMacroInstantiations = 0;
> +}
> +
> +MasmParser::~MasmParser() {
> + assert((HadError || ActiveMacros.empty()) &&
> + "Unexpected active macro instantiation!");
> +
> + // Restore the saved diagnostics handler and context for use
> during
> + // finalization.
> + SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);
> +}
> +
> +void MasmParser::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, SourceMgr::DK_Note,
> + "while in macro instantiation");
> +}
> +
> +void MasmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {
> + printPendingErrors();
> + printMessage(L, SourceMgr::DK_Note, Msg, Range);
> + printMacroInstantiations();
> +}
> +
> +bool MasmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {
> + if (getTargetParser().getTargetOptions().MCNoWarn)
> + return false;
> + if (getTargetParser().getTargetOptions().MCFatalWarnings)
> + return Error(L, Msg, Range);
> + printMessage(L, SourceMgr::DK_Warning, Msg, Range);
> + printMacroInstantiations();
> + return false;
> +}
> +
> +bool MasmParser::printError(SMLoc L, const Twine &Msg, SMRange
> Range) {
> + HadError = true;
> + printMessage(L, SourceMgr::DK_Error, Msg, Range);
> + printMacroInstantiations();
> + return true;
> +}
> +
> +bool MasmParser::enterIncludeFile(const std::string &Filename) {
> + std::string IncludedFile;
> + unsigned NewBuf =
> + SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
> + if (!NewBuf)
> + return true;
> +
> + CurBuffer = NewBuf;
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
> + return false;
> +}
> +
> +/// 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 MasmParser::processIncbinFile(const std::string &Filename,
> int64_t Skip,
> + const MCExpr *Count, SMLoc Loc) {
> + std::string IncludedFile;
> + unsigned NewBuf =
> + SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
> + if (!NewBuf)
> + return true;
> +
> + // Pick up the bytes from the file and emit them.
> + StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer();
> + Bytes = Bytes.drop_front(Skip);
> + if (Count) {
> + int64_t Res;
> + if (!Count->evaluateAsAbsolute(Res,
> getStreamer().getAssemblerPtr()))
> + 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;
> +}
> +
> +void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) {
> + CurBuffer = InBuffer ? InBuffer :
> SrcMgr.FindBufferContainingLoc(Loc);
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),
> + Loc.getPointer());
> +}
> +
> +const AsmToken &MasmParser::Lex() {
> + if (Lexer.getTok().is(AsmToken::Error))
> + Error(Lexer.getErrLoc(), Lexer.getErr());
> +
> + // if it's a end of statement with a comment in it
> + if (getTok().is(AsmToken::EndOfStatement)) {
> + // if this is a line comment output it.
> + if (!getTok().getString().empty() &&
> getTok().getString().front() != '\n' &&
> + getTok().getString().front() != '\r' &&
> MAI.preserveAsmComments())
> + Out.addExplicitComment(Twine(getTok().getString()));
> + }
> +
> + const AsmToken *tok = &Lexer.Lex();
> +
> + while (tok->is(AsmToken::Identifier)) {
> + auto it = Variables.find(tok->getIdentifier());
> + if (it != Variables.end() && it->second.IsText) {
> + std::unique_ptr<MemoryBuffer> Instantiation =
> + MemoryBuffer::getMemBufferCopy(it->second.TextValue,
> + "<instantiation>");
> +
> + // Jump to the macro instantiation and prime the lexer.
> + CurBuffer =
> SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
> + getTok().getEndLoc());
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)-
> >getBuffer(), nullptr,
> + /*EndStatementAtEOF=*/false);
> + tok = &Lexer.Lex();
> + } else {
> + break;
> + }
> + }
> +
> + // Parse comments here to be deferred until end of next statement.
> + while (tok->is(AsmToken::Comment)) {
> + if (MAI.preserveAsmComments())
> + Out.addExplicitComment(Twine(tok->getString()));
> + tok = &Lexer.Lex();
> + }
> +
> + if (tok->is(AsmToken::Eof)) {
> + // If this is the end of an included file, pop the parent file
> off the
> + // include stack.
> + SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
> + if (ParentIncludeLoc != SMLoc()) {
> + jumpToLoc(ParentIncludeLoc);
> + return Lex();
> + }
> + }
> +
> + return *tok;
> +}
> +
> +bool MasmParser::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) {
> + // Use the first #line directive for this, if any. It's
> preprocessed, so
> + // there is no checksum, and of course no source directive.
> + if (!FirstCppHashFilename.empty())
> + getContext().setMCLineTableRootFile(/*CUID=*/0,
> + getContext().getCompilatio
> nDir(),
> + FirstCppHashFilename,
> + /*Cksum=*/None,
> /*Source=*/None);
> + const MCDwarfFile &RootFile =
> + getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile();
> + getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDi
> rective(
> + /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name,
> + RootFile.Checksum, RootFile.Source));
> + }
> + return true;
> +}
> +
> +bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
> + // Create the initial section, if requested.
> + if (!NoInitialTextSection)
> + Out.InitSections(false);
> +
> + // Prime the lexer.
> + Lex();
> +
> + HadError = false;
> + AsmCond StartingCondState = TheCondState;
> + SmallVector<AsmRewrite, 4> AsmStrRewrites;
> +
> + // If we are generating dwarf for assembly source files save the
> initial text
> + // 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()) {
> + MCSymbol *SectionStartSym = getContext().createTempSymbol();
> + getStreamer().emitLabel(SectionStartSym);
> + Sec->setBeginSymbol(SectionStartSym);
> + }
> + bool InsertResult = getContext().addGenDwarfSection(Sec);
> + assert(InsertResult && ".text section should not have debug info
> yet");
> + (void)InsertResult;
> + }
> +
> + // While we have input, parse each statement.
> + while (Lexer.isNot(AsmToken::Eof)) {
> + ParseStatementInfo Info(&AsmStrRewrites);
> + bool Parsed = parseStatement(Info, nullptr);
> +
> + // 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 (Parsed && !hasPendingError() &&
> Lexer.getTok().is(AsmToken::Error)) {
> + Lex();
> + }
> +
> + // parseStatement returned true so may need to emit an error.
> + printPendingErrors();
> +
> + // Skipping to the next line if needed.
> + if (Parsed && !getLexer().isAtStartOfStatement())
> + eatToEndOfStatement();
> + }
> +
> + getTargetParser().onEndOfFile();
> + printPendingErrors();
> +
> + // All errors should have been emitted.
> + assert(!hasPendingError() && "unexpected error from
> parseStatement");
> +
> + getTargetParser().flushPendingInstructions(getStreamer());
> +
> + if (TheCondState.TheCond != StartingCondState.TheCond ||
> + TheCondState.Ignore != StartingCondState.Ignore)
> + 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)
> + printError(getTok().getLoc(), "unassigned file number: " +
> + Twine(Index) +
> + " for .file directives");
> + ++Index;
> + }
> + }
> +
> + // Check to see that all assembler local symbols were actually
> defined.
> + // Targets that don't do subsections via symbols may not want
> this, though,
> + // so conservatively exclude them. Only do this if we're
> finalizing, though,
> + // as otherwise we won't necessarilly have seen everything yet.
> + if (!NoFinalize) {
> + if (MAI.hasSubsectionsViaSymbols()) {
> + for (const auto &TableEntry : getContext().getSymbols()) {
> + MCSymbol *Sym = TableEntry.getValue();
> + // Variable symbols may not be marked as defined, so check
> those
> + // explicitly. If we know it's a variable, we have a
> definition for
> + // the purposes of this check.
> + if (Sym->isTemporary() && !Sym->isVariable() && !Sym-
> >isDefined())
> + // FIXME: We would really like to refer back to where the
> symbol was
> + // first referenced for a source location. We need to add
> something
> + // to track that. Currently, we just point to the end of
> the file.
> + printError(getTok().getLoc(), "assembler local symbol '" +
> + Sym->getName() + "' not
> defined");
> + }
> + }
> +
> + // Temporary symbols like the ones for directional jumps don't
> go in the
> + // symbol table. They also need to be diagnosed in all (final)
> cases.
> + for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym :
> DirLabels) {
> + if (std::get<2>(LocSym)->isUndefined()) {
> + // 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);
> + printError(std::get<0>(LocSym), "directional label
> undefined");
> + }
> + }
> + }
> +
> + // Finalize the output stream if there are no errors and if the
> client wants
> + // us to.
> + if (!HadError && !NoFinalize)
> + Out.Finish();
> +
> + return HadError || getContext().hadError();
> +}
> +
> +bool MasmParser::checkForValidSection() {
> + if (!ParsingInlineAsm && !getStreamer().getCurrentSectionOnly()) {
> + Out.InitSections(false);
> + return Error(getTok().getLoc(),
> + "expected section directive before assembly
> directive");
> + }
> + return false;
> +}
> +
> +/// Throw away the rest of the line for testing purposes.
> +void MasmParser::eatToEndOfStatement() {
> + while (Lexer.isNot(AsmToken::EndOfStatement) &&
> Lexer.isNot(AsmToken::Eof))
> + Lexer.Lex();
> +
> + // Eat EOL.
> + if (Lexer.is(AsmToken::EndOfStatement))
> + Lexer.Lex();
> +}
> +
> +StringRef MasmParser::parseStringToEndOfStatement() {
> + const char *Start = getTok().getLoc().getPointer();
> +
> + while (Lexer.isNot(AsmToken::EndOfStatement) &&
> Lexer.isNot(AsmToken::Eof))
> + Lexer.Lex();
> +
> + const char *End = getTok().getLoc().getPointer();
> + return StringRef(Start, End - Start);
> +}
> +
> +StringRef MasmParser::parseStringToComma() {
> + const char *Start = getTok().getLoc().getPointer();
> +
> + while (Lexer.isNot(AsmToken::EndOfStatement) &&
> + Lexer.isNot(AsmToken::Comma) && Lexer.isNot(AsmToken::Eof))
> + Lexer.Lex();
> +
> + const char *End = getTok().getLoc().getPointer();
> + return StringRef(Start, End - Start);
> +}
> +
> +/// Parse a paren expression and return it.
> +/// NOTE: This assumes the leading '(' has already been consumed.
> +///
> +/// parenexpr ::= expr)
> +///
> +bool MasmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {
> + if (parseExpression(Res))
> + return true;
> + if (Lexer.isNot(AsmToken::RParen))
> + return TokError("expected ')' in parentheses expression");
> + EndLoc = Lexer.getTok().getEndLoc();
> + Lex();
> + return false;
> +}
> +
> +/// Parse a bracket expression and return it.
> +/// NOTE: This assumes the leading '[' has already been consumed.
> +///
> +/// bracketexpr ::= expr]
> +///
> +bool MasmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc)
> {
> + if (parseExpression(Res))
> + return true;
> + EndLoc = getTok().getEndLoc();
> + if (parseToken(AsmToken::RBrac, "expected ']' in brackets
> expression"))
> + return true;
> + return false;
> +}
> +
> +/// Parse a primary expression and return it.
> +/// primaryexpr ::= (parenexpr
> +/// primaryexpr ::= symbol
> +/// primaryexpr ::= number
> +/// primaryexpr ::= '.'
> +/// primaryexpr ::= ~,+,- primaryexpr
> +bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc)
> {
> + SMLoc FirstTokenLoc = getLexer().getLoc();
> + AsmToken::TokenKind FirstTokenKind = Lexer.getKind();
> + switch (FirstTokenKind) {
> + default:
> + return TokError("unknown token in expression");
> + // If we have an error assume that we've already handled it.
> + case AsmToken::Error:
> + return true;
> + case AsmToken::Exclaim:
> + Lex(); // Eat the operator.
> + if (parsePrimaryExpr(Res, EndLoc))
> + return true;
> + Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);
> + return false;
> + case AsmToken::Dollar:
> + case AsmToken::At:
> + case AsmToken::String:
> + case AsmToken::Identifier: {
> + StringRef Identifier;
> + if (parseIdentifier(Identifier)) {
> + // 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();
> + Out.emitLabel(Sym);
> + Res = MCSymbolRefExpr::create(Sym,
> MCSymbolRefExpr::VK_None,
> + getContext());
> + EndLoc = FirstTokenLoc;
> + return false;
> + }
> + return Error(FirstTokenLoc, "invalid token in expression");
> + }
> + }
> + // Parse symbol variant
> + std::pair<StringRef, StringRef> Split;
> + if (!MAI.useParensForSymbolVariant()) {
> + if (FirstTokenKind == AsmToken::String) {
> + if (Lexer.is(AsmToken::At)) {
> + Lex(); // eat @
> + SMLoc AtLoc = getLexer().getLoc();
> + StringRef VName;
> + if (parseIdentifier(VName))
> + return Error(AtLoc, "expected symbol variant after
> '@'");
> +
> + Split = std::make_pair(Identifier, VName);
> + }
> + } else {
> + Split = Identifier.split('@');
> + }
> + } else if (Lexer.is(AsmToken::LParen)) {
> + Lex(); // eat '('.
> + StringRef VName;
> + parseIdentifier(VName);
> + // eat ')'.
> + if (parseToken(AsmToken::RParen,
> + "unexpected token in variant, expected ')'"))
> + return true;
> + Split = std::make_pair(Identifier, VName);
> + }
> +
> + EndLoc = SMLoc::getFromPointer(Identifier.end());
> +
> + // This is a symbol reference.
> + StringRef SymbolName = Identifier;
> + if (SymbolName.empty())
> + return Error(getLexer().getLoc(), "expected a symbol
> reference");
> +
> + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
> +
> + // Lookup the symbol variant if used.
> + if (!Split.second.empty()) {
> + Variant =
> MCSymbolRefExpr::getVariantKindForName(Split.second);
> + if (Variant != MCSymbolRefExpr::VK_Invalid) {
> + SymbolName = Split.first;
> + } else if (MAI.doesAllowAtInName() &&
> !MAI.useParensForSymbolVariant()) {
> + Variant = MCSymbolRefExpr::VK_None;
> + } else {
> + return Error(SMLoc::getFromPointer(Split.second.begin()),
> + "invalid variant '" + Split.second + "'");
> + }
> + }
> +
> + MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);
> + if (!Sym)
> + Sym = getContext().getOrCreateSymbol(SymbolName);
> +
> + // If this is an absolute variable reference, substitute it now
> to preserve
> + // semantics in the face of reassignment.
> + if (Sym->isVariable()) {
> + auto V = Sym->getVariableValue(/*SetUsed*/ false);
> + bool DoInline = isa<MCConstantExpr>(V) && !Variant;
> + 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.
> + Res = MCSymbolRefExpr::create(Sym, Variant, getContext(),
> FirstTokenLoc);
> + return false;
> + }
> + case AsmToken::BigNum:
> + return TokError("literal value out of range for directive");
> + case AsmToken::Integer: {
> + SMLoc Loc = getTok().getLoc();
> + int64_t IntVal = getTok().getIntVal();
> + Res = MCConstantExpr::create(IntVal, getContext());
> + EndLoc = Lexer.getTok().getEndLoc();
> + Lex(); // Eat token.
> + // Look for 'b' or 'f' following an Integer as a directional
> label
> + if (Lexer.getKind() == AsmToken::Identifier) {
> + StringRef IDVal = getTok().getString();
> + // Lookup the symbol variant if used.
> + std::pair<StringRef, StringRef> Split = IDVal.split('@');
> + MCSymbolRefExpr::VariantKind Variant =
> MCSymbolRefExpr::VK_None;
> + if (Split.first.size() != IDVal.size()) {
> + Variant =
> MCSymbolRefExpr::getVariantKindForName(Split.second);
> + if (Variant == MCSymbolRefExpr::VK_Invalid)
> + return TokError("invalid variant '" + Split.second + "'");
> + IDVal = Split.first;
> + }
> + if (IDVal == "f" || IDVal == "b") {
> + MCSymbol *Sym =
> + Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b");
> + Res = MCSymbolRefExpr::create(Sym, Variant, getContext());
> + if (IDVal == "b" && Sym->isUndefined())
> + return Error(Loc, "directional label undefined");
> + DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym));
> + EndLoc = Lexer.getTok().getEndLoc();
> + Lex(); // Eat identifier.
> + }
> + }
> + return false;
> + }
> + case AsmToken::Real: {
> + APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());
> + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
> + Res = MCConstantExpr::create(IntVal, getContext());
> + EndLoc = Lexer.getTok().getEndLoc();
> + Lex(); // Eat token.
> + return false;
> + }
> + case AsmToken::Dot: {
> + // This is a '.' reference, which references the current
> PC. Emit a
> + // temporary label to the streamer and refer to it.
> + MCSymbol *Sym = Ctx.createTempSymbol();
> + Out.emitLabel(Sym);
> + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
> getContext());
> + EndLoc = Lexer.getTok().getEndLoc();
> + Lex(); // Eat identifier.
> + return false;
> + }
> + case AsmToken::LParen:
> + Lex(); // Eat the '('.
> + return parseParenExpr(Res, EndLoc);
> + case AsmToken::LBrac:
> + if (!PlatformParser->HasBracketExpressions())
> + return TokError("brackets expression not supported on this
> target");
> + Lex(); // Eat the '['.
> + return parseBracketExpr(Res, EndLoc);
> + case AsmToken::Minus:
> + Lex(); // Eat the operator.
> + if (parsePrimaryExpr(Res, EndLoc))
> + return true;
> + Res = MCUnaryExpr::createMinus(Res, getContext(),
> FirstTokenLoc);
> + return false;
> + case AsmToken::Plus:
> + Lex(); // Eat the operator.
> + if (parsePrimaryExpr(Res, EndLoc))
> + return true;
> + Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);
> + return false;
> + case AsmToken::Tilde:
> + Lex(); // Eat the operator.
> + if (parsePrimaryExpr(Res, EndLoc))
> + return true;
> + Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);
> + 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;
> + }
> +}
> +
> +bool MasmParser::parseExpression(const MCExpr *&Res) {
> + SMLoc EndLoc;
> + return parseExpression(Res, EndLoc);
> +}
> +
> +/// This function checks if the next token is <string> type or
> arithmetic.
> +/// string that begin with character '<' must end with character
> '>'.
> +/// otherwise it is arithmetics.
> +/// If the function returns a 'true' value,
> +/// 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. GCC does not fully support this feature and so
> we will not
> +/// support it.
> +/// TODO: Adding single quote as a string.
> +static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {
> + assert((StrLoc.getPointer() != nullptr) &&
> + "Argument to the function cannot be a NULL value");
> + const char *CharPtr = StrLoc.getPointer();
> + while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr !=
> '\r') &&
> + (*CharPtr != '\0')) {
> + if (*CharPtr == '!')
> + CharPtr++;
> + CharPtr++;
> + }
> + if (*CharPtr == '>') {
> + EndLoc = StrLoc.getFromPointer(CharPtr + 1);
> + return true;
> + }
> + return false;
> +}
> +
> +/// creating a string without the escape characters '!'.
> +static std::string angleBracketString(StringRef AltMacroStr) {
> + std::string Res;
> + for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {
> + if (AltMacroStr[Pos] == '!')
> + Pos++;
> + Res += AltMacroStr[Pos];
> + }
> + return Res;
> +}
> +
> +/// Parse an expression and return it.
> +///
> +/// expr ::= expr &&,|| expr -> lowest.
> +/// expr ::= expr |,^,&,! expr
> +/// expr ::= expr ==,!=,<>,<,<=,>,>= expr
> +/// expr ::= expr <<,>> expr
> +/// expr ::= expr +,- expr
> +/// expr ::= expr *,/,% expr -> highest.
> +/// expr ::= primaryexpr
> +///
> +bool MasmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc)
> {
> + // Parse the expression.
> + Res = nullptr;
> + if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||
> + parseBinOpRHS(1, Res, EndLoc))
> + return true;
> +
> + // 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());
> +
> + return false;
> +}
> +
> +bool MasmParser::parseParenExpression(const MCExpr *&Res, SMLoc
> &EndLoc) {
> + Res = nullptr;
> + return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res,
> EndLoc);
> +}
> +
> +bool MasmParser::parseParenExprOfDepth(unsigned ParenDepth, const
> MCExpr *&Res,
> + SMLoc &EndLoc) {
> + if (parseParenExpr(Res, EndLoc))
> + return true;
> +
> + for (; ParenDepth > 0; --ParenDepth) {
> + if (parseBinOpRHS(1, Res, EndLoc))
> + return true;
> +
> + // We don't Lex() the last RParen.
> + // This is the same behavior as parseParenExpression().
> + if (ParenDepth - 1 > 0) {
> + EndLoc = getTok().getEndLoc();
> + if (parseToken(AsmToken::RParen,
> + "expected ')' in parentheses expression"))
> + return true;
> + }
> + }
> + return false;
> +}
> +
> +bool MasmParser::parseAbsoluteExpression(int64_t &Res) {
> + const MCExpr *Expr;
> +
> + SMLoc StartLoc = Lexer.getLoc();
> + if (parseExpression(Expr))
> + return true;
> +
> + if (!Expr->evaluateAsAbsolute(Res,
> getStreamer().getAssemblerPtr()))
> + return Error(StartLoc, "expected absolute expression");
> +
> + return false;
> +}
> +
> +static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,
> + MCBinaryExpr::Opcode &Kind,
> + bool ShouldUseLogicalShr) {
> + switch (K) {
> + default:
> + return 0; // not a binop.
> +
> + // Lowest Precedence: &&, ||
> + case AsmToken::AmpAmp:
> + Kind = MCBinaryExpr::LAnd;
> + return 2;
> + case AsmToken::PipePipe:
> + Kind = MCBinaryExpr::LOr;
> + return 1;
> +
> + // Low Precedence: ==, !=, <>, <, <=, >, >=
> + case AsmToken::EqualEqual:
> + Kind = MCBinaryExpr::EQ;
> + return 3;
> + case AsmToken::ExclaimEqual:
> + case AsmToken::LessGreater:
> + Kind = MCBinaryExpr::NE;
> + return 3;
> + case AsmToken::Less:
> + Kind = MCBinaryExpr::LT;
> + return 3;
> + case AsmToken::LessEqual:
> + Kind = MCBinaryExpr::LTE;
> + return 3;
> + case AsmToken::Greater:
> + Kind = MCBinaryExpr::GT;
> + return 3;
> + case AsmToken::GreaterEqual:
> + Kind = MCBinaryExpr::GTE;
> + return 3;
> +
> + // Low Intermediate Precedence: +, -
> + case AsmToken::Plus:
> + Kind = MCBinaryExpr::Add;
> + return 4;
> + case AsmToken::Minus:
> + Kind = MCBinaryExpr::Sub;
> + return 4;
> +
> + // High Intermediate Precedence: |, &, ^
> + //
> + // FIXME: gas seems to support '!' as an infix operator?
> + case AsmToken::Pipe:
> + Kind = MCBinaryExpr::Or;
> + return 5;
> + case AsmToken::Caret:
> + Kind = MCBinaryExpr::Xor;
> + return 5;
> + case AsmToken::Amp:
> + Kind = MCBinaryExpr::And;
> + return 5;
> +
> + // Highest Precedence: *, /, %, <<, >>
> + case AsmToken::Star:
> + Kind = MCBinaryExpr::Mul;
> + return 6;
> + case AsmToken::Slash:
> + Kind = MCBinaryExpr::Div;
> + return 6;
> + case AsmToken::Percent:
> + Kind = MCBinaryExpr::Mod;
> + return 6;
> + case AsmToken::LessLess:
> + Kind = MCBinaryExpr::Shl;
> + return 6;
> + case AsmToken::GreaterGreater:
> + Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr :
> MCBinaryExpr::AShr;
> + return 6;
> + }
> +}
> +
> +unsigned MasmParser::getBinOpPrecedence(AsmToken::TokenKind K,
> + MCBinaryExpr::Opcode &Kind)
> {
> + bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();
> + return getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr);
> +}
> +
> +/// Parse all binary operators with precedence >= 'Precedence'.
> +/// Res contains the LHS of the expression on input.
> +bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr
> *&Res,
> + SMLoc &EndLoc) {
> + SMLoc StartLoc = Lexer.getLoc();
> + while (true) {
> + MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;
> + unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind);
> +
> + // If the next token is lower precedence than we are allowed to
> eat, return
> + // successfully with what we ate already.
> + if (TokPrec < Precedence)
> + return false;
> +
> + Lex();
> +
> + // Eat the next primary expression.
> + const MCExpr *RHS;
> + if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))
> + return true;
> +
> + // If BinOp binds less tightly with RHS than the operator after
> RHS, let
> + // the pending operator take RHS as its LHS.
> + MCBinaryExpr::Opcode Dummy;
> + unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(),
> Dummy);
> + if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS,
> EndLoc))
> + return true;
> +
> + // Merge LHS and RHS according to operator.
> + Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(),
> StartLoc);
> + }
> +}
> +
> +/// ParseStatement:
> +/// ::= EndOfStatement
> +/// ::= Label* Directive ...Operands... EndOfStatement
> +/// ::= Label* Identifier OperandList* EndOfStatement
> +bool MasmParser::parseStatement(ParseStatementInfo &Info,
> + MCAsmParserSemaCallback *SI) {
> + assert(!hasPendingError() && "parseStatement started with pending
> error");
> + // Eat initial spaces and comments
> + while (Lexer.is(AsmToken::Space))
> + Lex();
> + if (Lexer.is(AsmToken::EndOfStatement)) {
> + // if this is a line comment we can drop it safely
> + if (getTok().getString().empty() || getTok().getString().front()
> == '\r' ||
> + getTok().getString().front() == '\n')
> + Out.AddBlankLine();
> + Lex();
> + return false;
> + }
> + // Statements always start with an identifier, unless we're
> dealing with a
> + // processor directive (.386, .686, etc.) that lexes as a real.
> + AsmToken ID = getTok();
> + SMLoc IDLoc = ID.getLoc();
> + StringRef IDVal;
> + int64_t LocalLabelVal = -1;
> + if (Lexer.is(AsmToken::HashDirective))
> + return parseCppHashLineFilenameComment(IDLoc);
> + // Allow an integer followed by a ':' as a directional local
> label.
> + if (Lexer.is(AsmToken::Integer)) {
> + LocalLabelVal = getTok().getIntVal();
> + if (LocalLabelVal < 0) {
> + 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) {
> + Lex(); // always eat a token
> + return Error(IDLoc, "unexpected token at start of
> statement");
> + }
> + }
> + }
> + } else if (Lexer.is(AsmToken::Dot)) {
> + // Treat '.' as a valid identifier in this context.
> + Lex();
> + IDVal = ".";
> + } else if (Lexer.is(AsmToken::LCurly)) {
> + // Treat '{' as a valid identifier in this context.
> + Lex();
> + IDVal = "{";
> +
> + } else if (Lexer.is(AsmToken::RCurly)) {
> + // Treat '}' as a valid identifier in this context.
> + Lex();
> + IDVal = "}";
> + } else if (Lexer.is(AsmToken::Star) &&
> + getTargetParser().starIsStartOfStatement()) {
> + // Accept '*' as a valid start of statement.
> + Lex();
> + IDVal = "*";
> + } else if (Lexer.is(AsmToken::Real)) {
> + // Treat ".<number>" as a valid identifier in this context.
> + IDVal = getTok().getString();
> + Lex(); // always eat a token
> + if (!IDVal.startswith("."))
> + return Error(IDLoc, "unexpected token at start of statement");
> + } else if (parseIdentifier(IDVal)) {
> + if (!TheCondState.Ignore) {
> + Lex(); // always eat a token
> + return Error(IDLoc, "unexpected token at start of statement");
> + }
> + IDVal = "";
> + }
> +
> + // Handle conditional assembly here before checking for
> skipping. We
> + // have to do this so that .endif isn't skipped in a ".if 0" block
> for
> + // example.
> + StringMap<DirectiveKind>::const_iterator DirKindIt =
> + DirectiveKindMap.find(IDVal.lower());
> + DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())
> + ? DK_NO_DIRECTIVE
> + : DirKindIt->getValue();
> + switch (DirKind) {
> + default:
> + break;
> + case DK_IF:
> + case DK_IFE:
> + return parseDirectiveIf(IDLoc, DirKind);
> + case DK_IFB:
> + return parseDirectiveIfb(IDLoc, true);
> + case DK_IFNB:
> + return parseDirectiveIfb(IDLoc, false);
> + case DK_IFDEF:
> + return parseDirectiveIfdef(IDLoc, true);
> + case DK_IFNDEF:
> + return parseDirectiveIfdef(IDLoc, false);
> + case DK_IFDIF:
> + return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/false);
> + case DK_IFDIFI:
> + return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/true);
> + case DK_IFIDN:
> + return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/false);
> + case DK_IFIDNI:
> + return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/true);
> + case DK_ELSEIF:
> + case DK_ELSEIFE:
> + return parseDirectiveElseIf(IDLoc, DirKind);
> + case DK_ELSEIFB:
> + return parseDirectiveElseIfb(IDLoc, true);
> + case DK_ELSEIFNB:
> + return parseDirectiveElseIfb(IDLoc, false);
> + case DK_ELSEIFDEF:
> + return parseDirectiveElseIfdef(IDLoc, true);
> + case DK_ELSEIFNDEF:
> + return parseDirectiveElseIfdef(IDLoc, false);
> + case DK_ELSEIFDIF:
> + return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/false);
> + case DK_ELSEIFDIFI:
> + return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/true);
> + case DK_ELSEIFIDN:
> + return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/false);
> + case DK_ELSEIFIDNI:
> + return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/true);
> + case DK_ELSE:
> + return parseDirectiveElse(IDLoc);
> + case DK_ENDIF:
> + return parseDirectiveEndIf(IDLoc);
> + }
> +
> + // Ignore the statement if in the middle of inactive conditional
> + // (e.g. ".if 0").
> + if (TheCondState.Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> +
> + // FIXME: Recurse on local labels?
> +
> + // See what kind of statement we have.
> + switch (Lexer.getKind()) {
> + case AsmToken::Colon: {
> + if (!getTargetParser().isLabel(ID))
> + break;
> + if (checkForValidSection())
> + return true;
> +
> + // identifier ':' -> Label.
> + Lex();
> +
> + // Diagnose attempt to use '.' as a label.
> + if (IDVal == ".")
> + return Error(IDLoc, "invalid use of pseudo-symbol '.' as a
> label");
> +
> + // Diagnose attempt to use a variable as a label.
> + //
> + // FIXME: Diagnostics. Note the location of the definition as a
> label.
> + // FIXME: This doesn't diagnose assignment to a symbol which has
> been
> + // implicitly marked as external.
> + MCSymbol *Sym;
> + if (LocalLabelVal == -1) {
> + if (ParsingInlineAsm && SI) {
> + StringRef RewrittenLabel =
> + SI->LookupInlineAsmLabel(IDVal, getSourceManager(),
> IDLoc, true);
> + assert(!RewrittenLabel.empty() &&
> + "We should have an internal name here.");
> + Info.AsmRewrites->emplace_back(AOK_Label, IDLoc,
> IDVal.size(),
> + RewrittenLabel);
> + IDVal = RewrittenLabel;
> + }
> + Sym = getContext().getOrCreateSymbol(IDVal);
> + } else
> + Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal);
> + // 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)) {
> + Lex();
> + }
> +
> + getTargetParser().doBeforeLabelEmit(Sym);
> +
> + // Emit the label.
> + if (!getTargetParser().isParsingInlineAsm())
> + Out.emitLabel(Sym, IDLoc);
> +
> + // 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 (enabledGenDwarfForAssembly())
> + MCGenDwarfLabelEntry::Make(Sym, &getStreamer(),
> getSourceManager(),
> + IDLoc);
> +
> + getTargetParser().onLabelParsed(Sym);
> +
> + return false;
> + }
> +
> + default: // Normal instruction or directive.
> + break;
> + }
> +
> + // If macros are enabled, check to see if this is a macro
> instantiation.
> + if (areMacrosEnabled())
> + if (const MCAsmMacro *M = getContext().lookupMacro(IDVal)) {
> + return handleMacroEntry(M, IDLoc);
> + }
> +
> + // Otherwise, we have a normal instruction or directive.
> +
> + if (DirKind != DK_NO_DIRECTIVE) {
> + // There are several entities interested in parsing directives:
> + //
> + // 1. Asm parser extensions. For example, platform-specific
> parsers
> + // (like the ELF parser) register themselves as extensions.
> + // 2. The target-specific assembly parser. Some directives are
> target
> + // specific or may potentially behave
> diff erently on certain targets.
> + // 3. The generic directive parser implemented by this class.
> These are
> + // all the directives that behave in a target and platform
> independent
> + // manner, or at least have a default behavior that's shared
> between
> + // all targets and platforms.
> +
> + getTargetParser().flushPendingInstructions(getStreamer());
> +
> + // First, check the extension directive map to see if any
> extension has
> + // registered itself to parse this directive.
> + std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =
> + ExtensionDirectiveMap.lookup(IDVal.lower());
> + if (Handler.first)
> + return (*Handler.second)(Handler.first, IDVal, IDLoc);
> +
> + // Next, let the target-specific assembly parser try.
> + SMLoc StartTokLoc = getTok().getLoc();
> + bool TPDirectiveReturn =
> + ID.is(AsmToken::Identifier) &&
> 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;
> +
> + // Finally, if no one else is interested in this directive, it
> must be
> + // generic and familiar to this class.
> + switch (DirKind) {
> + default:
> + break;
> + case DK_ASCII:
> + return parseDirectiveAscii(IDVal, false);
> + case DK_ASCIZ:
> + case DK_STRING:
> + return parseDirectiveAscii(IDVal, true);
> + case DK_BYTE:
> + case DK_SBYTE:
> + case DK_DB:
> + return parseDirectiveValue(IDVal, 1);
> + case DK_WORD:
> + case DK_SWORD:
> + case DK_DW:
> + return parseDirectiveValue(IDVal, 2);
> + case DK_DWORD:
> + case DK_SDWORD:
> + case DK_DD:
> + return parseDirectiveValue(IDVal, 4);
> + case DK_FWORD:
> + return parseDirectiveValue(IDVal, 6);
> + case DK_QWORD:
> + case DK_SQWORD:
> + case DK_DQ:
> + return parseDirectiveValue(IDVal, 8);
> + case DK_REAL4:
> + return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle());
> + case DK_REAL8:
> + return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble());
> + case DK_ALIGN:
> + return parseDirectiveAlign();
> + case DK_ORG:
> + return parseDirectiveOrg();
> + case DK_EXTERN:
> + eatToEndOfStatement(); // .extern is the default, ignore it.
> + return false;
> + case DK_PUBLIC:
> + return parseDirectiveSymbolAttribute(MCSA_Global);
> + case DK_COMM:
> + return parseDirectiveComm(/*IsLocal=*/false);
> + case DK_COMMENT:
> + return parseDirectiveComment(IDLoc);
> + case DK_INCLUDE:
> + return parseDirectiveInclude();
> + case DK_REPT:
> + return parseDirectiveRept(IDLoc, IDVal);
> + case DK_IRP:
> + return parseDirectiveIrp(IDLoc);
> + case DK_IRPC:
> + return parseDirectiveIrpc(IDLoc);
> + case DK_ENDR:
> + return parseDirectiveEndr(IDLoc);
> + case DK_FILE:
> + return parseDirectiveFile(IDLoc);
> + case DK_LINE:
> + return parseDirectiveLine();
> + case DK_LOC:
> + return parseDirectiveLoc();
> + case DK_STABS:
> + 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:
> + return parseDirectiveCVLinetable();
> + case DK_CV_INLINE_LINETABLE:
> + return parseDirectiveCVInlineLinetable();
> + case DK_CV_DEF_RANGE:
> + return parseDirectiveCVDefRange();
> + case DK_CV_STRING:
> + return parseDirectiveCVString();
> + case DK_CV_STRINGTABLE:
> + return parseDirectiveCVStringTable();
> + case DK_CV_FILECHECKSUMS:
> + return parseDirectiveCVFileChecksums();
> + case DK_CV_FILECHECKSUM_OFFSET:
> + return parseDirectiveCVFileChecksumOffset();
> + case DK_CV_FPO_DATA:
> + return parseDirectiveCVFPOData();
> + case DK_CFI_SECTIONS:
> + return parseDirectiveCFISections();
> + case DK_CFI_STARTPROC:
> + return parseDirectiveCFIStartProc();
> + case DK_CFI_ENDPROC:
> + return parseDirectiveCFIEndProc();
> + case DK_CFI_DEF_CFA:
> + return parseDirectiveCFIDefCfa(IDLoc);
> + case DK_CFI_DEF_CFA_OFFSET:
> + return parseDirectiveCFIDefCfaOffset();
> + case DK_CFI_ADJUST_CFA_OFFSET:
> + return parseDirectiveCFIAdjustCfaOffset();
> + case DK_CFI_DEF_CFA_REGISTER:
> + return parseDirectiveCFIDefCfaRegister(IDLoc);
> + case DK_CFI_OFFSET:
> + return parseDirectiveCFIOffset(IDLoc);
> + case DK_CFI_REL_OFFSET:
> + return parseDirectiveCFIRelOffset(IDLoc);
> + case DK_CFI_PERSONALITY:
> + return parseDirectiveCFIPersonalityOrLsda(true);
> + case DK_CFI_LSDA:
> + return parseDirectiveCFIPersonalityOrLsda(false);
> + case DK_CFI_REMEMBER_STATE:
> + return parseDirectiveCFIRememberState();
> + case DK_CFI_RESTORE_STATE:
> + return parseDirectiveCFIRestoreState();
> + case DK_CFI_SAME_VALUE:
> + return parseDirectiveCFISameValue(IDLoc);
> + case DK_CFI_RESTORE:
> + return parseDirectiveCFIRestore(IDLoc);
> + case DK_CFI_ESCAPE:
> + return parseDirectiveCFIEscape();
> + case DK_CFI_RETURN_COLUMN:
> + return parseDirectiveCFIReturnColumn(IDLoc);
> + case DK_CFI_SIGNAL_FRAME:
> + return parseDirectiveCFISignalFrame();
> + case DK_CFI_UNDEFINED:
> + return parseDirectiveCFIUndefined(IDLoc);
> + case DK_CFI_REGISTER:
> + return parseDirectiveCFIRegister(IDLoc);
> + case DK_CFI_WINDOW_SAVE:
> + return parseDirectiveCFIWindowSave();
> + case DK_MACRO:
> + return parseDirectiveMacro(IDLoc);
> + case DK_ALTMACRO:
> + case DK_NOALTMACRO:
> + return parseDirectiveAltmacro(IDVal);
> + case DK_EXITM:
> + return parseDirectiveExitMacro(IDVal);
> + case DK_ENDM:
> + return parseDirectiveEndMacro(IDVal);
> + case DK_PURGEM:
> + return parseDirectivePurgeMacro(IDLoc);
> + case DK_END:
> + return parseDirectiveEnd(IDLoc);
> + case DK_ERR:
> + return parseDirectiveError(IDLoc);
> + case DK_ERRB:
> + return parseDirectiveErrorIfb(IDLoc, true);
> + case DK_ERRNB:
> + return parseDirectiveErrorIfb(IDLoc, false);
> + case DK_ERRDEF:
> + return parseDirectiveErrorIfdef(IDLoc, true);
> + case DK_ERRNDEF:
> + return parseDirectiveErrorIfdef(IDLoc, false);
> + case DK_ERRDIF:
> + return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/false);
> + case DK_ERRDIFI:
> + return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,
> + /*CaseInsensitive=*/true);
> + case DK_ERRIDN:
> + return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/false);
> + case DK_ERRIDNI:
> + return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,
> + /*CaseInsensitive=*/true);
> + case DK_ERRE:
> + return parseDirectiveErrorIfe(IDLoc, true);
> + case DK_ERRNZ:
> + return parseDirectiveErrorIfe(IDLoc, false);
> + case DK_ECHO:
> + return parseDirectiveEcho();
> + }
> +
> + return Error(IDLoc, "unknown directive");
> + }
> +
> + // Non-conditional Microsoft directives sometimes follow their
> first argument.
> + const AsmToken nextTok = getTok();
> + const StringRef nextVal = nextTok.getString();
> + const SMLoc nextLoc = nextTok.getLoc();
> +
> + // There are several entities interested in parsing infix
> directives:
> + //
> + // 1. Asm parser extensions. For example, platform-specific
> parsers
> + // (like the ELF parser) register themselves as extensions.
> + // 2. The generic directive parser implemented by this class.
> These are
> + // all the directives that behave in a target and platform
> independent
> + // manner, or at least have a default behavior that's shared
> between
> + // all targets and platforms.
> +
> + getTargetParser().flushPendingInstructions(getStreamer());
> +
> + // First, check the extension directive map to see if any
> extension has
> + // registered itself to parse this directive.
> + std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =
> + ExtensionDirectiveMap.lookup(nextVal.lower());
> + if (Handler.first) {
> + Lex();
> + Lexer.UnLex(ID);
> + return (*Handler.second)(Handler.first, nextVal, nextLoc);
> + }
> +
> + // Finally, if no one else is interested in this directive, it
> must be
> + // generic and familiar to this class.
> + DirKindIt = DirectiveKindMap.find(nextVal.lower());
> + DirKind = (DirKindIt == DirectiveKindMap.end())
> + ? DK_NO_DIRECTIVE
> + : DirKindIt->getValue();
> + switch (DirKind) {
> + default:
> + break;
> + case DK_ASSIGN:
> + case DK_EQU:
> + case DK_TEXTEQU:
> + Lex();
> + return parseDirectiveEquate(nextVal, IDVal, DirKind);
> + }
> +
> + // __asm _emit or __asm __emit
> + if (ParsingInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||
> + IDVal == "_EMIT" || IDVal == "__EMIT"))
> + return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());
> +
> + // __asm align
> + if (ParsingInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))
> + return parseDirectiveMSAlign(IDLoc, Info);
> +
> + if (ParsingInlineAsm && (IDVal == "even" || IDVal == "EVEN"))
> + Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);
> + if (checkForValidSection())
> + return true;
> +
> + // Canonicalize the opcode to lower case.
> + std::string OpcodeStr = IDVal.lower();
> + ParseInstructionInfo IInfo(Info.AsmRewrites);
> + bool ParseHadError = getTargetParser().ParseInstruction(IInfo,
> OpcodeStr, ID,
> + Info.Parse
> dOperands);
> + Info.ParseError = ParseHadError;
> +
> + // Dump the parsed representation, if requested.
> + if (getShowParsedOperands()) {
> + SmallString<256> Str;
> + raw_svector_ostream OS(Str);
> + OS << "parsed instruction: [";
> + for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {
> + if (i != 0)
> + OS << ", ";
> + Info.ParsedOperands[i]->print(OS);
> + }
> + OS << "]";
> +
> + 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 (!ParseHadError && enabledGenDwarfForAssembly() &&
> + getContext().getGenDwarfSectionSyms().count(
> + getStreamer().getCurrentSectionOnly())) {
> + unsigned Line;
> + if (ActiveMacros.empty())
> + Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer);
> + else
> + Line = SrcMgr.FindLineNumber(ActiveMacros.front()-
> >InstantiationLoc,
> + ActiveMacros.front()-
> >ExitBuffer);
> +
> + // 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.
> + if (!CppHashInfo.Filename.empty()) {
> + unsigned FileNumber = getStreamer().emitDwarfFileDirective(
> + 0, StringRef(), CppHashInfo.Filename);
> + getContext().setGenDwarfFileNumber(FileNumber);
> +
> + unsigned CppHashLocLineNo =
> + SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf);
> + Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo);
> + }
> +
> + getStreamer().emitDwarfLocDirective(
> + getContext().getGenDwarfFileNumber(), Line, 0,
> + DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0,
> + StringRef());
> + }
> +
> + // If parsing succeeded, match the instruction.
> + if (!ParseHadError) {
> + uint64_t ErrorInfo;
> + if (getTargetParser().MatchAndEmitInstruction(
> + IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,
> + getTargetParser().isParsingInlineAsm()))
> + return true;
> + }
> + return false;
> +}
> +
> +// Parse and erase curly braces marking block start/end
> +bool MasmParser::parseCurlyBlockScope(
> + SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {
> + // Identify curly brace marking block start/end
> + if (Lexer.isNot(AsmToken::LCurly) &&
> Lexer.isNot(AsmToken::RCurly))
> + return false;
> +
> + SMLoc StartLoc = Lexer.getLoc();
> + Lex(); // Eat the brace
> + if (Lexer.is(AsmToken::EndOfStatement))
> + Lex(); // Eat EndOfStatement following the brace
> +
> + // Erase the block start/end brace from the output asm string
> + AsmStrRewrites.emplace_back(AOK_Skip, StartLoc,
> Lexer.getLoc().getPointer() -
> + StartLoc.getPointe
> r());
> + return true;
> +}
> +
> +/// parseCppHashLineFilenameComment as this:
> +/// ::= # number "filename"
> +bool MasmParser::parseCppHashLineFilenameComment(SMLoc L) {
> + Lex(); // Eat the hash token.
> + // Lexer only ever emits HashDirective if it fully formed if it's
> + // done the checking already so this is an internal error.
> + assert(getTok().is(AsmToken::Integer) &&
> + "Lexing Cpp line comment: Expected Integer");
> + int64_t LineNumber = getTok().getIntVal();
> + Lex();
> + assert(getTok().is(AsmToken::String) &&
> + "Lexing Cpp line comment: Expected String");
> + StringRef Filename = getTok().getString();
> + Lex();
> +
> + // Get rid of the enclosing quotes.
> + Filename = Filename.substr(1, Filename.size() - 2);
> +
> + // Save the SMLoc, Filename and LineNumber for later use by
> diagnostics
> + // and possibly DWARF file info.
> + CppHashInfo.Loc = L;
> + CppHashInfo.Filename = Filename;
> + CppHashInfo.LineNumber = LineNumber;
> + CppHashInfo.Buf = CurBuffer;
> + if (FirstCppHashFilename.empty())
> + FirstCppHashFilename = Filename;
> + return false;
> +}
> +
> +/// will use the last parsed cpp hash line filename comment
> +/// for the Filename and LineNo if any in the diagnostic.
> +void MasmParser::DiagHandler(const SMDiagnostic &Diag, void
> *Context) {
> + const MasmParser *Parser = static_cast<const MasmParser
> *>(Context);
> + raw_ostream &OS = errs();
> +
> + const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();
> + SMLoc DiagLoc = Diag.getLoc();
> + unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
> + unsigned CppHashBuf =
> + Parser->SrcMgr.FindBufferContainingLoc(Parser-
> >CppHashInfo.Loc);
> +
> + // Like SourceMgr::printMessage() we need to print the include
> stack if any
> + // before printing the message.
> + unsigned DiagCurBuffer =
> DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
> + if (!Parser->SavedDiagHandler && DiagCurBuffer &&
> + DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
> + SMLoc ParentIncludeLoc =
> DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);
> + DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
> + }
> +
> + // If we have not parsed a cpp hash line filename comment or the
> source
> + // manager changed or buffer changed (like in a nested include)
> then just
> + // print the normal diagnostic using its Filename and LineNo.
> + if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser-
> >SrcMgr ||
> + DiagBuf != CppHashBuf) {
> + if (Parser->SavedDiagHandler)
> + Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);
> + else
> + Diag.print(nullptr, OS);
> + return;
> + }
> +
> + // Use the CppHashFilename and calculate a line number based on
> the
> + // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this
> Diag's SMLoc
> + // for the diagnostic.
> + const std::string &Filename = std::string(Parser-
> >CppHashInfo.Filename);
> +
> + int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);
> + int CppHashLocLineNo =
> + Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc,
> CppHashBuf);
> + int LineNo =
> + Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo -
> CppHashLocLineNo);
> +
> + 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(nullptr, OS);
> +}
> +
> +// FIXME: This is mostly duplicated from the function in
> AsmLexer.cpp. The
> +//
> diff erence 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(static_cast<unsigned char>(c)) || c == '_' || c ==
> '$' ||
> + c == '.';
> +}
> +
> +bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef
> Body,
> + ArrayRef<MCAsmMacroParameter>
> Parameters,
> + ArrayRef<MCAsmMacroArgument> A,
> + bool EnableAtPseudoVariable, SMLoc L) {
> + unsigned NParameters = Parameters.size();
> + bool HasVararg = NParameters ? Parameters.back().Vararg : false;
> + if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
> + return Error(L, "Wrong number of arguments");
> +
> + // A macro without parameters is handled
> diff erently 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;
> + for (; Pos != End; ++Pos) {
> + // Check for a substitution or escape.
> + if (IsDarwin && !NParameters) {
> + // This macro has no parameters, look for $0, $1, etc.
> + if (Body[Pos] != '$' || Pos + 1 == End)
> + continue;
> +
> + char Next = Body[Pos + 1];
> + if (Next == '$' || Next == 'n' ||
> + isdigit(static_cast<unsigned char>(Next)))
> + break;
> + } else {
> + // This macro has parameters, look for \foo, \bar, etc.
> + if (Body[Pos] == '\\' && Pos + 1 != End)
> + break;
> + }
> + }
> +
> + // Add the prefix.
> + OS << Body.slice(0, Pos);
> +
> + // Check if we reached the end.
> + if (Pos == End)
> + break;
> +
> + if (IsDarwin && !NParameters) {
> + switch (Body[Pos + 1]) {
> + // $$ => $
> + case '$':
> + OS << '$';
> + break;
> +
> + // $n => number of arguments
> + case 'n':
> + OS << A.size();
> + break;
> +
> + // $[0-9] => argument
> + default: {
> + // Missing arguments are ignored.
> + unsigned Index = Body[Pos + 1] - '0';
> + if (Index >= A.size())
> + break;
> +
> + // Otherwise substitute with the token values, with spaces
> eliminated.
> + for (const AsmToken &Token : A[Index])
> + OS << Token.getString();
> + break;
> + }
> + }
> + Pos += 2;
> + } else {
> + unsigned I = Pos + 1;
> +
> + // Check for the \@ pseudo-variable.
> + if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End)
> + ++I;
> + else
> + while (isIdentifierChar(Body[I]) && I + 1 != End)
> + ++I;
> +
> + const char *Begin = Body.data() + Pos + 1;
> + StringRef Argument(Begin, I - (Pos + 1));
> + unsigned Index = 0;
> +
> + if (Argument == "@") {
> + OS << NumOfMacroInstantiations;
> + Pos += 2;
> + } else {
> + for (; Index < NParameters; ++Index)
> + if (Parameters[Index].Name == Argument)
> + break;
> +
> + if (Index == NParameters) {
> + if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
> + Pos += 3;
> + else {
> + OS << '\\' << Argument;
> + Pos = I;
> + }
> + } else {
> + bool VarargParameter = HasVararg && Index == (NParameters
> - 1);
> + for (const AsmToken &Token : A[Index])
> + // For altmacro mode, you can write '%expr'.
> + // The prefix '%' evaluates the expression 'expr'
> + // and uses the result as a string (e.g. replace %(1+2)
> with the
> + // string "3").
> + // Here, we identify the integer token which is the
> result of the
> + // absolute expression evaluation and replace it with
> its string
> + // representation.
> + if (AltMacroMode && Token.getString().front() == '%' &&
> + Token.is(AsmToken::Integer))
> + // Emit an integer value to the buffer.
> + OS << Token.getIntVal();
> + // Only Token that was validated as a string and begins
> with '<'
> + // is considered altMacroString!!!
> + else if (AltMacroMode && Token.getString().front() ==
> '<' &&
> + Token.is(AsmToken::String)) {
> + OS << angleBracketString(Token.getStringContents());
> + }
> + // We expect no quotes around the string's contents when
> + // parsing for varargs.
> + else if (Token.isNot(AsmToken::String) ||
> VarargParameter)
> + OS << Token.getString();
> + else
> + OS << Token.getStringContents();
> +
> + Pos += 1 + Argument.size();
> + }
> + }
> + }
> + // Update the scan point.
> + Body = Body.substr(Pos);
> + }
> +
> + return false;
> +}
> +
> +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::Less:
> + case AsmToken::LessEqual:
> + case AsmToken::LessLess:
> + case AsmToken::LessGreater:
> + case AsmToken::Greater:
> + case AsmToken::GreaterEqual:
> + case AsmToken::GreaterGreater:
> + return true;
> + }
> +}
> +
> +namespace {
> +
> +class AsmLexerSkipSpaceRAII {
> +public:
> + AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) :
> Lexer(Lexer) {
> + Lexer.setSkipSpace(SkipSpace);
> + }
> +
> + ~AsmLexerSkipSpaceRAII() {
> + Lexer.setSkipSpace(true);
> + }
> +
> +private:
> + AsmLexer &Lexer;
> +};
> +
> +} // end anonymous namespace
> +
> +bool MasmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool
> Vararg) {
> +
> + if (Vararg) {
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + StringRef Str = parseStringToEndOfStatement();
> + MA.emplace_back(AsmToken::String, Str);
> + }
> + return false;
> + }
> +
> + unsigned ParenLevel = 0;
> +
> + // Darwin doesn't use spaces to delmit arguments.
> + AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);
> +
> + bool SpaceEaten;
> +
> + while (true) {
> + SpaceEaten = false;
> + if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))
> + return TokError("unexpected token in macro instantiation");
> +
> + if (ParenLevel == 0) {
> +
> + if (Lexer.is(AsmToken::Comma))
> + break;
> +
> + if (Lexer.is(AsmToken::Space)) {
> + SpaceEaten = true;
> + Lexer.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 (!IsDarwin) {
> + if (isOperator(Lexer.getKind())) {
> + MA.push_back(getTok());
> + Lexer.Lex();
> +
> + // Whitespace after an operator can be ignored.
> + if (Lexer.is(AsmToken::Space))
> + Lexer.Lex();
> +
> + continue;
> + }
> + }
> + if (SpaceEaten)
> + 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;
> +
> + // Adjust the current parentheses level.
> + if (Lexer.is(AsmToken::LParen))
> + ++ParenLevel;
> + else if (Lexer.is(AsmToken::RParen) && ParenLevel)
> + --ParenLevel;
> +
> + // Append the token to the current argument list.
> + MA.push_back(getTok());
> + Lexer.Lex();
> + }
> +
> + if (ParenLevel != 0)
> + return TokError("unbalanced parentheses in macro argument");
> + return false;
> +}
> +
> +// Parse the macro instantiation arguments.
> +bool MasmParser::parseMacroArguments(const MCAsmMacro *M,
> + MCAsmMacroArguments &A) {
> + const unsigned NParameters = M ? M->Parameters.size() : 0;
> + bool NamedParametersFound = false;
> + SmallVector<SMLoc, 4> FALocs;
> +
> + A.resize(NParameters);
> + FALocs.resize(NParameters);
> +
> + // Parse two kinds of macro invocations:
> + // - macros defined without any parameters accept an arbitrary
> number of them
> + // - macros defined with parameters accept at most that many of
> them
> + bool HasVararg = NParameters ? M->Parameters.back().Vararg :
> false;
> + for (unsigned Parameter = 0; !NParameters || Parameter <
> NParameters;
> + ++Parameter) {
> + SMLoc IDLoc = Lexer.getLoc();
> + MCAsmMacroParameter FA;
> +
> + if (Lexer.is(AsmToken::Identifier) &&
> Lexer.peekTok().is(AsmToken::Equal)) {
> + 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");
> +
> + Lex();
> +
> + NamedParametersFound = true;
> + }
> + bool Vararg = HasVararg && Parameter == (NParameters - 1);
> +
> + if (NamedParametersFound && FA.Name.empty())
> + return Error(IDLoc, "cannot mix positional and keyword
> arguments");
> +
> + SMLoc StrLoc = Lexer.getLoc();
> + SMLoc EndLoc;
> + if (AltMacroMode && Lexer.is(AsmToken::Percent)) {
> + const MCExpr *AbsoluteExp;
> + int64_t Value;
> + /// Eat '%'
> + Lex();
> + if (parseExpression(AbsoluteExp, EndLoc))
> + return false;
> + if (!AbsoluteExp->evaluateAsAbsolute(Value,
> + getStreamer().getAssemble
> rPtr()))
> + return Error(StrLoc, "expected absolute expression");
> + const char *StrChar = StrLoc.getPointer();
> + const char *EndChar = EndLoc.getPointer();
> + AsmToken newToken(AsmToken::Integer,
> + StringRef(StrChar, EndChar - StrChar),
> Value);
> + FA.Value.push_back(newToken);
> + } else if (AltMacroMode && Lexer.is(AsmToken::Less) &&
> + isAngleBracketString(StrLoc, EndLoc)) {
> + const char *StrChar = StrLoc.getPointer();
> + const char *EndChar = EndLoc.getPointer();
> + jumpToLoc(EndLoc, CurBuffer);
> + /// Eat from '<' to '>'
> + Lex();
> + AsmToken newToken(AsmToken::String,
> + StringRef(StrChar, EndChar - StrChar));
> + FA.Value.push_back(newToken);
> + } else if(parseMacroArgument(FA.Value, Vararg))
> + return true;
> +
> + unsigned PI = Parameter;
> + if (!FA.Name.empty()) {
> + unsigned FAI = 0;
> + for (FAI = 0; FAI < NParameters; ++FAI)
> + if (M->Parameters[FAI].Name == FA.Name)
> + break;
> +
> + if (FAI >= NParameters) {
> + assert(M && "expected macro to be defined");
> + return Error(IDLoc, "parameter named '" + FA.Name +
> + "' does not exist for macro '" + M-
> >Name + "'");
> + }
> + PI = FAI;
> + }
> +
> + if (!FA.Value.empty()) {
> + if (A.size() <= PI)
> + A.resize(PI + 1);
> + A[PI] = FA.Value;
> +
> + if (FALocs.size() <= PI)
> + FALocs.resize(PI + 1);
> +
> + FALocs[PI] = Lexer.getLoc();
> + }
> +
> + // 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)) {
> + bool Failure = false;
> + for (unsigned FAI = 0; FAI < NParameters; ++FAI) {
> + if (A[FAI].empty()) {
> + if (M->Parameters[FAI].Required) {
> + Error(FALocs[FAI].isValid() ? FALocs[FAI] :
> Lexer.getLoc(),
> + "missing value for required parameter "
> + "'" + M->Parameters[FAI].Name + "' in macro '" +
> M->Name + "'");
> + Failure = true;
> + }
> +
> + if (!M->Parameters[FAI].Value.empty())
> + A[FAI] = M->Parameters[FAI].Value;
> + }
> + }
> + return Failure;
> + }
> +
> + if (Lexer.is(AsmToken::Comma))
> + Lex();
> + }
> +
> + return TokError("too many positional arguments");
> +}
> +
> +bool MasmParser::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.
> + 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))
> + return true;
> +
> + // Macro instantiation is lexical, unfortunately. We construct a
> new buffer
> + // to hold the macro body with substitutions.
> + SmallString<256> Buf;
> + StringRef Body = M->Body;
> + raw_svector_ostream OS(Buf);
> +
> + if (expandMacro(OS, Body, M->Parameters, A, true,
> getTok().getLoc()))
> + return true;
> +
> + // We include the .endmacro in the buffer as our cue to exit the
> macro
> + // instantiation.
> + OS << ".endmacro\n";
> +
> + std::unique_ptr<MemoryBuffer> Instantiation =
> + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
> +
> + // Create the macro instantiation object and add to the current
> macro
> + // instantiation stack.
> + MacroInstantiation *MI = new MacroInstantiation{
> + NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};
> + ActiveMacros.push_back(MI);
> +
> + ++NumOfMacroInstantiations;
> +
> + // Jump to the macro instantiation and prime the lexer.
> + CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
> SMLoc());
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
> + Lex();
> +
> + return false;
> +}
> +
> +void MasmParser::handleMacroExit() {
> + // Jump to the EndOfStatement we should return to, and consume it.
> + jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()-
> >ExitBuffer);
> + Lex();
> +
> + // Pop the instantiation entry.
> + delete ActiveMacros.back();
> + ActiveMacros.pop_back();
> +}
> +
> +/// parseIdentifier:
> +/// ::= identifier
> +/// ::= string
> +bool MasmParser::parseIdentifier(StringRef &Res) {
> + // The assembler has relaxed rules for accepting identifiers, in
> particular we
> + // allow things like '.globl $foo' and '.def @feat.00', which
> would normally
> + // be separate tokens. At this level, we have already lexed so we
> cannot
> + // (currently) handle this as a context dependent token, instead
> we detect
> + // adjacent tokens and return the combined identifier.
> + if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {
> + SMLoc PrefixLoc = getLexer().getLoc();
> +
> + // Consume the prefix character, and check for a following
> 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 != 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);
> + Lex(); // Parser Lex to maintain invariants.
> + return false;
> + }
> +
> + if (Lexer.isNot(AsmToken::Identifier) &&
> Lexer.isNot(AsmToken::String))
> + return true;
> +
> + Res = getTok().getIdentifier();
> +
> + Lex(); // Consume the identifier token.
> +
> + return false;
> +}
> +
> +/// parseDirectiveEquate:
> +/// ::= name "=" expression
> +/// | name "equ" expression (not redefinable)
> +/// | name "equ" text-list
> +/// | name "textequ" text-list
> +bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef
> Name,
> + DirectiveKind DirKind) {
> + Variable &Var = Variables[Name];
> + if (Var.Name.empty()) {
> + Var.Name = Name;
> + } else if (!Var.Redefinable) {
> + return TokError("invalid variable redefinition");
> + }
> + Var.Redefinable = (DirKind != DK_EQU);
> +
> + if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {
> + // "equ" and "textequ" both allow text expressions.
> + std::string Value;
> + if (!parseTextItem(Value)) {
> + Var.IsText = true;
> + Var.TextValue = Value;
> +
> + // Accept a text-list, not just one text-item
> + auto parseItem = [&]() -> bool {
> + if (parseTextItem(Value))
> + return true;
> + Var.TextValue += Value;
> + return false;
> + };
> + if (parseOptionalToken(AsmToken::Comma) &&
> parseMany(parseItem))
> + return addErrorSuffix(" in '" + Twine(IDVal) + "'
> directive");
> +
> + return false;
> + }
> + }
> + if (DirKind == DK_TEXTEQU)
> + return TokError("expected <text> in '" + Twine(IDVal) + "'
> directive");
> +
> + // Parse as expression assignment
> + const MCExpr *Expr;
> + SMLoc EndLoc, StartLoc = Lexer.getLoc();
> + if (parseExpression(Expr, EndLoc))
> + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
> + if (Expr->evaluateAsAbsolute(Var.NumericValue,
> + getStreamer().getAssemblerPtr()))
> + return false;
> +
> + // Not an absolute expression; define as a text replacement.
> + Var.IsText = true;
> + Var.TextValue = StringRef(StartLoc.getPointer(),
> + EndLoc.getPointer() -
> StartLoc.getPointer()).str();
> + return false;
> +}
> +
> +bool MasmParser::parseEscapedString(std::string &Data) {
> + if (check(getTok().isNot(AsmToken::String), "expected string"))
> + return true;
> +
> + Data = "";
> + StringRef Str = getTok().getStringContents();
> + for (unsigned i = 0, e = Str.size(); i != e; ++i) {
> + if (Str[i] != '\\') {
> + Data += Str[i];
> + continue;
> + }
> +
> + // Recognize escaped characters. Note that this escape semantics
> currently
> + // loosely follows Darwin 'as'.
> + ++i;
> + if (i == e)
> + return TokError("unexpected backslash at end of string");
> +
> + // Recognize hex sequences similarly to GNU 'as'.
> + if (Str[i] == 'x' || Str[i] == 'X') {
> + size_t length = Str.size();
> + if (i + 1 >= length || !isHexDigit(Str[i + 1]))
> + return TokError("invalid hexadecimal escape sequence");
> +
> + // Consume hex characters. GNU 'as' reads all hexadecimal
> characters and
> + // then truncates to the lower 16 bits. Seems reasonable.
> + unsigned Value = 0;
> + while (i + 1 < length && isHexDigit(Str[i + 1]))
> + Value = Value * 16 + hexDigitValue(Str[++i]);
> +
> + Data += (unsigned char)(Value & 0xFF);
> + continue;
> + }
> +
> + // Recognize octal sequences.
> + if ((unsigned)(Str[i] - '0') <= 7) {
> + // Consume up to three octal characters.
> + unsigned Value = Str[i] - '0';
> +
> + if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
> + ++i;
> + Value = Value * 8 + (Str[i] - '0');
> +
> + if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
> + ++i;
> + Value = Value * 8 + (Str[i] - '0');
> + }
> + }
> +
> + if (Value > 255)
> + return TokError("invalid octal escape sequence (out of
> range)");
> +
> + Data += (unsigned char)Value;
> + continue;
> + }
> +
> + // Otherwise recognize individual escapes.
> + switch (Str[i]) {
> + default:
> + // Just reject invalid escape sequences for now.
> + return TokError("invalid escape sequence (unrecognized
> character)");
> +
> + case 'b': Data += '\b'; break;
> + case 'f': Data += '\f'; break;
> + case 'n': Data += '\n'; break;
> + case 'r': Data += '\r'; break;
> + case 't': Data += '\t'; break;
> + case '"': Data += '"'; break;
> + case '\\': Data += '\\'; break;
> + }
> + }
> +
> + Lex();
> + return false;
> +}
> +
> +bool MasmParser::parseAngleBracketString(std::string &Data) {
> + SMLoc EndLoc, StartLoc = getTok().getLoc();
> + if (isAngleBracketString(StartLoc, EndLoc)) {
> + const char *StartChar = StartLoc.getPointer() + 1;
> + const char *EndChar = EndLoc.getPointer() - 1;
> + jumpToLoc(EndLoc, CurBuffer);
> + /// Eat from '<' to '>'
> + Lex();
> +
> + Data = angleBracketString(StringRef(StartChar, EndChar -
> StartChar));
> + return false;
> + }
> + return true;
> +}
> +
> +/// textItem ::= textLiteral | textMacroID | % constExpr
> +bool MasmParser::parseTextItem(std::string &Data) {
> + // TODO(epastor): Support textMacroID and % expansion of
> expressions.
> + return parseAngleBracketString(Data);
> +}
> +
> +/// parseDirectiveAscii:
> +/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
> +bool MasmParser::parseDirectiveAscii(StringRef IDVal, bool
> ZeroTerminated) {
> + auto parseOp = [&]() -> bool {
> + std::string Data;
> + if (checkForValidSection() || parseEscapedString(Data))
> + return true;
> + getStreamer().emitBytes(Data);
> + if (ZeroTerminated)
> + getStreamer().emitBytes(StringRef("\0", 1));
> + return false;
> + };
> +
> + if (parseMany(parseOp))
> + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
> + return false;
> +}
> +
> +/// parseDirectiveValue
> +/// ::= (byte | word | ... ) [ expression (, expression)* ]
> +bool MasmParser::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");
> + int64_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;
> + };
> +
> + if (parseMany(parseOp))
> + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
> + return false;
> +}
> +
> +static bool parseHexOcta(MasmParser &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;
> +}
> +
> +bool MasmParser::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();
> +
> + 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 (errorToBool(
> + Value.convertFromString(IDVal,
> APFloat::rmNearestTiesToEven)
> + .takeError()))
> + return TokError("invalid floating point literal");
> + if (IsNeg)
> + Value.changeSign();
> +
> + // Consume the numeric token.
> + Lex();
> +
> + Res = Value.bitcastToAPInt();
> +
> + return false;
> +}
> +
> +/// parseDirectiveRealValue
> +/// ::= (real4 | real8) [ expression (, expression)* ]
> +bool MasmParser::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;
> + };
> +
> + if (parseMany(parseOp))
> + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
> + return false;
> +}
> +
> +/// parseDirectiveOrg
> +/// ::= .org expression [ , expression ]
> +bool MasmParser::parseDirectiveOrg() {
> + const MCExpr *Offset;
> + SMLoc OffsetLoc = Lexer.getLoc();
> + if (checkForValidSection() || parseExpression(Offset))
> + return true;
> +
> + // Parse optional fill expression.
> + int64_t FillExpr = 0;
> + if (parseOptionalToken(AsmToken::Comma))
> + if (parseAbsoluteExpression(FillExpr))
> + return addErrorSuffix(" in '.org' directive");
> + if (parseToken(AsmToken::EndOfStatement))
> + return addErrorSuffix(" in '.org' directive");
> +
> + getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc);
> + return false;
> +}
> +
> +/// parseDirectiveAlign
> +/// ::= align expression
> +bool MasmParser::parseDirectiveAlign() {
> + SMLoc AlignmentLoc = getLexer().getLoc();
> + int64_t Alignment;
> +
> + if (checkForValidSection())
> + return addErrorSuffix(" in align directive");
> + // Ignore empty 'align' directives
> + if (getTok().is(AsmToken::EndOfStatement)) {
> + Warning(AlignmentLoc, "align directive with no operand is
> ignored");
> + return parseToken(AsmToken::EndOfStatement);
> + }
> + if (parseAbsoluteExpression(Alignment) ||
> + parseToken(AsmToken::EndOfStatement))
> + return addErrorSuffix(" in align directive");
> +
> + // Always emit an alignment here even if we thrown an error.
> + bool ReturnVal = false;
> +
> + // Reject alignments that aren't either a power of two or zero,
> + // for gas compatibility. Alignment of zero is silently rounded
> + // up to one.
> + if (Alignment == 0)
> + Alignment = 1;
> + if (!isPowerOf2_64(Alignment))
> + ReturnVal |= Error(AlignmentLoc, "alignment must be a power of
> 2");
> +
> + // Check whether we should use optimal code alignment for this
> align
> + // directive.
> + const MCSection *Section = getStreamer().getCurrentSectionOnly();
> + assert(Section && "must have section to emit alignment");
> + if (Section->UseCodeAlign()) {
> + getStreamer().emitCodeAlignment(Alignment,
> /*MaxBytesToEmit=*/0);
> + } else {
> + // FIXME: Target specific behavior about how the "extra" bytes
> are filled.
> + getStreamer().emitValueToAlignment(Alignment, /*Value=*/0,
> /*ValueSize=*/1,
> + /*MaxBytesToEmit=*/0);
> + }
> +
> + return ReturnVal;
> +}
> +
> +/// parseDirectiveFile
> +/// ::= .file filename
> +/// ::= .file number [directory] filename [md5 checksum] [source
> source-text]
> +bool MasmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
> + // FIXME: I'm not sure what this is.
> + int64_t FileNumber = -1;
> + if (getLexer().is(AsmToken::Integer)) {
> + FileNumber = getTok().getIntVal();
> + Lex();
> +
> + if (FileNumber < 0)
> + return TokError("negative file number");
> + }
> +
> + std::string Path;
> +
> + // Usually the directory and filename together, otherwise just the
> directory.
> + // Allow the strings to have escaped octal character sequence.
> + if (check(getTok().isNot(AsmToken::String),
> + "unexpected token in '.file' directive") ||
> + parseEscapedString(Path))
> + return true;
> +
> + StringRef Directory;
> + StringRef Filename;
> + std::string FilenameData;
> + if (getLexer().is(AsmToken::String)) {
> + if (check(FileNumber == -1,
> + "explicit path specified, but no file number") ||
> + parseEscapedString(FilenameData))
> + return true;
> + Filename = FilenameData;
> + Directory = Path;
> + } else {
> + Filename = Path;
> + }
> +
> + 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");
> + }
> + }
> +
> + if (FileNumber == -1) {
> + // Ignore the directive if there is no number and the target
> doesn't support
> + // numberless .file directives. This allows some portability of
> assembler
> + // between
> diff erent object file formats.
> + if (getContext().getAsmInfo()->hasSingleParameterDotFile())
> + getStreamer().emitFileDirective(Filename);
> + } else {
> + // 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.
> + // Throw away any implicit file table for the assembler source.
> + if (Ctx.getGenDwarfForAssembly()) {
> + Ctx.getMCDwarfLineTable(0).resetFileTable();
> + Ctx.setGenDwarfForAssembly(false);
> + }
> +
> + Optional<MD5::MD5Result> CKMem;
> + if (HasMD5) {
> + MD5::MD5Result Sum;
> + for (unsigned i = 0; i != 8; ++i) {
> + Sum.Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8));
> + Sum.Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8));
> + }
> + CKMem = Sum;
> + }
> + 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()));
> + }
> + // 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;
> +}
> +
> +/// parseDirectiveLine
> +/// ::= .line [number]
> +bool MasmParser::parseDirectiveLine() {
> + int64_t LineNumber;
> + if (getLexer().is(AsmToken::Integer)) {
> + if (parseIntToken(LineNumber, "unexpected token in '.line'
> directive"))
> + return true;
> + (void)LineNumber;
> + // FIXME: Do something with the .line.
> + }
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.line' directive"))
> + return true;
> +
> + return false;
> +}
> +
> +/// parseDirectiveLoc
> +/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block]
> [prologue_end]
> +/// [epilogue_begin] [is_stmt VALUE]
> [isa VALUE]
> +/// The first number is a file number, must have been previously
> assigned with
> +/// a .file directive, the second number is the line number and
> optionally the
> +/// third number is a column position (zero if not specified). The
> remaining
> +/// optional items are .loc sub-directives.
> +bool MasmParser::parseDirectiveLoc() {
> + int64_t FileNumber = 0, LineNumber = 0;
> + SMLoc Loc = getTok().getLoc();
> + if (parseIntToken(FileNumber, "unexpected token in '.loc'
> directive") ||
> + 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"))
> + return true;
> +
> + // optional
> + if (getLexer().is(AsmToken::Integer)) {
> + LineNumber = getTok().getIntVal();
> + if (LineNumber < 0)
> + return TokError("line number less than zero in '.loc'
> directive");
> + Lex();
> + }
> +
> + int64_t ColumnPos = 0;
> + if (getLexer().is(AsmToken::Integer)) {
> + ColumnPos = getTok().getIntVal();
> + if (ColumnPos < 0)
> + return TokError("column position less than zero in '.loc'
> directive");
> + Lex();
> + }
> +
> + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT
> : 0;
> + unsigned Isa = 0;
> + int64_t Discriminator = 0;
> +
> + 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, "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;
> + } else {
> + return Error(Loc, "unknown sub-directive in '.loc'
> directive");
> + }
> + return false;
> + };
> +
> + if (parseMany(parseLocOp, false /*hasComma*/))
> + return true;
> +
> + getStreamer().emitDwarfLocDirective(FileNumber, LineNumber,
> ColumnPos, Flags,
> + Isa, Discriminator,
> StringRef());
> +
> + return false;
> +}
> +
> +/// parseDirectiveStabs
> +/// ::= .stabs string, number, number, number
> +bool MasmParser::parseDirectiveStabs() {
> + return TokError("unsupported directive '.stabs'");
> +}
> +
> +/// parseDirectiveCVFile
> +/// ::= .cv_file number filename [checksum] [checksumkind]
> +bool MasmParser::parseDirectiveCVFile() {
> + SMLoc FileNumberLoc = getTok().getLoc();
> + int64_t FileNumber;
> + std::string Filename;
> + std::string Checksum;
> + int64_t ChecksumKind = 0;
> +
> + if (parseIntToken(FileNumber,
> + "expected file number in '.cv_file' directive")
> ||
> + check(FileNumber < 1, FileNumberLoc, "file number less than
> one") ||
> + check(getTok().isNot(AsmToken::String),
> + "unexpected token in '.cv_file' directive") ||
> + parseEscapedString(Filename))
> + return true;
> + if (!parseOptionalToken(AsmToken::EndOfStatement)) {
> + if (check(getTok().isNot(AsmToken::String),
> + "unexpected token in '.cv_file' directive") ||
> + parseEscapedString(Checksum) ||
> + parseIntToken(ChecksumKind,
> + "expected checksum kind in '.cv_file'
> directive") ||
> + parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.cv_file' directive"))
> + return true;
> + }
> +
> + Checksum = fromHex(Checksum);
> + void *CKMem = Ctx.allocate(Checksum.size(), 1);
> + memcpy(CKMem, Checksum.data(), Checksum.size());
> + ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t
> *>(CKMem),
> + Checksum.size());
> +
> + if (!getStreamer().EmitCVFileDirective(FileNumber, Filename,
> ChecksumAsBytes,
> + static_cast<uint8_t>(Checks
> umKind)))
> + return Error(FileNumberLoc, "file number already allocated");
> +
> + return false;
> +}
> +
> +bool MasmParser::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 MasmParser::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 MasmParser::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 MasmParser::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;
> +}
> +
> +/// parseDirectiveCVLoc
> +/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos]
> [prologue_end]
> +/// [is_stmt VALUE]
> +/// The first number is a file number, must have been previously
> assigned with
> +/// a .file directive, the second number is the line number and
> optionally the
> +/// third number is a column position (zero if not specified). The
> remaining
> +/// optional items are .loc sub-directives.
> +bool MasmParser::parseDirectiveCVLoc() {
> + SMLoc DirectiveLoc = getTok().getLoc();
> + int64_t FunctionId, FileNumber;
> + if (parseCVFunctionId(FunctionId, ".cv_loc") ||
> + parseCVFileId(FileNumber, ".cv_loc"))
> + return true;
> +
> + int64_t LineNumber = 0;
> + if (getLexer().is(AsmToken::Integer)) {
> + LineNumber = getTok().getIntVal();
> + if (LineNumber < 0)
> + return TokError("line number less than zero in '.cv_loc'
> directive");
> + Lex();
> + }
> +
> + int64_t ColumnPos = 0;
> + if (getLexer().is(AsmToken::Integer)) {
> + ColumnPos = getTok().getIntVal();
> + if (ColumnPos < 0)
> + return TokError("column position less than zero in '.cv_loc'
> directive");
> + Lex();
> + }
> +
> + bool PrologueEnd = false;
> + uint64_t IsStmt = 0;
> +
> + 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") {
> + Loc = getTok().getLoc();
> + const MCExpr *Value;
> + if (parseExpression(Value))
> + return true;
> + // The expression must be the constant 0 or 1.
> + IsStmt = ~0ULL;
> + if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))
> + IsStmt = MCE->getValue();
> +
> + if (IsStmt > 1)
> + return Error(Loc, "is_stmt value not 0 or 1");
> + } else {
> + return Error(Loc, "unknown sub-directive in '.cv_loc'
> directive");
> + }
> + return false;
> + };
> +
> + if (parseMany(parseOp, false /*hasComma*/))
> + return true;
> +
> + getStreamer().EmitCVLocDirective(FunctionId, FileNumber,
> LineNumber,
> + ColumnPos, PrologueEnd, IsStmt,
> StringRef(),
> + DirectiveLoc);
> + return false;
> +}
> +
> +/// parseDirectiveCVLinetable
> +/// ::= .cv_linetable FunctionId, FnStart, FnEnd
> +bool MasmParser::parseDirectiveCVLinetable() {
> + int64_t FunctionId;
> + StringRef FnStartName, FnEndName;
> + SMLoc Loc = getTok().getLoc();
> + if (parseCVFunctionId(FunctionId, ".cv_linetable") ||
> + parseToken(AsmToken::Comma,
> + "unexpected token in '.cv_linetable' directive") ||
> + parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
> + "expected identifier in
> directive") ||
> + parseToken(AsmToken::Comma,
> + "unexpected token in '.cv_linetable' directive") ||
> + parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
> + "expected identifier in
> directive"))
> + return true;
> +
> + MCSymbol *FnStartSym =
> getContext().getOrCreateSymbol(FnStartName);
> + MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
> +
> + getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym,
> FnEndSym);
> + return false;
> +}
> +
> +/// parseDirectiveCVInlineLinetable
> +/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum
> FnStart FnEnd
> +bool MasmParser::parseDirectiveCVInlineLinetable() {
> + int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;
> + StringRef FnStartName, FnEndName;
> + SMLoc Loc = getTok().getLoc();
> + 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") ||
> + 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") ||
> + parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
> + "expected identifier in
> directive") ||
> + parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
> + "expected identifier in
> directive"))
> + return true;
> +
> + if (parseToken(AsmToken::EndOfStatement, "Expected End of
> Statement"))
> + return true;
> +
> + MCSymbol *FnStartSym =
> getContext().getOrCreateSymbol(FnStartName);
> + MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
> + getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId,
> SourceFileId,
> + SourceLineNum,
> FnStartSym,
> + FnEndSym);
> + return false;
> +}
> +
> +void MasmParser::initializeCVDefRangeTypeMap() {
> + CVDefRangeTypeMap["reg"] = CVDR_DEFRANGE_REGISTER;
> + CVDefRangeTypeMap["frame_ptr_rel"] =
> CVDR_DEFRANGE_FRAMEPOINTER_REL;
> + CVDefRangeTypeMap["subfield_reg"] =
> CVDR_DEFRANGE_SUBFIELD_REGISTER;
> + CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;
> +}
> +
> +/// parseDirectiveCVDefRange
> +/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*
> +bool MasmParser::parseDirectiveCVDefRange() {
> + SMLoc Loc;
> + std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
> + while (getLexer().is(AsmToken::Identifier)) {
> + Loc = getLexer().getLoc();
> + StringRef GapStartName;
> + if (parseIdentifier(GapStartName))
> + return Error(Loc, "expected identifier in directive");
> + MCSymbol *GapStartSym =
> getContext().getOrCreateSymbol(GapStartName);
> +
> + Loc = getLexer().getLoc();
> + StringRef GapEndName;
> + if (parseIdentifier(GapEndName))
> + return Error(Loc, "expected identifier in directive");
> + MCSymbol *GapEndSym =
> getContext().getOrCreateSymbol(GapEndName);
> +
> + Ranges.push_back({GapStartSym, GapEndSym});
> + }
> +
> + StringRef CVDefRangeTypeStr;
> + if (parseToken(
> + AsmToken::Comma,
> + "expected comma before def_range type in .cv_def_range
> directive") ||
> + parseIdentifier(CVDefRangeTypeStr))
> + return Error(Loc, "expected def_range type in directive");
> +
> + StringMap<CVDefRangeType>::const_iterator CVTypeIt =
> + CVDefRangeTypeMap.find(CVDefRangeTypeStr);
> + CVDefRangeType CVDRType = (CVTypeIt == CVDefRangeTypeMap.end())
> + ? CVDR_DEFRANGE
> + : CVTypeIt->getValue();
> + switch (CVDRType) {
> + case CVDR_DEFRANGE_REGISTER: {
> + int64_t DRRegister;
> + if (parseToken(AsmToken::Comma, "expected comma before register
> number in "
> + ".cv_def_range directive") ||
> + parseAbsoluteExpression(DRRegister))
> + return Error(Loc, "expected register number");
> +
> + codeview::DefRangeRegisterHeader DRHdr;
> + DRHdr.Register = DRRegister;
> + DRHdr.MayHaveNoName = 0;
> + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
> + break;
> + }
> + case CVDR_DEFRANGE_FRAMEPOINTER_REL: {
> + int64_t DROffset;
> + if (parseToken(AsmToken::Comma,
> + "expected comma before offset in .cv_def_range
> directive") ||
> + parseAbsoluteExpression(DROffset))
> + return Error(Loc, "expected offset value");
> +
> + codeview::DefRangeFramePointerRelHeader DRHdr;
> + DRHdr.Offset = DROffset;
> + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
> + break;
> + }
> + case CVDR_DEFRANGE_SUBFIELD_REGISTER: {
> + int64_t DRRegister;
> + int64_t DROffsetInParent;
> + if (parseToken(AsmToken::Comma, "expected comma before register
> number in "
> + ".cv_def_range directive") ||
> + parseAbsoluteExpression(DRRegister))
> + return Error(Loc, "expected register number");
> + if (parseToken(AsmToken::Comma,
> + "expected comma before offset in .cv_def_range
> directive") ||
> + parseAbsoluteExpression(DROffsetInParent))
> + return Error(Loc, "expected offset value");
> +
> + codeview::DefRangeSubfieldRegisterHeader DRHdr;
> + DRHdr.Register = DRRegister;
> + DRHdr.MayHaveNoName = 0;
> + DRHdr.OffsetInParent = DROffsetInParent;
> + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
> + break;
> + }
> + case CVDR_DEFRANGE_REGISTER_REL: {
> + int64_t DRRegister;
> + int64_t DRFlags;
> + int64_t DRBasePointerOffset;
> + if (parseToken(AsmToken::Comma, "expected comma before register
> number in "
> + ".cv_def_range directive") ||
> + parseAbsoluteExpression(DRRegister))
> + return Error(Loc, "expected register value");
> + if (parseToken(
> + AsmToken::Comma,
> + "expected comma before flag value in .cv_def_range
> directive") ||
> + parseAbsoluteExpression(DRFlags))
> + return Error(Loc, "expected flag value");
> + if (parseToken(AsmToken::Comma, "expected comma before base
> pointer offset "
> + "in .cv_def_range directive") ||
> + parseAbsoluteExpression(DRBasePointerOffset))
> + return Error(Loc, "expected base pointer offset value");
> +
> + codeview::DefRangeRegisterRelHeader DRHdr;
> + DRHdr.Register = DRRegister;
> + DRHdr.Flags = DRFlags;
> + DRHdr.BasePointerOffset = DRBasePointerOffset;
> + getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
> + break;
> + }
> + default:
> + return Error(Loc, "unexpected def_range type in .cv_def_range
> directive");
> + }
> + return true;
> +}
> +
> +/// parseDirectiveCVString
> +/// ::= .cv_stringtable "string"
> +bool MasmParser::parseDirectiveCVString() {
> + std::string Data;
> + if (checkForValidSection() || parseEscapedString(Data))
> + return addErrorSuffix(" in '.cv_string' directive");
> +
> + // Put the string in the table and emit the offset.
> + std::pair<StringRef, unsigned> Insertion =
> + getCVContext().addToStringTable(Data);
> + getStreamer().emitIntValue(Insertion.second, 4);
> + return false;
> +}
> +
> +/// parseDirectiveCVStringTable
> +/// ::= .cv_stringtable
> +bool MasmParser::parseDirectiveCVStringTable() {
> + getStreamer().EmitCVStringTableDirective();
> + return false;
> +}
> +
> +/// parseDirectiveCVFileChecksums
> +/// ::= .cv_filechecksums
> +bool MasmParser::parseDirectiveCVFileChecksums() {
> + getStreamer().EmitCVFileChecksumsDirective();
> + return false;
> +}
> +
> +/// parseDirectiveCVFileChecksumOffset
> +/// ::= .cv_filechecksumoffset fileno
> +bool MasmParser::parseDirectiveCVFileChecksumOffset() {
> + int64_t FileNo;
> + if (parseIntToken(FileNo, "expected identifier in directive"))
> + return true;
> + if (parseToken(AsmToken::EndOfStatement, "Expected End of
> Statement"))
> + return true;
> + getStreamer().EmitCVFileChecksumOffsetDirective(FileNo);
> + return false;
> +}
> +
> +/// parseDirectiveCVFPOData
> +/// ::= .cv_fpo_data procsym
> +bool MasmParser::parseDirectiveCVFPOData() {
> + SMLoc DirLoc = getLexer().getLoc();
> + StringRef ProcName;
> + if (parseIdentifier(ProcName))
> + return TokError("expected symbol name");
> + if (parseEOL("unexpected tokens"))
> + return addErrorSuffix(" in '.cv_fpo_data' directive");
> + MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
> + getStreamer().EmitCVFPOData(ProcSym, DirLoc);
> + return false;
> +}
> +
> +/// parseDirectiveCFISections
> +/// ::= .cfi_sections section [, section]
> +bool MasmParser::parseDirectiveCFISections() {
> + StringRef Name;
> + bool EH = false;
> + bool Debug = false;
> +
> + if (parseIdentifier(Name))
> + return TokError("Expected an identifier");
> +
> + if (Name == ".eh_frame")
> + EH = true;
> + else if (Name == ".debug_frame")
> + Debug = true;
> +
> + if (getLexer().is(AsmToken::Comma)) {
> + Lex();
> +
> + if (parseIdentifier(Name))
> + return TokError("Expected an identifier");
> +
> + if (Name == ".eh_frame")
> + EH = true;
> + else if (Name == ".debug_frame")
> + Debug = true;
> + }
> +
> + getStreamer().emitCFISections(EH, Debug);
> + return false;
> +}
> +
> +/// parseDirectiveCFIStartProc
> +/// ::= .cfi_startproc [simple]
> +bool MasmParser::parseDirectiveCFIStartProc() {
> + StringRef Simple;
> + if (!parseOptionalToken(AsmToken::EndOfStatement)) {
> + if (check(parseIdentifier(Simple) || Simple != "simple",
> + "unexpected token") ||
> + parseToken(AsmToken::EndOfStatement))
> + return addErrorSuffix(" in '.cfi_startproc' directive");
> + }
> +
> + // TODO(kristina): Deal with a corner case of incorrect diagnostic
> context
> + // being produced if this directive is emitted as part of
> preprocessor macro
> + // expansion which can *ONLY* happen if Clang's cc1as is the API
> consumer.
> + // Tools like llvm-mc on the other hand are not affected by it,
> and report
> + // correct context information.
> + getStreamer().emitCFIStartProc(!Simple.empty(), Lexer.getLoc());
> + return false;
> +}
> +
> +/// parseDirectiveCFIEndProc
> +/// ::= .cfi_endproc
> +bool MasmParser::parseDirectiveCFIEndProc() {
> + getStreamer().emitCFIEndProc();
> + return false;
> +}
> +
> +/// parse register name or number.
> +bool MasmParser::parseRegisterOrRegisterNumber(int64_t &Register,
> + SMLoc DirectiveLoc) {
> + unsigned RegNo;
> +
> + if (getLexer().isNot(AsmToken::Integer)) {
> + if (getTargetParser().ParseRegister(RegNo, DirectiveLoc,
> DirectiveLoc))
> + return true;
> + Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo,
> true);
> + } else
> + return parseAbsoluteExpression(Register);
> +
> + return false;
> +}
> +
> +/// parseDirectiveCFIDefCfa
> +/// ::= .cfi_def_cfa register, offset
> +bool MasmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) {
> + int64_t Register = 0, Offset = 0;
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
> + parseToken(AsmToken::Comma, "unexpected token in directive")
> ||
> + parseAbsoluteExpression(Offset))
> + return true;
> +
> + getStreamer().emitCFIDefCfa(Register, Offset);
> + return false;
> +}
> +
> +/// parseDirectiveCFIDefCfaOffset
> +/// ::= .cfi_def_cfa_offset offset
> +bool MasmParser::parseDirectiveCFIDefCfaOffset() {
> + int64_t Offset = 0;
> + if (parseAbsoluteExpression(Offset))
> + return true;
> +
> + getStreamer().emitCFIDefCfaOffset(Offset);
> + return false;
> +}
> +
> +/// parseDirectiveCFIRegister
> +/// ::= .cfi_register register, register
> +bool MasmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) {
> + int64_t Register1 = 0, Register2 = 0;
> + if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) ||
> + parseToken(AsmToken::Comma, "unexpected token in directive")
> ||
> + parseRegisterOrRegisterNumber(Register2, DirectiveLoc))
> + return true;
> +
> + getStreamer().emitCFIRegister(Register1, Register2);
> + return false;
> +}
> +
> +/// parseDirectiveCFIWindowSave
> +/// ::= .cfi_window_save
> +bool MasmParser::parseDirectiveCFIWindowSave() {
> + getStreamer().emitCFIWindowSave();
> + return false;
> +}
> +
> +/// parseDirectiveCFIAdjustCfaOffset
> +/// ::= .cfi_adjust_cfa_offset adjustment
> +bool MasmParser::parseDirectiveCFIAdjustCfaOffset() {
> + int64_t Adjustment = 0;
> + if (parseAbsoluteExpression(Adjustment))
> + return true;
> +
> + getStreamer().emitCFIAdjustCfaOffset(Adjustment);
> + return false;
> +}
> +
> +/// parseDirectiveCFIDefCfaRegister
> +/// ::= .cfi_def_cfa_register register
> +bool MasmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc)
> {
> + int64_t Register = 0;
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
> + return true;
> +
> + getStreamer().emitCFIDefCfaRegister(Register);
> + return false;
> +}
> +
> +/// parseDirectiveCFIOffset
> +/// ::= .cfi_offset register, offset
> +bool MasmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {
> + int64_t Register = 0;
> + int64_t Offset = 0;
> +
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
> + parseToken(AsmToken::Comma, "unexpected token in directive")
> ||
> + parseAbsoluteExpression(Offset))
> + return true;
> +
> + getStreamer().emitCFIOffset(Register, Offset);
> + return false;
> +}
> +
> +/// parseDirectiveCFIRelOffset
> +/// ::= .cfi_rel_offset register, offset
> +bool MasmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) {
> + int64_t Register = 0, Offset = 0;
> +
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
> + parseToken(AsmToken::Comma, "unexpected token in directive")
> ||
> + parseAbsoluteExpression(Offset))
> + return true;
> +
> + getStreamer().emitCFIRelOffset(Register, Offset);
> + return false;
> +}
> +
> +static bool isValidEncoding(int64_t Encoding) {
> + if (Encoding & ~0xff)
> + return false;
> +
> + if (Encoding == dwarf::DW_EH_PE_omit)
> + return true;
> +
> + const unsigned Format = Encoding & 0xf;
> + if (Format != dwarf::DW_EH_PE_absptr && Format !=
> dwarf::DW_EH_PE_udata2 &&
> + Format != dwarf::DW_EH_PE_udata4 && Format !=
> dwarf::DW_EH_PE_udata8 &&
> + Format != dwarf::DW_EH_PE_sdata2 && Format !=
> dwarf::DW_EH_PE_sdata4 &&
> + Format != dwarf::DW_EH_PE_sdata8 && Format !=
> dwarf::DW_EH_PE_signed)
> + return false;
> +
> + const unsigned Application = Encoding & 0x70;
> + if (Application != dwarf::DW_EH_PE_absptr &&
> + Application != dwarf::DW_EH_PE_pcrel)
> + return false;
> +
> + return true;
> +}
> +
> +/// parseDirectiveCFIPersonalityOrLsda
> +/// IsPersonality true for cfi_personality, false for cfi_lsda
> +/// ::= .cfi_personality encoding, [symbol_name]
> +/// ::= .cfi_lsda encoding, [symbol_name]
> +bool MasmParser::parseDirectiveCFIPersonalityOrLsda(bool
> IsPersonality) {
> + int64_t Encoding = 0;
> + if (parseAbsoluteExpression(Encoding))
> + return true;
> + if (Encoding == dwarf::DW_EH_PE_omit)
> + return false;
> +
> + StringRef Name;
> + if (check(!isValidEncoding(Encoding), "unsupported encoding.") ||
> + parseToken(AsmToken::Comma, "unexpected token in directive")
> ||
> + check(parseIdentifier(Name), "expected identifier in
> directive"))
> + return true;
> +
> + MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
> +
> + if (IsPersonality)
> + getStreamer().emitCFIPersonality(Sym, Encoding);
> + else
> + getStreamer().emitCFILsda(Sym, Encoding);
> + return false;
> +}
> +
> +/// parseDirectiveCFIRememberState
> +/// ::= .cfi_remember_state
> +bool MasmParser::parseDirectiveCFIRememberState() {
> + getStreamer().emitCFIRememberState();
> + return false;
> +}
> +
> +/// parseDirectiveCFIRestoreState
> +/// ::= .cfi_remember_state
> +bool MasmParser::parseDirectiveCFIRestoreState() {
> + getStreamer().emitCFIRestoreState();
> + return false;
> +}
> +
> +/// parseDirectiveCFISameValue
> +/// ::= .cfi_same_value register
> +bool MasmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) {
> + int64_t Register = 0;
> +
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
> + return true;
> +
> + getStreamer().emitCFISameValue(Register);
> + return false;
> +}
> +
> +/// parseDirectiveCFIRestore
> +/// ::= .cfi_restore register
> +bool MasmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) {
> + int64_t Register = 0;
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
> + return true;
> +
> + getStreamer().emitCFIRestore(Register);
> + return false;
> +}
> +
> +/// parseDirectiveCFIEscape
> +/// ::= .cfi_escape expression[,...]
> +bool MasmParser::parseDirectiveCFIEscape() {
> + std::string Values;
> + int64_t CurrValue;
> + if (parseAbsoluteExpression(CurrValue))
> + return true;
> +
> + Values.push_back((uint8_t)CurrValue);
> +
> + while (getLexer().is(AsmToken::Comma)) {
> + Lex();
> +
> + if (parseAbsoluteExpression(CurrValue))
> + return true;
> +
> + Values.push_back((uint8_t)CurrValue);
> + }
> +
> + getStreamer().emitCFIEscape(Values);
> + return false;
> +}
> +
> +/// parseDirectiveCFIReturnColumn
> +/// ::= .cfi_return_column register
> +bool MasmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) {
> + int64_t Register = 0;
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
> + return true;
> + getStreamer().emitCFIReturnColumn(Register);
> + return false;
> +}
> +
> +/// parseDirectiveCFISignalFrame
> +/// ::= .cfi_signal_frame
> +bool MasmParser::parseDirectiveCFISignalFrame() {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.cfi_signal_frame'"))
> + return true;
> +
> + getStreamer().emitCFISignalFrame();
> + return false;
> +}
> +
> +/// parseDirectiveCFIUndefined
> +/// ::= .cfi_undefined register
> +bool MasmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
> + int64_t Register = 0;
> +
> + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
> + return true;
> +
> + getStreamer().emitCFIUndefined(Register);
> + return false;
> +}
> +
> +/// parseDirectiveAltmacro
> +/// ::= .altmacro
> +/// ::= .noaltmacro
> +bool MasmParser::parseDirectiveAltmacro(StringRef Directive) {
> + if (getLexer().isNot(AsmToken::EndOfStatement))
> + return TokError("unexpected token in '" + Directive + "'
> directive");
> + AltMacroMode = (Directive == ".altmacro");
> + return false;
> +}
> +
> +/// parseDirectiveMacrosOnOff
> +/// ::= .macros_on
> +/// ::= .macros_off
> +bool MasmParser::parseDirectiveMacrosOnOff(StringRef Directive) {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '" + Directive + "'
> directive"))
> + return true;
> +
> + setMacrosEnabled(Directive == ".macros_on");
> + return false;
> +}
> +
> +/// parseDirectiveMacro
> +/// ::= .macro name[,] [parameters]
> +bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
> + StringRef Name;
> + if (parseIdentifier(Name))
> + return TokError("expected identifier in '.macro' directive");
> +
> + if (getLexer().is(AsmToken::Comma))
> + Lex();
> +
> + MCAsmMacroParameters Parameters;
> + while (getLexer().isNot(AsmToken::EndOfStatement)) {
> +
> + if (!Parameters.empty() && Parameters.back().Vararg)
> + return Error(Lexer.getLoc(),
> + "Vararg parameter '" + Parameters.back().Name +
> + "' should be last one in the list of
> parameters.");
> +
> + MCAsmMacroParameter Parameter;
> + if (parseIdentifier(Parameter.Name))
> + return TokError("expected identifier in '.macro' directive");
> +
> + // Emit an error if two (or more) named parameters share the
> same name
> + for (const MCAsmMacroParameter& CurrParam : Parameters)
> + if (CurrParam.Name.equals(Parameter.Name))
> + return TokError("macro '" + Name + "' has multiple
> parameters"
> + " named '" + Parameter.Name + "'");
> +
> + if (Lexer.is(AsmToken::Colon)) {
> + Lex(); // consume ':'
> +
> + SMLoc QualLoc;
> + StringRef Qualifier;
> +
> + QualLoc = Lexer.getLoc();
> + if (parseIdentifier(Qualifier))
> + return Error(QualLoc, "missing parameter qualifier for "
> + "'" + Parameter.Name + "' in macro '" + Name +
> "'");
> +
> + if (Qualifier == "req")
> + Parameter.Required = true;
> + else if (Qualifier == "vararg")
> + Parameter.Vararg = true;
> + else
> + return Error(QualLoc, Qualifier + " is not a valid parameter
> qualifier "
> + "for '" + Parameter.Name + "' in macro '" +
> Name + "'");
> + }
> +
> + if (getLexer().is(AsmToken::Equal)) {
> + Lex();
> +
> + SMLoc ParamLoc;
> +
> + ParamLoc = Lexer.getLoc();
> + if (parseMacroArgument(Parameter.Value, /*Vararg=*/false ))
> + return true;
> +
> + if (Parameter.Required)
> + Warning(ParamLoc, "pointless default value for required
> parameter "
> + "'" + Parameter.Name + "' in macro '" + Name + "'");
> + }
> +
> + Parameters.push_back(std::move(Parameter));
> +
> + if (getLexer().is(AsmToken::Comma))
> + Lex();
> + }
> +
> + // Eat just the end of statement.
> + Lexer.Lex();
> +
> + // Consuming deferred text, so use Lexer.Lex to ignore Lexing
> Errors
> + AsmToken EndToken, StartToken = getTok();
> + unsigned MacroDepth = 0;
> + // Lex the macro definition.
> + while (true) {
> + // Ignore Lexing errors in macros.
> + while (Lexer.is(AsmToken::Error)) {
> + Lexer.Lex();
> + }
> +
> + // Check whether we have reached the end of the file.
> + if (getLexer().is(AsmToken::Eof))
> + return Error(DirectiveLoc, "no matching '.endmacro' in
> definition");
> +
> + // Otherwise, check whether we have reach the .endmacro.
> + if (getLexer().is(AsmToken::Identifier)) {
> + if (getTok().getIdentifier() == ".endm" ||
> + getTok().getIdentifier() == ".endmacro") {
> + if (MacroDepth == 0) { // Outermost macro.
> + EndToken = getTok();
> + Lexer.Lex();
> + if (getLexer().isNot(AsmToken::EndOfStatement))
> + return TokError("unexpected token in '" +
> EndToken.getIdentifier() +
> + "' directive");
> + break;
> + } else {
> + // Otherwise we just found the end of an inner macro.
> + --MacroDepth;
> + }
> + } else if (getTok().getIdentifier() == ".macro") {
> + // We allow nested macros. Those aren't instantiated until
> the outermost
> + // macro is expanded so just ignore them for now.
> + ++MacroDepth;
> + }
> + }
> +
> + // Otherwise, scan til the end of the statement.
> + eatToEndOfStatement();
> + }
> +
> + if (getContext().lookupMacro(Name)) {
> + return Error(DirectiveLoc, "macro '" + Name + "' is already
> defined");
> + }
> +
> + const char *BodyStart = StartToken.getLoc().getPointer();
> + const char *BodyEnd = EndToken.getLoc().getPointer();
> + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
> + checkForBadMacro(DirectiveLoc, Name, Body, 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;
> +}
> +
> +/// checkForBadMacro
> +///
> +/// With the support added for named parameters there may be code
> out there that
> +/// is transitioning from positional parameters. In versions of gas
> that did
> +/// not support named parameters they would be ignored on the macro
> definition.
> +/// But to support both styles of parameters this is not possible so
> if a macro
> +/// definition has named parameters but does not use them and has
> what appears
> +/// to be positional parameters, strings like $1, $2, ... and $n,
> then issue a
> +/// warning that the positional parameter found in body which have
> no effect.
> +/// Hoping the developer will either remove the named parameters
> from the macro
> +/// definition so the positional parameters get used if that was
> what was
> +/// intended or change the macro to use the named parameters. It is
> possible
> +/// this warning will trigger when the none of the named parameters
> are used
> +/// and the strings like $1 are infact to simply to be passed trough
> unchanged.
> +void MasmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef
> Name,
> + StringRef Body,
> + ArrayRef<MCAsmMacroParameter>
> Parameters) {
> + // If this macro is not defined with named parameters the warning
> we are
> + // checking for here doesn't apply.
> + unsigned NParameters = Parameters.size();
> + if (NParameters == 0)
> + return;
> +
> + bool NamedParametersFound = false;
> + bool PositionalParametersFound = false;
> +
> + // Look at the body of the macro for use of both the named
> parameters and what
> + // are likely to be positional parameters. This is what
> expandMacro() is
> + // doing when it finds the parameters in the body.
> + while (!Body.empty()) {
> + // Scan for the next possible parameter.
> + std::size_t End = Body.size(), Pos = 0;
> + for (; Pos != End; ++Pos) {
> + // Check for a substitution or escape.
> + // This macro is defined with parameters, look for \foo, \bar,
> etc.
> + if (Body[Pos] == '\\' && Pos + 1 != End)
> + break;
> +
> + // This macro should have parameters, but look for $0, $1,
> ..., $n too.
> + if (Body[Pos] != '$' || Pos + 1 == End)
> + continue;
> + char Next = Body[Pos + 1];
> + if (Next == '$' || Next == 'n' ||
> + isdigit(static_cast<unsigned char>(Next)))
> + break;
> + }
> +
> + // Check if we reached the end.
> + if (Pos == End)
> + break;
> +
> + if (Body[Pos] == '$') {
> + switch (Body[Pos + 1]) {
> + // $$ => $
> + case '$':
> + break;
> +
> + // $n => number of arguments
> + case 'n':
> + PositionalParametersFound = true;
> + break;
> +
> + // $[0-9] => argument
> + default: {
> + PositionalParametersFound = true;
> + break;
> + }
> + }
> + Pos += 2;
> + } else {
> + unsigned I = Pos + 1;
> + 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].Name == Argument)
> + break;
> +
> + if (Index == NParameters) {
> + if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
> + Pos += 3;
> + else {
> + Pos = I;
> + }
> + } else {
> + NamedParametersFound = true;
> + Pos += 1 + Argument.size();
> + }
> + }
> + // Update the scan point.
> + Body = Body.substr(Pos);
> + }
> +
> + if (!NamedParametersFound && PositionalParametersFound)
> + Warning(DirectiveLoc, "macro defined with named parameters which
> are not "
> + "used in macro body, possible positional
> parameter "
> + "found in body which will have no
> effect");
> +}
> +
> +/// parseDirectiveExitMacro
> +/// ::= .exitm
> +bool MasmParser::parseDirectiveExitMacro(StringRef Directive) {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '" + Directive + "'
> directive"))
> + return true;
> +
> + if (!isInsideMacroInstantiation())
> + return TokError("unexpected '" + Directive + "' in file, "
> + "no current macro
> definition");
> +
> + // Exit all conditionals that are active in the current macro.
> + while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth)
> {
> + TheCondState = TheCondStack.back();
> + TheCondStack.pop_back();
> + }
> +
> + handleMacroExit();
> + return false;
> +}
> +
> +/// parseDirectiveEndMacro
> +/// ::= .endm
> +/// ::= .endmacro
> +bool MasmParser::parseDirectiveEndMacro(StringRef Directive) {
> + if (getLexer().isNot(AsmToken::EndOfStatement))
> + return TokError("unexpected token in '" + Directive + "'
> directive");
> +
> + // If we are inside a macro instantiation, terminate the current
> + // instantiation.
> + if (isInsideMacroInstantiation()) {
> + handleMacroExit();
> + return false;
> + }
> +
> + // Otherwise, this .endmacro is a stray entry in the file; well
> formed
> + // .endmacro directives are handled during the macro definition
> parsing.
> + return TokError("unexpected '" + Directive + "' in file, "
> + "no current macro
> definition");
> +}
> +
> +/// parseDirectivePurgeMacro
> +/// ::= .purgem
> +bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {
> + StringRef Name;
> + SMLoc Loc;
> + if (parseTokenLoc(Loc) ||
> + check(parseIdentifier(Name), Loc,
> + "expected identifier in '.purgem' directive") ||
> + parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.purgem' directive"))
> + return true;
> +
> + if (!getContext().lookupMacro(Name))
> + return Error(DirectiveLoc, "macro '" + Name + "' is not
> defined");
> +
> + getContext().undefineMacro(Name);
> + DEBUG_WITH_TYPE("asm-macros", dbgs()
> + << "Un-defining macro: " << Name
> << "\n");
> + return false;
> +}
> +
> +/// parseDirectiveSymbolAttribute
> +/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
> +bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
> + auto parseOp = [&]() -> bool {
> + StringRef Name;
> + SMLoc Loc = getTok().getLoc();
> + if (parseIdentifier(Name))
> + return Error(Loc, "expected identifier");
> + 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");
> +
> + if (!getStreamer().emitSymbolAttribute(Sym, Attr))
> + return Error(Loc, "unable to emit symbol attribute");
> + return false;
> + };
> +
> + if (parseMany(parseOp))
> + return addErrorSuffix(" in directive");
> + return false;
> +}
> +
> +/// parseDirectiveComm
> +/// ::= ( .comm | .lcomm ) identifier , size_expression [ ,
> align_expression ]
> +bool MasmParser::parseDirectiveComm(bool IsLocal) {
> + if (checkForValidSection())
> + return true;
> +
> + SMLoc IDLoc = getLexer().getLoc();
> + StringRef Name;
> + if (parseIdentifier(Name))
> + return TokError("expected identifier in directive");
> +
> + // Handle the identifier as the key symbol.
> + MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
> +
> + if (getLexer().isNot(AsmToken::Comma))
> + return TokError("unexpected token in directive");
> + Lex();
> +
> + int64_t Size;
> + SMLoc SizeLoc = getLexer().getLoc();
> + if (parseAbsoluteExpression(Size))
> + return true;
> +
> + int64_t Pow2Alignment = 0;
> + SMLoc Pow2AlignmentLoc;
> + if (getLexer().is(AsmToken::Comma)) {
> + Lex();
> + Pow2AlignmentLoc = getLexer().getLoc();
> + 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 ((!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);
> + }
> + }
> +
> + 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.
> + if (Size < 0)
> + return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive
> size, can't "
> + "be less than zero");
> +
> + // NOTE: The alignment in the directive is a power of 2 value, the
> assembler
> + // may internally end up wanting an alignment in bytes.
> + // FIXME: Diagnose overflow.
> + if (Pow2Alignment < 0)
> + return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm'
> directive "
> + "alignment, can't be less than
> zero");
> +
> + Sym->redefineIfPossible();
> + if (!Sym->isUndefined())
> + return Error(IDLoc, "invalid symbol redefinition");
> +
> + // Create the Symbol as a common or local common with Size and
> Pow2Alignment
> + if (IsLocal) {
> + getStreamer().emitLocalCommonSymbol(Sym, Size, 1 <<
> Pow2Alignment);
> + return false;
> + }
> +
> + getStreamer().emitCommonSymbol(Sym, Size, 1 << Pow2Alignment);
> + return false;
> +}
> +
> +/// parseDirectiveComment
> +/// ::= comment delimiter [[text]]
> +/// [[text]]
> +/// [[text]] delimiter [[text]]
> +bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) {
> + StringRef FirstLine = parseStringToEndOfStatement();
> + size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A ");
> + StringRef Delimiter = FirstLine.take_front(DelimiterEnd);
> + if (Delimiter.empty())
> + return Error(DirectiveLoc, "no delimiter in 'comment'
> directive");
> + do {
> + if (getTok().is(AsmToken::Eof))
> + return Error(DirectiveLoc, "unmatched delimiter in 'comment'
> directive");
> + Lex(); // eat end of statement
> + } while (!parseStringToEndOfStatement().contains(Delimiter));
> + return parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'comment' directive");
> +}
> +
> +/// parseDirectiveInclude
> +/// ::= include <filename>
> +/// | include filename
> +bool MasmParser::parseDirectiveInclude() {
> + // Allow the strings to have escaped octal character sequence.
> + std::string Filename;
> + SMLoc IncludeLoc = getTok().getLoc();
> +
> + if (!parseAngleBracketString(Filename))
> + Filename = parseStringToEndOfStatement().str();
> + if (check(!Filename.empty(), "missing filename in 'include'
> directive") ||
> + check(getTok().isNot(AsmToken::EndOfStatement),
> + "unexpected token in 'include' directive") ||
> + // Attempt to switch the lexer to the included file before
> consuming the
> + // end of statement to avoid losing it when we switch.
> + check(enterIncludeFile(Filename), IncludeLoc,
> + "Could not find include file '" + Filename + "'"))
> + return true;
> +
> + return false;
> +}
> +
> +/// parseDirectiveIf
> +/// ::= .if{,eq,ge,gt,le,lt,ne} expression
> +bool MasmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind
> DirKind) {
> + TheCondStack.push_back(TheCondState);
> + TheCondState.TheCond = AsmCond::IfCond;
> + if (TheCondState.Ignore) {
> + eatToEndOfStatement();
> + } else {
> + int64_t ExprValue;
> + if (parseAbsoluteExpression(ExprValue) ||
> + parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.if' directive"))
> + return true;
> +
> + switch (DirKind) {
> + default:
> + llvm_unreachable("unsupported directive");
> + case DK_IF:
> + break;
> + case DK_IFE:
> + ExprValue = ExprValue == 0;
> + break;
> + }
> +
> + TheCondState.CondMet = ExprValue;
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveIfb
> +/// ::= .ifb string
> +bool MasmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool
> ExpectBlank) {
> + TheCondStack.push_back(TheCondState);
> + TheCondState.TheCond = AsmCond::IfCond;
> +
> + if (TheCondState.Ignore) {
> + eatToEndOfStatement();
> + } else {
> + std::string Str;
> + if (parseTextItem(Str))
> + return TokError("expected string parameter for 'ifb'
> directive");
> +
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'ifb' directive"))
> + return true;
> +
> + TheCondState.CondMet = ExpectBlank == Str.empty();
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveIfidn
> +/// ::= ifidn string1, string2
> +bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool
> ExpectEqual, bool CaseInsensitive) {
> + std::string String1, String2;
> +
> + if (parseTextItem(String1)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for 'ifidn'
> directive");
> + return TokError("expected string parameter for 'ifdif'
> directive");
> + }
> +
> + if (Lexer.isNot(AsmToken::Comma)) {
> + if (ExpectEqual)
> + return TokError(
> + "expected comma after first string for 'ifidn'
> directive");
> + return TokError("expected comma after first string for 'ifdif'
> directive");
> + }
> + Lex();
> +
> + if (parseTextItem(String2)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for 'ifidn'
> directive");
> + return TokError("expected string parameter for 'ifdif'
> directive");
> + }
> +
> + TheCondStack.push_back(TheCondState);
> + TheCondState.TheCond = AsmCond::IfCond;
> + if (CaseInsensitive)
> + TheCondState.CondMet =
> + ExpectEqual == (StringRef(String1).equals_lower(String2));
> + else
> + TheCondState.CondMet = ExpectEqual == (String1 == String2);
> + TheCondState.Ignore = !TheCondState.CondMet;
> +
> + return false;
> +}
> +
> +/// parseDirectiveIfdef
> +/// ::= ifdef symbol
> +/// | ifdef variable
> +bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool
> expect_defined) {
> + TheCondStack.push_back(TheCondState);
> + TheCondState.TheCond = AsmCond::IfCond;
> +
> + if (TheCondState.Ignore) {
> + eatToEndOfStatement();
> + } else {
> + bool is_defined = false;
> + unsigned RegNo;
> + SMLoc StartLoc, EndLoc;
> + is_defined = (getTargetParser().tryParseRegister(
> + RegNo, StartLoc, EndLoc) ==
> MatchOperand_Success);
> + if (!is_defined) {
> + StringRef Name;
> + if (check(parseIdentifier(Name), "expected identifier after
> 'ifdef'") ||
> + parseToken(AsmToken::EndOfStatement, "unexpected token in
> 'ifdef'"))
> + return true;
> +
> + if (Variables.find(Name) != Variables.end()) {
> + is_defined = true;
> + } else {
> + MCSymbol *Sym = getContext().lookupSymbol(Name);
> + is_defined = (Sym && !Sym->isUndefined(false));
> + }
> + }
> +
> + TheCondState.CondMet = (is_defined == expect_defined);
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveElseIf
> +/// ::= elseif expression
> +bool MasmParser::parseDirectiveElseIf(SMLoc DirectiveLoc,
> + DirectiveKind DirKind) {
> + if (TheCondState.TheCond != AsmCond::IfCond &&
> + TheCondState.TheCond != AsmCond::ElseIfCond)
> + return Error(DirectiveLoc, "Encountered a .elseif that doesn't
> follow an"
> + " .if or an .elseif");
> + TheCondState.TheCond = AsmCond::ElseIfCond;
> +
> + bool LastIgnoreState = false;
> + if (!TheCondStack.empty())
> + LastIgnoreState = TheCondStack.back().Ignore;
> + if (LastIgnoreState || TheCondState.CondMet) {
> + TheCondState.Ignore = true;
> + eatToEndOfStatement();
> + } else {
> + int64_t ExprValue;
> + if (parseAbsoluteExpression(ExprValue))
> + return true;
> +
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.elseif' directive"))
> + return true;
> +
> + switch (DirKind) {
> + default:
> + llvm_unreachable("unsupported directive");
> + case DK_ELSEIF:
> + break;
> + case DK_ELSEIFE:
> + ExprValue = ExprValue == 0;
> + break;
> + }
> +
> + TheCondState.CondMet = ExprValue;
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveElseIfb
> +/// ::= elseifb expression
> +bool MasmParser::parseDirectiveElseIfb(SMLoc DirectiveLoc, bool
> ExpectBlank) {
> + if (TheCondState.TheCond != AsmCond::IfCond &&
> + TheCondState.TheCond != AsmCond::ElseIfCond)
> + return Error(DirectiveLoc, "Encountered an elseif that doesn't
> follow an"
> + " if or an elseif");
> + TheCondState.TheCond = AsmCond::ElseIfCond;
> +
> + bool LastIgnoreState = false;
> + if (!TheCondStack.empty())
> + LastIgnoreState = TheCondStack.back().Ignore;
> + if (LastIgnoreState || TheCondState.CondMet) {
> + TheCondState.Ignore = true;
> + eatToEndOfStatement();
> + } else {
> + std::string Str;
> + if (parseTextItem(Str))
> + return TokError("expected string parameter for 'elseifb'
> directive");
> +
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'elseifb' directive"))
> + return true;
> +
> + TheCondState.CondMet = ExpectBlank == Str.empty();
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveElseIfdef
> +/// ::= elseifdef symbol
> +/// | elseifdef variable
> +bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc,
> + bool expect_defined) {
> + if (TheCondState.TheCond != AsmCond::IfCond &&
> + TheCondState.TheCond != AsmCond::ElseIfCond)
> + return Error(DirectiveLoc, "Encountered an elseif that doesn't
> follow an"
> + " if or an elseif");
> + TheCondState.TheCond = AsmCond::ElseIfCond;
> +
> + bool LastIgnoreState = false;
> + if (!TheCondStack.empty())
> + LastIgnoreState = TheCondStack.back().Ignore;
> + if (LastIgnoreState || TheCondState.CondMet) {
> + TheCondState.Ignore = true;
> + eatToEndOfStatement();
> + } else {
> + bool is_defined = false;
> + unsigned RegNo;
> + SMLoc StartLoc, EndLoc;
> + is_defined = (getTargetParser().tryParseRegister(RegNo,
> StartLoc, EndLoc) ==
> + MatchOperand_Success);
> + if (!is_defined) {
> + StringRef Name;
> + if (check(parseIdentifier(Name),
> + "expected identifier after 'elseifdef'") ||
> + parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'elseifdef'"))
> + return true;
> +
> + if (Variables.find(Name) != Variables.end()) {
> + is_defined = true;
> + } else {
> + MCSymbol *Sym = getContext().lookupSymbol(Name);
> + is_defined = (Sym && !Sym->isUndefined(false));
> + }
> + }
> +
> + TheCondState.CondMet = (is_defined == expect_defined);
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveElseIfidn
> +/// ::= elseifidn string1, string2
> +bool MasmParser::parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool
> ExpectEqual,
> + bool CaseInsensitive) {
> + if (TheCondState.TheCond != AsmCond::IfCond &&
> + TheCondState.TheCond != AsmCond::ElseIfCond)
> + return Error(DirectiveLoc, "Encountered an elseif that doesn't
> follow an"
> + " if or an elseif");
> + TheCondState.TheCond = AsmCond::ElseIfCond;
> +
> + bool LastIgnoreState = false;
> + if (!TheCondStack.empty())
> + LastIgnoreState = TheCondStack.back().Ignore;
> + if (LastIgnoreState || TheCondState.CondMet) {
> + TheCondState.Ignore = true;
> + eatToEndOfStatement();
> + } else {
> + std::string String1, String2;
> +
> + if (parseTextItem(String1)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for 'elseifidn'
> directive");
> + return TokError("expected string parameter for 'elseifdif'
> directive");
> + }
> +
> + if (Lexer.isNot(AsmToken::Comma)) {
> + if (ExpectEqual)
> + return TokError(
> + "expected comma after first string for 'elseifidn'
> directive");
> + return TokError(
> + "expected comma after first string for 'elseifdif'
> directive");
> + }
> + Lex();
> +
> + if (parseTextItem(String2)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for 'elseifidn'
> directive");
> + return TokError("expected string parameter for 'elseifdif'
> directive");
> + }
> +
> + if (CaseInsensitive)
> + TheCondState.CondMet =
> + ExpectEqual == (StringRef(String1).equals_lower(String2));
> + else
> + TheCondState.CondMet = ExpectEqual == (String1 == String2);
> + TheCondState.Ignore = !TheCondState.CondMet;
> + }
> +
> + return false;
> +}
> +
> +/// parseDirectiveElse
> +/// ::= else
> +bool MasmParser::parseDirectiveElse(SMLoc DirectiveLoc) {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'else' directive"))
> + return true;
> +
> + if (TheCondState.TheCond != AsmCond::IfCond &&
> + TheCondState.TheCond != AsmCond::ElseIfCond)
> + return Error(DirectiveLoc, "Encountered an else that doesn't
> follow an if"
> + " or an elseif");
> + TheCondState.TheCond = AsmCond::ElseCond;
> + bool LastIgnoreState = false;
> + if (!TheCondStack.empty())
> + LastIgnoreState = TheCondStack.back().Ignore;
> + if (LastIgnoreState || TheCondState.CondMet)
> + TheCondState.Ignore = true;
> + else
> + TheCondState.Ignore = false;
> +
> + return false;
> +}
> +
> +/// parseDirectiveEnd
> +/// ::= end
> +bool MasmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in 'end' directive"))
> + return true;
> +
> + while (Lexer.isNot(AsmToken::Eof))
> + Lexer.Lex();
> +
> + return false;
> +}
> +
> +/// parseDirectiveError
> +/// ::= .err [message]
> +bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) {
> + if (!TheCondStack.empty()) {
> + if (TheCondStack.back().Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> + }
> +
> + StringRef Message = ".err directive invoked in source file";
> + if (Lexer.isNot(AsmToken::EndOfStatement))
> + Message = parseStringToEndOfStatement();
> + Lex();
> +
> + return Error(DirectiveLoc, Message);
> +}
> +
> +/// parseDirectiveErrorIfb
> +/// ::= .errb textitem[, message]
> +bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool
> ExpectBlank) {
> + if (!TheCondStack.empty()) {
> + if (TheCondStack.back().Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> + }
> +
> + std::string Text;
> + if (parseTextItem(Text))
> + return Error(getTok().getLoc(), "missing text item in '.errb'
> directive");
> +
> + StringRef Message = ".errb directive invoked in source file";
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + if (parseToken(AsmToken::Comma))
> + return addErrorSuffix(" in '.errb' directive");
> + Message = parseStringToEndOfStatement();
> + }
> + Lex();
> +
> + if (Text.empty() == ExpectBlank)
> + return Error(DirectiveLoc, Message);
> + return false;
> +}
> +
> +/// parseDirectiveErrorIfdef
> +/// ::= .errdef name[, message]
> +bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc,
> + bool ExpectDefined) {
> + if (!TheCondStack.empty()) {
> + if (TheCondStack.back().Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> + }
> +
> + bool IsDefined = false;
> + unsigned RegNo;
> + SMLoc StartLoc, EndLoc;
> + IsDefined = (getTargetParser().tryParseRegister(RegNo, StartLoc,
> EndLoc) ==
> + MatchOperand_Success);
> + if (!IsDefined) {
> + StringRef Name;
> + if (check(parseIdentifier(Name), "expected identifier after
> '.errdef'"))
> + return true;
> +
> + if (Variables.find(Name) != Variables.end()) {
> + IsDefined = true;
> + } else {
> + MCSymbol *Sym = getContext().lookupSymbol(Name);
> + IsDefined = (Sym && !Sym->isUndefined(false));
> + }
> + }
> +
> + StringRef Message = ".errdef directive invoked in source file";
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + if (parseToken(AsmToken::Comma))
> + return addErrorSuffix(" in '.errdef' directive");
> + Message = parseStringToEndOfStatement();
> + }
> + Lex();
> +
> + if (IsDefined == ExpectDefined)
> + return Error(DirectiveLoc, Message);
> + return false;
> +}
> +
> +/// parseDirectiveErrorIfidn
> +/// ::= .erridn textitem1, textitem2[, message]
> +bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool
> ExpectEqual,
> + bool CaseInsensitive) {
> + if (!TheCondStack.empty()) {
> + if (TheCondStack.back().Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> + }
> +
> + std::string String1, String2;
> +
> + if (parseTextItem(String1)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for '.erridn'
> directive");
> + return TokError("expected string parameter for '.errdif'
> directive");
> + }
> +
> + if (Lexer.isNot(AsmToken::Comma)) {
> + if (ExpectEqual)
> + return TokError(
> + "expected comma after first string for '.erridn'
> directive");
> + return TokError(
> + "expected comma after first string for '.errdif'
> directive");
> + }
> + Lex();
> +
> + if (parseTextItem(String2)) {
> + if (ExpectEqual)
> + return TokError("expected string parameter for '.erridn'
> directive");
> + return TokError("expected string parameter for '.errdif'
> directive");
> + }
> +
> + StringRef Message;
> + if (ExpectEqual)
> + Message = ".erridn directive invoked in source file";
> + else
> + Message = ".errdif directive invoked in source file";
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + if (parseToken(AsmToken::Comma))
> + return addErrorSuffix(" in '.erridn' directive");
> + Message = parseStringToEndOfStatement();
> + }
> + Lex();
> +
> + if (CaseInsensitive)
> + TheCondState.CondMet =
> + ExpectEqual == (StringRef(String1).equals_lower(String2));
> + else
> + TheCondState.CondMet = ExpectEqual == (String1 == String2);
> + TheCondState.Ignore = !TheCondState.CondMet;
> +
> + if ((CaseInsensitive &&
> + ExpectEqual == StringRef(String1).equals_lower(String2)) ||
> + (ExpectEqual == (String1 == String2)))
> + return Error(DirectiveLoc, Message);
> + return false;
> +}
> +
> +/// parseDirectiveErrorIfe
> +/// ::= .erre expression[, message]
> +bool MasmParser::parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool
> ExpectZero) {
> + if (!TheCondStack.empty()) {
> + if (TheCondStack.back().Ignore) {
> + eatToEndOfStatement();
> + return false;
> + }
> + }
> +
> + int64_t ExprValue;
> + if (parseAbsoluteExpression(ExprValue))
> + return addErrorSuffix(" in '.erre' directive");
> +
> + StringRef Message = ".erre directive invoked in source file";
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + if (parseToken(AsmToken::Comma))
> + return addErrorSuffix(" in '.erre' directive");
> + Message = parseStringToEndOfStatement();
> + }
> + Lex();
> +
> + if ((ExprValue == 0) == ExpectZero)
> + return Error(DirectiveLoc, Message);
> + return false;
> +}
> +
> +/// parseDirectiveEndIf
> +/// ::= .endif
> +bool MasmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {
> + if (parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '.endif' directive"))
> + return true;
> +
> + if ((TheCondState.TheCond == AsmCond::NoCond) ||
> TheCondStack.empty())
> + return Error(DirectiveLoc, "Encountered a .endif that doesn't
> follow "
> + "an .if or .else");
> + if (!TheCondStack.empty()) {
> + TheCondState = TheCondStack.back();
> + TheCondStack.pop_back();
> + }
> +
> + return false;
> +}
> +
> +void MasmParser::initializeDirectiveKindMap() {
> + DirectiveKindMap["="] = DK_ASSIGN;
> + DirectiveKindMap["equ"] = DK_EQU;
> + DirectiveKindMap["textequ"] = DK_TEXTEQU;
> + // DirectiveKindMap[".ascii"] = DK_ASCII;
> + // DirectiveKindMap[".asciz"] = DK_ASCIZ;
> + // DirectiveKindMap[".string"] = DK_STRING;
> + DirectiveKindMap["byte"] = DK_BYTE;
> + DirectiveKindMap["sbyte"] = DK_SBYTE;
> + DirectiveKindMap["word"] = DK_WORD;
> + DirectiveKindMap["sword"] = DK_SWORD;
> + DirectiveKindMap["dword"] = DK_DWORD;
> + DirectiveKindMap["sdword"] = DK_SDWORD;
> + DirectiveKindMap["fword"] = DK_FWORD;
> + DirectiveKindMap["qword"] = DK_QWORD;
> + DirectiveKindMap["sqword"] = DK_SQWORD;
> + DirectiveKindMap["real4"] = DK_REAL4;
> + DirectiveKindMap["real8"] = DK_REAL8;
> + DirectiveKindMap["align"] = DK_ALIGN;
> + // DirectiveKindMap[".org"] = DK_ORG;
> + DirectiveKindMap["extern"] = DK_EXTERN;
> + DirectiveKindMap["public"] = DK_PUBLIC;
> + // DirectiveKindMap[".comm"] = DK_COMM;
> + DirectiveKindMap["comment"] = DK_COMMENT;
> + DirectiveKindMap["include"] = DK_INCLUDE;
> + // DirectiveKindMap[".rept"] = DK_REPT;
> + // DirectiveKindMap[".rep"] = DK_REPT;
> + // DirectiveKindMap[".irp"] = DK_IRP;
> + // DirectiveKindMap[".irpc"] = DK_IRPC;
> + // DirectiveKindMap[".endr"] = DK_ENDR;
> + DirectiveKindMap["if"] = DK_IF;
> + DirectiveKindMap["ife"] = DK_IFE;
> + DirectiveKindMap["ifb"] = DK_IFB;
> + DirectiveKindMap["ifnb"] = DK_IFNB;
> + DirectiveKindMap["ifdef"] = DK_IFDEF;
> + DirectiveKindMap["ifndef"] = DK_IFNDEF;
> + DirectiveKindMap["ifdif"] = DK_IFDIF;
> + DirectiveKindMap["ifdifi"] = DK_IFDIFI;
> + DirectiveKindMap["ifidn"] = DK_IFIDN;
> + DirectiveKindMap["ifidni"] = DK_IFIDNI;
> + DirectiveKindMap["elseif"] = DK_ELSEIF;
> + DirectiveKindMap["elseifdef"] = DK_ELSEIFDEF;
> + DirectiveKindMap["elseifndef"] = DK_ELSEIFNDEF;
> + DirectiveKindMap["elseifdif"] = DK_ELSEIFDIF;
> + DirectiveKindMap["elseifidn"] = DK_ELSEIFIDN;
> + DirectiveKindMap["else"] = DK_ELSE;
> + DirectiveKindMap["end"] = DK_END;
> + DirectiveKindMap["endif"] = DK_ENDIF;
> + // DirectiveKindMap[".file"] = DK_FILE;
> + // DirectiveKindMap[".line"] = DK_LINE;
> + // 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_string"] = DK_CV_STRING;
> + // DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
> + // DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
> + // DirectiveKindMap[".cv_filechecksumoffset"] =
> DK_CV_FILECHECKSUM_OFFSET;
> + // DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;
> + // DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
> + // DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;
> + // DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;
> + // DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;
> + // DirectiveKindMap[".cfi_def_cfa_offset"] =
> DK_CFI_DEF_CFA_OFFSET;
> + // DirectiveKindMap[".cfi_adjust_cfa_offset"] =
> DK_CFI_ADJUST_CFA_OFFSET;
> + // DirectiveKindMap[".cfi_def_cfa_register"] =
> DK_CFI_DEF_CFA_REGISTER;
> + // DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
> + // DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
> + // DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
> + // DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
> + // DirectiveKindMap[".cfi_remember_state"] =
> DK_CFI_REMEMBER_STATE;
> + // DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;
> + // DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;
> + // DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;
> + // DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;
> + // DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;
> + // DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;
> + // DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
> + // DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
> + // DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
> + // DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
> + // DirectiveKindMap[".macro"] = DK_MACRO;
> + // DirectiveKindMap[".exitm"] = DK_EXITM;
> + // DirectiveKindMap[".endm"] = DK_ENDM;
> + // DirectiveKindMap[".purgem"] = DK_PURGEM;
> + DirectiveKindMap[".err"] = DK_ERR;
> + DirectiveKindMap[".errb"] = DK_ERRB;
> + DirectiveKindMap[".errnb"] = DK_ERRNB;
> + DirectiveKindMap[".errdef"] = DK_ERRDEF;
> + DirectiveKindMap[".errndef"] = DK_ERRNDEF;
> + DirectiveKindMap[".errdif"] = DK_ERRDIF;
> + DirectiveKindMap[".errdifi"] = DK_ERRDIFI;
> + DirectiveKindMap[".erridn"] = DK_ERRIDN;
> + DirectiveKindMap[".erridni"] = DK_ERRIDNI;
> + DirectiveKindMap[".erre"] = DK_ERRE;
> + DirectiveKindMap[".errnz"] = DK_ERRNZ;
> + // DirectiveKindMap[".altmacro"] = DK_ALTMACRO;
> + // DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;
> + DirectiveKindMap["db"] = DK_DB;
> + DirectiveKindMap["dd"] = DK_DD;
> + DirectiveKindMap["dq"] = DK_DQ;
> + DirectiveKindMap["dw"] = DK_DW;
> + DirectiveKindMap["echo"] = DK_ECHO;
> +}
> +
> +MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {
> + AsmToken EndToken, StartToken = getTok();
> +
> + unsigned NestLevel = 0;
> + while (true) {
> + // Check whether we have reached the end of the file.
> + if (getLexer().is(AsmToken::Eof)) {
> + printError(DirectiveLoc, "no matching '.endr' in definition");
> + return nullptr;
> + }
> +
> + if (Lexer.is(AsmToken::Identifier) &&
> + (getTok().getIdentifier() == ".rep" ||
> + getTok().getIdentifier() == ".rept" ||
> + getTok().getIdentifier() == ".irp" ||
> + getTok().getIdentifier() == ".irpc")) {
> + ++NestLevel;
> + }
> +
> + // Otherwise, check whether we have reached the .endr.
> + if (Lexer.is(AsmToken::Identifier) && getTok().getIdentifier()
> == ".endr") {
> + if (NestLevel == 0) {
> + EndToken = getTok();
> + Lex();
> + if (Lexer.isNot(AsmToken::EndOfStatement)) {
> + printError(getTok().getLoc(),
> + "unexpected token in '.endr' directive");
> + return nullptr;
> + }
> + break;
> + }
> + --NestLevel;
> + }
> +
> + // Otherwise, scan till the end of the statement.
> + eatToEndOfStatement();
> + }
> +
> + const char *BodyStart = StartToken.getLoc().getPointer();
> + const char *BodyEnd = EndToken.getLoc().getPointer();
> + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
> +
> + // We Are Anonymous.
> + MacroLikeBodies.emplace_back(StringRef(), Body,
> MCAsmMacroParameters());
> + return &MacroLikeBodies.back();
> +}
> +
> +void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc
> DirectiveLoc,
> + raw_svector_ostream &OS) {
> + OS << ".endr\n";
> +
> + std::unique_ptr<MemoryBuffer> Instantiation =
> + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
> +
> + // Create the macro instantiation object and add to the current
> macro
> + // instantiation stack.
> + MacroInstantiation *MI = new MacroInstantiation{
> + DirectiveLoc, CurBuffer, getTok().getLoc(),
> TheCondStack.size()};
> + ActiveMacros.push_back(MI);
> +
> + // Jump to the macro instantiation and prime the lexer.
> + CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation),
> SMLoc());
> + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
> + Lex();
> +}
> +
> +/// parseDirectiveRept
> +/// ::= .rep | .rept count
> +bool MasmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef
> Dir) {
> + const MCExpr *CountExpr;
> + SMLoc CountLoc = getTok().getLoc();
> + if (parseExpression(CountExpr))
> + return true;
> +
> + int64_t Count;
> + if (!CountExpr->evaluateAsAbsolute(Count,
> getStreamer().getAssemblerPtr())) {
> + return Error(CountLoc, "unexpected token in '" + Dir + "'
> directive");
> + }
> +
> + if (check(Count < 0, CountLoc, "Count is negative") ||
> + parseToken(AsmToken::EndOfStatement,
> + "unexpected token in '" + Dir + "' directive"))
> + return true;
> +
> + // Lex the rept definition.
> + MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
> + if (!M)
> + return true;
> +
> + // Macro instantiation is lexical, unfortunately. We construct a
> new buffer
> + // to hold the macro body with substitutions.
> + SmallString<256> Buf;
> + raw_svector_ostream OS(Buf);
> + while (Count--) {
> + // Note that the AtPseudoVariable is disabled for instantiations
> of .rep(t).
> + if (expandMacro(OS, M->Body, None, None, false,
> getTok().getLoc()))
> + return true;
> + }
> + instantiateMacroLikeBody(M, DirectiveLoc, OS);
> +
> + return false;
> +}
> +
> +/// parseDirectiveIrp
> +/// ::= .irp symbol,values
> +bool MasmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
> + MCAsmMacroParameter Parameter;
> + MCAsmMacroArguments A;
> + if (check(parseIdentifier(Parameter.Name),
> + "expected identifier in '.irp' directive") ||
> + parseToken(AsmToken::Comma, "expected comma in '.irp'
> directive") ||
> + parseMacroArguments(nullptr, A) ||
> + parseToken(AsmToken::EndOfStatement, "expected End of
> Statement"))
> + return true;
> +
> + // Lex the irp definition.
> + MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
> + if (!M)
> + return true;
> +
> + // Macro instantiation is lexical, unfortunately. We construct a
> new buffer
> + // to hold the macro body with substitutions.
> + SmallString<256> Buf;
> + raw_svector_ostream OS(Buf);
> +
> + for (const MCAsmMacroArgument &Arg : A) {
> + // Note that the AtPseudoVariable is enabled for instantiations
> of .irp.
> + // This is undocumented, but GAS seems to support it.
> + if (expandMacro(OS, M->Body, Parameter, Arg, true,
> getTok().getLoc()))
> + return true;
> + }
> +
> + instantiateMacroLikeBody(M, DirectiveLoc, OS);
> +
> + return false;
> +}
> +
> +/// parseDirectiveIrpc
> +/// ::= .irpc symbol,values
> +bool MasmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
> + MCAsmMacroParameter Parameter;
> + MCAsmMacroArguments A;
> +
> + if (check(parseIdentifier(Parameter.Name),
> + "expected identifier in '.irpc' directive") ||
> + parseToken(AsmToken::Comma, "expected comma in '.irpc'
> directive") ||
> + parseMacroArguments(nullptr, A))
> + return true;
> +
> + if (A.size() != 1 || A.front().size() != 1)
> + return TokError("unexpected token in '.irpc' directive");
> +
> + // Eat the end of statement.
> + if (parseToken(AsmToken::EndOfStatement, "expected end of
> statement"))
> + return true;
> +
> + // Lex the irpc definition.
> + MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
> + if (!M)
> + return true;
> +
> + // Macro instantiation is lexical, unfortunately. We construct a
> new buffer
> + // to hold the macro body with substitutions.
> + SmallString<256> Buf;
> + raw_svector_ostream OS(Buf);
> +
> + StringRef Values = A.front().front().getString();
> + for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
> + MCAsmMacroArgument Arg;
> + Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1));
> +
> + // Note that the AtPseudoVariable is enabled for instantiations
> of .irpc.
> + // This is undocumented, but GAS seems to support it.
> + if (expandMacro(OS, M->Body, Parameter, Arg, true,
> getTok().getLoc()))
> + return true;
> + }
> +
> + instantiateMacroLikeBody(M, DirectiveLoc, OS);
> +
> + return false;
> +}
> +
> +bool MasmParser::parseDirectiveEndr(SMLoc DirectiveLoc) {
> + if (ActiveMacros.empty())
> + return TokError("unmatched '.endr' directive");
> +
> + // The only .repl that should get here are the ones created by
> + // instantiateMacroLikeBody.
> + assert(getLexer().is(AsmToken::EndOfStatement));
> +
> + handleMacroExit();
> + return false;
> +}
> +
> +bool MasmParser::parseDirectiveMSEmit(SMLoc IDLoc,
> ParseStatementInfo &Info,
> + size_t Len) {
> + 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 (!isUInt<8>(IntValue) && !isInt<8>(IntValue))
> + return Error(ExprLoc, "literal value out of range for
> directive");
> +
> + Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);
> + return false;
> +}
> +
> +bool MasmParser::parseDirectiveMSAlign(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 align");
> + uint64_t IntValue = MCE->getValue();
> + if (!isPowerOf2_64(IntValue))
> + return Error(ExprLoc, "literal value not a power of two greater
> then zero");
> +
> + Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5,
> Log2_64(IntValue));
> + return false;
> +}
> +
> +bool MasmParser::parseDirectiveEcho() {
> + StringRef Message = parseStringToEndOfStatement();
> + Lex(); // eat end of statement
> + llvm::outs() << Message << '\n';
> + 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,
> + const AsmRewrite *AsmRewriteB) {
> + if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())
> + return -1;
> + if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())
> + return 1;
> +
> + // It's possible to have a SizeDirective, Imm/ImmPrefix and an
> Input/Output
> + // rewrite to the same location. Make sure the SizeDirective
> rewrite is
> + // performed first, then the Imm/ImmPrefix and finally the
> Input/Output. This
> + // ensures the sort algorithm is stable.
> + if (AsmRewritePrecedence[AsmRewriteA->Kind] >
> + AsmRewritePrecedence[AsmRewriteB->Kind])
> + return -1;
> +
> + if (AsmRewritePrecedence[AsmRewriteA->Kind] <
> + AsmRewritePrecedence[AsmRewriteB->Kind])
> + return 1;
> + llvm_unreachable("Unstable rewrite sort.");
> +}
> +
> +bool MasmParser::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> InputDeclsAddressOf;
> + SmallVector<bool, 4> OutputDeclsAddressOf;
> + SmallVector<std::string, 4> InputConstraints;
> + SmallVector<std::string, 4> OutputConstraints;
> + SmallVector<unsigned, 4> ClobberRegs;
> +
> + SmallVector<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)) {
> + // Parse curly braces marking block start/end
> + if (parseCurlyBlockScope(AsmStrRewrites))
> + continue;
> +
> + ParseStatementInfo Info(&AsmStrRewrites);
> + bool StatementErr = parseStatement(Info, &SI);
> +
> + 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;
> +
> + 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];
> +
> + // Register operand.
> + if (Operand.isReg() && !Operand.needAddressOf() &&
> + !getTargetParser().OmitRegisterFromClobberLists(Operand.ge
> tReg())) {
> + unsigned NumDefs = Desc.getNumDefs();
> + // Clobber.
> + if (NumDefs && Operand.getMCOperandNum() < NumDefs)
> + ClobberRegs.push_back(Operand.getReg());
> + continue;
> + }
> +
> + // Expr/Input or Output.
> + StringRef SymName = Operand.getSymName();
> + if (SymName.empty())
> + continue;
> +
> + void *OpDecl = Operand.getOpDecl();
> + if (!OpDecl)
> + continue;
> +
> + StringRef Constraint = Operand.getConstraint();
> + if (Operand.isImm()) {
> + // Offset as immediate
> + if (Operand.isOffsetOfLocal())
> + Constraint = "r";
> + else
> + Constraint = "i";
> + }
> +
> + bool isOutput = (i == 1) && Desc.mayStore();
> + SMLoc Start = SMLoc::getFromPointer(SymName.data());
> + if (isOutput) {
> + ++InputIdx;
> + OutputDecls.push_back(OpDecl);
> + OutputDeclsAddressOf.push_back(Operand.needAddressOf());
> + OutputConstraints.push_back(("=" + Constraint).str());
> + AsmStrRewrites.emplace_back(AOK_Output, Start,
> SymName.size());
> + } else {
> + InputDecls.push_back(OpDecl);
> + InputDeclsAddressOf.push_back(Operand.needAddressOf());
> + InputConstraints.push_back(Constraint.str());
> + if (Desc.OpInfo[i - 1].isBranchTarget())
> + AsmStrRewrites.emplace_back(AOK_CallInput, Start,
> SymName.size());
> + else
> + AsmStrRewrites.emplace_back(AOK_Input, Start,
> SymName.size());
> + }
> + }
> +
> + // Consider implicit defs to be clobbers. Think of cpuid and
> push.
> + ArrayRef<MCPhysReg> ImpDefs(Desc.getImplicitDefs(),
> + Desc.getNumImplicitDefs());
> + ClobberRegs.insert(ClobberRegs.end(), ImpDefs.begin(),
> ImpDefs.end());
> + }
> +
> + // Set the number of Outputs and Inputs.
> + NumOutputs = OutputDecls.size();
> + NumInputs = InputDecls.size();
> +
> + // Set the unique clobbers.
> + array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());
> + ClobberRegs.erase(std::unique(ClobberRegs.begin(),
> ClobberRegs.end()),
> + ClobberRegs.end());
> + Clobbers.assign(ClobberRegs.size(), std::string());
> + for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {
> + raw_string_ostream OS(Clobbers[I]);
> + IP->printRegName(OS, ClobberRegs[I]);
> + }
> +
> + // Merge the various outputs and inputs. Output are expected
> first.
> + if (NumOutputs || NumInputs) {
> + unsigned NumExprs = NumOutputs + NumInputs;
> + OpDecls.resize(NumExprs);
> + Constraints.resize(NumExprs);
> + for (unsigned i = 0; i < NumOutputs; ++i) {
> + OpDecls[i] = std::make_pair(OutputDecls[i],
> OutputDeclsAddressOf[i]);
> + Constraints[i] = OutputConstraints[i];
> + }
> + for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
> + OpDecls[j] = std::make_pair(InputDecls[i],
> InputDeclsAddressOf[i]);
> + Constraints[j] = InputConstraints[i];
> + }
> + }
> +
> + // Build the IR assembly string.
> + std::string AsmStringIR;
> + raw_string_ostream OS(AsmStringIR);
> + StringRef ASMString =
> + SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();
> + const char *AsmStart = ASMString.begin();
> + const char *AsmEnd = ASMString.end();
> + array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(),
> rewritesSort);
> + for (auto it = AsmStrRewrites.begin(); it != AsmStrRewrites.end();
> ++it) {
> + const AsmRewrite &AR = *it;
> + // Check if this has already been covered by another rewrite...
> + if (AR.Done)
> + continue;
> + AsmRewriteKind Kind = AR.Kind;
> +
> + const char *Loc = AR.Loc.getPointer();
> + assert(Loc >= AsmStart && "Expected Loc to be at or after
> Start!");
> +
> + // Emit everything up to the immediate/expression.
> + if (unsigned Len = Loc - AsmStart)
> + OS << StringRef(AsmStart, Len);
> +
> + // Skip the original expression.
> + if (Kind == AOK_Skip) {
> + AsmStart = Loc + AR.Len;
> + continue;
> + }
> +
> + unsigned AdditionalSkip = 0;
> + // Rewrite expressions in $N notation.
> + switch (Kind) {
> + default:
> + break;
> + case AOK_IntelExpr:
> + assert(AR.IntelExp.isValid() && "cannot write invalid intel
> expression");
> + if (AR.IntelExp.NeedBracs)
> + OS << "[";
> + if (AR.IntelExp.hasBaseReg())
> + OS << AR.IntelExp.BaseReg;
> + if (AR.IntelExp.hasIndexReg())
> + OS << (AR.IntelExp.hasBaseReg() ? " + " : "")
> + << AR.IntelExp.IndexReg;
> + if (AR.IntelExp.Scale > 1)
> + OS << " * $$" << AR.IntelExp.Scale;
> + if (AR.IntelExp.hasOffset()) {
> + if (AR.IntelExp.hasRegs())
> + OS << " + ";
> + // Fuse this rewrite with a rewrite of the offset name, if
> present.
> + StringRef OffsetName = AR.IntelExp.OffsetName;
> + SMLoc OffsetLoc =
> SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());
> + size_t OffsetLen = OffsetName.size();
> + auto rewrite_it = std::find_if(
> + it, AsmStrRewrites.end(), [&](const AsmRewrite
> &FusingAR) {
> + return FusingAR.Loc == OffsetLoc && FusingAR.Len ==
> OffsetLen &&
> + (FusingAR.Kind == AOK_Input ||
> + FusingAR.Kind == AOK_CallInput);
> + });
> + if (rewrite_it == AsmStrRewrites.end()) {
> + OS << "offset " << OffsetName;
> + } else if (rewrite_it->Kind == AOK_CallInput) {
> + OS << "${" << InputIdx++ << ":P}";
> + rewrite_it->Done = true;
> + } else {
> + OS << '$' << InputIdx++;
> + rewrite_it->Done = true;
> + }
> + }
> + if (AR.IntelExp.Imm || AR.IntelExp.emitImm())
> + OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") <<
> AR.IntelExp.Imm;
> + if (AR.IntelExp.NeedBracs)
> + OS << "]";
> + break;
> + case AOK_Label:
> + OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;
> + break;
> + case AOK_Input:
> + OS << '$' << InputIdx++;
> + break;
> + case AOK_CallInput:
> + OS << "${" << InputIdx++ << ":P}";
> + break;
> + case AOK_Output:
> + OS << '$' << OutputIdx++;
> + break;
> + case AOK_SizeDirective:
> + switch (AR.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_Align: {
> + // MS alignment directives are measured in bytes. If the
> native assembler
> + // measures alignment in bytes, we can pass it straight
> through.
> + OS << ".align";
> + if (getContext().getAsmInfo()->getAlignmentIsInBytes())
> + break;
> +
> + // Alignment is in log2 form, so print that instead and skip
> the original
> + // immediate.
> + unsigned Val = AR.Val;
> + OS << ' ' << Val;
> + assert(Val < 10 && "Expected alignment less then 2^10.");
> + AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;
> + break;
> + }
> + case AOK_EVEN:
> + OS << ".even";
> + break;
> + case AOK_EndOfStatement:
> + OS << "\n\t";
> + break;
> + }
> +
> + // Skip the original expression.
> + AsmStart = Loc + AR.Len + AdditionalSkip;
> + }
> +
> + // Emit the remainder of the asm string.
> + if (AsmStart != AsmEnd)
> + OS << StringRef(AsmStart, AsmEnd - AsmStart);
> +
> + AsmString = OS.str();
> + return false;
> +}
> +
> +/// Create an MCAsmParser instance.
> +MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,
> + MCStreamer &Out, const
> MCAsmInfo &MAI,
> + unsigned CB) {
> + return new MasmParser(SM, C, Out, MAI, CB);
> +}
>
> diff --git a/llvm/lib/MC/MCTargetOptions.cpp
> b/llvm/lib/MC/MCTargetOptions.cpp
> index 5848e3ecadbe..0a5d0cefeddc 100644
> --- a/llvm/lib/MC/MCTargetOptions.cpp
> +++ b/llvm/lib/MC/MCTargetOptions.cpp
> @@ -21,3 +21,7 @@ MCTargetOptions::MCTargetOptions()
> StringRef MCTargetOptions::getABIName() const {
> return ABIName;
> }
> +
> +StringRef MCTargetOptions::getAssemblyLanguage() const {
> + return AssemblyLanguage;
> +}
>
> diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
> b/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
> index d986c829d98e..1c697a1ad632 100644
> --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
> +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
> @@ -145,6 +145,16 @@
> X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
> UseIntegratedAssembler = true;
> }
>
> +void X86MCAsmInfoMicrosoftMASM::anchor() { }
> +
> +X86MCAsmInfoMicrosoftMASM::X86MCAsmInfoMicrosoftMASM(const Triple
> &Triple)
> + : X86MCAsmInfoMicrosoft(Triple) {
> + DollarIsPC = true;
> + SeparatorString = "\n";
> + CommentString = ";";
> + AllowSymbolAtNameStart = true;
> +}
> +
> void X86MCAsmInfoGNUCOFF::anchor() { }
>
> X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
>
> diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.h
> b/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.h
> index b2369647a40f..5dfb89196e83 100644
> --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.h
> +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.h
> @@ -49,6 +49,13 @@ class X86MCAsmInfoMicrosoft : public
> MCAsmInfoMicrosoft {
> explicit X86MCAsmInfoMicrosoft(const Triple &Triple);
> };
>
> +class X86MCAsmInfoMicrosoftMASM : public X86MCAsmInfoMicrosoft {
> + void anchor() override;
> +
> +public:
> + explicit X86MCAsmInfoMicrosoftMASM(const Triple &Triple);
> +};
> +
> class X86MCAsmInfoGNUCOFF : public MCAsmInfoGNUCOFF {
> void anchor() override;
>
>
> diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
> b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
> index 5594f342bfa1..9406f18f7b76 100644
> --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
> +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
> @@ -335,7 +335,10 @@ static MCAsmInfo *createX86MCAsmInfo(const
> MCRegisterInfo &MRI,
> MAI = new X86ELFMCAsmInfo(TheTriple);
> } else if (TheTriple.isWindowsMSVCEnvironment() ||
> TheTriple.isWindowsCoreCLREnvironment()) {
> - MAI = new X86MCAsmInfoMicrosoft(TheTriple);
> + if (Options.getAssemblyLanguage().equals_lower("masm"))
> + MAI = new X86MCAsmInfoMicrosoftMASM(TheTriple);
> + else
> + MAI = new X86MCAsmInfoMicrosoft(TheTriple);
> } else if (TheTriple.isOSCygMing() ||
> TheTriple.isWindowsItaniumEnvironment()) {
> MAI = new X86MCAsmInfoGNUCOFF(TheTriple);
>
> diff --git a/llvm/test/tools/llvm-ml/basic.test
> b/llvm/test/tools/llvm-ml/basic.test
> index 8e8967f5c9d2..30aa860f2b90 100644
> --- a/llvm/test/tools/llvm-ml/basic.test
> +++ b/llvm/test/tools/llvm-ml/basic.test
> @@ -1,4 +1,3 @@
> -# REQUIRES: x86-registered-target
> # RUN: not llvm-ml %t.blah -o /dev/null 2>&1 | FileCheck --check-
> prefix=ENOENT %s
>
> # ENOENT: {{.*}}.blah: {{[Nn]}}o such file or directory
>
> diff --git a/llvm/test/tools/llvm-ml/lit.local.cfg
> b/llvm/test/tools/llvm-ml/lit.local.cfg
> new file mode 100644
> index 000000000000..7230f35fdb83
> --- /dev/null
> +++ b/llvm/test/tools/llvm-ml/lit.local.cfg
> @@ -0,0 +1,3 @@
> +if not ('X86' in config.root.targets):
> + # We need support for X86.
> + config.unsupported = True
>
> diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-
> ml/llvm-ml.cpp
> index 1b30f3e831e6..2e8ecd95f6b9 100644
> --- a/llvm/tools/llvm-ml/llvm-ml.cpp
> +++ b/llvm/tools/llvm-ml/llvm-ml.cpp
> @@ -189,7 +189,8 @@ static int AssembleInput(const char *ProgName,
> const Target *TheTarget,
> SourceMgr &SrcMgr, MCContext &Ctx,
> MCStreamer &Str,
> MCAsmInfo &MAI, MCSubtargetInfo &STI,
> MCInstrInfo &MCII, MCTargetOptions
> &MCOptions) {
> - std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
> Str, MAI));
> + std::unique_ptr<MCAsmParser> Parser(
> + createMCMasmParser(SrcMgr, Ctx, Str, MAI));
> std::unique_ptr<MCTargetAsmParser> TAP(
> TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
>
> @@ -222,6 +223,7 @@ int main(int argc, char **argv) {
>
> cl::ParseCommandLineOptions(argc, argv, "llvm machine code
> playground\n");
> MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
> + MCOptions.AssemblyLanguage = "masm";
>
> const char *ProgName = argv[0];
> const Target *TheTarget = GetTarget(ProgName);
>
> diff --git a/llvm/utils/gn/secondary/llvm/lib/MC/MCParser/BUILD.gn
> b/llvm/utils/gn/secondary/llvm/lib/MC/MCParser/BUILD.gn
> index 5c9d23074693..c3739c966c49 100644
> --- a/llvm/utils/gn/secondary/llvm/lib/MC/MCParser/BUILD.gn
> +++ b/llvm/utils/gn/secondary/llvm/lib/MC/MCParser/BUILD.gn
> @@ -14,6 +14,7 @@ static_library("MCParser") {
> "MCAsmLexer.cpp",
> "MCAsmParser.cpp",
> "MCAsmParserExtension.cpp",
> + "MasmParser.cpp",
> "MCTargetAsmParser.cpp",
> "WasmAsmParser.cpp",
> ]
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list