diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/MC/MCParser | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/MC/MCParser')
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/AsmLexer.cpp | 1484 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/AsmParser.cpp | 12236 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/COFFAsmParser.cpp | 1434 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/COFFMasmParser.cpp | 686 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/DarwinAsmParser.cpp | 2416 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/ELFAsmParser.cpp | 1752 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/MCAsmLexer.cpp | 258 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/MCAsmParser.cpp | 282 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/MCAsmParserExtension.cpp | 124 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/MCTargetAsmParser.cpp | 58 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/MasmParser.cpp | 12274 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/WasmAsmParser.cpp | 468 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/MC/MCParser/ya.make | 58 |
13 files changed, 16765 insertions, 16765 deletions
diff --git a/contrib/libs/llvm12/lib/MC/MCParser/AsmLexer.cpp b/contrib/libs/llvm12/lib/MC/MCParser/AsmLexer.cpp index f075f3cfd4..1fa22ab000 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/AsmLexer.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/AsmLexer.cpp @@ -1,283 +1,283 @@ -//===- AsmLexer.cpp - Lexer 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 lexer for assembly files. -// -//===----------------------------------------------------------------------===// - -#include "llvm/MC/MCParser/AsmLexer.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" +//===- AsmLexer.cpp - Lexer 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 lexer for assembly files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/SMLoc.h" -#include "llvm/Support/SaveAndRestore.h" -#include <cassert> -#include <cctype> -#include <cstdio> -#include <cstring> -#include <string> -#include <tuple> -#include <utility> - -using namespace llvm; - -AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) { - AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); -} - -AsmLexer::~AsmLexer() = default; - -void AsmLexer::setBuffer(StringRef Buf, const char *ptr, - bool EndStatementAtEOF) { - CurBuf = Buf; - - if (ptr) - CurPtr = ptr; - else - CurPtr = CurBuf.begin(); - - TokStart = nullptr; - this->EndStatementAtEOF = EndStatementAtEOF; -} - -/// ReturnError - Set the error to the specified string at the specified -/// location. This is defined to always return AsmToken::Error. -AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { - SetError(SMLoc::getFromPointer(Loc), Msg); - - return AsmToken(AsmToken::Error, StringRef(Loc, CurPtr - Loc)); -} - -int AsmLexer::getNextChar() { - if (CurPtr == CurBuf.end()) - return EOF; - return (unsigned char)*CurPtr++; -} - +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SaveAndRestore.h" +#include <cassert> +#include <cctype> +#include <cstdio> +#include <cstring> +#include <string> +#include <tuple> +#include <utility> + +using namespace llvm; + +AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) { + AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); +} + +AsmLexer::~AsmLexer() = default; + +void AsmLexer::setBuffer(StringRef Buf, const char *ptr, + bool EndStatementAtEOF) { + CurBuf = Buf; + + if (ptr) + CurPtr = ptr; + else + CurPtr = CurBuf.begin(); + + TokStart = nullptr; + this->EndStatementAtEOF = EndStatementAtEOF; +} + +/// ReturnError - Set the error to the specified string at the specified +/// location. This is defined to always return AsmToken::Error. +AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { + SetError(SMLoc::getFromPointer(Loc), Msg); + + return AsmToken(AsmToken::Error, StringRef(Loc, CurPtr - Loc)); +} + +int AsmLexer::getNextChar() { + if (CurPtr == CurBuf.end()) + return EOF; + return (unsigned char)*CurPtr++; +} + int AsmLexer::peekNextChar() { if (CurPtr == CurBuf.end()) return EOF; return (unsigned char)*CurPtr; } -/// The leading integral digit sequence and dot should have already been -/// consumed, some or all of the fractional digit sequence *can* have been -/// consumed. -AsmToken AsmLexer::LexFloatLiteral() { - // Skip the fractional digit sequence. - while (isDigit(*CurPtr)) - ++CurPtr; - - if (*CurPtr == '-' || *CurPtr == '+') - return ReturnError(CurPtr, "Invalid sign in float literal"); - - // Check for exponent - if ((*CurPtr == 'e' || *CurPtr == 'E')) { - ++CurPtr; - - if (*CurPtr == '-' || *CurPtr == '+') - ++CurPtr; - - while (isDigit(*CurPtr)) - ++CurPtr; - } - - return AsmToken(AsmToken::Real, - StringRef(TokStart, CurPtr - TokStart)); -} - -/// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+ -/// while making sure there are enough actual digits around for the constant to -/// be valid. -/// -/// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed -/// before we get here. -AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { - assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') && - "unexpected parse state in floating hex"); - bool NoFracDigits = true; - - // Skip the fractional part if there is one - if (*CurPtr == '.') { - ++CurPtr; - - const char *FracStart = CurPtr; - while (isHexDigit(*CurPtr)) - ++CurPtr; - - NoFracDigits = CurPtr == FracStart; - } - - if (NoIntDigits && NoFracDigits) - return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " - "expected at least one significand digit"); - - // Make sure we do have some kind of proper exponent part - if (*CurPtr != 'p' && *CurPtr != 'P') - return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " - "expected exponent part 'p'"); - ++CurPtr; - - if (*CurPtr == '+' || *CurPtr == '-') - ++CurPtr; - - // N.b. exponent digits are *not* hex - const char *ExpStart = CurPtr; - while (isDigit(*CurPtr)) - ++CurPtr; - - if (CurPtr == ExpStart) - return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " - "expected at least one exponent digit"); - - return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); -} - -/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* -static bool IsIdentifierChar(char c, bool AllowAt) { - return isAlnum(c) || c == '_' || c == '$' || c == '.' || - (c == '@' && AllowAt) || c == '?'; -} - -AsmToken AsmLexer::LexIdentifier() { - // Check for floating point literals. - if (CurPtr[-1] == '.' && isDigit(*CurPtr)) { - // Disambiguate a .1243foo identifier from a floating literal. - while (isDigit(*CurPtr)) - ++CurPtr; - - if (!IsIdentifierChar(*CurPtr, AllowAtInIdentifier) || - *CurPtr == 'e' || *CurPtr == 'E') - return LexFloatLiteral(); - } - - while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) - ++CurPtr; - - // Handle . as a special case. - if (CurPtr == TokStart+1 && TokStart[0] == '.') - return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); - - return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); -} - -/// LexSlash: Slash: / -/// C-Style Comment: /* ... */ -AsmToken AsmLexer::LexSlash() { - switch (*CurPtr) { - case '*': - IsAtStartOfStatement = false; - break; // C style comment. - case '/': - ++CurPtr; - return LexLineComment(); - default: - IsAtStartOfStatement = false; - return AsmToken(AsmToken::Slash, StringRef(TokStart, 1)); - } - - // C Style comment. - ++CurPtr; // skip the star. - const char *CommentTextStart = CurPtr; - while (CurPtr != CurBuf.end()) { - switch (*CurPtr++) { - case '*': - // End of the comment? - if (*CurPtr != '/') - break; - // If we have a CommentConsumer, notify it about the comment. - if (CommentConsumer) { - CommentConsumer->HandleComment( - SMLoc::getFromPointer(CommentTextStart), - StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); - } - ++CurPtr; // End the */. - return AsmToken(AsmToken::Comment, - StringRef(TokStart, CurPtr - TokStart)); - } - } - return ReturnError(TokStart, "unterminated comment"); -} - -/// LexLineComment: Comment: #[^\n]* -/// : //[^\n]* -AsmToken AsmLexer::LexLineComment() { - // Mark This as an end of statement with a body of the - // comment. While it would be nicer to leave this two tokens, - // backwards compatability with TargetParsers makes keeping this in this form - // better. - const char *CommentTextStart = CurPtr; - int CurChar = getNextChar(); - while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) - CurChar = getNextChar(); - if (CurChar == '\r' && CurPtr != CurBuf.end() && *CurPtr == '\n') - ++CurPtr; - - // If we have a CommentConsumer, notify it about the comment. - if (CommentConsumer) { - CommentConsumer->HandleComment( - SMLoc::getFromPointer(CommentTextStart), - StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); - } - - IsAtStartOfLine = true; - // This is a whole line comment. leave newline - if (IsAtStartOfStatement) - return AsmToken(AsmToken::EndOfStatement, - StringRef(TokStart, CurPtr - TokStart)); - IsAtStartOfStatement = true; - - return AsmToken(AsmToken::EndOfStatement, - StringRef(TokStart, CurPtr - 1 - TokStart)); -} - -static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { - // Skip ULL, UL, U, L and LL suffices. - if (CurPtr[0] == 'U') - ++CurPtr; - if (CurPtr[0] == 'L') - ++CurPtr; - if (CurPtr[0] == 'L') - ++CurPtr; -} - -// Look ahead to search for first non-hex digit, if it's [hH], then we treat the -// integer as a hexadecimal, possibly with leading zeroes. -static unsigned doHexLookAhead(const char *&CurPtr, unsigned DefaultRadix, - bool LexHex) { - const char *FirstNonDec = nullptr; - const char *LookAhead = CurPtr; - while (true) { - if (isDigit(*LookAhead)) { - ++LookAhead; - } else { - if (!FirstNonDec) - FirstNonDec = LookAhead; - - // Keep going if we are looking for a 'h' suffix. - if (LexHex && isHexDigit(*LookAhead)) - ++LookAhead; - else - break; - } - } - bool isHex = LexHex && (*LookAhead == 'h' || *LookAhead == 'H'); - CurPtr = isHex || !FirstNonDec ? LookAhead : FirstNonDec; - if (isHex) - return 16; - return DefaultRadix; -} - +/// The leading integral digit sequence and dot should have already been +/// consumed, some or all of the fractional digit sequence *can* have been +/// consumed. +AsmToken AsmLexer::LexFloatLiteral() { + // Skip the fractional digit sequence. + while (isDigit(*CurPtr)) + ++CurPtr; + + if (*CurPtr == '-' || *CurPtr == '+') + return ReturnError(CurPtr, "Invalid sign in float literal"); + + // Check for exponent + if ((*CurPtr == 'e' || *CurPtr == 'E')) { + ++CurPtr; + + if (*CurPtr == '-' || *CurPtr == '+') + ++CurPtr; + + while (isDigit(*CurPtr)) + ++CurPtr; + } + + return AsmToken(AsmToken::Real, + StringRef(TokStart, CurPtr - TokStart)); +} + +/// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+ +/// while making sure there are enough actual digits around for the constant to +/// be valid. +/// +/// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed +/// before we get here. +AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { + assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') && + "unexpected parse state in floating hex"); + bool NoFracDigits = true; + + // Skip the fractional part if there is one + if (*CurPtr == '.') { + ++CurPtr; + + const char *FracStart = CurPtr; + while (isHexDigit(*CurPtr)) + ++CurPtr; + + NoFracDigits = CurPtr == FracStart; + } + + if (NoIntDigits && NoFracDigits) + return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " + "expected at least one significand digit"); + + // Make sure we do have some kind of proper exponent part + if (*CurPtr != 'p' && *CurPtr != 'P') + return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " + "expected exponent part 'p'"); + ++CurPtr; + + if (*CurPtr == '+' || *CurPtr == '-') + ++CurPtr; + + // N.b. exponent digits are *not* hex + const char *ExpStart = CurPtr; + while (isDigit(*CurPtr)) + ++CurPtr; + + if (CurPtr == ExpStart) + return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " + "expected at least one exponent digit"); + + return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); +} + +/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* +static bool IsIdentifierChar(char c, bool AllowAt) { + return isAlnum(c) || c == '_' || c == '$' || c == '.' || + (c == '@' && AllowAt) || c == '?'; +} + +AsmToken AsmLexer::LexIdentifier() { + // Check for floating point literals. + if (CurPtr[-1] == '.' && isDigit(*CurPtr)) { + // Disambiguate a .1243foo identifier from a floating literal. + while (isDigit(*CurPtr)) + ++CurPtr; + + if (!IsIdentifierChar(*CurPtr, AllowAtInIdentifier) || + *CurPtr == 'e' || *CurPtr == 'E') + return LexFloatLiteral(); + } + + while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) + ++CurPtr; + + // Handle . as a special case. + if (CurPtr == TokStart+1 && TokStart[0] == '.') + return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); + + return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); +} + +/// LexSlash: Slash: / +/// C-Style Comment: /* ... */ +AsmToken AsmLexer::LexSlash() { + switch (*CurPtr) { + case '*': + IsAtStartOfStatement = false; + break; // C style comment. + case '/': + ++CurPtr; + return LexLineComment(); + default: + IsAtStartOfStatement = false; + return AsmToken(AsmToken::Slash, StringRef(TokStart, 1)); + } + + // C Style comment. + ++CurPtr; // skip the star. + const char *CommentTextStart = CurPtr; + while (CurPtr != CurBuf.end()) { + switch (*CurPtr++) { + case '*': + // End of the comment? + if (*CurPtr != '/') + break; + // If we have a CommentConsumer, notify it about the comment. + if (CommentConsumer) { + CommentConsumer->HandleComment( + SMLoc::getFromPointer(CommentTextStart), + StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); + } + ++CurPtr; // End the */. + return AsmToken(AsmToken::Comment, + StringRef(TokStart, CurPtr - TokStart)); + } + } + return ReturnError(TokStart, "unterminated comment"); +} + +/// LexLineComment: Comment: #[^\n]* +/// : //[^\n]* +AsmToken AsmLexer::LexLineComment() { + // Mark This as an end of statement with a body of the + // comment. While it would be nicer to leave this two tokens, + // backwards compatability with TargetParsers makes keeping this in this form + // better. + const char *CommentTextStart = CurPtr; + int CurChar = getNextChar(); + while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) + CurChar = getNextChar(); + if (CurChar == '\r' && CurPtr != CurBuf.end() && *CurPtr == '\n') + ++CurPtr; + + // If we have a CommentConsumer, notify it about the comment. + if (CommentConsumer) { + CommentConsumer->HandleComment( + SMLoc::getFromPointer(CommentTextStart), + StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); + } + + IsAtStartOfLine = true; + // This is a whole line comment. leave newline + if (IsAtStartOfStatement) + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, CurPtr - TokStart)); + IsAtStartOfStatement = true; + + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, CurPtr - 1 - TokStart)); +} + +static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { + // Skip ULL, UL, U, L and LL suffices. + if (CurPtr[0] == 'U') + ++CurPtr; + if (CurPtr[0] == 'L') + ++CurPtr; + if (CurPtr[0] == 'L') + ++CurPtr; +} + +// Look ahead to search for first non-hex digit, if it's [hH], then we treat the +// integer as a hexadecimal, possibly with leading zeroes. +static unsigned doHexLookAhead(const char *&CurPtr, unsigned DefaultRadix, + bool LexHex) { + const char *FirstNonDec = nullptr; + const char *LookAhead = CurPtr; + while (true) { + if (isDigit(*LookAhead)) { + ++LookAhead; + } else { + if (!FirstNonDec) + FirstNonDec = LookAhead; + + // Keep going if we are looking for a 'h' suffix. + if (LexHex && isHexDigit(*LookAhead)) + ++LookAhead; + else + break; + } + } + bool isHex = LexHex && (*LookAhead == 'h' || *LookAhead == 'H'); + CurPtr = isHex || !FirstNonDec ? LookAhead : FirstNonDec; + if (isHex) + return 16; + return DefaultRadix; +} + static const char *findLastDigit(const char *CurPtr, unsigned DefaultRadix) { while (hexDigitValue(*CurPtr) < DefaultRadix) { ++CurPtr; @@ -286,11 +286,11 @@ static const char *findLastDigit(const char *CurPtr, unsigned DefaultRadix) { } static AsmToken intToken(StringRef Ref, APInt &Value) { - if (Value.isIntN(64)) - return AsmToken(AsmToken::Integer, Ref, Value); - return AsmToken(AsmToken::BigNum, Ref, Value); -} - + if (Value.isIntN(64)) + return AsmToken(AsmToken::Integer, Ref, Value); + return AsmToken(AsmToken::BigNum, Ref, Value); +} + static std::string radixName(unsigned Radix) { switch (Radix) { case 2: @@ -306,25 +306,25 @@ static std::string radixName(unsigned Radix) { } } -/// LexDigit: First character is [0-9]. -/// Local Label: [0-9][:] -/// Forward/Backward Label: [0-9][fb] -/// Binary integer: 0b[01]+ -/// Octal integer: 0[0-7]+ -/// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] -/// Decimal integer: [1-9][0-9]* -AsmToken AsmLexer::LexDigit() { +/// LexDigit: First character is [0-9]. +/// Local Label: [0-9][:] +/// Forward/Backward Label: [0-9][fb] +/// Binary integer: 0b[01]+ +/// Octal integer: 0[0-7]+ +/// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] +/// Decimal integer: [1-9][0-9]* +AsmToken AsmLexer::LexDigit() { // MASM-flavor binary integer: [01]+[yY] (if DefaultRadix < 16, [bByY]) // MASM-flavor octal integer: [0-7]+[oOqQ] // MASM-flavor decimal integer: [0-9]+[tT] (if DefaultRadix < 16, [dDtT]) - // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH] - if (LexMasmIntegers && isdigit(CurPtr[-1])) { + // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH] + if (LexMasmIntegers && isdigit(CurPtr[-1])) { const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ? CurPtr - 1 : nullptr; const char *FirstNonDecimal = (CurPtr[-1] < '0' || CurPtr[-1] > '9') ? CurPtr - 1 : nullptr; - const char *OldCurPtr = CurPtr; - while (isHexDigit(*CurPtr)) { + const char *OldCurPtr = CurPtr; + while (isHexDigit(*CurPtr)) { switch (*CurPtr) { default: if (!FirstNonDecimal) { @@ -347,25 +347,25 @@ AsmToken AsmLexer::LexDigit() { case '0': break; } - ++CurPtr; - } + ++CurPtr; + } if (*CurPtr == '.') { // MASM float literals (other than hex floats) always contain a ".", and // are always written in decimal. ++CurPtr; return LexFloatLiteral(); } - + if (LexMasmHexFloats && (*CurPtr == 'r' || *CurPtr == 'R')) { ++CurPtr; return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); } - unsigned Radix = 0; - if (*CurPtr == 'h' || *CurPtr == 'H') { - // hexadecimal number - ++CurPtr; - Radix = 16; + unsigned Radix = 0; + if (*CurPtr == 'h' || *CurPtr == 'H') { + // hexadecimal number + ++CurPtr; + Radix = 16; } else if (*CurPtr == 't' || *CurPtr == 'T') { // decimal number ++CurPtr; @@ -383,29 +383,29 @@ AsmToken AsmLexer::LexDigit() { DefaultRadix < 14 && (*FirstNonDecimal == 'd' || *FirstNonDecimal == 'D')) { Radix = 10; - } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr && + } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr && DefaultRadix < 12 && (*FirstNonBinary == 'b' || *FirstNonBinary == 'B')) { - Radix = 2; + Radix = 2; } - + if (Radix) { - StringRef Result(TokStart, CurPtr - TokStart); - APInt Value(128, 0, true); - - if (Result.drop_back().getAsInteger(Radix, Value)) + StringRef Result(TokStart, CurPtr - TokStart); + APInt Value(128, 0, true); + + if (Result.drop_back().getAsInteger(Radix, Value)) return ReturnError(TokStart, "invalid " + radixName(Radix) + " number"); - - // MSVC accepts and ignores type suffices on integer literals. - SkipIgnoredIntegerSuffix(CurPtr); - - return intToken(Result, Value); + + // MSVC accepts and ignores type suffices on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(Result, Value); } - + // default-radix integers, or floating point numbers, fall through - CurPtr = OldCurPtr; - } - + CurPtr = OldCurPtr; + } + // MASM default-radix integers: [0-9a-fA-F]+ // (All other integer literals have a radix specifier.) if (LexMasmIntegers && UseMasmDefaultRadix) { @@ -421,112 +421,112 @@ AsmToken AsmLexer::LexDigit() { return intToken(Result, Value); } - // Decimal integer: [1-9][0-9]* - if (CurPtr[-1] != '0' || CurPtr[0] == '.') { - unsigned Radix = doHexLookAhead(CurPtr, 10, LexMasmIntegers); - bool isHex = Radix == 16; - // Check for floating point literals. - if (!isHex && (*CurPtr == '.' || *CurPtr == 'e' || *CurPtr == 'E')) { - if (*CurPtr == '.') - ++CurPtr; - return LexFloatLiteral(); - } - - StringRef Result(TokStart, CurPtr - TokStart); - - APInt Value(128, 0, true); + // Decimal integer: [1-9][0-9]* + if (CurPtr[-1] != '0' || CurPtr[0] == '.') { + unsigned Radix = doHexLookAhead(CurPtr, 10, LexMasmIntegers); + bool isHex = Radix == 16; + // Check for floating point literals. + if (!isHex && (*CurPtr == '.' || *CurPtr == 'e' || *CurPtr == 'E')) { + if (*CurPtr == '.') + ++CurPtr; + return LexFloatLiteral(); + } + + StringRef Result(TokStart, CurPtr - TokStart); + + APInt Value(128, 0, true); if (Result.getAsInteger(Radix, Value)) { return ReturnError(TokStart, "invalid " + radixName(Radix) + " number"); } - - // The darwin/x86 (and x86-64) assembler accepts and ignores type - // suffices on integer literals. - SkipIgnoredIntegerSuffix(CurPtr); - - return intToken(Result, Value); - } - - if (!LexMasmIntegers && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { - ++CurPtr; - // See if we actually have "0b" as part of something like "jmp 0b\n" - if (!isDigit(CurPtr[0])) { - --CurPtr; - StringRef Result(TokStart, CurPtr - TokStart); - return AsmToken(AsmToken::Integer, Result, 0); - } - const char *NumStart = CurPtr; - while (CurPtr[0] == '0' || CurPtr[0] == '1') - ++CurPtr; - - // Requires at least one binary digit. - if (CurPtr == NumStart) - return ReturnError(TokStart, "invalid binary number"); - - StringRef Result(TokStart, CurPtr - TokStart); - - APInt Value(128, 0, true); - if (Result.substr(2).getAsInteger(2, Value)) - return ReturnError(TokStart, "invalid binary number"); - - // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL - // suffixes on integer literals. - SkipIgnoredIntegerSuffix(CurPtr); - - return intToken(Result, Value); - } - - if ((*CurPtr == 'x') || (*CurPtr == 'X')) { - ++CurPtr; - const char *NumStart = CurPtr; - while (isHexDigit(CurPtr[0])) - ++CurPtr; - - // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be - // diagnosed by LexHexFloatLiteral). - if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P') - return LexHexFloatLiteral(NumStart == CurPtr); - - // Otherwise requires at least one hex digit. - if (CurPtr == NumStart) - return ReturnError(CurPtr-2, "invalid hexadecimal number"); - - APInt Result(128, 0); - if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) - return ReturnError(TokStart, "invalid hexadecimal number"); - - // Consume the optional [hH]. - if (LexMasmIntegers && (*CurPtr == 'h' || *CurPtr == 'H')) - ++CurPtr; - - // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL - // suffixes on integer literals. - SkipIgnoredIntegerSuffix(CurPtr); - - return intToken(StringRef(TokStart, CurPtr - TokStart), Result); - } - - // Either octal or hexadecimal. - APInt Value(128, 0, true); - unsigned Radix = doHexLookAhead(CurPtr, 8, LexMasmIntegers); - StringRef Result(TokStart, CurPtr - TokStart); - if (Result.getAsInteger(Radix, Value)) + + // The darwin/x86 (and x86-64) assembler accepts and ignores type + // suffices on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(Result, Value); + } + + if (!LexMasmIntegers && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { + ++CurPtr; + // See if we actually have "0b" as part of something like "jmp 0b\n" + if (!isDigit(CurPtr[0])) { + --CurPtr; + StringRef Result(TokStart, CurPtr - TokStart); + return AsmToken(AsmToken::Integer, Result, 0); + } + const char *NumStart = CurPtr; + while (CurPtr[0] == '0' || CurPtr[0] == '1') + ++CurPtr; + + // Requires at least one binary digit. + if (CurPtr == NumStart) + return ReturnError(TokStart, "invalid binary number"); + + StringRef Result(TokStart, CurPtr - TokStart); + + APInt Value(128, 0, true); + if (Result.substr(2).getAsInteger(2, Value)) + return ReturnError(TokStart, "invalid binary number"); + + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(Result, Value); + } + + if ((*CurPtr == 'x') || (*CurPtr == 'X')) { + ++CurPtr; + const char *NumStart = CurPtr; + while (isHexDigit(CurPtr[0])) + ++CurPtr; + + // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be + // diagnosed by LexHexFloatLiteral). + if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P') + return LexHexFloatLiteral(NumStart == CurPtr); + + // Otherwise requires at least one hex digit. + if (CurPtr == NumStart) + return ReturnError(CurPtr-2, "invalid hexadecimal number"); + + APInt Result(128, 0); + if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) + return ReturnError(TokStart, "invalid hexadecimal number"); + + // Consume the optional [hH]. + if (LexMasmIntegers && (*CurPtr == 'h' || *CurPtr == 'H')) + ++CurPtr; + + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(StringRef(TokStart, CurPtr - TokStart), Result); + } + + // Either octal or hexadecimal. + APInt Value(128, 0, true); + unsigned Radix = doHexLookAhead(CurPtr, 8, LexMasmIntegers); + StringRef Result(TokStart, CurPtr - TokStart); + if (Result.getAsInteger(Radix, Value)) return ReturnError(TokStart, "invalid " + radixName(Radix) + " number"); - - // Consume the [hH]. - if (Radix == 16) - ++CurPtr; - - // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL - // suffixes on integer literals. - SkipIgnoredIntegerSuffix(CurPtr); - - return intToken(Result, Value); -} - -/// LexSingleQuote: Integer: 'b' -AsmToken AsmLexer::LexSingleQuote() { - int CurChar = getNextChar(); - + + // Consume the [hH]. + if (Radix == 16) + ++CurPtr; + + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return intToken(Result, Value); +} + +/// LexSingleQuote: Integer: 'b' +AsmToken AsmLexer::LexSingleQuote() { + int CurChar = getNextChar(); + if (LexMasmStrings) { while (CurChar != EOF) { if (CurChar != '\'') { @@ -545,40 +545,40 @@ AsmToken AsmLexer::LexSingleQuote() { return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); } - if (CurChar == '\\') - CurChar = getNextChar(); - - if (CurChar == EOF) - return ReturnError(TokStart, "unterminated single quote"); - - CurChar = getNextChar(); - - if (CurChar != '\'') - return ReturnError(TokStart, "single quote way too long"); - - // The idea here being that 'c' is basically just an integral - // constant. - StringRef Res = StringRef(TokStart,CurPtr - TokStart); - long long Value; - - if (Res.startswith("\'\\")) { - char theChar = Res[2]; - switch (theChar) { - default: Value = theChar; break; - case '\'': Value = '\''; break; - case 't': Value = '\t'; break; - case 'n': Value = '\n'; break; - case 'b': Value = '\b'; break; - } - } else - Value = TokStart[1]; - - return AsmToken(AsmToken::Integer, Res, Value); -} - -/// LexQuote: String: "..." -AsmToken AsmLexer::LexQuote() { - int CurChar = getNextChar(); + if (CurChar == '\\') + CurChar = getNextChar(); + + if (CurChar == EOF) + return ReturnError(TokStart, "unterminated single quote"); + + CurChar = getNextChar(); + + if (CurChar != '\'') + return ReturnError(TokStart, "single quote way too long"); + + // The idea here being that 'c' is basically just an integral + // constant. + StringRef Res = StringRef(TokStart,CurPtr - TokStart); + long long Value; + + if (Res.startswith("\'\\")) { + char theChar = Res[2]; + switch (theChar) { + default: Value = theChar; break; + case '\'': Value = '\''; break; + case 't': Value = '\t'; break; + case 'n': Value = '\n'; break; + case 'b': Value = '\b'; break; + } + } else + Value = TokStart[1]; + + return AsmToken(AsmToken::Integer, Res, Value); +} + +/// LexQuote: String: "..." +AsmToken AsmLexer::LexQuote() { + int CurChar = getNextChar(); if (LexMasmStrings) { while (CurChar != EOF) { if (CurChar != '"') { @@ -597,296 +597,296 @@ AsmToken AsmLexer::LexQuote() { return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); } - // TODO: does gas allow multiline string constants? - while (CurChar != '"') { - if (CurChar == '\\') { - // Allow \", etc. - CurChar = getNextChar(); - } - - if (CurChar == EOF) - return ReturnError(TokStart, "unterminated string constant"); - - CurChar = getNextChar(); - } - - return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); -} - -StringRef AsmLexer::LexUntilEndOfStatement() { - TokStart = CurPtr; - - while (!isAtStartOfComment(CurPtr) && // Start of line comment. - !isAtStatementSeparator(CurPtr) && // End of statement marker. - *CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { - ++CurPtr; - } - return StringRef(TokStart, CurPtr-TokStart); -} - -StringRef AsmLexer::LexUntilEndOfLine() { - TokStart = CurPtr; - - while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { - ++CurPtr; - } - return StringRef(TokStart, CurPtr-TokStart); -} - -size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, - bool ShouldSkipSpace) { - SaveAndRestore<const char *> SavedTokenStart(TokStart); - SaveAndRestore<const char *> SavedCurPtr(CurPtr); - SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine); - SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement); - SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace); - SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true); - std::string SavedErr = getErr(); - SMLoc SavedErrLoc = getErrLoc(); - - size_t ReadCount; - for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) { - AsmToken Token = LexToken(); - - Buf[ReadCount] = Token; - - if (Token.is(AsmToken::Eof)) - break; - } - - SetError(SavedErrLoc, SavedErr); - return ReadCount; -} - -bool AsmLexer::isAtStartOfComment(const char *Ptr) { - StringRef CommentString = MAI.getCommentString(); - - if (CommentString.size() == 1) - return CommentString[0] == Ptr[0]; - - // Allow # preprocessor commments also be counted as comments for "##" cases - if (CommentString[1] == '#') - return CommentString[0] == Ptr[0]; - - return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0; -} - -bool AsmLexer::isAtStatementSeparator(const char *Ptr) { - return strncmp(Ptr, MAI.getSeparatorString(), - strlen(MAI.getSeparatorString())) == 0; -} - -AsmToken AsmLexer::LexToken() { - TokStart = CurPtr; - // This always consumes at least one character. - int CurChar = getNextChar(); - - if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) { - // If this starts with a '#', this may be a cpp - // hash directive and otherwise a line comment. - AsmToken TokenBuf[2]; - MutableArrayRef<AsmToken> Buf(TokenBuf, 2); - size_t num = peekTokens(Buf, true); - // There cannot be a space preceding this - if (IsAtStartOfLine && num == 2 && TokenBuf[0].is(AsmToken::Integer) && - TokenBuf[1].is(AsmToken::String)) { - CurPtr = TokStart; // reset curPtr; - StringRef s = LexUntilEndOfLine(); - UnLex(TokenBuf[1]); - UnLex(TokenBuf[0]); - return AsmToken(AsmToken::HashDirective, s); - } - return LexLineComment(); - } - - if (isAtStartOfComment(TokStart)) - return LexLineComment(); - - if (isAtStatementSeparator(TokStart)) { - CurPtr += strlen(MAI.getSeparatorString()) - 1; - IsAtStartOfLine = true; - IsAtStartOfStatement = true; - return AsmToken(AsmToken::EndOfStatement, - StringRef(TokStart, strlen(MAI.getSeparatorString()))); - } - - // If we're missing a newline at EOF, make sure we still get an - // EndOfStatement token before the Eof token. - if (CurChar == EOF && !IsAtStartOfStatement && EndStatementAtEOF) { - IsAtStartOfLine = true; - IsAtStartOfStatement = true; + // TODO: does gas allow multiline string constants? + while (CurChar != '"') { + if (CurChar == '\\') { + // Allow \", etc. + CurChar = getNextChar(); + } + + if (CurChar == EOF) + return ReturnError(TokStart, "unterminated string constant"); + + CurChar = getNextChar(); + } + + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); +} + +StringRef AsmLexer::LexUntilEndOfStatement() { + TokStart = CurPtr; + + while (!isAtStartOfComment(CurPtr) && // Start of line comment. + !isAtStatementSeparator(CurPtr) && // End of statement marker. + *CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); +} + +StringRef AsmLexer::LexUntilEndOfLine() { + TokStart = CurPtr; + + while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); +} + +size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, + bool ShouldSkipSpace) { + SaveAndRestore<const char *> SavedTokenStart(TokStart); + SaveAndRestore<const char *> SavedCurPtr(CurPtr); + SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine); + SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement); + SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace); + SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true); + std::string SavedErr = getErr(); + SMLoc SavedErrLoc = getErrLoc(); + + size_t ReadCount; + for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) { + AsmToken Token = LexToken(); + + Buf[ReadCount] = Token; + + if (Token.is(AsmToken::Eof)) + break; + } + + SetError(SavedErrLoc, SavedErr); + return ReadCount; +} + +bool AsmLexer::isAtStartOfComment(const char *Ptr) { + StringRef CommentString = MAI.getCommentString(); + + if (CommentString.size() == 1) + return CommentString[0] == Ptr[0]; + + // Allow # preprocessor commments also be counted as comments for "##" cases + if (CommentString[1] == '#') + return CommentString[0] == Ptr[0]; + + return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0; +} + +bool AsmLexer::isAtStatementSeparator(const char *Ptr) { + return strncmp(Ptr, MAI.getSeparatorString(), + strlen(MAI.getSeparatorString())) == 0; +} + +AsmToken AsmLexer::LexToken() { + TokStart = CurPtr; + // This always consumes at least one character. + int CurChar = getNextChar(); + + if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) { + // If this starts with a '#', this may be a cpp + // hash directive and otherwise a line comment. + AsmToken TokenBuf[2]; + MutableArrayRef<AsmToken> Buf(TokenBuf, 2); + size_t num = peekTokens(Buf, true); + // There cannot be a space preceding this + if (IsAtStartOfLine && num == 2 && TokenBuf[0].is(AsmToken::Integer) && + TokenBuf[1].is(AsmToken::String)) { + CurPtr = TokStart; // reset curPtr; + StringRef s = LexUntilEndOfLine(); + UnLex(TokenBuf[1]); + UnLex(TokenBuf[0]); + return AsmToken(AsmToken::HashDirective, s); + } + return LexLineComment(); + } + + if (isAtStartOfComment(TokStart)) + return LexLineComment(); + + if (isAtStatementSeparator(TokStart)) { + CurPtr += strlen(MAI.getSeparatorString()) - 1; + IsAtStartOfLine = true; + IsAtStartOfStatement = true; + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, strlen(MAI.getSeparatorString()))); + } + + // If we're missing a newline at EOF, make sure we still get an + // EndOfStatement token before the Eof token. + if (CurChar == EOF && !IsAtStartOfStatement && EndStatementAtEOF) { + IsAtStartOfLine = true; + IsAtStartOfStatement = true; return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 0)); - } - IsAtStartOfLine = false; - bool OldIsAtStartOfStatement = IsAtStartOfStatement; - IsAtStartOfStatement = false; - switch (CurChar) { - default: - 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: - if (EndStatementAtEOF) { - IsAtStartOfLine = true; - IsAtStartOfStatement = true; - } - return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); - case 0: - case ' ': - case '\t': - IsAtStartOfStatement = OldIsAtStartOfStatement; - while (*CurPtr == ' ' || *CurPtr == '\t') - CurPtr++; - if (SkipSpace) - return LexToken(); // Ignore whitespace. - else - return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart)); - case '\r': { - IsAtStartOfLine = true; - IsAtStartOfStatement = true; - // If this is a CR followed by LF, treat that as one token. - if (CurPtr != CurBuf.end() && *CurPtr == '\n') - ++CurPtr; - return AsmToken(AsmToken::EndOfStatement, - StringRef(TokStart, CurPtr - TokStart)); - } - case '\n': - IsAtStartOfLine = true; - IsAtStartOfStatement = true; - return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); - case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); - case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); - case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); - case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); - case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); - case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); - case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); - case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); - case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); - case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); - case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); - case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); - case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); - case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); - case '=': - if (*CurPtr == '=') { - ++CurPtr; - return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); - } - return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); - case '-': - if (*CurPtr == '>') { - ++CurPtr; - return AsmToken(AsmToken::MinusGreater, StringRef(TokStart, 2)); - } - return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); - case '|': - if (*CurPtr == '|') { - ++CurPtr; - return AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); - } - return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); - case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); - case '&': - if (*CurPtr == '&') { - ++CurPtr; - return AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); - } - return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); - case '!': - if (*CurPtr == '=') { - ++CurPtr; - return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); - } - return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); - case '%': - if (MAI.hasMipsExpressions()) { - AsmToken::TokenKind Operator; - unsigned OperatorLength; - - std::tie(Operator, OperatorLength) = - StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>( - StringRef(CurPtr)) - .StartsWith("call16", {AsmToken::PercentCall16, 7}) - .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8}) - .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8}) - .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10}) - .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10}) - .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9}) - .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7}) - .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7}) - .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9}) - .StartsWith("got_page", {AsmToken::PercentGot_Page, 9}) - .StartsWith("gottprel", {AsmToken::PercentGottprel, 9}) - .StartsWith("got", {AsmToken::PercentGot, 4}) - .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7}) - .StartsWith("higher", {AsmToken::PercentHigher, 7}) - .StartsWith("highest", {AsmToken::PercentHighest, 8}) - .StartsWith("hi", {AsmToken::PercentHi, 3}) - .StartsWith("lo", {AsmToken::PercentLo, 3}) - .StartsWith("neg", {AsmToken::PercentNeg, 4}) - .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9}) - .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9}) - .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6}) - .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7}) - .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9}) - .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9}) - .Default({AsmToken::Percent, 1}); - - if (Operator != AsmToken::Percent) { - CurPtr += OperatorLength - 1; - return AsmToken(Operator, StringRef(TokStart, OperatorLength)); - } - } - return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); - case '/': - IsAtStartOfStatement = OldIsAtStartOfStatement; - return LexSlash(); - case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); - case '\'': return LexSingleQuote(); - case '"': return LexQuote(); - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return LexDigit(); - case '<': - switch (*CurPtr) { - case '<': - ++CurPtr; - return AsmToken(AsmToken::LessLess, StringRef(TokStart, 2)); - case '=': - ++CurPtr; - return AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2)); - case '>': - ++CurPtr; - return AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2)); - default: - return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); - } - case '>': - switch (*CurPtr) { - case '>': - ++CurPtr; - return AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2)); - case '=': - ++CurPtr; - return AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2)); - default: - return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); - } - - // TODO: Quoted identifiers (objc methods etc) - // local labels: [0-9][:] - // Forward/backward labels: [0-9][fb] - // Integers, fp constants, character constants. - } -} + } + IsAtStartOfLine = false; + bool OldIsAtStartOfStatement = IsAtStartOfStatement; + IsAtStartOfStatement = false; + switch (CurChar) { + default: + 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: + if (EndStatementAtEOF) { + IsAtStartOfLine = true; + IsAtStartOfStatement = true; + } + return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); + case 0: + case ' ': + case '\t': + IsAtStartOfStatement = OldIsAtStartOfStatement; + while (*CurPtr == ' ' || *CurPtr == '\t') + CurPtr++; + if (SkipSpace) + return LexToken(); // Ignore whitespace. + else + return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart)); + case '\r': { + IsAtStartOfLine = true; + IsAtStartOfStatement = true; + // If this is a CR followed by LF, treat that as one token. + if (CurPtr != CurBuf.end() && *CurPtr == '\n') + ++CurPtr; + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, CurPtr - TokStart)); + } + case '\n': + IsAtStartOfLine = true; + IsAtStartOfStatement = true; + return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); + case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); + case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); + case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); + case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); + case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); + case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); + case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); + case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); + case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); + case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); + case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); + case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); + case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); + case '=': + if (*CurPtr == '=') { + ++CurPtr; + return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); + case '-': + if (*CurPtr == '>') { + ++CurPtr; + return AsmToken(AsmToken::MinusGreater, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); + case '|': + if (*CurPtr == '|') { + ++CurPtr; + return AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); + case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); + case '&': + if (*CurPtr == '&') { + ++CurPtr; + return AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); + case '!': + if (*CurPtr == '=') { + ++CurPtr; + return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); + } + return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); + case '%': + if (MAI.hasMipsExpressions()) { + AsmToken::TokenKind Operator; + unsigned OperatorLength; + + std::tie(Operator, OperatorLength) = + StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>( + StringRef(CurPtr)) + .StartsWith("call16", {AsmToken::PercentCall16, 7}) + .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8}) + .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8}) + .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10}) + .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10}) + .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9}) + .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7}) + .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7}) + .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9}) + .StartsWith("got_page", {AsmToken::PercentGot_Page, 9}) + .StartsWith("gottprel", {AsmToken::PercentGottprel, 9}) + .StartsWith("got", {AsmToken::PercentGot, 4}) + .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7}) + .StartsWith("higher", {AsmToken::PercentHigher, 7}) + .StartsWith("highest", {AsmToken::PercentHighest, 8}) + .StartsWith("hi", {AsmToken::PercentHi, 3}) + .StartsWith("lo", {AsmToken::PercentLo, 3}) + .StartsWith("neg", {AsmToken::PercentNeg, 4}) + .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9}) + .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9}) + .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6}) + .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7}) + .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9}) + .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9}) + .Default({AsmToken::Percent, 1}); + + if (Operator != AsmToken::Percent) { + CurPtr += OperatorLength - 1; + return AsmToken(Operator, StringRef(TokStart, OperatorLength)); + } + } + return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); + case '/': + IsAtStartOfStatement = OldIsAtStartOfStatement; + return LexSlash(); + case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + case '\'': return LexSingleQuote(); + case '"': return LexQuote(); + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return LexDigit(); + case '<': + switch (*CurPtr) { + case '<': + ++CurPtr; + return AsmToken(AsmToken::LessLess, StringRef(TokStart, 2)); + case '=': + ++CurPtr; + return AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2)); + case '>': + ++CurPtr; + return AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2)); + default: + return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); + } + case '>': + switch (*CurPtr) { + case '>': + ++CurPtr; + return AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2)); + case '=': + ++CurPtr; + return AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2)); + default: + return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); + } + + // TODO: Quoted identifiers (objc methods etc) + // local labels: [0-9][:] + // Forward/backward labels: [0-9][fb] + // Integers, fp constants, character constants. + } +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/AsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/AsmParser.cpp index 99548acb88..c5ff241ead 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/AsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/AsmParser.cpp @@ -1,1623 +1,1623 @@ -//===- 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 a parser for assembly files similar to gas syntax. -// -//===----------------------------------------------------------------------===// - -#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; - -MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default; - -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. -class AsmParser : public MCAsmParser { -private: - AsmLexer Lexer; - MCContext &Ctx; - MCStreamer &Out; - const MCAsmInfo &MAI; - SourceMgr &SrcMgr; - SourceMgr::DiagHandlerTy SavedDiagHandler; - void *SavedDiagContext; - std::unique_ptr<MCAsmParserExtension> PlatformParser; +//===- 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 a parser for assembly files similar to gas syntax. +// +//===----------------------------------------------------------------------===// + +#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; + +MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default; + +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. +class AsmParser : public MCAsmParser { +private: + AsmLexer Lexer; + MCContext &Ctx; + MCStreamer &Out; + const MCAsmInfo &MAI; + SourceMgr &SrcMgr; + SourceMgr::DiagHandlerTy SavedDiagHandler; + void *SavedDiagContext; + std::unique_ptr<MCAsmParserExtension> PlatformParser; SMLoc StartTokLoc; - - /// 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; - - /// 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. - unsigned AssemblerDialect = ~0U; - - /// is Darwin compatibility enabled? - bool IsDarwin = false; - - /// Are we parsing ms-style inline assembly? - bool ParsingMSInlineAsm = false; - - /// Did we already inform the user about inconsistent MD5 usage? - bool ReportedInconsistentMD5 = false; - - // Is alt macro mode enabled. - bool AltMacroMode = false; - -public: - AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, - const MCAsmInfo &MAI, unsigned CB); - AsmParser(const AsmParser &) = delete; - AsmParser &operator=(const AsmParser &) = delete; - ~AsmParser() override; - - bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; - - void addDirectiveHandler(StringRef Directive, - ExtensionDirectiveHandler Handler) override { - ExtensionDirectiveMap[Directive] = Handler; - } - - void addAliasForDirective(StringRef Directive, StringRef Alias) override { - DirectiveKindMap[Directive.lower()] = DirectiveKindMap[Alias.lower()]; - } - - /// @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 setParsingMSInlineAsm(bool V) override { - ParsingMSInlineAsm = V; - // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and - // hex integer literals. - Lexer.setLexMasmIntegers(V); - } - bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; } - - 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; + + /// 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; + + /// 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. + unsigned AssemblerDialect = ~0U; + + /// is Darwin compatibility enabled? + bool IsDarwin = false; + + /// Are we parsing ms-style inline assembly? + bool ParsingMSInlineAsm = false; + + /// Did we already inform the user about inconsistent MD5 usage? + bool ReportedInconsistentMD5 = false; + + // Is alt macro mode enabled. + bool AltMacroMode = false; + +public: + AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI, unsigned CB); + AsmParser(const AsmParser &) = delete; + AsmParser &operator=(const AsmParser &) = delete; + ~AsmParser() override; + + bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; + + void addDirectiveHandler(StringRef Directive, + ExtensionDirectiveHandler Handler) override { + ExtensionDirectiveMap[Directive] = Handler; + } + + void addAliasForDirective(StringRef Directive, StringRef Alias) override { + DirectiveKindMap[Directive.lower()] = DirectiveKindMap[Alias.lower()]; + } + + /// @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 setParsingMSInlineAsm(bool V) override { + ParsingMSInlineAsm = V; + // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and + // hex integer literals. + Lexer.setLexMasmIntegers(V); + } + bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; } + + 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, AsmTypeInfo *TypeInfo) 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, bool SaveLocInfo = true); - - 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 parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false); - - 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_SET, - DK_EQU, - DK_EQUIV, - DK_ASCII, - DK_ASCIZ, - DK_STRING, - DK_BYTE, - DK_SHORT, - DK_RELOC, - DK_VALUE, - DK_2BYTE, - DK_LONG, - DK_INT, - DK_4BYTE, - DK_QUAD, - DK_8BYTE, - DK_OCTA, - DK_DC, - DK_DC_A, - DK_DC_B, - DK_DC_D, - DK_DC_L, - DK_DC_S, - DK_DC_W, - DK_DC_X, - DK_DCB, - DK_DCB_B, - DK_DCB_D, - DK_DCB_L, - DK_DCB_S, - DK_DCB_W, - DK_DCB_X, - DK_DS, - DK_DS_B, - DK_DS_D, - DK_DS_L, - DK_DS_P, - DK_DS_S, - DK_DS_W, - DK_DS_X, - DK_SINGLE, - DK_FLOAT, - DK_DOUBLE, - DK_ALIGN, - DK_ALIGN32, - DK_BALIGN, - DK_BALIGNW, - DK_BALIGNL, - DK_P2ALIGN, - DK_P2ALIGNW, - DK_P2ALIGNL, - DK_ORG, - DK_FILL, - DK_ENDR, - DK_BUNDLE_ALIGN_MODE, - DK_BUNDLE_LOCK, - DK_BUNDLE_UNLOCK, - DK_ZERO, - DK_EXTERN, - DK_GLOBL, - DK_GLOBAL, - DK_LAZY_REFERENCE, - DK_NO_DEAD_STRIP, - DK_SYMBOL_RESOLVER, - DK_PRIVATE_EXTERN, - DK_REFERENCE, - DK_WEAK_DEFINITION, - DK_WEAK_REFERENCE, - DK_WEAK_DEF_CAN_BE_HIDDEN, - DK_COLD, - DK_COMM, - DK_COMMON, - DK_LCOMM, - DK_ABORT, - DK_INCLUDE, - DK_INCBIN, - DK_CODE16, - DK_CODE16GCC, - DK_REPT, - DK_IRP, - DK_IRPC, - DK_IF, - DK_IFEQ, - DK_IFGE, - DK_IFGT, - DK_IFLE, - DK_IFLT, - DK_IFNE, - DK_IFB, - DK_IFNB, - DK_IFC, - DK_IFEQS, - DK_IFNC, - DK_IFNES, - DK_IFDEF, - DK_IFNDEF, - DK_IFNOTDEF, - DK_ELSEIF, - DK_ELSE, - DK_ENDIF, - DK_SPACE, - DK_SKIP, - DK_FILE, - DK_LINE, - DK_LOC, - DK_STABS, - DK_CV_FILE, - DK_CV_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_MACROS_ON, - DK_MACROS_OFF, - DK_ALTMACRO, - DK_NOALTMACRO, - DK_MACRO, - DK_EXITM, - DK_ENDM, - DK_ENDMACRO, - DK_PURGEM, - DK_SLEB128, - DK_ULEB128, - DK_ERR, - DK_ERROR, - DK_WARNING, - DK_PRINT, - DK_ADDRSIG, - DK_ADDRSIG_SYM, + 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, bool SaveLocInfo = true); + + 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 parseAssignment(StringRef Name, bool allow_redef, + bool NoDeadStrip = false); + + 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_SET, + DK_EQU, + DK_EQUIV, + DK_ASCII, + DK_ASCIZ, + DK_STRING, + DK_BYTE, + DK_SHORT, + DK_RELOC, + DK_VALUE, + DK_2BYTE, + DK_LONG, + DK_INT, + DK_4BYTE, + DK_QUAD, + DK_8BYTE, + DK_OCTA, + DK_DC, + DK_DC_A, + DK_DC_B, + DK_DC_D, + DK_DC_L, + DK_DC_S, + DK_DC_W, + DK_DC_X, + DK_DCB, + DK_DCB_B, + DK_DCB_D, + DK_DCB_L, + DK_DCB_S, + DK_DCB_W, + DK_DCB_X, + DK_DS, + DK_DS_B, + DK_DS_D, + DK_DS_L, + DK_DS_P, + DK_DS_S, + DK_DS_W, + DK_DS_X, + DK_SINGLE, + DK_FLOAT, + DK_DOUBLE, + DK_ALIGN, + DK_ALIGN32, + DK_BALIGN, + DK_BALIGNW, + DK_BALIGNL, + DK_P2ALIGN, + DK_P2ALIGNW, + DK_P2ALIGNL, + DK_ORG, + DK_FILL, + DK_ENDR, + DK_BUNDLE_ALIGN_MODE, + DK_BUNDLE_LOCK, + DK_BUNDLE_UNLOCK, + DK_ZERO, + DK_EXTERN, + DK_GLOBL, + DK_GLOBAL, + DK_LAZY_REFERENCE, + DK_NO_DEAD_STRIP, + DK_SYMBOL_RESOLVER, + DK_PRIVATE_EXTERN, + DK_REFERENCE, + DK_WEAK_DEFINITION, + DK_WEAK_REFERENCE, + DK_WEAK_DEF_CAN_BE_HIDDEN, + DK_COLD, + DK_COMM, + DK_COMMON, + DK_LCOMM, + DK_ABORT, + DK_INCLUDE, + DK_INCBIN, + DK_CODE16, + DK_CODE16GCC, + DK_REPT, + DK_IRP, + DK_IRPC, + DK_IF, + DK_IFEQ, + DK_IFGE, + DK_IFGT, + DK_IFLE, + DK_IFLT, + DK_IFNE, + DK_IFB, + DK_IFNB, + DK_IFC, + DK_IFEQS, + DK_IFNC, + DK_IFNES, + DK_IFDEF, + DK_IFNDEF, + DK_IFNOTDEF, + DK_ELSEIF, + DK_ELSE, + DK_ENDIF, + DK_SPACE, + DK_SKIP, + DK_FILE, + DK_LINE, + DK_LOC, + DK_STABS, + DK_CV_FILE, + DK_CV_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_MACROS_ON, + DK_MACROS_OFF, + DK_ALTMACRO, + DK_NOALTMACRO, + DK_MACRO, + DK_EXITM, + DK_ENDM, + DK_ENDMACRO, + DK_PURGEM, + DK_SLEB128, + DK_ULEB128, + DK_ERR, + DK_ERROR, + DK_WARNING, + DK_PRINT, + DK_ADDRSIG, + DK_ADDRSIG_SYM, DK_PSEUDO_PROBE, - 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 parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" - bool parseDirectiveValue(StringRef IDVal, - unsigned Size); // ".byte", ".long", ... - bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ... - bool parseDirectiveRealValue(StringRef IDVal, - const fltSemantics &); // ".single", ... - bool parseDirectiveFill(); // ".fill" - bool parseDirectiveZero(); // ".zero" - // ".set", ".equ", ".equiv" - bool parseDirectiveSet(StringRef IDVal, bool allow_redef); - bool parseDirectiveOrg(); // ".org" - // ".align{,32}", ".p2align{,w,l}" - bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize); - - // ".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); - // ".bundle_align_mode" - bool parseDirectiveBundleAlignMode(); - // ".bundle_lock" - bool parseDirectiveBundleLock(); - // ".bundle_unlock" - bool parseDirectiveBundleUnlock(); - - // ".space", ".skip" - bool parseDirectiveSpace(StringRef IDVal); - - // ".dcb" - bool parseDirectiveDCB(StringRef IDVal, unsigned Size); - bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &); - // ".ds" - bool parseDirectiveDS(StringRef IDVal, unsigned Size); - - // .sleb128 (Signed=true) and .uleb128 (Signed=false) - bool parseDirectiveLEB128(bool Signed); - - /// 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 parseDirectiveAbort(); // ".abort" - bool parseDirectiveInclude(); // ".include" - bool parseDirectiveIncbin(); // ".incbin" - - // ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne" - bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind); - // ".ifb" or ".ifnb", depending on ExpectBlank. - bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank); - // ".ifc" or ".ifnc", depending on ExpectEqual. - bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual); - // ".ifeqs" or ".ifnes", depending on ExpectEqual. - bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual); - // ".ifdef" or ".ifndef", depending on expect_defined - bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); - bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" - 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); - - // 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" or ".error" - bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage); - - // ".warning" - bool parseDirectiveWarning(SMLoc DirectiveLoc); - - // .print <double-quotes-string> - bool parseDirectivePrint(SMLoc DirectiveLoc); - + 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 parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" + bool parseDirectiveValue(StringRef IDVal, + unsigned Size); // ".byte", ".long", ... + bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ... + bool parseDirectiveRealValue(StringRef IDVal, + const fltSemantics &); // ".single", ... + bool parseDirectiveFill(); // ".fill" + bool parseDirectiveZero(); // ".zero" + // ".set", ".equ", ".equiv" + bool parseDirectiveSet(StringRef IDVal, bool allow_redef); + bool parseDirectiveOrg(); // ".org" + // ".align{,32}", ".p2align{,w,l}" + bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize); + + // ".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); + // ".bundle_align_mode" + bool parseDirectiveBundleAlignMode(); + // ".bundle_lock" + bool parseDirectiveBundleLock(); + // ".bundle_unlock" + bool parseDirectiveBundleUnlock(); + + // ".space", ".skip" + bool parseDirectiveSpace(StringRef IDVal); + + // ".dcb" + bool parseDirectiveDCB(StringRef IDVal, unsigned Size); + bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &); + // ".ds" + bool parseDirectiveDS(StringRef IDVal, unsigned Size); + + // .sleb128 (Signed=true) and .uleb128 (Signed=false) + bool parseDirectiveLEB128(bool Signed); + + /// 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 parseDirectiveAbort(); // ".abort" + bool parseDirectiveInclude(); // ".include" + bool parseDirectiveIncbin(); // ".incbin" + + // ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne" + bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind); + // ".ifb" or ".ifnb", depending on ExpectBlank. + bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank); + // ".ifc" or ".ifnc", depending on ExpectEqual. + bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual); + // ".ifeqs" or ".ifnes", depending on ExpectEqual. + bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual); + // ".ifdef" or ".ifndef", depending on expect_defined + bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); + bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" + 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); + + // 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" or ".error" + bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage); + + // ".warning" + bool parseDirectiveWarning(SMLoc DirectiveLoc); + + // .print <double-quotes-string> + bool parseDirectivePrint(SMLoc DirectiveLoc); + // .pseudoprobe bool parseDirectivePseudoProbe(); - // Directives to support address-significance tables. - bool parseDirectiveAddrsig(); - bool parseDirectiveAddrsigSym(); - - void initializeDirectiveKindMap(); - void initializeCVDefRangeTypeMap(); -}; - -} // end anonymous namespace - -namespace llvm { - -extern MCAsmParserExtension *createDarwinAsmParser(); -extern MCAsmParserExtension *createELFAsmParser(); -extern MCAsmParserExtension *createCOFFAsmParser(); -extern MCAsmParserExtension *createWasmAsmParser(); - -} // end namespace llvm - -enum { DEFAULT_ADDRSPACE = 0 }; - -AsmParser::AsmParser(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()); + // Directives to support address-significance tables. + bool parseDirectiveAddrsig(); + bool parseDirectiveAddrsigSym(); + + void initializeDirectiveKindMap(); + void initializeCVDefRangeTypeMap(); +}; + +} // end anonymous namespace + +namespace llvm { + +extern MCAsmParserExtension *createDarwinAsmParser(); +extern MCAsmParserExtension *createELFAsmParser(); +extern MCAsmParserExtension *createCOFFAsmParser(); +extern MCAsmParserExtension *createWasmAsmParser(); + +} // end namespace llvm + +enum { DEFAULT_ADDRSPACE = 0 }; + +AsmParser::AsmParser(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()); // Make MCStreamer aware of the StartTokLoc for locations in diagnostics. Out.setStartTokLocPtr(&StartTokLoc); - - // Initialize the platform / file format parser. - switch (Ctx.getObjectFileInfo()->getObjectFileType()) { - case MCObjectFileInfo::IsCOFF: - PlatformParser.reset(createCOFFAsmParser()); - break; - case MCObjectFileInfo::IsMachO: - PlatformParser.reset(createDarwinAsmParser()); - IsDarwin = true; - break; - case MCObjectFileInfo::IsELF: - PlatformParser.reset(createELFAsmParser()); - break; - case MCObjectFileInfo::IsWasm: - PlatformParser.reset(createWasmAsmParser()); - break; - case MCObjectFileInfo::IsXCOFF: - report_fatal_error( - "Need to implement createXCOFFAsmParser for XCOFF format."); - break; - } - - PlatformParser->Initialize(*this); - initializeDirectiveKindMap(); - initializeCVDefRangeTypeMap(); - - NumOfMacroInstantiations = 0; -} - -AsmParser::~AsmParser() { - assert((HadError || ActiveMacros.empty()) && - "Unexpected active macro instantiation!"); - + + // Initialize the platform / file format parser. + switch (Ctx.getObjectFileInfo()->getObjectFileType()) { + case MCObjectFileInfo::IsCOFF: + PlatformParser.reset(createCOFFAsmParser()); + break; + case MCObjectFileInfo::IsMachO: + PlatformParser.reset(createDarwinAsmParser()); + IsDarwin = true; + break; + case MCObjectFileInfo::IsELF: + PlatformParser.reset(createELFAsmParser()); + break; + case MCObjectFileInfo::IsWasm: + PlatformParser.reset(createWasmAsmParser()); + break; + case MCObjectFileInfo::IsXCOFF: + report_fatal_error( + "Need to implement createXCOFFAsmParser for XCOFF format."); + break; + } + + PlatformParser->Initialize(*this); + initializeDirectiveKindMap(); + initializeCVDefRangeTypeMap(); + + NumOfMacroInstantiations = 0; +} + +AsmParser::~AsmParser() { + assert((HadError || ActiveMacros.empty()) && + "Unexpected active macro instantiation!"); + // Remove MCStreamer's reference to the parser SMLoc. Out.setStartTokLocPtr(nullptr); - // Restore the saved diagnostics handler and context for use during - // finalization. - SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext); -} - -void AsmParser::printMacroInstantiations() { - // Print the active macro instantiation stack. - for (std::vector<MacroInstantiation *>::const_reverse_iterator - it = ActiveMacros.rbegin(), - ie = ActiveMacros.rend(); - it != ie; ++it) - printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note, - "while in macro instantiation"); -} - -void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) { - printPendingErrors(); - printMessage(L, SourceMgr::DK_Note, Msg, Range); - printMacroInstantiations(); -} - -bool AsmParser::Warning(SMLoc L, const Twine &Msg, 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 AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) { - HadError = true; - printMessage(L, SourceMgr::DK_Error, Msg, Range); - printMacroInstantiations(); - return true; -} - -bool AsmParser::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 AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, - const MCExpr *Count, SMLoc Loc) { - std::string IncludedFile; - unsigned NewBuf = - SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); - 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 AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) { - CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), - Loc.getPointer()); -} - -const AsmToken &AsmParser::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(); - - // 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 AsmParser::enabledGenDwarfForAssembly() { - // Check whether the user specified -g. - if (!getContext().getGenDwarfForAssembly()) - return false; - // If we haven't encountered any .file directives (which would imply that - // the assembler source was produced with debug info already) then emit one - // describing the assembler source file itself. - if (getContext().getGenDwarfFileNumber() == 0) { - // 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().getCompilationDir(), - FirstCppHashFilename, - /*Cksum=*/None, /*Source=*/None); - const MCDwarfFile &RootFile = - getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile(); - getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective( - /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name, - RootFile.Checksum, RootFile.Source)); - } - return true; -} - -bool AsmParser::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) + // Restore the saved diagnostics handler and context for use during + // finalization. + SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext); +} + +void AsmParser::printMacroInstantiations() { + // Print the active macro instantiation stack. + for (std::vector<MacroInstantiation *>::const_reverse_iterator + it = ActiveMacros.rbegin(), + ie = ActiveMacros.rend(); + it != ie; ++it) + printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note, + "while in macro instantiation"); +} + +void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) { + printPendingErrors(); + printMessage(L, SourceMgr::DK_Note, Msg, Range); + printMacroInstantiations(); +} + +bool AsmParser::Warning(SMLoc L, const Twine &Msg, 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 AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) { + HadError = true; + printMessage(L, SourceMgr::DK_Error, Msg, Range); + printMacroInstantiations(); + return true; +} + +bool AsmParser::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 AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, + const MCExpr *Count, SMLoc Loc) { + std::string IncludedFile; + unsigned NewBuf = + SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); + 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 AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) { + CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), + Loc.getPointer()); +} + +const AsmToken &AsmParser::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(); + + // 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 AsmParser::enabledGenDwarfForAssembly() { + // Check whether the user specified -g. + if (!getContext().getGenDwarfForAssembly()) + return false; + // If we haven't encountered any .file directives (which would imply that + // the assembler source was produced with debug info already) then emit one + // describing the assembler source file itself. + if (getContext().getGenDwarfFileNumber() == 0) { + // 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().getCompilationDir(), + FirstCppHashFilename, + /*Cksum=*/None, /*Source=*/None); + const MCDwarfFile &RootFile = + getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile(); + getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective( + /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name, + RootFile.Checksum, RootFile.Source)); + } + return true; +} + +bool AsmParser::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(Lexer.getLoc()); - - return HadError || getContext().hadError(); -} - -bool AsmParser::checkForValidSection() { - if (!ParsingMSInlineAsm && !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 AsmParser::eatToEndOfStatement() { - while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) - Lexer.Lex(); - - // Eat EOL. - if (Lexer.is(AsmToken::EndOfStatement)) - Lexer.Lex(); -} - -StringRef AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 + + return HadError || getContext().hadError(); +} + +bool AsmParser::checkForValidSection() { + if (!ParsingMSInlineAsm && !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 AsmParser::eatToEndOfStatement() { + while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) + Lexer.Lex(); + + // Eat EOL. + if (Lexer.is(AsmToken::EndOfStatement)) + Lexer.Lex(); +} + +StringRef AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, AsmTypeInfo *TypeInfo) { - 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. + 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, TypeInfo)) - 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. + 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, TypeInfo)) - return true; - Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); - return false; - case AsmToken::Plus: - Lex(); // Eat the operator. + return true; + Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); + return false; + case AsmToken::Plus: + Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) - return true; - Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); - return false; - case AsmToken::Tilde: - Lex(); // Eat the operator. + return true; + Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); + return false; + case AsmToken::Tilde: + Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc, TypeInfo)) - 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 AsmParser::parseExpression(const MCExpr *&Res) { - SMLoc EndLoc; - return parseExpression(Res, EndLoc); -} - -const MCExpr * -AsmParser::applyModifierToExpr(const MCExpr *E, - MCSymbolRefExpr::VariantKind Variant) { - // Ask the target implementation about this expression first. - const MCExpr *NewE = getTargetParser().applyModifierToExpr(E, Variant, Ctx); - if (NewE) - return NewE; - // Recurse over the given expression, rebuilding it to apply the given variant - // if there is exactly one symbol. - switch (E->getKind()) { - case MCExpr::Target: - case MCExpr::Constant: - return nullptr; - - case MCExpr::SymbolRef: { - const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E); - - if (SRE->getKind() != MCSymbolRefExpr::VK_None) { - TokError("invalid variant on expression '" + getTok().getIdentifier() + - "' (already modified)"); - return E; - } - - return MCSymbolRefExpr::create(&SRE->getSymbol(), Variant, getContext()); - } - - case MCExpr::Unary: { - const MCUnaryExpr *UE = cast<MCUnaryExpr>(E); - const MCExpr *Sub = applyModifierToExpr(UE->getSubExpr(), Variant); - if (!Sub) - return nullptr; - return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext()); - } - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(E); - const MCExpr *LHS = applyModifierToExpr(BE->getLHS(), Variant); - const MCExpr *RHS = applyModifierToExpr(BE->getRHS(), Variant); - - if (!LHS && !RHS) - return nullptr; - - if (!LHS) - LHS = BE->getLHS(); - if (!RHS) - RHS = BE->getRHS(); - - return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext()); - } - } - - llvm_unreachable("Invalid expression kind!"); -} - -/// 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 AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { - // Parse the expression. - Res = nullptr; - if (getTargetParser().parsePrimaryExpr(Res, EndLoc) || - parseBinOpRHS(1, Res, EndLoc)) - return true; - - // As a special case, we support 'a op b @ modifier' by rewriting the - // expression to include the modifier. This is inefficient, but in general we - // expect users to use 'a@modifier op b'. - if (Lexer.getKind() == AsmToken::At) { - Lex(); - - if (Lexer.isNot(AsmToken::Identifier)) - return TokError("unexpected symbol modifier following '@'"); - - MCSymbolRefExpr::VariantKind Variant = - MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier()); - if (Variant == MCSymbolRefExpr::VK_Invalid) - return TokError("invalid variant '" + getTok().getIdentifier() + "'"); - - const MCExpr *ModifiedRes = applyModifierToExpr(Res, Variant); - if (!ModifiedRes) { - return TokError("invalid modifier '" + getTok().getIdentifier() + - "' (no symbols present)"); - } - - Res = ModifiedRes; - Lex(); - } - - // 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 AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { - Res = nullptr; - return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc); -} - -bool AsmParser::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 AsmParser::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 getDarwinBinOpPrecedence(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 1; - case AsmToken::PipePipe: - Kind = MCBinaryExpr::LOr; - return 1; - - // Low Precedence: |, &, ^ - case AsmToken::Pipe: - Kind = MCBinaryExpr::Or; - return 2; - case AsmToken::Caret: - Kind = MCBinaryExpr::Xor; - return 2; - case AsmToken::Amp: - Kind = MCBinaryExpr::And; - return 2; - - // Low Intermediate 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; - - // Intermediate Precedence: <<, >> - case AsmToken::LessLess: - Kind = MCBinaryExpr::Shl; - return 4; - case AsmToken::GreaterGreater: - Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr; - return 4; - - // High Intermediate Precedence: +, - - case AsmToken::Plus: - Kind = MCBinaryExpr::Add; - return 5; - case AsmToken::Minus: - Kind = MCBinaryExpr::Sub; - 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; - } -} - + 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 AsmParser::parseExpression(const MCExpr *&Res) { + SMLoc EndLoc; + return parseExpression(Res, EndLoc); +} + +const MCExpr * +AsmParser::applyModifierToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant) { + // Ask the target implementation about this expression first. + const MCExpr *NewE = getTargetParser().applyModifierToExpr(E, Variant, Ctx); + if (NewE) + return NewE; + // Recurse over the given expression, rebuilding it to apply the given variant + // if there is exactly one symbol. + switch (E->getKind()) { + case MCExpr::Target: + case MCExpr::Constant: + return nullptr; + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E); + + if (SRE->getKind() != MCSymbolRefExpr::VK_None) { + TokError("invalid variant on expression '" + getTok().getIdentifier() + + "' (already modified)"); + return E; + } + + return MCSymbolRefExpr::create(&SRE->getSymbol(), Variant, getContext()); + } + + case MCExpr::Unary: { + const MCUnaryExpr *UE = cast<MCUnaryExpr>(E); + const MCExpr *Sub = applyModifierToExpr(UE->getSubExpr(), Variant); + if (!Sub) + return nullptr; + return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext()); + } + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(E); + const MCExpr *LHS = applyModifierToExpr(BE->getLHS(), Variant); + const MCExpr *RHS = applyModifierToExpr(BE->getRHS(), Variant); + + if (!LHS && !RHS) + return nullptr; + + if (!LHS) + LHS = BE->getLHS(); + if (!RHS) + RHS = BE->getRHS(); + + return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext()); + } + } + + llvm_unreachable("Invalid expression kind!"); +} + +/// 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 AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { + // Parse the expression. + Res = nullptr; + if (getTargetParser().parsePrimaryExpr(Res, EndLoc) || + parseBinOpRHS(1, Res, EndLoc)) + return true; + + // As a special case, we support 'a op b @ modifier' by rewriting the + // expression to include the modifier. This is inefficient, but in general we + // expect users to use 'a@modifier op b'. + if (Lexer.getKind() == AsmToken::At) { + Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("unexpected symbol modifier following '@'"); + + MCSymbolRefExpr::VariantKind Variant = + MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier()); + if (Variant == MCSymbolRefExpr::VK_Invalid) + return TokError("invalid variant '" + getTok().getIdentifier() + "'"); + + const MCExpr *ModifiedRes = applyModifierToExpr(Res, Variant); + if (!ModifiedRes) { + return TokError("invalid modifier '" + getTok().getIdentifier() + + "' (no symbols present)"); + } + + Res = ModifiedRes; + Lex(); + } + + // 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 AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { + Res = nullptr; + return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc); +} + +bool AsmParser::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 AsmParser::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 getDarwinBinOpPrecedence(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 1; + case AsmToken::PipePipe: + Kind = MCBinaryExpr::LOr; + return 1; + + // Low Precedence: |, &, ^ + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; + return 2; + case AsmToken::Caret: + Kind = MCBinaryExpr::Xor; + return 2; + case AsmToken::Amp: + Kind = MCBinaryExpr::And; + return 2; + + // Low Intermediate 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; + + // Intermediate Precedence: <<, >> + case AsmToken::LessLess: + Kind = MCBinaryExpr::Shl; + return 4; + case AsmToken::GreaterGreater: + Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr; + return 4; + + // High Intermediate Precedence: +, - + case AsmToken::Plus: + Kind = MCBinaryExpr::Add; + return 5; + case AsmToken::Minus: + Kind = MCBinaryExpr::Sub; + 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; + } +} + static unsigned getGNUBinOpPrecedence(const MCAsmInfo &MAI, 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; - + 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: |, !, &, ^ - // - case AsmToken::Pipe: - Kind = MCBinaryExpr::Or; - return 5; + // + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; + return 5; case AsmToken::Exclaim: // Hack to support ARM compatible aliases (implied 'sp' operand in 'srs*' // instructions like 'srsda #31!') and not parse ! as an infix operator. @@ -1625,1396 +1625,1396 @@ static unsigned getGNUBinOpPrecedence(const MCAsmInfo &MAI, return 0; Kind = MCBinaryExpr::OrNot; 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 AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, - MCBinaryExpr::Opcode &Kind) { - bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr(); - return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr) + 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 AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, + MCBinaryExpr::Opcode &Kind) { + bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr(); + return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr) : getGNUBinOpPrecedence(MAI, K, Kind, ShouldUseLogicalShr); -} - -/// Parse all binary operators with precedence >= 'Precedence'. -/// Res contains the LHS of the expression on input. -bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, - SMLoc &EndLoc) { - 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 AsmParser::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. - AsmToken ID = getTok(); - SMLoc IDLoc = ID.getLoc(); - StringRef IDVal; - int64_t LocalLabelVal = -1; +} + +/// Parse all binary operators with precedence >= 'Precedence'. +/// Res contains the LHS of the expression on input. +bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, + SMLoc &EndLoc) { + 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 AsmParser::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. + AsmToken ID = getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal; + int64_t LocalLabelVal = -1; StartTokLoc = ID.getLoc(); - if (Lexer.is(AsmToken::HashDirective)) - return parseCppHashLineFilenameComment(IDLoc, - !isInsideMacroInstantiation()); - - // 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 (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_IFEQ: - case DK_IFGE: - case DK_IFGT: - case DK_IFLE: - case DK_IFLT: - case DK_IFNE: - return parseDirectiveIf(IDLoc, DirKind); - case DK_IFB: - return parseDirectiveIfb(IDLoc, true); - case DK_IFNB: - return parseDirectiveIfb(IDLoc, false); - case DK_IFC: - return parseDirectiveIfc(IDLoc, true); - case DK_IFEQS: - return parseDirectiveIfeqs(IDLoc, true); - case DK_IFNC: - return parseDirectiveIfc(IDLoc, false); - case DK_IFNES: - return parseDirectiveIfeqs(IDLoc, false); - case DK_IFDEF: - return parseDirectiveIfdef(IDLoc, true); - case DK_IFNDEF: - case DK_IFNOTDEF: - return parseDirectiveIfdef(IDLoc, false); - case DK_ELSEIF: - return parseDirectiveElseIf(IDLoc); - 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 (ParsingMSInlineAsm && 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().isParsingMSInlineAsm()) - 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; - } - - case AsmToken::Equal: - if (!getTargetParser().equalIsAsmAssignment()) - break; - // identifier '=' ... -> assignment statement - Lex(); - - return parseAssignment(IDVal, true); - - 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. - - // Directives start with "." - if (IDVal.startswith(".") && IDVal != ".") { - // There are several entities interested in parsing directives: - // - // 1. The target-specific assembly parser. Some directives are target - // specific or may potentially behave differently on certain targets. - // 2. Asm parser extensions. For example, platform-specific parsers - // (like the ELF parser) register themselves as extensions. - // 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()); - - SMLoc StartTokLoc = getTok().getLoc(); - bool TPDirectiveReturn = getTargetParser().ParseDirective(ID); - - if (hasPendingError()) - return true; - // Currently the return value should be true if we are - // uninterested but as this is at odds with the standard parsing - // convention (return true = error) we have instances of a parsed - // directive that fails returning true as an error. Catch these - // cases as best as possible errors here. - if (TPDirectiveReturn && StartTokLoc != getTok().getLoc()) - return true; - // Return if we did some parsing or believe we succeeded. - if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc()) - return false; - - // Next, check the extension directive map to see if any extension has - // registered itself to parse this directive. - std::pair<MCAsmParserExtension *, DirectiveHandler> Handler = - ExtensionDirectiveMap.lookup(IDVal); - if (Handler.first) - return (*Handler.second)(Handler.first, IDVal, IDLoc); - - // 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_SET: - case DK_EQU: - return parseDirectiveSet(IDVal, true); - case DK_EQUIV: - return parseDirectiveSet(IDVal, false); - case DK_ASCII: - return parseDirectiveAscii(IDVal, false); - case DK_ASCIZ: - case DK_STRING: - return parseDirectiveAscii(IDVal, true); - case DK_BYTE: - case DK_DC_B: - return parseDirectiveValue(IDVal, 1); - case DK_DC: - case DK_DC_W: - case DK_SHORT: - case DK_VALUE: - case DK_2BYTE: - return parseDirectiveValue(IDVal, 2); - case DK_LONG: - case DK_INT: - case DK_4BYTE: - case DK_DC_L: - return parseDirectiveValue(IDVal, 4); - case DK_QUAD: - case DK_8BYTE: - return parseDirectiveValue(IDVal, 8); - case DK_DC_A: - return parseDirectiveValue( - IDVal, getContext().getAsmInfo()->getCodePointerSize()); - case DK_OCTA: - return parseDirectiveOctaValue(IDVal); - case DK_SINGLE: - case DK_FLOAT: - case DK_DC_S: - return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle()); - case DK_DOUBLE: - case DK_DC_D: - return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble()); - case DK_ALIGN: { - bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); - return parseDirectiveAlign(IsPow2, /*ExprSize=*/1); - } - case DK_ALIGN32: { - bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); - return parseDirectiveAlign(IsPow2, /*ExprSize=*/4); - } - case DK_BALIGN: - return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); - case DK_BALIGNW: - return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); - case DK_BALIGNL: - return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); - case DK_P2ALIGN: - return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); - case DK_P2ALIGNW: - return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); - case DK_P2ALIGNL: - return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); - case DK_ORG: - return parseDirectiveOrg(); - case DK_FILL: - return parseDirectiveFill(); - case DK_ZERO: - return parseDirectiveZero(); - case DK_EXTERN: - eatToEndOfStatement(); // .extern is the default, ignore it. - return false; - case DK_GLOBL: - case DK_GLOBAL: - return parseDirectiveSymbolAttribute(MCSA_Global); - case DK_LAZY_REFERENCE: - return parseDirectiveSymbolAttribute(MCSA_LazyReference); - case DK_NO_DEAD_STRIP: - return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip); - case DK_SYMBOL_RESOLVER: - return parseDirectiveSymbolAttribute(MCSA_SymbolResolver); - case DK_PRIVATE_EXTERN: - return parseDirectiveSymbolAttribute(MCSA_PrivateExtern); - case DK_REFERENCE: - return parseDirectiveSymbolAttribute(MCSA_Reference); - case DK_WEAK_DEFINITION: - return parseDirectiveSymbolAttribute(MCSA_WeakDefinition); - case DK_WEAK_REFERENCE: - return parseDirectiveSymbolAttribute(MCSA_WeakReference); - case DK_WEAK_DEF_CAN_BE_HIDDEN: - return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate); - case DK_COLD: - return parseDirectiveSymbolAttribute(MCSA_Cold); - case DK_COMM: - case DK_COMMON: - return parseDirectiveComm(/*IsLocal=*/false); - case DK_LCOMM: - return parseDirectiveComm(/*IsLocal=*/true); - case DK_ABORT: - return parseDirectiveAbort(); - case DK_INCLUDE: - return parseDirectiveInclude(); - case DK_INCBIN: - return parseDirectiveIncbin(); - case DK_CODE16: - case DK_CODE16GCC: - return TokError(Twine(IDVal) + - " not currently supported for this target"); - 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_BUNDLE_ALIGN_MODE: - return parseDirectiveBundleAlignMode(); - case DK_BUNDLE_LOCK: - return parseDirectiveBundleLock(); - case DK_BUNDLE_UNLOCK: - return parseDirectiveBundleUnlock(); - case DK_SLEB128: - return parseDirectiveLEB128(true); - case DK_ULEB128: - return parseDirectiveLEB128(false); - case DK_SPACE: - case DK_SKIP: - return parseDirectiveSpace(IDVal); - 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_MACROS_ON: - case DK_MACROS_OFF: - return parseDirectiveMacrosOnOff(IDVal); - case DK_MACRO: - return parseDirectiveMacro(IDLoc); - case DK_ALTMACRO: - case DK_NOALTMACRO: - return parseDirectiveAltmacro(IDVal); - case DK_EXITM: - return parseDirectiveExitMacro(IDVal); - case DK_ENDM: - case DK_ENDMACRO: - return parseDirectiveEndMacro(IDVal); - case DK_PURGEM: - return parseDirectivePurgeMacro(IDLoc); - case DK_END: - return parseDirectiveEnd(IDLoc); - case DK_ERR: - return parseDirectiveError(IDLoc, false); - case DK_ERROR: - return parseDirectiveError(IDLoc, true); - case DK_WARNING: - return parseDirectiveWarning(IDLoc); - case DK_RELOC: - return parseDirectiveReloc(IDLoc); - case DK_DCB: - case DK_DCB_W: - return parseDirectiveDCB(IDVal, 2); - case DK_DCB_B: - return parseDirectiveDCB(IDVal, 1); - case DK_DCB_D: - return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble()); - case DK_DCB_L: - return parseDirectiveDCB(IDVal, 4); - case DK_DCB_S: - return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle()); - case DK_DC_X: - case DK_DCB_X: - return TokError(Twine(IDVal) + - " not currently supported for this target"); - case DK_DS: - case DK_DS_W: - return parseDirectiveDS(IDVal, 2); - case DK_DS_B: - return parseDirectiveDS(IDVal, 1); - case DK_DS_D: - return parseDirectiveDS(IDVal, 8); - case DK_DS_L: - case DK_DS_S: - return parseDirectiveDS(IDVal, 4); - case DK_DS_P: - case DK_DS_X: - return parseDirectiveDS(IDVal, 12); - case DK_PRINT: - return parseDirectivePrint(IDLoc); - case DK_ADDRSIG: - return parseDirectiveAddrsig(); - case DK_ADDRSIG_SYM: - return parseDirectiveAddrsigSym(); + if (Lexer.is(AsmToken::HashDirective)) + return parseCppHashLineFilenameComment(IDLoc, + !isInsideMacroInstantiation()); + + // 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 (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_IFEQ: + case DK_IFGE: + case DK_IFGT: + case DK_IFLE: + case DK_IFLT: + case DK_IFNE: + return parseDirectiveIf(IDLoc, DirKind); + case DK_IFB: + return parseDirectiveIfb(IDLoc, true); + case DK_IFNB: + return parseDirectiveIfb(IDLoc, false); + case DK_IFC: + return parseDirectiveIfc(IDLoc, true); + case DK_IFEQS: + return parseDirectiveIfeqs(IDLoc, true); + case DK_IFNC: + return parseDirectiveIfc(IDLoc, false); + case DK_IFNES: + return parseDirectiveIfeqs(IDLoc, false); + case DK_IFDEF: + return parseDirectiveIfdef(IDLoc, true); + case DK_IFNDEF: + case DK_IFNOTDEF: + return parseDirectiveIfdef(IDLoc, false); + case DK_ELSEIF: + return parseDirectiveElseIf(IDLoc); + 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 (ParsingMSInlineAsm && 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().isParsingMSInlineAsm()) + 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; + } + + case AsmToken::Equal: + if (!getTargetParser().equalIsAsmAssignment()) + break; + // identifier '=' ... -> assignment statement + Lex(); + + return parseAssignment(IDVal, true); + + 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. + + // Directives start with "." + if (IDVal.startswith(".") && IDVal != ".") { + // There are several entities interested in parsing directives: + // + // 1. The target-specific assembly parser. Some directives are target + // specific or may potentially behave differently on certain targets. + // 2. Asm parser extensions. For example, platform-specific parsers + // (like the ELF parser) register themselves as extensions. + // 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()); + + SMLoc StartTokLoc = getTok().getLoc(); + bool TPDirectiveReturn = getTargetParser().ParseDirective(ID); + + if (hasPendingError()) + return true; + // Currently the return value should be true if we are + // uninterested but as this is at odds with the standard parsing + // convention (return true = error) we have instances of a parsed + // directive that fails returning true as an error. Catch these + // cases as best as possible errors here. + if (TPDirectiveReturn && StartTokLoc != getTok().getLoc()) + return true; + // Return if we did some parsing or believe we succeeded. + if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc()) + return false; + + // Next, check the extension directive map to see if any extension has + // registered itself to parse this directive. + std::pair<MCAsmParserExtension *, DirectiveHandler> Handler = + ExtensionDirectiveMap.lookup(IDVal); + if (Handler.first) + return (*Handler.second)(Handler.first, IDVal, IDLoc); + + // 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_SET: + case DK_EQU: + return parseDirectiveSet(IDVal, true); + case DK_EQUIV: + return parseDirectiveSet(IDVal, false); + case DK_ASCII: + return parseDirectiveAscii(IDVal, false); + case DK_ASCIZ: + case DK_STRING: + return parseDirectiveAscii(IDVal, true); + case DK_BYTE: + case DK_DC_B: + return parseDirectiveValue(IDVal, 1); + case DK_DC: + case DK_DC_W: + case DK_SHORT: + case DK_VALUE: + case DK_2BYTE: + return parseDirectiveValue(IDVal, 2); + case DK_LONG: + case DK_INT: + case DK_4BYTE: + case DK_DC_L: + return parseDirectiveValue(IDVal, 4); + case DK_QUAD: + case DK_8BYTE: + return parseDirectiveValue(IDVal, 8); + case DK_DC_A: + return parseDirectiveValue( + IDVal, getContext().getAsmInfo()->getCodePointerSize()); + case DK_OCTA: + return parseDirectiveOctaValue(IDVal); + case DK_SINGLE: + case DK_FLOAT: + case DK_DC_S: + return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle()); + case DK_DOUBLE: + case DK_DC_D: + return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble()); + case DK_ALIGN: { + bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); + return parseDirectiveAlign(IsPow2, /*ExprSize=*/1); + } + case DK_ALIGN32: { + bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); + return parseDirectiveAlign(IsPow2, /*ExprSize=*/4); + } + case DK_BALIGN: + return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); + case DK_BALIGNW: + return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); + case DK_BALIGNL: + return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); + case DK_P2ALIGN: + return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); + case DK_P2ALIGNW: + return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); + case DK_P2ALIGNL: + return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + case DK_ORG: + return parseDirectiveOrg(); + case DK_FILL: + return parseDirectiveFill(); + case DK_ZERO: + return parseDirectiveZero(); + case DK_EXTERN: + eatToEndOfStatement(); // .extern is the default, ignore it. + return false; + case DK_GLOBL: + case DK_GLOBAL: + return parseDirectiveSymbolAttribute(MCSA_Global); + case DK_LAZY_REFERENCE: + return parseDirectiveSymbolAttribute(MCSA_LazyReference); + case DK_NO_DEAD_STRIP: + return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip); + case DK_SYMBOL_RESOLVER: + return parseDirectiveSymbolAttribute(MCSA_SymbolResolver); + case DK_PRIVATE_EXTERN: + return parseDirectiveSymbolAttribute(MCSA_PrivateExtern); + case DK_REFERENCE: + return parseDirectiveSymbolAttribute(MCSA_Reference); + case DK_WEAK_DEFINITION: + return parseDirectiveSymbolAttribute(MCSA_WeakDefinition); + case DK_WEAK_REFERENCE: + return parseDirectiveSymbolAttribute(MCSA_WeakReference); + case DK_WEAK_DEF_CAN_BE_HIDDEN: + return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate); + case DK_COLD: + return parseDirectiveSymbolAttribute(MCSA_Cold); + case DK_COMM: + case DK_COMMON: + return parseDirectiveComm(/*IsLocal=*/false); + case DK_LCOMM: + return parseDirectiveComm(/*IsLocal=*/true); + case DK_ABORT: + return parseDirectiveAbort(); + case DK_INCLUDE: + return parseDirectiveInclude(); + case DK_INCBIN: + return parseDirectiveIncbin(); + case DK_CODE16: + case DK_CODE16GCC: + return TokError(Twine(IDVal) + + " not currently supported for this target"); + 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_BUNDLE_ALIGN_MODE: + return parseDirectiveBundleAlignMode(); + case DK_BUNDLE_LOCK: + return parseDirectiveBundleLock(); + case DK_BUNDLE_UNLOCK: + return parseDirectiveBundleUnlock(); + case DK_SLEB128: + return parseDirectiveLEB128(true); + case DK_ULEB128: + return parseDirectiveLEB128(false); + case DK_SPACE: + case DK_SKIP: + return parseDirectiveSpace(IDVal); + 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_MACROS_ON: + case DK_MACROS_OFF: + return parseDirectiveMacrosOnOff(IDVal); + case DK_MACRO: + return parseDirectiveMacro(IDLoc); + case DK_ALTMACRO: + case DK_NOALTMACRO: + return parseDirectiveAltmacro(IDVal); + case DK_EXITM: + return parseDirectiveExitMacro(IDVal); + case DK_ENDM: + case DK_ENDMACRO: + return parseDirectiveEndMacro(IDVal); + case DK_PURGEM: + return parseDirectivePurgeMacro(IDLoc); + case DK_END: + return parseDirectiveEnd(IDLoc); + case DK_ERR: + return parseDirectiveError(IDLoc, false); + case DK_ERROR: + return parseDirectiveError(IDLoc, true); + case DK_WARNING: + return parseDirectiveWarning(IDLoc); + case DK_RELOC: + return parseDirectiveReloc(IDLoc); + case DK_DCB: + case DK_DCB_W: + return parseDirectiveDCB(IDVal, 2); + case DK_DCB_B: + return parseDirectiveDCB(IDVal, 1); + case DK_DCB_D: + return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble()); + case DK_DCB_L: + return parseDirectiveDCB(IDVal, 4); + case DK_DCB_S: + return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle()); + case DK_DC_X: + case DK_DCB_X: + return TokError(Twine(IDVal) + + " not currently supported for this target"); + case DK_DS: + case DK_DS_W: + return parseDirectiveDS(IDVal, 2); + case DK_DS_B: + return parseDirectiveDS(IDVal, 1); + case DK_DS_D: + return parseDirectiveDS(IDVal, 8); + case DK_DS_L: + case DK_DS_S: + return parseDirectiveDS(IDVal, 4); + case DK_DS_P: + case DK_DS_X: + return parseDirectiveDS(IDVal, 12); + case DK_PRINT: + return parseDirectivePrint(IDLoc); + case DK_ADDRSIG: + return parseDirectiveAddrsig(); + case DK_ADDRSIG_SYM: + return parseDirectiveAddrsigSym(); case DK_PSEUDO_PROBE: return parseDirectivePseudoProbe(); - } - - return Error(IDLoc, "unknown directive"); - } - - // __asm _emit or __asm __emit - if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" || - IDVal == "_EMIT" || IDVal == "__EMIT")) - return parseDirectiveMSEmit(IDLoc, Info, IDVal.size()); - - // __asm align - if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN")) - return parseDirectiveMSAlign(IDLoc, Info); - - if (ParsingMSInlineAsm && (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.ParsedOperands); - 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().isParsingMSInlineAsm())) - return true; - } - return false; -} - -// Parse and erase curly braces marking block start/end -bool -AsmParser::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.getPointer()); - return true; -} - -/// parseCppHashLineFilenameComment as this: -/// ::= # number "filename" -bool AsmParser::parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo) { - 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(); - - if (!SaveLocInfo) - return false; - - // 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 AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { - const AsmParser *Parser = static_cast<const AsmParser *>(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 -// difference being that that function accepts '@' as part of identifiers and -// we can't do that. AsmLexer.cpp should probably be changed to handle -// '@' as a special case when needed. -static bool isIdentifierChar(char c) { - return isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$' || - c == '.'; -} - -bool AsmParser::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 differently on Darwin: - // gas accepts no arguments and does no substitutions - while (!Body.empty()) { - // Scan for the next substitution. - std::size_t End = Body.size(), Pos = 0; - 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 AsmParser::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 AsmParser::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().getAssemblerPtr())) - 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 AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { - // Arbitrarily limit macro nesting depth (default matches 'as'). We can - // eliminate this, although we should protect against infinite loops. - 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 AsmParser::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(); -} - -bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip) { - MCSymbol *Sym; - const MCExpr *Value; - if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value)) - return true; - - if (!Sym) { - // In the case where we parse an expression starting with a '.', we will - // not generate an error, nor will we create a symbol. In this case we - // should just return out. - return false; - } - - // Do the assignment. - Out.emitAssignment(Sym, Value); - if (NoDeadStrip) - Out.emitSymbolAttribute(Sym, MCSA_NoDeadStrip); - - return false; -} - -/// parseIdentifier: -/// ::= identifier -/// ::= string -bool AsmParser::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) && Buf[0].isNot(AsmToken::Integer)) - return true; - - // We have a '$' or '@' followed by an identifier or integer token, 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().getString().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; -} - -/// parseDirectiveSet: -/// ::= .equ identifier ',' expression -/// ::= .equiv identifier ',' expression -/// ::= .set identifier ',' expression -bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) { - StringRef Name; - if (check(parseIdentifier(Name), "expected identifier") || - parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - return false; -} - -bool AsmParser::parseEscapedString(std::string &Data) { - 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 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: + } + + return Error(IDLoc, "unknown directive"); + } + + // __asm _emit or __asm __emit + if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" || + IDVal == "_EMIT" || IDVal == "__EMIT")) + return parseDirectiveMSEmit(IDLoc, Info, IDVal.size()); + + // __asm align + if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN")) + return parseDirectiveMSAlign(IDLoc, Info); + + if (ParsingMSInlineAsm && (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.ParsedOperands); + 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().isParsingMSInlineAsm())) + return true; + } + return false; +} + +// Parse and erase curly braces marking block start/end +bool +AsmParser::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.getPointer()); + return true; +} + +/// parseCppHashLineFilenameComment as this: +/// ::= # number "filename" +bool AsmParser::parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo) { + 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(); + + if (!SaveLocInfo) + return false; + + // 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 AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { + const AsmParser *Parser = static_cast<const AsmParser *>(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 +// difference being that that function accepts '@' as part of identifiers and +// we can't do that. AsmLexer.cpp should probably be changed to handle +// '@' as a special case when needed. +static bool isIdentifierChar(char c) { + return isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$' || + c == '.'; +} + +bool AsmParser::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 differently on Darwin: + // gas accepts no arguments and does no substitutions + while (!Body.empty()) { + // Scan for the next substitution. + std::size_t End = Body.size(), Pos = 0; + 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 AsmParser::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 AsmParser::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().getAssemblerPtr())) + 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 AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { + // Arbitrarily limit macro nesting depth (default matches 'as'). We can + // eliminate this, although we should protect against infinite loops. + 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 AsmParser::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(); +} + +bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, + bool NoDeadStrip) { + MCSymbol *Sym; + const MCExpr *Value; + if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, + Value)) + return true; + + if (!Sym) { + // In the case where we parse an expression starting with a '.', we will + // not generate an error, nor will we create a symbol. In this case we + // should just return out. + return false; + } + + // Do the assignment. + Out.emitAssignment(Sym, Value); + if (NoDeadStrip) + Out.emitSymbolAttribute(Sym, MCSA_NoDeadStrip); + + return false; +} + +/// parseIdentifier: +/// ::= identifier +/// ::= string +bool AsmParser::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) && Buf[0].isNot(AsmToken::Integer)) + return true; + + // We have a '$' or '@' followed by an identifier or integer token, 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().getString().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; +} + +/// parseDirectiveSet: +/// ::= .equ identifier ',' expression +/// ::= .equiv identifier ',' expression +/// ::= .set identifier ',' expression +bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) { + StringRef Name; + if (check(parseIdentifier(Name), "expected identifier") || + parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} + +bool AsmParser::parseEscapedString(std::string &Data) { + 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 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 [ "string"+ ( , "string"+ )* ] /// ::= ( .asciz | .string ) [ "string" ( , "string" )* ] -bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { - auto parseOp = [&]() -> bool { - std::string Data; +bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { + auto parseOp = [&]() -> bool { + std::string Data; if (checkForValidSection()) - return true; + return true; // Only support spaces as separators for .ascii directive for now. See the // discusssion at https://reviews.llvm.org/D91460 for more details. do { @@ -3022,2775 +3022,2775 @@ bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { return true; getStreamer().emitBytes(Data); } while (!ZeroTerminated && getTok().is(AsmToken::String)); - if (ZeroTerminated) - getStreamer().emitBytes(StringRef("\0", 1)); - return false; - }; - - if (parseMany(parseOp)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - return false; -} - -/// parseDirectiveReloc -/// ::= .reloc expression , identifier [ , expression ] -bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { - const MCExpr *Offset; - const MCExpr *Expr = nullptr; - SMLoc OffsetLoc = Lexer.getTok().getLoc(); - - if (parseExpression(Offset)) - return true; - if (parseToken(AsmToken::Comma, "expected comma") || - check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) - return true; - - SMLoc NameLoc = Lexer.getTok().getLoc(); - StringRef Name = Lexer.getTok().getIdentifier(); - Lex(); - - if (Lexer.is(AsmToken::Comma)) { - Lex(); - SMLoc ExprLoc = Lexer.getLoc(); - if (parseExpression(Expr)) - return true; - - MCValue Value; - if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) - return Error(ExprLoc, "expression must be relocatable"); - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in .reloc directive")) - return true; - - const MCTargetAsmParser &MCT = getTargetParser(); - const MCSubtargetInfo &STI = MCT.getSTI(); - if (Optional<std::pair<bool, std::string>> Err = - getStreamer().emitRelocDirective(*Offset, Name, Expr, DirectiveLoc, - STI)) - return Error(Err->first ? NameLoc : OffsetLoc, Err->second); - - return false; -} - -/// parseDirectiveValue -/// ::= (.byte | .short | ... ) [ expression (, expression)* ] -bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { - auto parseOp = [&]() -> bool { - const MCExpr *Value; - SMLoc ExprLoc = getLexer().getLoc(); - if (checkForValidSection() || parseExpression(Value)) - return true; - // Special case constant expressions to match code generator. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { - assert(Size <= 8 && "Invalid size"); - uint64_t IntValue = MCE->getValue(); - if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) - return Error(ExprLoc, "out of range literal value"); - getStreamer().emitIntValue(IntValue, Size); - } else - getStreamer().emitValue(Value, Size, ExprLoc); - return false; - }; - - if (parseMany(parseOp)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - return false; -} - -static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) { - if (Asm.getTok().isNot(AsmToken::Integer) && - Asm.getTok().isNot(AsmToken::BigNum)) - return Asm.TokError("unknown token in expression"); - SMLoc ExprLoc = Asm.getTok().getLoc(); - APInt IntValue = Asm.getTok().getAPIntVal(); - Asm.Lex(); - if (!IntValue.isIntN(128)) - return Asm.Error(ExprLoc, "out of range literal value"); - if (!IntValue.isIntN(64)) { - hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); - lo = IntValue.getLoBits(64).getZExtValue(); - } else { - hi = 0; - lo = IntValue.getZExtValue(); - } - return false; -} - -/// ParseDirectiveOctaValue -/// ::= .octa [ hexconstant (, hexconstant)* ] - -bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) { - auto parseOp = [&]() -> bool { - if (checkForValidSection()) - return true; - uint64_t hi, lo; - if (parseHexOcta(*this, hi, lo)) - return true; - if (MAI.isLittleEndian()) { - getStreamer().emitInt64(lo); - getStreamer().emitInt64(hi); - } else { - getStreamer().emitInt64(hi); - getStreamer().emitInt64(lo); - } - return false; - }; - - if (parseMany(parseOp)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - return false; -} - -bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { - // We don't truly support arithmetic on floating point expressions, so we - // have to manually parse unary prefixes. - bool IsNeg = false; - if (getLexer().is(AsmToken::Minus)) { - Lexer.Lex(); - IsNeg = true; - } else if (getLexer().is(AsmToken::Plus)) - Lexer.Lex(); - - 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 -/// ::= (.single | .double) [ expression (, expression)* ] -bool AsmParser::parseDirectiveRealValue(StringRef IDVal, - const fltSemantics &Semantics) { - auto parseOp = [&]() -> bool { - APInt AsInt; - if (checkForValidSection() || parseRealValue(Semantics, AsInt)) - return true; - getStreamer().emitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - return false; - }; - - if (parseMany(parseOp)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - return false; -} - -/// parseDirectiveZero -/// ::= .zero expression -bool AsmParser::parseDirectiveZero() { - SMLoc NumBytesLoc = Lexer.getLoc(); - const MCExpr *NumBytes; - if (checkForValidSection() || parseExpression(NumBytes)) - return true; - - int64_t Val = 0; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - if (parseAbsoluteExpression(Val)) - return true; - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.zero' directive")) - return true; - getStreamer().emitFill(*NumBytes, Val, NumBytesLoc); - - return false; -} - -/// parseDirectiveFill -/// ::= .fill expression [ , expression [ , expression ] ] -bool AsmParser::parseDirectiveFill() { - SMLoc NumValuesLoc = Lexer.getLoc(); - const MCExpr *NumValues; - if (checkForValidSection() || parseExpression(NumValues)) - return true; - - int64_t FillSize = 1; - int64_t FillExpr = 0; - - SMLoc SizeLoc, ExprLoc; - - if (parseOptionalToken(AsmToken::Comma)) { - SizeLoc = getTok().getLoc(); - if (parseAbsoluteExpression(FillSize)) - return true; - if (parseOptionalToken(AsmToken::Comma)) { - ExprLoc = getTok().getLoc(); - if (parseAbsoluteExpression(FillExpr)) - return true; - } - } - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.fill' directive")) - return true; - - if (FillSize < 0) { - Warning(SizeLoc, "'.fill' directive with negative size has no effect"); - return false; - } - if (FillSize > 8) { - Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8"); - FillSize = 8; - } - - if (!isUInt<32>(FillExpr) && FillSize > 4) - Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits"); - - getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc); - - return false; -} - -/// parseDirectiveOrg -/// ::= .org expression [ , expression ] -bool AsmParser::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 [ , expression [ , expression ]] -bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { - SMLoc AlignmentLoc = getLexer().getLoc(); - int64_t Alignment; - SMLoc MaxBytesLoc; - bool HasFillExpr = false; - int64_t FillExpr = 0; - int64_t MaxBytesToFill = 0; - - auto parseAlign = [&]() -> bool { - if (parseAbsoluteExpression(Alignment)) - return true; - if (parseOptionalToken(AsmToken::Comma)) { - // The fill expression can be omitted while specifying a maximum number of - // alignment bytes, e.g: - // .align 3,,4 - if (getTok().isNot(AsmToken::Comma)) { - HasFillExpr = true; - if (parseAbsoluteExpression(FillExpr)) - return true; - } - if (parseOptionalToken(AsmToken::Comma)) - if (parseTokenLoc(MaxBytesLoc) || - parseAbsoluteExpression(MaxBytesToFill)) - return true; - } - return parseToken(AsmToken::EndOfStatement); - }; - - if (checkForValidSection()) - return addErrorSuffix(" in directive"); - // Ignore empty '.p2align' directives for GNU-as compatibility - if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) { - Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored"); - return parseToken(AsmToken::EndOfStatement); - } - if (parseAlign()) - return addErrorSuffix(" in directive"); - - // Always emit an alignment here even if we thrown an error. - bool ReturnVal = false; - - // Compute alignment in bytes. - if (IsPow2) { - // FIXME: Diagnose overflow. - if (Alignment >= 32) { - ReturnVal |= Error(AlignmentLoc, "invalid alignment value"); - Alignment = 31; - } - - Alignment = 1ULL << Alignment; - } else { - // 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"); + if (ZeroTerminated) + getStreamer().emitBytes(StringRef("\0", 1)); + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} + +/// parseDirectiveReloc +/// ::= .reloc expression , identifier [ , expression ] +bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { + const MCExpr *Offset; + const MCExpr *Expr = nullptr; + SMLoc OffsetLoc = Lexer.getTok().getLoc(); + + if (parseExpression(Offset)) + return true; + if (parseToken(AsmToken::Comma, "expected comma") || + check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) + return true; + + SMLoc NameLoc = Lexer.getTok().getLoc(); + StringRef Name = Lexer.getTok().getIdentifier(); + Lex(); + + if (Lexer.is(AsmToken::Comma)) { + Lex(); + SMLoc ExprLoc = Lexer.getLoc(); + if (parseExpression(Expr)) + return true; + + MCValue Value; + if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) + return Error(ExprLoc, "expression must be relocatable"); + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in .reloc directive")) + return true; + + const MCTargetAsmParser &MCT = getTargetParser(); + const MCSubtargetInfo &STI = MCT.getSTI(); + if (Optional<std::pair<bool, std::string>> Err = + getStreamer().emitRelocDirective(*Offset, Name, Expr, DirectiveLoc, + STI)) + return Error(Err->first ? NameLoc : OffsetLoc, Err->second); + + return false; +} + +/// parseDirectiveValue +/// ::= (.byte | .short | ... ) [ expression (, expression)* ] +bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { + auto parseOp = [&]() -> bool { + const MCExpr *Value; + SMLoc ExprLoc = getLexer().getLoc(); + if (checkForValidSection() || parseExpression(Value)) + return true; + // Special case constant expressions to match code generator. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { + assert(Size <= 8 && "Invalid size"); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) + return Error(ExprLoc, "out of range literal value"); + getStreamer().emitIntValue(IntValue, Size); + } else + getStreamer().emitValue(Value, Size, ExprLoc); + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} + +static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) { + if (Asm.getTok().isNot(AsmToken::Integer) && + Asm.getTok().isNot(AsmToken::BigNum)) + return Asm.TokError("unknown token in expression"); + SMLoc ExprLoc = Asm.getTok().getLoc(); + APInt IntValue = Asm.getTok().getAPIntVal(); + Asm.Lex(); + if (!IntValue.isIntN(128)) + return Asm.Error(ExprLoc, "out of range literal value"); + if (!IntValue.isIntN(64)) { + hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); + lo = IntValue.getLoBits(64).getZExtValue(); + } else { + hi = 0; + lo = IntValue.getZExtValue(); + } + return false; +} + +/// ParseDirectiveOctaValue +/// ::= .octa [ hexconstant (, hexconstant)* ] + +bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) { + auto parseOp = [&]() -> bool { + if (checkForValidSection()) + return true; + uint64_t hi, lo; + if (parseHexOcta(*this, hi, lo)) + return true; + if (MAI.isLittleEndian()) { + getStreamer().emitInt64(lo); + getStreamer().emitInt64(hi); + } else { + getStreamer().emitInt64(hi); + getStreamer().emitInt64(lo); + } + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} + +bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { + // We don't truly support arithmetic on floating point expressions, so we + // have to manually parse unary prefixes. + bool IsNeg = false; + if (getLexer().is(AsmToken::Minus)) { + Lexer.Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) + Lexer.Lex(); + + 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 +/// ::= (.single | .double) [ expression (, expression)* ] +bool AsmParser::parseDirectiveRealValue(StringRef IDVal, + const fltSemantics &Semantics) { + auto parseOp = [&]() -> bool { + APInt AsInt; + if (checkForValidSection() || parseRealValue(Semantics, AsInt)) + return true; + getStreamer().emitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + return false; +} + +/// parseDirectiveZero +/// ::= .zero expression +bool AsmParser::parseDirectiveZero() { + SMLoc NumBytesLoc = Lexer.getLoc(); + const MCExpr *NumBytes; + if (checkForValidSection() || parseExpression(NumBytes)) + return true; + + int64_t Val = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (parseAbsoluteExpression(Val)) + return true; + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.zero' directive")) + return true; + getStreamer().emitFill(*NumBytes, Val, NumBytesLoc); + + return false; +} + +/// parseDirectiveFill +/// ::= .fill expression [ , expression [ , expression ] ] +bool AsmParser::parseDirectiveFill() { + SMLoc NumValuesLoc = Lexer.getLoc(); + const MCExpr *NumValues; + if (checkForValidSection() || parseExpression(NumValues)) + return true; + + int64_t FillSize = 1; + int64_t FillExpr = 0; + + SMLoc SizeLoc, ExprLoc; + + if (parseOptionalToken(AsmToken::Comma)) { + SizeLoc = getTok().getLoc(); + if (parseAbsoluteExpression(FillSize)) + return true; + if (parseOptionalToken(AsmToken::Comma)) { + ExprLoc = getTok().getLoc(); + if (parseAbsoluteExpression(FillExpr)) + return true; + } + } + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.fill' directive")) + return true; + + if (FillSize < 0) { + Warning(SizeLoc, "'.fill' directive with negative size has no effect"); + return false; + } + if (FillSize > 8) { + Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8"); + FillSize = 8; + } + + if (!isUInt<32>(FillExpr) && FillSize > 4) + Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits"); + + getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc); + + return false; +} + +/// parseDirectiveOrg +/// ::= .org expression [ , expression ] +bool AsmParser::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 [ , expression [ , expression ]] +bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + SMLoc AlignmentLoc = getLexer().getLoc(); + int64_t Alignment; + SMLoc MaxBytesLoc; + bool HasFillExpr = false; + int64_t FillExpr = 0; + int64_t MaxBytesToFill = 0; + + auto parseAlign = [&]() -> bool { + if (parseAbsoluteExpression(Alignment)) + return true; + if (parseOptionalToken(AsmToken::Comma)) { + // The fill expression can be omitted while specifying a maximum number of + // alignment bytes, e.g: + // .align 3,,4 + if (getTok().isNot(AsmToken::Comma)) { + HasFillExpr = true; + if (parseAbsoluteExpression(FillExpr)) + return true; + } + if (parseOptionalToken(AsmToken::Comma)) + if (parseTokenLoc(MaxBytesLoc) || + parseAbsoluteExpression(MaxBytesToFill)) + return true; + } + return parseToken(AsmToken::EndOfStatement); + }; + + if (checkForValidSection()) + return addErrorSuffix(" in directive"); + // Ignore empty '.p2align' directives for GNU-as compatibility + if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) { + Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored"); + return parseToken(AsmToken::EndOfStatement); + } + if (parseAlign()) + return addErrorSuffix(" in directive"); + + // Always emit an alignment here even if we thrown an error. + bool ReturnVal = false; + + // Compute alignment in bytes. + if (IsPow2) { + // FIXME: Diagnose overflow. + if (Alignment >= 32) { + ReturnVal |= Error(AlignmentLoc, "invalid alignment value"); + Alignment = 31; + } + + Alignment = 1ULL << Alignment; + } else { + // 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"); if (!isUInt<32>(Alignment)) ReturnVal |= Error(AlignmentLoc, "alignment must be smaller than 2**32"); - } - - // Diagnose non-sensical max bytes to align. - if (MaxBytesLoc.isValid()) { - if (MaxBytesToFill < 1) { - ReturnVal |= Error(MaxBytesLoc, - "alignment directive can never be satisfied in this " - "many bytes, ignoring maximum bytes expression"); - MaxBytesToFill = 0; - } - - if (MaxBytesToFill >= Alignment) { - Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and " - "has no effect"); - MaxBytesToFill = 0; - } - } - - // 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"); - bool UseCodeAlign = Section->UseCodeAlign(); - if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && - ValueSize == 1 && UseCodeAlign) { - getStreamer().emitCodeAlignment(Alignment, MaxBytesToFill); - } else { - // FIXME: Target specific behavior about how the "extra" bytes are filled. - getStreamer().emitValueToAlignment(Alignment, FillExpr, ValueSize, - MaxBytesToFill); - } - - return ReturnVal; -} - -/// parseDirectiveFile -/// ::= .file filename -/// ::= .file number [directory] filename [md5 checksum] [source source-text] -bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { - // FIXME: I'm not sure what this is. - int64_t FileNumber = -1; - 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 different 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 AsmParser::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 AsmParser::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(); - } - - auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags(); - unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT; - 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 AsmParser::parseDirectiveStabs() { - return TokError("unsupported directive '.stabs'"); -} - -/// parseDirectiveCVFile -/// ::= .cv_file number filename [checksum] [checksumkind] -bool AsmParser::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>(ChecksumKind))) - return Error(FileNumberLoc, "file number already allocated"); - - return false; -} - -bool AsmParser::parseCVFunctionId(int64_t &FunctionId, - StringRef DirectiveName) { - SMLoc Loc; - return parseTokenLoc(Loc) || - parseIntToken(FunctionId, "expected function id in '" + DirectiveName + - "' directive") || - check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc, - "expected function id within range [0, UINT_MAX)"); -} - -bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) { - SMLoc Loc; - return parseTokenLoc(Loc) || - parseIntToken(FileNumber, "expected integer in '" + DirectiveName + - "' directive") || - check(FileNumber < 1, Loc, "file number less than one in '" + - DirectiveName + "' directive") || - check(!getCVContext().isValidFileNumber(FileNumber), Loc, - "unassigned file number in '" + DirectiveName + "' directive"); -} - -/// parseDirectiveCVFuncId -/// ::= .cv_func_id FunctionId -/// -/// Introduces a function ID that can be used with .cv_loc. -bool AsmParser::parseDirectiveCVFuncId() { - SMLoc FunctionIdLoc = getTok().getLoc(); - int64_t FunctionId; - - if (parseCVFunctionId(FunctionId, ".cv_func_id") || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cv_func_id' directive")) - return true; - - if (!getStreamer().EmitCVFuncIdDirective(FunctionId)) - return Error(FunctionIdLoc, "function id already allocated"); - - return false; -} - -/// parseDirectiveCVInlineSiteId -/// ::= .cv_inline_site_id FunctionId -/// "within" IAFunc -/// "inlined_at" IAFile IALine [IACol] -/// -/// Introduces a function ID that can be used with .cv_loc. Includes "inlined -/// at" source location information for use in the line table of the caller, -/// whether the caller is a real function or another inlined call site. -bool AsmParser::parseDirectiveCVInlineSiteId() { - SMLoc FunctionIdLoc = getTok().getLoc(); - int64_t FunctionId; - int64_t IAFunc; - int64_t IAFile; - int64_t IALine; - int64_t IACol = 0; - - // FunctionId - if (parseCVFunctionId(FunctionId, ".cv_inline_site_id")) - return true; - - // "within" - if (check((getLexer().isNot(AsmToken::Identifier) || - getTok().getIdentifier() != "within"), - "expected 'within' identifier in '.cv_inline_site_id' directive")) - return true; - Lex(); - - // IAFunc - if (parseCVFunctionId(IAFunc, ".cv_inline_site_id")) - return true; - - // "inlined_at" - if (check((getLexer().isNot(AsmToken::Identifier) || - getTok().getIdentifier() != "inlined_at"), - "expected 'inlined_at' identifier in '.cv_inline_site_id' " - "directive") ) - return true; - Lex(); - - // IAFile IALine - if (parseCVFileId(IAFile, ".cv_inline_site_id") || - parseIntToken(IALine, "expected line number after 'inlined_at'")) - return true; - - // [IACol] - if (getLexer().is(AsmToken::Integer)) { - IACol = getTok().getIntVal(); - Lex(); - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cv_inline_site_id' directive")) - return true; - - if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, - IALine, IACol, FunctionIdLoc)) - return Error(FunctionIdLoc, "function id already allocated"); - - return false; -} - -/// 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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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().emitInt32(Insertion.second); - return false; -} - -/// parseDirectiveCVStringTable -/// ::= .cv_stringtable -bool AsmParser::parseDirectiveCVStringTable() { - getStreamer().emitCVStringTableDirective(); - return false; -} - -/// parseDirectiveCVFileChecksums -/// ::= .cv_filechecksums -bool AsmParser::parseDirectiveCVFileChecksums() { - getStreamer().emitCVFileChecksumsDirective(); - return false; -} - -/// parseDirectiveCVFileChecksumOffset -/// ::= .cv_filechecksumoffset fileno -bool AsmParser::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 AsmParser::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 AsmParser::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; - } - + } + + // Diagnose non-sensical max bytes to align. + if (MaxBytesLoc.isValid()) { + if (MaxBytesToFill < 1) { + ReturnVal |= Error(MaxBytesLoc, + "alignment directive can never be satisfied in this " + "many bytes, ignoring maximum bytes expression"); + MaxBytesToFill = 0; + } + + if (MaxBytesToFill >= Alignment) { + Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and " + "has no effect"); + MaxBytesToFill = 0; + } + } + + // 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"); + bool UseCodeAlign = Section->UseCodeAlign(); + if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && + ValueSize == 1 && UseCodeAlign) { + getStreamer().emitCodeAlignment(Alignment, MaxBytesToFill); + } else { + // FIXME: Target specific behavior about how the "extra" bytes are filled. + getStreamer().emitValueToAlignment(Alignment, FillExpr, ValueSize, + MaxBytesToFill); + } + + return ReturnVal; +} + +/// parseDirectiveFile +/// ::= .file filename +/// ::= .file number [directory] filename [md5 checksum] [source source-text] +bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { + // FIXME: I'm not sure what this is. + int64_t FileNumber = -1; + 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 different 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 AsmParser::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 AsmParser::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(); + } + + auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags(); + unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT; + 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 AsmParser::parseDirectiveStabs() { + return TokError("unsupported directive '.stabs'"); +} + +/// parseDirectiveCVFile +/// ::= .cv_file number filename [checksum] [checksumkind] +bool AsmParser::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>(ChecksumKind))) + return Error(FileNumberLoc, "file number already allocated"); + + return false; +} + +bool AsmParser::parseCVFunctionId(int64_t &FunctionId, + StringRef DirectiveName) { + SMLoc Loc; + return parseTokenLoc(Loc) || + parseIntToken(FunctionId, "expected function id in '" + DirectiveName + + "' directive") || + check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc, + "expected function id within range [0, UINT_MAX)"); +} + +bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) { + SMLoc Loc; + return parseTokenLoc(Loc) || + parseIntToken(FileNumber, "expected integer in '" + DirectiveName + + "' directive") || + check(FileNumber < 1, Loc, "file number less than one in '" + + DirectiveName + "' directive") || + check(!getCVContext().isValidFileNumber(FileNumber), Loc, + "unassigned file number in '" + DirectiveName + "' directive"); +} + +/// parseDirectiveCVFuncId +/// ::= .cv_func_id FunctionId +/// +/// Introduces a function ID that can be used with .cv_loc. +bool AsmParser::parseDirectiveCVFuncId() { + SMLoc FunctionIdLoc = getTok().getLoc(); + int64_t FunctionId; + + if (parseCVFunctionId(FunctionId, ".cv_func_id") || + parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_func_id' directive")) + return true; + + if (!getStreamer().EmitCVFuncIdDirective(FunctionId)) + return Error(FunctionIdLoc, "function id already allocated"); + + return false; +} + +/// parseDirectiveCVInlineSiteId +/// ::= .cv_inline_site_id FunctionId +/// "within" IAFunc +/// "inlined_at" IAFile IALine [IACol] +/// +/// Introduces a function ID that can be used with .cv_loc. Includes "inlined +/// at" source location information for use in the line table of the caller, +/// whether the caller is a real function or another inlined call site. +bool AsmParser::parseDirectiveCVInlineSiteId() { + SMLoc FunctionIdLoc = getTok().getLoc(); + int64_t FunctionId; + int64_t IAFunc; + int64_t IAFile; + int64_t IALine; + int64_t IACol = 0; + + // FunctionId + if (parseCVFunctionId(FunctionId, ".cv_inline_site_id")) + return true; + + // "within" + if (check((getLexer().isNot(AsmToken::Identifier) || + getTok().getIdentifier() != "within"), + "expected 'within' identifier in '.cv_inline_site_id' directive")) + return true; + Lex(); + + // IAFunc + if (parseCVFunctionId(IAFunc, ".cv_inline_site_id")) + return true; + + // "inlined_at" + if (check((getLexer().isNot(AsmToken::Identifier) || + getTok().getIdentifier() != "inlined_at"), + "expected 'inlined_at' identifier in '.cv_inline_site_id' " + "directive") ) + return true; + Lex(); + + // IAFile IALine + if (parseCVFileId(IAFile, ".cv_inline_site_id") || + parseIntToken(IALine, "expected line number after 'inlined_at'")) + return true; + + // [IACol] + if (getLexer().is(AsmToken::Integer)) { + IACol = getTok().getIntVal(); + Lex(); + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cv_inline_site_id' directive")) + return true; + + if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, + IALine, IACol, FunctionIdLoc)) + return Error(FunctionIdLoc, "function id already allocated"); + + return false; +} + +/// 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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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().emitInt32(Insertion.second); + return false; +} + +/// parseDirectiveCVStringTable +/// ::= .cv_stringtable +bool AsmParser::parseDirectiveCVStringTable() { + getStreamer().emitCVStringTableDirective(); + return false; +} + +/// parseDirectiveCVFileChecksums +/// ::= .cv_filechecksums +bool AsmParser::parseDirectiveCVFileChecksums() { + getStreamer().emitCVFileChecksumsDirective(); + return false; +} + +/// parseDirectiveCVFileChecksumOffset +/// ::= .cv_filechecksumoffset fileno +bool AsmParser::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 AsmParser::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 AsmParser::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; + } + if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.cfi_sections' directive"); - getStreamer().emitCFISections(EH, Debug); - return false; -} - -/// parseDirectiveCFIStartProc -/// ::= .cfi_startproc [simple] -bool AsmParser::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 AsmParser::parseDirectiveCFIEndProc() { + getStreamer().emitCFISections(EH, Debug); + return false; +} + +/// parseDirectiveCFIStartProc +/// ::= .cfi_startproc [simple] +bool AsmParser::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 AsmParser::parseDirectiveCFIEndProc() { if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.cfi_endproc' directive"); - getStreamer().emitCFIEndProc(); - return false; -} - -/// parse register name or number. -bool AsmParser::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 AsmParser::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 AsmParser::parseDirectiveCFIDefCfaOffset() { - int64_t Offset = 0; - if (parseAbsoluteExpression(Offset)) - return true; - - getStreamer().emitCFIDefCfaOffset(Offset); - return false; -} - -/// parseDirectiveCFIRegister -/// ::= .cfi_register register, register -bool AsmParser::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 AsmParser::parseDirectiveCFIWindowSave() { - getStreamer().emitCFIWindowSave(); - return false; -} - -/// parseDirectiveCFIAdjustCfaOffset -/// ::= .cfi_adjust_cfa_offset adjustment -bool AsmParser::parseDirectiveCFIAdjustCfaOffset() { - int64_t Adjustment = 0; - if (parseAbsoluteExpression(Adjustment)) - return true; - - getStreamer().emitCFIAdjustCfaOffset(Adjustment); - return false; -} - -/// parseDirectiveCFIDefCfaRegister -/// ::= .cfi_def_cfa_register register -bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) { - int64_t Register = 0; - if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) - return true; - - getStreamer().emitCFIDefCfaRegister(Register); - return false; -} - -/// parseDirectiveCFIOffset -/// ::= .cfi_offset register, offset -bool AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::parseDirectiveCFIRememberState() { - getStreamer().emitCFIRememberState(); - return false; -} - -/// parseDirectiveCFIRestoreState -/// ::= .cfi_remember_state -bool AsmParser::parseDirectiveCFIRestoreState() { - getStreamer().emitCFIRestoreState(); - return false; -} - -/// parseDirectiveCFISameValue -/// ::= .cfi_same_value register -bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) { - int64_t Register = 0; - - if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) - return true; - - getStreamer().emitCFISameValue(Register); - return false; -} - -/// parseDirectiveCFIRestore -/// ::= .cfi_restore register -bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) { - int64_t Register = 0; - if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) - return true; - - getStreamer().emitCFIRestore(Register); - return false; -} - -/// parseDirectiveCFIEscape -/// ::= .cfi_escape expression[,...] -bool AsmParser::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 AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) { - int64_t Register = 0; - if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) - return true; - getStreamer().emitCFIReturnColumn(Register); - return false; -} - -/// parseDirectiveCFISignalFrame -/// ::= .cfi_signal_frame -bool AsmParser::parseDirectiveCFISignalFrame() { - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.cfi_signal_frame'")) - return true; - - getStreamer().emitCFISignalFrame(); - return false; -} - -/// parseDirectiveCFIUndefined -/// ::= .cfi_undefined register -bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) { - int64_t Register = 0; - - if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) - return true; - - getStreamer().emitCFIUndefined(Register); - return false; -} - -/// parseDirectiveAltmacro -/// ::= .altmacro -/// ::= .noaltmacro -bool AsmParser::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 AsmParser::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 AsmParser::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 the last parameter"); - - 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 or the start of a - // preprocessor line marker. - 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; - } - } else if (Lexer.is(AsmToken::HashDirective)) { - (void)parseCppHashLineFilenameComment(getLexer().getLoc()); - } - - // 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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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; -} - -/// parseDirectiveBundleAlignMode -/// ::= {.bundle_align_mode} expression -bool AsmParser::parseDirectiveBundleAlignMode() { - // Expect a single argument: an expression that evaluates to a constant - // in the inclusive range 0-30. - SMLoc ExprLoc = getLexer().getLoc(); - int64_t AlignSizePow2; - if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) || - parseToken(AsmToken::EndOfStatement, "unexpected token after expression " - "in '.bundle_align_mode' " - "directive") || - check(AlignSizePow2 < 0 || AlignSizePow2 > 30, ExprLoc, - "invalid bundle alignment size (expected between 0 and 30)")) - return true; - - // Because of AlignSizePow2's verified range we can safely truncate it to - // unsigned. - getStreamer().emitBundleAlignMode(static_cast<unsigned>(AlignSizePow2)); - return false; -} - -/// parseDirectiveBundleLock -/// ::= {.bundle_lock} [align_to_end] -bool AsmParser::parseDirectiveBundleLock() { - if (checkForValidSection()) - return true; - bool AlignToEnd = false; - - StringRef Option; - SMLoc Loc = getTok().getLoc(); - const char *kInvalidOptionError = - "invalid option for '.bundle_lock' directive"; - - if (!parseOptionalToken(AsmToken::EndOfStatement)) { - if (check(parseIdentifier(Option), Loc, kInvalidOptionError) || - check(Option != "align_to_end", Loc, kInvalidOptionError) || - parseToken(AsmToken::EndOfStatement, - "unexpected token after '.bundle_lock' directive option")) - return true; - AlignToEnd = true; - } - - getStreamer().emitBundleLock(AlignToEnd); - return false; -} - -/// parseDirectiveBundleLock -/// ::= {.bundle_lock} -bool AsmParser::parseDirectiveBundleUnlock() { - if (checkForValidSection() || - parseToken(AsmToken::EndOfStatement, - "unexpected token in '.bundle_unlock' directive")) - return true; - - getStreamer().emitBundleUnlock(); - return false; -} - -/// parseDirectiveSpace -/// ::= (.skip | .space) expression [ , expression ] -bool AsmParser::parseDirectiveSpace(StringRef IDVal) { - SMLoc NumBytesLoc = Lexer.getLoc(); - const MCExpr *NumBytes; - if (checkForValidSection() || parseExpression(NumBytes)) - return true; - - int64_t FillExpr = 0; - if (parseOptionalToken(AsmToken::Comma)) - if (parseAbsoluteExpression(FillExpr)) - return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); - - // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. - getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc); - - return false; -} - -/// parseDirectiveDCB -/// ::= .dcb.{b, l, w} expression, expression -bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) { - SMLoc NumValuesLoc = Lexer.getLoc(); - int64_t NumValues; - if (checkForValidSection() || parseAbsoluteExpression(NumValues)) - return true; - - if (NumValues < 0) { - Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); - return false; - } - - if (parseToken(AsmToken::Comma, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - - const MCExpr *Value; - SMLoc ExprLoc = getLexer().getLoc(); - if (parseExpression(Value)) - return true; - - // Special case constant expressions to match code generator. - if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { - assert(Size <= 8 && "Invalid size"); - uint64_t IntValue = MCE->getValue(); - if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) - return Error(ExprLoc, "literal value out of range for directive"); - for (uint64_t i = 0, e = NumValues; i != e; ++i) - getStreamer().emitIntValue(IntValue, Size); - } else { - for (uint64_t i = 0, e = NumValues; i != e; ++i) - getStreamer().emitValue(Value, Size, ExprLoc); - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - - return false; -} - -/// parseDirectiveRealDCB -/// ::= .dcb.{d, s} expression, expression -bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) { - SMLoc NumValuesLoc = Lexer.getLoc(); - int64_t NumValues; - if (checkForValidSection() || parseAbsoluteExpression(NumValues)) - return true; - - if (NumValues < 0) { - Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); - return false; - } - - if (parseToken(AsmToken::Comma, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - - APInt AsInt; - if (parseRealValue(Semantics, AsInt)) - return true; - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - - for (uint64_t i = 0, e = NumValues; i != e; ++i) - getStreamer().emitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - - return false; -} - -/// parseDirectiveDS -/// ::= .ds.{b, d, l, p, s, w, x} expression -bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) { - SMLoc NumValuesLoc = Lexer.getLoc(); - int64_t NumValues; - if (checkForValidSection() || parseAbsoluteExpression(NumValues)) - return true; - - if (NumValues < 0) { - Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); - return false; - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '" + Twine(IDVal) + "' directive")) - return true; - - for (uint64_t i = 0, e = NumValues; i != e; ++i) - getStreamer().emitFill(Size, 0); - - return false; -} - -/// parseDirectiveLEB128 -/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ] -bool AsmParser::parseDirectiveLEB128(bool Signed) { - if (checkForValidSection()) - return true; - - auto parseOp = [&]() -> bool { - const MCExpr *Value; - if (parseExpression(Value)) - return true; - if (Signed) - getStreamer().emitSLEB128Value(Value); - else - getStreamer().emitULEB128Value(Value); - return false; - }; - - if (parseMany(parseOp)) - return addErrorSuffix(" in directive"); - - return false; -} - -/// parseDirectiveSymbolAttribute -/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] -bool AsmParser::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 AsmParser::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; -} - -/// parseDirectiveAbort -/// ::= .abort [... message ...] -bool AsmParser::parseDirectiveAbort() { - // FIXME: Use loc from directive. - SMLoc Loc = getLexer().getLoc(); - - StringRef Str = parseStringToEndOfStatement(); - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.abort' directive")) - return true; - - if (Str.empty()) - return Error(Loc, ".abort detected. Assembly stopping."); - else - return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); - // FIXME: Actually abort assembly here. - - return false; -} - -/// parseDirectiveInclude -/// ::= .include "filename" -bool AsmParser::parseDirectiveInclude() { - // Allow the strings to have escaped octal character sequence. - std::string Filename; - SMLoc IncludeLoc = getTok().getLoc(); - - if (check(getTok().isNot(AsmToken::String), - "expected string in '.include' directive") || - parseEscapedString(Filename) || - 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; -} - -/// parseDirectiveIncbin -/// ::= .incbin "filename" [ , skip [ , count ] ] -bool AsmParser::parseDirectiveIncbin() { - // Allow the strings to have escaped octal character sequence. - std::string Filename; - SMLoc IncbinLoc = getTok().getLoc(); - if (check(getTok().isNot(AsmToken::String), - "expected string in '.incbin' directive") || - parseEscapedString(Filename)) - return true; - - int64_t Skip = 0; - const MCExpr *Count = nullptr; - SMLoc SkipLoc, CountLoc; - if (parseOptionalToken(AsmToken::Comma)) { - // The skip expression can be omitted while specifying the count, e.g: - // .incbin "filename",,4 - if (getTok().isNot(AsmToken::Comma)) { - if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip)) - return true; - } - if (parseOptionalToken(AsmToken::Comma)) { - CountLoc = getTok().getLoc(); - if (parseExpression(Count)) - return true; - } - } - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.incbin' directive")) - return true; - - if (check(Skip < 0, SkipLoc, "skip is negative")) - return true; - - // Attempt to process the included file. - if (processIncbinFile(Filename, Skip, Count, CountLoc)) - return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); - return false; -} - -/// parseDirectiveIf -/// ::= .if{,eq,ge,gt,le,lt,ne} expression -bool AsmParser::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: - case DK_IFNE: - break; - case DK_IFEQ: - ExprValue = ExprValue == 0; - break; - case DK_IFGE: - ExprValue = ExprValue >= 0; - break; - case DK_IFGT: - ExprValue = ExprValue > 0; - break; - case DK_IFLE: - ExprValue = ExprValue <= 0; - break; - case DK_IFLT: - ExprValue = ExprValue < 0; - break; - } - - TheCondState.CondMet = ExprValue; - TheCondState.Ignore = !TheCondState.CondMet; - } - - return false; -} - -/// parseDirectiveIfb -/// ::= .ifb string -bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) { - TheCondStack.push_back(TheCondState); - TheCondState.TheCond = AsmCond::IfCond; - - if (TheCondState.Ignore) { - eatToEndOfStatement(); - } else { - StringRef Str = parseStringToEndOfStatement(); - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.ifb' directive")) - return true; - - TheCondState.CondMet = ExpectBlank == Str.empty(); - TheCondState.Ignore = !TheCondState.CondMet; - } - - return false; -} - -/// parseDirectiveIfc -/// ::= .ifc string1, string2 -/// ::= .ifnc string1, string2 -bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) { - TheCondStack.push_back(TheCondState); - TheCondState.TheCond = AsmCond::IfCond; - - if (TheCondState.Ignore) { - eatToEndOfStatement(); - } else { - StringRef Str1 = parseStringToComma(); - - if (parseToken(AsmToken::Comma, "unexpected token in '.ifc' directive")) - return true; - - StringRef Str2 = parseStringToEndOfStatement(); - - if (parseToken(AsmToken::EndOfStatement, - "unexpected token in '.ifc' directive")) - return true; - - TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim()); - TheCondState.Ignore = !TheCondState.CondMet; - } - - return false; -} - -/// parseDirectiveIfeqs -/// ::= .ifeqs string1, string2 -bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) { - if (Lexer.isNot(AsmToken::String)) { - if (ExpectEqual) - return TokError("expected string parameter for '.ifeqs' directive"); - return TokError("expected string parameter for '.ifnes' directive"); - } - - StringRef String1 = getTok().getStringContents(); - Lex(); - - if (Lexer.isNot(AsmToken::Comma)) { - if (ExpectEqual) - return TokError( - "expected comma after first string for '.ifeqs' directive"); - return TokError("expected comma after first string for '.ifnes' directive"); - } - - Lex(); - - if (Lexer.isNot(AsmToken::String)) { - if (ExpectEqual) - return TokError("expected string parameter for '.ifeqs' directive"); - return TokError("expected string parameter for '.ifnes' directive"); - } - - StringRef String2 = getTok().getStringContents(); - Lex(); - - TheCondStack.push_back(TheCondState); - TheCondState.TheCond = AsmCond::IfCond; - TheCondState.CondMet = ExpectEqual == (String1 == String2); - TheCondState.Ignore = !TheCondState.CondMet; - - return false; -} - -/// parseDirectiveIfdef -/// ::= .ifdef symbol -bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { - StringRef Name; - TheCondStack.push_back(TheCondState); - TheCondState.TheCond = AsmCond::IfCond; - - if (TheCondState.Ignore) { - eatToEndOfStatement(); - } else { - if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") || - parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifdef'")) - return true; - - MCSymbol *Sym = getContext().lookupSymbol(Name); - - if (expect_defined) - TheCondState.CondMet = (Sym && !Sym->isUndefined(false)); - else - TheCondState.CondMet = (!Sym || Sym->isUndefined(false)); - TheCondState.Ignore = !TheCondState.CondMet; - } - - return false; -} - -/// parseDirectiveElseIf -/// ::= .elseif expression -bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) { - 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; - - TheCondState.CondMet = ExprValue; - TheCondState.Ignore = !TheCondState.CondMet; - } - - return false; -} - -/// parseDirectiveElse -/// ::= .else -bool AsmParser::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 a .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 AsmParser::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 -/// ::= .error [string] -bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) { - if (!TheCondStack.empty()) { - if (TheCondStack.back().Ignore) { - eatToEndOfStatement(); - return false; - } - } - - if (!WithMessage) - return Error(L, ".err encountered"); - - StringRef Message = ".error directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (Lexer.isNot(AsmToken::String)) - return TokError(".error argument must be a string"); - - Message = getTok().getStringContents(); - Lex(); - } - - return Error(L, Message); -} - -/// parseDirectiveWarning -/// ::= .warning [string] -bool AsmParser::parseDirectiveWarning(SMLoc L) { - if (!TheCondStack.empty()) { - if (TheCondStack.back().Ignore) { - eatToEndOfStatement(); - return false; - } - } - - StringRef Message = ".warning directive invoked in source file"; - - if (!parseOptionalToken(AsmToken::EndOfStatement)) { - if (Lexer.isNot(AsmToken::String)) - return TokError(".warning argument must be a string"); - - Message = getTok().getStringContents(); - Lex(); - if (parseToken(AsmToken::EndOfStatement, - "expected end of statement in '.warning' directive")) - return true; - } - - return Warning(L, Message); -} - -/// parseDirectiveEndIf -/// ::= .endif -bool AsmParser::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 AsmParser::initializeDirectiveKindMap() { - /* Lookup will be done with the directive - * converted to lower case, so all these - * keys should be lower case. - * (target specific directives are handled - * elsewhere) - */ - DirectiveKindMap[".set"] = DK_SET; - DirectiveKindMap[".equ"] = DK_EQU; - DirectiveKindMap[".equiv"] = DK_EQUIV; - DirectiveKindMap[".ascii"] = DK_ASCII; - DirectiveKindMap[".asciz"] = DK_ASCIZ; - DirectiveKindMap[".string"] = DK_STRING; - DirectiveKindMap[".byte"] = DK_BYTE; - DirectiveKindMap[".short"] = DK_SHORT; - DirectiveKindMap[".value"] = DK_VALUE; - DirectiveKindMap[".2byte"] = DK_2BYTE; - DirectiveKindMap[".long"] = DK_LONG; - DirectiveKindMap[".int"] = DK_INT; - DirectiveKindMap[".4byte"] = DK_4BYTE; - DirectiveKindMap[".quad"] = DK_QUAD; - DirectiveKindMap[".8byte"] = DK_8BYTE; - DirectiveKindMap[".octa"] = DK_OCTA; - DirectiveKindMap[".single"] = DK_SINGLE; - DirectiveKindMap[".float"] = DK_FLOAT; - DirectiveKindMap[".double"] = DK_DOUBLE; - DirectiveKindMap[".align"] = DK_ALIGN; - DirectiveKindMap[".align32"] = DK_ALIGN32; - DirectiveKindMap[".balign"] = DK_BALIGN; - DirectiveKindMap[".balignw"] = DK_BALIGNW; - DirectiveKindMap[".balignl"] = DK_BALIGNL; - DirectiveKindMap[".p2align"] = DK_P2ALIGN; - DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW; - DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL; - DirectiveKindMap[".org"] = DK_ORG; - DirectiveKindMap[".fill"] = DK_FILL; - DirectiveKindMap[".zero"] = DK_ZERO; - DirectiveKindMap[".extern"] = DK_EXTERN; - DirectiveKindMap[".globl"] = DK_GLOBL; - DirectiveKindMap[".global"] = DK_GLOBAL; - DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE; - DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP; - DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER; - DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN; - DirectiveKindMap[".reference"] = DK_REFERENCE; - DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION; - DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE; - DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN; - DirectiveKindMap[".cold"] = DK_COLD; - DirectiveKindMap[".comm"] = DK_COMM; - DirectiveKindMap[".common"] = DK_COMMON; - DirectiveKindMap[".lcomm"] = DK_LCOMM; - DirectiveKindMap[".abort"] = DK_ABORT; - DirectiveKindMap[".include"] = DK_INCLUDE; - DirectiveKindMap[".incbin"] = DK_INCBIN; - DirectiveKindMap[".code16"] = DK_CODE16; - DirectiveKindMap[".code16gcc"] = DK_CODE16GCC; - DirectiveKindMap[".rept"] = DK_REPT; - DirectiveKindMap[".rep"] = DK_REPT; - DirectiveKindMap[".irp"] = DK_IRP; - DirectiveKindMap[".irpc"] = DK_IRPC; - DirectiveKindMap[".endr"] = DK_ENDR; - DirectiveKindMap[".bundle_align_mode"] = DK_BUNDLE_ALIGN_MODE; - DirectiveKindMap[".bundle_lock"] = DK_BUNDLE_LOCK; - DirectiveKindMap[".bundle_unlock"] = DK_BUNDLE_UNLOCK; - DirectiveKindMap[".if"] = DK_IF; - DirectiveKindMap[".ifeq"] = DK_IFEQ; - DirectiveKindMap[".ifge"] = DK_IFGE; - DirectiveKindMap[".ifgt"] = DK_IFGT; - DirectiveKindMap[".ifle"] = DK_IFLE; - DirectiveKindMap[".iflt"] = DK_IFLT; - DirectiveKindMap[".ifne"] = DK_IFNE; - DirectiveKindMap[".ifb"] = DK_IFB; - DirectiveKindMap[".ifnb"] = DK_IFNB; - DirectiveKindMap[".ifc"] = DK_IFC; - DirectiveKindMap[".ifeqs"] = DK_IFEQS; - DirectiveKindMap[".ifnc"] = DK_IFNC; - DirectiveKindMap[".ifnes"] = DK_IFNES; - DirectiveKindMap[".ifdef"] = DK_IFDEF; - DirectiveKindMap[".ifndef"] = DK_IFNDEF; - DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF; - DirectiveKindMap[".elseif"] = DK_ELSEIF; - DirectiveKindMap[".else"] = DK_ELSE; - DirectiveKindMap[".end"] = DK_END; - DirectiveKindMap[".endif"] = DK_ENDIF; - DirectiveKindMap[".skip"] = DK_SKIP; - DirectiveKindMap[".space"] = DK_SPACE; - 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[".sleb128"] = DK_SLEB128; - DirectiveKindMap[".uleb128"] = DK_ULEB128; - 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[".macros_on"] = DK_MACROS_ON; - DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; - DirectiveKindMap[".macro"] = DK_MACRO; - DirectiveKindMap[".exitm"] = DK_EXITM; - DirectiveKindMap[".endm"] = DK_ENDM; - DirectiveKindMap[".endmacro"] = DK_ENDMACRO; - DirectiveKindMap[".purgem"] = DK_PURGEM; - DirectiveKindMap[".err"] = DK_ERR; - DirectiveKindMap[".error"] = DK_ERROR; - DirectiveKindMap[".warning"] = DK_WARNING; - DirectiveKindMap[".altmacro"] = DK_ALTMACRO; - DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO; - DirectiveKindMap[".reloc"] = DK_RELOC; - DirectiveKindMap[".dc"] = DK_DC; - DirectiveKindMap[".dc.a"] = DK_DC_A; - DirectiveKindMap[".dc.b"] = DK_DC_B; - DirectiveKindMap[".dc.d"] = DK_DC_D; - DirectiveKindMap[".dc.l"] = DK_DC_L; - DirectiveKindMap[".dc.s"] = DK_DC_S; - DirectiveKindMap[".dc.w"] = DK_DC_W; - DirectiveKindMap[".dc.x"] = DK_DC_X; - DirectiveKindMap[".dcb"] = DK_DCB; - DirectiveKindMap[".dcb.b"] = DK_DCB_B; - DirectiveKindMap[".dcb.d"] = DK_DCB_D; - DirectiveKindMap[".dcb.l"] = DK_DCB_L; - DirectiveKindMap[".dcb.s"] = DK_DCB_S; - DirectiveKindMap[".dcb.w"] = DK_DCB_W; - DirectiveKindMap[".dcb.x"] = DK_DCB_X; - DirectiveKindMap[".ds"] = DK_DS; - DirectiveKindMap[".ds.b"] = DK_DS_B; - DirectiveKindMap[".ds.d"] = DK_DS_D; - DirectiveKindMap[".ds.l"] = DK_DS_L; - DirectiveKindMap[".ds.p"] = DK_DS_P; - DirectiveKindMap[".ds.s"] = DK_DS_S; - DirectiveKindMap[".ds.w"] = DK_DS_W; - DirectiveKindMap[".ds.x"] = DK_DS_X; - DirectiveKindMap[".print"] = DK_PRINT; - DirectiveKindMap[".addrsig"] = DK_ADDRSIG; - DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; + getStreamer().emitCFIEndProc(); + return false; +} + +/// parse register name or number. +bool AsmParser::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 AsmParser::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 AsmParser::parseDirectiveCFIDefCfaOffset() { + int64_t Offset = 0; + if (parseAbsoluteExpression(Offset)) + return true; + + getStreamer().emitCFIDefCfaOffset(Offset); + return false; +} + +/// parseDirectiveCFIRegister +/// ::= .cfi_register register, register +bool AsmParser::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 AsmParser::parseDirectiveCFIWindowSave() { + getStreamer().emitCFIWindowSave(); + return false; +} + +/// parseDirectiveCFIAdjustCfaOffset +/// ::= .cfi_adjust_cfa_offset adjustment +bool AsmParser::parseDirectiveCFIAdjustCfaOffset() { + int64_t Adjustment = 0; + if (parseAbsoluteExpression(Adjustment)) + return true; + + getStreamer().emitCFIAdjustCfaOffset(Adjustment); + return false; +} + +/// parseDirectiveCFIDefCfaRegister +/// ::= .cfi_def_cfa_register register +bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) { + int64_t Register = 0; + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + getStreamer().emitCFIDefCfaRegister(Register); + return false; +} + +/// parseDirectiveCFIOffset +/// ::= .cfi_offset register, offset +bool AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::parseDirectiveCFIRememberState() { + getStreamer().emitCFIRememberState(); + return false; +} + +/// parseDirectiveCFIRestoreState +/// ::= .cfi_remember_state +bool AsmParser::parseDirectiveCFIRestoreState() { + getStreamer().emitCFIRestoreState(); + return false; +} + +/// parseDirectiveCFISameValue +/// ::= .cfi_same_value register +bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) { + int64_t Register = 0; + + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + getStreamer().emitCFISameValue(Register); + return false; +} + +/// parseDirectiveCFIRestore +/// ::= .cfi_restore register +bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) { + int64_t Register = 0; + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + getStreamer().emitCFIRestore(Register); + return false; +} + +/// parseDirectiveCFIEscape +/// ::= .cfi_escape expression[,...] +bool AsmParser::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 AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) { + int64_t Register = 0; + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + getStreamer().emitCFIReturnColumn(Register); + return false; +} + +/// parseDirectiveCFISignalFrame +/// ::= .cfi_signal_frame +bool AsmParser::parseDirectiveCFISignalFrame() { + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cfi_signal_frame'")) + return true; + + getStreamer().emitCFISignalFrame(); + return false; +} + +/// parseDirectiveCFIUndefined +/// ::= .cfi_undefined register +bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) { + int64_t Register = 0; + + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + getStreamer().emitCFIUndefined(Register); + return false; +} + +/// parseDirectiveAltmacro +/// ::= .altmacro +/// ::= .noaltmacro +bool AsmParser::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 AsmParser::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 AsmParser::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 the last parameter"); + + 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 or the start of a + // preprocessor line marker. + 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; + } + } else if (Lexer.is(AsmToken::HashDirective)) { + (void)parseCppHashLineFilenameComment(getLexer().getLoc()); + } + + // 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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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; +} + +/// parseDirectiveBundleAlignMode +/// ::= {.bundle_align_mode} expression +bool AsmParser::parseDirectiveBundleAlignMode() { + // Expect a single argument: an expression that evaluates to a constant + // in the inclusive range 0-30. + SMLoc ExprLoc = getLexer().getLoc(); + int64_t AlignSizePow2; + if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) || + parseToken(AsmToken::EndOfStatement, "unexpected token after expression " + "in '.bundle_align_mode' " + "directive") || + check(AlignSizePow2 < 0 || AlignSizePow2 > 30, ExprLoc, + "invalid bundle alignment size (expected between 0 and 30)")) + return true; + + // Because of AlignSizePow2's verified range we can safely truncate it to + // unsigned. + getStreamer().emitBundleAlignMode(static_cast<unsigned>(AlignSizePow2)); + return false; +} + +/// parseDirectiveBundleLock +/// ::= {.bundle_lock} [align_to_end] +bool AsmParser::parseDirectiveBundleLock() { + if (checkForValidSection()) + return true; + bool AlignToEnd = false; + + StringRef Option; + SMLoc Loc = getTok().getLoc(); + const char *kInvalidOptionError = + "invalid option for '.bundle_lock' directive"; + + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (check(parseIdentifier(Option), Loc, kInvalidOptionError) || + check(Option != "align_to_end", Loc, kInvalidOptionError) || + parseToken(AsmToken::EndOfStatement, + "unexpected token after '.bundle_lock' directive option")) + return true; + AlignToEnd = true; + } + + getStreamer().emitBundleLock(AlignToEnd); + return false; +} + +/// parseDirectiveBundleLock +/// ::= {.bundle_lock} +bool AsmParser::parseDirectiveBundleUnlock() { + if (checkForValidSection() || + parseToken(AsmToken::EndOfStatement, + "unexpected token in '.bundle_unlock' directive")) + return true; + + getStreamer().emitBundleUnlock(); + return false; +} + +/// parseDirectiveSpace +/// ::= (.skip | .space) expression [ , expression ] +bool AsmParser::parseDirectiveSpace(StringRef IDVal) { + SMLoc NumBytesLoc = Lexer.getLoc(); + const MCExpr *NumBytes; + if (checkForValidSection() || parseExpression(NumBytes)) + return true; + + int64_t FillExpr = 0; + if (parseOptionalToken(AsmToken::Comma)) + if (parseAbsoluteExpression(FillExpr)) + return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); + + // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. + getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc); + + return false; +} + +/// parseDirectiveDCB +/// ::= .dcb.{b, l, w} expression, expression +bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) { + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::Comma, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + const MCExpr *Value; + SMLoc ExprLoc = getLexer().getLoc(); + if (parseExpression(Value)) + return true; + + // Special case constant expressions to match code generator. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) { + assert(Size <= 8 && "Invalid size"); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) + return Error(ExprLoc, "literal value out of range for directive"); + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().emitIntValue(IntValue, Size); + } else { + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().emitValue(Value, Size, ExprLoc); + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + return false; +} + +/// parseDirectiveRealDCB +/// ::= .dcb.{d, s} expression, expression +bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) { + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::Comma, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + APInt AsInt; + if (parseRealValue(Semantics, AsInt)) + return true; + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().emitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + + return false; +} + +/// parseDirectiveDS +/// ::= .ds.{b, d, l, p, s, w, x} expression +bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) { + SMLoc NumValuesLoc = Lexer.getLoc(); + int64_t NumValues; + if (checkForValidSection() || parseAbsoluteExpression(NumValues)) + return true; + + if (NumValues < 0) { + Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); + return false; + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '" + Twine(IDVal) + "' directive")) + return true; + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().emitFill(Size, 0); + + return false; +} + +/// parseDirectiveLEB128 +/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ] +bool AsmParser::parseDirectiveLEB128(bool Signed) { + if (checkForValidSection()) + return true; + + auto parseOp = [&]() -> bool { + const MCExpr *Value; + if (parseExpression(Value)) + return true; + if (Signed) + getStreamer().emitSLEB128Value(Value); + else + getStreamer().emitULEB128Value(Value); + return false; + }; + + if (parseMany(parseOp)) + return addErrorSuffix(" in directive"); + + return false; +} + +/// parseDirectiveSymbolAttribute +/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] +bool AsmParser::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 AsmParser::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; +} + +/// parseDirectiveAbort +/// ::= .abort [... message ...] +bool AsmParser::parseDirectiveAbort() { + // FIXME: Use loc from directive. + SMLoc Loc = getLexer().getLoc(); + + StringRef Str = parseStringToEndOfStatement(); + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.abort' directive")) + return true; + + if (Str.empty()) + return Error(Loc, ".abort detected. Assembly stopping."); + else + return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + // FIXME: Actually abort assembly here. + + return false; +} + +/// parseDirectiveInclude +/// ::= .include "filename" +bool AsmParser::parseDirectiveInclude() { + // Allow the strings to have escaped octal character sequence. + std::string Filename; + SMLoc IncludeLoc = getTok().getLoc(); + + if (check(getTok().isNot(AsmToken::String), + "expected string in '.include' directive") || + parseEscapedString(Filename) || + 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; +} + +/// parseDirectiveIncbin +/// ::= .incbin "filename" [ , skip [ , count ] ] +bool AsmParser::parseDirectiveIncbin() { + // Allow the strings to have escaped octal character sequence. + std::string Filename; + SMLoc IncbinLoc = getTok().getLoc(); + if (check(getTok().isNot(AsmToken::String), + "expected string in '.incbin' directive") || + parseEscapedString(Filename)) + return true; + + int64_t Skip = 0; + const MCExpr *Count = nullptr; + SMLoc SkipLoc, CountLoc; + if (parseOptionalToken(AsmToken::Comma)) { + // The skip expression can be omitted while specifying the count, e.g: + // .incbin "filename",,4 + if (getTok().isNot(AsmToken::Comma)) { + if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip)) + return true; + } + if (parseOptionalToken(AsmToken::Comma)) { + CountLoc = getTok().getLoc(); + if (parseExpression(Count)) + return true; + } + } + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.incbin' directive")) + return true; + + if (check(Skip < 0, SkipLoc, "skip is negative")) + return true; + + // Attempt to process the included file. + if (processIncbinFile(Filename, Skip, Count, CountLoc)) + return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); + return false; +} + +/// parseDirectiveIf +/// ::= .if{,eq,ge,gt,le,lt,ne} expression +bool AsmParser::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: + case DK_IFNE: + break; + case DK_IFEQ: + ExprValue = ExprValue == 0; + break; + case DK_IFGE: + ExprValue = ExprValue >= 0; + break; + case DK_IFGT: + ExprValue = ExprValue > 0; + break; + case DK_IFLE: + ExprValue = ExprValue <= 0; + break; + case DK_IFLT: + ExprValue = ExprValue < 0; + break; + } + + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveIfb +/// ::= .ifb string +bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) { + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + eatToEndOfStatement(); + } else { + StringRef Str = parseStringToEndOfStatement(); + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.ifb' directive")) + return true; + + TheCondState.CondMet = ExpectBlank == Str.empty(); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveIfc +/// ::= .ifc string1, string2 +/// ::= .ifnc string1, string2 +bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) { + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + eatToEndOfStatement(); + } else { + StringRef Str1 = parseStringToComma(); + + if (parseToken(AsmToken::Comma, "unexpected token in '.ifc' directive")) + return true; + + StringRef Str2 = parseStringToEndOfStatement(); + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.ifc' directive")) + return true; + + TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim()); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveIfeqs +/// ::= .ifeqs string1, string2 +bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) { + if (Lexer.isNot(AsmToken::String)) { + if (ExpectEqual) + return TokError("expected string parameter for '.ifeqs' directive"); + return TokError("expected string parameter for '.ifnes' directive"); + } + + StringRef String1 = getTok().getStringContents(); + Lex(); + + if (Lexer.isNot(AsmToken::Comma)) { + if (ExpectEqual) + return TokError( + "expected comma after first string for '.ifeqs' directive"); + return TokError("expected comma after first string for '.ifnes' directive"); + } + + Lex(); + + if (Lexer.isNot(AsmToken::String)) { + if (ExpectEqual) + return TokError("expected string parameter for '.ifeqs' directive"); + return TokError("expected string parameter for '.ifnes' directive"); + } + + StringRef String2 = getTok().getStringContents(); + Lex(); + + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + TheCondState.CondMet = ExpectEqual == (String1 == String2); + TheCondState.Ignore = !TheCondState.CondMet; + + return false; +} + +/// parseDirectiveIfdef +/// ::= .ifdef symbol +bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { + StringRef Name; + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + eatToEndOfStatement(); + } else { + if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") || + parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifdef'")) + return true; + + MCSymbol *Sym = getContext().lookupSymbol(Name); + + if (expect_defined) + TheCondState.CondMet = (Sym && !Sym->isUndefined(false)); + else + TheCondState.CondMet = (!Sym || Sym->isUndefined(false)); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveElseIf +/// ::= .elseif expression +bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) { + 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; + + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveElse +/// ::= .else +bool AsmParser::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 a .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 AsmParser::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 +/// ::= .error [string] +bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) { + if (!TheCondStack.empty()) { + if (TheCondStack.back().Ignore) { + eatToEndOfStatement(); + return false; + } + } + + if (!WithMessage) + return Error(L, ".err encountered"); + + StringRef Message = ".error directive invoked in source file"; + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::String)) + return TokError(".error argument must be a string"); + + Message = getTok().getStringContents(); + Lex(); + } + + return Error(L, Message); +} + +/// parseDirectiveWarning +/// ::= .warning [string] +bool AsmParser::parseDirectiveWarning(SMLoc L) { + if (!TheCondStack.empty()) { + if (TheCondStack.back().Ignore) { + eatToEndOfStatement(); + return false; + } + } + + StringRef Message = ".warning directive invoked in source file"; + + if (!parseOptionalToken(AsmToken::EndOfStatement)) { + if (Lexer.isNot(AsmToken::String)) + return TokError(".warning argument must be a string"); + + Message = getTok().getStringContents(); + Lex(); + if (parseToken(AsmToken::EndOfStatement, + "expected end of statement in '.warning' directive")) + return true; + } + + return Warning(L, Message); +} + +/// parseDirectiveEndIf +/// ::= .endif +bool AsmParser::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 AsmParser::initializeDirectiveKindMap() { + /* Lookup will be done with the directive + * converted to lower case, so all these + * keys should be lower case. + * (target specific directives are handled + * elsewhere) + */ + DirectiveKindMap[".set"] = DK_SET; + DirectiveKindMap[".equ"] = DK_EQU; + DirectiveKindMap[".equiv"] = DK_EQUIV; + DirectiveKindMap[".ascii"] = DK_ASCII; + DirectiveKindMap[".asciz"] = DK_ASCIZ; + DirectiveKindMap[".string"] = DK_STRING; + DirectiveKindMap[".byte"] = DK_BYTE; + DirectiveKindMap[".short"] = DK_SHORT; + DirectiveKindMap[".value"] = DK_VALUE; + DirectiveKindMap[".2byte"] = DK_2BYTE; + DirectiveKindMap[".long"] = DK_LONG; + DirectiveKindMap[".int"] = DK_INT; + DirectiveKindMap[".4byte"] = DK_4BYTE; + DirectiveKindMap[".quad"] = DK_QUAD; + DirectiveKindMap[".8byte"] = DK_8BYTE; + DirectiveKindMap[".octa"] = DK_OCTA; + DirectiveKindMap[".single"] = DK_SINGLE; + DirectiveKindMap[".float"] = DK_FLOAT; + DirectiveKindMap[".double"] = DK_DOUBLE; + DirectiveKindMap[".align"] = DK_ALIGN; + DirectiveKindMap[".align32"] = DK_ALIGN32; + DirectiveKindMap[".balign"] = DK_BALIGN; + DirectiveKindMap[".balignw"] = DK_BALIGNW; + DirectiveKindMap[".balignl"] = DK_BALIGNL; + DirectiveKindMap[".p2align"] = DK_P2ALIGN; + DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW; + DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL; + DirectiveKindMap[".org"] = DK_ORG; + DirectiveKindMap[".fill"] = DK_FILL; + DirectiveKindMap[".zero"] = DK_ZERO; + DirectiveKindMap[".extern"] = DK_EXTERN; + DirectiveKindMap[".globl"] = DK_GLOBL; + DirectiveKindMap[".global"] = DK_GLOBAL; + DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE; + DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP; + DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER; + DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN; + DirectiveKindMap[".reference"] = DK_REFERENCE; + DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION; + DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE; + DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN; + DirectiveKindMap[".cold"] = DK_COLD; + DirectiveKindMap[".comm"] = DK_COMM; + DirectiveKindMap[".common"] = DK_COMMON; + DirectiveKindMap[".lcomm"] = DK_LCOMM; + DirectiveKindMap[".abort"] = DK_ABORT; + DirectiveKindMap[".include"] = DK_INCLUDE; + DirectiveKindMap[".incbin"] = DK_INCBIN; + DirectiveKindMap[".code16"] = DK_CODE16; + DirectiveKindMap[".code16gcc"] = DK_CODE16GCC; + DirectiveKindMap[".rept"] = DK_REPT; + DirectiveKindMap[".rep"] = DK_REPT; + DirectiveKindMap[".irp"] = DK_IRP; + DirectiveKindMap[".irpc"] = DK_IRPC; + DirectiveKindMap[".endr"] = DK_ENDR; + DirectiveKindMap[".bundle_align_mode"] = DK_BUNDLE_ALIGN_MODE; + DirectiveKindMap[".bundle_lock"] = DK_BUNDLE_LOCK; + DirectiveKindMap[".bundle_unlock"] = DK_BUNDLE_UNLOCK; + DirectiveKindMap[".if"] = DK_IF; + DirectiveKindMap[".ifeq"] = DK_IFEQ; + DirectiveKindMap[".ifge"] = DK_IFGE; + DirectiveKindMap[".ifgt"] = DK_IFGT; + DirectiveKindMap[".ifle"] = DK_IFLE; + DirectiveKindMap[".iflt"] = DK_IFLT; + DirectiveKindMap[".ifne"] = DK_IFNE; + DirectiveKindMap[".ifb"] = DK_IFB; + DirectiveKindMap[".ifnb"] = DK_IFNB; + DirectiveKindMap[".ifc"] = DK_IFC; + DirectiveKindMap[".ifeqs"] = DK_IFEQS; + DirectiveKindMap[".ifnc"] = DK_IFNC; + DirectiveKindMap[".ifnes"] = DK_IFNES; + DirectiveKindMap[".ifdef"] = DK_IFDEF; + DirectiveKindMap[".ifndef"] = DK_IFNDEF; + DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF; + DirectiveKindMap[".elseif"] = DK_ELSEIF; + DirectiveKindMap[".else"] = DK_ELSE; + DirectiveKindMap[".end"] = DK_END; + DirectiveKindMap[".endif"] = DK_ENDIF; + DirectiveKindMap[".skip"] = DK_SKIP; + DirectiveKindMap[".space"] = DK_SPACE; + 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[".sleb128"] = DK_SLEB128; + DirectiveKindMap[".uleb128"] = DK_ULEB128; + 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[".macros_on"] = DK_MACROS_ON; + DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; + DirectiveKindMap[".macro"] = DK_MACRO; + DirectiveKindMap[".exitm"] = DK_EXITM; + DirectiveKindMap[".endm"] = DK_ENDM; + DirectiveKindMap[".endmacro"] = DK_ENDMACRO; + DirectiveKindMap[".purgem"] = DK_PURGEM; + DirectiveKindMap[".err"] = DK_ERR; + DirectiveKindMap[".error"] = DK_ERROR; + DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".altmacro"] = DK_ALTMACRO; + DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO; + DirectiveKindMap[".reloc"] = DK_RELOC; + DirectiveKindMap[".dc"] = DK_DC; + DirectiveKindMap[".dc.a"] = DK_DC_A; + DirectiveKindMap[".dc.b"] = DK_DC_B; + DirectiveKindMap[".dc.d"] = DK_DC_D; + DirectiveKindMap[".dc.l"] = DK_DC_L; + DirectiveKindMap[".dc.s"] = DK_DC_S; + DirectiveKindMap[".dc.w"] = DK_DC_W; + DirectiveKindMap[".dc.x"] = DK_DC_X; + DirectiveKindMap[".dcb"] = DK_DCB; + DirectiveKindMap[".dcb.b"] = DK_DCB_B; + DirectiveKindMap[".dcb.d"] = DK_DCB_D; + DirectiveKindMap[".dcb.l"] = DK_DCB_L; + DirectiveKindMap[".dcb.s"] = DK_DCB_S; + DirectiveKindMap[".dcb.w"] = DK_DCB_W; + DirectiveKindMap[".dcb.x"] = DK_DCB_X; + DirectiveKindMap[".ds"] = DK_DS; + DirectiveKindMap[".ds.b"] = DK_DS_B; + DirectiveKindMap[".ds.d"] = DK_DS_D; + DirectiveKindMap[".ds.l"] = DK_DS_L; + DirectiveKindMap[".ds.p"] = DK_DS_P; + DirectiveKindMap[".ds.s"] = DK_DS_S; + DirectiveKindMap[".ds.w"] = DK_DS_W; + DirectiveKindMap[".ds.x"] = DK_DS_X; + DirectiveKindMap[".print"] = DK_PRINT; + DirectiveKindMap[".addrsig"] = DK_ADDRSIG; + DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; DirectiveKindMap[".pseudoprobe"] = DK_PSEUDO_PROBE; -} - -MCAsmMacro *AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { - const AsmToken StrTok = getTok(); - Lex(); - if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"') - return Error(DirectiveLoc, "expected double quoted string after .print"); - if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) - return true; - llvm::outs() << StrTok.getStringContents() << '\n'; - return false; -} - -bool AsmParser::parseDirectiveAddrsig() { - getStreamer().emitAddrsig(); - return false; -} - -bool AsmParser::parseDirectiveAddrsigSym() { - StringRef Name; - if (check(parseIdentifier(Name), - "expected identifier in '.addrsig_sym' directive")) - return true; - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitAddrsigSym(Sym); - return false; -} - +} + +MCAsmMacro *AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::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 AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { + const AsmToken StrTok = getTok(); + Lex(); + if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"') + return Error(DirectiveLoc, "expected double quoted string after .print"); + if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) + return true; + llvm::outs() << StrTok.getStringContents() << '\n'; + return false; +} + +bool AsmParser::parseDirectiveAddrsig() { + getStreamer().emitAddrsig(); + return false; +} + +bool AsmParser::parseDirectiveAddrsigSym() { + StringRef Name; + if (check(parseIdentifier(Name), + "expected identifier in '.addrsig_sym' directive")) + return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitAddrsigSym(Sym); + return false; +} + bool AsmParser::parseDirectivePseudoProbe() { int64_t Guid; int64_t Index; @@ -5854,379 +5854,379 @@ bool AsmParser::parseDirectivePseudoProbe() { 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 AsmParser::parseMSInlineAsm( - void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, - unsigned &NumInputs, SmallVectorImpl<std::pair<void *, bool>> &OpDecls, - SmallVectorImpl<std::string> &Constraints, - SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII, - const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) { - SmallVector<void *, 4> InputDecls; - SmallVector<void *, 4> OutputDecls; - SmallVector<bool, 4> 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.getReg())) { - 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()); +// 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 AsmParser::parseMSInlineAsm( + void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, + unsigned &NumInputs, SmallVectorImpl<std::pair<void *, bool>> &OpDecls, + SmallVectorImpl<std::string> &Constraints, + SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII, + const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) { + SmallVector<void *, 4> InputDecls; + SmallVector<void *, 4> OutputDecls; + SmallVector<bool, 4> 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.getReg())) { + 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()); llvm::append_range(ClobberRegs, ImpDefs); - } - - // 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; -} - -namespace llvm { -namespace MCParserUtils { - -/// Returns whether the given symbol is used anywhere in the given expression, -/// or subexpressions. -static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Binary: { - const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value); - return isSymbolUsedInExpression(Sym, BE->getLHS()) || - isSymbolUsedInExpression(Sym, BE->getRHS()); - } - case MCExpr::Target: - case MCExpr::Constant: - return false; - case MCExpr::SymbolRef: { - const MCSymbol &S = - static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); - if (S.isVariable()) - return isSymbolUsedInExpression(Sym, S.getVariableValue()); - return &S == Sym; - } - case MCExpr::Unary: - return isSymbolUsedInExpression( - Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr()); - } - - llvm_unreachable("Unknown expr kind!"); -} - -bool parseAssignmentExpression(StringRef Name, bool allow_redef, - MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value) { - - // FIXME: Use better location, we should use proper tokens. - SMLoc EqualLoc = Parser.getTok().getLoc(); - if (Parser.parseExpression(Value)) - return Parser.TokError("missing expression"); - - // Note: we don't count b as used in "a = b". This is to allow - // a = b - // b = c - - if (Parser.parseToken(AsmToken::EndOfStatement)) - return true; - - // Validate that the LHS is allowed to be a variable (either it has not been - // used as a symbol, or it is an absolute symbol). - Sym = Parser.getContext().lookupSymbol(Name); - if (Sym) { - // Diagnose assignment to a label. - // - // FIXME: Diagnostics. Note the location of the definition as a label. - // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (isSymbolUsedInExpression(Sym, Value)) - return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'"); - else if (Sym->isUndefined(/*SetUsed*/ false) && !Sym->isUsed() && - !Sym->isVariable()) - ; // Allow redefinitions of undefined symbols only used in directives. - else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) - ; // Allow redefinitions of variables that haven't yet been used. - else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) - return Parser.Error(EqualLoc, "redefinition of '" + Name + "'"); - else if (!Sym->isVariable()) - return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'"); - else if (!isa<MCConstantExpr>(Sym->getVariableValue())) - return Parser.Error(EqualLoc, - "invalid reassignment of non-absolute variable '" + - Name + "'"); - } else if (Name == ".") { - Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc); - return false; - } else - Sym = Parser.getContext().getOrCreateSymbol(Name); - - Sym->setRedefinable(allow_redef); - - return false; -} - -} // end namespace MCParserUtils -} // end namespace llvm - -/// Create an MCAsmParser instance. -MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, - MCStreamer &Out, const MCAsmInfo &MAI, - unsigned CB) { - return new AsmParser(SM, C, Out, MAI, CB); -} + } + + // 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; +} + +namespace llvm { +namespace MCParserUtils { + +/// Returns whether the given symbol is used anywhere in the given expression, +/// or subexpressions. +static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value); + return isSymbolUsedInExpression(Sym, BE->getLHS()) || + isSymbolUsedInExpression(Sym, BE->getRHS()); + } + case MCExpr::Target: + case MCExpr::Constant: + return false; + case MCExpr::SymbolRef: { + const MCSymbol &S = + static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); + if (S.isVariable()) + return isSymbolUsedInExpression(Sym, S.getVariableValue()); + return &S == Sym; + } + case MCExpr::Unary: + return isSymbolUsedInExpression( + Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr()); + } + + llvm_unreachable("Unknown expr kind!"); +} + +bool parseAssignmentExpression(StringRef Name, bool allow_redef, + MCAsmParser &Parser, MCSymbol *&Sym, + const MCExpr *&Value) { + + // FIXME: Use better location, we should use proper tokens. + SMLoc EqualLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(Value)) + return Parser.TokError("missing expression"); + + // Note: we don't count b as used in "a = b". This is to allow + // a = b + // b = c + + if (Parser.parseToken(AsmToken::EndOfStatement)) + return true; + + // Validate that the LHS is allowed to be a variable (either it has not been + // used as a symbol, or it is an absolute symbol). + Sym = Parser.getContext().lookupSymbol(Name); + if (Sym) { + // Diagnose assignment to a label. + // + // FIXME: Diagnostics. Note the location of the definition as a label. + // FIXME: Diagnose assignment to protected identifier (e.g., register name). + if (isSymbolUsedInExpression(Sym, Value)) + return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'"); + else if (Sym->isUndefined(/*SetUsed*/ false) && !Sym->isUsed() && + !Sym->isVariable()) + ; // Allow redefinitions of undefined symbols only used in directives. + else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) + ; // Allow redefinitions of variables that haven't yet been used. + else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) + return Parser.Error(EqualLoc, "redefinition of '" + Name + "'"); + else if (!Sym->isVariable()) + return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'"); + else if (!isa<MCConstantExpr>(Sym->getVariableValue())) + return Parser.Error(EqualLoc, + "invalid reassignment of non-absolute variable '" + + Name + "'"); + } else if (Name == ".") { + Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc); + return false; + } else + Sym = Parser.getContext().getOrCreateSymbol(Name); + + Sym->setRedefinable(allow_redef); + + return false; +} + +} // end namespace MCParserUtils +} // end namespace llvm + +/// Create an MCAsmParser instance. +MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, + MCStreamer &Out, const MCAsmInfo &MAI, + unsigned CB) { + return new AsmParser(SM, C, Out, MAI, CB); +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/COFFAsmParser.cpp index a859bf2ab2..3ac6a88341 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/COFFAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/COFFAsmParser.cpp @@ -1,726 +1,726 @@ -//===- COFFAsmParser.cpp - COFF 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/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 COFFAsmParser : public MCAsmParserExtension { - template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> - void addDirectiveHandler(StringRef Directive) { - MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( - this, HandleDirective<COFFAsmParser, 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 ParseSectionName(StringRef &SectionName); - bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, - unsigned *Flags); - - void Initialize(MCAsmParser &Parser) override { - // Call the base implementation. - MCAsmParserExtension::Initialize(Parser); - - addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); - addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); - addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); - addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); - - // Win64 EH directives. - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( - ".seh_proc"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( - ".seh_endproc"); +//===- COFFAsmParser.cpp - COFF 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/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 COFFAsmParser : public MCAsmParserExtension { + template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<COFFAsmParser, 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 ParseSectionName(StringRef &SectionName); + bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, + unsigned *Flags); + + void Initialize(MCAsmParser &Parser) override { + // Call the base implementation. + MCAsmParserExtension::Initialize(Parser); + + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); + addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); + + // Win64 EH directives. + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( + ".seh_proc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( + ".seh_endproc"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc>( ".seh_endfunclet"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( - ".seh_startchained"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( - ".seh_endchained"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( - ".seh_handler"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( - ".seh_handlerdata"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( - ".seh_stackalloc"); - addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( - ".seh_endprologue"); - } - - bool ParseSectionDirectiveText(StringRef, SMLoc) { - return ParseSectionSwitch(".text", - COFF::IMAGE_SCN_CNT_CODE - | COFF::IMAGE_SCN_MEM_EXECUTE - | COFF::IMAGE_SCN_MEM_READ, - SectionKind::getText()); - } - - bool ParseSectionDirectiveData(StringRef, SMLoc) { - return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | - COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getData()); - } - - bool ParseSectionDirectiveBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".bss", - COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA - | COFF::IMAGE_SCN_MEM_READ - | COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getBSS()); - } - - bool ParseDirectiveSection(StringRef, SMLoc); - bool ParseDirectiveDef(StringRef, SMLoc); - bool ParseDirectiveScl(StringRef, SMLoc); - bool ParseDirectiveType(StringRef, SMLoc); - bool ParseDirectiveEndef(StringRef, SMLoc); - bool ParseDirectiveSecRel32(StringRef, SMLoc); - bool ParseDirectiveSecIdx(StringRef, SMLoc); - bool ParseDirectiveSafeSEH(StringRef, SMLoc); - bool ParseDirectiveSymIdx(StringRef, SMLoc); - bool parseCOMDATType(COFF::COMDATType &Type); - bool ParseDirectiveLinkOnce(StringRef, SMLoc); - bool ParseDirectiveRVA(StringRef, SMLoc); - bool ParseDirectiveCGProfile(StringRef, SMLoc); - - // Win64 EH directives. - bool ParseSEHDirectiveStartProc(StringRef, SMLoc); - bool ParseSEHDirectiveEndProc(StringRef, SMLoc); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( + ".seh_startchained"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( + ".seh_endchained"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( + ".seh_handler"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( + ".seh_handlerdata"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( + ".seh_stackalloc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( + ".seh_endprologue"); + } + + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + } + + bool ParseSectionDirectiveData(StringRef, SMLoc) { + return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getData()); + } + + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + } + + bool ParseDirectiveSection(StringRef, SMLoc); + bool ParseDirectiveDef(StringRef, SMLoc); + bool ParseDirectiveScl(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveEndef(StringRef, SMLoc); + bool ParseDirectiveSecRel32(StringRef, SMLoc); + bool ParseDirectiveSecIdx(StringRef, SMLoc); + bool ParseDirectiveSafeSEH(StringRef, SMLoc); + bool ParseDirectiveSymIdx(StringRef, SMLoc); + bool parseCOMDATType(COFF::COMDATType &Type); + bool ParseDirectiveLinkOnce(StringRef, SMLoc); + bool ParseDirectiveRVA(StringRef, SMLoc); + bool ParseDirectiveCGProfile(StringRef, SMLoc); + + // Win64 EH directives. + bool ParseSEHDirectiveStartProc(StringRef, SMLoc); + bool ParseSEHDirectiveEndProc(StringRef, SMLoc); bool ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc); - bool ParseSEHDirectiveStartChained(StringRef, SMLoc); - bool ParseSEHDirectiveEndChained(StringRef, SMLoc); - bool ParseSEHDirectiveHandler(StringRef, SMLoc); - bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); - bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); - bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); - - bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); - bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); - -public: - COFFAsmParser() = 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 COFFAsmParser::ParseSectionFlags(StringRef SectionName, - StringRef FlagsString, unsigned *Flags) { - enum { - None = 0, - Alloc = 1 << 0, - Code = 1 << 1, - Load = 1 << 2, - InitData = 1 << 3, - Shared = 1 << 4, - NoLoad = 1 << 5, - NoRead = 1 << 6, - NoWrite = 1 << 7, - Discardable = 1 << 8, - }; - - bool ReadOnlyRemoved = false; - unsigned SecFlags = None; - - for (char FlagChar : FlagsString) { - switch (FlagChar) { - case 'a': - // Ignored. - break; - - case 'b': // bss section - SecFlags |= Alloc; - if (SecFlags & InitData) - return TokError("conflicting section flags 'b' and 'd'."); - SecFlags &= ~Load; - break; - - case 'd': // data section - SecFlags |= InitData; - if (SecFlags & Alloc) - return TokError("conflicting section flags 'b' and 'd'."); - SecFlags &= ~NoWrite; - if ((SecFlags & NoLoad) == 0) - SecFlags |= Load; - break; - - case 'n': // section is not loaded - SecFlags |= NoLoad; - SecFlags &= ~Load; - break; - - case 'D': // discardable - SecFlags |= Discardable; - break; - - case 'r': // read-only - ReadOnlyRemoved = false; - SecFlags |= NoWrite; - if ((SecFlags & Code) == 0) - SecFlags |= InitData; - if ((SecFlags & NoLoad) == 0) - SecFlags |= Load; - break; - - case 's': // shared section - SecFlags |= Shared | InitData; - SecFlags &= ~NoWrite; - if ((SecFlags & NoLoad) == 0) - SecFlags |= Load; - break; - - case 'w': // writable - SecFlags &= ~NoWrite; - ReadOnlyRemoved = true; - break; - - case 'x': // executable section - SecFlags |= Code; - if ((SecFlags & NoLoad) == 0) - SecFlags |= Load; - if (!ReadOnlyRemoved) - SecFlags |= NoWrite; - break; - - case 'y': // not readable - SecFlags |= NoRead | NoWrite; - break; - - default: - return TokError("unknown flag"); - } - } - - *Flags = 0; - - if (SecFlags == None) - SecFlags = InitData; - - if (SecFlags & Code) - *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; - if (SecFlags & InitData) - *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - if ((SecFlags & Alloc) && (SecFlags & Load) == 0) - *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; - if (SecFlags & NoLoad) - *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; - if ((SecFlags & Discardable) || - MCSectionCOFF::isImplicitlyDiscardable(SectionName)) - *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; - if ((SecFlags & NoRead) == 0) - *Flags |= COFF::IMAGE_SCN_MEM_READ; - if ((SecFlags & NoWrite) == 0) - *Flags |= COFF::IMAGE_SCN_MEM_WRITE; - if (SecFlags & Shared) - *Flags |= COFF::IMAGE_SCN_MEM_SHARED; - - return false; -} - -/// ParseDirectiveSymbolAttribute -/// ::= { ".weak", ... } [ identifier ( , identifier )* ] -bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { - MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) - .Case(".weak", MCSA_Weak) - .Default(MCSA_Invalid); - assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - while (true) { - StringRef Name; - - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - getStreamer().emitSymbolAttribute(Sym, Attr); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - } - } - - Lex(); - return false; -} - -bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { - return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); -} - -bool COFFAsmParser::ParseSectionSwitch(StringRef Section, - unsigned Characteristics, - SectionKind Kind) { - return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0); -} - -bool COFFAsmParser::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 COFFAsmParser::ParseSectionName(StringRef &SectionName) { - if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String)) - return true; - - SectionName = getTok().getIdentifier(); - Lex(); - return false; -} - -// .section name [, "flags"] [, identifier [ identifier ], identifier] -// -// Supported flags: -// a: Ignored. -// b: BSS section (uninitialized data) -// d: data section (initialized data) -// n: "noload" section (removed by linker) -// D: Discardable section -// r: Readable section -// s: Shared section -// w: Writable section -// x: Executable section -// y: Not-readable section (clears 'r') -// -// Subsections are not supported. -bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { - StringRef SectionName; - - if (ParseSectionName(SectionName)) - return TokError("expected identifier in directive"); - - unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | - COFF::IMAGE_SCN_MEM_WRITE; - - if (getLexer().is(AsmToken::Comma)) { - Lex(); - - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in directive"); - - StringRef FlagsStr = getTok().getStringContents(); - Lex(); - - if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) - return true; - } - - COFF::COMDATType Type = (COFF::COMDATType)0; - StringRef COMDATSymName; - if (getLexer().is(AsmToken::Comma)) { - Type = COFF::IMAGE_COMDAT_SELECT_ANY; - Lex(); - - Flags |= COFF::IMAGE_SCN_LNK_COMDAT; - - if (!getLexer().is(AsmToken::Identifier)) - return TokError("expected comdat type such as 'discard' or 'largest' " - "after protection bits"); - - if (parseCOMDATType(Type)) - return true; - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected comma in directive"); - Lex(); - - if (getParser().parseIdentifier(COMDATSymName)) - return TokError("expected identifier in directive"); - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - SectionKind Kind = computeSectionKind(Flags); - if (Kind.isText()) { - const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); - if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) - Flags |= COFF::IMAGE_SCN_MEM_16BIT; - } - ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type); - return false; -} - -bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { - StringRef SymbolName; - - if (getParser().parseIdentifier(SymbolName)) - return TokError("expected identifier in directive"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); - - getStreamer().BeginCOFFSymbolDef(Sym); - - Lex(); - return false; -} - -bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { - int64_t SymbolStorageClass; - if (getParser().parseAbsoluteExpression(SymbolStorageClass)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); - return false; -} - -bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { - int64_t Type; - if (getParser().parseAbsoluteExpression(Type)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitCOFFSymbolType(Type); - return false; -} - -bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { - Lex(); - getStreamer().EndCOFFSymbolDef(); - return false; -} - -bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return TokError("expected identifier in directive"); - - int64_t Offset = 0; - SMLoc OffsetLoc; - if (getLexer().is(AsmToken::Plus)) { - OffsetLoc = getLexer().getLoc(); - if (getParser().parseAbsoluteExpression(Offset)) - return true; - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) - return Error( - OffsetLoc, - "invalid '.secrel32' directive offset, can't be less " - "than zero or greater than std::numeric_limits<uint32_t>::max()"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitCOFFSecRel32(Symbol, Offset); - return false; -} - -bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { - auto parseOp = [&]() -> bool { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return TokError("expected identifier in directive"); - - int64_t Offset = 0; - SMLoc OffsetLoc; - if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { - OffsetLoc = getLexer().getLoc(); - if (getParser().parseAbsoluteExpression(Offset)) - return true; - } - - if (Offset < std::numeric_limits<int32_t>::min() || - Offset > std::numeric_limits<int32_t>::max()) - return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " - "than -2147483648 or greater than " - "2147483647"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - getStreamer().EmitCOFFImgRel32(Symbol, Offset); - return false; - }; - - if (getParser().parseMany(parseOp)) - return addErrorSuffix(" in directive"); - return false; -} - -bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitCOFFSafeSEH(Symbol); - return false; -} - -bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitCOFFSectionIndex(Symbol); - return false; -} - -bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitCOFFSymbolIndex(Symbol); - return false; -} - -/// ::= [ identifier ] -bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { - StringRef TypeId = getTok().getIdentifier(); - - Type = StringSwitch<COFF::COMDATType>(TypeId) - .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) - .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) - .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) - .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) - .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) - .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) - .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) - .Default((COFF::COMDATType)0); - - if (Type == 0) - return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); - - Lex(); - - return false; -} - -/// ParseDirectiveLinkOnce -/// ::= .linkonce [ identifier ] -bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { - COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; - if (getLexer().is(AsmToken::Identifier)) - if (parseCOMDATType(Type)) - return true; - - const MCSectionCOFF *Current = - static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); - - if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) - return Error(Loc, "cannot make section associative with .linkonce"); - - if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) - return Error(Loc, Twine("section '") + Current->getName() + - "' is already linkonce"); - - Current->setSelection(Type); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitWinCFIStartProc(Symbol, Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { - Lex(); - getStreamer().EmitWinCFIEndProc(Loc); - return false; -} - + bool ParseSEHDirectiveStartChained(StringRef, SMLoc); + bool ParseSEHDirectiveEndChained(StringRef, SMLoc); + bool ParseSEHDirectiveHandler(StringRef, SMLoc); + bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); + bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); + bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); + + bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); + bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); + +public: + COFFAsmParser() = 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 COFFAsmParser::ParseSectionFlags(StringRef SectionName, + StringRef FlagsString, unsigned *Flags) { + enum { + None = 0, + Alloc = 1 << 0, + Code = 1 << 1, + Load = 1 << 2, + InitData = 1 << 3, + Shared = 1 << 4, + NoLoad = 1 << 5, + NoRead = 1 << 6, + NoWrite = 1 << 7, + Discardable = 1 << 8, + }; + + bool ReadOnlyRemoved = false; + unsigned SecFlags = None; + + for (char FlagChar : FlagsString) { + switch (FlagChar) { + case 'a': + // Ignored. + break; + + case 'b': // bss section + SecFlags |= Alloc; + if (SecFlags & InitData) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~Load; + break; + + case 'd': // data section + SecFlags |= InitData; + if (SecFlags & Alloc) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'n': // section is not loaded + SecFlags |= NoLoad; + SecFlags &= ~Load; + break; + + case 'D': // discardable + SecFlags |= Discardable; + break; + + case 'r': // read-only + ReadOnlyRemoved = false; + SecFlags |= NoWrite; + if ((SecFlags & Code) == 0) + SecFlags |= InitData; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 's': // shared section + SecFlags |= Shared | InitData; + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'w': // writable + SecFlags &= ~NoWrite; + ReadOnlyRemoved = true; + break; + + case 'x': // executable section + SecFlags |= Code; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + if (!ReadOnlyRemoved) + SecFlags |= NoWrite; + break; + + case 'y': // not readable + SecFlags |= NoRead | NoWrite; + break; + + default: + return TokError("unknown flag"); + } + } + + *Flags = 0; + + if (SecFlags == None) + SecFlags = InitData; + + if (SecFlags & Code) + *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; + if (SecFlags & InitData) + *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + if ((SecFlags & Alloc) && (SecFlags & Load) == 0) + *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + if (SecFlags & NoLoad) + *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; + if ((SecFlags & Discardable) || + MCSectionCOFF::isImplicitlyDiscardable(SectionName)) + *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; + if ((SecFlags & NoRead) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_READ; + if ((SecFlags & NoWrite) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_WRITE; + if (SecFlags & Shared) + *Flags |= COFF::IMAGE_SCN_MEM_SHARED; + + return false; +} + +/// ParseDirectiveSymbolAttribute +/// ::= { ".weak", ... } [ identifier ( , identifier )* ] +bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { + MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) + .Case(".weak", MCSA_Weak) + .Default(MCSA_Invalid); + assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + while (true) { + StringRef Name; + + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + getStreamer().emitSymbolAttribute(Sym, Attr); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { + return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0); +} + +bool COFFAsmParser::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 COFFAsmParser::ParseSectionName(StringRef &SectionName) { + if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String)) + return true; + + SectionName = getTok().getIdentifier(); + Lex(); + return false; +} + +// .section name [, "flags"] [, identifier [ identifier ], identifier] +// +// Supported flags: +// a: Ignored. +// b: BSS section (uninitialized data) +// d: data section (initialized data) +// n: "noload" section (removed by linker) +// D: Discardable section +// r: Readable section +// s: Shared section +// w: Writable section +// x: Executable section +// y: Not-readable section (clears 'r') +// +// Subsections are not supported. +bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) + return true; + } + + COFF::COMDATType Type = (COFF::COMDATType)0; + StringRef COMDATSymName; + if (getLexer().is(AsmToken::Comma)) { + Type = COFF::IMAGE_COMDAT_SELECT_ANY; + Lex(); + + Flags |= COFF::IMAGE_SCN_LNK_COMDAT; + + if (!getLexer().is(AsmToken::Identifier)) + return TokError("expected comdat type such as 'discard' or 'largest' " + "after protection bits"); + + if (parseCOMDATType(Type)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected comma in directive"); + Lex(); + + if (getParser().parseIdentifier(COMDATSymName)) + return TokError("expected identifier in directive"); + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + SectionKind Kind = computeSectionKind(Flags); + if (Kind.isText()) { + const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); + if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) + Flags |= COFF::IMAGE_SCN_MEM_16BIT; + } + ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type); + return false; +} + +bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { + StringRef SymbolName; + + if (getParser().parseIdentifier(SymbolName)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); + + getStreamer().BeginCOFFSymbolDef(Sym); + + Lex(); + return false; +} + +bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { + int64_t SymbolStorageClass; + if (getParser().parseAbsoluteExpression(SymbolStorageClass)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); + return false; +} + +bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + int64_t Type; + if (getParser().parseAbsoluteExpression(Type)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolType(Type); + return false; +} + +bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { + Lex(); + getStreamer().EndCOFFSymbolDef(); + return false; +} + +bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + int64_t Offset = 0; + SMLoc OffsetLoc; + if (getLexer().is(AsmToken::Plus)) { + OffsetLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Offset)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) + return Error( + OffsetLoc, + "invalid '.secrel32' directive offset, can't be less " + "than zero or greater than std::numeric_limits<uint32_t>::max()"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSecRel32(Symbol, Offset); + return false; +} + +bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { + auto parseOp = [&]() -> bool { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + int64_t Offset = 0; + SMLoc OffsetLoc; + if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { + OffsetLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Offset)) + return true; + } + + if (Offset < std::numeric_limits<int32_t>::min() || + Offset > std::numeric_limits<int32_t>::max()) + return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " + "than -2147483648 or greater than " + "2147483647"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + getStreamer().EmitCOFFImgRel32(Symbol, Offset); + return false; + }; + + if (getParser().parseMany(parseOp)) + return addErrorSuffix(" in directive"); + return false; +} + +bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSafeSEH(Symbol); + return false; +} + +bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSectionIndex(Symbol); + return false; +} + +bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSymbolIndex(Symbol); + return false; +} + +/// ::= [ identifier ] +bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { + StringRef TypeId = getTok().getIdentifier(); + + Type = StringSwitch<COFF::COMDATType>(TypeId) + .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) + .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) + .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) + .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) + .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) + .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) + .Default((COFF::COMDATType)0); + + if (Type == 0) + return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); + + Lex(); + + return false; +} + +/// ParseDirectiveLinkOnce +/// ::= .linkonce [ identifier ] +bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + if (getLexer().is(AsmToken::Identifier)) + if (parseCOMDATType(Type)) + return true; + + const MCSectionCOFF *Current = + static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + return Error(Loc, "cannot make section associative with .linkonce"); + + if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) + return Error(Loc, Twine("section '") + Current->getName() + + "' is already linkonce"); + + Current->setSelection(Type); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitWinCFIStartProc(Symbol, Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinCFIEndProc(Loc); + return false; +} + bool COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) { Lex(); getStreamer().EmitWinCFIFuncletOrFuncEnd(Loc); return false; } -bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { - Lex(); - getStreamer().EmitWinCFIStartChained(Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { - Lex(); - getStreamer().EmitWinCFIEndChained(Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { - StringRef SymbolID; - if (getParser().parseIdentifier(SymbolID)) - return true; - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("you must specify one or both of @unwind or @except"); - Lex(); - bool unwind = false, except = false; - if (ParseAtUnwindOrAtExcept(unwind, except)) - return true; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - if (ParseAtUnwindOrAtExcept(unwind, except)) - return true; - } - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); - - Lex(); - getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { - Lex(); - getStreamer().EmitWinEHHandlerData(); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { - int64_t Size; - if (getParser().parseAbsoluteExpression(Size)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - getStreamer().EmitWinCFIAllocStack(Size, Loc); - return false; -} - -bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { - Lex(); - getStreamer().EmitWinCFIEndProlog(Loc); - return false; -} - -bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { - StringRef identifier; - if (getLexer().isNot(AsmToken::At)) - return TokError("a handler attribute must begin with '@'"); - SMLoc startLoc = getLexer().getLoc(); - Lex(); - if (getParser().parseIdentifier(identifier)) - return Error(startLoc, "expected @unwind or @except"); - if (identifier == "unwind") - unwind = true; - else if (identifier == "except") - except = true; - else - return Error(startLoc, "expected @unwind or @except"); - return false; -} - -namespace llvm { - -MCAsmParserExtension *createCOFFAsmParser() { - return new COFFAsmParser; -} - -} // end namespace llvm +bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinCFIStartChained(Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinCFIEndChained(Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { + StringRef SymbolID; + if (getParser().parseIdentifier(SymbolID)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify one or both of @unwind or @except"); + Lex(); + bool unwind = false, except = false; + if (ParseAtUnwindOrAtExcept(unwind, except)) + return true; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (ParseAtUnwindOrAtExcept(unwind, except)) + return true; + } + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinEHHandlerData(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { + int64_t Size; + if (getParser().parseAbsoluteExpression(Size)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWinCFIAllocStack(Size, Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinCFIEndProlog(Loc); + return false; +} + +bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { + StringRef identifier; + if (getLexer().isNot(AsmToken::At)) + return TokError("a handler attribute must begin with '@'"); + SMLoc startLoc = getLexer().getLoc(); + Lex(); + if (getParser().parseIdentifier(identifier)) + return Error(startLoc, "expected @unwind or @except"); + if (identifier == "unwind") + unwind = true; + else if (identifier == "except") + except = true; + else + return Error(startLoc, "expected @unwind or @except"); + return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { + return new COFFAsmParser; +} + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/MC/MCParser/COFFMasmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/COFFMasmParser.cpp index 2930e7b89a..95128cf7d1 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/COFFMasmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/COFFMasmParser.cpp @@ -1,343 +1,343 @@ -//===- 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/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" +//===- 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/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/MCSymbolCOFF.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); - +#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 ParseDirectiveAlias(StringRef, SMLoc); bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); bool ParseSEHDirectiveEndProlog(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 + 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 addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>( ".allocstack"); addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>( ".endprolog"); - - // Code label directives - // label - // org - - // Conditional control flow directives - // .break - // .continue - // .else - // .elseif - // .endif - // .endw - // .if - // .repeat - // .until - // .untilcxz - // .while - - // Data allocation directives - // align - // even + + // Code label directives + // label + // org + + // Conditional control flow directives + // .break + // .continue + // .else + // .elseif + // .endif + // .endw + // .if + // .repeat + // .until + // .untilcxz + // .while + + // Data allocation directives + // align + // even // mmword - // tbyte + // tbyte // xmmword // ymmword - - // Listing control directives - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond"); - addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title"); - - // Macro directives - // goto - - // Miscellaneous directives + + // Listing control directives + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond"); + addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title"); + + // Macro directives + // goto + + // Miscellaneous directives addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias"); - // assume - // .fpo - addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( - "includelib"); - // option - // popcontext - // pushcontext - // .safeseh - - // Procedure directives - addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp"); - // invoke (32-bit only) - addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc"); - // proto - + // assume + // .fpo + addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( + "includelib"); + // option + // popcontext + // pushcontext + // .safeseh + + // Procedure directives + addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp"); + // invoke (32-bit only) + addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc"); + // proto + // Processor directives; all ignored - 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"); - - // 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>("segment"); - - // Simplified segment directives - addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code"); - // .const - addDirectiveHandler< - &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data"); - addDirectiveHandler< - &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?"); - // .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 - // record - // typedef - } - - 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; + 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"); + + // 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>("segment"); + + // Simplified segment directives + addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code"); + // .const + addDirectiveHandler< + &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data"); + addDirectiveHandler< + &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?"); + // .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 + // record + // typedef + } + + 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; bool CurrentProcedureFramed; - -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(); - } - } + +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(); + } + } MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label)); - + // Define symbol as simple external function Sym->setExternal(true); Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT); - + bool Framed = false; if (getLexer().is(AsmToken::Identifier) && getTok().getString().equals_lower("frame")) { @@ -345,32 +345,32 @@ bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) { Framed = true; getStreamer().EmitWinCFIStartProc(Sym, Loc); } - getStreamer().emitLabel(Sym, Loc); + getStreamer().emitLabel(Sym, Loc); - CurrentProcedure = Label; + CurrentProcedure = Label; CurrentProcedureFramed = Framed; - 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; +} +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 + "'"); if (CurrentProcedureFramed) { getStreamer().EmitWinCFIEndProc(Loc); } CurrentProcedure = ""; CurrentProcedureFramed = false; - return false; -} - + return false; +} + bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) { std::string AliasName, ActualName; if (getTok().isNot(AsmToken::Less) || @@ -408,8 +408,8 @@ bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive, return false; } -namespace llvm { - -MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; } - -} // end namespace llvm +namespace llvm { + +MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; } + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/MC/MCParser/DarwinAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/DarwinAsmParser.cpp index 36e0d25660..9264834512 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/DarwinAsmParser.cpp @@ -1,1209 +1,1209 @@ -//===- DarwinAsmParser.cpp - Darwin (Mach-O) 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/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/MachO.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/MCAsmParser.h" -#include "llvm/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/SectionKind.h" -#include "llvm/Support/FileSystem.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 <cstddef> -#include <cstdint> -#include <string> -#include <system_error> -#include <utility> - -using namespace llvm; - -namespace { - -/// Implementation of directive handling which is shared across all -/// Darwin targets. -class DarwinAsmParser : public MCAsmParserExtension { - template<bool (DarwinAsmParser::*HandlerMethod)(StringRef, SMLoc)> - void addDirectiveHandler(StringRef Directive) { - MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( - this, HandleDirective<DarwinAsmParser, HandlerMethod>); - getParser().addDirectiveHandler(Directive, Handler); - } - - bool parseSectionSwitch(StringRef Segment, StringRef Section, - unsigned TAA = 0, unsigned ImplicitAlign = 0, - unsigned StubSize = 0); - - SMLoc LastVersionDirective; - -public: - DarwinAsmParser() = default; - - void Initialize(MCAsmParser &Parser) override { - // Call the base implementation. - this->MCAsmParserExtension::Initialize(Parser); - - addDirectiveHandler<&DarwinAsmParser::parseDirectiveAltEntry>(".alt_entry"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveDesc>(".desc"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveIndirectSymbol>( - ".indirect_symbol"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveLsym>(".lsym"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveSubsectionsViaSymbols>( - ".subsections_via_symbols"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".dump"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".load"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveSection>(".section"); - addDirectiveHandler<&DarwinAsmParser::parseDirectivePushSection>( - ".pushsection"); - addDirectiveHandler<&DarwinAsmParser::parseDirectivePopSection>( - ".popsection"); - addDirectiveHandler<&DarwinAsmParser::parseDirectivePrevious>(".previous"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogUnique>( - ".secure_log_unique"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogReset>( - ".secure_log_reset"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveTBSS>(".tbss"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveZerofill>(".zerofill"); - - addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegion>( - ".data_region"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegionEnd>( - ".end_data_region"); - - // Special section directives. - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveBss>(".bss"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConst>(".const"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstData>( - ".const_data"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstructor>( - ".constructor"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveCString>( - ".cstring"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveData>(".data"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDestructor>( - ".destructor"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDyld>(".dyld"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit0>( - ".fvmlib_init0"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit1>( - ".fvmlib_init1"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveLazySymbolPointers>( - ".lazy_symbol_pointer"); - addDirectiveHandler<&DarwinAsmParser::parseDirectiveLinkerOption>( - ".linker_option"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral16>( - ".literal16"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral4>( - ".literal4"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral8>( - ".literal8"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModInitFunc>( - ".mod_init_func"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModTermFunc>( - ".mod_term_func"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveNonLazySymbolPointers>( - ".non_lazy_symbol_pointer"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveThreadLocalVariablePointers>( - ".thread_local_variable_pointer"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatClsMeth>( - ".objc_cat_cls_meth"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatInstMeth>( - ".objc_cat_inst_meth"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCategory>( - ".objc_category"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClass>( - ".objc_class"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassNames>( - ".objc_class_names"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassVars>( - ".objc_class_vars"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsMeth>( - ".objc_cls_meth"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsRefs>( - ".objc_cls_refs"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCInstMeth>( - ".objc_inst_meth"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveObjCInstanceVars>( - ".objc_instance_vars"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMessageRefs>( - ".objc_message_refs"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMetaClass>( - ".objc_meta_class"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveObjCMethVarNames>( - ".objc_meth_var_names"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveObjCMethVarTypes>( - ".objc_meth_var_types"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCModuleInfo>( - ".objc_module_info"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCProtocol>( - ".objc_protocol"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveObjCSelectorStrs>( - ".objc_selector_strs"); - addDirectiveHandler< - &DarwinAsmParser::parseSectionDirectiveObjCStringObject>( - ".objc_string_object"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCSymbols>( - ".objc_symbols"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectivePICSymbolStub>( - ".picsymbol_stub"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticConst>( - ".static_const"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticData>( - ".static_data"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveSymbolStub>( - ".symbol_stub"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTData>(".tdata"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveText>(".text"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveThreadInitFunc>( - ".thread_init_func"); - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTLV>(".tlv"); - - addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveIdent>(".ident"); - addDirectiveHandler<&DarwinAsmParser::parseWatchOSVersionMin>( - ".watchos_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseTvOSVersionMin>( - ".tvos_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseIOSVersionMin>( - ".ios_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>( - ".macosx_version_min"); - addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version"); - - LastVersionDirective = SMLoc(); - } - - bool parseDirectiveAltEntry(StringRef, SMLoc); - bool parseDirectiveDesc(StringRef, SMLoc); - bool parseDirectiveIndirectSymbol(StringRef, SMLoc); - bool parseDirectiveDumpOrLoad(StringRef, SMLoc); - bool parseDirectiveLsym(StringRef, SMLoc); - bool parseDirectiveLinkerOption(StringRef, SMLoc); - bool parseDirectiveSection(StringRef, SMLoc); - bool parseDirectivePushSection(StringRef, SMLoc); - bool parseDirectivePopSection(StringRef, SMLoc); - bool parseDirectivePrevious(StringRef, SMLoc); - bool parseDirectiveSecureLogReset(StringRef, SMLoc); - bool parseDirectiveSecureLogUnique(StringRef, SMLoc); - bool parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); - bool parseDirectiveTBSS(StringRef, SMLoc); - bool parseDirectiveZerofill(StringRef, SMLoc); - bool parseDirectiveDataRegion(StringRef, SMLoc); - bool parseDirectiveDataRegionEnd(StringRef, SMLoc); - - // Named Section Directive - bool parseSectionDirectiveBss(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__bss"); - } - - bool parseSectionDirectiveConst(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__const"); - } - - bool parseSectionDirectiveStaticConst(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__static_const"); - } - - bool parseSectionDirectiveCString(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__cstring", - MachO::S_CSTRING_LITERALS); - } - - bool parseSectionDirectiveLiteral4(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__literal4", - MachO::S_4BYTE_LITERALS, 4); - } - - bool parseSectionDirectiveLiteral8(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__literal8", - MachO::S_8BYTE_LITERALS, 8); - } - - bool parseSectionDirectiveLiteral16(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__literal16", - MachO::S_16BYTE_LITERALS, 16); - } - - bool parseSectionDirectiveConstructor(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__constructor"); - } - - bool parseSectionDirectiveDestructor(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__destructor"); - } - - bool parseSectionDirectiveFVMLibInit0(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__fvmlib_init0"); - } - - bool parseSectionDirectiveFVMLibInit1(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__fvmlib_init1"); - } - - bool parseSectionDirectiveSymbolStub(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__symbol_stub", - MachO::S_SYMBOL_STUBS | - MachO::S_ATTR_PURE_INSTRUCTIONS, - // FIXME: Different on PPC and ARM. - 0, 16); - } - - bool parseSectionDirectivePICSymbolStub(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT","__picsymbol_stub", - MachO::S_SYMBOL_STUBS | - MachO::S_ATTR_PURE_INSTRUCTIONS, 0, 26); - } - - bool parseSectionDirectiveData(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__data"); - } - - bool parseSectionDirectiveStaticData(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__static_data"); - } - - bool parseSectionDirectiveNonLazySymbolPointers(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__nl_symbol_ptr", - MachO::S_NON_LAZY_SYMBOL_POINTERS, 4); - } - - bool parseSectionDirectiveLazySymbolPointers(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__la_symbol_ptr", - MachO::S_LAZY_SYMBOL_POINTERS, 4); - } - - bool parseSectionDirectiveThreadLocalVariablePointers(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__thread_ptr", - MachO::S_THREAD_LOCAL_VARIABLE_POINTERS, 4); - } - - bool parseSectionDirectiveDyld(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__dyld"); - } - - bool parseSectionDirectiveModInitFunc(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__mod_init_func", - MachO::S_MOD_INIT_FUNC_POINTERS, 4); - } - - bool parseSectionDirectiveModTermFunc(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__mod_term_func", - MachO::S_MOD_TERM_FUNC_POINTERS, 4); - } - - bool parseSectionDirectiveConstData(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__const"); - } - - bool parseSectionDirectiveObjCClass(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__class", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCMetaClass(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__meta_class", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCCatClsMeth(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__cat_cls_meth", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCCatInstMeth(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__cat_inst_meth", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCProtocol(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__protocol", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCStringObject(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__string_object", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCClsMeth(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__cls_meth", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCInstMeth(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__inst_meth", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCClsRefs(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__cls_refs", - MachO::S_ATTR_NO_DEAD_STRIP | - MachO::S_LITERAL_POINTERS, 4); - } - - bool parseSectionDirectiveObjCMessageRefs(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__message_refs", - MachO::S_ATTR_NO_DEAD_STRIP | - MachO::S_LITERAL_POINTERS, 4); - } - - bool parseSectionDirectiveObjCSymbols(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__symbols", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCCategory(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__category", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCClassVars(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__class_vars", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCInstanceVars(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__instance_vars", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCModuleInfo(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__module_info", - MachO::S_ATTR_NO_DEAD_STRIP); - } - - bool parseSectionDirectiveObjCClassNames(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__cstring", - MachO::S_CSTRING_LITERALS); - } - - bool parseSectionDirectiveObjCMethVarTypes(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__cstring", - MachO::S_CSTRING_LITERALS); - } - - bool parseSectionDirectiveObjCMethVarNames(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__cstring", - MachO::S_CSTRING_LITERALS); - } - - bool parseSectionDirectiveObjCSelectorStrs(StringRef, SMLoc) { - return parseSectionSwitch("__OBJC", "__selector_strs", - MachO::S_CSTRING_LITERALS); - } - - bool parseSectionDirectiveTData(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__thread_data", - MachO::S_THREAD_LOCAL_REGULAR); - } - - bool parseSectionDirectiveText(StringRef, SMLoc) { - return parseSectionSwitch("__TEXT", "__text", - MachO::S_ATTR_PURE_INSTRUCTIONS); - } - - bool parseSectionDirectiveTLV(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__thread_vars", - MachO::S_THREAD_LOCAL_VARIABLES); - } - - bool parseSectionDirectiveIdent(StringRef, SMLoc) { - // Darwin silently ignores the .ident directive. - getParser().eatToEndOfStatement(); - return false; - } - - bool parseSectionDirectiveThreadInitFunc(StringRef, SMLoc) { - return parseSectionSwitch("__DATA", "__thread_init", - MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS); - } - - bool parseWatchOSVersionMin(StringRef Directive, SMLoc Loc) { - return parseVersionMin(Directive, Loc, MCVM_WatchOSVersionMin); - } - bool parseTvOSVersionMin(StringRef Directive, SMLoc Loc) { - return parseVersionMin(Directive, Loc, MCVM_TvOSVersionMin); - } - bool parseIOSVersionMin(StringRef Directive, SMLoc Loc) { - return parseVersionMin(Directive, Loc, MCVM_IOSVersionMin); - } - bool parseMacOSXVersionMin(StringRef Directive, SMLoc Loc) { - return parseVersionMin(Directive, Loc, MCVM_OSXVersionMin); - } - - bool parseBuildVersion(StringRef Directive, SMLoc Loc); - bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); - bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, - const char *VersionName); - bool parseOptionalTrailingVersionComponent(unsigned *Component, - const char *ComponentName); - bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); - bool parseSDKVersion(VersionTuple &SDKVersion); - void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, - Triple::OSType ExpectedOS); -}; - -} // end anonymous namespace - -bool DarwinAsmParser::parseSectionSwitch(StringRef Segment, StringRef Section, - unsigned TAA, unsigned Align, - unsigned StubSize) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in section switching directive"); - Lex(); - - // FIXME: Arch specific. - bool isText = TAA & MachO::S_ATTR_PURE_INSTRUCTIONS; - getStreamer().SwitchSection(getContext().getMachOSection( - Segment, Section, TAA, StubSize, - isText ? SectionKind::getText() : SectionKind::getData())); - - // Set the implicit alignment, if any. - // - // FIXME: This isn't really what 'as' does; I think it just uses the implicit - // alignment on the section (e.g., if one manually inserts bytes into the - // section, then just issuing the section switch directive will not realign - // the section. However, this is arguably more reasonable behavior, and there - // is no good reason for someone to intentionally emit incorrectly sized - // values into the implicitly aligned sections. - if (Align) - getStreamer().emitValueToAlignment(Align); - - return false; -} - -/// parseDirectiveAltEntry -/// ::= .alt_entry identifier -bool DarwinAsmParser::parseDirectiveAltEntry(StringRef, SMLoc) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - // Look up symbol. - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - if (Sym->isDefined()) - return TokError(".alt_entry must preceed symbol definition"); - - if (!getStreamer().emitSymbolAttribute(Sym, MCSA_AltEntry)) - return TokError("unable to emit symbol attribute"); - - Lex(); - return false; -} - -/// parseDirectiveDesc -/// ::= .desc identifier , expression -bool DarwinAsmParser::parseDirectiveDesc(StringRef, SMLoc) { - StringRef Name; - if (getParser().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 '.desc' directive"); - Lex(); - - int64_t DescValue; - if (getParser().parseAbsoluteExpression(DescValue)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.desc' directive"); - - Lex(); - - // Set the n_desc field of this Symbol to this DescValue - getStreamer().emitSymbolDesc(Sym, DescValue); - - return false; -} - -/// parseDirectiveIndirectSymbol -/// ::= .indirect_symbol identifier -bool DarwinAsmParser::parseDirectiveIndirectSymbol(StringRef, SMLoc Loc) { - const MCSectionMachO *Current = static_cast<const MCSectionMachO *>( - getStreamer().getCurrentSectionOnly()); - MachO::SectionType SectionType = Current->getType(); - if (SectionType != MachO::S_NON_LAZY_SYMBOL_POINTERS && - SectionType != MachO::S_LAZY_SYMBOL_POINTERS && - SectionType != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS && - SectionType != MachO::S_SYMBOL_STUBS) - return Error(Loc, "indirect symbol not in a symbol pointer or stub " - "section"); - - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in .indirect_symbol directive"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - // Assembler local symbols don't make any sense here. Complain loudly. - if (Sym->isTemporary()) - return TokError("non-local symbol required in directive"); - - if (!getStreamer().emitSymbolAttribute(Sym, MCSA_IndirectSymbol)) - return TokError("unable to emit indirect symbol attribute for: " + Name); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.indirect_symbol' directive"); - - Lex(); - - return false; -} - -/// parseDirectiveDumpOrLoad -/// ::= ( .dump | .load ) "filename" -bool DarwinAsmParser::parseDirectiveDumpOrLoad(StringRef Directive, - SMLoc IDLoc) { - bool IsDump = Directive == ".dump"; - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '.dump' or '.load' directive"); - - Lex(); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.dump' or '.load' directive"); - - Lex(); - - // FIXME: If/when .dump and .load are implemented they will be done in the - // the assembly parser and not have any need for an MCStreamer API. - if (IsDump) - return Warning(IDLoc, "ignoring directive .dump for now"); - else - return Warning(IDLoc, "ignoring directive .load for now"); -} - -/// ParseDirectiveLinkerOption -/// ::= .linker_option "string" ( , "string" )* -bool DarwinAsmParser::parseDirectiveLinkerOption(StringRef IDVal, SMLoc) { - SmallVector<std::string, 4> Args; - while (true) { - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '" + Twine(IDVal) + "' directive"); - - std::string Data; - if (getParser().parseEscapedString(Data)) - return true; - - Args.push_back(Data); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); - Lex(); - } - - getStreamer().emitLinkerOptions(Args); - return false; -} - -/// parseDirectiveLsym -/// ::= .lsym identifier , expression -bool DarwinAsmParser::parseDirectiveLsym(StringRef, SMLoc) { - StringRef Name; - if (getParser().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 '.lsym' directive"); - Lex(); - - const MCExpr *Value; - if (getParser().parseExpression(Value)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.lsym' directive"); - - Lex(); - - // We don't currently support this directive. - // - // FIXME: Diagnostic location! - (void) Sym; - return TokError("directive '.lsym' is unsupported"); -} - -/// parseDirectiveSection: -/// ::= .section identifier (',' identifier)* -bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) { - SMLoc Loc = getLexer().getLoc(); - - StringRef SectionName; - if (getParser().parseIdentifier(SectionName)) - return Error(Loc, "expected identifier after '.section' directive"); - - // Verify there is a following comma. - if (!getLexer().is(AsmToken::Comma)) - return TokError("unexpected token in '.section' directive"); - - std::string SectionSpec = std::string(SectionName); - SectionSpec += ","; - - // Add all the tokens until the end of the line, ParseSectionSpecifier will - // handle this. - StringRef EOL = getLexer().LexUntilEndOfStatement(); - SectionSpec.append(EOL.begin(), EOL.end()); - - Lex(); - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.section' directive"); - Lex(); - - StringRef Segment, Section; - unsigned StubSize; - unsigned TAA; - bool TAAParsed; - std::string ErrorStr = - MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, - TAA, TAAParsed, StubSize); - - if (!ErrorStr.empty()) - return Error(Loc, ErrorStr); - - // Issue a warning if the target is not powerpc and Section is a *coal* section. - Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple(); - Triple::ArchType ArchTy = TT.getArch(); - - if (ArchTy != Triple::ppc && ArchTy != Triple::ppc64) { - StringRef NonCoalSection = StringSwitch<StringRef>(Section) - .Case("__textcoal_nt", "__text") - .Case("__const_coal", "__const") - .Case("__datacoal_nt", "__data") - .Default(Section); - - if (!Section.equals(NonCoalSection)) { - StringRef SectionVal(Loc.getPointer()); - size_t B = SectionVal.find(',') + 1, E = SectionVal.find(',', B); - SMLoc BLoc = SMLoc::getFromPointer(SectionVal.data() + B); - SMLoc ELoc = SMLoc::getFromPointer(SectionVal.data() + E); - getParser().Warning(Loc, "section \"" + Section + "\" is deprecated", - SMRange(BLoc, ELoc)); - getParser().Note(Loc, "change section name to \"" + NonCoalSection + - "\"", SMRange(BLoc, ELoc)); - } - } - - // FIXME: Arch specific. - bool isText = Segment == "__TEXT"; // FIXME: Hack. - getStreamer().SwitchSection(getContext().getMachOSection( - Segment, Section, TAA, StubSize, - isText ? SectionKind::getText() : SectionKind::getData())); - return false; -} - -/// ParseDirectivePushSection: -/// ::= .pushsection identifier (',' identifier)* -bool DarwinAsmParser::parseDirectivePushSection(StringRef S, SMLoc Loc) { - getStreamer().PushSection(); - - if (parseDirectiveSection(S, Loc)) { - getStreamer().PopSection(); - return true; - } - - return false; -} - -/// ParseDirectivePopSection: -/// ::= .popsection -bool DarwinAsmParser::parseDirectivePopSection(StringRef, SMLoc) { - if (!getStreamer().PopSection()) - return TokError(".popsection without corresponding .pushsection"); - return false; -} - -/// ParseDirectivePrevious: -/// ::= .previous -bool DarwinAsmParser::parseDirectivePrevious(StringRef DirName, SMLoc) { - MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); - if (!PreviousSection.first) - return TokError(".previous without corresponding .section"); - getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); - return false; -} - -/// ParseDirectiveSecureLogUnique -/// ::= .secure_log_unique ... message ... -bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { - StringRef LogMessage = getParser().parseStringToEndOfStatement(); - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.secure_log_unique' directive"); - - if (getContext().getSecureLogUsed()) - return Error(IDLoc, ".secure_log_unique specified multiple times"); - - // Get the secure log path. - const char *SecureLogFile = getContext().getSecureLogFile(); - if (!SecureLogFile) - return Error(IDLoc, ".secure_log_unique used but AS_SECURE_LOG_FILE " - "environment variable unset."); - - // Open the secure log file if we haven't already. - raw_fd_ostream *OS = getContext().getSecureLog(); - if (!OS) { - std::error_code EC; - auto NewOS = std::make_unique<raw_fd_ostream>( - StringRef(SecureLogFile), EC, sys::fs::OF_Append | sys::fs::OF_Text); - if (EC) - return Error(IDLoc, Twine("can't open secure log file: ") + - SecureLogFile + " (" + EC.message() + ")"); - OS = NewOS.get(); - getContext().setSecureLog(std::move(NewOS)); - } - - // Write the message. - unsigned CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc); - *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier() - << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":" - << LogMessage + "\n"; - - getContext().setSecureLogUsed(true); - - return false; -} - -/// ParseDirectiveSecureLogReset -/// ::= .secure_log_reset -bool DarwinAsmParser::parseDirectiveSecureLogReset(StringRef, SMLoc IDLoc) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.secure_log_reset' directive"); - - Lex(); - - getContext().setSecureLogUsed(false); - - return false; -} - -/// parseDirectiveSubsectionsViaSymbols -/// ::= .subsections_via_symbols -bool DarwinAsmParser::parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.subsections_via_symbols' directive"); - - Lex(); - - getStreamer().emitAssemblerFlag(MCAF_SubsectionsViaSymbols); - - return false; -} - -/// ParseDirectiveTBSS -/// ::= .tbss identifier, size, align -bool DarwinAsmParser::parseDirectiveTBSS(StringRef, SMLoc) { - SMLoc IDLoc = getLexer().getLoc(); - StringRef Name; - if (getParser().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 (getParser().parseAbsoluteExpression(Size)) - return true; - - int64_t Pow2Alignment = 0; - SMLoc Pow2AlignmentLoc; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - Pow2AlignmentLoc = getLexer().getLoc(); - if (getParser().parseAbsoluteExpression(Pow2Alignment)) - return true; - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.tbss' directive"); - - Lex(); - - if (Size < 0) - return Error(SizeLoc, "invalid '.tbss' directive size, can't be less than" - "zero"); - - // FIXME: Diagnose overflow. - if (Pow2Alignment < 0) - return Error(Pow2AlignmentLoc, "invalid '.tbss' alignment, can't be less" - "than zero"); - - if (!Sym->isUndefined()) - return Error(IDLoc, "invalid symbol redefinition"); - - getStreamer().emitTBSSSymbol( - getContext().getMachOSection("__DATA", "__thread_bss", - MachO::S_THREAD_LOCAL_ZEROFILL, 0, - SectionKind::getThreadBSS()), - Sym, Size, 1 << Pow2Alignment); - - return false; -} - -/// ParseDirectiveZerofill -/// ::= .zerofill segname , sectname [, identifier , size_expression [ -/// , align_expression ]] -bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { - StringRef Segment; - if (getParser().parseIdentifier(Segment)) - return TokError("expected segment name after '.zerofill' directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - - StringRef Section; - SMLoc SectionLoc = getLexer().getLoc(); - if (getParser().parseIdentifier(Section)) - return TokError("expected section name after comma in '.zerofill' " - "directive"); - - // If this is the end of the line all that was wanted was to create the - // the section but with no symbol. - if (getLexer().is(AsmToken::EndOfStatement)) { - // Create the zerofill section but no symbol - getStreamer().emitZerofill( - getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0, - SectionKind::getBSS()), - /*Symbol=*/nullptr, /*Size=*/0, /*ByteAlignment=*/0, SectionLoc); - return false; - } - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - - SMLoc IDLoc = getLexer().getLoc(); - StringRef IDStr; - if (getParser().parseIdentifier(IDStr)) - return TokError("expected identifier in directive"); - - // handle the identifier as the key symbol. - MCSymbol *Sym = getContext().getOrCreateSymbol(IDStr); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - - int64_t Size; - SMLoc SizeLoc = getLexer().getLoc(); - if (getParser().parseAbsoluteExpression(Size)) - return true; - - int64_t Pow2Alignment = 0; - SMLoc Pow2AlignmentLoc; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - Pow2AlignmentLoc = getLexer().getLoc(); - if (getParser().parseAbsoluteExpression(Pow2Alignment)) - return true; - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.zerofill' directive"); - - Lex(); - - if (Size < 0) - return Error(SizeLoc, "invalid '.zerofill' 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 '.zerofill' directive alignment, " - "can't be less than zero"); - - if (!Sym->isUndefined()) - return Error(IDLoc, "invalid symbol redefinition"); - - // Create the zerofill Symbol with Size and Pow2Alignment - // - // FIXME: Arch specific. - getStreamer().emitZerofill(getContext().getMachOSection( - Segment, Section, MachO::S_ZEROFILL, - 0, SectionKind::getBSS()), - Sym, Size, 1 << Pow2Alignment, SectionLoc); - - return false; -} - -/// ParseDirectiveDataRegion -/// ::= .data_region [ ( jt8 | jt16 | jt32 ) ] -bool DarwinAsmParser::parseDirectiveDataRegion(StringRef, SMLoc) { - if (getLexer().is(AsmToken::EndOfStatement)) { - Lex(); - getStreamer().emitDataRegion(MCDR_DataRegion); - return false; - } - StringRef RegionType; - SMLoc Loc = getParser().getTok().getLoc(); - if (getParser().parseIdentifier(RegionType)) - return TokError("expected region type after '.data_region' directive"); - int Kind = StringSwitch<int>(RegionType) - .Case("jt8", MCDR_DataRegionJT8) - .Case("jt16", MCDR_DataRegionJT16) - .Case("jt32", MCDR_DataRegionJT32) - .Default(-1); - if (Kind == -1) - return Error(Loc, "unknown region type in '.data_region' directive"); - Lex(); - - getStreamer().emitDataRegion((MCDataRegionType)Kind); - return false; -} - -/// ParseDirectiveDataRegionEnd -/// ::= .end_data_region -bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.end_data_region' directive"); - - Lex(); - getStreamer().emitDataRegion(MCDR_DataRegionEnd); - return false; -} - -static bool isSDKVersionToken(const AsmToken &Tok) { - return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version"; -} - -/// parseMajorMinorVersionComponent ::= major, minor -bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major, - unsigned *Minor, - const char *VersionName) { - // Get the major version number. - if (getLexer().isNot(AsmToken::Integer)) - return TokError(Twine("invalid ") + VersionName + - " major version number, integer expected"); - int64_t MajorVal = getLexer().getTok().getIntVal(); - if (MajorVal > 65535 || MajorVal <= 0) - return TokError(Twine("invalid ") + VersionName + " major version number"); - *Major = (unsigned)MajorVal; - Lex(); - if (getLexer().isNot(AsmToken::Comma)) - return TokError(Twine(VersionName) + - " minor version number required, comma expected"); - Lex(); - // Get the minor version number. - if (getLexer().isNot(AsmToken::Integer)) - return TokError(Twine("invalid ") + VersionName + - " minor version number, integer expected"); - int64_t MinorVal = getLexer().getTok().getIntVal(); - if (MinorVal > 255 || MinorVal < 0) - return TokError(Twine("invalid ") + VersionName + " minor version number"); - *Minor = MinorVal; - Lex(); - return false; -} - -/// parseOptionalTrailingVersionComponent ::= , version_number -bool DarwinAsmParser::parseOptionalTrailingVersionComponent( - unsigned *Component, const char *ComponentName) { - assert(getLexer().is(AsmToken::Comma) && "comma expected"); - Lex(); - if (getLexer().isNot(AsmToken::Integer)) - return TokError(Twine("invalid ") + ComponentName + - " version number, integer expected"); - int64_t Val = getLexer().getTok().getIntVal(); - if (Val > 255 || Val < 0) - return TokError(Twine("invalid ") + ComponentName + " version number"); - *Component = Val; - Lex(); - return false; -} - -/// parseVersion ::= parseMajorMinorVersionComponent -/// parseOptionalTrailingVersionComponent -bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, - unsigned *Update) { - if (parseMajorMinorVersionComponent(Major, Minor, "OS")) - return true; - - // Get the update level, if specified - *Update = 0; - if (getLexer().is(AsmToken::EndOfStatement) || - isSDKVersionToken(getLexer().getTok())) - return false; - if (getLexer().isNot(AsmToken::Comma)) - return TokError("invalid OS update specifier, comma expected"); - if (parseOptionalTrailingVersionComponent(Update, "OS update")) - return true; - return false; -} - -bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) { - assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version"); - Lex(); - unsigned Major, Minor; - if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK")) - return true; - SDKVersion = VersionTuple(Major, Minor); - - // Get the subminor version, if specified. - if (getLexer().is(AsmToken::Comma)) { - unsigned Subminor; - if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor")) - return true; - SDKVersion = VersionTuple(Major, Minor, Subminor); - } - return false; -} - -void DarwinAsmParser::checkVersion(StringRef Directive, StringRef Arg, - SMLoc Loc, Triple::OSType ExpectedOS) { - const Triple &Target = getContext().getObjectFileInfo()->getTargetTriple(); - if (Target.getOS() != ExpectedOS) - Warning(Loc, Twine(Directive) + - (Arg.empty() ? Twine() : Twine(' ') + Arg) + - " used while targeting " + Target.getOSName()); - - if (LastVersionDirective.isValid()) { - Warning(Loc, "overriding previous version directive"); - Note(LastVersionDirective, "previous definition is here"); - } - LastVersionDirective = Loc; -} - -static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { - switch (Type) { - case MCVM_WatchOSVersionMin: return Triple::WatchOS; - case MCVM_TvOSVersionMin: return Triple::TvOS; - case MCVM_IOSVersionMin: return Triple::IOS; - case MCVM_OSXVersionMin: return Triple::MacOSX; - } - llvm_unreachable("Invalid mc version min type"); -} - -/// parseVersionMin -/// ::= .ios_version_min parseVersion parseSDKVersion -/// | .macosx_version_min parseVersion parseSDKVersion -/// | .tvos_version_min parseVersion parseSDKVersion -/// | .watchos_version_min parseVersion parseSDKVersion -bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, - MCVersionMinType Type) { - unsigned Major; - unsigned Minor; - unsigned Update; - if (parseVersion(&Major, &Minor, &Update)) - return true; - - VersionTuple SDKVersion; - if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) - return true; - - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(Twine(" in '") + Directive + "' directive"); - - Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type); - checkVersion(Directive, StringRef(), Loc, ExpectedOS); - getStreamer().emitVersionMin(Type, Major, Minor, Update, SDKVersion); - return false; -} - -static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { - switch (Type) { - case MachO::PLATFORM_MACOS: return Triple::MacOSX; - case MachO::PLATFORM_IOS: return Triple::IOS; - case MachO::PLATFORM_TVOS: return Triple::TvOS; - case MachO::PLATFORM_WATCHOS: return Triple::WatchOS; - case MachO::PLATFORM_BRIDGEOS: /* silence warning */ break; - case MachO::PLATFORM_MACCATALYST: return Triple::IOS; - case MachO::PLATFORM_IOSSIMULATOR: /* silence warning */ break; - case MachO::PLATFORM_TVOSSIMULATOR: /* silence warning */ break; - case MachO::PLATFORM_WATCHOSSIMULATOR: /* silence warning */ break; +//===- DarwinAsmParser.cpp - Darwin (Mach-O) 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/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.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/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/FileSystem.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 <cstddef> +#include <cstdint> +#include <string> +#include <system_error> +#include <utility> + +using namespace llvm; + +namespace { + +/// Implementation of directive handling which is shared across all +/// Darwin targets. +class DarwinAsmParser : public MCAsmParserExtension { + template<bool (DarwinAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<DarwinAsmParser, HandlerMethod>); + getParser().addDirectiveHandler(Directive, Handler); + } + + bool parseSectionSwitch(StringRef Segment, StringRef Section, + unsigned TAA = 0, unsigned ImplicitAlign = 0, + unsigned StubSize = 0); + + SMLoc LastVersionDirective; + +public: + DarwinAsmParser() = default; + + void Initialize(MCAsmParser &Parser) override { + // Call the base implementation. + this->MCAsmParserExtension::Initialize(Parser); + + addDirectiveHandler<&DarwinAsmParser::parseDirectiveAltEntry>(".alt_entry"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveDesc>(".desc"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveIndirectSymbol>( + ".indirect_symbol"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveLsym>(".lsym"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveSubsectionsViaSymbols>( + ".subsections_via_symbols"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".dump"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".load"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveSection>(".section"); + addDirectiveHandler<&DarwinAsmParser::parseDirectivePushSection>( + ".pushsection"); + addDirectiveHandler<&DarwinAsmParser::parseDirectivePopSection>( + ".popsection"); + addDirectiveHandler<&DarwinAsmParser::parseDirectivePrevious>(".previous"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogUnique>( + ".secure_log_unique"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogReset>( + ".secure_log_reset"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveTBSS>(".tbss"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveZerofill>(".zerofill"); + + addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegion>( + ".data_region"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegionEnd>( + ".end_data_region"); + + // Special section directives. + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveBss>(".bss"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConst>(".const"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstData>( + ".const_data"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstructor>( + ".constructor"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveCString>( + ".cstring"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveData>(".data"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDestructor>( + ".destructor"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDyld>(".dyld"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit0>( + ".fvmlib_init0"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit1>( + ".fvmlib_init1"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveLazySymbolPointers>( + ".lazy_symbol_pointer"); + addDirectiveHandler<&DarwinAsmParser::parseDirectiveLinkerOption>( + ".linker_option"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral16>( + ".literal16"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral4>( + ".literal4"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral8>( + ".literal8"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModInitFunc>( + ".mod_init_func"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModTermFunc>( + ".mod_term_func"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveNonLazySymbolPointers>( + ".non_lazy_symbol_pointer"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveThreadLocalVariablePointers>( + ".thread_local_variable_pointer"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatClsMeth>( + ".objc_cat_cls_meth"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatInstMeth>( + ".objc_cat_inst_meth"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCategory>( + ".objc_category"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClass>( + ".objc_class"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassNames>( + ".objc_class_names"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassVars>( + ".objc_class_vars"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsMeth>( + ".objc_cls_meth"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsRefs>( + ".objc_cls_refs"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCInstMeth>( + ".objc_inst_meth"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveObjCInstanceVars>( + ".objc_instance_vars"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMessageRefs>( + ".objc_message_refs"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMetaClass>( + ".objc_meta_class"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveObjCMethVarNames>( + ".objc_meth_var_names"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveObjCMethVarTypes>( + ".objc_meth_var_types"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCModuleInfo>( + ".objc_module_info"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCProtocol>( + ".objc_protocol"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveObjCSelectorStrs>( + ".objc_selector_strs"); + addDirectiveHandler< + &DarwinAsmParser::parseSectionDirectiveObjCStringObject>( + ".objc_string_object"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCSymbols>( + ".objc_symbols"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectivePICSymbolStub>( + ".picsymbol_stub"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticConst>( + ".static_const"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticData>( + ".static_data"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveSymbolStub>( + ".symbol_stub"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTData>(".tdata"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveText>(".text"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveThreadInitFunc>( + ".thread_init_func"); + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTLV>(".tlv"); + + addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveIdent>(".ident"); + addDirectiveHandler<&DarwinAsmParser::parseWatchOSVersionMin>( + ".watchos_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseTvOSVersionMin>( + ".tvos_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseIOSVersionMin>( + ".ios_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>( + ".macosx_version_min"); + addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version"); + + LastVersionDirective = SMLoc(); + } + + bool parseDirectiveAltEntry(StringRef, SMLoc); + bool parseDirectiveDesc(StringRef, SMLoc); + bool parseDirectiveIndirectSymbol(StringRef, SMLoc); + bool parseDirectiveDumpOrLoad(StringRef, SMLoc); + bool parseDirectiveLsym(StringRef, SMLoc); + bool parseDirectiveLinkerOption(StringRef, SMLoc); + bool parseDirectiveSection(StringRef, SMLoc); + bool parseDirectivePushSection(StringRef, SMLoc); + bool parseDirectivePopSection(StringRef, SMLoc); + bool parseDirectivePrevious(StringRef, SMLoc); + bool parseDirectiveSecureLogReset(StringRef, SMLoc); + bool parseDirectiveSecureLogUnique(StringRef, SMLoc); + bool parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); + bool parseDirectiveTBSS(StringRef, SMLoc); + bool parseDirectiveZerofill(StringRef, SMLoc); + bool parseDirectiveDataRegion(StringRef, SMLoc); + bool parseDirectiveDataRegionEnd(StringRef, SMLoc); + + // Named Section Directive + bool parseSectionDirectiveBss(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__bss"); + } + + bool parseSectionDirectiveConst(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__const"); + } + + bool parseSectionDirectiveStaticConst(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__static_const"); + } + + bool parseSectionDirectiveCString(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__cstring", + MachO::S_CSTRING_LITERALS); + } + + bool parseSectionDirectiveLiteral4(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__literal4", + MachO::S_4BYTE_LITERALS, 4); + } + + bool parseSectionDirectiveLiteral8(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__literal8", + MachO::S_8BYTE_LITERALS, 8); + } + + bool parseSectionDirectiveLiteral16(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__literal16", + MachO::S_16BYTE_LITERALS, 16); + } + + bool parseSectionDirectiveConstructor(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__constructor"); + } + + bool parseSectionDirectiveDestructor(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__destructor"); + } + + bool parseSectionDirectiveFVMLibInit0(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__fvmlib_init0"); + } + + bool parseSectionDirectiveFVMLibInit1(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__fvmlib_init1"); + } + + bool parseSectionDirectiveSymbolStub(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__symbol_stub", + MachO::S_SYMBOL_STUBS | + MachO::S_ATTR_PURE_INSTRUCTIONS, + // FIXME: Different on PPC and ARM. + 0, 16); + } + + bool parseSectionDirectivePICSymbolStub(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT","__picsymbol_stub", + MachO::S_SYMBOL_STUBS | + MachO::S_ATTR_PURE_INSTRUCTIONS, 0, 26); + } + + bool parseSectionDirectiveData(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__data"); + } + + bool parseSectionDirectiveStaticData(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__static_data"); + } + + bool parseSectionDirectiveNonLazySymbolPointers(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__nl_symbol_ptr", + MachO::S_NON_LAZY_SYMBOL_POINTERS, 4); + } + + bool parseSectionDirectiveLazySymbolPointers(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__la_symbol_ptr", + MachO::S_LAZY_SYMBOL_POINTERS, 4); + } + + bool parseSectionDirectiveThreadLocalVariablePointers(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__thread_ptr", + MachO::S_THREAD_LOCAL_VARIABLE_POINTERS, 4); + } + + bool parseSectionDirectiveDyld(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__dyld"); + } + + bool parseSectionDirectiveModInitFunc(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__mod_init_func", + MachO::S_MOD_INIT_FUNC_POINTERS, 4); + } + + bool parseSectionDirectiveModTermFunc(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__mod_term_func", + MachO::S_MOD_TERM_FUNC_POINTERS, 4); + } + + bool parseSectionDirectiveConstData(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__const"); + } + + bool parseSectionDirectiveObjCClass(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__class", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCMetaClass(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__meta_class", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCCatClsMeth(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__cat_cls_meth", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCCatInstMeth(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__cat_inst_meth", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCProtocol(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__protocol", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCStringObject(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__string_object", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCClsMeth(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__cls_meth", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCInstMeth(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__inst_meth", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCClsRefs(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__cls_refs", + MachO::S_ATTR_NO_DEAD_STRIP | + MachO::S_LITERAL_POINTERS, 4); + } + + bool parseSectionDirectiveObjCMessageRefs(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__message_refs", + MachO::S_ATTR_NO_DEAD_STRIP | + MachO::S_LITERAL_POINTERS, 4); + } + + bool parseSectionDirectiveObjCSymbols(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__symbols", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCCategory(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__category", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCClassVars(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__class_vars", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCInstanceVars(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__instance_vars", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCModuleInfo(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__module_info", + MachO::S_ATTR_NO_DEAD_STRIP); + } + + bool parseSectionDirectiveObjCClassNames(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__cstring", + MachO::S_CSTRING_LITERALS); + } + + bool parseSectionDirectiveObjCMethVarTypes(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__cstring", + MachO::S_CSTRING_LITERALS); + } + + bool parseSectionDirectiveObjCMethVarNames(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__cstring", + MachO::S_CSTRING_LITERALS); + } + + bool parseSectionDirectiveObjCSelectorStrs(StringRef, SMLoc) { + return parseSectionSwitch("__OBJC", "__selector_strs", + MachO::S_CSTRING_LITERALS); + } + + bool parseSectionDirectiveTData(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__thread_data", + MachO::S_THREAD_LOCAL_REGULAR); + } + + bool parseSectionDirectiveText(StringRef, SMLoc) { + return parseSectionSwitch("__TEXT", "__text", + MachO::S_ATTR_PURE_INSTRUCTIONS); + } + + bool parseSectionDirectiveTLV(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__thread_vars", + MachO::S_THREAD_LOCAL_VARIABLES); + } + + bool parseSectionDirectiveIdent(StringRef, SMLoc) { + // Darwin silently ignores the .ident directive. + getParser().eatToEndOfStatement(); + return false; + } + + bool parseSectionDirectiveThreadInitFunc(StringRef, SMLoc) { + return parseSectionSwitch("__DATA", "__thread_init", + MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS); + } + + bool parseWatchOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_WatchOSVersionMin); + } + bool parseTvOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_TvOSVersionMin); + } + bool parseIOSVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_IOSVersionMin); + } + bool parseMacOSXVersionMin(StringRef Directive, SMLoc Loc) { + return parseVersionMin(Directive, Loc, MCVM_OSXVersionMin); + } + + bool parseBuildVersion(StringRef Directive, SMLoc Loc); + bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); + bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, + const char *VersionName); + bool parseOptionalTrailingVersionComponent(unsigned *Component, + const char *ComponentName); + bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); + bool parseSDKVersion(VersionTuple &SDKVersion); + void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, + Triple::OSType ExpectedOS); +}; + +} // end anonymous namespace + +bool DarwinAsmParser::parseSectionSwitch(StringRef Segment, StringRef Section, + unsigned TAA, unsigned Align, + unsigned StubSize) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + // FIXME: Arch specific. + bool isText = TAA & MachO::S_ATTR_PURE_INSTRUCTIONS; + getStreamer().SwitchSection(getContext().getMachOSection( + Segment, Section, TAA, StubSize, + isText ? SectionKind::getText() : SectionKind::getData())); + + // Set the implicit alignment, if any. + // + // FIXME: This isn't really what 'as' does; I think it just uses the implicit + // alignment on the section (e.g., if one manually inserts bytes into the + // section, then just issuing the section switch directive will not realign + // the section. However, this is arguably more reasonable behavior, and there + // is no good reason for someone to intentionally emit incorrectly sized + // values into the implicitly aligned sections. + if (Align) + getStreamer().emitValueToAlignment(Align); + + return false; +} + +/// parseDirectiveAltEntry +/// ::= .alt_entry identifier +bool DarwinAsmParser::parseDirectiveAltEntry(StringRef, SMLoc) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Look up symbol. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + if (Sym->isDefined()) + return TokError(".alt_entry must preceed symbol definition"); + + if (!getStreamer().emitSymbolAttribute(Sym, MCSA_AltEntry)) + return TokError("unable to emit symbol attribute"); + + Lex(); + return false; +} + +/// parseDirectiveDesc +/// ::= .desc identifier , expression +bool DarwinAsmParser::parseDirectiveDesc(StringRef, SMLoc) { + StringRef Name; + if (getParser().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 '.desc' directive"); + Lex(); + + int64_t DescValue; + if (getParser().parseAbsoluteExpression(DescValue)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.desc' directive"); + + Lex(); + + // Set the n_desc field of this Symbol to this DescValue + getStreamer().emitSymbolDesc(Sym, DescValue); + + return false; +} + +/// parseDirectiveIndirectSymbol +/// ::= .indirect_symbol identifier +bool DarwinAsmParser::parseDirectiveIndirectSymbol(StringRef, SMLoc Loc) { + const MCSectionMachO *Current = static_cast<const MCSectionMachO *>( + getStreamer().getCurrentSectionOnly()); + MachO::SectionType SectionType = Current->getType(); + if (SectionType != MachO::S_NON_LAZY_SYMBOL_POINTERS && + SectionType != MachO::S_LAZY_SYMBOL_POINTERS && + SectionType != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS && + SectionType != MachO::S_SYMBOL_STUBS) + return Error(Loc, "indirect symbol not in a symbol pointer or stub " + "section"); + + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in .indirect_symbol directive"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + // Assembler local symbols don't make any sense here. Complain loudly. + if (Sym->isTemporary()) + return TokError("non-local symbol required in directive"); + + if (!getStreamer().emitSymbolAttribute(Sym, MCSA_IndirectSymbol)) + return TokError("unable to emit indirect symbol attribute for: " + Name); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.indirect_symbol' directive"); + + Lex(); + + return false; +} + +/// parseDirectiveDumpOrLoad +/// ::= ( .dump | .load ) "filename" +bool DarwinAsmParser::parseDirectiveDumpOrLoad(StringRef Directive, + SMLoc IDLoc) { + bool IsDump = Directive == ".dump"; + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '.dump' or '.load' directive"); + + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.dump' or '.load' directive"); + + Lex(); + + // FIXME: If/when .dump and .load are implemented they will be done in the + // the assembly parser and not have any need for an MCStreamer API. + if (IsDump) + return Warning(IDLoc, "ignoring directive .dump for now"); + else + return Warning(IDLoc, "ignoring directive .load for now"); +} + +/// ParseDirectiveLinkerOption +/// ::= .linker_option "string" ( , "string" )* +bool DarwinAsmParser::parseDirectiveLinkerOption(StringRef IDVal, SMLoc) { + SmallVector<std::string, 4> Args; + while (true) { + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '" + Twine(IDVal) + "' directive"); + + std::string Data; + if (getParser().parseEscapedString(Data)) + return true; + + Args.push_back(Data); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); + Lex(); + } + + getStreamer().emitLinkerOptions(Args); + return false; +} + +/// parseDirectiveLsym +/// ::= .lsym identifier , expression +bool DarwinAsmParser::parseDirectiveLsym(StringRef, SMLoc) { + StringRef Name; + if (getParser().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 '.lsym' directive"); + Lex(); + + const MCExpr *Value; + if (getParser().parseExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.lsym' directive"); + + Lex(); + + // We don't currently support this directive. + // + // FIXME: Diagnostic location! + (void) Sym; + return TokError("directive '.lsym' is unsupported"); +} + +/// parseDirectiveSection: +/// ::= .section identifier (',' identifier)* +bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) { + SMLoc Loc = getLexer().getLoc(); + + StringRef SectionName; + if (getParser().parseIdentifier(SectionName)) + return Error(Loc, "expected identifier after '.section' directive"); + + // Verify there is a following comma. + if (!getLexer().is(AsmToken::Comma)) + return TokError("unexpected token in '.section' directive"); + + std::string SectionSpec = std::string(SectionName); + SectionSpec += ","; + + // Add all the tokens until the end of the line, ParseSectionSpecifier will + // handle this. + StringRef EOL = getLexer().LexUntilEndOfStatement(); + SectionSpec.append(EOL.begin(), EOL.end()); + + Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.section' directive"); + Lex(); + + StringRef Segment, Section; + unsigned StubSize; + unsigned TAA; + bool TAAParsed; + std::string ErrorStr = + MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section, + TAA, TAAParsed, StubSize); + + if (!ErrorStr.empty()) + return Error(Loc, ErrorStr); + + // Issue a warning if the target is not powerpc and Section is a *coal* section. + Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple(); + Triple::ArchType ArchTy = TT.getArch(); + + if (ArchTy != Triple::ppc && ArchTy != Triple::ppc64) { + StringRef NonCoalSection = StringSwitch<StringRef>(Section) + .Case("__textcoal_nt", "__text") + .Case("__const_coal", "__const") + .Case("__datacoal_nt", "__data") + .Default(Section); + + if (!Section.equals(NonCoalSection)) { + StringRef SectionVal(Loc.getPointer()); + size_t B = SectionVal.find(',') + 1, E = SectionVal.find(',', B); + SMLoc BLoc = SMLoc::getFromPointer(SectionVal.data() + B); + SMLoc ELoc = SMLoc::getFromPointer(SectionVal.data() + E); + getParser().Warning(Loc, "section \"" + Section + "\" is deprecated", + SMRange(BLoc, ELoc)); + getParser().Note(Loc, "change section name to \"" + NonCoalSection + + "\"", SMRange(BLoc, ELoc)); + } + } + + // FIXME: Arch specific. + bool isText = Segment == "__TEXT"; // FIXME: Hack. + getStreamer().SwitchSection(getContext().getMachOSection( + Segment, Section, TAA, StubSize, + isText ? SectionKind::getText() : SectionKind::getData())); + return false; +} + +/// ParseDirectivePushSection: +/// ::= .pushsection identifier (',' identifier)* +bool DarwinAsmParser::parseDirectivePushSection(StringRef S, SMLoc Loc) { + getStreamer().PushSection(); + + if (parseDirectiveSection(S, Loc)) { + getStreamer().PopSection(); + return true; + } + + return false; +} + +/// ParseDirectivePopSection: +/// ::= .popsection +bool DarwinAsmParser::parseDirectivePopSection(StringRef, SMLoc) { + if (!getStreamer().PopSection()) + return TokError(".popsection without corresponding .pushsection"); + return false; +} + +/// ParseDirectivePrevious: +/// ::= .previous +bool DarwinAsmParser::parseDirectivePrevious(StringRef DirName, SMLoc) { + MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); + if (!PreviousSection.first) + return TokError(".previous without corresponding .section"); + getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); + return false; +} + +/// ParseDirectiveSecureLogUnique +/// ::= .secure_log_unique ... message ... +bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { + StringRef LogMessage = getParser().parseStringToEndOfStatement(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.secure_log_unique' directive"); + + if (getContext().getSecureLogUsed()) + return Error(IDLoc, ".secure_log_unique specified multiple times"); + + // Get the secure log path. + const char *SecureLogFile = getContext().getSecureLogFile(); + if (!SecureLogFile) + return Error(IDLoc, ".secure_log_unique used but AS_SECURE_LOG_FILE " + "environment variable unset."); + + // Open the secure log file if we haven't already. + raw_fd_ostream *OS = getContext().getSecureLog(); + if (!OS) { + std::error_code EC; + auto NewOS = std::make_unique<raw_fd_ostream>( + StringRef(SecureLogFile), EC, sys::fs::OF_Append | sys::fs::OF_Text); + if (EC) + return Error(IDLoc, Twine("can't open secure log file: ") + + SecureLogFile + " (" + EC.message() + ")"); + OS = NewOS.get(); + getContext().setSecureLog(std::move(NewOS)); + } + + // Write the message. + unsigned CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc); + *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier() + << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":" + << LogMessage + "\n"; + + getContext().setSecureLogUsed(true); + + return false; +} + +/// ParseDirectiveSecureLogReset +/// ::= .secure_log_reset +bool DarwinAsmParser::parseDirectiveSecureLogReset(StringRef, SMLoc IDLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.secure_log_reset' directive"); + + Lex(); + + getContext().setSecureLogUsed(false); + + return false; +} + +/// parseDirectiveSubsectionsViaSymbols +/// ::= .subsections_via_symbols +bool DarwinAsmParser::parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.subsections_via_symbols' directive"); + + Lex(); + + getStreamer().emitAssemblerFlag(MCAF_SubsectionsViaSymbols); + + return false; +} + +/// ParseDirectiveTBSS +/// ::= .tbss identifier, size, align +bool DarwinAsmParser::parseDirectiveTBSS(StringRef, SMLoc) { + SMLoc IDLoc = getLexer().getLoc(); + StringRef Name; + if (getParser().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 (getParser().parseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + Pow2AlignmentLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.tbss' directive"); + + Lex(); + + if (Size < 0) + return Error(SizeLoc, "invalid '.tbss' directive size, can't be less than" + "zero"); + + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.tbss' alignment, can't be less" + "than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + getStreamer().emitTBSSSymbol( + getContext().getMachOSection("__DATA", "__thread_bss", + MachO::S_THREAD_LOCAL_ZEROFILL, 0, + SectionKind::getThreadBSS()), + Sym, Size, 1 << Pow2Alignment); + + return false; +} + +/// ParseDirectiveZerofill +/// ::= .zerofill segname , sectname [, identifier , size_expression [ +/// , align_expression ]] +bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { + StringRef Segment; + if (getParser().parseIdentifier(Segment)) + return TokError("expected segment name after '.zerofill' directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + StringRef Section; + SMLoc SectionLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(Section)) + return TokError("expected section name after comma in '.zerofill' " + "directive"); + + // If this is the end of the line all that was wanted was to create the + // the section but with no symbol. + if (getLexer().is(AsmToken::EndOfStatement)) { + // Create the zerofill section but no symbol + getStreamer().emitZerofill( + getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0, + SectionKind::getBSS()), + /*Symbol=*/nullptr, /*Size=*/0, /*ByteAlignment=*/0, SectionLoc); + return false; + } + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + SMLoc IDLoc = getLexer().getLoc(); + StringRef IDStr; + if (getParser().parseIdentifier(IDStr)) + return TokError("expected identifier in directive"); + + // handle the identifier as the key symbol. + MCSymbol *Sym = getContext().getOrCreateSymbol(IDStr); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Size; + SMLoc SizeLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + Pow2AlignmentLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zerofill' directive"); + + Lex(); + + if (Size < 0) + return Error(SizeLoc, "invalid '.zerofill' 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 '.zerofill' directive alignment, " + "can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(IDLoc, "invalid symbol redefinition"); + + // Create the zerofill Symbol with Size and Pow2Alignment + // + // FIXME: Arch specific. + getStreamer().emitZerofill(getContext().getMachOSection( + Segment, Section, MachO::S_ZEROFILL, + 0, SectionKind::getBSS()), + Sym, Size, 1 << Pow2Alignment, SectionLoc); + + return false; +} + +/// ParseDirectiveDataRegion +/// ::= .data_region [ ( jt8 | jt16 | jt32 ) ] +bool DarwinAsmParser::parseDirectiveDataRegion(StringRef, SMLoc) { + if (getLexer().is(AsmToken::EndOfStatement)) { + Lex(); + getStreamer().emitDataRegion(MCDR_DataRegion); + return false; + } + StringRef RegionType; + SMLoc Loc = getParser().getTok().getLoc(); + if (getParser().parseIdentifier(RegionType)) + return TokError("expected region type after '.data_region' directive"); + int Kind = StringSwitch<int>(RegionType) + .Case("jt8", MCDR_DataRegionJT8) + .Case("jt16", MCDR_DataRegionJT16) + .Case("jt32", MCDR_DataRegionJT32) + .Default(-1); + if (Kind == -1) + return Error(Loc, "unknown region type in '.data_region' directive"); + Lex(); + + getStreamer().emitDataRegion((MCDataRegionType)Kind); + return false; +} + +/// ParseDirectiveDataRegionEnd +/// ::= .end_data_region +bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.end_data_region' directive"); + + Lex(); + getStreamer().emitDataRegion(MCDR_DataRegionEnd); + return false; +} + +static bool isSDKVersionToken(const AsmToken &Tok) { + return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version"; +} + +/// parseMajorMinorVersionComponent ::= major, minor +bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major, + unsigned *Minor, + const char *VersionName) { + // Get the major version number. + if (getLexer().isNot(AsmToken::Integer)) + return TokError(Twine("invalid ") + VersionName + + " major version number, integer expected"); + int64_t MajorVal = getLexer().getTok().getIntVal(); + if (MajorVal > 65535 || MajorVal <= 0) + return TokError(Twine("invalid ") + VersionName + " major version number"); + *Major = (unsigned)MajorVal; + Lex(); + if (getLexer().isNot(AsmToken::Comma)) + return TokError(Twine(VersionName) + + " minor version number required, comma expected"); + Lex(); + // Get the minor version number. + if (getLexer().isNot(AsmToken::Integer)) + return TokError(Twine("invalid ") + VersionName + + " minor version number, integer expected"); + int64_t MinorVal = getLexer().getTok().getIntVal(); + if (MinorVal > 255 || MinorVal < 0) + return TokError(Twine("invalid ") + VersionName + " minor version number"); + *Minor = MinorVal; + Lex(); + return false; +} + +/// parseOptionalTrailingVersionComponent ::= , version_number +bool DarwinAsmParser::parseOptionalTrailingVersionComponent( + unsigned *Component, const char *ComponentName) { + assert(getLexer().is(AsmToken::Comma) && "comma expected"); + Lex(); + if (getLexer().isNot(AsmToken::Integer)) + return TokError(Twine("invalid ") + ComponentName + + " version number, integer expected"); + int64_t Val = getLexer().getTok().getIntVal(); + if (Val > 255 || Val < 0) + return TokError(Twine("invalid ") + ComponentName + " version number"); + *Component = Val; + Lex(); + return false; +} + +/// parseVersion ::= parseMajorMinorVersionComponent +/// parseOptionalTrailingVersionComponent +bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, + unsigned *Update) { + if (parseMajorMinorVersionComponent(Major, Minor, "OS")) + return true; + + // Get the update level, if specified + *Update = 0; + if (getLexer().is(AsmToken::EndOfStatement) || + isSDKVersionToken(getLexer().getTok())) + return false; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("invalid OS update specifier, comma expected"); + if (parseOptionalTrailingVersionComponent(Update, "OS update")) + return true; + return false; +} + +bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) { + assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version"); + Lex(); + unsigned Major, Minor; + if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK")) + return true; + SDKVersion = VersionTuple(Major, Minor); + + // Get the subminor version, if specified. + if (getLexer().is(AsmToken::Comma)) { + unsigned Subminor; + if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor")) + return true; + SDKVersion = VersionTuple(Major, Minor, Subminor); + } + return false; +} + +void DarwinAsmParser::checkVersion(StringRef Directive, StringRef Arg, + SMLoc Loc, Triple::OSType ExpectedOS) { + const Triple &Target = getContext().getObjectFileInfo()->getTargetTriple(); + if (Target.getOS() != ExpectedOS) + Warning(Loc, Twine(Directive) + + (Arg.empty() ? Twine() : Twine(' ') + Arg) + + " used while targeting " + Target.getOSName()); + + if (LastVersionDirective.isValid()) { + Warning(Loc, "overriding previous version directive"); + Note(LastVersionDirective, "previous definition is here"); + } + LastVersionDirective = Loc; +} + +static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { + switch (Type) { + case MCVM_WatchOSVersionMin: return Triple::WatchOS; + case MCVM_TvOSVersionMin: return Triple::TvOS; + case MCVM_IOSVersionMin: return Triple::IOS; + case MCVM_OSXVersionMin: return Triple::MacOSX; + } + llvm_unreachable("Invalid mc version min type"); +} + +/// parseVersionMin +/// ::= .ios_version_min parseVersion parseSDKVersion +/// | .macosx_version_min parseVersion parseSDKVersion +/// | .tvos_version_min parseVersion parseSDKVersion +/// | .watchos_version_min parseVersion parseSDKVersion +bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, + MCVersionMinType Type) { + unsigned Major; + unsigned Minor; + unsigned Update; + if (parseVersion(&Major, &Minor, &Update)) + return true; + + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(Twine(" in '") + Directive + "' directive"); + + Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type); + checkVersion(Directive, StringRef(), Loc, ExpectedOS); + getStreamer().emitVersionMin(Type, Major, Minor, Update, SDKVersion); + return false; +} + +static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { + switch (Type) { + case MachO::PLATFORM_MACOS: return Triple::MacOSX; + case MachO::PLATFORM_IOS: return Triple::IOS; + case MachO::PLATFORM_TVOS: return Triple::TvOS; + case MachO::PLATFORM_WATCHOS: return Triple::WatchOS; + case MachO::PLATFORM_BRIDGEOS: /* silence warning */ break; + case MachO::PLATFORM_MACCATALYST: return Triple::IOS; + case MachO::PLATFORM_IOSSIMULATOR: /* silence warning */ break; + case MachO::PLATFORM_TVOSSIMULATOR: /* silence warning */ break; + case MachO::PLATFORM_WATCHOSSIMULATOR: /* silence warning */ break; case MachO::PLATFORM_DRIVERKIT: /* silence warning */ break; - } - llvm_unreachable("Invalid mach-o platform type"); -} - -/// parseBuildVersion -/// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion -bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { - StringRef PlatformName; - SMLoc PlatformLoc = getTok().getLoc(); - if (getParser().parseIdentifier(PlatformName)) - return TokError("platform name expected"); - - unsigned Platform = StringSwitch<unsigned>(PlatformName) - .Case("macos", MachO::PLATFORM_MACOS) - .Case("ios", MachO::PLATFORM_IOS) - .Case("tvos", MachO::PLATFORM_TVOS) - .Case("watchos", MachO::PLATFORM_WATCHOS) - .Case("macCatalyst", MachO::PLATFORM_MACCATALYST) - .Default(0); - if (Platform == 0) - return Error(PlatformLoc, "unknown platform name"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("version number required, comma expected"); - Lex(); - - unsigned Major; - unsigned Minor; - unsigned Update; - if (parseVersion(&Major, &Minor, &Update)) - return true; - - VersionTuple SDKVersion; - if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) - return true; - - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(" in '.build_version' directive"); - - Triple::OSType ExpectedOS - = getOSTypeFromPlatform((MachO::PlatformType)Platform); - checkVersion(Directive, PlatformName, Loc, ExpectedOS); - getStreamer().emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); - return false; -} - - -namespace llvm { - -MCAsmParserExtension *createDarwinAsmParser() { - return new DarwinAsmParser; -} - -} // end llvm namespace + } + llvm_unreachable("Invalid mach-o platform type"); +} + +/// parseBuildVersion +/// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion +bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { + StringRef PlatformName; + SMLoc PlatformLoc = getTok().getLoc(); + if (getParser().parseIdentifier(PlatformName)) + return TokError("platform name expected"); + + unsigned Platform = StringSwitch<unsigned>(PlatformName) + .Case("macos", MachO::PLATFORM_MACOS) + .Case("ios", MachO::PLATFORM_IOS) + .Case("tvos", MachO::PLATFORM_TVOS) + .Case("watchos", MachO::PLATFORM_WATCHOS) + .Case("macCatalyst", MachO::PLATFORM_MACCATALYST) + .Default(0); + if (Platform == 0) + return Error(PlatformLoc, "unknown platform name"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("version number required, comma expected"); + Lex(); + + unsigned Major; + unsigned Minor; + unsigned Update; + if (parseVersion(&Major, &Minor, &Update)) + return true; + + VersionTuple SDKVersion; + if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) + return true; + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.build_version' directive"); + + Triple::OSType ExpectedOS + = getOSTypeFromPlatform((MachO::PlatformType)Platform); + checkVersion(Directive, PlatformName, Loc, ExpectedOS); + getStreamer().emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); + return false; +} + + +namespace llvm { + +MCAsmParserExtension *createDarwinAsmParser() { + return new DarwinAsmParser; +} + +} // end llvm namespace diff --git a/contrib/libs/llvm12/lib/MC/MCParser/ELFAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/ELFAsmParser.cpp index 243cdc2e3e..65ac1d6b5b 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/ELFAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/ELFAsmParser.cpp @@ -1,888 +1,888 @@ -//===- ELFAsmParser.cpp - ELF 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/BinaryFormat/ELF.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDirectives.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCSection.h" -#include "llvm/MC/MCSectionELF.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCSymbolELF.h" -#include "llvm/MC/SectionKind.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/SMLoc.h" -#include <cassert> -#include <cstdint> -#include <utility> - -using namespace llvm; - -namespace { - -class ELFAsmParser : public MCAsmParserExtension { - template<bool (ELFAsmParser::*HandlerMethod)(StringRef, SMLoc)> - void addDirectiveHandler(StringRef Directive) { - MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( - this, HandleDirective<ELFAsmParser, HandlerMethod>); - - getParser().addDirectiveHandler(Directive, Handler); - } - - bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind); - -public: - ELFAsmParser() { BracketExpressionsSupported = true; } - - void Initialize(MCAsmParser &Parser) override { - // Call the base implementation. - this->MCAsmParserExtension::Initialize(Parser); - - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data"); - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text"); - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss"); - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata"); - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata"); - addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss"); - addDirectiveHandler< - &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel"); - addDirectiveHandler< - &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro"); - addDirectiveHandler< - &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); - addDirectiveHandler< - &ELFAsmParser::ParseDirectivePushSection>(".pushsection"); - addDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); - addDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveVersion>(".version"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local"); - addDirectiveHandler< - &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected"); - addDirectiveHandler< - &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal"); - addDirectiveHandler< - &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection"); - addDirectiveHandler<&ELFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); - } - - // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is - // the best way for us to get access to it? - bool ParseSectionDirectiveData(StringRef, SMLoc) { - return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, - ELF::SHF_WRITE | ELF::SHF_ALLOC, - SectionKind::getData()); - } - bool ParseSectionDirectiveText(StringRef, SMLoc) { - return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | - ELF::SHF_ALLOC, SectionKind::getText()); - } - bool ParseSectionDirectiveBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, - ELF::SHF_WRITE | - ELF::SHF_ALLOC, SectionKind::getBSS()); - } - bool ParseSectionDirectiveRoData(StringRef, SMLoc) { - return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC, - SectionKind::getReadOnly()); - } - bool ParseSectionDirectiveTData(StringRef, SMLoc) { - return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | - ELF::SHF_TLS | ELF::SHF_WRITE, - SectionKind::getThreadData()); - } - bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, - ELF::SHF_ALLOC | - ELF::SHF_TLS | ELF::SHF_WRITE, - SectionKind::getThreadBSS()); - } - bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | ELF::SHF_WRITE, - SectionKind::getData()); - } - bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | - ELF::SHF_WRITE, - SectionKind::getReadOnlyWithRel()); - } - bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { - return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | ELF::SHF_WRITE, - SectionKind::getData()); - } - bool ParseDirectivePushSection(StringRef, SMLoc); - bool ParseDirectivePopSection(StringRef, SMLoc); - bool ParseDirectiveSection(StringRef, SMLoc); - bool ParseDirectiveSize(StringRef, SMLoc); - bool ParseDirectivePrevious(StringRef, SMLoc); - bool ParseDirectiveType(StringRef, SMLoc); - bool ParseDirectiveIdent(StringRef, SMLoc); - bool ParseDirectiveSymver(StringRef, SMLoc); - bool ParseDirectiveVersion(StringRef, SMLoc); - bool ParseDirectiveWeakref(StringRef, SMLoc); - bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); - bool ParseDirectiveSubsection(StringRef, SMLoc); - bool ParseDirectiveCGProfile(StringRef, SMLoc); - -private: - bool ParseSectionName(StringRef &SectionName); - bool ParseSectionArguments(bool IsPush, SMLoc loc); - unsigned parseSunStyleSectionFlags(); - bool maybeParseSectionType(StringRef &TypeName); - bool parseMergeSize(int64_t &Size); - bool parseGroup(StringRef &GroupName); - bool parseLinkedToSym(MCSymbolELF *&LinkedToSym); - bool maybeParseUniqueID(int64_t &UniqueID); -}; - -} // end anonymous namespace - -/// ParseDirectiveSymbolAttribute -/// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] -bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { - MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) - .Case(".weak", MCSA_Weak) - .Case(".local", MCSA_Local) - .Case(".hidden", MCSA_Hidden) - .Case(".internal", MCSA_Internal) - .Case(".protected", MCSA_Protected) - .Default(MCSA_Invalid); - assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - while (true) { - StringRef Name; - - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - getStreamer().emitSymbolAttribute(Sym, Attr); - - if (getLexer().is(AsmToken::EndOfStatement)) - break; - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - } - } - - Lex(); - return false; -} - -bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, - unsigned Flags, SectionKind Kind) { - const MCExpr *Subsection = nullptr; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getParser().parseExpression(Subsection)) - return true; - } - Lex(); - - getStreamer().SwitchSection(getContext().getELFSection(Section, Type, Flags), - Subsection); - - return false; -} - -bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - MCSymbolELF *Sym = cast<MCSymbolELF>(getContext().getOrCreateSymbol(Name)); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - - const MCExpr *Expr; - if (getParser().parseExpression(Expr)) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - Lex(); - - getStreamer().emitELFSize(Sym, Expr); - return false; -} - -bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { - // A section name can contain -, so we cannot just use - // parseIdentifier. - SMLoc FirstLoc = getLexer().getLoc(); - unsigned Size = 0; - - if (getLexer().is(AsmToken::String)) { - SectionName = getTok().getIdentifier(); - Lex(); - return false; - } - - while (!getParser().hasPendingError()) { - SMLoc PrevLoc = getLexer().getLoc(); - if (getLexer().is(AsmToken::Comma) || - getLexer().is(AsmToken::EndOfStatement)) - break; - - unsigned CurSize; - if (getLexer().is(AsmToken::String)) { - CurSize = getTok().getIdentifier().size() + 2; - Lex(); - } else if (getLexer().is(AsmToken::Identifier)) { - CurSize = getTok().getIdentifier().size(); - Lex(); - } else { - CurSize = getTok().getString().size(); - Lex(); - } - Size += CurSize; - SectionName = StringRef(FirstLoc.getPointer(), Size); - - // Make sure the following token is adjacent. - if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) - break; - } - if (Size == 0) - return true; - - return false; -} - -static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { - unsigned flags = 0; - - // If a valid numerical value is set for the section flag, use it verbatim - if (!flagsStr.getAsInteger(0, flags)) - return flags; - - for (char i : flagsStr) { - switch (i) { - case 'a': - flags |= ELF::SHF_ALLOC; - break; - case 'e': - flags |= ELF::SHF_EXCLUDE; - break; - case 'x': - flags |= ELF::SHF_EXECINSTR; - break; - case 'w': - flags |= ELF::SHF_WRITE; - break; - case 'o': - flags |= ELF::SHF_LINK_ORDER; - break; - case 'M': - flags |= ELF::SHF_MERGE; - break; - case 'S': - flags |= ELF::SHF_STRINGS; - break; - case 'T': - flags |= ELF::SHF_TLS; - break; - case 'c': - flags |= ELF::XCORE_SHF_CP_SECTION; - break; - case 'd': - flags |= ELF::XCORE_SHF_DP_SECTION; - break; - case 'y': - flags |= ELF::SHF_ARM_PURECODE; - break; - case 's': - flags |= ELF::SHF_HEX_GPREL; - break; - case 'G': - flags |= ELF::SHF_GROUP; - break; - case '?': - *UseLastGroup = true; - break; - default: - return -1U; - } - } - - return flags; -} - -unsigned ELFAsmParser::parseSunStyleSectionFlags() { - unsigned flags = 0; - while (getLexer().is(AsmToken::Hash)) { - Lex(); // Eat the #. - - if (!getLexer().is(AsmToken::Identifier)) - return -1U; - - StringRef flagId = getTok().getIdentifier(); - if (flagId == "alloc") - flags |= ELF::SHF_ALLOC; - else if (flagId == "execinstr") - flags |= ELF::SHF_EXECINSTR; - else if (flagId == "write") - flags |= ELF::SHF_WRITE; - else if (flagId == "tls") - flags |= ELF::SHF_TLS; - else - return -1U; - - Lex(); // Eat the flag. - - if (!getLexer().is(AsmToken::Comma)) - break; - Lex(); // Eat the comma. - } - return flags; -} - - -bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { - getStreamer().PushSection(); - - if (ParseSectionArguments(/*IsPush=*/true, loc)) { - getStreamer().PopSection(); - return true; - } - - return false; -} - -bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { - if (!getStreamer().PopSection()) - return TokError(".popsection without corresponding .pushsection"); - return false; -} - -bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { - return ParseSectionArguments(/*IsPush=*/false, loc); -} - -bool ELFAsmParser::maybeParseSectionType(StringRef &TypeName) { - MCAsmLexer &L = getLexer(); - if (L.isNot(AsmToken::Comma)) - return false; - Lex(); - if (L.isNot(AsmToken::At) && L.isNot(AsmToken::Percent) && - L.isNot(AsmToken::String)) { - if (L.getAllowAtInIdentifier()) - return TokError("expected '@<type>', '%<type>' or \"<type>\""); - else - return TokError("expected '%<type>' or \"<type>\""); - } - if (!L.is(AsmToken::String)) - Lex(); - if (L.is(AsmToken::Integer)) { - TypeName = getTok().getString(); - Lex(); - } else if (getParser().parseIdentifier(TypeName)) - return TokError("expected identifier in directive"); - return false; -} - -bool ELFAsmParser::parseMergeSize(int64_t &Size) { - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected the entry size"); - Lex(); - if (getParser().parseAbsoluteExpression(Size)) - return true; - if (Size <= 0) - return TokError("entry size must be positive"); - return false; -} - -bool ELFAsmParser::parseGroup(StringRef &GroupName) { - MCAsmLexer &L = getLexer(); - if (L.isNot(AsmToken::Comma)) - return TokError("expected group name"); - Lex(); - if (L.is(AsmToken::Integer)) { - GroupName = getTok().getString(); - Lex(); - } else if (getParser().parseIdentifier(GroupName)) { - return TokError("invalid group name"); - } - if (L.is(AsmToken::Comma)) { - Lex(); - StringRef Linkage; - if (getParser().parseIdentifier(Linkage)) - return TokError("invalid linkage"); - if (Linkage != "comdat") - return TokError("Linkage must be 'comdat'"); - } - return false; -} - -bool ELFAsmParser::parseLinkedToSym(MCSymbolELF *&LinkedToSym) { - MCAsmLexer &L = getLexer(); - if (L.isNot(AsmToken::Comma)) - return TokError("expected linked-to symbol"); - Lex(); - StringRef Name; - SMLoc StartLoc = L.getLoc(); +//===- ELFAsmParser.cpp - ELF 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/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/SMLoc.h" +#include <cassert> +#include <cstdint> +#include <utility> + +using namespace llvm; + +namespace { + +class ELFAsmParser : public MCAsmParserExtension { + template<bool (ELFAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<ELFAsmParser, HandlerMethod>); + + getParser().addDirectiveHandler(Directive, Handler); + } + + bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind); + +public: + ELFAsmParser() { BracketExpressionsSupported = true; } + + void Initialize(MCAsmParser &Parser) override { + // Call the base implementation. + this->MCAsmParserExtension::Initialize(Parser); + + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data"); + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text"); + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss"); + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata"); + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata"); + addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss"); + addDirectiveHandler< + &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel"); + addDirectiveHandler< + &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro"); + addDirectiveHandler< + &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); + addDirectiveHandler< + &ELFAsmParser::ParseDirectivePushSection>(".pushsection"); + addDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); + addDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveVersion>(".version"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local"); + addDirectiveHandler< + &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected"); + addDirectiveHandler< + &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal"); + addDirectiveHandler< + &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); + } + + // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is + // the best way for us to get access to it? + bool ParseSectionDirectiveData(StringRef, SMLoc) { + return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getData()); + } + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); + } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); + } + bool ParseSectionDirectiveRoData(StringRef, SMLoc) { + return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, + SectionKind::getReadOnly()); + } + bool ParseSectionDirectiveTData(StringRef, SMLoc) { + return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, + SectionKind::getThreadData()); + } + bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, + SectionKind::getThreadBSS()); + } + bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE, + SectionKind::getData()); + } + bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, + SectionKind::getReadOnlyWithRel()); + } + bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { + return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE, + SectionKind::getData()); + } + bool ParseDirectivePushSection(StringRef, SMLoc); + bool ParseDirectivePopSection(StringRef, SMLoc); + bool ParseDirectiveSection(StringRef, SMLoc); + bool ParseDirectiveSize(StringRef, SMLoc); + bool ParseDirectivePrevious(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveIdent(StringRef, SMLoc); + bool ParseDirectiveSymver(StringRef, SMLoc); + bool ParseDirectiveVersion(StringRef, SMLoc); + bool ParseDirectiveWeakref(StringRef, SMLoc); + bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); + bool ParseDirectiveSubsection(StringRef, SMLoc); + bool ParseDirectiveCGProfile(StringRef, SMLoc); + +private: + bool ParseSectionName(StringRef &SectionName); + bool ParseSectionArguments(bool IsPush, SMLoc loc); + unsigned parseSunStyleSectionFlags(); + bool maybeParseSectionType(StringRef &TypeName); + bool parseMergeSize(int64_t &Size); + bool parseGroup(StringRef &GroupName); + bool parseLinkedToSym(MCSymbolELF *&LinkedToSym); + bool maybeParseUniqueID(int64_t &UniqueID); +}; + +} // end anonymous namespace + +/// ParseDirectiveSymbolAttribute +/// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] +bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { + MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) + .Case(".weak", MCSA_Weak) + .Case(".local", MCSA_Local) + .Case(".hidden", MCSA_Hidden) + .Case(".internal", MCSA_Internal) + .Case(".protected", MCSA_Protected) + .Default(MCSA_Invalid); + assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + while (true) { + StringRef Name; + + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + getStreamer().emitSymbolAttribute(Sym, Attr); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind) { + const MCExpr *Subsection = nullptr; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getParser().parseExpression(Subsection)) + return true; + } + Lex(); + + getStreamer().SwitchSection(getContext().getELFSection(Section, Type, Flags), + Subsection); + + return false; +} + +bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + MCSymbolELF *Sym = cast<MCSymbolELF>(getContext().getOrCreateSymbol(Name)); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + Lex(); + + getStreamer().emitELFSize(Sym, Expr); + return false; +} + +bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { + // A section name can contain -, so we cannot just use + // parseIdentifier. + SMLoc FirstLoc = getLexer().getLoc(); + unsigned Size = 0; + + if (getLexer().is(AsmToken::String)) { + SectionName = getTok().getIdentifier(); + Lex(); + return false; + } + + while (!getParser().hasPendingError()) { + SMLoc PrevLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Comma) || + getLexer().is(AsmToken::EndOfStatement)) + break; + + unsigned CurSize; + if (getLexer().is(AsmToken::String)) { + CurSize = getTok().getIdentifier().size() + 2; + Lex(); + } else if (getLexer().is(AsmToken::Identifier)) { + CurSize = getTok().getIdentifier().size(); + Lex(); + } else { + CurSize = getTok().getString().size(); + Lex(); + } + Size += CurSize; + SectionName = StringRef(FirstLoc.getPointer(), Size); + + // Make sure the following token is adjacent. + if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) + break; + } + if (Size == 0) + return true; + + return false; +} + +static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { + unsigned flags = 0; + + // If a valid numerical value is set for the section flag, use it verbatim + if (!flagsStr.getAsInteger(0, flags)) + return flags; + + for (char i : flagsStr) { + switch (i) { + case 'a': + flags |= ELF::SHF_ALLOC; + break; + case 'e': + flags |= ELF::SHF_EXCLUDE; + break; + case 'x': + flags |= ELF::SHF_EXECINSTR; + break; + case 'w': + flags |= ELF::SHF_WRITE; + break; + case 'o': + flags |= ELF::SHF_LINK_ORDER; + break; + case 'M': + flags |= ELF::SHF_MERGE; + break; + case 'S': + flags |= ELF::SHF_STRINGS; + break; + case 'T': + flags |= ELF::SHF_TLS; + break; + case 'c': + flags |= ELF::XCORE_SHF_CP_SECTION; + break; + case 'd': + flags |= ELF::XCORE_SHF_DP_SECTION; + break; + case 'y': + flags |= ELF::SHF_ARM_PURECODE; + break; + case 's': + flags |= ELF::SHF_HEX_GPREL; + break; + case 'G': + flags |= ELF::SHF_GROUP; + break; + case '?': + *UseLastGroup = true; + break; + default: + return -1U; + } + } + + return flags; +} + +unsigned ELFAsmParser::parseSunStyleSectionFlags() { + unsigned flags = 0; + while (getLexer().is(AsmToken::Hash)) { + Lex(); // Eat the #. + + if (!getLexer().is(AsmToken::Identifier)) + return -1U; + + StringRef flagId = getTok().getIdentifier(); + if (flagId == "alloc") + flags |= ELF::SHF_ALLOC; + else if (flagId == "execinstr") + flags |= ELF::SHF_EXECINSTR; + else if (flagId == "write") + flags |= ELF::SHF_WRITE; + else if (flagId == "tls") + flags |= ELF::SHF_TLS; + else + return -1U; + + Lex(); // Eat the flag. + + if (!getLexer().is(AsmToken::Comma)) + break; + Lex(); // Eat the comma. + } + return flags; +} + + +bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { + getStreamer().PushSection(); + + if (ParseSectionArguments(/*IsPush=*/true, loc)) { + getStreamer().PopSection(); + return true; + } + + return false; +} + +bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { + if (!getStreamer().PopSection()) + return TokError(".popsection without corresponding .pushsection"); + return false; +} + +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { + return ParseSectionArguments(/*IsPush=*/false, loc); +} + +bool ELFAsmParser::maybeParseSectionType(StringRef &TypeName) { + MCAsmLexer &L = getLexer(); + if (L.isNot(AsmToken::Comma)) + return false; + Lex(); + if (L.isNot(AsmToken::At) && L.isNot(AsmToken::Percent) && + L.isNot(AsmToken::String)) { + if (L.getAllowAtInIdentifier()) + return TokError("expected '@<type>', '%<type>' or \"<type>\""); + else + return TokError("expected '%<type>' or \"<type>\""); + } + if (!L.is(AsmToken::String)) + Lex(); + if (L.is(AsmToken::Integer)) { + TypeName = getTok().getString(); + Lex(); + } else if (getParser().parseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + return false; +} + +bool ELFAsmParser::parseMergeSize(int64_t &Size) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected the entry size"); + Lex(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + if (Size <= 0) + return TokError("entry size must be positive"); + return false; +} + +bool ELFAsmParser::parseGroup(StringRef &GroupName) { + MCAsmLexer &L = getLexer(); + if (L.isNot(AsmToken::Comma)) + return TokError("expected group name"); + Lex(); + if (L.is(AsmToken::Integer)) { + GroupName = getTok().getString(); + Lex(); + } else if (getParser().parseIdentifier(GroupName)) { + return TokError("invalid group name"); + } + if (L.is(AsmToken::Comma)) { + Lex(); + StringRef Linkage; + if (getParser().parseIdentifier(Linkage)) + return TokError("invalid linkage"); + if (Linkage != "comdat") + return TokError("Linkage must be 'comdat'"); + } + return false; +} + +bool ELFAsmParser::parseLinkedToSym(MCSymbolELF *&LinkedToSym) { + MCAsmLexer &L = getLexer(); + if (L.isNot(AsmToken::Comma)) + return TokError("expected linked-to symbol"); + Lex(); + StringRef Name; + SMLoc StartLoc = L.getLoc(); if (getParser().parseIdentifier(Name)) { if (getParser().getTok().getString() == "0") { getParser().Lex(); LinkedToSym = nullptr; return false; } - return TokError("invalid linked-to symbol"); + return TokError("invalid linked-to symbol"); } - LinkedToSym = dyn_cast_or_null<MCSymbolELF>(getContext().lookupSymbol(Name)); - if (!LinkedToSym || !LinkedToSym->isInSection()) - return Error(StartLoc, "linked-to symbol is not in a section: " + Name); - return false; -} - -bool ELFAsmParser::maybeParseUniqueID(int64_t &UniqueID) { - MCAsmLexer &L = getLexer(); - if (L.isNot(AsmToken::Comma)) - return false; - Lex(); - StringRef UniqueStr; - if (getParser().parseIdentifier(UniqueStr)) - return TokError("expected identifier in directive"); - if (UniqueStr != "unique") - return TokError("expected 'unique'"); - if (L.isNot(AsmToken::Comma)) - return TokError("expected commma"); - Lex(); - if (getParser().parseAbsoluteExpression(UniqueID)) - return true; - if (UniqueID < 0) - return TokError("unique id must be positive"); - if (!isUInt<32>(UniqueID) || UniqueID == ~0U) - return TokError("unique id is too large"); - return false; -} - -static bool hasPrefix(StringRef SectionName, StringRef Prefix) { - return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); -} - -bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { - StringRef SectionName; - - if (ParseSectionName(SectionName)) - return TokError("expected identifier in directive"); - - StringRef TypeName; - int64_t Size = 0; - StringRef GroupName; - unsigned Flags = 0; - const MCExpr *Subsection = nullptr; - bool UseLastGroup = false; - MCSymbolELF *LinkedToSym = nullptr; - int64_t UniqueID = ~0; - - // Set the defaults first. - if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") - Flags |= ELF::SHF_ALLOC; - else if (SectionName == ".fini" || SectionName == ".init" || - hasPrefix(SectionName, ".text.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; - else if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || - hasPrefix(SectionName, ".bss.") || - hasPrefix(SectionName, ".init_array.") || - hasPrefix(SectionName, ".fini_array.") || - hasPrefix(SectionName, ".preinit_array.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE; - else if (hasPrefix(SectionName, ".tdata.") || - hasPrefix(SectionName, ".tbss.")) - Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; - - if (getLexer().is(AsmToken::Comma)) { - Lex(); - - if (IsPush && getLexer().isNot(AsmToken::String)) { - if (getParser().parseExpression(Subsection)) - return true; - if (getLexer().isNot(AsmToken::Comma)) - goto EndStmt; - Lex(); - } - - unsigned extraFlags; - - if (getLexer().isNot(AsmToken::String)) { - if (!getContext().getAsmInfo()->usesSunStyleELFSectionSwitchSyntax() - || getLexer().isNot(AsmToken::Hash)) - return TokError("expected string in directive"); - extraFlags = parseSunStyleSectionFlags(); - } else { - StringRef FlagsStr = getTok().getStringContents(); - Lex(); - extraFlags = parseSectionFlags(FlagsStr, &UseLastGroup); - } - - if (extraFlags == -1U) - return TokError("unknown flag"); - Flags |= extraFlags; - - bool Mergeable = Flags & ELF::SHF_MERGE; - bool Group = Flags & ELF::SHF_GROUP; - if (Group && UseLastGroup) - return TokError("Section cannot specifiy a group name while also acting " - "as a member of the last group"); - - if (maybeParseSectionType(TypeName)) - return true; - - MCAsmLexer &L = getLexer(); - if (TypeName.empty()) { - if (Mergeable) - return TokError("Mergeable section must specify the type"); - if (Group) - return TokError("Group section must specify the type"); - if (L.isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - } - - if (Mergeable) - if (parseMergeSize(Size)) - return true; - if (Group) - if (parseGroup(GroupName)) - return true; - if (Flags & ELF::SHF_LINK_ORDER) - if (parseLinkedToSym(LinkedToSym)) - return true; - if (maybeParseUniqueID(UniqueID)) - return true; - } - -EndStmt: - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - Lex(); - - unsigned Type = ELF::SHT_PROGBITS; - - if (TypeName.empty()) { - if (SectionName.startswith(".note")) - Type = ELF::SHT_NOTE; - else if (hasPrefix(SectionName, ".init_array.")) - Type = ELF::SHT_INIT_ARRAY; - else if (hasPrefix(SectionName, ".bss.")) - Type = ELF::SHT_NOBITS; - else if (hasPrefix(SectionName, ".tbss.")) - Type = ELF::SHT_NOBITS; - else if (hasPrefix(SectionName, ".fini_array.")) - Type = ELF::SHT_FINI_ARRAY; - else if (hasPrefix(SectionName, ".preinit_array.")) - Type = ELF::SHT_PREINIT_ARRAY; - } else { - if (TypeName == "init_array") - Type = ELF::SHT_INIT_ARRAY; - else if (TypeName == "fini_array") - Type = ELF::SHT_FINI_ARRAY; - else if (TypeName == "preinit_array") - Type = ELF::SHT_PREINIT_ARRAY; - else if (TypeName == "nobits") - Type = ELF::SHT_NOBITS; - else if (TypeName == "progbits") - Type = ELF::SHT_PROGBITS; - else if (TypeName == "note") - Type = ELF::SHT_NOTE; - else if (TypeName == "unwind") - Type = ELF::SHT_X86_64_UNWIND; - else if (TypeName == "llvm_odrtab") - Type = ELF::SHT_LLVM_ODRTAB; - else if (TypeName == "llvm_linker_options") - Type = ELF::SHT_LLVM_LINKER_OPTIONS; - else if (TypeName == "llvm_call_graph_profile") - Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE; - else if (TypeName == "llvm_dependent_libraries") - Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES; - else if (TypeName == "llvm_sympart") - Type = ELF::SHT_LLVM_SYMPART; + LinkedToSym = dyn_cast_or_null<MCSymbolELF>(getContext().lookupSymbol(Name)); + if (!LinkedToSym || !LinkedToSym->isInSection()) + return Error(StartLoc, "linked-to symbol is not in a section: " + Name); + return false; +} + +bool ELFAsmParser::maybeParseUniqueID(int64_t &UniqueID) { + MCAsmLexer &L = getLexer(); + if (L.isNot(AsmToken::Comma)) + return false; + Lex(); + StringRef UniqueStr; + if (getParser().parseIdentifier(UniqueStr)) + return TokError("expected identifier in directive"); + if (UniqueStr != "unique") + return TokError("expected 'unique'"); + if (L.isNot(AsmToken::Comma)) + return TokError("expected commma"); + Lex(); + if (getParser().parseAbsoluteExpression(UniqueID)) + return true; + if (UniqueID < 0) + return TokError("unique id must be positive"); + if (!isUInt<32>(UniqueID) || UniqueID == ~0U) + return TokError("unique id is too large"); + return false; +} + +static bool hasPrefix(StringRef SectionName, StringRef Prefix) { + return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); +} + +bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + StringRef TypeName; + int64_t Size = 0; + StringRef GroupName; + unsigned Flags = 0; + const MCExpr *Subsection = nullptr; + bool UseLastGroup = false; + MCSymbolELF *LinkedToSym = nullptr; + int64_t UniqueID = ~0; + + // Set the defaults first. + if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1") + Flags |= ELF::SHF_ALLOC; + else if (SectionName == ".fini" || SectionName == ".init" || + hasPrefix(SectionName, ".text.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + else if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" || + hasPrefix(SectionName, ".bss.") || + hasPrefix(SectionName, ".init_array.") || + hasPrefix(SectionName, ".fini_array.") || + hasPrefix(SectionName, ".preinit_array.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE; + else if (hasPrefix(SectionName, ".tdata.") || + hasPrefix(SectionName, ".tbss.")) + Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (IsPush && getLexer().isNot(AsmToken::String)) { + if (getParser().parseExpression(Subsection)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + goto EndStmt; + Lex(); + } + + unsigned extraFlags; + + if (getLexer().isNot(AsmToken::String)) { + if (!getContext().getAsmInfo()->usesSunStyleELFSectionSwitchSyntax() + || getLexer().isNot(AsmToken::Hash)) + return TokError("expected string in directive"); + extraFlags = parseSunStyleSectionFlags(); + } else { + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + extraFlags = parseSectionFlags(FlagsStr, &UseLastGroup); + } + + if (extraFlags == -1U) + return TokError("unknown flag"); + Flags |= extraFlags; + + bool Mergeable = Flags & ELF::SHF_MERGE; + bool Group = Flags & ELF::SHF_GROUP; + if (Group && UseLastGroup) + return TokError("Section cannot specifiy a group name while also acting " + "as a member of the last group"); + + if (maybeParseSectionType(TypeName)) + return true; + + MCAsmLexer &L = getLexer(); + if (TypeName.empty()) { + if (Mergeable) + return TokError("Mergeable section must specify the type"); + if (Group) + return TokError("Group section must specify the type"); + if (L.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + } + + if (Mergeable) + if (parseMergeSize(Size)) + return true; + if (Group) + if (parseGroup(GroupName)) + return true; + if (Flags & ELF::SHF_LINK_ORDER) + if (parseLinkedToSym(LinkedToSym)) + return true; + if (maybeParseUniqueID(UniqueID)) + return true; + } + +EndStmt: + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + Lex(); + + unsigned Type = ELF::SHT_PROGBITS; + + if (TypeName.empty()) { + if (SectionName.startswith(".note")) + Type = ELF::SHT_NOTE; + else if (hasPrefix(SectionName, ".init_array.")) + Type = ELF::SHT_INIT_ARRAY; + else if (hasPrefix(SectionName, ".bss.")) + Type = ELF::SHT_NOBITS; + else if (hasPrefix(SectionName, ".tbss.")) + Type = ELF::SHT_NOBITS; + else if (hasPrefix(SectionName, ".fini_array.")) + Type = ELF::SHT_FINI_ARRAY; + else if (hasPrefix(SectionName, ".preinit_array.")) + Type = ELF::SHT_PREINIT_ARRAY; + } else { + if (TypeName == "init_array") + Type = ELF::SHT_INIT_ARRAY; + else if (TypeName == "fini_array") + Type = ELF::SHT_FINI_ARRAY; + else if (TypeName == "preinit_array") + Type = ELF::SHT_PREINIT_ARRAY; + else if (TypeName == "nobits") + Type = ELF::SHT_NOBITS; + else if (TypeName == "progbits") + Type = ELF::SHT_PROGBITS; + else if (TypeName == "note") + Type = ELF::SHT_NOTE; + else if (TypeName == "unwind") + Type = ELF::SHT_X86_64_UNWIND; + else if (TypeName == "llvm_odrtab") + Type = ELF::SHT_LLVM_ODRTAB; + else if (TypeName == "llvm_linker_options") + Type = ELF::SHT_LLVM_LINKER_OPTIONS; + else if (TypeName == "llvm_call_graph_profile") + Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE; + else if (TypeName == "llvm_dependent_libraries") + Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES; + else if (TypeName == "llvm_sympart") + Type = ELF::SHT_LLVM_SYMPART; else if (TypeName == "llvm_bb_addr_map") Type = ELF::SHT_LLVM_BB_ADDR_MAP; - else if (TypeName.getAsInteger(0, Type)) - return TokError("unknown section type"); - } - - if (UseLastGroup) { - MCSectionSubPair CurrentSection = getStreamer().getCurrentSection(); - if (const MCSectionELF *Section = - cast_or_null<MCSectionELF>(CurrentSection.first)) - if (const MCSymbol *Group = Section->getGroup()) { - GroupName = Group->getName(); - Flags |= ELF::SHF_GROUP; - } - } - - MCSectionELF *Section = getContext().getELFSection( - SectionName, Type, Flags, Size, GroupName, UniqueID, LinkedToSym); - getStreamer().SwitchSection(Section, Subsection); - // x86-64 psABI names SHT_X86_64_UNWIND as the canonical type for .eh_frame, - // but GNU as emits SHT_PROGBITS .eh_frame for .cfi_* directives. Don't error - // for SHT_PROGBITS .eh_frame - if (Section->getType() != Type && - !(SectionName == ".eh_frame" && Type == ELF::SHT_PROGBITS)) - Error(loc, "changed section type for " + SectionName + ", expected: 0x" + - utohexstr(Section->getType())); - // Check that flags are used consistently. However, the GNU assembler permits - // to leave out in subsequent uses of the same sections; for compatibility, - // do likewise. - if ((Flags || Size || !TypeName.empty()) && Section->getFlags() != Flags) - Error(loc, "changed section flags for " + SectionName + ", expected: 0x" + - utohexstr(Section->getFlags())); - if ((Flags || Size || !TypeName.empty()) && Section->getEntrySize() != Size) - Error(loc, "changed section entsize for " + SectionName + - ", expected: " + Twine(Section->getEntrySize())); - + else if (TypeName.getAsInteger(0, Type)) + return TokError("unknown section type"); + } + + if (UseLastGroup) { + MCSectionSubPair CurrentSection = getStreamer().getCurrentSection(); + if (const MCSectionELF *Section = + cast_or_null<MCSectionELF>(CurrentSection.first)) + if (const MCSymbol *Group = Section->getGroup()) { + GroupName = Group->getName(); + Flags |= ELF::SHF_GROUP; + } + } + + MCSectionELF *Section = getContext().getELFSection( + SectionName, Type, Flags, Size, GroupName, UniqueID, LinkedToSym); + getStreamer().SwitchSection(Section, Subsection); + // x86-64 psABI names SHT_X86_64_UNWIND as the canonical type for .eh_frame, + // but GNU as emits SHT_PROGBITS .eh_frame for .cfi_* directives. Don't error + // for SHT_PROGBITS .eh_frame + if (Section->getType() != Type && + !(SectionName == ".eh_frame" && Type == ELF::SHT_PROGBITS)) + Error(loc, "changed section type for " + SectionName + ", expected: 0x" + + utohexstr(Section->getType())); + // Check that flags are used consistently. However, the GNU assembler permits + // to leave out in subsequent uses of the same sections; for compatibility, + // do likewise. + if ((Flags || Size || !TypeName.empty()) && Section->getFlags() != Flags) + Error(loc, "changed section flags for " + SectionName + ", expected: 0x" + + utohexstr(Section->getFlags())); + if ((Flags || Size || !TypeName.empty()) && Section->getEntrySize() != Size) + Error(loc, "changed section entsize for " + SectionName + + ", expected: " + Twine(Section->getEntrySize())); + if (getContext().getGenDwarfForAssembly() && (Section->getFlags() & ELF::SHF_ALLOC) && (Section->getFlags() & ELF::SHF_EXECINSTR)) { - bool InsertResult = getContext().addGenDwarfSection(Section); - if (InsertResult) { - if (getContext().getDwarfVersion() <= 2) - Warning(loc, "DWARF2 only supports one section per compilation unit"); - - if (!Section->getBeginSymbol()) { - MCSymbol *SectionStartSymbol = getContext().createTempSymbol(); - getStreamer().emitLabel(SectionStartSymbol); - Section->setBeginSymbol(SectionStartSymbol); - } - } - } - - return false; -} - -bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { - MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); - if (PreviousSection.first == nullptr) - return TokError(".previous without corresponding .section"); - getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); - - return false; -} - -static MCSymbolAttr MCAttrForString(StringRef Type) { - return StringSwitch<MCSymbolAttr>(Type) - .Cases("STT_FUNC", "function", MCSA_ELF_TypeFunction) - .Cases("STT_OBJECT", "object", MCSA_ELF_TypeObject) - .Cases("STT_TLS", "tls_object", MCSA_ELF_TypeTLS) - .Cases("STT_COMMON", "common", MCSA_ELF_TypeCommon) - .Cases("STT_NOTYPE", "notype", MCSA_ELF_TypeNoType) - .Cases("STT_GNU_IFUNC", "gnu_indirect_function", - MCSA_ELF_TypeIndFunction) - .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) - .Default(MCSA_Invalid); -} - -/// ParseDirectiveELFType -/// ::= .type identifier , STT_<TYPE_IN_UPPER_CASE> -/// ::= .type identifier , #attribute -/// ::= .type identifier , @attribute -/// ::= .type identifier , %attribute -/// ::= .type identifier , "attribute" -bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - // Handle the identifier as the key symbol. - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - // NOTE the comma is optional in all cases. It is only documented as being - // optional in the first case, however, GAS will silently treat the comma as - // optional in all cases. Furthermore, although the documentation states that - // the first form only accepts STT_<TYPE_IN_UPPER_CASE>, in reality, GAS - // accepts both the upper case name as well as the lower case aliases. - if (getLexer().is(AsmToken::Comma)) - Lex(); - - if (getLexer().isNot(AsmToken::Identifier) && - getLexer().isNot(AsmToken::Hash) && - getLexer().isNot(AsmToken::Percent) && - getLexer().isNot(AsmToken::String)) { - if (!getLexer().getAllowAtInIdentifier()) - return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', " - "'%<type>' or \"<type>\""); - else if (getLexer().isNot(AsmToken::At)) - return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', '@<type>', " - "'%<type>' or \"<type>\""); - } - - if (getLexer().isNot(AsmToken::String) && - getLexer().isNot(AsmToken::Identifier)) - Lex(); - - SMLoc TypeLoc = getLexer().getLoc(); - - StringRef Type; - if (getParser().parseIdentifier(Type)) - return TokError("expected symbol type in directive"); - - MCSymbolAttr Attr = MCAttrForString(Type); - if (Attr == MCSA_Invalid) - return Error(TypeLoc, "unsupported attribute in '.type' directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.type' directive"); - Lex(); - - getStreamer().emitSymbolAttribute(Sym, Attr); - - return false; -} - -/// ParseDirectiveIdent -/// ::= .ident string -bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { - if (getLexer().isNot(AsmToken::String)) - return TokError("unexpected token in '.ident' directive"); - - StringRef Data = getTok().getIdentifier(); - - Lex(); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.ident' directive"); - Lex(); - - getStreamer().emitIdent(Data); - return false; -} - -/// ParseDirectiveSymver -/// ::= .symver foo, bar2@zed -bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - - // ARM assembly uses @ for a comment... - // except when parsing the second parameter of the .symver directive. - // Force the next symbol to allow @ in the identifier, which is - // required for this directive and then reset it to its initial state. - const bool AllowAtInIdentifier = getLexer().getAllowAtInIdentifier(); - getLexer().setAllowAtInIdentifier(true); - Lex(); - getLexer().setAllowAtInIdentifier(AllowAtInIdentifier); - - StringRef AliasName; - if (getParser().parseIdentifier(AliasName)) - return TokError("expected identifier in directive"); - - if (AliasName.find('@') == StringRef::npos) - return TokError("expected a '@' in the name"); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitELFSymverDirective(AliasName, Sym); - return false; -} - -/// ParseDirectiveVersion -/// ::= .version string -bool ELFAsmParser::ParseDirectiveVersion(StringRef, SMLoc) { - if (getLexer().isNot(AsmToken::String)) - return TokError("unexpected token in '.version' directive"); - - StringRef Data = getTok().getIdentifier(); - - Lex(); - - MCSection *Note = getContext().getELFSection(".note", ELF::SHT_NOTE, 0); - - getStreamer().PushSection(); - getStreamer().SwitchSection(Note); - getStreamer().emitInt32(Data.size() + 1); // namesz - getStreamer().emitInt32(0); // descsz = 0 (no description). - getStreamer().emitInt32(1); // type = NT_VERSION - getStreamer().emitBytes(Data); // name - getStreamer().emitInt8(0); // NUL - getStreamer().emitValueToAlignment(4); - getStreamer().PopSection(); - return false; -} - -/// ParseDirectiveWeakref -/// ::= .weakref foo, bar -bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { - // FIXME: Share code with the other alias building directives. - - StringRef AliasName; - if (getParser().parseIdentifier(AliasName)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - - Lex(); - - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); - - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - - getStreamer().emitWeakReference(Alias, Sym); - return false; -} - -bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) { - const MCExpr *Subsection = nullptr; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getParser().parseExpression(Subsection)) - return true; - } - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - Lex(); - - getStreamer().SubSection(Subsection); - return false; -} - -bool ELFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { - return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); -} - -namespace llvm { - -MCAsmParserExtension *createELFAsmParser() { - return new ELFAsmParser; -} - -} // end namespace llvm + bool InsertResult = getContext().addGenDwarfSection(Section); + if (InsertResult) { + if (getContext().getDwarfVersion() <= 2) + Warning(loc, "DWARF2 only supports one section per compilation unit"); + + if (!Section->getBeginSymbol()) { + MCSymbol *SectionStartSymbol = getContext().createTempSymbol(); + getStreamer().emitLabel(SectionStartSymbol); + Section->setBeginSymbol(SectionStartSymbol); + } + } + } + + return false; +} + +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection.first == nullptr) + return TokError(".previous without corresponding .section"); + getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); + + return false; +} + +static MCSymbolAttr MCAttrForString(StringRef Type) { + return StringSwitch<MCSymbolAttr>(Type) + .Cases("STT_FUNC", "function", MCSA_ELF_TypeFunction) + .Cases("STT_OBJECT", "object", MCSA_ELF_TypeObject) + .Cases("STT_TLS", "tls_object", MCSA_ELF_TypeTLS) + .Cases("STT_COMMON", "common", MCSA_ELF_TypeCommon) + .Cases("STT_NOTYPE", "notype", MCSA_ELF_TypeNoType) + .Cases("STT_GNU_IFUNC", "gnu_indirect_function", + MCSA_ELF_TypeIndFunction) + .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) + .Default(MCSA_Invalid); +} + +/// ParseDirectiveELFType +/// ::= .type identifier , STT_<TYPE_IN_UPPER_CASE> +/// ::= .type identifier , #attribute +/// ::= .type identifier , @attribute +/// ::= .type identifier , %attribute +/// ::= .type identifier , "attribute" +bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + // NOTE the comma is optional in all cases. It is only documented as being + // optional in the first case, however, GAS will silently treat the comma as + // optional in all cases. Furthermore, although the documentation states that + // the first form only accepts STT_<TYPE_IN_UPPER_CASE>, in reality, GAS + // accepts both the upper case name as well as the lower case aliases. + if (getLexer().is(AsmToken::Comma)) + Lex(); + + if (getLexer().isNot(AsmToken::Identifier) && + getLexer().isNot(AsmToken::Hash) && + getLexer().isNot(AsmToken::Percent) && + getLexer().isNot(AsmToken::String)) { + if (!getLexer().getAllowAtInIdentifier()) + return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', " + "'%<type>' or \"<type>\""); + else if (getLexer().isNot(AsmToken::At)) + return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', '@<type>', " + "'%<type>' or \"<type>\""); + } + + if (getLexer().isNot(AsmToken::String) && + getLexer().isNot(AsmToken::Identifier)) + Lex(); + + SMLoc TypeLoc = getLexer().getLoc(); + + StringRef Type; + if (getParser().parseIdentifier(Type)) + return TokError("expected symbol type in directive"); + + MCSymbolAttr Attr = MCAttrForString(Type); + if (Attr == MCSA_Invalid) + return Error(TypeLoc, "unsupported attribute in '.type' directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.type' directive"); + Lex(); + + getStreamer().emitSymbolAttribute(Sym, Attr); + + return false; +} + +/// ParseDirectiveIdent +/// ::= .ident string +bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.ident' directive"); + + StringRef Data = getTok().getIdentifier(); + + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ident' directive"); + Lex(); + + getStreamer().emitIdent(Data); + return false; +} + +/// ParseDirectiveSymver +/// ::= .symver foo, bar2@zed +bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + // ARM assembly uses @ for a comment... + // except when parsing the second parameter of the .symver directive. + // Force the next symbol to allow @ in the identifier, which is + // required for this directive and then reset it to its initial state. + const bool AllowAtInIdentifier = getLexer().getAllowAtInIdentifier(); + getLexer().setAllowAtInIdentifier(true); + Lex(); + getLexer().setAllowAtInIdentifier(AllowAtInIdentifier); + + StringRef AliasName; + if (getParser().parseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (AliasName.find('@') == StringRef::npos) + return TokError("expected a '@' in the name"); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitELFSymverDirective(AliasName, Sym); + return false; +} + +/// ParseDirectiveVersion +/// ::= .version string +bool ELFAsmParser::ParseDirectiveVersion(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.version' directive"); + + StringRef Data = getTok().getIdentifier(); + + Lex(); + + MCSection *Note = getContext().getELFSection(".note", ELF::SHT_NOTE, 0); + + getStreamer().PushSection(); + getStreamer().SwitchSection(Note); + getStreamer().emitInt32(Data.size() + 1); // namesz + getStreamer().emitInt32(0); // descsz = 0 (no description). + getStreamer().emitInt32(1); // type = NT_VERSION + getStreamer().emitBytes(Data); // name + getStreamer().emitInt8(0); // NUL + getStreamer().emitValueToAlignment(4); + getStreamer().PopSection(); + return false; +} + +/// ParseDirectiveWeakref +/// ::= .weakref foo, bar +bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { + // FIXME: Share code with the other alias building directives. + + StringRef AliasName; + if (getParser().parseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); + + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + getStreamer().emitWeakReference(Alias, Sym); + return false; +} + +bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) { + const MCExpr *Subsection = nullptr; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getParser().parseExpression(Subsection)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + + getStreamer().SubSection(Subsection); + return false; +} + +bool ELFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { + return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); +} + +namespace llvm { + +MCAsmParserExtension *createELFAsmParser() { + return new ELFAsmParser; +} + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmLexer.cpp b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmLexer.cpp index 8907716438..497055bc17 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmLexer.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmLexer.cpp @@ -1,129 +1,129 @@ -//===- MCAsmLexer.cpp - Abstract Asm Lexer Interface ----------------------===// -// -// 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/MC/MCParser/MCAsmLexer.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/SMLoc.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -MCAsmLexer::MCAsmLexer() { - CurTok.emplace_back(AsmToken::Space, StringRef()); -} - -MCAsmLexer::~MCAsmLexer() = default; - -SMLoc MCAsmLexer::getLoc() const { - return SMLoc::getFromPointer(TokStart); -} - -SMLoc AsmToken::getLoc() const { - return SMLoc::getFromPointer(Str.data()); -} - -SMLoc AsmToken::getEndLoc() const { - return SMLoc::getFromPointer(Str.data() + Str.size()); -} - -SMRange AsmToken::getLocRange() const { - return SMRange(getLoc(), getEndLoc()); -} - -void AsmToken::dump(raw_ostream &OS) const { - switch (Kind) { - case AsmToken::Error: - OS << "error"; - break; - case AsmToken::Identifier: - OS << "identifier: " << getString(); - break; - case AsmToken::Integer: - OS << "int: " << getString(); - break; - case AsmToken::Real: - OS << "real: " << getString(); - break; - case AsmToken::String: - OS << "string: " << getString(); - break; - - case AsmToken::Amp: OS << "Amp"; break; - case AsmToken::AmpAmp: OS << "AmpAmp"; break; - case AsmToken::At: OS << "At"; break; - case AsmToken::BackSlash: OS << "BackSlash"; break; - case AsmToken::BigNum: OS << "BigNum"; break; - case AsmToken::Caret: OS << "Caret"; break; - case AsmToken::Colon: OS << "Colon"; break; - case AsmToken::Comma: OS << "Comma"; break; - case AsmToken::Comment: OS << "Comment"; break; - case AsmToken::Dollar: OS << "Dollar"; break; - case AsmToken::Dot: OS << "Dot"; break; - case AsmToken::EndOfStatement: OS << "EndOfStatement"; break; - case AsmToken::Eof: OS << "Eof"; break; - case AsmToken::Equal: OS << "Equal"; break; - case AsmToken::EqualEqual: OS << "EqualEqual"; break; - case AsmToken::Exclaim: OS << "Exclaim"; break; - case AsmToken::ExclaimEqual: OS << "ExclaimEqual"; break; - case AsmToken::Greater: OS << "Greater"; break; - case AsmToken::GreaterEqual: OS << "GreaterEqual"; break; - case AsmToken::GreaterGreater: OS << "GreaterGreater"; break; - case AsmToken::Hash: OS << "Hash"; break; - case AsmToken::HashDirective: OS << "HashDirective"; break; - case AsmToken::LBrac: OS << "LBrac"; break; - case AsmToken::LCurly: OS << "LCurly"; break; - case AsmToken::LParen: OS << "LParen"; break; - case AsmToken::Less: OS << "Less"; break; - case AsmToken::LessEqual: OS << "LessEqual"; break; - case AsmToken::LessGreater: OS << "LessGreater"; break; - case AsmToken::LessLess: OS << "LessLess"; break; - case AsmToken::Minus: OS << "Minus"; break; - case AsmToken::MinusGreater: OS << "MinusGreater"; break; - case AsmToken::Percent: OS << "Percent"; break; - case AsmToken::Pipe: OS << "Pipe"; break; - case AsmToken::PipePipe: OS << "PipePipe"; break; - case AsmToken::Plus: OS << "Plus"; break; - case AsmToken::RBrac: OS << "RBrac"; break; - case AsmToken::RCurly: OS << "RCurly"; break; - case AsmToken::RParen: OS << "RParen"; break; - case AsmToken::Slash: OS << "Slash"; break; - case AsmToken::Space: OS << "Space"; break; - case AsmToken::Star: OS << "Star"; break; - case AsmToken::Tilde: OS << "Tilde"; break; - case AsmToken::PercentCall16: OS << "PercentCall16"; break; - case AsmToken::PercentCall_Hi: OS << "PercentCall_Hi"; break; - case AsmToken::PercentCall_Lo: OS << "PercentCall_Lo"; break; - case AsmToken::PercentDtprel_Hi: OS << "PercentDtprel_Hi"; break; - case AsmToken::PercentDtprel_Lo: OS << "PercentDtprel_Lo"; break; - case AsmToken::PercentGot: OS << "PercentGot"; break; - case AsmToken::PercentGot_Disp: OS << "PercentGot_Disp"; break; - case AsmToken::PercentGot_Hi: OS << "PercentGot_Hi"; break; - case AsmToken::PercentGot_Lo: OS << "PercentGot_Lo"; break; - case AsmToken::PercentGot_Ofst: OS << "PercentGot_Ofst"; break; - case AsmToken::PercentGot_Page: OS << "PercentGot_Page"; break; - case AsmToken::PercentGottprel: OS << "PercentGottprel"; break; - case AsmToken::PercentGp_Rel: OS << "PercentGp_Rel"; break; - case AsmToken::PercentHi: OS << "PercentHi"; break; - case AsmToken::PercentHigher: OS << "PercentHigher"; break; - case AsmToken::PercentHighest: OS << "PercentHighest"; break; - case AsmToken::PercentLo: OS << "PercentLo"; break; - case AsmToken::PercentNeg: OS << "PercentNeg"; break; - case AsmToken::PercentPcrel_Hi: OS << "PercentPcrel_Hi"; break; - case AsmToken::PercentPcrel_Lo: OS << "PercentPcrel_Lo"; break; - case AsmToken::PercentTlsgd: OS << "PercentTlsgd"; break; - case AsmToken::PercentTlsldm: OS << "PercentTlsldm"; break; - case AsmToken::PercentTprel_Hi: OS << "PercentTprel_Hi"; break; - case AsmToken::PercentTprel_Lo: OS << "PercentTprel_Lo"; break; - } - - // Print the token string. - OS << " (\""; - OS.write_escaped(getString()); - OS << "\")"; -} +//===- MCAsmLexer.cpp - Abstract Asm Lexer Interface ----------------------===// +// +// 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/MC/MCParser/MCAsmLexer.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCAsmLexer::MCAsmLexer() { + CurTok.emplace_back(AsmToken::Space, StringRef()); +} + +MCAsmLexer::~MCAsmLexer() = default; + +SMLoc MCAsmLexer::getLoc() const { + return SMLoc::getFromPointer(TokStart); +} + +SMLoc AsmToken::getLoc() const { + return SMLoc::getFromPointer(Str.data()); +} + +SMLoc AsmToken::getEndLoc() const { + return SMLoc::getFromPointer(Str.data() + Str.size()); +} + +SMRange AsmToken::getLocRange() const { + return SMRange(getLoc(), getEndLoc()); +} + +void AsmToken::dump(raw_ostream &OS) const { + switch (Kind) { + case AsmToken::Error: + OS << "error"; + break; + case AsmToken::Identifier: + OS << "identifier: " << getString(); + break; + case AsmToken::Integer: + OS << "int: " << getString(); + break; + case AsmToken::Real: + OS << "real: " << getString(); + break; + case AsmToken::String: + OS << "string: " << getString(); + break; + + case AsmToken::Amp: OS << "Amp"; break; + case AsmToken::AmpAmp: OS << "AmpAmp"; break; + case AsmToken::At: OS << "At"; break; + case AsmToken::BackSlash: OS << "BackSlash"; break; + case AsmToken::BigNum: OS << "BigNum"; break; + case AsmToken::Caret: OS << "Caret"; break; + case AsmToken::Colon: OS << "Colon"; break; + case AsmToken::Comma: OS << "Comma"; break; + case AsmToken::Comment: OS << "Comment"; break; + case AsmToken::Dollar: OS << "Dollar"; break; + case AsmToken::Dot: OS << "Dot"; break; + case AsmToken::EndOfStatement: OS << "EndOfStatement"; break; + case AsmToken::Eof: OS << "Eof"; break; + case AsmToken::Equal: OS << "Equal"; break; + case AsmToken::EqualEqual: OS << "EqualEqual"; break; + case AsmToken::Exclaim: OS << "Exclaim"; break; + case AsmToken::ExclaimEqual: OS << "ExclaimEqual"; break; + case AsmToken::Greater: OS << "Greater"; break; + case AsmToken::GreaterEqual: OS << "GreaterEqual"; break; + case AsmToken::GreaterGreater: OS << "GreaterGreater"; break; + case AsmToken::Hash: OS << "Hash"; break; + case AsmToken::HashDirective: OS << "HashDirective"; break; + case AsmToken::LBrac: OS << "LBrac"; break; + case AsmToken::LCurly: OS << "LCurly"; break; + case AsmToken::LParen: OS << "LParen"; break; + case AsmToken::Less: OS << "Less"; break; + case AsmToken::LessEqual: OS << "LessEqual"; break; + case AsmToken::LessGreater: OS << "LessGreater"; break; + case AsmToken::LessLess: OS << "LessLess"; break; + case AsmToken::Minus: OS << "Minus"; break; + case AsmToken::MinusGreater: OS << "MinusGreater"; break; + case AsmToken::Percent: OS << "Percent"; break; + case AsmToken::Pipe: OS << "Pipe"; break; + case AsmToken::PipePipe: OS << "PipePipe"; break; + case AsmToken::Plus: OS << "Plus"; break; + case AsmToken::RBrac: OS << "RBrac"; break; + case AsmToken::RCurly: OS << "RCurly"; break; + case AsmToken::RParen: OS << "RParen"; break; + case AsmToken::Slash: OS << "Slash"; break; + case AsmToken::Space: OS << "Space"; break; + case AsmToken::Star: OS << "Star"; break; + case AsmToken::Tilde: OS << "Tilde"; break; + case AsmToken::PercentCall16: OS << "PercentCall16"; break; + case AsmToken::PercentCall_Hi: OS << "PercentCall_Hi"; break; + case AsmToken::PercentCall_Lo: OS << "PercentCall_Lo"; break; + case AsmToken::PercentDtprel_Hi: OS << "PercentDtprel_Hi"; break; + case AsmToken::PercentDtprel_Lo: OS << "PercentDtprel_Lo"; break; + case AsmToken::PercentGot: OS << "PercentGot"; break; + case AsmToken::PercentGot_Disp: OS << "PercentGot_Disp"; break; + case AsmToken::PercentGot_Hi: OS << "PercentGot_Hi"; break; + case AsmToken::PercentGot_Lo: OS << "PercentGot_Lo"; break; + case AsmToken::PercentGot_Ofst: OS << "PercentGot_Ofst"; break; + case AsmToken::PercentGot_Page: OS << "PercentGot_Page"; break; + case AsmToken::PercentGottprel: OS << "PercentGottprel"; break; + case AsmToken::PercentGp_Rel: OS << "PercentGp_Rel"; break; + case AsmToken::PercentHi: OS << "PercentHi"; break; + case AsmToken::PercentHigher: OS << "PercentHigher"; break; + case AsmToken::PercentHighest: OS << "PercentHighest"; break; + case AsmToken::PercentLo: OS << "PercentLo"; break; + case AsmToken::PercentNeg: OS << "PercentNeg"; break; + case AsmToken::PercentPcrel_Hi: OS << "PercentPcrel_Hi"; break; + case AsmToken::PercentPcrel_Lo: OS << "PercentPcrel_Lo"; break; + case AsmToken::PercentTlsgd: OS << "PercentTlsgd"; break; + case AsmToken::PercentTlsldm: OS << "PercentTlsldm"; break; + case AsmToken::PercentTprel_Hi: OS << "PercentTprel_Hi"; break; + case AsmToken::PercentTprel_Lo: OS << "PercentTprel_Lo"; break; + } + + // Print the token string. + OS << " (\""; + OS.write_escaped(getString()); + OS << "\")"; +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParser.cpp index 0bf21343a1..c2fa7be56a 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParser.cpp @@ -1,141 +1,141 @@ -//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// -// -// 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/MC/MCParser/MCAsmParser.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Config/llvm-config.h" -#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" -#include <cassert> - -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; - -void MCAsmParser::setTargetParser(MCTargetAsmParser &P) { - assert(!TargetParser && "Target parser is already initialized!"); - TargetParser = &P; - TargetParser->Initialize(*this); -} - -const AsmToken &MCAsmParser::getTok() const { - return getLexer().getTok(); -} - -bool MCAsmParser::parseTokenLoc(SMLoc &Loc) { - Loc = getTok().getLoc(); - return false; -} - -bool MCAsmParser::parseEOL(const Twine &Msg) { - if (getTok().getKind() != AsmToken::EndOfStatement) - return Error(getTok().getLoc(), Msg); - Lex(); - return false; -} - -bool MCAsmParser::parseToken(AsmToken::TokenKind T, const Twine &Msg) { - if (T == AsmToken::EndOfStatement) - return parseEOL(Msg); - if (getTok().getKind() != T) - return Error(getTok().getLoc(), Msg); - Lex(); - return false; -} - -bool MCAsmParser::parseIntToken(int64_t &V, const Twine &Msg) { - if (getTok().getKind() != AsmToken::Integer) - return TokError(Msg); - V = getTok().getIntVal(); - Lex(); - return false; -} - -bool MCAsmParser::parseOptionalToken(AsmToken::TokenKind T) { - bool Present = (getTok().getKind() == T); - if (Present) - parseToken(T); - return Present; -} - -bool MCAsmParser::check(bool P, const Twine &Msg) { - return check(P, getTok().getLoc(), Msg); -} - -bool MCAsmParser::check(bool P, SMLoc Loc, const Twine &Msg) { - if (P) - return Error(Loc, Msg); - return false; -} - -bool MCAsmParser::TokError(const Twine &Msg, SMRange Range) { - return Error(getLexer().getLoc(), Msg, Range); -} - -bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) { - - MCPendingError PErr; - PErr.Loc = L; - Msg.toVector(PErr.Msg); - PErr.Range = Range; - PendingErrors.push_back(PErr); - - // If we threw this parsing error after a lexing error, this should - // supercede the lexing error and so we remove it from the Lexer - // before it can propagate - if (getTok().is(AsmToken::Error)) - getLexer().Lex(); - return true; -} - -bool MCAsmParser::addErrorSuffix(const Twine &Suffix) { - // Make sure lexing errors have propagated to the parser. - if (getTok().is(AsmToken::Error)) - Lex(); - for (auto &PErr : PendingErrors) - Suffix.toVector(PErr.Msg); - return true; -} - -bool MCAsmParser::parseMany(function_ref<bool()> parseOne, bool hasComma) { - if (parseOptionalToken(AsmToken::EndOfStatement)) - return false; - while (true) { - if (parseOne()) - return true; - if (parseOptionalToken(AsmToken::EndOfStatement)) - return false; - if (hasComma && parseToken(AsmToken::Comma)) - return true; - } - return false; -} - -bool MCAsmParser::parseExpression(const MCExpr *&Res) { - SMLoc L; - return parseExpression(Res, L); -} - -void MCParsedAsmOperand::dump() const { - // Cannot completely remove virtual function even in release mode. -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - dbgs() << " " << *this; -#endif -} +//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// +// +// 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/MC/MCParser/MCAsmParser.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" +#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" +#include <cassert> + +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; + +void MCAsmParser::setTargetParser(MCTargetAsmParser &P) { + assert(!TargetParser && "Target parser is already initialized!"); + TargetParser = &P; + TargetParser->Initialize(*this); +} + +const AsmToken &MCAsmParser::getTok() const { + return getLexer().getTok(); +} + +bool MCAsmParser::parseTokenLoc(SMLoc &Loc) { + Loc = getTok().getLoc(); + return false; +} + +bool MCAsmParser::parseEOL(const Twine &Msg) { + if (getTok().getKind() != AsmToken::EndOfStatement) + return Error(getTok().getLoc(), Msg); + Lex(); + return false; +} + +bool MCAsmParser::parseToken(AsmToken::TokenKind T, const Twine &Msg) { + if (T == AsmToken::EndOfStatement) + return parseEOL(Msg); + if (getTok().getKind() != T) + return Error(getTok().getLoc(), Msg); + Lex(); + return false; +} + +bool MCAsmParser::parseIntToken(int64_t &V, const Twine &Msg) { + if (getTok().getKind() != AsmToken::Integer) + return TokError(Msg); + V = getTok().getIntVal(); + Lex(); + return false; +} + +bool MCAsmParser::parseOptionalToken(AsmToken::TokenKind T) { + bool Present = (getTok().getKind() == T); + if (Present) + parseToken(T); + return Present; +} + +bool MCAsmParser::check(bool P, const Twine &Msg) { + return check(P, getTok().getLoc(), Msg); +} + +bool MCAsmParser::check(bool P, SMLoc Loc, const Twine &Msg) { + if (P) + return Error(Loc, Msg); + return false; +} + +bool MCAsmParser::TokError(const Twine &Msg, SMRange Range) { + return Error(getLexer().getLoc(), Msg, Range); +} + +bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) { + + MCPendingError PErr; + PErr.Loc = L; + Msg.toVector(PErr.Msg); + PErr.Range = Range; + PendingErrors.push_back(PErr); + + // If we threw this parsing error after a lexing error, this should + // supercede the lexing error and so we remove it from the Lexer + // before it can propagate + if (getTok().is(AsmToken::Error)) + getLexer().Lex(); + return true; +} + +bool MCAsmParser::addErrorSuffix(const Twine &Suffix) { + // Make sure lexing errors have propagated to the parser. + if (getTok().is(AsmToken::Error)) + Lex(); + for (auto &PErr : PendingErrors) + Suffix.toVector(PErr.Msg); + return true; +} + +bool MCAsmParser::parseMany(function_ref<bool()> parseOne, bool hasComma) { + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + while (true) { + if (parseOne()) + return true; + if (parseOptionalToken(AsmToken::EndOfStatement)) + return false; + if (hasComma && parseToken(AsmToken::Comma)) + return true; + } + return false; +} + +bool MCAsmParser::parseExpression(const MCExpr *&Res) { + SMLoc L; + return parseExpression(Res, L); +} + +void MCParsedAsmOperand::dump() const { + // Cannot completely remove virtual function even in release mode. +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + dbgs() << " " << *this; +#endif +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParserExtension.cpp b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParserExtension.cpp index 5dbc65645b..0b5046cd8f 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParserExtension.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/MCAsmParserExtension.cpp @@ -1,62 +1,62 @@ -//===- MCAsmParserExtension.cpp - Asm Parser Hooks ------------------------===// -// -// 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/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCStreamer.h" - -using namespace llvm; - -MCAsmParserExtension::MCAsmParserExtension() = default; - -MCAsmParserExtension::~MCAsmParserExtension() = default; - -void MCAsmParserExtension::Initialize(MCAsmParser &Parser) { - this->Parser = &Parser; -} - -/// ParseDirectiveCGProfile -/// ::= .cg_profile identifier, identifier, <number> -bool MCAsmParserExtension::ParseDirectiveCGProfile(StringRef, SMLoc) { - StringRef From; - SMLoc FromLoc = getLexer().getLoc(); - if (getParser().parseIdentifier(From)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - Lex(); - - StringRef To; - SMLoc ToLoc = getLexer().getLoc(); - if (getParser().parseIdentifier(To)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - Lex(); - - int64_t Count; - if (getParser().parseIntToken( - Count, "expected integer count in '.cg_profile' directive")) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *FromSym = getContext().getOrCreateSymbol(From); - MCSymbol *ToSym = getContext().getOrCreateSymbol(To); - - getStreamer().emitCGProfileEntry( - MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(), - FromLoc), - MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(), - ToLoc), - Count); - return false; -} +//===- MCAsmParserExtension.cpp - Asm Parser Hooks ------------------------===// +// +// 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/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +MCAsmParserExtension::MCAsmParserExtension() = default; + +MCAsmParserExtension::~MCAsmParserExtension() = default; + +void MCAsmParserExtension::Initialize(MCAsmParser &Parser) { + this->Parser = &Parser; +} + +/// ParseDirectiveCGProfile +/// ::= .cg_profile identifier, identifier, <number> +bool MCAsmParserExtension::ParseDirectiveCGProfile(StringRef, SMLoc) { + StringRef From; + SMLoc FromLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(From)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + StringRef To; + SMLoc ToLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(To)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + int64_t Count; + if (getParser().parseIntToken( + Count, "expected integer count in '.cg_profile' directive")) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *FromSym = getContext().getOrCreateSymbol(From); + MCSymbol *ToSym = getContext().getOrCreateSymbol(To); + + getStreamer().emitCGProfileEntry( + MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(), + FromLoc), + MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(), + ToLoc), + Count); + return false; +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/MCTargetAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/MCTargetAsmParser.cpp index c10418e48b..940f26d475 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/MCTargetAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/MCTargetAsmParser.cpp @@ -1,29 +1,29 @@ -//===-- MCTargetAsmParser.cpp - Target 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/MC/MCParser/MCTargetAsmParser.h" -#include "llvm/MC/MCContext.h" - -using namespace llvm; - -MCTargetAsmParser::MCTargetAsmParser(MCTargetOptions const &MCOptions, - const MCSubtargetInfo &STI, - const MCInstrInfo &MII) - : MCOptions(MCOptions), STI(&STI), MII(MII) {} - -MCTargetAsmParser::~MCTargetAsmParser() = default; - -MCSubtargetInfo &MCTargetAsmParser::copySTI() { - MCSubtargetInfo &STICopy = getContext().getSubtargetCopy(getSTI()); - STI = &STICopy; - return STICopy; -} - -const MCSubtargetInfo &MCTargetAsmParser::getSTI() const { - return *STI; -} +//===-- MCTargetAsmParser.cpp - Target 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/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCContext.h" + +using namespace llvm; + +MCTargetAsmParser::MCTargetAsmParser(MCTargetOptions const &MCOptions, + const MCSubtargetInfo &STI, + const MCInstrInfo &MII) + : MCOptions(MCOptions), STI(&STI), MII(MII) {} + +MCTargetAsmParser::~MCTargetAsmParser() = default; + +MCSubtargetInfo &MCTargetAsmParser::copySTI() { + MCSubtargetInfo &STICopy = getContext().getSubtargetCopy(getSTI()); + STI = &STICopy; + return STICopy; +} + +const MCSubtargetInfo &MCTargetAsmParser::getSTI() const { + return *STI; +} diff --git a/contrib/libs/llvm12/lib/MC/MCParser/MasmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/MasmParser.cpp index 958d4e0489..4957ee7a03 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/MasmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/MasmParser.cpp @@ -1,616 +1,616 @@ -//===- 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" +//===- 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/Optional.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/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/StringSwitch.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/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/Format.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; - +#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; + /// The value associated with a macro exit. Optional<std::string> ExitValue; - SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr; - - ParseStatementInfo() = delete; - ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites) - : AsmRewrites(rewrites) {} -}; - -enum FieldType { - FT_INTEGRAL, // Initializer: integer expression, stored as an MCExpr. - FT_REAL, // Initializer: real number, stored as an APInt. - FT_STRUCT // Initializer: struct initializer, stored recursively. -}; - -struct FieldInfo; -struct StructInfo { - StringRef Name; - bool IsUnion = false; + SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr; + + ParseStatementInfo() = delete; + ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites) + : AsmRewrites(rewrites) {} +}; + +enum FieldType { + FT_INTEGRAL, // Initializer: integer expression, stored as an MCExpr. + FT_REAL, // Initializer: real number, stored as an APInt. + FT_STRUCT // Initializer: struct initializer, stored recursively. +}; + +struct FieldInfo; +struct StructInfo { + StringRef Name; + bool IsUnion = false; unsigned Alignment = 0; unsigned Size = 0; unsigned AlignmentSize = 0; - std::vector<FieldInfo> Fields; - StringMap<size_t> FieldsByName; - + std::vector<FieldInfo> Fields; + StringMap<size_t> FieldsByName; + FieldInfo &addField(StringRef FieldName, FieldType FT, unsigned FieldAlignmentSize); - - StructInfo() = default; - - StructInfo(StringRef StructName, bool Union, unsigned AlignmentValue) - : Name(StructName), IsUnion(Union), Alignment(AlignmentValue) {} -}; - -// FIXME: This should probably use a class hierarchy, raw pointers between the -// objects, and dynamic type resolution instead of a union. On the other hand, -// ownership then becomes much more complicated; the obvious thing would be to -// use BumpPtrAllocator, but the lack of a destructor makes that messy. - -struct StructInitializer; -struct IntFieldInfo { - SmallVector<const MCExpr *, 1> Values; - - IntFieldInfo() = default; - IntFieldInfo(const SmallVector<const MCExpr *, 1> &V) { Values = V; } - IntFieldInfo(SmallVector<const MCExpr *, 1> &&V) { Values = V; } -}; -struct RealFieldInfo { - SmallVector<APInt, 1> AsIntValues; - - RealFieldInfo() = default; - RealFieldInfo(const SmallVector<APInt, 1> &V) { AsIntValues = V; } - RealFieldInfo(SmallVector<APInt, 1> &&V) { AsIntValues = V; } -}; -struct StructFieldInfo { - std::vector<StructInitializer> Initializers; - StructInfo Structure; - - StructFieldInfo() = default; - StructFieldInfo(const std::vector<StructInitializer> &V, StructInfo S) { - Initializers = V; - Structure = S; - } - StructFieldInfo(std::vector<StructInitializer> &&V, StructInfo S) { - Initializers = V; - Structure = S; - } -}; - -class FieldInitializer { -public: - FieldType FT; - union { - IntFieldInfo IntInfo; - RealFieldInfo RealInfo; - StructFieldInfo StructInfo; - }; - - ~FieldInitializer() { - switch (FT) { - case FT_INTEGRAL: - IntInfo.~IntFieldInfo(); - break; - case FT_REAL: - RealInfo.~RealFieldInfo(); - break; - case FT_STRUCT: - StructInfo.~StructFieldInfo(); - break; - } - } - - FieldInitializer(FieldType FT) : FT(FT) { - switch (FT) { - case FT_INTEGRAL: - new (&IntInfo) IntFieldInfo(); - break; - case FT_REAL: - new (&RealInfo) RealFieldInfo(); - break; - case FT_STRUCT: - new (&StructInfo) StructFieldInfo(); - break; - } - } - - FieldInitializer(SmallVector<const MCExpr *, 1> &&Values) : FT(FT_INTEGRAL) { - new (&IntInfo) IntFieldInfo(Values); - } - - FieldInitializer(SmallVector<APInt, 1> &&AsIntValues) : FT(FT_REAL) { - new (&RealInfo) RealFieldInfo(AsIntValues); - } - - FieldInitializer(std::vector<StructInitializer> &&Initializers, - struct StructInfo Structure) - : FT(FT_STRUCT) { - new (&StructInfo) StructFieldInfo(Initializers, Structure); - } - - FieldInitializer(const FieldInitializer &Initializer) : FT(Initializer.FT) { - switch (FT) { - case FT_INTEGRAL: - new (&IntInfo) IntFieldInfo(Initializer.IntInfo); - break; - case FT_REAL: - new (&RealInfo) RealFieldInfo(Initializer.RealInfo); - break; - case FT_STRUCT: - new (&StructInfo) StructFieldInfo(Initializer.StructInfo); - break; - } - } - - FieldInitializer(FieldInitializer &&Initializer) : FT(Initializer.FT) { - switch (FT) { - case FT_INTEGRAL: - new (&IntInfo) IntFieldInfo(Initializer.IntInfo); - break; - case FT_REAL: - new (&RealInfo) RealFieldInfo(Initializer.RealInfo); - break; - case FT_STRUCT: - new (&StructInfo) StructFieldInfo(Initializer.StructInfo); - break; - } - } - - FieldInitializer &operator=(const FieldInitializer &Initializer) { - if (FT != Initializer.FT) { - switch (FT) { - case FT_INTEGRAL: - IntInfo.~IntFieldInfo(); - break; - case FT_REAL: - RealInfo.~RealFieldInfo(); - break; - case FT_STRUCT: - StructInfo.~StructFieldInfo(); - break; - } - } - FT = Initializer.FT; - switch (FT) { - case FT_INTEGRAL: - IntInfo = Initializer.IntInfo; - break; - case FT_REAL: - RealInfo = Initializer.RealInfo; - break; - case FT_STRUCT: - StructInfo = Initializer.StructInfo; - break; - } - return *this; - } - - FieldInitializer &operator=(FieldInitializer &&Initializer) { - if (FT != Initializer.FT) { - switch (FT) { - case FT_INTEGRAL: - IntInfo.~IntFieldInfo(); - break; - case FT_REAL: - RealInfo.~RealFieldInfo(); - break; - case FT_STRUCT: - StructInfo.~StructFieldInfo(); - break; - } - } - FT = Initializer.FT; - switch (FT) { - case FT_INTEGRAL: - IntInfo = Initializer.IntInfo; - break; - case FT_REAL: - RealInfo = Initializer.RealInfo; - break; - case FT_STRUCT: - StructInfo = Initializer.StructInfo; - break; - } - return *this; - } -}; - -struct StructInitializer { - std::vector<FieldInitializer> FieldInitializers; -}; - -struct FieldInfo { - // Offset of the field within the containing STRUCT. - size_t Offset = 0; - - // Total size of the field (= LengthOf * Type). + + StructInfo() = default; + + StructInfo(StringRef StructName, bool Union, unsigned AlignmentValue) + : Name(StructName), IsUnion(Union), Alignment(AlignmentValue) {} +}; + +// FIXME: This should probably use a class hierarchy, raw pointers between the +// objects, and dynamic type resolution instead of a union. On the other hand, +// ownership then becomes much more complicated; the obvious thing would be to +// use BumpPtrAllocator, but the lack of a destructor makes that messy. + +struct StructInitializer; +struct IntFieldInfo { + SmallVector<const MCExpr *, 1> Values; + + IntFieldInfo() = default; + IntFieldInfo(const SmallVector<const MCExpr *, 1> &V) { Values = V; } + IntFieldInfo(SmallVector<const MCExpr *, 1> &&V) { Values = V; } +}; +struct RealFieldInfo { + SmallVector<APInt, 1> AsIntValues; + + RealFieldInfo() = default; + RealFieldInfo(const SmallVector<APInt, 1> &V) { AsIntValues = V; } + RealFieldInfo(SmallVector<APInt, 1> &&V) { AsIntValues = V; } +}; +struct StructFieldInfo { + std::vector<StructInitializer> Initializers; + StructInfo Structure; + + StructFieldInfo() = default; + StructFieldInfo(const std::vector<StructInitializer> &V, StructInfo S) { + Initializers = V; + Structure = S; + } + StructFieldInfo(std::vector<StructInitializer> &&V, StructInfo S) { + Initializers = V; + Structure = S; + } +}; + +class FieldInitializer { +public: + FieldType FT; + union { + IntFieldInfo IntInfo; + RealFieldInfo RealInfo; + StructFieldInfo StructInfo; + }; + + ~FieldInitializer() { + switch (FT) { + case FT_INTEGRAL: + IntInfo.~IntFieldInfo(); + break; + case FT_REAL: + RealInfo.~RealFieldInfo(); + break; + case FT_STRUCT: + StructInfo.~StructFieldInfo(); + break; + } + } + + FieldInitializer(FieldType FT) : FT(FT) { + switch (FT) { + case FT_INTEGRAL: + new (&IntInfo) IntFieldInfo(); + break; + case FT_REAL: + new (&RealInfo) RealFieldInfo(); + break; + case FT_STRUCT: + new (&StructInfo) StructFieldInfo(); + break; + } + } + + FieldInitializer(SmallVector<const MCExpr *, 1> &&Values) : FT(FT_INTEGRAL) { + new (&IntInfo) IntFieldInfo(Values); + } + + FieldInitializer(SmallVector<APInt, 1> &&AsIntValues) : FT(FT_REAL) { + new (&RealInfo) RealFieldInfo(AsIntValues); + } + + FieldInitializer(std::vector<StructInitializer> &&Initializers, + struct StructInfo Structure) + : FT(FT_STRUCT) { + new (&StructInfo) StructFieldInfo(Initializers, Structure); + } + + FieldInitializer(const FieldInitializer &Initializer) : FT(Initializer.FT) { + switch (FT) { + case FT_INTEGRAL: + new (&IntInfo) IntFieldInfo(Initializer.IntInfo); + break; + case FT_REAL: + new (&RealInfo) RealFieldInfo(Initializer.RealInfo); + break; + case FT_STRUCT: + new (&StructInfo) StructFieldInfo(Initializer.StructInfo); + break; + } + } + + FieldInitializer(FieldInitializer &&Initializer) : FT(Initializer.FT) { + switch (FT) { + case FT_INTEGRAL: + new (&IntInfo) IntFieldInfo(Initializer.IntInfo); + break; + case FT_REAL: + new (&RealInfo) RealFieldInfo(Initializer.RealInfo); + break; + case FT_STRUCT: + new (&StructInfo) StructFieldInfo(Initializer.StructInfo); + break; + } + } + + FieldInitializer &operator=(const FieldInitializer &Initializer) { + if (FT != Initializer.FT) { + switch (FT) { + case FT_INTEGRAL: + IntInfo.~IntFieldInfo(); + break; + case FT_REAL: + RealInfo.~RealFieldInfo(); + break; + case FT_STRUCT: + StructInfo.~StructFieldInfo(); + break; + } + } + FT = Initializer.FT; + switch (FT) { + case FT_INTEGRAL: + IntInfo = Initializer.IntInfo; + break; + case FT_REAL: + RealInfo = Initializer.RealInfo; + break; + case FT_STRUCT: + StructInfo = Initializer.StructInfo; + break; + } + return *this; + } + + FieldInitializer &operator=(FieldInitializer &&Initializer) { + if (FT != Initializer.FT) { + switch (FT) { + case FT_INTEGRAL: + IntInfo.~IntFieldInfo(); + break; + case FT_REAL: + RealInfo.~RealFieldInfo(); + break; + case FT_STRUCT: + StructInfo.~StructFieldInfo(); + break; + } + } + FT = Initializer.FT; + switch (FT) { + case FT_INTEGRAL: + IntInfo = Initializer.IntInfo; + break; + case FT_REAL: + RealInfo = Initializer.RealInfo; + break; + case FT_STRUCT: + StructInfo = Initializer.StructInfo; + break; + } + return *this; + } +}; + +struct StructInitializer { + std::vector<FieldInitializer> FieldInitializers; +}; + +struct FieldInfo { + // Offset of the field within the containing STRUCT. + size_t Offset = 0; + + // Total size of the field (= LengthOf * Type). unsigned SizeOf = 0; - - // Number of elements in the field (1 if scalar, >1 if an array). + + // Number of elements in the field (1 if scalar, >1 if an array). unsigned LengthOf = 0; - - // Size of a single entry in this field, in bytes ("type" in MASM standards). + + // Size of a single entry in this field, in bytes ("type" in MASM standards). unsigned Type = 0; - - FieldInitializer Contents; - - FieldInfo(FieldType FT) : Contents(FT) {} -}; - + + FieldInitializer Contents; + + FieldInfo(FieldType FT) : Contents(FT) {} +}; + FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT, unsigned FieldAlignmentSize) { - if (!FieldName.empty()) + if (!FieldName.empty()) FieldsByName[FieldName.lower()] = Fields.size(); - Fields.emplace_back(FT); - FieldInfo &Field = Fields.back(); - if (IsUnion) { - Field.Offset = 0; - } else { + Fields.emplace_back(FT); + FieldInfo &Field = Fields.back(); + if (IsUnion) { + Field.Offset = 0; + } else { Size = llvm::alignTo(Size, std::min(Alignment, FieldAlignmentSize)); - Field.Offset = Size; - } + Field.Offset = Size; + } AlignmentSize = std::max(AlignmentSize, FieldAlignmentSize); - return Field; -} - -/// 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; + return Field; +} + +/// 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; std::vector<bool> EndStatementAtEOFStack; - - 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 struct definitions. - SmallVector<StructInfo, 1> StructInProgress; - - /// Maps struct tags to struct definitions. - StringMap<StructInfo> Structs; - + + 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 struct definitions. + SmallVector<StructInfo, 1> StructInProgress; + + /// Maps struct tags to struct definitions. + StringMap<StructInfo> Structs; + /// Maps data location names to types. StringMap<AsmTypeInfo> KnownType; - - /// Stack of active macro instantiations. - std::vector<MacroInstantiation*> ActiveMacros; - - /// List of bodies of anonymous macros. - std::deque<MCAsmMacro> MacroLikeBodies; - - /// 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 ParsingMSInlineAsm = false; - - /// Did we already inform the user about inconsistent MD5 usage? - bool ReportedInconsistentMD5 = false; - - // Current <...> expression depth. - unsigned AngleBracketDepth = 0U; - + + /// Stack of active macro instantiations. + std::vector<MacroInstantiation*> ActiveMacros; + + /// List of bodies of anonymous macros. + std::deque<MCAsmMacro> MacroLikeBodies; + + /// 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 ParsingMSInlineAsm = false; + + /// Did we already inform the user about inconsistent MD5 usage? + bool ReportedInconsistentMD5 = false; + + // Current <...> expression depth. + unsigned AngleBracketDepth = 0U; + // Number of locals defined. uint16_t LocalCounter = 0; -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 setParsingMSInlineAsm(bool V) override { - ParsingMSInlineAsm = V; - // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and - // hex integer literals. - Lexer.setLexMasmIntegers(V); - } - bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; } - - bool isParsingMasm() const override { return true; } - +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 setParsingMSInlineAsm(bool V) override { + ParsingMSInlineAsm = V; + // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and + // hex integer literals. + Lexer.setLexMasmIntegers(V); + } + bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; } + + bool isParsingMasm() const override { return true; } + bool defineMacro(StringRef Name, StringRef Value) override; - + bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override; bool lookUpField(StringRef Base, StringRef Member, AsmFieldInfo &Info) const override; bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override; - 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 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, AsmTypeInfo *TypeInfo) 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); - - bool expandMacro(raw_svector_ostream &OS, StringRef Body, - ArrayRef<MCAsmMacroParameter> Parameters, + 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); + + bool expandMacro(raw_svector_ostream &OS, StringRef Body, + ArrayRef<MCAsmMacroParameter> Parameters, ArrayRef<MCAsmMacroArgument> A, const std::vector<std::string> &Locals, SMLoc L); - - /// Are we inside a macro instantiation? - bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} - - /// Handle entry to macro instantiation. - /// - /// \param M The macro. - /// \param NameLoc Instantiation location. + + /// 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, AsmToken::TokenKind ArgumentEndTok = AsmToken::EndOfStatement); - + /// Handle invocation of macro function. /// /// \param M The macro. /// \param NameLoc Invocation location. bool handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc); - /// Handle exit from macro instantiation. - void handleMacroExit(); - - /// Extract AsmTokens for a macro argument. + /// Handle exit from macro instantiation. + void handleMacroExit(); + + /// Extract AsmTokens for a macro argument. bool parseMacroArgument(const MCAsmMacroParameter *MP, MCAsmMacroArgument &MA, AsmToken::TokenKind EndTok = AsmToken::EndOfStatement); - - /// Parse all macro arguments for a given macro. + + /// Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A, AsmToken::TokenKind EndTok = AsmToken::EndOfStatement); - - void printMacroInstantiations(); + + void printMacroInstantiations(); bool expandStatement(SMLoc Loc); - 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); - - bool lookUpField(const StructInfo &Structure, StringRef Member, + 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); + + bool lookUpField(const StructInfo &Structure, StringRef Member, AsmFieldInfo &Info) const; - - /// 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); - - /// 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. + + /// 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); + + /// 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, bool EndStatementAtEOF = true); - + /// Parse up to a token of kind \p EndTok and return the contents from the /// current token up to (but not including) this token; the current token on /// exit will be either this kind or EOF. Reads through instantiated macro @@ -621,140 +621,140 @@ private: /// Parse up to the end of statement and 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; - - 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, + StringRef parseStringToEndOfStatement() override; + + 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_DF, - DK_DQ, - DK_DW, - DK_REAL4, - DK_REAL8, + DK_DQ, + DK_DW, + DK_REAL4, + DK_REAL8, DK_REAL10, - DK_ALIGN, - DK_ORG, - DK_ENDR, - DK_EXTERN, - DK_PUBLIC, - DK_COMM, - DK_COMMENT, - DK_INCLUDE, + DK_ALIGN, + DK_ORG, + DK_ENDR, + DK_EXTERN, + DK_PUBLIC, + DK_COMM, + DK_COMMENT, + DK_INCLUDE, DK_REPEAT, DK_WHILE, DK_FOR, DK_FORC, - 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_MACRO, - DK_EXITM, - DK_ENDM, + 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_MACRO, + DK_EXITM, + DK_ENDM, DK_PURGE, - 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_STRUCT, - DK_UNION, - DK_ENDS, + 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_STRUCT, + DK_UNION, + DK_ENDS, DK_END, DK_PUSHFRAME, DK_PUSHREG, @@ -762,382 +762,382 @@ private: DK_SAVEXMM128, DK_SETFRAME, DK_RADIX, - }; - - /// Maps directive name --> DirectiveKind enum, for directives parsed by this - /// class. - StringMap<DirectiveKind> DirectiveKindMap; - + }; + + /// Maps directive name --> DirectiveKind enum, for directives parsed by this + /// class. + StringMap<DirectiveKind> DirectiveKindMap; + bool isMacroLikeDirective(); - // 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); - - // "byte", "word", ... - bool emitIntValue(const MCExpr *Value, unsigned Size); - bool parseScalarInitializer(unsigned Size, - SmallVectorImpl<const MCExpr *> &Values, - unsigned StringPadLength = 0); - bool parseScalarInstList( - unsigned Size, SmallVectorImpl<const MCExpr *> &Values, - const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); + // 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); + + // "byte", "word", ... + bool emitIntValue(const MCExpr *Value, unsigned Size); + bool parseScalarInitializer(unsigned Size, + SmallVectorImpl<const MCExpr *> &Values, + unsigned StringPadLength = 0); + bool parseScalarInstList( + unsigned Size, SmallVectorImpl<const MCExpr *> &Values, + const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); bool emitIntegralValues(unsigned Size, unsigned *Count = nullptr); - bool addIntegralField(StringRef Name, unsigned Size); - bool parseDirectiveValue(StringRef IDVal, unsigned Size); + bool addIntegralField(StringRef Name, unsigned Size); + bool parseDirectiveValue(StringRef IDVal, unsigned Size); bool parseDirectiveNamedValue(StringRef TypeName, unsigned Size, StringRef Name, SMLoc NameLoc); - + // "real4", "real8", "real10" bool emitRealValues(const fltSemantics &Semantics, unsigned *Count = nullptr); bool addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size); bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics, size_t Size); - bool parseRealInstList( - const fltSemantics &Semantics, SmallVectorImpl<APInt> &Values, - const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); + bool parseRealInstList( + const fltSemantics &Semantics, SmallVectorImpl<APInt> &Values, + const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); bool parseDirectiveNamedRealValue(StringRef TypeName, - const fltSemantics &Semantics, + const fltSemantics &Semantics, unsigned Size, StringRef Name, SMLoc NameLoc); - - bool parseOptionalAngleBracketOpen(); - bool parseAngleBracketClose(const Twine &Msg = "expected '>'"); - - bool parseFieldInitializer(const FieldInfo &Field, - FieldInitializer &Initializer); - bool parseFieldInitializer(const FieldInfo &Field, - const IntFieldInfo &Contents, - FieldInitializer &Initializer); - bool parseFieldInitializer(const FieldInfo &Field, - const RealFieldInfo &Contents, - FieldInitializer &Initializer); - bool parseFieldInitializer(const FieldInfo &Field, - const StructFieldInfo &Contents, - FieldInitializer &Initializer); - - bool parseStructInitializer(const StructInfo &Structure, - StructInitializer &Initializer); - bool parseStructInstList( - const StructInfo &Structure, std::vector<StructInitializer> &Initializers, - const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); - - bool emitFieldValue(const FieldInfo &Field); - bool emitFieldValue(const FieldInfo &Field, const IntFieldInfo &Contents); - bool emitFieldValue(const FieldInfo &Field, const RealFieldInfo &Contents); - bool emitFieldValue(const FieldInfo &Field, const StructFieldInfo &Contents); - - bool emitFieldInitializer(const FieldInfo &Field, - const FieldInitializer &Initializer); - bool emitFieldInitializer(const FieldInfo &Field, - const IntFieldInfo &Contents, - const IntFieldInfo &Initializer); - bool emitFieldInitializer(const FieldInfo &Field, - const RealFieldInfo &Contents, - const RealFieldInfo &Initializer); - bool emitFieldInitializer(const FieldInfo &Field, - const StructFieldInfo &Contents, - const StructFieldInfo &Initializer); - - bool emitStructInitializer(const StructInfo &Structure, - const StructInitializer &Initializer); - - // User-defined types (structs, unions): + + bool parseOptionalAngleBracketOpen(); + bool parseAngleBracketClose(const Twine &Msg = "expected '>'"); + + bool parseFieldInitializer(const FieldInfo &Field, + FieldInitializer &Initializer); + bool parseFieldInitializer(const FieldInfo &Field, + const IntFieldInfo &Contents, + FieldInitializer &Initializer); + bool parseFieldInitializer(const FieldInfo &Field, + const RealFieldInfo &Contents, + FieldInitializer &Initializer); + bool parseFieldInitializer(const FieldInfo &Field, + const StructFieldInfo &Contents, + FieldInitializer &Initializer); + + bool parseStructInitializer(const StructInfo &Structure, + StructInitializer &Initializer); + bool parseStructInstList( + const StructInfo &Structure, std::vector<StructInitializer> &Initializers, + const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement); + + bool emitFieldValue(const FieldInfo &Field); + bool emitFieldValue(const FieldInfo &Field, const IntFieldInfo &Contents); + bool emitFieldValue(const FieldInfo &Field, const RealFieldInfo &Contents); + bool emitFieldValue(const FieldInfo &Field, const StructFieldInfo &Contents); + + bool emitFieldInitializer(const FieldInfo &Field, + const FieldInitializer &Initializer); + bool emitFieldInitializer(const FieldInfo &Field, + const IntFieldInfo &Contents, + const IntFieldInfo &Initializer); + bool emitFieldInitializer(const FieldInfo &Field, + const RealFieldInfo &Contents, + const RealFieldInfo &Initializer); + bool emitFieldInitializer(const FieldInfo &Field, + const StructFieldInfo &Contents, + const StructFieldInfo &Initializer); + + bool emitStructInitializer(const StructInfo &Structure, + const StructInitializer &Initializer); + + // User-defined types (structs, unions): bool emitStructValues(const StructInfo &Structure, unsigned *Count = nullptr); - bool addStructField(StringRef Name, const StructInfo &Structure); - bool parseDirectiveStructValue(const StructInfo &Structure, - StringRef Directive, SMLoc DirLoc); - bool parseDirectiveNamedStructValue(const StructInfo &Structure, - StringRef Directive, SMLoc DirLoc, - StringRef Name); - - // "=", "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 addStructField(StringRef Name, const StructInfo &Structure); + bool parseDirectiveStructValue(const StructInfo &Structure, + StringRef Directive, SMLoc DirLoc); + bool parseDirectiveNamedStructValue(const StructInfo &Structure, + StringRef Directive, SMLoc DirLoc, + StringRef Name); + + // "=", "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(SMLoc DirectiveLoc, StringRef Directive, std::string &Value); - bool parseDirectiveEndMacro(StringRef Directive); + bool parseDirectiveEndMacro(StringRef Directive); bool parseDirectiveMacro(StringRef Name, SMLoc NameLoc); - - bool parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind, - StringRef Name, SMLoc NameLoc); - bool parseDirectiveNestedStruct(StringRef Directive, DirectiveKind DirKind); - bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc); - bool parseDirectiveNestedEnds(); - - /// 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 parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind, + StringRef Name, SMLoc NameLoc); + bool parseDirectiveNestedStruct(StringRef Directive, DirectiveKind DirKind); + bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc); + bool parseDirectiveNestedEnds(); + + /// 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); void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, SMLoc ExitLoc, raw_svector_ostream &OS); bool parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Directive); bool parseDirectiveFor(SMLoc DirectiveLoc, StringRef Directive); bool parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive); bool parseDirectiveWhile(SMLoc DirectiveLoc); - - // "_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); - + + // "_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); + // ".radix" bool parseDirectiveRadix(SMLoc DirectiveLoc); - // "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()) { - 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()); + // "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()) { + 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()); EndStatementAtEOFStack.push_back(true); - - // 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()); + + // 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()); EndStatementAtEOFStack.push_back(true); - return false; -} - + return false; +} + void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer, bool EndStatementAtEOF) { - CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), + CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), Loc.getPointer(), EndStatementAtEOF); -} - -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)) { +} + +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().lower()); const llvm::MCAsmMacro *M = getContext().lookupMacro(tok->getIdentifier().lower()); - if (it != Variables.end() && it->second.IsText) { + if (it != Variables.end() && it->second.IsText) { // This is a textmacro; expand it in place. - 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); + 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); EndStatementAtEOFStack.push_back(false); - tok = &Lexer.Lex(); + tok = &Lexer.Lex(); } else if (M && M->IsFunction && Lexer.peekTok().is(AsmToken::LParen)) { // This is a macro function invocation; expand it in place. const AsmToken MacroTok = *tok; @@ -1147,18 +1147,18 @@ const AsmToken &MasmParser::Lex() { tok = &Lexer.Lex(); } continue; - } 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(); - } - + } 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(); + } + // Recognize and bypass line continuations. while (tok->is(AsmToken::BackSlash) && Lexer.peekTok().is(AsmToken::EndOfStatement)) { @@ -1167,174 +1167,174 @@ const AsmToken &MasmParser::Lex() { 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()) { + 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()) { EndStatementAtEOFStack.pop_back(); jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back()); - return Lex(); - } + return Lex(); + } EndStatementAtEOFStack.pop_back(); assert(EndStatementAtEOFStack.empty()); - } - - 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().getCompilationDir(), - FirstCppHashFilename, - /*Cksum=*/None, /*Source=*/None); - const MCDwarfFile &RootFile = - getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile(); - getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective( - /*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. + } + + 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().getCompilationDir(), + FirstCppHashFilename, + /*Cksum=*/None, /*Source=*/None); + const MCDwarfFile &RootFile = + getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile(); + getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective( + /*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) || SrcMgr.getParentIncludeLoc(CurBuffer) != SMLoc()) { // Skip through the EOF at the end of an inclusion. if (Lexer.is(AsmToken::Eof)) Lex(); - 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) + 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(Lexer.getLoc()); - - return HadError || getContext().hadError(); -} - -bool MasmParser::checkForValidSection() { - if (!ParsingMSInlineAsm && !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() { + + return HadError || getContext().hadError(); +} + +bool MasmParser::checkForValidSection() { + if (!ParsingMSInlineAsm && !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)) { if (Lexer.is(AsmToken::Eof)) { SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); @@ -1346,14 +1346,14 @@ void MasmParser::eatToEndOfStatement() { jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back()); } - Lexer.Lex(); + Lexer.Lex(); } - - // Eat EOL. - if (Lexer.is(AsmToken::EndOfStatement)) - Lexer.Lex(); -} - + + // Eat EOL. + if (Lexer.is(AsmToken::EndOfStatement)) + Lexer.Lex(); +} + SmallVector<StringRef, 1> MasmParser::parseStringRefsTo(AsmToken::TokenKind EndTok) { SmallVector<StringRef, 1> Refs; @@ -1387,90 +1387,90 @@ std::string MasmParser::parseStringTo(AsmToken::TokenKind EndTok) { return Str; } -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); -} - -/// 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 ::= '.' +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); +} + +/// 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 ::= ~,+,-,'not' primaryexpr /// primaryexpr ::= string /// (a string is interpreted as a 64-bit number in big-endian base-256) bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, AsmTypeInfo *TypeInfo) { - 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. + 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, nullptr)) - return true; - Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc); - return false; - case AsmToken::Dollar: - case AsmToken::At: - 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"); - } - } + return true; + Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc); + return false; + case AsmToken::Dollar: + case AsmToken::At: + 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 named bitwise negation. if (Identifier.equals_lower("not")) { if (parsePrimaryExpr(Res, EndLoc, nullptr)) @@ -1478,101 +1478,101 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; } - // 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; - - // Look up 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 + "'"); - } - } - - // Find the field offset if used. + // 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; + + // Look up 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 + "'"); + } + } + + // Find the field offset if used. AsmFieldInfo Info; - Split = SymbolName.split('.'); + Split = SymbolName.split('.'); if (Split.second.empty()) { } else { - SymbolName = Split.first; + SymbolName = Split.first; if (lookUpField(SymbolName, Split.second, Info)) { std::pair<StringRef, StringRef> BaseMember = Split.second.split('.'); StringRef Base = BaseMember.first, Member = BaseMember.second; lookUpField(Base, Member, Info); } else if (Structs.count(SymbolName.lower())) { - // This is actually a reference to a field offset. + // This is actually a reference to a field offset. Res = MCConstantExpr::create(Info.Offset, getContext()); - return false; - } - } - - 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. - const MCExpr *SymRef = - MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc); + return false; + } + } + + 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. + const MCExpr *SymRef = + MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc); if (Info.Offset) { Res = MCBinaryExpr::create( MCBinaryExpr::Add, SymRef, MCConstantExpr::create(Info.Offset, getContext()), getContext()); - } else { - Res = SymRef; - } + } else { + Res = SymRef; + } if (TypeInfo) { if (Info.Type.Name.empty()) { auto TypeIt = KnownType.find(Identifier.lower()); @@ -1583,41 +1583,41 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, *TypeInfo = Info.Type; } - 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(); - // Look up 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; - } + 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(); + // Look up 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::String: { // MASM strings (used as constants) are interpreted as big-endian base-256. SMLoc ValueLoc = getTok().getLoc(); @@ -1632,286 +1632,286 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, Res = MCConstantExpr::create(IntValue, getContext()); 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. + 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, nullptr)) - return true; - Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); - return false; - case AsmToken::Plus: - Lex(); // Eat the operator. + return true; + Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); + return false; + case AsmToken::Plus: + Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc, nullptr)) - return true; - Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); - return false; - case AsmToken::Tilde: - Lex(); // Eat the operator. + return true; + Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); + return false; + case AsmToken::Tilde: + Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc, nullptr)) - 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. -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 '!'. + 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. +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 BracketContents) { - std::string Res; + std::string Res; for (size_t Pos = 0; Pos < BracketContents.size(); Pos++) { if (BracketContents[Pos] == '!') - Pos++; + Pos++; Res += BracketContents[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, - bool EndExpressionAtGreater) { - 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: - if (EndExpressionAtGreater) - return 0; - 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: |, &, ^ - 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: - if (EndExpressionAtGreater) - return 0; - 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, - AngleBracketDepth > 0); -} - -/// 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) { + } + 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, + bool EndExpressionAtGreater) { + 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: + if (EndExpressionAtGreater) + return 0; + 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: |, &, ^ + 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: + if (EndExpressionAtGreater) + return 0; + 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, + AngleBracketDepth > 0); +} + +/// 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) { AsmToken::TokenKind TokKind = Lexer.getKind(); if (Lexer.getKind() == AsmToken::Identifier) { TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString()) @@ -1926,52 +1926,52 @@ bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, .CaseLower("ge", AsmToken::GreaterEqual) .Default(TokKind); } - MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; + MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(TokKind, 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: + + // 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: /// ::= % statement -/// ::= 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; - } +/// ::= 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; + } // If preceded by an expansion operator, first expand all text macros and // macro functions. @@ -1981,321 +1981,321 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info, return true; } - // 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"); + // 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 (Lexer.is(AsmToken::Identifier) && getTok().getString().equals_lower("echo")) { // Intercept echo early to avoid lexical substitution in its message, and // delegate all handling to the appropriate function. return parseDirectiveEcho(); - } 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 (ParsingMSInlineAsm && 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)) { + } 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 (ParsingMSInlineAsm && 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)) { std::string CommentStr = parseStringTo(AsmToken::EndOfStatement); - 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().isParsingMSInlineAsm()) - 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. + 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().isParsingMSInlineAsm()) + 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 (const MCAsmMacro *M = getContext().lookupMacro(IDVal.lower())) { - 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 differently 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()); - - // Special-case handling of structure-end directives at higher priority, - // since ENDS is overloaded as a segment-end directive. - if (IDVal.equals_lower("ends") && StructInProgress.size() > 1 && - getTok().is(AsmToken::EndOfStatement)) { - return parseDirectiveNestedEnds(); - } - - // 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 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 differently 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()); + + // Special-case handling of structure-end directives at higher priority, + // since ENDS is overloaded as a segment-end directive. + if (IDVal.equals_lower("ends") && StructInProgress.size() > 1 && + getTok().is(AsmToken::EndOfStatement)) { + return parseDirectiveNestedEnds(); + } + + // 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: case DK_DF: - return parseDirectiveValue(IDVal, 6); - case DK_QWORD: - case DK_SQWORD: - case DK_DQ: - return parseDirectiveValue(IDVal, 8); - case DK_REAL4: + 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(), 4); - case DK_REAL8: + case DK_REAL8: return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble(), 8); case DK_REAL10: return parseDirectiveRealValue(IDVal, APFloat::x87DoubleExtended(), 10); - case DK_STRUCT: - case DK_UNION: - return parseDirectiveNestedStruct(IDVal, DirKind); - case DK_ENDS: - return parseDirectiveNestedEnds(); - 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_STRUCT: + case DK_UNION: + return parseDirectiveNestedStruct(IDVal, DirKind); + case DK_ENDS: + return parseDirectiveNestedEnds(); + 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_REPEAT: return parseDirectiveRepeat(IDLoc, IDVal); case DK_WHILE: @@ -2304,428 +2304,428 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveFor(IDLoc, IDVal); case DK_FORC: return parseDirectiveForc(IDLoc, IDVal); - 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_EXITM: + 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_EXITM: Info.ExitValue = ""; return parseDirectiveExitMacro(IDLoc, IDVal, *Info.ExitValue); - case DK_ENDM: + case DK_ENDM: Info.ExitValue = ""; - return parseDirectiveEndMacro(IDVal); + return parseDirectiveEndMacro(IDVal); case DK_PURGE: - 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); + 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_RADIX: return parseDirectiveRadix(IDLoc); - } - - return Error(IDLoc, "unknown directive"); - } - - // We also check if this is allocating memory with user-defined type. - auto IDIt = Structs.find(IDVal.lower()); - if (IDIt != Structs.end()) - return parseDirectiveStructValue(/*Structure=*/IDIt->getValue(), IDVal, - IDLoc); - - // 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()); - - // Special-case handling of structure-end directives at higher priority, since - // ENDS is overloaded as a segment-end directive. - if (nextVal.equals_lower("ends") && StructInProgress.size() == 1) { - Lex(); - return parseDirectiveEnds(IDVal, IDLoc); - } - - // 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); - } - - // 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); - case DK_BYTE: + } + + return Error(IDLoc, "unknown directive"); + } + + // We also check if this is allocating memory with user-defined type. + auto IDIt = Structs.find(IDVal.lower()); + if (IDIt != Structs.end()) + return parseDirectiveStructValue(/*Structure=*/IDIt->getValue(), IDVal, + IDLoc); + + // 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()); + + // Special-case handling of structure-end directives at higher priority, since + // ENDS is overloaded as a segment-end directive. + if (nextVal.equals_lower("ends") && StructInProgress.size() == 1) { + Lex(); + return parseDirectiveEnds(IDVal, IDLoc); + } + + // 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); + } + + // 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); + case DK_BYTE: case DK_SBYTE: - case DK_DB: - Lex(); - return parseDirectiveNamedValue(nextVal, 1, IDVal, IDLoc); - case DK_WORD: + case DK_DB: + Lex(); + return parseDirectiveNamedValue(nextVal, 1, IDVal, IDLoc); + case DK_WORD: case DK_SWORD: - case DK_DW: - Lex(); - return parseDirectiveNamedValue(nextVal, 2, IDVal, IDLoc); - case DK_DWORD: + case DK_DW: + Lex(); + return parseDirectiveNamedValue(nextVal, 2, IDVal, IDLoc); + case DK_DWORD: case DK_SDWORD: - case DK_DD: - Lex(); - return parseDirectiveNamedValue(nextVal, 4, IDVal, IDLoc); - case DK_FWORD: + case DK_DD: + Lex(); + return parseDirectiveNamedValue(nextVal, 4, IDVal, IDLoc); + case DK_FWORD: case DK_DF: - Lex(); - return parseDirectiveNamedValue(nextVal, 6, IDVal, IDLoc); - case DK_QWORD: + Lex(); + return parseDirectiveNamedValue(nextVal, 6, IDVal, IDLoc); + case DK_QWORD: case DK_SQWORD: - case DK_DQ: - Lex(); - return parseDirectiveNamedValue(nextVal, 8, IDVal, IDLoc); - case DK_REAL4: - Lex(); + case DK_DQ: + Lex(); + return parseDirectiveNamedValue(nextVal, 8, IDVal, IDLoc); + case DK_REAL4: + Lex(); return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEsingle(), 4, IDVal, IDLoc); - case DK_REAL8: - Lex(); + case DK_REAL8: + Lex(); return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEdouble(), 8, IDVal, IDLoc); case DK_REAL10: Lex(); return parseDirectiveNamedRealValue(nextVal, APFloat::x87DoubleExtended(), 10, IDVal, IDLoc); - case DK_STRUCT: - case DK_UNION: - Lex(); - return parseDirectiveStruct(nextVal, DirKind, IDVal, IDLoc); - case DK_ENDS: - Lex(); - return parseDirectiveEnds(IDVal, IDLoc); + case DK_STRUCT: + case DK_UNION: + Lex(); + return parseDirectiveStruct(nextVal, DirKind, IDVal, IDLoc); + case DK_ENDS: + Lex(); + return parseDirectiveEnds(IDVal, IDLoc); case DK_MACRO: Lex(); return parseDirectiveMacro(IDVal, IDLoc); - } - - // Finally, we check if this is allocating a variable with user-defined type. - auto NextIt = Structs.find(nextVal.lower()); - if (NextIt != Structs.end()) { - Lex(); - return parseDirectiveNamedStructValue(/*Structure=*/NextIt->getValue(), - nextVal, nextLoc, IDVal); - } - - // __asm _emit or __asm __emit - if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" || - IDVal == "_EMIT" || IDVal == "__EMIT")) - return parseDirectiveMSEmit(IDLoc, Info, IDVal.size()); - - // __asm align - if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN")) - return parseDirectiveMSAlign(IDLoc, Info); - - if (ParsingMSInlineAsm && (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.ParsedOperands); - 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().isParsingMSInlineAsm())) - 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.getPointer()); - 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); -} - + } + + // Finally, we check if this is allocating a variable with user-defined type. + auto NextIt = Structs.find(nextVal.lower()); + if (NextIt != Structs.end()) { + Lex(); + return parseDirectiveNamedStructValue(/*Structure=*/NextIt->getValue(), + nextVal, nextLoc, IDVal); + } + + // __asm _emit or __asm __emit + if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" || + IDVal == "_EMIT" || IDVal == "__EMIT")) + return parseDirectiveMSEmit(IDLoc, Info, IDVal.size()); + + // __asm align + if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN")) + return parseDirectiveMSAlign(IDLoc, Info); + + if (ParsingMSInlineAsm && (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.ParsedOperands); + 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().isParsingMSInlineAsm())) + 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.getPointer()); + 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); +} + // This is similar to the IsIdentifierChar function in AsmLexer.cpp, but does // not accept '.'. static bool isMacroParameterChar(char C) { return isAlnum(C) || C == '_' || C == '$' || C == '@' || C == '?'; -} - -bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, - ArrayRef<MCAsmMacroParameter> Parameters, - ArrayRef<MCAsmMacroArgument> A, +} + +bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, + ArrayRef<MCAsmMacroParameter> Parameters, + ArrayRef<MCAsmMacroArgument> A, const std::vector<std::string> &Locals, SMLoc L) { - unsigned NParameters = Parameters.size(); + unsigned NParameters = Parameters.size(); if (NParameters != A.size()) - return Error(L, "Wrong number of arguments"); + return Error(L, "Wrong number of arguments"); StringMap<std::string> LocalSymbols; std::string Name; Name.reserve(6); @@ -2736,25 +2736,25 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, LocalSymbols.insert({Local, LocalName.str()}); Name.clear(); } - + Optional<char> CurrentQuote; - while (!Body.empty()) { - // Scan for the next substitution. - std::size_t End = Body.size(), Pos = 0; + while (!Body.empty()) { + // Scan for the next substitution. + std::size_t End = Body.size(), Pos = 0; std::size_t IdentifierPos = End; - for (; Pos != End; ++Pos) { + for (; Pos != End; ++Pos) { // Find the next possible macro parameter, including preceding a '&' // inside quotes. if (Body[Pos] == '&') break; if (isMacroParameterChar(Body[Pos])) { if (!CurrentQuote.hasValue()) - break; + break; if (IdentifierPos == End) IdentifierPos = Pos; - } else { + } else { IdentifierPos = End; - } + } // Track quotation status if (!CurrentQuote.hasValue()) { @@ -2769,21 +2769,21 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, CurrentQuote.reset(); } } - } + } if (IdentifierPos != End) { // We've recognized an identifier before an apostrophe inside quotes; // check once to see if we can expand it. Pos = IdentifierPos; IdentifierPos = End; } - - // Add the prefix. - OS << Body.slice(0, Pos); - - // Check if we reached the end. - if (Pos == End) - break; - + + // Add the prefix. + OS << Body.slice(0, Pos); + + // Check if we reached the end. + if (Pos == End) + break; + unsigned I = Pos; bool InitialAmpersand = (Body[I] == '&'); if (InitialAmpersand) { @@ -2792,15 +2792,15 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, } while (I < End && isMacroParameterChar(Body[I])) ++I; - + const char *Begin = Body.data() + Pos; StringRef Argument(Begin, I - Pos); unsigned Index = 0; for (; Index < NParameters; ++Index) if (Parameters[Index].Name == Argument) - break; - + break; + if (Index == NParameters) { if (InitialAmpersand) OS << '&'; @@ -2823,69 +2823,69 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, // Emit an integer value to the buffer. OS << Token.getIntVal(); else - OS << Token.getString(); - } - + OS << Token.getString(); + } + Pos += Argument.size(); if (Pos < End && Body[Pos] == '&') { ++Pos; - } - } - // 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 - + } + } + // 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(const MCAsmMacroParameter *MP, MCAsmMacroArgument &MA, AsmToken::TokenKind EndTok) { @@ -2895,10 +2895,10 @@ bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP, for (StringRef S : Str) { MA.emplace_back(AsmToken::String, S); } - } - return false; - } - + } + return false; + } + SMLoc StrLoc = Lexer.getLoc(), EndLoc; if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) { const char *StrChar = StrLoc.getPointer() + 1; @@ -2910,63 +2910,63 @@ bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP, 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)) + 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"); - - if (ParenLevel == 0) { - if (Lexer.is(AsmToken::Comma)) - break; - - if (Lexer.is(AsmToken::Space)) { - SpaceEaten = true; + + if (ParenLevel == 0) { + if (Lexer.is(AsmToken::Comma)) + break; + + if (Lexer.is(AsmToken::Space)) { + SpaceEaten = true; 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) { + } + + // 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()) && Lexer.isNot(EndTok)) { - MA.push_back(getTok()); + MA.push_back(getTok()); Lex(); - - // Whitespace after an operator can be ignored. - if (Lexer.is(AsmToken::Space)) + + // Whitespace after an operator can be ignored. + if (Lexer.is(AsmToken::Space)) Lex(); - - continue; - } - } - if (SpaceEaten) - break; - } - - // handleMacroEntry relies on not advancing the lexer here - // to be able to fill in the remaining default parameter values + + 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(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0)) - 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()); + 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()); Lex(); - } - - if (ParenLevel != 0) + } + + if (ParenLevel != 0) return TokError("unbalanced parentheses in argument"); if (MA.empty() && MP) { @@ -2977,43 +2977,43 @@ bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP, MA = MP->Value; } } - return false; -} - -// Parse the macro instantiation arguments. -bool MasmParser::parseMacroArguments(const MCAsmMacro *M, + return false; +} + +// Parse the macro instantiation arguments. +bool MasmParser::parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A, AsmToken::TokenKind EndTok) { - 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 - 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; - } - - if (NamedParametersFound && FA.Name.empty()) - return Error(IDLoc, "cannot mix positional and keyword arguments"); - + 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 + 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; + } + + if (NamedParametersFound && FA.Name.empty()) + return Error(IDLoc, "cannot mix positional and keyword arguments"); + unsigned PI = Parameter; if (!FA.Name.empty()) { assert(M && "expected macro to be defined"); @@ -3032,133 +3032,133 @@ bool MasmParser::parseMacroArguments(const MCAsmMacro *M, if (M && PI < NParameters) MP = &M->Parameters[PI]; - SMLoc StrLoc = Lexer.getLoc(); - SMLoc EndLoc; + SMLoc StrLoc = Lexer.getLoc(); + SMLoc EndLoc; if (Lexer.is(AsmToken::Percent)) { - const MCExpr *AbsoluteExp; - int64_t Value; - /// Eat '%'. - Lex(); - if (parseExpression(AbsoluteExp, EndLoc)) - return false; - if (!AbsoluteExp->evaluateAsAbsolute(Value, - getStreamer().getAssemblerPtr())) - 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); + const MCExpr *AbsoluteExp; + int64_t Value; + /// Eat '%'. + Lex(); + if (parseExpression(AbsoluteExp, EndLoc)) + return false; + if (!AbsoluteExp->evaluateAsAbsolute(Value, + getStreamer().getAssemblerPtr())) + 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 (parseMacroArgument(MP, FA.Value, EndTok)) { if (M) return addErrorSuffix(" in '" + M->Name + "' macro"); else return true; - } - - 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 (!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(EndTok)) { - 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 " + 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"); -} - + 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, AsmToken::TokenKind ArgumentEndTok) { - // 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; + // 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, ArgumentEndTok)) - 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); - + 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, M->Locals, getTok().getLoc())) - return true; - + return true; + // We include the endm in the buffer as our cue to exit the macro - // instantiation. + // instantiation. OS << "endm\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()); + + 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()); EndStatementAtEOFStack.push_back(true); - Lex(); - - return false; -} - -void MasmParser::handleMacroExit() { + Lex(); + + return false; +} + +void MasmParser::handleMacroExit() { // Jump to the token we should return to, and consume it. EndStatementAtEOFStack.pop_back(); jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer, EndStatementAtEOFStack.back()); - Lex(); - - // Pop the instantiation entry. - delete ActiveMacros.back(); - ActiveMacros.pop_back(); -} - + Lex(); + + // Pop the instantiation entry. + delete ActiveMacros.back(); + ActiveMacros.pop_back(); +} + bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) { if (!M->IsFunction) return Error(NameLoc, "cannot invoke macro procedure as function"); @@ -3216,115 +3216,115 @@ bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) { return false; } -/// 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)) +/// 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 TokError("expected text item"); - 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"); + 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"); MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name); Sym->setRedefinable(Var.Redefinable); Sym->setVariableValue(Expr); Sym->setExternal(false); - 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 = ""; + 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 = ""; char Quote = getTok().getString().front(); - StringRef Str = getTok().getStringContents(); + StringRef Str = getTok().getStringContents(); Data.reserve(Str.size()); for (size_t i = 0, e = Str.size(); i != e; ++i) { Data.push_back(Str[i]); @@ -3335,31 +3335,31 @@ bool MasmParser::parseEscapedString(std::string &Data) { if (i + 1 == Str.size()) return Error(getTok().getLoc(), "missing quotation mark in string"); if (Str[i + 1] == Quote) - ++i; - } - } - - 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; + ++i; + } + } + + 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, EndStatementAtEOFStack.back()); - // Eat from '<' to '>'. - Lex(); - - Data = angleBracketString(StringRef(StartChar, EndChar - StartChar)); - return false; - } - return true; -} - -/// textItem ::= textLiteral | textMacroID | % constExpr -bool MasmParser::parseTextItem(std::string &Data) { + // Eat from '<' to '>'. + Lex(); + + Data = angleBracketString(StringRef(StartChar, EndChar - StartChar)); + return false; + } + return true; +} + +/// textItem ::= textLiteral | textMacroID | % constExpr +bool MasmParser::parseTextItem(std::string &Data) { switch (getTok().getKind()) { default: return true; @@ -3396,49 +3396,49 @@ bool MasmParser::parseTextItem(std::string &Data) { } } llvm_unreachable("unhandled token kind"); -} - -/// 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; -} - -bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) { - // 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(MCE->getLoc(), "out of range literal value"); - getStreamer().emitIntValue(IntValue, Size); - } else { - const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Value); - if (MSE && MSE->getSymbol().getName() == "?") { - // ? initializer; treat as 0. - getStreamer().emitIntValue(0, Size); - } else { - getStreamer().emitValue(Value, Size, Value->getLoc()); - } - } - return false; -} - -bool MasmParser::parseScalarInitializer(unsigned Size, - SmallVectorImpl<const MCExpr *> &Values, - unsigned StringPadLength) { +} + +/// 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; +} + +bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) { + // 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(MCE->getLoc(), "out of range literal value"); + getStreamer().emitIntValue(IntValue, Size); + } else { + const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Value); + if (MSE && MSE->getSymbol().getName() == "?") { + // ? initializer; treat as 0. + getStreamer().emitIntValue(0, Size); + } else { + getStreamer().emitValue(Value, Size, Value->getLoc()); + } + } + return false; +} + +bool MasmParser::parseScalarInitializer(unsigned Size, + SmallVectorImpl<const MCExpr *> &Values, + unsigned StringPadLength) { if (Size == 1 && getTok().is(AsmToken::String)) { std::string Value; if (parseEscapedString(Value)) @@ -3446,113 +3446,113 @@ bool MasmParser::parseScalarInitializer(unsigned Size, // Treat each character as an initializer. for (const unsigned char CharVal : Value) Values.push_back(MCConstantExpr::create(CharVal, getContext())); - + // Pad the string with spaces to the specified length. for (size_t i = Value.size(); i < StringPadLength; ++i) Values.push_back(MCConstantExpr::create(' ', getContext())); - } else { - const MCExpr *Value; + } else { + const MCExpr *Value; if (parseExpression(Value)) - return true; - if (getTok().is(AsmToken::Identifier) && - getTok().getString().equals_lower("dup")) { - Lex(); // Eat 'dup'. - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); - if (!MCE) - return Error(Value->getLoc(), - "cannot repeat value a non-constant number of times"); - const int64_t Repetitions = MCE->getValue(); - if (Repetitions < 0) - return Error(Value->getLoc(), - "cannot repeat value a negative number of times"); - - SmallVector<const MCExpr *, 1> DuplicatedValues; - if (parseToken(AsmToken::LParen, - "parentheses required for 'dup' contents") || - parseScalarInstList(Size, DuplicatedValues) || - parseToken(AsmToken::RParen, "unmatched parentheses")) - return true; - - for (int i = 0; i < Repetitions; ++i) - Values.append(DuplicatedValues.begin(), DuplicatedValues.end()); - } else { - Values.push_back(Value); - } - } - return false; -} - -bool MasmParser::parseScalarInstList(unsigned Size, - SmallVectorImpl<const MCExpr *> &Values, - const AsmToken::TokenKind EndToken) { - while (getTok().isNot(EndToken) && - (EndToken != AsmToken::Greater || - getTok().isNot(AsmToken::GreaterGreater))) { - parseScalarInitializer(Size, Values); - - // If we see a comma, continue, and allow line continuation. - if (!parseOptionalToken(AsmToken::Comma)) - break; - parseOptionalToken(AsmToken::EndOfStatement); - } - return false; -} - + return true; + if (getTok().is(AsmToken::Identifier) && + getTok().getString().equals_lower("dup")) { + Lex(); // Eat 'dup'. + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); + if (!MCE) + return Error(Value->getLoc(), + "cannot repeat value a non-constant number of times"); + const int64_t Repetitions = MCE->getValue(); + if (Repetitions < 0) + return Error(Value->getLoc(), + "cannot repeat value a negative number of times"); + + SmallVector<const MCExpr *, 1> DuplicatedValues; + if (parseToken(AsmToken::LParen, + "parentheses required for 'dup' contents") || + parseScalarInstList(Size, DuplicatedValues) || + parseToken(AsmToken::RParen, "unmatched parentheses")) + return true; + + for (int i = 0; i < Repetitions; ++i) + Values.append(DuplicatedValues.begin(), DuplicatedValues.end()); + } else { + Values.push_back(Value); + } + } + return false; +} + +bool MasmParser::parseScalarInstList(unsigned Size, + SmallVectorImpl<const MCExpr *> &Values, + const AsmToken::TokenKind EndToken) { + while (getTok().isNot(EndToken) && + (EndToken != AsmToken::Greater || + getTok().isNot(AsmToken::GreaterGreater))) { + parseScalarInitializer(Size, Values); + + // If we see a comma, continue, and allow line continuation. + if (!parseOptionalToken(AsmToken::Comma)) + break; + parseOptionalToken(AsmToken::EndOfStatement); + } + return false; +} + bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) { - SmallVector<const MCExpr *, 1> Values; - if (checkForValidSection() || parseScalarInstList(Size, Values)) - return true; - - for (auto Value : Values) { - emitIntValue(Value, Size); - } + SmallVector<const MCExpr *, 1> Values; + if (checkForValidSection() || parseScalarInstList(Size, Values)) + return true; + + for (auto Value : Values) { + emitIntValue(Value, Size); + } if (Count) *Count = Values.size(); - return false; -} - -// Add a field to the current structure. -bool MasmParser::addIntegralField(StringRef Name, unsigned Size) { - StructInfo &Struct = StructInProgress.back(); + return false; +} + +// Add a field to the current structure. +bool MasmParser::addIntegralField(StringRef Name, unsigned Size) { + StructInfo &Struct = StructInProgress.back(); FieldInfo &Field = Struct.addField(Name, FT_INTEGRAL, Size); - IntFieldInfo &IntInfo = Field.Contents.IntInfo; - - Field.Type = Size; - - if (parseScalarInstList(Size, IntInfo.Values)) - return true; - - Field.SizeOf = Field.Type * IntInfo.Values.size(); - Field.LengthOf = IntInfo.Values.size(); - if (Struct.IsUnion) - Struct.Size = std::max(Struct.Size, Field.SizeOf); - else - Struct.Size += Field.SizeOf; - return false; -} - -/// parseDirectiveValue -/// ::= (byte | word | ... ) [ expression (, expression)* ] -bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { - if (StructInProgress.empty()) { - // Initialize data value. - if (emitIntegralValues(Size)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - } else if (addIntegralField("", Size)) { - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - } - - return false; -} - -/// parseDirectiveNamedValue -/// ::= name (byte | word | ... ) [ expression (, expression)* ] + IntFieldInfo &IntInfo = Field.Contents.IntInfo; + + Field.Type = Size; + + if (parseScalarInstList(Size, IntInfo.Values)) + return true; + + Field.SizeOf = Field.Type * IntInfo.Values.size(); + Field.LengthOf = IntInfo.Values.size(); + if (Struct.IsUnion) + Struct.Size = std::max(Struct.Size, Field.SizeOf); + else + Struct.Size += Field.SizeOf; + return false; +} + +/// parseDirectiveValue +/// ::= (byte | word | ... ) [ expression (, expression)* ] +bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { + if (StructInProgress.empty()) { + // Initialize data value. + if (emitIntegralValues(Size)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + } else if (addIntegralField("", Size)) { + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + } + + return false; +} + +/// parseDirectiveNamedValue +/// ::= name (byte | word | ... ) [ expression (, expression)* ] bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size, - StringRef Name, SMLoc NameLoc) { - if (StructInProgress.empty()) { - // Initialize named data value. - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitLabel(Sym); + StringRef Name, SMLoc NameLoc) { + if (StructInProgress.empty()) { + // Initialize named data value. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitLabel(Sym); unsigned Count; if (emitIntegralValues(Size, &Count)) return addErrorSuffix(" in '" + Twine(TypeName) + "' directive"); @@ -3563,64 +3563,64 @@ bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size, Type.ElementSize = Size; Type.Length = Count; KnownType[Name.lower()] = Type; - } else if (addIntegralField(Name, Size)) { + } else if (addIntegralField(Name, Size)) { return addErrorSuffix(" in '" + Twine(TypeName) + "' 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; + } + + 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; SMLoc SignLoc; - if (getLexer().is(AsmToken::Minus)) { + if (getLexer().is(AsmToken::Minus)) { SignLoc = getLexer().getLoc(); - Lexer.Lex(); - IsNeg = true; - } else if (getLexer().is(AsmToken::Plus)) { + Lexer.Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) { SignLoc = getLexer().getLoc(); - 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.equals_lower("infinity") || IDVal.equals_lower("inf")) - Value = APFloat::getInf(Semantics); - else if (IDVal.equals_lower("nan")) - Value = APFloat::getNaN(Semantics, false, ~0); - else if (IDVal.equals_lower("?")) - Value = APFloat::getZero(Semantics); - else - return TokError("invalid floating point literal"); + 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.equals_lower("infinity") || IDVal.equals_lower("inf")) + Value = APFloat::getInf(Semantics); + else if (IDVal.equals_lower("nan")) + Value = APFloat::getNaN(Semantics, false, ~0); + else if (IDVal.equals_lower("?")) + Value = APFloat::getZero(Semantics); + else + return TokError("invalid floating point literal"); } else if (IDVal.consume_back("r") || IDVal.consume_back("R")) { // MASM hexadecimal floating-point literal; no APFloat conversion needed. // To match ML64.exe, ignore the initial sign. @@ -3635,133 +3635,133 @@ bool MasmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { if (SignLoc.isValid()) return Warning(SignLoc, "MASM-style hex floats ignore explicit sign"); return false; - } 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; -} - -bool MasmParser::parseRealInstList(const fltSemantics &Semantics, - SmallVectorImpl<APInt> &ValuesAsInt, - const AsmToken::TokenKind EndToken) { - while (getTok().isNot(EndToken) || - (EndToken == AsmToken::Greater && - getTok().isNot(AsmToken::GreaterGreater))) { - const AsmToken NextTok = Lexer.peekTok(); - if (NextTok.is(AsmToken::Identifier) && - NextTok.getString().equals_lower("dup")) { - const MCExpr *Value; - if (parseExpression(Value) || parseToken(AsmToken::Identifier)) - return true; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); - if (!MCE) - return Error(Value->getLoc(), - "cannot repeat value a non-constant number of times"); - const int64_t Repetitions = MCE->getValue(); - if (Repetitions < 0) - return Error(Value->getLoc(), - "cannot repeat value a negative number of times"); - - SmallVector<APInt, 1> DuplicatedValues; - if (parseToken(AsmToken::LParen, - "parentheses required for 'dup' contents") || - parseRealInstList(Semantics, DuplicatedValues) || - parseToken(AsmToken::RParen, "unmatched parentheses")) - return true; - - for (int i = 0; i < Repetitions; ++i) - ValuesAsInt.append(DuplicatedValues.begin(), DuplicatedValues.end()); - } else { - APInt AsInt; - if (parseRealValue(Semantics, AsInt)) - return true; - ValuesAsInt.push_back(AsInt); - } - - // Continue if we see a comma. (Also, allow line continuation.) - if (!parseOptionalToken(AsmToken::Comma)) - break; - parseOptionalToken(AsmToken::EndOfStatement); - } - - return false; -} - -// Initialize real data values. + } 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; +} + +bool MasmParser::parseRealInstList(const fltSemantics &Semantics, + SmallVectorImpl<APInt> &ValuesAsInt, + const AsmToken::TokenKind EndToken) { + while (getTok().isNot(EndToken) || + (EndToken == AsmToken::Greater && + getTok().isNot(AsmToken::GreaterGreater))) { + const AsmToken NextTok = Lexer.peekTok(); + if (NextTok.is(AsmToken::Identifier) && + NextTok.getString().equals_lower("dup")) { + const MCExpr *Value; + if (parseExpression(Value) || parseToken(AsmToken::Identifier)) + return true; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); + if (!MCE) + return Error(Value->getLoc(), + "cannot repeat value a non-constant number of times"); + const int64_t Repetitions = MCE->getValue(); + if (Repetitions < 0) + return Error(Value->getLoc(), + "cannot repeat value a negative number of times"); + + SmallVector<APInt, 1> DuplicatedValues; + if (parseToken(AsmToken::LParen, + "parentheses required for 'dup' contents") || + parseRealInstList(Semantics, DuplicatedValues) || + parseToken(AsmToken::RParen, "unmatched parentheses")) + return true; + + for (int i = 0; i < Repetitions; ++i) + ValuesAsInt.append(DuplicatedValues.begin(), DuplicatedValues.end()); + } else { + APInt AsInt; + if (parseRealValue(Semantics, AsInt)) + return true; + ValuesAsInt.push_back(AsInt); + } + + // Continue if we see a comma. (Also, allow line continuation.) + if (!parseOptionalToken(AsmToken::Comma)) + break; + parseOptionalToken(AsmToken::EndOfStatement); + } + + return false; +} + +// Initialize real data values. bool MasmParser::emitRealValues(const fltSemantics &Semantics, unsigned *Count) { if (checkForValidSection()) return true; - SmallVector<APInt, 1> ValuesAsInt; - if (parseRealInstList(Semantics, ValuesAsInt)) - return true; - - for (const APInt &AsInt : ValuesAsInt) { + SmallVector<APInt, 1> ValuesAsInt; + if (parseRealInstList(Semantics, ValuesAsInt)) + return true; + + for (const APInt &AsInt : ValuesAsInt) { getStreamer().emitIntValue(AsInt); - } + } if (Count) *Count = ValuesAsInt.size(); - return false; -} - -// Add a real field to the current struct. + return false; +} + +// Add a real field to the current struct. bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size) { - StructInfo &Struct = StructInProgress.back(); + StructInfo &Struct = StructInProgress.back(); FieldInfo &Field = Struct.addField(Name, FT_REAL, Size); - RealFieldInfo &RealInfo = Field.Contents.RealInfo; - - Field.SizeOf = 0; - + RealFieldInfo &RealInfo = Field.Contents.RealInfo; + + Field.SizeOf = 0; + if (parseRealInstList(Semantics, RealInfo.AsIntValues)) - return true; - - Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8; - Field.LengthOf = RealInfo.AsIntValues.size(); - Field.SizeOf = Field.Type * Field.LengthOf; - if (Struct.IsUnion) - Struct.Size = std::max(Struct.Size, Field.SizeOf); - else - Struct.Size += Field.SizeOf; - return false; -} - -/// parseDirectiveRealValue + return true; + + Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8; + Field.LengthOf = RealInfo.AsIntValues.size(); + Field.SizeOf = Field.Type * Field.LengthOf; + if (Struct.IsUnion) + Struct.Size = std::max(Struct.Size, Field.SizeOf); + else + Struct.Size += Field.SizeOf; + return false; +} + +/// parseDirectiveRealValue /// ::= (real4 | real8 | real10) [ expression (, expression)* ] -bool MasmParser::parseDirectiveRealValue(StringRef IDVal, +bool MasmParser::parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics, size_t Size) { - if (StructInProgress.empty()) { - // Initialize data value. - if (emitRealValues(Semantics)) - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + if (StructInProgress.empty()) { + // Initialize data value. + if (emitRealValues(Semantics)) + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); } else if (addRealField("", Semantics, Size)) { - return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); - } - return false; -} - -/// parseDirectiveNamedRealValue + return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + } + return false; +} + +/// parseDirectiveNamedRealValue /// ::= name (real4 | real8 | real10) [ expression (, expression)* ] bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName, - const fltSemantics &Semantics, + const fltSemantics &Semantics, unsigned Size, StringRef Name, SMLoc NameLoc) { - if (StructInProgress.empty()) { - // Initialize named data value. - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitLabel(Sym); + if (StructInProgress.empty()) { + // Initialize named data value. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitLabel(Sym); unsigned Count; if (emitRealValues(Semantics, &Count)) return addErrorSuffix(" in '" + TypeName + "' directive"); @@ -3774,79 +3774,79 @@ bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName, KnownType[Name.lower()] = Type; } else if (addRealField(Name, Semantics, Size)) { return addErrorSuffix(" in '" + TypeName + "' directive"); - } - return false; -} - -bool MasmParser::parseOptionalAngleBracketOpen() { - const AsmToken Tok = getTok(); - if (parseOptionalToken(AsmToken::LessLess)) { - AngleBracketDepth++; - Lexer.UnLex(AsmToken(AsmToken::Less, Tok.getString().substr(1))); - return true; - } else if (parseOptionalToken(AsmToken::LessGreater)) { - AngleBracketDepth++; - Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1))); - return true; - } else if (parseOptionalToken(AsmToken::Less)) { - AngleBracketDepth++; - return true; - } - - return false; -} - -bool MasmParser::parseAngleBracketClose(const Twine &Msg) { - const AsmToken Tok = getTok(); - if (parseOptionalToken(AsmToken::GreaterGreater)) { - Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1))); - } else if (parseToken(AsmToken::Greater, Msg)) { - return true; - } - AngleBracketDepth--; - return false; -} - -bool MasmParser::parseFieldInitializer(const FieldInfo &Field, - const IntFieldInfo &Contents, - FieldInitializer &Initializer) { - SMLoc Loc = getTok().getLoc(); - - SmallVector<const MCExpr *, 1> Values; - if (parseOptionalToken(AsmToken::LCurly)) { - if (Field.LengthOf == 1 && Field.Type > 1) - return Error(Loc, "Cannot initialize scalar field with array value"); - if (parseScalarInstList(Field.Type, Values, AsmToken::RCurly) || - parseToken(AsmToken::RCurly)) - return true; - } else if (parseOptionalAngleBracketOpen()) { - if (Field.LengthOf == 1 && Field.Type > 1) - return Error(Loc, "Cannot initialize scalar field with array value"); - if (parseScalarInstList(Field.Type, Values, AsmToken::Greater) || - parseAngleBracketClose()) - return true; - } else if (Field.LengthOf > 1 && Field.Type > 1) { - return Error(Loc, "Cannot initialize array field with scalar value"); - } else if (parseScalarInitializer(Field.Type, Values, - /*StringPadLength=*/Field.LengthOf)) { - return true; - } - - if (Values.size() > Field.LengthOf) { - return Error(Loc, "Initializer too long for field; expected at most " + - std::to_string(Field.LengthOf) + " elements, got " + - std::to_string(Values.size())); - } - // Default-initialize all remaining values. - Values.append(Contents.Values.begin() + Values.size(), Contents.Values.end()); - - Initializer = FieldInitializer(std::move(Values)); - return false; -} - -bool MasmParser::parseFieldInitializer(const FieldInfo &Field, - const RealFieldInfo &Contents, - FieldInitializer &Initializer) { + } + return false; +} + +bool MasmParser::parseOptionalAngleBracketOpen() { + const AsmToken Tok = getTok(); + if (parseOptionalToken(AsmToken::LessLess)) { + AngleBracketDepth++; + Lexer.UnLex(AsmToken(AsmToken::Less, Tok.getString().substr(1))); + return true; + } else if (parseOptionalToken(AsmToken::LessGreater)) { + AngleBracketDepth++; + Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1))); + return true; + } else if (parseOptionalToken(AsmToken::Less)) { + AngleBracketDepth++; + return true; + } + + return false; +} + +bool MasmParser::parseAngleBracketClose(const Twine &Msg) { + const AsmToken Tok = getTok(); + if (parseOptionalToken(AsmToken::GreaterGreater)) { + Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1))); + } else if (parseToken(AsmToken::Greater, Msg)) { + return true; + } + AngleBracketDepth--; + return false; +} + +bool MasmParser::parseFieldInitializer(const FieldInfo &Field, + const IntFieldInfo &Contents, + FieldInitializer &Initializer) { + SMLoc Loc = getTok().getLoc(); + + SmallVector<const MCExpr *, 1> Values; + if (parseOptionalToken(AsmToken::LCurly)) { + if (Field.LengthOf == 1 && Field.Type > 1) + return Error(Loc, "Cannot initialize scalar field with array value"); + if (parseScalarInstList(Field.Type, Values, AsmToken::RCurly) || + parseToken(AsmToken::RCurly)) + return true; + } else if (parseOptionalAngleBracketOpen()) { + if (Field.LengthOf == 1 && Field.Type > 1) + return Error(Loc, "Cannot initialize scalar field with array value"); + if (parseScalarInstList(Field.Type, Values, AsmToken::Greater) || + parseAngleBracketClose()) + return true; + } else if (Field.LengthOf > 1 && Field.Type > 1) { + return Error(Loc, "Cannot initialize array field with scalar value"); + } else if (parseScalarInitializer(Field.Type, Values, + /*StringPadLength=*/Field.LengthOf)) { + return true; + } + + if (Values.size() > Field.LengthOf) { + return Error(Loc, "Initializer too long for field; expected at most " + + std::to_string(Field.LengthOf) + " elements, got " + + std::to_string(Values.size())); + } + // Default-initialize all remaining values. + Values.append(Contents.Values.begin() + Values.size(), Contents.Values.end()); + + Initializer = FieldInitializer(std::move(Values)); + return false; +} + +bool MasmParser::parseFieldInitializer(const FieldInfo &Field, + const RealFieldInfo &Contents, + FieldInitializer &Initializer) { const fltSemantics *Semantics; switch (Field.Type) { case 4: @@ -3861,1665 +3861,1665 @@ bool MasmParser::parseFieldInitializer(const FieldInfo &Field, default: llvm_unreachable("unknown real field type"); } - - SMLoc Loc = getTok().getLoc(); - - SmallVector<APInt, 1> AsIntValues; - if (parseOptionalToken(AsmToken::LCurly)) { - if (Field.LengthOf == 1) - return Error(Loc, "Cannot initialize scalar field with array value"); + + SMLoc Loc = getTok().getLoc(); + + SmallVector<APInt, 1> AsIntValues; + if (parseOptionalToken(AsmToken::LCurly)) { + if (Field.LengthOf == 1) + return Error(Loc, "Cannot initialize scalar field with array value"); if (parseRealInstList(*Semantics, AsIntValues, AsmToken::RCurly) || - parseToken(AsmToken::RCurly)) - return true; - } else if (parseOptionalAngleBracketOpen()) { - if (Field.LengthOf == 1) - return Error(Loc, "Cannot initialize scalar field with array value"); + parseToken(AsmToken::RCurly)) + return true; + } else if (parseOptionalAngleBracketOpen()) { + if (Field.LengthOf == 1) + return Error(Loc, "Cannot initialize scalar field with array value"); if (parseRealInstList(*Semantics, AsIntValues, AsmToken::Greater) || - parseAngleBracketClose()) - return true; - } else if (Field.LengthOf > 1) { - return Error(Loc, "Cannot initialize array field with scalar value"); - } else { - AsIntValues.emplace_back(); + parseAngleBracketClose()) + return true; + } else if (Field.LengthOf > 1) { + return Error(Loc, "Cannot initialize array field with scalar value"); + } else { + AsIntValues.emplace_back(); if (parseRealValue(*Semantics, AsIntValues.back())) - return true; - } - - if (AsIntValues.size() > Field.LengthOf) { - return Error(Loc, "Initializer too long for field; expected at most " + - std::to_string(Field.LengthOf) + " elements, got " + - std::to_string(AsIntValues.size())); - } - // Default-initialize all remaining values. - AsIntValues.append(Contents.AsIntValues.begin() + AsIntValues.size(), - Contents.AsIntValues.end()); - - Initializer = FieldInitializer(std::move(AsIntValues)); - return false; -} - -bool MasmParser::parseFieldInitializer(const FieldInfo &Field, - const StructFieldInfo &Contents, - FieldInitializer &Initializer) { - SMLoc Loc = getTok().getLoc(); - - std::vector<StructInitializer> Initializers; - if (Field.LengthOf > 1) { - if (parseOptionalToken(AsmToken::LCurly)) { - if (parseStructInstList(Contents.Structure, Initializers, - AsmToken::RCurly) || - parseToken(AsmToken::RCurly)) - return true; - } else if (parseOptionalAngleBracketOpen()) { - if (parseStructInstList(Contents.Structure, Initializers, - AsmToken::Greater) || - parseAngleBracketClose()) - return true; - } else { - return Error(Loc, "Cannot initialize array field with scalar value"); - } - } else { - Initializers.emplace_back(); - if (parseStructInitializer(Contents.Structure, Initializers.back())) - return true; - } - - if (Initializers.size() > Field.LengthOf) { - return Error(Loc, "Initializer too long for field; expected at most " + - std::to_string(Field.LengthOf) + " elements, got " + - std::to_string(Initializers.size())); - } - // Default-initialize all remaining values. - Initializers.insert(Initializers.end(), - Contents.Initializers.begin() + Initializers.size(), - Contents.Initializers.end()); - - Initializer = FieldInitializer(std::move(Initializers), Contents.Structure); - return false; -} - -bool MasmParser::parseFieldInitializer(const FieldInfo &Field, - FieldInitializer &Initializer) { - switch (Field.Contents.FT) { - case FT_INTEGRAL: - return parseFieldInitializer(Field, Field.Contents.IntInfo, Initializer); - case FT_REAL: - return parseFieldInitializer(Field, Field.Contents.RealInfo, Initializer); - case FT_STRUCT: - return parseFieldInitializer(Field, Field.Contents.StructInfo, Initializer); - } - llvm_unreachable("Unhandled FieldType enum"); -} - -bool MasmParser::parseStructInitializer(const StructInfo &Structure, - StructInitializer &Initializer) { - const AsmToken FirstToken = getTok(); - - Optional<AsmToken::TokenKind> EndToken; - if (parseOptionalToken(AsmToken::LCurly)) { - EndToken = AsmToken::RCurly; - } else if (parseOptionalAngleBracketOpen()) { - EndToken = AsmToken::Greater; - AngleBracketDepth++; - } else if (FirstToken.is(AsmToken::Identifier) && - FirstToken.getString() == "?") { - // ? initializer; leave EndToken uninitialized to treat as empty. - if (parseToken(AsmToken::Identifier)) - return true; - } else { - return Error(FirstToken.getLoc(), "Expected struct initializer"); - } - - auto &FieldInitializers = Initializer.FieldInitializers; - size_t FieldIndex = 0; - if (EndToken.hasValue()) { - // Initialize all fields with given initializers. - while (getTok().isNot(EndToken.getValue()) && - FieldIndex < Structure.Fields.size()) { - const FieldInfo &Field = Structure.Fields[FieldIndex++]; - if (parseOptionalToken(AsmToken::Comma)) { - // Empty initializer; use the default and continue. (Also, allow line - // continuation.) - FieldInitializers.push_back(Field.Contents); - parseOptionalToken(AsmToken::EndOfStatement); - continue; - } - FieldInitializers.emplace_back(Field.Contents.FT); - if (parseFieldInitializer(Field, FieldInitializers.back())) - return true; - - // Continue if we see a comma. (Also, allow line continuation.) - SMLoc CommaLoc = getTok().getLoc(); - if (!parseOptionalToken(AsmToken::Comma)) - break; - if (FieldIndex == Structure.Fields.size()) - return Error(CommaLoc, "'" + Structure.Name + - "' initializer initializes too many fields"); - parseOptionalToken(AsmToken::EndOfStatement); - } - } - // Default-initialize all remaining fields. - for (auto It = Structure.Fields.begin() + FieldIndex; - It != Structure.Fields.end(); ++It) { - const FieldInfo &Field = *It; - FieldInitializers.push_back(Field.Contents); - } - - if (EndToken.hasValue()) { - if (EndToken.getValue() == AsmToken::Greater) - return parseAngleBracketClose(); - - return parseToken(EndToken.getValue()); - } - - return false; -} - -bool MasmParser::parseStructInstList( - const StructInfo &Structure, std::vector<StructInitializer> &Initializers, - const AsmToken::TokenKind EndToken) { - while (getTok().isNot(EndToken) || - (EndToken == AsmToken::Greater && - getTok().isNot(AsmToken::GreaterGreater))) { - const AsmToken NextTok = Lexer.peekTok(); - if (NextTok.is(AsmToken::Identifier) && - NextTok.getString().equals_lower("dup")) { - const MCExpr *Value; - if (parseExpression(Value) || parseToken(AsmToken::Identifier)) - return true; - const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); - if (!MCE) - return Error(Value->getLoc(), - "cannot repeat value a non-constant number of times"); - const int64_t Repetitions = MCE->getValue(); - if (Repetitions < 0) - return Error(Value->getLoc(), - "cannot repeat value a negative number of times"); - - std::vector<StructInitializer> DuplicatedValues; - if (parseToken(AsmToken::LParen, - "parentheses required for 'dup' contents") || - parseStructInstList(Structure, DuplicatedValues) || - parseToken(AsmToken::RParen, "unmatched parentheses")) - return true; - - for (int i = 0; i < Repetitions; ++i) + return true; + } + + if (AsIntValues.size() > Field.LengthOf) { + return Error(Loc, "Initializer too long for field; expected at most " + + std::to_string(Field.LengthOf) + " elements, got " + + std::to_string(AsIntValues.size())); + } + // Default-initialize all remaining values. + AsIntValues.append(Contents.AsIntValues.begin() + AsIntValues.size(), + Contents.AsIntValues.end()); + + Initializer = FieldInitializer(std::move(AsIntValues)); + return false; +} + +bool MasmParser::parseFieldInitializer(const FieldInfo &Field, + const StructFieldInfo &Contents, + FieldInitializer &Initializer) { + SMLoc Loc = getTok().getLoc(); + + std::vector<StructInitializer> Initializers; + if (Field.LengthOf > 1) { + if (parseOptionalToken(AsmToken::LCurly)) { + if (parseStructInstList(Contents.Structure, Initializers, + AsmToken::RCurly) || + parseToken(AsmToken::RCurly)) + return true; + } else if (parseOptionalAngleBracketOpen()) { + if (parseStructInstList(Contents.Structure, Initializers, + AsmToken::Greater) || + parseAngleBracketClose()) + return true; + } else { + return Error(Loc, "Cannot initialize array field with scalar value"); + } + } else { + Initializers.emplace_back(); + if (parseStructInitializer(Contents.Structure, Initializers.back())) + return true; + } + + if (Initializers.size() > Field.LengthOf) { + return Error(Loc, "Initializer too long for field; expected at most " + + std::to_string(Field.LengthOf) + " elements, got " + + std::to_string(Initializers.size())); + } + // Default-initialize all remaining values. + Initializers.insert(Initializers.end(), + Contents.Initializers.begin() + Initializers.size(), + Contents.Initializers.end()); + + Initializer = FieldInitializer(std::move(Initializers), Contents.Structure); + return false; +} + +bool MasmParser::parseFieldInitializer(const FieldInfo &Field, + FieldInitializer &Initializer) { + switch (Field.Contents.FT) { + case FT_INTEGRAL: + return parseFieldInitializer(Field, Field.Contents.IntInfo, Initializer); + case FT_REAL: + return parseFieldInitializer(Field, Field.Contents.RealInfo, Initializer); + case FT_STRUCT: + return parseFieldInitializer(Field, Field.Contents.StructInfo, Initializer); + } + llvm_unreachable("Unhandled FieldType enum"); +} + +bool MasmParser::parseStructInitializer(const StructInfo &Structure, + StructInitializer &Initializer) { + const AsmToken FirstToken = getTok(); + + Optional<AsmToken::TokenKind> EndToken; + if (parseOptionalToken(AsmToken::LCurly)) { + EndToken = AsmToken::RCurly; + } else if (parseOptionalAngleBracketOpen()) { + EndToken = AsmToken::Greater; + AngleBracketDepth++; + } else if (FirstToken.is(AsmToken::Identifier) && + FirstToken.getString() == "?") { + // ? initializer; leave EndToken uninitialized to treat as empty. + if (parseToken(AsmToken::Identifier)) + return true; + } else { + return Error(FirstToken.getLoc(), "Expected struct initializer"); + } + + auto &FieldInitializers = Initializer.FieldInitializers; + size_t FieldIndex = 0; + if (EndToken.hasValue()) { + // Initialize all fields with given initializers. + while (getTok().isNot(EndToken.getValue()) && + FieldIndex < Structure.Fields.size()) { + const FieldInfo &Field = Structure.Fields[FieldIndex++]; + if (parseOptionalToken(AsmToken::Comma)) { + // Empty initializer; use the default and continue. (Also, allow line + // continuation.) + FieldInitializers.push_back(Field.Contents); + parseOptionalToken(AsmToken::EndOfStatement); + continue; + } + FieldInitializers.emplace_back(Field.Contents.FT); + if (parseFieldInitializer(Field, FieldInitializers.back())) + return true; + + // Continue if we see a comma. (Also, allow line continuation.) + SMLoc CommaLoc = getTok().getLoc(); + if (!parseOptionalToken(AsmToken::Comma)) + break; + if (FieldIndex == Structure.Fields.size()) + return Error(CommaLoc, "'" + Structure.Name + + "' initializer initializes too many fields"); + parseOptionalToken(AsmToken::EndOfStatement); + } + } + // Default-initialize all remaining fields. + for (auto It = Structure.Fields.begin() + FieldIndex; + It != Structure.Fields.end(); ++It) { + const FieldInfo &Field = *It; + FieldInitializers.push_back(Field.Contents); + } + + if (EndToken.hasValue()) { + if (EndToken.getValue() == AsmToken::Greater) + return parseAngleBracketClose(); + + return parseToken(EndToken.getValue()); + } + + return false; +} + +bool MasmParser::parseStructInstList( + const StructInfo &Structure, std::vector<StructInitializer> &Initializers, + const AsmToken::TokenKind EndToken) { + while (getTok().isNot(EndToken) || + (EndToken == AsmToken::Greater && + getTok().isNot(AsmToken::GreaterGreater))) { + const AsmToken NextTok = Lexer.peekTok(); + if (NextTok.is(AsmToken::Identifier) && + NextTok.getString().equals_lower("dup")) { + const MCExpr *Value; + if (parseExpression(Value) || parseToken(AsmToken::Identifier)) + return true; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value); + if (!MCE) + return Error(Value->getLoc(), + "cannot repeat value a non-constant number of times"); + const int64_t Repetitions = MCE->getValue(); + if (Repetitions < 0) + return Error(Value->getLoc(), + "cannot repeat value a negative number of times"); + + std::vector<StructInitializer> DuplicatedValues; + if (parseToken(AsmToken::LParen, + "parentheses required for 'dup' contents") || + parseStructInstList(Structure, DuplicatedValues) || + parseToken(AsmToken::RParen, "unmatched parentheses")) + return true; + + for (int i = 0; i < Repetitions; ++i) llvm::append_range(Initializers, DuplicatedValues); - } else { - Initializers.emplace_back(); - if (parseStructInitializer(Structure, Initializers.back())) - return true; - } - - // Continue if we see a comma. (Also, allow line continuation.) - if (!parseOptionalToken(AsmToken::Comma)) - break; - parseOptionalToken(AsmToken::EndOfStatement); - } - - return false; -} - -bool MasmParser::emitFieldValue(const FieldInfo &Field, - const IntFieldInfo &Contents) { - // Default-initialize all values. - for (const MCExpr *Value : Contents.Values) { - if (emitIntValue(Value, Field.Type)) - return true; - } - return false; -} - -bool MasmParser::emitFieldValue(const FieldInfo &Field, - const RealFieldInfo &Contents) { - for (const APInt &AsInt : Contents.AsIntValues) { - getStreamer().emitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - } - return false; -} - -bool MasmParser::emitFieldValue(const FieldInfo &Field, - const StructFieldInfo &Contents) { - for (const auto &Initializer : Contents.Initializers) { - size_t Index = 0, Offset = 0; - for (const auto &SubField : Contents.Structure.Fields) { - getStreamer().emitZeros(SubField.Offset - Offset); - Offset = SubField.Offset + SubField.SizeOf; - emitFieldInitializer(SubField, Initializer.FieldInitializers[Index++]); - } - } - return false; -} - -bool MasmParser::emitFieldValue(const FieldInfo &Field) { - switch (Field.Contents.FT) { - case FT_INTEGRAL: - return emitFieldValue(Field, Field.Contents.IntInfo); - case FT_REAL: - return emitFieldValue(Field, Field.Contents.RealInfo); - case FT_STRUCT: - return emitFieldValue(Field, Field.Contents.StructInfo); - } - llvm_unreachable("Unhandled FieldType enum"); -} - -bool MasmParser::emitFieldInitializer(const FieldInfo &Field, - const IntFieldInfo &Contents, - const IntFieldInfo &Initializer) { - for (const auto &Value : Initializer.Values) { - if (emitIntValue(Value, Field.Type)) - return true; - } - // Default-initialize all remaining values. - for (auto it = Contents.Values.begin() + Initializer.Values.size(); - it != Contents.Values.end(); ++it) { - const auto &Value = *it; - if (emitIntValue(Value, Field.Type)) - return true; - } - return false; -} - -bool MasmParser::emitFieldInitializer(const FieldInfo &Field, - const RealFieldInfo &Contents, - const RealFieldInfo &Initializer) { - for (const auto &AsInt : Initializer.AsIntValues) { - getStreamer().emitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - } - // Default-initialize all remaining values. - for (auto It = Contents.AsIntValues.begin() + Initializer.AsIntValues.size(); - It != Contents.AsIntValues.end(); ++It) { - const auto &AsInt = *It; - getStreamer().emitIntValue(AsInt.getLimitedValue(), - AsInt.getBitWidth() / 8); - } - return false; -} - -bool MasmParser::emitFieldInitializer(const FieldInfo &Field, - const StructFieldInfo &Contents, - const StructFieldInfo &Initializer) { - for (const auto &Init : Initializer.Initializers) { - emitStructInitializer(Contents.Structure, Init); - } - // Default-initialize all remaining values. - for (auto It = - Contents.Initializers.begin() + Initializer.Initializers.size(); - It != Contents.Initializers.end(); ++It) { - const auto &Init = *It; - emitStructInitializer(Contents.Structure, Init); - } - return false; -} - -bool MasmParser::emitFieldInitializer(const FieldInfo &Field, - const FieldInitializer &Initializer) { - switch (Field.Contents.FT) { - case FT_INTEGRAL: - return emitFieldInitializer(Field, Field.Contents.IntInfo, - Initializer.IntInfo); - case FT_REAL: - return emitFieldInitializer(Field, Field.Contents.RealInfo, - Initializer.RealInfo); - case FT_STRUCT: - return emitFieldInitializer(Field, Field.Contents.StructInfo, - Initializer.StructInfo); - } - llvm_unreachable("Unhandled FieldType enum"); -} - -bool MasmParser::emitStructInitializer(const StructInfo &Structure, - const StructInitializer &Initializer) { - size_t Index = 0, Offset = 0; - for (const auto &Init : Initializer.FieldInitializers) { - const auto &Field = Structure.Fields[Index++]; - getStreamer().emitZeros(Field.Offset - Offset); - Offset = Field.Offset + Field.SizeOf; - if (emitFieldInitializer(Field, Init)) - return true; - } - // Default-initialize all remaining fields. - for (auto It = - Structure.Fields.begin() + Initializer.FieldInitializers.size(); - It != Structure.Fields.end(); ++It) { - const auto &Field = *It; - getStreamer().emitZeros(Field.Offset - Offset); - Offset = Field.Offset + Field.SizeOf; - if (emitFieldValue(Field)) - return true; - } - // Add final padding. - if (Offset != Structure.Size) - getStreamer().emitZeros(Structure.Size - Offset); - return false; -} - -// Set data values from initializers. + } else { + Initializers.emplace_back(); + if (parseStructInitializer(Structure, Initializers.back())) + return true; + } + + // Continue if we see a comma. (Also, allow line continuation.) + if (!parseOptionalToken(AsmToken::Comma)) + break; + parseOptionalToken(AsmToken::EndOfStatement); + } + + return false; +} + +bool MasmParser::emitFieldValue(const FieldInfo &Field, + const IntFieldInfo &Contents) { + // Default-initialize all values. + for (const MCExpr *Value : Contents.Values) { + if (emitIntValue(Value, Field.Type)) + return true; + } + return false; +} + +bool MasmParser::emitFieldValue(const FieldInfo &Field, + const RealFieldInfo &Contents) { + for (const APInt &AsInt : Contents.AsIntValues) { + getStreamer().emitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + } + return false; +} + +bool MasmParser::emitFieldValue(const FieldInfo &Field, + const StructFieldInfo &Contents) { + for (const auto &Initializer : Contents.Initializers) { + size_t Index = 0, Offset = 0; + for (const auto &SubField : Contents.Structure.Fields) { + getStreamer().emitZeros(SubField.Offset - Offset); + Offset = SubField.Offset + SubField.SizeOf; + emitFieldInitializer(SubField, Initializer.FieldInitializers[Index++]); + } + } + return false; +} + +bool MasmParser::emitFieldValue(const FieldInfo &Field) { + switch (Field.Contents.FT) { + case FT_INTEGRAL: + return emitFieldValue(Field, Field.Contents.IntInfo); + case FT_REAL: + return emitFieldValue(Field, Field.Contents.RealInfo); + case FT_STRUCT: + return emitFieldValue(Field, Field.Contents.StructInfo); + } + llvm_unreachable("Unhandled FieldType enum"); +} + +bool MasmParser::emitFieldInitializer(const FieldInfo &Field, + const IntFieldInfo &Contents, + const IntFieldInfo &Initializer) { + for (const auto &Value : Initializer.Values) { + if (emitIntValue(Value, Field.Type)) + return true; + } + // Default-initialize all remaining values. + for (auto it = Contents.Values.begin() + Initializer.Values.size(); + it != Contents.Values.end(); ++it) { + const auto &Value = *it; + if (emitIntValue(Value, Field.Type)) + return true; + } + return false; +} + +bool MasmParser::emitFieldInitializer(const FieldInfo &Field, + const RealFieldInfo &Contents, + const RealFieldInfo &Initializer) { + for (const auto &AsInt : Initializer.AsIntValues) { + getStreamer().emitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + } + // Default-initialize all remaining values. + for (auto It = Contents.AsIntValues.begin() + Initializer.AsIntValues.size(); + It != Contents.AsIntValues.end(); ++It) { + const auto &AsInt = *It; + getStreamer().emitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + } + return false; +} + +bool MasmParser::emitFieldInitializer(const FieldInfo &Field, + const StructFieldInfo &Contents, + const StructFieldInfo &Initializer) { + for (const auto &Init : Initializer.Initializers) { + emitStructInitializer(Contents.Structure, Init); + } + // Default-initialize all remaining values. + for (auto It = + Contents.Initializers.begin() + Initializer.Initializers.size(); + It != Contents.Initializers.end(); ++It) { + const auto &Init = *It; + emitStructInitializer(Contents.Structure, Init); + } + return false; +} + +bool MasmParser::emitFieldInitializer(const FieldInfo &Field, + const FieldInitializer &Initializer) { + switch (Field.Contents.FT) { + case FT_INTEGRAL: + return emitFieldInitializer(Field, Field.Contents.IntInfo, + Initializer.IntInfo); + case FT_REAL: + return emitFieldInitializer(Field, Field.Contents.RealInfo, + Initializer.RealInfo); + case FT_STRUCT: + return emitFieldInitializer(Field, Field.Contents.StructInfo, + Initializer.StructInfo); + } + llvm_unreachable("Unhandled FieldType enum"); +} + +bool MasmParser::emitStructInitializer(const StructInfo &Structure, + const StructInitializer &Initializer) { + size_t Index = 0, Offset = 0; + for (const auto &Init : Initializer.FieldInitializers) { + const auto &Field = Structure.Fields[Index++]; + getStreamer().emitZeros(Field.Offset - Offset); + Offset = Field.Offset + Field.SizeOf; + if (emitFieldInitializer(Field, Init)) + return true; + } + // Default-initialize all remaining fields. + for (auto It = + Structure.Fields.begin() + Initializer.FieldInitializers.size(); + It != Structure.Fields.end(); ++It) { + const auto &Field = *It; + getStreamer().emitZeros(Field.Offset - Offset); + Offset = Field.Offset + Field.SizeOf; + if (emitFieldValue(Field)) + return true; + } + // Add final padding. + if (Offset != Structure.Size) + getStreamer().emitZeros(Structure.Size - Offset); + return false; +} + +// Set data values from initializers. bool MasmParser::emitStructValues(const StructInfo &Structure, unsigned *Count) { - std::vector<StructInitializer> Initializers; - if (parseStructInstList(Structure, Initializers)) - return true; - - for (const auto &Initializer : Initializers) { - if (emitStructInitializer(Structure, Initializer)) - return true; - } - + std::vector<StructInitializer> Initializers; + if (parseStructInstList(Structure, Initializers)) + return true; + + for (const auto &Initializer : Initializers) { + if (emitStructInitializer(Structure, Initializer)) + return true; + } + if (Count) *Count = Initializers.size(); - return false; -} - -// Declare a field in the current struct. -bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) { - StructInfo &OwningStruct = StructInProgress.back(); + return false; +} + +// Declare a field in the current struct. +bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) { + StructInfo &OwningStruct = StructInProgress.back(); FieldInfo &Field = OwningStruct.addField(Name, FT_STRUCT, Structure.AlignmentSize); - StructFieldInfo &StructInfo = Field.Contents.StructInfo; - - StructInfo.Structure = Structure; - Field.Type = Structure.Size; - - if (parseStructInstList(Structure, StructInfo.Initializers)) - return true; - - Field.LengthOf = StructInfo.Initializers.size(); - Field.SizeOf = Field.Type * Field.LengthOf; - if (OwningStruct.IsUnion) - OwningStruct.Size = std::max(OwningStruct.Size, Field.SizeOf); - else - OwningStruct.Size += Field.SizeOf; - - return false; -} - -/// parseDirectiveStructValue -/// ::= struct-id (<struct-initializer> | {struct-initializer}) -/// [, (<struct-initializer> | {struct-initializer})]* -bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure, - StringRef Directive, SMLoc DirLoc) { - if (StructInProgress.empty()) { - if (emitStructValues(Structure)) - return true; - } else if (addStructField("", Structure)) { - return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); - } - - return false; -} - -/// parseDirectiveNamedValue -/// ::= name (byte | word | ... ) [ expression (, expression)* ] -bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure, - StringRef Directive, - SMLoc DirLoc, StringRef Name) { - if (StructInProgress.empty()) { - // Initialize named data value. - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitLabel(Sym); + StructFieldInfo &StructInfo = Field.Contents.StructInfo; + + StructInfo.Structure = Structure; + Field.Type = Structure.Size; + + if (parseStructInstList(Structure, StructInfo.Initializers)) + return true; + + Field.LengthOf = StructInfo.Initializers.size(); + Field.SizeOf = Field.Type * Field.LengthOf; + if (OwningStruct.IsUnion) + OwningStruct.Size = std::max(OwningStruct.Size, Field.SizeOf); + else + OwningStruct.Size += Field.SizeOf; + + return false; +} + +/// parseDirectiveStructValue +/// ::= struct-id (<struct-initializer> | {struct-initializer}) +/// [, (<struct-initializer> | {struct-initializer})]* +bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure, + StringRef Directive, SMLoc DirLoc) { + if (StructInProgress.empty()) { + if (emitStructValues(Structure)) + return true; + } else if (addStructField("", Structure)) { + return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); + } + + return false; +} + +/// parseDirectiveNamedValue +/// ::= name (byte | word | ... ) [ expression (, expression)* ] +bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure, + StringRef Directive, + SMLoc DirLoc, StringRef Name) { + if (StructInProgress.empty()) { + // Initialize named data value. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitLabel(Sym); unsigned Count; if (emitStructValues(Structure, &Count)) - return true; + return true; AsmTypeInfo Type; Type.Name = Structure.Name; Type.Size = Structure.Size * Count; Type.ElementSize = Structure.Size; Type.Length = Count; KnownType[Name.lower()] = Type; - } else if (addStructField(Name, Structure)) { - return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); - } - - return false; -} - -/// parseDirectiveStruct -/// ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE] -/// (dataDir | generalDir | offsetDir | nestedStruct)+ -/// <name> ENDS -////// dataDir = data declaration -////// offsetDir = EVEN, ORG, ALIGN -bool MasmParser::parseDirectiveStruct(StringRef Directive, - DirectiveKind DirKind, StringRef Name, - SMLoc NameLoc) { - // We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS - // anyway, so all field accesses must be qualified. - AsmToken NextTok = getTok(); - int64_t AlignmentValue = 1; - if (NextTok.isNot(AsmToken::Comma) && - NextTok.isNot(AsmToken::EndOfStatement) && - parseAbsoluteExpression(AlignmentValue)) { - return addErrorSuffix(" in alignment value for '" + Twine(Directive) + - "' directive"); - } - if (!isPowerOf2_64(AlignmentValue)) { - return Error(NextTok.getLoc(), "alignment must be a power of two; was " + - std::to_string(AlignmentValue)); - } - - StringRef Qualifier; - SMLoc QualifierLoc; - if (parseOptionalToken(AsmToken::Comma)) { - QualifierLoc = getTok().getLoc(); - if (parseIdentifier(Qualifier)) - return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); - if (!Qualifier.equals_lower("nonunique")) - return Error(QualifierLoc, "Unrecognized qualifier for '" + - Twine(Directive) + - "' directive; expected none or NONUNIQUE"); - } - - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); - - StructInProgress.emplace_back(Name, DirKind == DK_UNION, AlignmentValue); - return false; -} - -/// parseDirectiveNestedStruct -/// ::= (STRUC | STRUCT | UNION) [name] -/// (dataDir | generalDir | offsetDir | nestedStruct)+ -/// ENDS -bool MasmParser::parseDirectiveNestedStruct(StringRef Directive, - DirectiveKind DirKind) { - if (StructInProgress.empty()) - return TokError("missing name in top-level '" + Twine(Directive) + - "' directive"); - - StringRef Name; - if (getTok().is(AsmToken::Identifier)) { - Name = getTok().getIdentifier(); - parseToken(AsmToken::Identifier); - } - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); - + } else if (addStructField(Name, Structure)) { + return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); + } + + return false; +} + +/// parseDirectiveStruct +/// ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE] +/// (dataDir | generalDir | offsetDir | nestedStruct)+ +/// <name> ENDS +////// dataDir = data declaration +////// offsetDir = EVEN, ORG, ALIGN +bool MasmParser::parseDirectiveStruct(StringRef Directive, + DirectiveKind DirKind, StringRef Name, + SMLoc NameLoc) { + // We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS + // anyway, so all field accesses must be qualified. + AsmToken NextTok = getTok(); + int64_t AlignmentValue = 1; + if (NextTok.isNot(AsmToken::Comma) && + NextTok.isNot(AsmToken::EndOfStatement) && + parseAbsoluteExpression(AlignmentValue)) { + return addErrorSuffix(" in alignment value for '" + Twine(Directive) + + "' directive"); + } + if (!isPowerOf2_64(AlignmentValue)) { + return Error(NextTok.getLoc(), "alignment must be a power of two; was " + + std::to_string(AlignmentValue)); + } + + StringRef Qualifier; + SMLoc QualifierLoc; + if (parseOptionalToken(AsmToken::Comma)) { + QualifierLoc = getTok().getLoc(); + if (parseIdentifier(Qualifier)) + return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); + if (!Qualifier.equals_lower("nonunique")) + return Error(QualifierLoc, "Unrecognized qualifier for '" + + Twine(Directive) + + "' directive; expected none or NONUNIQUE"); + } + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); + + StructInProgress.emplace_back(Name, DirKind == DK_UNION, AlignmentValue); + return false; +} + +/// parseDirectiveNestedStruct +/// ::= (STRUC | STRUCT | UNION) [name] +/// (dataDir | generalDir | offsetDir | nestedStruct)+ +/// ENDS +bool MasmParser::parseDirectiveNestedStruct(StringRef Directive, + DirectiveKind DirKind) { + if (StructInProgress.empty()) + return TokError("missing name in top-level '" + Twine(Directive) + + "' directive"); + + StringRef Name; + if (getTok().is(AsmToken::Identifier)) { + Name = getTok().getIdentifier(); + parseToken(AsmToken::Identifier); + } + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '" + Twine(Directive) + "' directive"); + // Reserve space to ensure Alignment doesn't get invalidated when // StructInProgress grows. StructInProgress.reserve(StructInProgress.size() + 1); - StructInProgress.emplace_back(Name, DirKind == DK_UNION, - StructInProgress.back().Alignment); - return false; -} - -bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) { - if (StructInProgress.empty()) - return Error(NameLoc, "ENDS directive without matching STRUC/STRUCT/UNION"); - if (StructInProgress.size() > 1) - return Error(NameLoc, "unexpected name in nested ENDS directive"); - if (StructInProgress.back().Name.compare_lower(Name)) - return Error(NameLoc, "mismatched name in ENDS directive; expected '" + - StructInProgress.back().Name + "'"); - StructInfo Structure = StructInProgress.pop_back_val(); + StructInProgress.emplace_back(Name, DirKind == DK_UNION, + StructInProgress.back().Alignment); + return false; +} + +bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) { + if (StructInProgress.empty()) + return Error(NameLoc, "ENDS directive without matching STRUC/STRUCT/UNION"); + if (StructInProgress.size() > 1) + return Error(NameLoc, "unexpected name in nested ENDS directive"); + if (StructInProgress.back().Name.compare_lower(Name)) + return Error(NameLoc, "mismatched name in ENDS directive; expected '" + + StructInProgress.back().Name + "'"); + StructInfo Structure = StructInProgress.pop_back_val(); // Pad to make the structure's size divisible by the smaller of its alignment // and the size of its largest field. Structure.Size = llvm::alignTo( Structure.Size, std::min(Structure.Alignment, Structure.AlignmentSize)); - Structs[Name.lower()] = Structure; - - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(" in ENDS directive"); - - return false; -} - -bool MasmParser::parseDirectiveNestedEnds() { - if (StructInProgress.empty()) - return TokError("ENDS directive without matching STRUC/STRUCT/UNION"); - if (StructInProgress.size() == 1) - return TokError("missing name in top-level ENDS directive"); - - if (parseToken(AsmToken::EndOfStatement)) - return addErrorSuffix(" in nested ENDS directive"); - - StructInfo Structure = StructInProgress.pop_back_val(); - // Pad to make the structure's size divisible by its alignment. - Structure.Size = llvm::alignTo(Structure.Size, Structure.Alignment); - - StructInfo &ParentStruct = StructInProgress.back(); - if (Structure.Name.empty()) { - const size_t OldFields = ParentStruct.Fields.size(); - ParentStruct.Fields.insert( - ParentStruct.Fields.end(), - std::make_move_iterator(Structure.Fields.begin()), - std::make_move_iterator(Structure.Fields.end())); - for (const auto &FieldByName : Structure.FieldsByName) { - ParentStruct.FieldsByName[FieldByName.getKey()] = - FieldByName.getValue() + OldFields; - } - if (!ParentStruct.IsUnion) { - for (auto FieldIter = ParentStruct.Fields.begin() + OldFields; - FieldIter != ParentStruct.Fields.end(); ++FieldIter) { - FieldIter->Offset += ParentStruct.Size; - } - } - - if (ParentStruct.IsUnion) - ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size); - else - ParentStruct.Size += Structure.Size; - } else { + Structs[Name.lower()] = Structure; + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in ENDS directive"); + + return false; +} + +bool MasmParser::parseDirectiveNestedEnds() { + if (StructInProgress.empty()) + return TokError("ENDS directive without matching STRUC/STRUCT/UNION"); + if (StructInProgress.size() == 1) + return TokError("missing name in top-level ENDS directive"); + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in nested ENDS directive"); + + StructInfo Structure = StructInProgress.pop_back_val(); + // Pad to make the structure's size divisible by its alignment. + Structure.Size = llvm::alignTo(Structure.Size, Structure.Alignment); + + StructInfo &ParentStruct = StructInProgress.back(); + if (Structure.Name.empty()) { + const size_t OldFields = ParentStruct.Fields.size(); + ParentStruct.Fields.insert( + ParentStruct.Fields.end(), + std::make_move_iterator(Structure.Fields.begin()), + std::make_move_iterator(Structure.Fields.end())); + for (const auto &FieldByName : Structure.FieldsByName) { + ParentStruct.FieldsByName[FieldByName.getKey()] = + FieldByName.getValue() + OldFields; + } + if (!ParentStruct.IsUnion) { + for (auto FieldIter = ParentStruct.Fields.begin() + OldFields; + FieldIter != ParentStruct.Fields.end(); ++FieldIter) { + FieldIter->Offset += ParentStruct.Size; + } + } + + if (ParentStruct.IsUnion) + ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size); + else + ParentStruct.Size += Structure.Size; + } else { FieldInfo &Field = ParentStruct.addField(Structure.Name, FT_STRUCT, Structure.AlignmentSize); - StructFieldInfo &StructInfo = Field.Contents.StructInfo; - Field.Type = Structure.Size; - Field.LengthOf = 1; - Field.SizeOf = Structure.Size; - - if (ParentStruct.IsUnion) - ParentStruct.Size = std::max(ParentStruct.Size, Field.SizeOf); - else - ParentStruct.Size += Field.SizeOf; - - StructInfo.Structure = Structure; - StructInfo.Initializers.emplace_back(); - auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers; - for (const auto &SubField : Structure.Fields) { - FieldInitializers.push_back(SubField.Contents); - } - } - - 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 different 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(); - } - - auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags(); - unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT; - 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>(ChecksumKind))) - 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; -} - -/// parseDirectiveMacro + StructFieldInfo &StructInfo = Field.Contents.StructInfo; + Field.Type = Structure.Size; + Field.LengthOf = 1; + Field.SizeOf = Structure.Size; + + if (ParentStruct.IsUnion) + ParentStruct.Size = std::max(ParentStruct.Size, Field.SizeOf); + else + ParentStruct.Size += Field.SizeOf; + + StructInfo.Structure = Structure; + StructInfo.Initializers.emplace_back(); + auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers; + for (const auto &SubField : Structure.Fields) { + FieldInitializers.push_back(SubField.Contents); + } + } + + 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 different 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(); + } + + auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags(); + unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT; + 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>(ChecksumKind))) + 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; +} + +/// parseDirectiveMacro /// ::= name macro [parameters] /// ["LOCAL" identifiers] /// parameters ::= parameter [, parameter]* /// parameter ::= name ":" qualifier /// qualifier ::= "req" | "vararg" | "=" macro_argument bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) { - MCAsmMacroParameters Parameters; - while (getLexer().isNot(AsmToken::EndOfStatement)) { - if (!Parameters.empty() && Parameters.back().Vararg) - return Error(Lexer.getLoc(), - "Vararg parameter '" + Parameters.back().Name + + 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 in the list of parameters"); - - MCAsmMacroParameter Parameter; - if (parseIdentifier(Parameter.Name)) + + 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) + + // Emit an error if two (or more) named parameters share the same name. + for (const MCAsmMacroParameter& CurrParam : Parameters) if (CurrParam.Name.equals_lower(Parameter.Name)) - return TokError("macro '" + Name + "' has multiple parameters" - " named '" + Parameter.Name + "'"); - - if (Lexer.is(AsmToken::Colon)) { - Lex(); // consume ':' - + return TokError("macro '" + Name + "' has multiple parameters" + " named '" + Parameter.Name + "'"); + + if (Lexer.is(AsmToken::Colon)) { + Lex(); // consume ':' + if (parseOptionalToken(AsmToken::Equal)) { // Default value SMLoc ParamLoc; - + ParamLoc = Lexer.getLoc(); if (parseMacroArgument(nullptr, Parameter.Value)) return true; } else { SMLoc QualLoc; StringRef Qualifier; - + QualLoc = Lexer.getLoc(); if (parseIdentifier(Qualifier)) return Error(QualLoc, "missing parameter qualifier for " "'" + Parameter.Name + "' in macro '" + Name + "'"); - + if (Qualifier.equals_lower("req")) Parameter.Required = true; else if (Qualifier.equals_lower("vararg")) @@ -5529,17 +5529,17 @@ bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) { Qualifier + " is not a valid parameter qualifier for '" + 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(); - + } + + Parameters.push_back(std::move(Parameter)); + + if (getLexer().is(AsmToken::Comma)) + Lex(); + } + + // Eat just the end of statement. + Lexer.Lex(); + std::vector<std::string> Locals; if (getTok().is(AsmToken::Identifier) && getTok().getIdentifier().equals_lower("local")) { @@ -5558,36 +5558,36 @@ bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) { } } - // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors. - AsmToken EndToken, StartToken = getTok(); - unsigned MacroDepth = 0; + // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors. + AsmToken EndToken, StartToken = getTok(); + unsigned MacroDepth = 0; bool IsMacroFunction = false; - // 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)) + // 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(NameLoc, "no matching 'endm' in definition"); - + // Otherwise, check whether we have reached the 'endm'... and determine if // this is a macro function. - if (getLexer().is(AsmToken::Identifier)) { + if (getLexer().is(AsmToken::Identifier)) { if (getTok().getIdentifier().equals_lower("endm")) { - 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; - } + 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().equals_lower("exitm")) { if (MacroDepth == 0 && getLexer().peekTok().isNot(AsmToken::EndOfStatement)) { @@ -5596,30 +5596,30 @@ bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) { } else if (isMacroLikeDirective()) { // 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(); - } - + ++MacroDepth; + } + } + + // Otherwise, scan til the end of the statement. + eatToEndOfStatement(); + } + if (getContext().lookupMacro(Name.lower())) { return Error(NameLoc, "macro '" + Name + "' is already defined"); - } - - const char *BodyStart = StartToken.getLoc().getPointer(); - const char *BodyEnd = EndToken.getLoc().getPointer(); - StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); + } + + const char *BodyStart = StartToken.getLoc().getPointer(); + const char *BodyEnd = EndToken.getLoc().getPointer(); + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals), IsMacroFunction); - DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n"; - Macro.dump()); - getContext().defineMacro(Name, std::move(Macro)); - return false; -} - -/// parseDirectiveExitMacro + DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n"; + Macro.dump()); + getContext().defineMacro(Name, std::move(Macro)); + return false; +} + +/// parseDirectiveExitMacro /// ::= "exitm" [textitem] bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc, StringRef Directive, @@ -5629,764 +5629,764 @@ bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc, return Error(EndLoc, "unable to parse text item in '" + Directive + "' directive"); eatToEndOfStatement(); - - 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 + + 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 -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 +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 /// ::= purge identifier ( , identifier )* -bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { - StringRef Name; +bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { + StringRef Name; while (true) { SMLoc NameLoc; if (parseTokenLoc(NameLoc) || check(parseIdentifier(Name), NameLoc, "expected identifier in 'purge' directive")) return true; - + DEBUG_WITH_TYPE("asm-macros", dbgs() << "Un-defining macro: " << Name << "\n"); if (!getContext().lookupMacro(Name.lower())) return Error(NameLoc, "macro '" + Name + "' is not defined"); getContext().undefineMacro(Name.lower()); - + if (!parseOptionalToken(AsmToken::Comma)) break; parseOptionalToken(AsmToken::EndOfStatement); } - 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) { + 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) { std::string FirstLine = parseStringTo(AsmToken::EndOfStatement); - size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A "); + size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A "); StringRef Delimiter = StringRef(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 + 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 ( !StringRef(parseStringTo(AsmToken::EndOfStatement)).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)) + 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 = parseStringTo(AsmToken::EndOfStatement); - 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 + 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 textitem -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)) +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 text item 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 + + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in 'ifb' directive")) + return true; + + TheCondState.CondMet = ExpectBlank == Str.empty(); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveIfidn /// ::= ifidn textitem, textitem bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual, bool CaseInsensitive) { - std::string String1, String2; - - if (parseTextItem(String1)) { - if (ExpectEqual) + std::string String1, String2; + + if (parseTextItem(String1)) { + if (ExpectEqual) return TokError("expected text item parameter for 'ifidn' directive"); return TokError("expected text item 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) + } + + 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 text item parameter for 'ifidn' directive"); return TokError("expected text item 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 + } + + 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 textitem -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; +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)) { if (ExpectBlank) return TokError("expected text item parameter for 'elseifb' directive"); return TokError("expected text item parameter for 'elseifnb' 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 + + 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 textitem, textitem -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) +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 text item parameter for 'elseifidn' directive"); return TokError("expected text item 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) + } + + 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 text item parameter for 'elseifidn' directive"); return TokError("expected text item 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; - } - } - + } + + 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; + } + } + std::string Message = ".err directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) + if (Lexer.isNot(AsmToken::EndOfStatement)) Message = parseStringTo(AsmToken::EndOfStatement); - 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"); - + 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"); + std::string Message = ".errb directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma)) - return addErrorSuffix(" in '.errb' directive"); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (parseToken(AsmToken::Comma)) + return addErrorSuffix(" in '.errb' directive"); Message = parseStringTo(AsmToken::EndOfStatement); - } - 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)); - } - } - + } + 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)); + } + } + std::string Message = ".errdef directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma)) - return addErrorSuffix(" in '.errdef' directive"); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (parseToken(AsmToken::Comma)) + return addErrorSuffix(" in '.errdef' directive"); Message = parseStringTo(AsmToken::EndOfStatement); - } - Lex(); - - if (IsDefined == ExpectDefined) - return Error(DirectiveLoc, Message); - return false; -} - -/// parseDirectiveErrorIfidn + } + Lex(); + + if (IsDefined == ExpectDefined) + return Error(DirectiveLoc, Message); + return false; +} + +/// parseDirectiveErrorIfidn /// ::= .erridn textitem, textitem[, 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"); - } - +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"); + } + std::string 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"); + 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 = parseStringTo(AsmToken::EndOfStatement); - } - 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"); - + } + 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"); + std::string Message = ".erre directive invoked in source file"; - if (Lexer.isNot(AsmToken::EndOfStatement)) { - if (parseToken(AsmToken::Comma)) - return addErrorSuffix(" in '.erre' directive"); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (parseToken(AsmToken::Comma)) + return addErrorSuffix(" in '.erre' directive"); Message = parseStringTo(AsmToken::EndOfStatement); - } - 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; + } + 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["real10"] = DK_REAL10; - 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["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["repeat"] = DK_REPEAT; DirectiveKindMap["rept"] = DK_REPEAT; DirectiveKindMap["while"] = DK_WHILE; @@ -6394,95 +6394,95 @@ void MasmParser::initializeDirectiveKindMap() { DirectiveKindMap["irp"] = DK_FOR; DirectiveKindMap["forc"] = DK_FORC; DirectiveKindMap["irpc"] = DK_FORC; - 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["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["purge"] = DK_PURGE; - 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[".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[".pushframe"] = DK_PUSHFRAME; DirectiveKindMap[".pushreg"] = DK_PUSHREG; DirectiveKindMap[".savereg"] = DK_SAVEREG; DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128; DirectiveKindMap[".setframe"] = DK_SETFRAME; DirectiveKindMap[".radix"] = DK_RADIX; - DirectiveKindMap["db"] = DK_DB; - DirectiveKindMap["dd"] = DK_DD; + DirectiveKindMap["db"] = DK_DB; + DirectiveKindMap["dd"] = DK_DD; DirectiveKindMap["df"] = DK_DF; - DirectiveKindMap["dq"] = DK_DQ; - DirectiveKindMap["dw"] = DK_DW; - DirectiveKindMap["echo"] = DK_ECHO; - DirectiveKindMap["struc"] = DK_STRUCT; - DirectiveKindMap["struct"] = DK_STRUCT; - DirectiveKindMap["union"] = DK_UNION; - DirectiveKindMap["ends"] = DK_ENDS; -} - + DirectiveKindMap["dq"] = DK_DQ; + DirectiveKindMap["dw"] = DK_DW; + DirectiveKindMap["echo"] = DK_ECHO; + DirectiveKindMap["struc"] = DK_STRUCT; + DirectiveKindMap["struct"] = DK_STRUCT; + DirectiveKindMap["union"] = DK_UNION; + DirectiveKindMap["ends"] = DK_ENDS; +} + bool MasmParser::isMacroLikeDirective() { if (getLexer().is(AsmToken::Identifier)) { bool IsMacroLike = StringSwitch<bool>(getTok().getIdentifier()) @@ -6501,48 +6501,48 @@ bool MasmParser::isMacroLikeDirective() { return false; } -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)) { +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 'endm' in definition"); - return nullptr; - } - + return nullptr; + } + if (isMacroLikeDirective()) - ++NestLevel; - + ++NestLevel; + // Otherwise, check whether we have reached the endm. if (Lexer.is(AsmToken::Identifier) && getTok().getIdentifier().equals_lower("endm")) { - if (NestLevel == 0) { - EndToken = getTok(); - Lex(); - if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (NestLevel == 0) { + EndToken = getTok(); + Lex(); + if (Lexer.isNot(AsmToken::EndOfStatement)) { printError(getTok().getLoc(), "unexpected token in 'endm' 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(); -} - + 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(); +} + bool MasmParser::expandStatement(SMLoc Loc) { std::string Body = parseStringTo(AsmToken::EndOfStatement); SMLoc EndLoc = getTok().getLoc(); @@ -6580,69 +6580,69 @@ bool MasmParser::expandStatement(SMLoc Loc) { return false; } -void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, - raw_svector_ostream &OS) { +void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, + raw_svector_ostream &OS) { instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/getTok().getLoc(), OS); } void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, SMLoc ExitLoc, raw_svector_ostream &OS) { OS << "endm\n"; - - std::unique_ptr<MemoryBuffer> Instantiation = - MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); - - // Create the macro instantiation object and add to the current macro - // instantiation stack. + + 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, ExitLoc, 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()); + 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()); EndStatementAtEOFStack.push_back(true); - Lex(); -} - + Lex(); +} + /// parseDirectiveRepeat /// ::= ("repeat" | "rept") count /// body /// endm bool MasmParser::parseDirectiveRepeat(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; - + 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 repeat 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--) { + 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--) { if (expandMacro(OS, M->Body, None, None, M->Locals, getTok().getLoc())) - return true; - } - instantiateMacroLikeBody(M, DirectiveLoc, OS); - - return false; -} - + return true; + } + instantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + /// parseDirectiveWhile /// ::= "while" expression /// body @@ -6681,9 +6681,9 @@ bool MasmParser::parseDirectiveWhile(SMLoc DirectiveLoc) { /// body /// endm bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) { - MCAsmMacroParameter Parameter; - MCAsmMacroArguments A; - if (check(parseIdentifier(Parameter.Name), + MCAsmMacroParameter Parameter; + MCAsmMacroArguments A; + if (check(parseIdentifier(Parameter.Name), "expected identifier in '" + Dir + "' directive")) return true; @@ -6737,42 +6737,42 @@ bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) { if (parseToken(AsmToken::Greater, "values in '" + Dir + "' directive must be enclosed in angle brackets") || - parseToken(AsmToken::EndOfStatement, "expected End of Statement")) - return true; - + parseToken(AsmToken::EndOfStatement, "expected End of Statement")) + return true; + // Lex the for 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) { + 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) { if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc())) - return true; - } - - instantiateMacroLikeBody(M, DirectiveLoc, OS); - - return false; -} - + return true; + } + + instantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + /// parseDirectiveForc /// ::= ("forc" | "irpc") symbol, <string> /// body /// endm bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) { - MCAsmMacroParameter Parameter; - + MCAsmMacroParameter Parameter; + std::string Argument; - if (check(parseIdentifier(Parameter.Name), + if (check(parseIdentifier(Parameter.Name), "expected identifier in '" + Directive + "' directive") || parseToken(AsmToken::Comma, "expected comma in '" + Directive + "' directive")) - return true; + return true; if (parseAngleBracketString(Argument)) { // Match ml64.exe; treat all characters to end of statement as a string, // ignoring comment markers, then discard anything following a space (using @@ -6787,66 +6787,66 @@ bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) { } Argument.resize(End); } - 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); - + 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(Argument); - for (std::size_t I = 0, End = Values.size(); I != End; ++I) { - MCAsmMacroArgument Arg; - Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1)); - + for (std::size_t I = 0, End = Values.size(); I != End; ++I) { + MCAsmMacroArgument Arg; + Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1)); + if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc())) - return true; - } - - instantiateMacroLikeBody(M, DirectiveLoc, OS); - - 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; -} - + return true; + } + + instantiateMacroLikeBody(M, DirectiveLoc, OS); + + 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::parseDirectiveRadix(SMLoc DirectiveLoc) { const SMLoc Loc = getLexer().getLoc(); std::string RadixStringRaw = parseStringTo(AsmToken::EndOfStatement); @@ -6866,7 +6866,7 @@ bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) { /// parseDirectiveEcho /// ::= "echo" message -bool MasmParser::parseDirectiveEcho() { +bool MasmParser::parseDirectiveEcho() { // We're called before the directive is parsed, to avoid triggering lexical // substitutions in the message. Assert that the next token is the directive, // then eat it without using the Parser's Lex method. @@ -6878,32 +6878,32 @@ bool MasmParser::parseDirectiveEcho() { llvm::outs() << Message; if (!StringRef(Message).endswith("\n")) llvm::outs() << '\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."); -} - + 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::defineMacro(StringRef Name, StringRef Value) { Variable &Var = Variables[Name.lower()]; if (Var.Name.empty()) { @@ -6918,76 +6918,76 @@ bool MasmParser::defineMacro(StringRef Name, StringRef Value) { } bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const { - const std::pair<StringRef, StringRef> BaseMember = Name.split('.'); - const StringRef Base = BaseMember.first, Member = BaseMember.second; + const std::pair<StringRef, StringRef> BaseMember = Name.split('.'); + const StringRef Base = BaseMember.first, Member = BaseMember.second; return lookUpField(Base, Member, Info); -} - +} + bool MasmParser::lookUpField(StringRef Base, StringRef Member, AsmFieldInfo &Info) const { - if (Base.empty()) - return true; - + if (Base.empty()) + return true; + AsmFieldInfo BaseInfo; if (Base.contains('.') && !lookUpField(Base, BaseInfo)) Base = BaseInfo.Type.Name; - - auto StructIt = Structs.find(Base.lower()); + + auto StructIt = Structs.find(Base.lower()); auto TypeIt = KnownType.find(Base.lower()); if (TypeIt != KnownType.end()) { StructIt = Structs.find(TypeIt->second.Name.lower()); } - if (StructIt != Structs.end()) + if (StructIt != Structs.end()) return lookUpField(StructIt->second, Member, Info); - - return true; -} - -bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member, + + return true; +} + +bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member, AsmFieldInfo &Info) const { - if (Member.empty()) { + if (Member.empty()) { Info.Type.Name = Structure.Name; Info.Type.Size = Structure.Size; Info.Type.ElementSize = Structure.Size; Info.Type.Length = 1; - return false; - } - - std::pair<StringRef, StringRef> Split = Member.split('.'); - const StringRef FieldName = Split.first, FieldMember = Split.second; - - auto StructIt = Structs.find(FieldName.lower()); - if (StructIt != Structs.end()) + return false; + } + + std::pair<StringRef, StringRef> Split = Member.split('.'); + const StringRef FieldName = Split.first, FieldMember = Split.second; + + auto StructIt = Structs.find(FieldName.lower()); + if (StructIt != Structs.end()) return lookUpField(StructIt->second, FieldMember, Info); - - auto FieldIt = Structure.FieldsByName.find(FieldName.lower()); - if (FieldIt == Structure.FieldsByName.end()) - return true; - - const FieldInfo &Field = Structure.Fields[FieldIt->second]; - if (FieldMember.empty()) { + + auto FieldIt = Structure.FieldsByName.find(FieldName.lower()); + if (FieldIt == Structure.FieldsByName.end()) + return true; + + const FieldInfo &Field = Structure.Fields[FieldIt->second]; + if (FieldMember.empty()) { Info.Offset += Field.Offset; Info.Type.Size = Field.SizeOf; Info.Type.ElementSize = Field.Type; Info.Type.Length = Field.LengthOf; - if (Field.Contents.FT == FT_STRUCT) + if (Field.Contents.FT == FT_STRUCT) Info.Type.Name = Field.Contents.StructInfo.Structure.Name; else Info.Type.Name = ""; - return false; - } - - if (Field.Contents.FT != FT_STRUCT) - return true; - const StructFieldInfo &StructInfo = Field.Contents.StructInfo; - + return false; + } + + if (Field.Contents.FT != FT_STRUCT) + return true; + const StructFieldInfo &StructInfo = Field.Contents.StructInfo; + if (lookUpField(StructInfo.Structure, FieldMember, Info)) - return true; - + return true; + Info.Offset += Field.Offset; - return false; -} - + return false; +} + bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const { unsigned Size = StringSwitch<unsigned>(Name) .CasesLower("byte", "db", "sbyte", 1) @@ -7020,273 +7020,273 @@ bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const { return true; } -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.getReg())) { - 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()); +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.getReg())) { + 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()); llvm::append_range(ClobberRegs, ImpDefs); - } - - // 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); -} + } + + // 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/contrib/libs/llvm12/lib/MC/MCParser/WasmAsmParser.cpp b/contrib/libs/llvm12/lib/MC/MCParser/WasmAsmParser.cpp index 58aaebc2d7..0c255ef02d 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/WasmAsmParser.cpp +++ b/contrib/libs/llvm12/lib/MC/MCParser/WasmAsmParser.cpp @@ -1,100 +1,100 @@ -//===- WasmAsmParser.cpp - Wasm 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 -// -// -- -// -// Note, this is for wasm, the binary format (analogous to ELF), not wasm, -// the instruction set (analogous to x86), for which parsing code lives in -// WebAssemblyAsmParser. -// -// This file contains processing for generic directives implemented using -// MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in -// WebAssemblyAsmParser. -// -//===----------------------------------------------------------------------===// - -#include "llvm/BinaryFormat/Wasm.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCSectionWasm.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCSymbolWasm.h" -#include "llvm/Support/MachineValueType.h" - -using namespace llvm; - -namespace { - -class WasmAsmParser : public MCAsmParserExtension { - MCAsmParser *Parser = nullptr; - MCAsmLexer *Lexer = nullptr; - - template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)> - void addDirectiveHandler(StringRef Directive) { - MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( - this, HandleDirective<WasmAsmParser, HandlerMethod>); - - getParser().addDirectiveHandler(Directive, Handler); - } - -public: - WasmAsmParser() { BracketExpressionsSupported = true; } - - void Initialize(MCAsmParser &P) override { - Parser = &P; - Lexer = &Parser->getLexer(); - // Call the base implementation. - this->MCAsmParserExtension::Initialize(*Parser); - - addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text"); - addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section"); - addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size"); - addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type"); - addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident"); - addDirectiveHandler< - &WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak"); - addDirectiveHandler< - &WasmAsmParser::ParseDirectiveSymbolAttribute>(".local"); - addDirectiveHandler< - &WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal"); - addDirectiveHandler< - &WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); - } - - bool error(const StringRef &Msg, const AsmToken &Tok) { - return Parser->Error(Tok.getLoc(), Msg + Tok.getString()); - } - - bool isNext(AsmToken::TokenKind Kind) { - auto Ok = Lexer->is(Kind); - if (Ok) - Lex(); - return Ok; - } - - bool expect(AsmToken::TokenKind Kind, const char *KindName) { - if (!isNext(Kind)) - return error(std::string("Expected ") + KindName + ", instead got: ", - Lexer->getTok()); - return false; - } - - bool parseSectionDirectiveText(StringRef, SMLoc) { - // FIXME: .text currently no-op. - return false; - } - +//===- WasmAsmParser.cpp - Wasm 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 +// +// -- +// +// Note, this is for wasm, the binary format (analogous to ELF), not wasm, +// the instruction set (analogous to x86), for which parsing code lives in +// WebAssemblyAsmParser. +// +// This file contains processing for generic directives implemented using +// MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in +// WebAssemblyAsmParser. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCSectionWasm.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Support/MachineValueType.h" + +using namespace llvm; + +namespace { + +class WasmAsmParser : public MCAsmParserExtension { + MCAsmParser *Parser = nullptr; + MCAsmLexer *Lexer = nullptr; + + template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)> + void addDirectiveHandler(StringRef Directive) { + MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( + this, HandleDirective<WasmAsmParser, HandlerMethod>); + + getParser().addDirectiveHandler(Directive, Handler); + } + +public: + WasmAsmParser() { BracketExpressionsSupported = true; } + + void Initialize(MCAsmParser &P) override { + Parser = &P; + Lexer = &Parser->getLexer(); + // Call the base implementation. + this->MCAsmParserExtension::Initialize(*Parser); + + addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text"); + addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section"); + addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size"); + addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type"); + addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident"); + addDirectiveHandler< + &WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + addDirectiveHandler< + &WasmAsmParser::ParseDirectiveSymbolAttribute>(".local"); + addDirectiveHandler< + &WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal"); + addDirectiveHandler< + &WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); + } + + bool error(const StringRef &Msg, const AsmToken &Tok) { + return Parser->Error(Tok.getLoc(), Msg + Tok.getString()); + } + + bool isNext(AsmToken::TokenKind Kind) { + auto Ok = Lexer->is(Kind); + if (Ok) + Lex(); + return Ok; + } + + bool expect(AsmToken::TokenKind Kind, const char *KindName) { + if (!isNext(Kind)) + return error(std::string("Expected ") + KindName + ", instead got: ", + Lexer->getTok()); + return false; + } + + bool parseSectionDirectiveText(StringRef, SMLoc) { + // FIXME: .text currently no-op. + return false; + } + bool parseSectionFlags(StringRef FlagStr, bool &Passive, bool &Group) { for (char C : FlagStr) { switch (C) { case 'p': - Passive = true; + Passive = true; break; case 'G': Group = true; @@ -103,10 +103,10 @@ public: return Parser->Error(getTok().getLoc(), StringRef("Unexepcted section flag: ") + FlagStr); } - } - return false; - } - + } + return false; + } + bool parseGroup(StringRef &GroupName) { if (Lexer->isNot(AsmToken::Comma)) return TokError("expected group name"); @@ -128,40 +128,40 @@ public: return false; } - bool parseSectionDirective(StringRef, SMLoc) { - StringRef Name; - if (Parser->parseIdentifier(Name)) - return TokError("expected identifier in directive"); - - if (expect(AsmToken::Comma, ",")) - return true; - - if (Lexer->isNot(AsmToken::String)) - return error("expected string in directive, instead got: ", Lexer->getTok()); - - auto Kind = StringSwitch<Optional<SectionKind>>(Name) - .StartsWith(".data", SectionKind::getData()) + bool parseSectionDirective(StringRef, SMLoc) { + StringRef Name; + if (Parser->parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (expect(AsmToken::Comma, ",")) + return true; + + if (Lexer->isNot(AsmToken::String)) + return error("expected string in directive, instead got: ", Lexer->getTok()); + + auto Kind = StringSwitch<Optional<SectionKind>>(Name) + .StartsWith(".data", SectionKind::getData()) .StartsWith(".tdata", SectionKind::getThreadData()) .StartsWith(".tbss", SectionKind::getThreadBSS()) - .StartsWith(".rodata", SectionKind::getReadOnly()) - .StartsWith(".text", SectionKind::getText()) - .StartsWith(".custom_section", SectionKind::getMetadata()) - .StartsWith(".bss", SectionKind::getBSS()) - // See use of .init_array in WasmObjectWriter and - // TargetLoweringObjectFileWasm - .StartsWith(".init_array", SectionKind::getData()) - .StartsWith(".debug_", SectionKind::getMetadata()) - .Default(Optional<SectionKind>()); - if (!Kind.hasValue()) - return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); - - - // Update section flags if present in this .section directive - bool Passive = false; + .StartsWith(".rodata", SectionKind::getReadOnly()) + .StartsWith(".text", SectionKind::getText()) + .StartsWith(".custom_section", SectionKind::getMetadata()) + .StartsWith(".bss", SectionKind::getBSS()) + // See use of .init_array in WasmObjectWriter and + // TargetLoweringObjectFileWasm + .StartsWith(".init_array", SectionKind::getData()) + .StartsWith(".debug_", SectionKind::getMetadata()) + .Default(Optional<SectionKind>()); + if (!Kind.hasValue()) + return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); + + + // Update section flags if present in this .section directive + bool Passive = false; bool Group = false; if (parseSectionFlags(getTok().getStringContents(), Passive, Group)) - return true; - + return true; + Lex(); if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@")) @@ -177,118 +177,118 @@ public: // TODO: Parse UniqueID MCSectionWasm *WS = getContext().getWasmSection( Name, Kind.getValue(), GroupName, MCContext::GenericSectionID); - if (Passive) { + if (Passive) { if (!WS->isWasmData()) - return Parser->Error(getTok().getLoc(), - "Only data sections can be passive"); + return Parser->Error(getTok().getLoc(), + "Only data sections can be passive"); WS->setPassive(); - } - getStreamer().SwitchSection(WS); - return false; - } - - // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize - // so maybe could be shared somehow. - bool parseDirectiveSize(StringRef, SMLoc) { - StringRef Name; - if (Parser->parseIdentifier(Name)) - return TokError("expected identifier in directive"); - auto Sym = getContext().getOrCreateSymbol(Name); - if (expect(AsmToken::Comma, ",")) - return true; - const MCExpr *Expr; - if (Parser->parseExpression(Expr)) - return true; - if (expect(AsmToken::EndOfStatement, "eol")) - return true; - // This is done automatically by the assembler for functions currently, - // so this is only currently needed for data sections: - getStreamer().emitELFSize(Sym, Expr); - return false; - } - - bool parseDirectiveType(StringRef, SMLoc) { - // This could be the start of a function, check if followed by - // "label,@function" - if (!Lexer->is(AsmToken::Identifier)) - return error("Expected label after .type directive, got: ", - Lexer->getTok()); - auto WasmSym = cast<MCSymbolWasm>( - getStreamer().getContext().getOrCreateSymbol( - Lexer->getTok().getString())); - Lex(); - if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && - Lexer->is(AsmToken::Identifier))) - return error("Expected label,@type declaration, got: ", Lexer->getTok()); - auto TypeName = Lexer->getTok().getString(); + } + getStreamer().SwitchSection(WS); + return false; + } + + // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize + // so maybe could be shared somehow. + bool parseDirectiveSize(StringRef, SMLoc) { + StringRef Name; + if (Parser->parseIdentifier(Name)) + return TokError("expected identifier in directive"); + auto Sym = getContext().getOrCreateSymbol(Name); + if (expect(AsmToken::Comma, ",")) + return true; + const MCExpr *Expr; + if (Parser->parseExpression(Expr)) + return true; + if (expect(AsmToken::EndOfStatement, "eol")) + return true; + // This is done automatically by the assembler for functions currently, + // so this is only currently needed for data sections: + getStreamer().emitELFSize(Sym, Expr); + return false; + } + + bool parseDirectiveType(StringRef, SMLoc) { + // This could be the start of a function, check if followed by + // "label,@function" + if (!Lexer->is(AsmToken::Identifier)) + return error("Expected label after .type directive, got: ", + Lexer->getTok()); + auto WasmSym = cast<MCSymbolWasm>( + getStreamer().getContext().getOrCreateSymbol( + Lexer->getTok().getString())); + Lex(); + if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && + Lexer->is(AsmToken::Identifier))) + return error("Expected label,@type declaration, got: ", Lexer->getTok()); + auto TypeName = Lexer->getTok().getString(); if (TypeName == "function") { - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); auto *Current = cast<MCSectionWasm>(getStreamer().getCurrentSection().first); if (Current->getGroup()) WasmSym->setComdat(true); } else if (TypeName == "global") - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); - else if (TypeName == "object") - WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); - else - return error("Unknown WASM symbol type: ", Lexer->getTok()); - Lex(); - return expect(AsmToken::EndOfStatement, "EOL"); - } - - // FIXME: Shared with ELF. - /// ParseDirectiveIdent - /// ::= .ident string - bool ParseDirectiveIdent(StringRef, SMLoc) { - if (getLexer().isNot(AsmToken::String)) - return TokError("unexpected token in '.ident' directive"); - StringRef Data = getTok().getIdentifier(); - Lex(); - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.ident' directive"); - Lex(); - getStreamer().emitIdent(Data); - return false; - } - - // FIXME: Shared with ELF. - /// ParseDirectiveSymbolAttribute - /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] - bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { - MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) - .Case(".weak", MCSA_Weak) - .Case(".local", MCSA_Local) - .Case(".hidden", MCSA_Hidden) - .Case(".internal", MCSA_Internal) - .Case(".protected", MCSA_Protected) - .Default(MCSA_Invalid); - assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - while (true) { - StringRef Name; - if (getParser().parseIdentifier(Name)) - return TokError("expected identifier in directive"); - MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - getStreamer().emitSymbolAttribute(Sym, Attr); - if (getLexer().is(AsmToken::EndOfStatement)) - break; - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in directive"); - Lex(); - } - } - Lex(); - return false; - } -}; - -} // end anonymous namespace - -namespace llvm { - -MCAsmParserExtension *createWasmAsmParser() { - return new WasmAsmParser; -} - -} // end namespace llvm + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + else if (TypeName == "object") + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); + else + return error("Unknown WASM symbol type: ", Lexer->getTok()); + Lex(); + return expect(AsmToken::EndOfStatement, "EOL"); + } + + // FIXME: Shared with ELF. + /// ParseDirectiveIdent + /// ::= .ident string + bool ParseDirectiveIdent(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.ident' directive"); + StringRef Data = getTok().getIdentifier(); + Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ident' directive"); + Lex(); + getStreamer().emitIdent(Data); + return false; + } + + // FIXME: Shared with ELF. + /// ParseDirectiveSymbolAttribute + /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] + bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { + MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) + .Case(".weak", MCSA_Weak) + .Case(".local", MCSA_Local) + .Case(".hidden", MCSA_Hidden) + .Case(".internal", MCSA_Internal) + .Case(".protected", MCSA_Protected) + .Default(MCSA_Invalid); + assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); + if (getLexer().isNot(AsmToken::EndOfStatement)) { + while (true) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().emitSymbolAttribute(Sym, Attr); + if (getLexer().is(AsmToken::EndOfStatement)) + break; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + Lex(); + return false; + } +}; + +} // end anonymous namespace + +namespace llvm { + +MCAsmParserExtension *createWasmAsmParser() { + return new WasmAsmParser; +} + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/MC/MCParser/ya.make b/contrib/libs/llvm12/lib/MC/MCParser/ya.make index cc9e74ac69..304ad7d65a 100644 --- a/contrib/libs/llvm12/lib/MC/MCParser/ya.make +++ b/contrib/libs/llvm12/lib/MC/MCParser/ya.make @@ -1,43 +1,43 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/MC contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/MC/MCParser ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - AsmLexer.cpp - AsmParser.cpp - COFFAsmParser.cpp - COFFMasmParser.cpp - DarwinAsmParser.cpp - ELFAsmParser.cpp - MCAsmLexer.cpp - MCAsmParser.cpp - MCAsmParserExtension.cpp - MCTargetAsmParser.cpp - MasmParser.cpp - WasmAsmParser.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + AsmLexer.cpp + AsmParser.cpp + COFFAsmParser.cpp + COFFMasmParser.cpp + DarwinAsmParser.cpp + ELFAsmParser.cpp + MCAsmLexer.cpp + MCAsmParser.cpp + MCAsmParserExtension.cpp + MCTargetAsmParser.cpp + MasmParser.cpp + WasmAsmParser.cpp +) + +END() |