6270 lines · cpp
1//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class implements the parser for assembly files.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/APFloat.h"14#include "llvm/ADT/APInt.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/BitVector.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/SmallString.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/ADT/StringMap.h"22#include "llvm/ADT/StringRef.h"23#include "llvm/ADT/StringSwitch.h"24#include "llvm/ADT/Twine.h"25#include "llvm/MC/MCAsmInfo.h"26#include "llvm/MC/MCCodeView.h"27#include "llvm/MC/MCContext.h"28#include "llvm/MC/MCDirectives.h"29#include "llvm/MC/MCExpr.h"30#include "llvm/MC/MCInstPrinter.h"31#include "llvm/MC/MCInstrDesc.h"32#include "llvm/MC/MCInstrInfo.h"33#include "llvm/MC/MCParser/AsmCond.h"34#include "llvm/MC/MCParser/AsmLexer.h"35#include "llvm/MC/MCParser/MCAsmParser.h"36#include "llvm/MC/MCParser/MCAsmParserExtension.h"37#include "llvm/MC/MCParser/MCParsedAsmOperand.h"38#include "llvm/MC/MCParser/MCTargetAsmParser.h"39#include "llvm/MC/MCSection.h"40#include "llvm/MC/MCStreamer.h"41#include "llvm/MC/MCSubtargetInfo.h"42#include "llvm/MC/MCSymbolCOFF.h"43#include "llvm/MC/MCTargetOptions.h"44#include "llvm/Support/Casting.h"45#include "llvm/Support/CommandLine.h"46#include "llvm/Support/ErrorHandling.h"47#include "llvm/Support/Format.h"48#include "llvm/Support/MD5.h"49#include "llvm/Support/MathExtras.h"50#include "llvm/Support/MemoryBuffer.h"51#include "llvm/Support/Path.h"52#include "llvm/Support/SMLoc.h"53#include "llvm/Support/SourceMgr.h"54#include "llvm/Support/raw_ostream.h"55#include <algorithm>56#include <cassert>57#include <climits>58#include <cstddef>59#include <cstdint>60#include <ctime>61#include <deque>62#include <memory>63#include <optional>64#include <sstream>65#include <string>66#include <tuple>67#include <utility>68#include <vector>69 70using namespace llvm;71 72namespace {73 74/// Helper types for tracking macro definitions.75typedef std::vector<AsmToken> MCAsmMacroArgument;76typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;77 78/// Helper class for storing information about an active macro instantiation.79struct MacroInstantiation {80 /// The location of the instantiation.81 SMLoc InstantiationLoc;82 83 /// The buffer where parsing should resume upon instantiation completion.84 unsigned ExitBuffer;85 86 /// The location where parsing should resume upon instantiation completion.87 SMLoc ExitLoc;88 89 /// The depth of TheCondStack at the start of the instantiation.90 size_t CondStackDepth;91};92 93struct ParseStatementInfo {94 /// The parsed operands from the last parsed statement.95 SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;96 97 /// The opcode from the last parsed instruction.98 unsigned Opcode = ~0U;99 100 /// Was there an error parsing the inline assembly?101 bool ParseError = false;102 103 /// The value associated with a macro exit.104 std::optional<std::string> ExitValue;105 106 SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;107 108 ParseStatementInfo() = delete;109 ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)110 : AsmRewrites(rewrites) {}111};112 113enum FieldType {114 FT_INTEGRAL, // Initializer: integer expression, stored as an MCExpr.115 FT_REAL, // Initializer: real number, stored as an APInt.116 FT_STRUCT // Initializer: struct initializer, stored recursively.117};118 119struct FieldInfo;120struct StructInfo {121 StringRef Name;122 bool IsUnion = false;123 bool Initializable = true;124 unsigned Alignment = 0;125 unsigned AlignmentSize = 0;126 unsigned NextOffset = 0;127 unsigned Size = 0;128 std::vector<FieldInfo> Fields;129 StringMap<size_t> FieldsByName;130 131 FieldInfo &addField(StringRef FieldName, FieldType FT,132 unsigned FieldAlignmentSize);133 134 StructInfo() = default;135 StructInfo(StringRef StructName, bool Union, unsigned AlignmentValue);136};137 138// FIXME: This should probably use a class hierarchy, raw pointers between the139// objects, and dynamic type resolution instead of a union. On the other hand,140// ownership then becomes much more complicated; the obvious thing would be to141// use BumpPtrAllocator, but the lack of a destructor makes that messy.142 143struct StructInitializer;144struct IntFieldInfo {145 SmallVector<const MCExpr *, 1> Values;146 147 IntFieldInfo() = default;148 IntFieldInfo(const SmallVector<const MCExpr *, 1> &V) { Values = V; }149 IntFieldInfo(SmallVector<const MCExpr *, 1> &&V) { Values = std::move(V); }150};151struct RealFieldInfo {152 SmallVector<APInt, 1> AsIntValues;153 154 RealFieldInfo() = default;155 RealFieldInfo(const SmallVector<APInt, 1> &V) { AsIntValues = V; }156 RealFieldInfo(SmallVector<APInt, 1> &&V) { AsIntValues = std::move(V); }157};158struct StructFieldInfo {159 std::vector<StructInitializer> Initializers;160 StructInfo Structure;161 162 StructFieldInfo() = default;163 StructFieldInfo(std::vector<StructInitializer> V, StructInfo S);164};165 166class FieldInitializer {167public:168 FieldType FT;169 union {170 IntFieldInfo IntInfo;171 RealFieldInfo RealInfo;172 StructFieldInfo StructInfo;173 };174 175 ~FieldInitializer();176 FieldInitializer(FieldType FT);177 178 FieldInitializer(SmallVector<const MCExpr *, 1> &&Values);179 FieldInitializer(SmallVector<APInt, 1> &&AsIntValues);180 FieldInitializer(std::vector<StructInitializer> &&Initializers,181 struct StructInfo Structure);182 183 FieldInitializer(const FieldInitializer &Initializer);184 FieldInitializer(FieldInitializer &&Initializer);185 186 FieldInitializer &operator=(const FieldInitializer &Initializer);187 FieldInitializer &operator=(FieldInitializer &&Initializer);188};189 190struct StructInitializer {191 std::vector<FieldInitializer> FieldInitializers;192};193 194struct FieldInfo {195 // Offset of the field within the containing STRUCT.196 unsigned Offset = 0;197 198 // Total size of the field (= LengthOf * Type).199 unsigned SizeOf = 0;200 201 // Number of elements in the field (1 if scalar, >1 if an array).202 unsigned LengthOf = 0;203 204 // Size of a single entry in this field, in bytes ("type" in MASM standards).205 unsigned Type = 0;206 207 FieldInitializer Contents;208 209 FieldInfo(FieldType FT) : Contents(FT) {}210};211 212StructFieldInfo::StructFieldInfo(std::vector<StructInitializer> V,213 StructInfo S) {214 Initializers = std::move(V);215 Structure = S;216}217 218StructInfo::StructInfo(StringRef StructName, bool Union,219 unsigned AlignmentValue)220 : Name(StructName), IsUnion(Union), Alignment(AlignmentValue) {}221 222FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT,223 unsigned FieldAlignmentSize) {224 if (!FieldName.empty())225 FieldsByName[FieldName.lower()] = Fields.size();226 Fields.emplace_back(FT);227 FieldInfo &Field = Fields.back();228 Field.Offset =229 llvm::alignTo(NextOffset, std::min(Alignment, FieldAlignmentSize));230 if (!IsUnion) {231 NextOffset = std::max(NextOffset, Field.Offset);232 }233 AlignmentSize = std::max(AlignmentSize, FieldAlignmentSize);234 return Field;235}236 237FieldInitializer::~FieldInitializer() {238 switch (FT) {239 case FT_INTEGRAL:240 IntInfo.~IntFieldInfo();241 break;242 case FT_REAL:243 RealInfo.~RealFieldInfo();244 break;245 case FT_STRUCT:246 StructInfo.~StructFieldInfo();247 break;248 }249}250 251FieldInitializer::FieldInitializer(FieldType FT) : FT(FT) {252 switch (FT) {253 case FT_INTEGRAL:254 new (&IntInfo) IntFieldInfo();255 break;256 case FT_REAL:257 new (&RealInfo) RealFieldInfo();258 break;259 case FT_STRUCT:260 new (&StructInfo) StructFieldInfo();261 break;262 }263}264 265FieldInitializer::FieldInitializer(SmallVector<const MCExpr *, 1> &&Values)266 : FT(FT_INTEGRAL) {267 new (&IntInfo) IntFieldInfo(std::move(Values));268}269 270FieldInitializer::FieldInitializer(SmallVector<APInt, 1> &&AsIntValues)271 : FT(FT_REAL) {272 new (&RealInfo) RealFieldInfo(std::move(AsIntValues));273}274 275FieldInitializer::FieldInitializer(276 std::vector<StructInitializer> &&Initializers, struct StructInfo Structure)277 : FT(FT_STRUCT) {278 new (&StructInfo) StructFieldInfo(std::move(Initializers), Structure);279}280 281FieldInitializer::FieldInitializer(const FieldInitializer &Initializer)282 : FT(Initializer.FT) {283 switch (FT) {284 case FT_INTEGRAL:285 new (&IntInfo) IntFieldInfo(Initializer.IntInfo);286 break;287 case FT_REAL:288 new (&RealInfo) RealFieldInfo(Initializer.RealInfo);289 break;290 case FT_STRUCT:291 new (&StructInfo) StructFieldInfo(Initializer.StructInfo);292 break;293 }294}295 296FieldInitializer::FieldInitializer(FieldInitializer &&Initializer)297 : FT(Initializer.FT) {298 switch (FT) {299 case FT_INTEGRAL:300 new (&IntInfo) IntFieldInfo(Initializer.IntInfo);301 break;302 case FT_REAL:303 new (&RealInfo) RealFieldInfo(Initializer.RealInfo);304 break;305 case FT_STRUCT:306 new (&StructInfo) StructFieldInfo(Initializer.StructInfo);307 break;308 }309}310 311FieldInitializer &312FieldInitializer::operator=(const FieldInitializer &Initializer) {313 if (FT != Initializer.FT) {314 switch (FT) {315 case FT_INTEGRAL:316 IntInfo.~IntFieldInfo();317 break;318 case FT_REAL:319 RealInfo.~RealFieldInfo();320 break;321 case FT_STRUCT:322 StructInfo.~StructFieldInfo();323 break;324 }325 }326 FT = Initializer.FT;327 switch (FT) {328 case FT_INTEGRAL:329 IntInfo = Initializer.IntInfo;330 break;331 case FT_REAL:332 RealInfo = Initializer.RealInfo;333 break;334 case FT_STRUCT:335 StructInfo = Initializer.StructInfo;336 break;337 }338 return *this;339}340 341FieldInitializer &FieldInitializer::operator=(FieldInitializer &&Initializer) {342 if (FT != Initializer.FT) {343 switch (FT) {344 case FT_INTEGRAL:345 IntInfo.~IntFieldInfo();346 break;347 case FT_REAL:348 RealInfo.~RealFieldInfo();349 break;350 case FT_STRUCT:351 StructInfo.~StructFieldInfo();352 break;353 }354 }355 FT = Initializer.FT;356 switch (FT) {357 case FT_INTEGRAL:358 IntInfo = Initializer.IntInfo;359 break;360 case FT_REAL:361 RealInfo = Initializer.RealInfo;362 break;363 case FT_STRUCT:364 StructInfo = Initializer.StructInfo;365 break;366 }367 return *this;368}369 370/// The concrete assembly parser instance.371// Note that this is a full MCAsmParser, not an MCAsmParserExtension!372// It's a peer of AsmParser, not of COFFAsmParser, WasmAsmParser, etc.373class MasmParser : public MCAsmParser {374private:375 SourceMgr::DiagHandlerTy SavedDiagHandler;376 void *SavedDiagContext;377 std::unique_ptr<MCAsmParserExtension> PlatformParser;378 379 /// This is the current buffer index we're lexing from as managed by the380 /// SourceMgr object.381 unsigned CurBuffer;382 383 /// time of assembly384 struct tm TM;385 386 BitVector EndStatementAtEOFStack;387 388 AsmCond TheCondState;389 std::vector<AsmCond> TheCondStack;390 391 /// maps directive names to handler methods in parser392 /// extensions. Extensions register themselves in this map by calling393 /// addDirectiveHandler.394 StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;395 396 /// maps assembly-time variable names to variables.397 struct Variable {398 enum RedefinableKind { NOT_REDEFINABLE, WARN_ON_REDEFINITION, REDEFINABLE };399 400 StringRef Name;401 RedefinableKind Redefinable = REDEFINABLE;402 bool IsText = false;403 std::string TextValue;404 };405 StringMap<Variable> Variables;406 407 /// Stack of active struct definitions.408 SmallVector<StructInfo, 1> StructInProgress;409 410 /// Maps struct tags to struct definitions.411 StringMap<StructInfo> Structs;412 413 /// Maps data location names to types.414 StringMap<AsmTypeInfo> KnownType;415 416 /// Stack of active macro instantiations.417 std::vector<MacroInstantiation*> ActiveMacros;418 419 /// List of bodies of anonymous macros.420 std::deque<MCAsmMacro> MacroLikeBodies;421 422 /// Keeps track of how many .macro's have been instantiated.423 unsigned NumOfMacroInstantiations;424 425 /// The values from the last parsed cpp hash file line comment if any.426 struct CppHashInfoTy {427 StringRef Filename;428 int64_t LineNumber;429 SMLoc Loc;430 unsigned Buf;431 CppHashInfoTy() : LineNumber(0), Buf(0) {}432 };433 CppHashInfoTy CppHashInfo;434 435 /// The filename from the first cpp hash file line comment, if any.436 StringRef FirstCppHashFilename;437 438 /// List of forward directional labels for diagnosis at the end.439 SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;440 441 /// AssemblerDialect. ~OU means unset value and use value provided by MAI.442 /// Defaults to 1U, meaning Intel.443 unsigned AssemblerDialect = 1U;444 445 /// Are we parsing ms-style inline assembly?446 bool ParsingMSInlineAsm = false;447 448 // Current <...> expression depth.449 unsigned AngleBracketDepth = 0U;450 451 // Number of locals defined.452 uint16_t LocalCounter = 0;453 454public:455 MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,456 const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0);457 MasmParser(const MasmParser &) = delete;458 MasmParser &operator=(const MasmParser &) = delete;459 ~MasmParser() override;460 461 bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;462 463 void addDirectiveHandler(StringRef Directive,464 ExtensionDirectiveHandler Handler) override {465 ExtensionDirectiveMap[Directive] = Handler;466 DirectiveKindMap.try_emplace(Directive, DK_HANDLER_DIRECTIVE);467 }468 469 void addAliasForDirective(StringRef Directive, StringRef Alias) override {470 DirectiveKindMap[Directive] = DirectiveKindMap[Alias];471 }472 473 /// @name MCAsmParser Interface474 /// {475 476 unsigned getAssemblerDialect() override {477 if (AssemblerDialect == ~0U)478 return MAI.getAssemblerDialect();479 else480 return AssemblerDialect;481 }482 void setAssemblerDialect(unsigned i) override {483 AssemblerDialect = i;484 }485 486 void Note(SMLoc L, const Twine &Msg, SMRange Range = {}) override;487 bool Warning(SMLoc L, const Twine &Msg, SMRange Range = {}) override;488 bool printError(SMLoc L, const Twine &Msg, SMRange Range = {}) override;489 490 enum ExpandKind { ExpandMacros, DoNotExpandMacros };491 const AsmToken &Lex(ExpandKind ExpandNextToken);492 const AsmToken &Lex() override { return Lex(ExpandMacros); }493 494 void setParsingMSInlineAsm(bool V) override {495 ParsingMSInlineAsm = V;496 // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and497 // hex integer literals.498 Lexer.setLexMasmIntegers(V);499 }500 bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; }501 502 bool isParsingMasm() const override { return true; }503 504 bool defineMacro(StringRef Name, StringRef Value) override;505 506 bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override;507 bool lookUpField(StringRef Base, StringRef Member,508 AsmFieldInfo &Info) const override;509 510 bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override;511 512 bool parseMSInlineAsm(std::string &AsmString, unsigned &NumOutputs,513 unsigned &NumInputs,514 SmallVectorImpl<std::pair<void *, bool>> &OpDecls,515 SmallVectorImpl<std::string> &Constraints,516 SmallVectorImpl<std::string> &Clobbers,517 const MCInstrInfo *MII, MCInstPrinter *IP,518 MCAsmParserSemaCallback &SI) override;519 520 bool parseExpression(const MCExpr *&Res);521 bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;522 bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,523 AsmTypeInfo *TypeInfo) override;524 bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;525 bool parseAbsoluteExpression(int64_t &Res) override;526 527 /// Parse a floating point expression using the float \p Semantics528 /// and set \p Res to the value.529 bool parseRealValue(const fltSemantics &Semantics, APInt &Res);530 531 /// Parse an identifier or string (as a quoted identifier)532 /// and set \p Res to the identifier contents.533 enum IdentifierPositionKind { StandardPosition, StartOfStatement };534 bool parseIdentifier(StringRef &Res, IdentifierPositionKind Position);535 bool parseIdentifier(StringRef &Res) override {536 return parseIdentifier(Res, StandardPosition);537 }538 void eatToEndOfStatement() override;539 540 bool checkForValidSection() override;541 542 /// }543 544private:545 bool expandMacros();546 const AsmToken peekTok(bool ShouldSkipSpace = true);547 548 bool parseStatement(ParseStatementInfo &Info,549 MCAsmParserSemaCallback *SI);550 bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);551 bool parseCppHashLineFilenameComment(SMLoc L);552 553 bool expandMacro(raw_svector_ostream &OS, StringRef Body,554 ArrayRef<MCAsmMacroParameter> Parameters,555 ArrayRef<MCAsmMacroArgument> A,556 const std::vector<std::string> &Locals, SMLoc L);557 558 /// Are we inside a macro instantiation?559 bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}560 561 /// Handle entry to macro instantiation.562 ///563 /// \param M The macro.564 /// \param NameLoc Instantiation location.565 bool handleMacroEntry(566 const MCAsmMacro *M, SMLoc NameLoc,567 AsmToken::TokenKind ArgumentEndTok = AsmToken::EndOfStatement);568 569 /// Handle invocation of macro function.570 ///571 /// \param M The macro.572 /// \param NameLoc Invocation location.573 bool handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc);574 575 /// Handle exit from macro instantiation.576 void handleMacroExit();577 578 /// Extract AsmTokens for a macro argument.579 bool580 parseMacroArgument(const MCAsmMacroParameter *MP, MCAsmMacroArgument &MA,581 AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);582 583 /// Parse all macro arguments for a given macro.584 bool585 parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A,586 AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);587 588 void printMacroInstantiations();589 590 bool expandStatement(SMLoc Loc);591 592 void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,593 SMRange Range = {}) const {594 ArrayRef<SMRange> Ranges(Range);595 SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);596 }597 static void DiagHandler(const SMDiagnostic &Diag, void *Context);598 599 bool lookUpField(const StructInfo &Structure, StringRef Member,600 AsmFieldInfo &Info) const;601 602 /// Enter the specified file. This returns true on failure.603 bool enterIncludeFile(const std::string &Filename);604 605 /// Reset the current lexer position to that given by \p Loc. The606 /// current token is not set; clients should ensure Lex() is called607 /// subsequently.608 ///609 /// \param InBuffer If not 0, should be the known buffer id that contains the610 /// location.611 void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0,612 bool EndStatementAtEOF = true);613 614 /// Parse up to a token of kind \p EndTok and return the contents from the615 /// current token up to (but not including) this token; the current token on616 /// exit will be either this kind or EOF. Reads through instantiated macro617 /// functions and text macros.618 SmallVector<StringRef, 1> parseStringRefsTo(AsmToken::TokenKind EndTok);619 std::string parseStringTo(AsmToken::TokenKind EndTok);620 621 /// Parse up to the end of statement and return the contents from the current622 /// token until the end of the statement; the current token on exit will be623 /// either the EndOfStatement or EOF.624 StringRef parseStringToEndOfStatement() override;625 626 bool parseTextItem(std::string &Data);627 628 unsigned getBinOpPrecedence(AsmToken::TokenKind K,629 MCBinaryExpr::Opcode &Kind);630 631 bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);632 bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);633 bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);634 635 // Generic (target and platform independent) directive parsing.636 enum DirectiveKind {637 DK_NO_DIRECTIVE, // Placeholder638 DK_HANDLER_DIRECTIVE,639 DK_ASSIGN,640 DK_EQU,641 DK_TEXTEQU,642 DK_ASCII,643 DK_ASCIZ,644 DK_STRING,645 DK_BYTE,646 DK_SBYTE,647 DK_WORD,648 DK_SWORD,649 DK_DWORD,650 DK_SDWORD,651 DK_FWORD,652 DK_QWORD,653 DK_SQWORD,654 DK_DB,655 DK_DD,656 DK_DF,657 DK_DQ,658 DK_DW,659 DK_REAL4,660 DK_REAL8,661 DK_REAL10,662 DK_ALIGN,663 DK_EVEN,664 DK_ORG,665 DK_ENDR,666 DK_EXTERN,667 DK_PUBLIC,668 DK_COMM,669 DK_COMMENT,670 DK_INCLUDE,671 DK_REPEAT,672 DK_WHILE,673 DK_FOR,674 DK_FORC,675 DK_IF,676 DK_IFE,677 DK_IFB,678 DK_IFNB,679 DK_IFDEF,680 DK_IFNDEF,681 DK_IFDIF,682 DK_IFDIFI,683 DK_IFIDN,684 DK_IFIDNI,685 DK_ELSEIF,686 DK_ELSEIFE,687 DK_ELSEIFB,688 DK_ELSEIFNB,689 DK_ELSEIFDEF,690 DK_ELSEIFNDEF,691 DK_ELSEIFDIF,692 DK_ELSEIFDIFI,693 DK_ELSEIFIDN,694 DK_ELSEIFIDNI,695 DK_ELSE,696 DK_ENDIF,697 698 DK_MACRO,699 DK_EXITM,700 DK_ENDM,701 DK_PURGE,702 DK_ERR,703 DK_ERRB,704 DK_ERRNB,705 DK_ERRDEF,706 DK_ERRNDEF,707 DK_ERRDIF,708 DK_ERRDIFI,709 DK_ERRIDN,710 DK_ERRIDNI,711 DK_ERRE,712 DK_ERRNZ,713 DK_ECHO,714 DK_STRUCT,715 DK_UNION,716 DK_ENDS,717 DK_END,718 DK_PUSHFRAME,719 DK_PUSHREG,720 DK_SAVEREG,721 DK_SAVEXMM128,722 DK_SETFRAME,723 DK_RADIX,724 };725 726 /// Maps directive name --> DirectiveKind enum, for directives parsed by this727 /// class.728 StringMap<DirectiveKind> DirectiveKindMap;729 730 bool isMacroLikeDirective();731 732 // Generic (target and platform independent) directive parsing.733 enum BuiltinSymbol {734 BI_NO_SYMBOL, // Placeholder735 BI_DATE,736 BI_TIME,737 BI_VERSION,738 BI_FILECUR,739 BI_FILENAME,740 BI_LINE,741 BI_CURSEG,742 BI_CPU,743 BI_INTERFACE,744 BI_CODE,745 BI_DATA,746 BI_FARDATA,747 BI_WORDSIZE,748 BI_CODESIZE,749 BI_DATASIZE,750 BI_MODEL,751 BI_STACK,752 };753 754 /// Maps builtin name --> BuiltinSymbol enum, for builtins handled by this755 /// class.756 StringMap<BuiltinSymbol> BuiltinSymbolMap;757 758 const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc);759 760 std::optional<std::string> evaluateBuiltinTextMacro(BuiltinSymbol Symbol,761 SMLoc StartLoc);762 763 // Generic (target and platform independent) directive parsing.764 enum BuiltinFunction {765 BI_NO_FUNCTION, // Placeholder766 BI_CATSTR,767 };768 769 /// Maps builtin name --> BuiltinFunction enum, for builtins handled by this770 /// class.771 StringMap<BuiltinFunction> BuiltinFunctionMap;772 773 bool evaluateBuiltinMacroFunction(BuiltinFunction Function, StringRef Name,774 std::string &Res);775 776 // ".ascii", ".asciz", ".string"777 bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);778 779 // "byte", "word", ...780 bool emitIntValue(const MCExpr *Value, unsigned Size);781 bool parseScalarInitializer(unsigned Size,782 SmallVectorImpl<const MCExpr *> &Values,783 unsigned StringPadLength = 0);784 bool parseScalarInstList(785 unsigned Size, SmallVectorImpl<const MCExpr *> &Values,786 const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);787 bool emitIntegralValues(unsigned Size, unsigned *Count = nullptr);788 bool addIntegralField(StringRef Name, unsigned Size);789 bool parseDirectiveValue(StringRef IDVal, unsigned Size);790 bool parseDirectiveNamedValue(StringRef TypeName, unsigned Size,791 StringRef Name, SMLoc NameLoc);792 793 // "real4", "real8", "real10"794 bool emitRealValues(const fltSemantics &Semantics, unsigned *Count = nullptr);795 bool addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size);796 bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics,797 size_t Size);798 bool parseRealInstList(799 const fltSemantics &Semantics, SmallVectorImpl<APInt> &Values,800 const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);801 bool parseDirectiveNamedRealValue(StringRef TypeName,802 const fltSemantics &Semantics,803 unsigned Size, StringRef Name,804 SMLoc NameLoc);805 806 bool parseOptionalAngleBracketOpen();807 bool parseAngleBracketClose(const Twine &Msg = "expected '>'");808 809 bool parseFieldInitializer(const FieldInfo &Field,810 FieldInitializer &Initializer);811 bool parseFieldInitializer(const FieldInfo &Field,812 const IntFieldInfo &Contents,813 FieldInitializer &Initializer);814 bool parseFieldInitializer(const FieldInfo &Field,815 const RealFieldInfo &Contents,816 FieldInitializer &Initializer);817 bool parseFieldInitializer(const FieldInfo &Field,818 const StructFieldInfo &Contents,819 FieldInitializer &Initializer);820 821 bool parseStructInitializer(const StructInfo &Structure,822 StructInitializer &Initializer);823 bool parseStructInstList(824 const StructInfo &Structure, std::vector<StructInitializer> &Initializers,825 const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);826 827 bool emitFieldValue(const FieldInfo &Field);828 bool emitFieldValue(const FieldInfo &Field, const IntFieldInfo &Contents);829 bool emitFieldValue(const FieldInfo &Field, const RealFieldInfo &Contents);830 bool emitFieldValue(const FieldInfo &Field, const StructFieldInfo &Contents);831 832 bool emitFieldInitializer(const FieldInfo &Field,833 const FieldInitializer &Initializer);834 bool emitFieldInitializer(const FieldInfo &Field,835 const IntFieldInfo &Contents,836 const IntFieldInfo &Initializer);837 bool emitFieldInitializer(const FieldInfo &Field,838 const RealFieldInfo &Contents,839 const RealFieldInfo &Initializer);840 bool emitFieldInitializer(const FieldInfo &Field,841 const StructFieldInfo &Contents,842 const StructFieldInfo &Initializer);843 844 bool emitStructInitializer(const StructInfo &Structure,845 const StructInitializer &Initializer);846 847 // User-defined types (structs, unions):848 bool emitStructValues(const StructInfo &Structure, unsigned *Count = nullptr);849 bool addStructField(StringRef Name, const StructInfo &Structure);850 bool parseDirectiveStructValue(const StructInfo &Structure,851 StringRef Directive, SMLoc DirLoc);852 bool parseDirectiveNamedStructValue(const StructInfo &Structure,853 StringRef Directive, SMLoc DirLoc,854 StringRef Name);855 856 // "=", "equ", "textequ"857 bool parseDirectiveEquate(StringRef IDVal, StringRef Name,858 DirectiveKind DirKind, SMLoc NameLoc);859 860 bool parseDirectiveOrg(); // "org"861 862 bool emitAlignTo(int64_t Alignment);863 bool parseDirectiveAlign(); // "align"864 bool parseDirectiveEven(); // "even"865 866 // macro directives867 bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);868 bool parseDirectiveExitMacro(SMLoc DirectiveLoc, StringRef Directive,869 std::string &Value);870 bool parseDirectiveEndMacro(StringRef Directive);871 bool parseDirectiveMacro(StringRef Name, SMLoc NameLoc);872 873 bool parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind,874 StringRef Name, SMLoc NameLoc);875 bool parseDirectiveNestedStruct(StringRef Directive, DirectiveKind DirKind);876 bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc);877 bool parseDirectiveNestedEnds();878 879 bool parseDirectiveExtern();880 881 /// Parse a directive like ".globl" which accepts a single symbol (which882 /// should be a label or an external).883 bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);884 885 bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"886 887 bool parseDirectiveComment(SMLoc DirectiveLoc); // "comment"888 889 bool parseDirectiveInclude(); // "include"890 891 // "if" or "ife"892 bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);893 // "ifb" or "ifnb", depending on ExpectBlank.894 bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);895 // "ifidn", "ifdif", "ifidni", or "ifdifi", depending on ExpectEqual and896 // CaseInsensitive.897 bool parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,898 bool CaseInsensitive);899 // "ifdef" or "ifndef", depending on expect_defined900 bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);901 // "elseif" or "elseife"902 bool parseDirectiveElseIf(SMLoc DirectiveLoc, DirectiveKind DirKind);903 // "elseifb" or "elseifnb", depending on ExpectBlank.904 bool parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank);905 // ".elseifdef" or ".elseifndef", depending on expect_defined906 bool parseDirectiveElseIfdef(SMLoc DirectiveLoc, bool expect_defined);907 // "elseifidn", "elseifdif", "elseifidni", or "elseifdifi", depending on908 // ExpectEqual and CaseInsensitive.909 bool parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,910 bool CaseInsensitive);911 bool parseDirectiveElse(SMLoc DirectiveLoc); // "else"912 bool parseDirectiveEndIf(SMLoc DirectiveLoc); // "endif"913 bool parseEscapedString(std::string &Data) override;914 bool parseAngleBracketString(std::string &Data) override;915 916 // Macro-like directives917 MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);918 void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,919 raw_svector_ostream &OS);920 void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,921 SMLoc ExitLoc, raw_svector_ostream &OS);922 bool parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Directive);923 bool parseDirectiveFor(SMLoc DirectiveLoc, StringRef Directive);924 bool parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive);925 bool parseDirectiveWhile(SMLoc DirectiveLoc);926 927 // "_emit" or "__emit"928 bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,929 size_t Len);930 931 // "align"932 bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);933 934 // "end"935 bool parseDirectiveEnd(SMLoc DirectiveLoc);936 937 // ".err"938 bool parseDirectiveError(SMLoc DirectiveLoc);939 // ".errb" or ".errnb", depending on ExpectBlank.940 bool parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank);941 // ".errdef" or ".errndef", depending on ExpectBlank.942 bool parseDirectiveErrorIfdef(SMLoc DirectiveLoc, bool ExpectDefined);943 // ".erridn", ".errdif", ".erridni", or ".errdifi", depending on ExpectEqual944 // and CaseInsensitive.945 bool parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,946 bool CaseInsensitive);947 // ".erre" or ".errnz", depending on ExpectZero.948 bool parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero);949 950 // ".radix"951 bool parseDirectiveRadix(SMLoc DirectiveLoc);952 953 // "echo"954 bool parseDirectiveEcho(SMLoc DirectiveLoc);955 956 void initializeDirectiveKindMap();957 void initializeBuiltinSymbolMaps();958};959 960} // end anonymous namespace961 962namespace llvm {963 964extern cl::opt<unsigned> AsmMacroMaxNestingDepth;965 966} // end namespace llvm967 968enum { DEFAULT_ADDRSPACE = 0 };969 970MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,971 const MCAsmInfo &MAI, struct tm TM, unsigned CB)972 : MCAsmParser(Ctx, Out, SM, MAI), CurBuffer(CB ? CB : SM.getMainFileID()),973 TM(TM) {974 HadError = false;975 // Save the old handler.976 SavedDiagHandler = SrcMgr.getDiagHandler();977 SavedDiagContext = SrcMgr.getDiagContext();978 // Set our own handler which calls the saved handler.979 SrcMgr.setDiagHandler(DiagHandler, this);980 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());981 EndStatementAtEOFStack.push_back(true);982 983 // Initialize the platform / file format parser.984 switch (Ctx.getObjectFileType()) {985 case MCContext::IsCOFF:986 PlatformParser.reset(createCOFFMasmParser());987 break;988 default:989 report_fatal_error("llvm-ml currently supports only COFF output.");990 break;991 }992 993 initializeDirectiveKindMap();994 PlatformParser->Initialize(*this);995 initializeBuiltinSymbolMaps();996 997 NumOfMacroInstantiations = 0;998}999 1000MasmParser::~MasmParser() {1001 assert((HadError || ActiveMacros.empty()) &&1002 "Unexpected active macro instantiation!");1003 1004 // Restore the saved diagnostics handler and context for use during1005 // finalization.1006 SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);1007}1008 1009void MasmParser::printMacroInstantiations() {1010 // Print the active macro instantiation stack.1011 for (std::vector<MacroInstantiation *>::const_reverse_iterator1012 it = ActiveMacros.rbegin(),1013 ie = ActiveMacros.rend();1014 it != ie; ++it)1015 printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,1016 "while in macro instantiation");1017}1018 1019void MasmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {1020 printPendingErrors();1021 printMessage(L, SourceMgr::DK_Note, Msg, Range);1022 printMacroInstantiations();1023}1024 1025bool MasmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {1026 if (getTargetParser().getTargetOptions().MCNoWarn)1027 return false;1028 if (getTargetParser().getTargetOptions().MCFatalWarnings)1029 return Error(L, Msg, Range);1030 printMessage(L, SourceMgr::DK_Warning, Msg, Range);1031 printMacroInstantiations();1032 return false;1033}1034 1035bool MasmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {1036 HadError = true;1037 printMessage(L, SourceMgr::DK_Error, Msg, Range);1038 printMacroInstantiations();1039 return true;1040}1041 1042bool MasmParser::enterIncludeFile(const std::string &Filename) {1043 std::string IncludedFile;1044 unsigned NewBuf =1045 SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);1046 if (!NewBuf)1047 return true;1048 1049 CurBuffer = NewBuf;1050 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());1051 EndStatementAtEOFStack.push_back(true);1052 return false;1053}1054 1055void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer,1056 bool EndStatementAtEOF) {1057 CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);1058 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),1059 Loc.getPointer(), EndStatementAtEOF);1060}1061 1062bool MasmParser::expandMacros() {1063 const AsmToken &Tok = getTok();1064 const std::string IDLower = Tok.getIdentifier().lower();1065 1066 const llvm::MCAsmMacro *M = getContext().lookupMacro(IDLower);1067 if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) {1068 // This is a macro function invocation; expand it in place.1069 const SMLoc MacroLoc = Tok.getLoc();1070 const StringRef MacroId = Tok.getIdentifier();1071 Lexer.Lex();1072 if (handleMacroInvocation(M, MacroLoc)) {1073 Lexer.UnLex(AsmToken(AsmToken::Error, MacroId));1074 Lexer.Lex();1075 }1076 return false;1077 }1078 1079 std::optional<std::string> ExpandedValue;1080 1081 if (auto BuiltinIt = BuiltinSymbolMap.find(IDLower);1082 BuiltinIt != BuiltinSymbolMap.end()) {1083 ExpandedValue =1084 evaluateBuiltinTextMacro(BuiltinIt->getValue(), Tok.getLoc());1085 } else if (auto BuiltinFuncIt = BuiltinFunctionMap.find(IDLower);1086 BuiltinFuncIt != BuiltinFunctionMap.end()) {1087 StringRef Name;1088 if (parseIdentifier(Name)) {1089 return true;1090 }1091 std::string Res;1092 if (evaluateBuiltinMacroFunction(BuiltinFuncIt->getValue(), Name, Res)) {1093 return true;1094 }1095 ExpandedValue = Res;1096 } else if (auto VarIt = Variables.find(IDLower);1097 VarIt != Variables.end() && VarIt->getValue().IsText) {1098 ExpandedValue = VarIt->getValue().TextValue;1099 }1100 1101 if (!ExpandedValue)1102 return true;1103 std::unique_ptr<MemoryBuffer> Instantiation =1104 MemoryBuffer::getMemBufferCopy(*ExpandedValue, "<instantiation>");1105 1106 // Jump to the macro instantiation and prime the lexer.1107 CurBuffer =1108 SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());1109 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,1110 /*EndStatementAtEOF=*/false);1111 EndStatementAtEOFStack.push_back(false);1112 Lexer.Lex();1113 return false;1114}1115 1116const AsmToken &MasmParser::Lex(ExpandKind ExpandNextToken) {1117 if (Lexer.getTok().is(AsmToken::Error))1118 Error(Lexer.getErrLoc(), Lexer.getErr());1119 bool StartOfStatement = false;1120 1121 // if it's a end of statement with a comment in it1122 if (getTok().is(AsmToken::EndOfStatement)) {1123 // if this is a line comment output it.1124 if (!getTok().getString().empty() && getTok().getString().front() != '\n' &&1125 getTok().getString().front() != '\r' && MAI.preserveAsmComments())1126 Out.addExplicitComment(Twine(getTok().getString()));1127 StartOfStatement = true;1128 }1129 1130 const AsmToken *tok = &Lexer.Lex();1131 1132 while (ExpandNextToken == ExpandMacros && tok->is(AsmToken::Identifier)) {1133 if (StartOfStatement) {1134 AsmToken NextTok;1135 MutableArrayRef<AsmToken> Buf(NextTok);1136 size_t ReadCount = Lexer.peekTokens(Buf);1137 if (ReadCount && NextTok.is(AsmToken::Identifier) &&1138 (NextTok.getString().equals_insensitive("equ") ||1139 NextTok.getString().equals_insensitive("textequ"))) {1140 // This looks like an EQU or TEXTEQU directive; don't expand the1141 // identifier, allowing for redefinitions.1142 break;1143 }1144 }1145 if (expandMacros())1146 break;1147 }1148 1149 // Parse comments here to be deferred until end of next statement.1150 while (tok->is(AsmToken::Comment)) {1151 if (MAI.preserveAsmComments())1152 Out.addExplicitComment(Twine(tok->getString()));1153 tok = &Lexer.Lex();1154 }1155 1156 // Recognize and bypass line continuations.1157 while (tok->is(AsmToken::BackSlash) &&1158 peekTok().is(AsmToken::EndOfStatement)) {1159 // Eat both the backslash and the end of statement.1160 Lexer.Lex();1161 tok = &Lexer.Lex();1162 }1163 1164 if (tok->is(AsmToken::Eof)) {1165 // If this is the end of an included file, pop the parent file off the1166 // include stack.1167 SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1168 if (ParentIncludeLoc != SMLoc()) {1169 EndStatementAtEOFStack.pop_back();1170 jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1171 return Lex();1172 }1173 EndStatementAtEOFStack.pop_back();1174 assert(EndStatementAtEOFStack.empty());1175 }1176 1177 return *tok;1178}1179 1180const AsmToken MasmParser::peekTok(bool ShouldSkipSpace) {1181 AsmToken Tok;1182 1183 MutableArrayRef<AsmToken> Buf(Tok);1184 size_t ReadCount = Lexer.peekTokens(Buf, ShouldSkipSpace);1185 1186 if (ReadCount == 0) {1187 // If this is the end of an included file, pop the parent file off the1188 // include stack.1189 SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1190 if (ParentIncludeLoc != SMLoc()) {1191 EndStatementAtEOFStack.pop_back();1192 jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1193 return peekTok(ShouldSkipSpace);1194 }1195 EndStatementAtEOFStack.pop_back();1196 assert(EndStatementAtEOFStack.empty());1197 }1198 1199 assert(ReadCount == 1);1200 return Tok;1201}1202 1203bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize) {1204 // Create the initial section, if requested.1205 if (!NoInitialTextSection)1206 Out.initSections(false, getTargetParser().getSTI());1207 1208 // Prime the lexer.1209 Lex();1210 1211 HadError = false;1212 AsmCond StartingCondState = TheCondState;1213 SmallVector<AsmRewrite, 4> AsmStrRewrites;1214 1215 // While we have input, parse each statement.1216 while (Lexer.isNot(AsmToken::Eof) ||1217 SrcMgr.getParentIncludeLoc(CurBuffer) != SMLoc()) {1218 // Skip through the EOF at the end of an inclusion.1219 if (Lexer.is(AsmToken::Eof))1220 Lex();1221 1222 ParseStatementInfo Info(&AsmStrRewrites);1223 bool HasError = parseStatement(Info, nullptr);1224 1225 // If we have a Lexer Error we are on an Error Token. Load in Lexer Error1226 // for printing ErrMsg via Lex() only if no (presumably better) parser error1227 // exists.1228 if (HasError && !hasPendingError() && Lexer.getTok().is(AsmToken::Error))1229 Lex();1230 1231 // parseStatement returned true so may need to emit an error.1232 printPendingErrors();1233 1234 // Skipping to the next line if needed.1235 if (HasError && !getLexer().justConsumedEOL())1236 eatToEndOfStatement();1237 }1238 1239 printPendingErrors();1240 1241 // All errors should have been emitted.1242 assert(!hasPendingError() && "unexpected error from parseStatement");1243 1244 if (TheCondState.TheCond != StartingCondState.TheCond ||1245 TheCondState.Ignore != StartingCondState.Ignore)1246 printError(getTok().getLoc(), "unmatched .ifs or .elses");1247 1248 // Check to see that all assembler local symbols were actually defined.1249 // Targets that don't do subsections via symbols may not want this, though,1250 // so conservatively exclude them. Only do this if we're finalizing, though,1251 // as otherwise we won't necessarily have seen everything yet.1252 if (!NoFinalize) {1253 // Temporary symbols like the ones for directional jumps don't go in the1254 // symbol table. They also need to be diagnosed in all (final) cases.1255 for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {1256 if (std::get<2>(LocSym)->isUndefined()) {1257 // Reset the state of any "# line file" directives we've seen to the1258 // context as it was at the diagnostic site.1259 CppHashInfo = std::get<1>(LocSym);1260 printError(std::get<0>(LocSym), "directional label undefined");1261 }1262 }1263 }1264 1265 // Finalize the output stream if there are no errors and if the client wants1266 // us to.1267 if (!HadError && !NoFinalize)1268 Out.finish(Lexer.getLoc());1269 1270 return HadError || getContext().hadError();1271}1272 1273bool MasmParser::checkForValidSection() {1274 if (!ParsingMSInlineAsm && !(getStreamer().getCurrentFragment() &&1275 getStreamer().getCurrentSectionOnly())) {1276 Out.initSections(false, getTargetParser().getSTI());1277 return Error(getTok().getLoc(),1278 "expected section directive before assembly directive");1279 }1280 return false;1281}1282 1283/// Throw away the rest of the line for testing purposes.1284void MasmParser::eatToEndOfStatement() {1285 while (Lexer.isNot(AsmToken::EndOfStatement)) {1286 if (Lexer.is(AsmToken::Eof)) {1287 SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1288 if (ParentIncludeLoc == SMLoc()) {1289 break;1290 }1291 1292 EndStatementAtEOFStack.pop_back();1293 jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1294 }1295 1296 Lexer.Lex();1297 }1298 1299 // Eat EOL.1300 if (Lexer.is(AsmToken::EndOfStatement))1301 Lexer.Lex();1302}1303 1304SmallVector<StringRef, 1>1305MasmParser::parseStringRefsTo(AsmToken::TokenKind EndTok) {1306 SmallVector<StringRef, 1> Refs;1307 const char *Start = getTok().getLoc().getPointer();1308 while (Lexer.isNot(EndTok)) {1309 if (Lexer.is(AsmToken::Eof)) {1310 SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1311 if (ParentIncludeLoc == SMLoc()) {1312 break;1313 }1314 Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);1315 1316 EndStatementAtEOFStack.pop_back();1317 jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1318 Lexer.Lex();1319 Start = getTok().getLoc().getPointer();1320 } else {1321 Lexer.Lex();1322 }1323 }1324 Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);1325 return Refs;1326}1327 1328std::string MasmParser::parseStringTo(AsmToken::TokenKind EndTok) {1329 SmallVector<StringRef, 1> Refs = parseStringRefsTo(EndTok);1330 std::string Str;1331 for (StringRef S : Refs) {1332 Str.append(S.str());1333 }1334 return Str;1335}1336 1337StringRef MasmParser::parseStringToEndOfStatement() {1338 const char *Start = getTok().getLoc().getPointer();1339 1340 while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))1341 Lexer.Lex();1342 1343 const char *End = getTok().getLoc().getPointer();1344 return StringRef(Start, End - Start);1345}1346 1347/// Parse a paren expression and return it.1348/// NOTE: This assumes the leading '(' has already been consumed.1349///1350/// parenexpr ::= expr)1351///1352bool MasmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {1353 if (parseExpression(Res))1354 return true;1355 EndLoc = Lexer.getTok().getEndLoc();1356 return parseRParen();1357}1358 1359/// Parse a bracket expression and return it.1360/// NOTE: This assumes the leading '[' has already been consumed.1361///1362/// bracketexpr ::= expr]1363///1364bool MasmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {1365 if (parseExpression(Res))1366 return true;1367 EndLoc = getTok().getEndLoc();1368 if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))1369 return true;1370 return false;1371}1372 1373/// Parse a primary expression and return it.1374/// primaryexpr ::= (parenexpr1375/// primaryexpr ::= symbol1376/// primaryexpr ::= number1377/// primaryexpr ::= '.'1378/// primaryexpr ::= ~,+,-,'not' primaryexpr1379/// primaryexpr ::= string1380/// (a string is interpreted as a 64-bit number in big-endian base-256)1381bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,1382 AsmTypeInfo *TypeInfo) {1383 SMLoc FirstTokenLoc = getLexer().getLoc();1384 AsmToken::TokenKind FirstTokenKind = Lexer.getKind();1385 switch (FirstTokenKind) {1386 default:1387 return TokError("unknown token in expression");1388 // If we have an error assume that we've already handled it.1389 case AsmToken::Error:1390 return true;1391 case AsmToken::Exclaim:1392 Lex(); // Eat the operator.1393 if (parsePrimaryExpr(Res, EndLoc, nullptr))1394 return true;1395 Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);1396 return false;1397 case AsmToken::Dollar:1398 case AsmToken::At:1399 case AsmToken::Identifier: {1400 StringRef Identifier;1401 if (parseIdentifier(Identifier)) {1402 // We may have failed but $ may be a valid token.1403 if (getTok().is(AsmToken::Dollar)) {1404 if (Lexer.getMAI().getDollarIsPC()) {1405 Lex();1406 // This is a '$' reference, which references the current PC. Emit a1407 // temporary label to the streamer and refer to it.1408 MCSymbol *Sym = Ctx.createTempSymbol();1409 Out.emitLabel(Sym);1410 Res = MCSymbolRefExpr::create(Sym, getContext());1411 EndLoc = FirstTokenLoc;1412 return false;1413 }1414 return Error(FirstTokenLoc, "invalid token in expression");1415 }1416 }1417 // Parse named bitwise negation.1418 if (Identifier.equals_insensitive("not")) {1419 if (parsePrimaryExpr(Res, EndLoc, nullptr))1420 return true;1421 Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1422 return false;1423 }1424 // Parse directional local label references.1425 if (Identifier.equals_insensitive("@b") ||1426 Identifier.equals_insensitive("@f")) {1427 bool Before = Identifier.equals_insensitive("@b");1428 MCSymbol *Sym = getContext().getDirectionalLocalSymbol(0, Before);1429 if (Before && Sym->isUndefined())1430 return Error(FirstTokenLoc, "Expected @@ label before @B reference");1431 Res = MCSymbolRefExpr::create(Sym, getContext());1432 return false;1433 }1434 1435 EndLoc = SMLoc::getFromPointer(Identifier.end());1436 1437 // This is a symbol reference.1438 StringRef SymbolName = Identifier;1439 if (SymbolName.empty())1440 return Error(getLexer().getLoc(), "expected a symbol reference");1441 1442 // Find the field offset if used.1443 AsmFieldInfo Info;1444 auto Split = SymbolName.split('.');1445 if (Split.second.empty()) {1446 } else {1447 SymbolName = Split.first;1448 if (lookUpField(SymbolName, Split.second, Info)) {1449 std::pair<StringRef, StringRef> BaseMember = Split.second.split('.');1450 StringRef Base = BaseMember.first, Member = BaseMember.second;1451 lookUpField(Base, Member, Info);1452 } else if (Structs.count(SymbolName.lower())) {1453 // This is actually a reference to a field offset.1454 Res = MCConstantExpr::create(Info.Offset, getContext());1455 return false;1456 }1457 }1458 1459 MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);1460 if (!Sym) {1461 // If this is a built-in numeric value, treat it as a constant.1462 auto BuiltinIt = BuiltinSymbolMap.find(SymbolName.lower());1463 const BuiltinSymbol Symbol = (BuiltinIt == BuiltinSymbolMap.end())1464 ? BI_NO_SYMBOL1465 : BuiltinIt->getValue();1466 if (Symbol != BI_NO_SYMBOL) {1467 const MCExpr *Value = evaluateBuiltinValue(Symbol, FirstTokenLoc);1468 if (Value) {1469 Res = Value;1470 return false;1471 }1472 }1473 1474 // Variables use case-insensitive symbol names; if this is a variable, we1475 // find the symbol using its canonical name.1476 auto VarIt = Variables.find(SymbolName.lower());1477 if (VarIt != Variables.end())1478 SymbolName = VarIt->second.Name;1479 Sym = getContext().parseSymbol(SymbolName);1480 }1481 1482 // If this is an absolute variable reference, substitute it now to preserve1483 // semantics in the face of reassignment.1484 if (Sym->isVariable()) {1485 auto V = Sym->getVariableValue();1486 bool DoInline = isa<MCConstantExpr>(V);1487 if (auto TV = dyn_cast<MCTargetExpr>(V))1488 DoInline = TV->inlineAssignedExpr();1489 if (DoInline) {1490 Res = Sym->getVariableValue();1491 return false;1492 }1493 }1494 1495 // Otherwise create a symbol ref.1496 const MCExpr *SymRef =1497 MCSymbolRefExpr::create(Sym, getContext(), FirstTokenLoc);1498 if (Info.Offset) {1499 Res = MCBinaryExpr::create(1500 MCBinaryExpr::Add, SymRef,1501 MCConstantExpr::create(Info.Offset, getContext()), getContext());1502 } else {1503 Res = SymRef;1504 }1505 if (TypeInfo) {1506 if (Info.Type.Name.empty()) {1507 auto TypeIt = KnownType.find(Identifier.lower());1508 if (TypeIt != KnownType.end()) {1509 Info.Type = TypeIt->second;1510 }1511 }1512 1513 *TypeInfo = Info.Type;1514 }1515 return false;1516 }1517 case AsmToken::BigNum:1518 return TokError("literal value out of range for directive");1519 case AsmToken::Integer: {1520 int64_t IntVal = getTok().getIntVal();1521 Res = MCConstantExpr::create(IntVal, getContext());1522 EndLoc = Lexer.getTok().getEndLoc();1523 Lex(); // Eat token.1524 return false;1525 }1526 case AsmToken::String: {1527 // MASM strings (used as constants) are interpreted as big-endian base-256.1528 SMLoc ValueLoc = getTok().getLoc();1529 std::string Value;1530 if (parseEscapedString(Value))1531 return true;1532 if (Value.size() > 8)1533 return Error(ValueLoc, "literal value out of range");1534 uint64_t IntValue = 0;1535 for (const unsigned char CharVal : Value)1536 IntValue = (IntValue << 8) | CharVal;1537 Res = MCConstantExpr::create(IntValue, getContext());1538 return false;1539 }1540 case AsmToken::Real: {1541 APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());1542 uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();1543 Res = MCConstantExpr::create(IntVal, getContext());1544 EndLoc = Lexer.getTok().getEndLoc();1545 Lex(); // Eat token.1546 return false;1547 }1548 case AsmToken::Dot: {1549 // This is a '.' reference, which references the current PC. Emit a1550 // temporary label to the streamer and refer to it.1551 MCSymbol *Sym = Ctx.createTempSymbol();1552 Out.emitLabel(Sym);1553 Res = MCSymbolRefExpr::create(Sym, getContext());1554 EndLoc = Lexer.getTok().getEndLoc();1555 Lex(); // Eat identifier.1556 return false;1557 }1558 case AsmToken::LParen:1559 Lex(); // Eat the '('.1560 return parseParenExpr(Res, EndLoc);1561 case AsmToken::LBrac:1562 if (!PlatformParser->HasBracketExpressions())1563 return TokError("brackets expression not supported on this target");1564 Lex(); // Eat the '['.1565 return parseBracketExpr(Res, EndLoc);1566 case AsmToken::Minus:1567 Lex(); // Eat the operator.1568 if (parsePrimaryExpr(Res, EndLoc, nullptr))1569 return true;1570 Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc);1571 return false;1572 case AsmToken::Plus:1573 Lex(); // Eat the operator.1574 if (parsePrimaryExpr(Res, EndLoc, nullptr))1575 return true;1576 Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);1577 return false;1578 case AsmToken::Tilde:1579 Lex(); // Eat the operator.1580 if (parsePrimaryExpr(Res, EndLoc, nullptr))1581 return true;1582 Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1583 return false;1584 }1585}1586 1587bool MasmParser::parseExpression(const MCExpr *&Res) {1588 SMLoc EndLoc;1589 return parseExpression(Res, EndLoc);1590}1591 1592/// This function checks if the next token is <string> type or arithmetic.1593/// string that begin with character '<' must end with character '>'.1594/// otherwise it is arithmetics.1595/// If the function returns a 'true' value,1596/// the End argument will be filled with the last location pointed to the '>'1597/// character.1598static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {1599 assert((StrLoc.getPointer() != nullptr) &&1600 "Argument to the function cannot be a NULL value");1601 const char *CharPtr = StrLoc.getPointer();1602 while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') &&1603 (*CharPtr != '\0')) {1604 if (*CharPtr == '!')1605 CharPtr++;1606 CharPtr++;1607 }1608 if (*CharPtr == '>') {1609 EndLoc = StrLoc.getFromPointer(CharPtr + 1);1610 return true;1611 }1612 return false;1613}1614 1615/// creating a string without the escape characters '!'.1616static std::string angleBracketString(StringRef BracketContents) {1617 std::string Res;1618 for (size_t Pos = 0; Pos < BracketContents.size(); Pos++) {1619 if (BracketContents[Pos] == '!')1620 Pos++;1621 Res += BracketContents[Pos];1622 }1623 return Res;1624}1625 1626/// Parse an expression and return it.1627///1628/// expr ::= expr &&,|| expr -> lowest.1629/// expr ::= expr |,^,&,! expr1630/// expr ::= expr ==,!=,<>,<,<=,>,>= expr1631/// expr ::= expr <<,>> expr1632/// expr ::= expr +,- expr1633/// expr ::= expr *,/,% expr -> highest.1634/// expr ::= primaryexpr1635///1636bool MasmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {1637 // Parse the expression.1638 Res = nullptr;1639 if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||1640 parseBinOpRHS(1, Res, EndLoc))1641 return true;1642 1643 // Try to constant fold it up front, if possible. Do not exploit1644 // assembler here.1645 int64_t Value;1646 if (Res->evaluateAsAbsolute(Value))1647 Res = MCConstantExpr::create(Value, getContext());1648 1649 return false;1650}1651 1652bool MasmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {1653 Res = nullptr;1654 return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);1655}1656 1657bool MasmParser::parseAbsoluteExpression(int64_t &Res) {1658 const MCExpr *Expr;1659 1660 SMLoc StartLoc = Lexer.getLoc();1661 if (parseExpression(Expr))1662 return true;1663 1664 if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))1665 return Error(StartLoc, "expected absolute expression");1666 1667 return false;1668}1669 1670static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,1671 MCBinaryExpr::Opcode &Kind,1672 bool ShouldUseLogicalShr,1673 bool EndExpressionAtGreater) {1674 switch (K) {1675 default:1676 return 0; // not a binop.1677 1678 // Lowest Precedence: &&, ||1679 case AsmToken::AmpAmp:1680 Kind = MCBinaryExpr::LAnd;1681 return 2;1682 case AsmToken::PipePipe:1683 Kind = MCBinaryExpr::LOr;1684 return 1;1685 1686 // Low Precedence: ==, !=, <>, <, <=, >, >=1687 case AsmToken::EqualEqual:1688 Kind = MCBinaryExpr::EQ;1689 return 3;1690 case AsmToken::ExclaimEqual:1691 case AsmToken::LessGreater:1692 Kind = MCBinaryExpr::NE;1693 return 3;1694 case AsmToken::Less:1695 Kind = MCBinaryExpr::LT;1696 return 3;1697 case AsmToken::LessEqual:1698 Kind = MCBinaryExpr::LTE;1699 return 3;1700 case AsmToken::Greater:1701 if (EndExpressionAtGreater)1702 return 0;1703 Kind = MCBinaryExpr::GT;1704 return 3;1705 case AsmToken::GreaterEqual:1706 Kind = MCBinaryExpr::GTE;1707 return 3;1708 1709 // Low Intermediate Precedence: +, -1710 case AsmToken::Plus:1711 Kind = MCBinaryExpr::Add;1712 return 4;1713 case AsmToken::Minus:1714 Kind = MCBinaryExpr::Sub;1715 return 4;1716 1717 // High Intermediate Precedence: |, &, ^1718 case AsmToken::Pipe:1719 Kind = MCBinaryExpr::Or;1720 return 5;1721 case AsmToken::Caret:1722 Kind = MCBinaryExpr::Xor;1723 return 5;1724 case AsmToken::Amp:1725 Kind = MCBinaryExpr::And;1726 return 5;1727 1728 // Highest Precedence: *, /, %, <<, >>1729 case AsmToken::Star:1730 Kind = MCBinaryExpr::Mul;1731 return 6;1732 case AsmToken::Slash:1733 Kind = MCBinaryExpr::Div;1734 return 6;1735 case AsmToken::Percent:1736 Kind = MCBinaryExpr::Mod;1737 return 6;1738 case AsmToken::LessLess:1739 Kind = MCBinaryExpr::Shl;1740 return 6;1741 case AsmToken::GreaterGreater:1742 if (EndExpressionAtGreater)1743 return 0;1744 Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;1745 return 6;1746 }1747}1748 1749unsigned MasmParser::getBinOpPrecedence(AsmToken::TokenKind K,1750 MCBinaryExpr::Opcode &Kind) {1751 bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();1752 return getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr,1753 AngleBracketDepth > 0);1754}1755 1756/// Parse all binary operators with precedence >= 'Precedence'.1757/// Res contains the LHS of the expression on input.1758bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,1759 SMLoc &EndLoc) {1760 SMLoc StartLoc = Lexer.getLoc();1761 while (true) {1762 AsmToken::TokenKind TokKind = Lexer.getKind();1763 if (Lexer.getKind() == AsmToken::Identifier) {1764 TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString())1765 .CaseLower("and", AsmToken::Amp)1766 .CaseLower("not", AsmToken::Exclaim)1767 .CaseLower("or", AsmToken::Pipe)1768 .CaseLower("xor", AsmToken::Caret)1769 .CaseLower("shl", AsmToken::LessLess)1770 .CaseLower("shr", AsmToken::GreaterGreater)1771 .CaseLower("eq", AsmToken::EqualEqual)1772 .CaseLower("ne", AsmToken::ExclaimEqual)1773 .CaseLower("lt", AsmToken::Less)1774 .CaseLower("le", AsmToken::LessEqual)1775 .CaseLower("gt", AsmToken::Greater)1776 .CaseLower("ge", AsmToken::GreaterEqual)1777 .Default(TokKind);1778 }1779 MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;1780 unsigned TokPrec = getBinOpPrecedence(TokKind, Kind);1781 1782 // If the next token is lower precedence than we are allowed to eat, return1783 // successfully with what we ate already.1784 if (TokPrec < Precedence)1785 return false;1786 1787 Lex();1788 1789 // Eat the next primary expression.1790 const MCExpr *RHS;1791 if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))1792 return true;1793 1794 // If BinOp binds less tightly with RHS than the operator after RHS, let1795 // the pending operator take RHS as its LHS.1796 MCBinaryExpr::Opcode Dummy;1797 unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);1798 if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))1799 return true;1800 1801 // Merge LHS and RHS according to operator.1802 Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc);1803 }1804}1805 1806/// ParseStatement:1807/// ::= % statement1808/// ::= EndOfStatement1809/// ::= Label* Directive ...Operands... EndOfStatement1810/// ::= Label* Identifier OperandList* EndOfStatement1811bool MasmParser::parseStatement(ParseStatementInfo &Info,1812 MCAsmParserSemaCallback *SI) {1813 assert(!hasPendingError() && "parseStatement started with pending error");1814 // Eat initial spaces and comments.1815 while (Lexer.is(AsmToken::Space))1816 Lex();1817 if (Lexer.is(AsmToken::EndOfStatement)) {1818 // If this is a line comment we can drop it safely.1819 if (getTok().getString().empty() || getTok().getString().front() == '\r' ||1820 getTok().getString().front() == '\n')1821 Out.addBlankLine();1822 Lex();1823 return false;1824 }1825 1826 // If preceded by an expansion operator, first expand all text macros and1827 // macro functions.1828 if (getTok().is(AsmToken::Percent)) {1829 SMLoc ExpansionLoc = getTok().getLoc();1830 if (parseToken(AsmToken::Percent) || expandStatement(ExpansionLoc))1831 return true;1832 }1833 1834 // Statements always start with an identifier, unless we're dealing with a1835 // processor directive (.386, .686, etc.) that lexes as a real.1836 AsmToken ID = getTok();1837 SMLoc IDLoc = ID.getLoc();1838 StringRef IDVal;1839 if (Lexer.is(AsmToken::HashDirective))1840 return parseCppHashLineFilenameComment(IDLoc);1841 if (Lexer.is(AsmToken::Dot)) {1842 // Treat '.' as a valid identifier in this context.1843 Lex();1844 IDVal = ".";1845 } else if (Lexer.is(AsmToken::Real)) {1846 // Treat ".<number>" as a valid identifier in this context.1847 IDVal = getTok().getString();1848 Lex(); // always eat a token1849 if (!IDVal.starts_with("."))1850 return Error(IDLoc, "unexpected token at start of statement");1851 } else if (parseIdentifier(IDVal, StartOfStatement)) {1852 if (!TheCondState.Ignore) {1853 Lex(); // always eat a token1854 return Error(IDLoc, "unexpected token at start of statement");1855 }1856 IDVal = "";1857 }1858 1859 // Handle conditional assembly here before checking for skipping. We1860 // have to do this so that .endif isn't skipped in a ".if 0" block for1861 // example.1862 StringMap<DirectiveKind>::const_iterator DirKindIt =1863 DirectiveKindMap.find(IDVal.lower());1864 DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())1865 ? DK_NO_DIRECTIVE1866 : DirKindIt->getValue();1867 switch (DirKind) {1868 default:1869 break;1870 case DK_IF:1871 case DK_IFE:1872 return parseDirectiveIf(IDLoc, DirKind);1873 case DK_IFB:1874 return parseDirectiveIfb(IDLoc, true);1875 case DK_IFNB:1876 return parseDirectiveIfb(IDLoc, false);1877 case DK_IFDEF:1878 return parseDirectiveIfdef(IDLoc, true);1879 case DK_IFNDEF:1880 return parseDirectiveIfdef(IDLoc, false);1881 case DK_IFDIF:1882 return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,1883 /*CaseInsensitive=*/false);1884 case DK_IFDIFI:1885 return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,1886 /*CaseInsensitive=*/true);1887 case DK_IFIDN:1888 return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,1889 /*CaseInsensitive=*/false);1890 case DK_IFIDNI:1891 return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,1892 /*CaseInsensitive=*/true);1893 case DK_ELSEIF:1894 case DK_ELSEIFE:1895 return parseDirectiveElseIf(IDLoc, DirKind);1896 case DK_ELSEIFB:1897 return parseDirectiveElseIfb(IDLoc, true);1898 case DK_ELSEIFNB:1899 return parseDirectiveElseIfb(IDLoc, false);1900 case DK_ELSEIFDEF:1901 return parseDirectiveElseIfdef(IDLoc, true);1902 case DK_ELSEIFNDEF:1903 return parseDirectiveElseIfdef(IDLoc, false);1904 case DK_ELSEIFDIF:1905 return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,1906 /*CaseInsensitive=*/false);1907 case DK_ELSEIFDIFI:1908 return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,1909 /*CaseInsensitive=*/true);1910 case DK_ELSEIFIDN:1911 return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,1912 /*CaseInsensitive=*/false);1913 case DK_ELSEIFIDNI:1914 return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,1915 /*CaseInsensitive=*/true);1916 case DK_ELSE:1917 return parseDirectiveElse(IDLoc);1918 case DK_ENDIF:1919 return parseDirectiveEndIf(IDLoc);1920 }1921 1922 // Ignore the statement if in the middle of inactive conditional1923 // (e.g. ".if 0").1924 if (TheCondState.Ignore) {1925 eatToEndOfStatement();1926 return false;1927 }1928 1929 // FIXME: Recurse on local labels?1930 1931 // Check for a label.1932 // ::= identifier ':'1933 // ::= number ':'1934 if (Lexer.is(AsmToken::Colon) && getTargetParser().isLabel(ID)) {1935 if (checkForValidSection())1936 return true;1937 1938 // identifier ':' -> Label.1939 Lex();1940 1941 // Diagnose attempt to use '.' as a label.1942 if (IDVal == ".")1943 return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");1944 1945 // Diagnose attempt to use a variable as a label.1946 //1947 // FIXME: Diagnostics. Note the location of the definition as a label.1948 // FIXME: This doesn't diagnose assignment to a symbol which has been1949 // implicitly marked as external.1950 MCSymbol *Sym;1951 if (ParsingMSInlineAsm && SI) {1952 StringRef RewrittenLabel =1953 SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);1954 assert(!RewrittenLabel.empty() &&1955 "We should have an internal name here.");1956 Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),1957 RewrittenLabel);1958 IDVal = RewrittenLabel;1959 }1960 // Handle directional local labels1961 if (IDVal == "@@") {1962 Sym = Ctx.createDirectionalLocalSymbol(0);1963 } else {1964 Sym = getContext().parseSymbol(IDVal);1965 }1966 1967 // End of Labels should be treated as end of line for lexing1968 // purposes but that information is not available to the Lexer who1969 // does not understand Labels. This may cause us to see a Hash1970 // here instead of a preprocessor line comment.1971 if (getTok().is(AsmToken::Hash)) {1972 std::string CommentStr = parseStringTo(AsmToken::EndOfStatement);1973 Lexer.Lex();1974 Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));1975 }1976 1977 // Consume any end of statement token, if present, to avoid spurious1978 // addBlankLine calls().1979 if (getTok().is(AsmToken::EndOfStatement)) {1980 Lex();1981 }1982 1983 // Emit the label.1984 if (!getTargetParser().isParsingMSInlineAsm())1985 Out.emitLabel(Sym, IDLoc);1986 return false;1987 }1988 1989 // If macros are enabled, check to see if this is a macro instantiation.1990 if (const MCAsmMacro *M = getContext().lookupMacro(IDVal.lower())) {1991 AsmToken::TokenKind ArgumentEndTok = parseOptionalToken(AsmToken::LParen)1992 ? AsmToken::RParen1993 : AsmToken::EndOfStatement;1994 return handleMacroEntry(M, IDLoc, ArgumentEndTok);1995 }1996 1997 // Otherwise, we have a normal instruction or directive.1998 1999 if (DirKind != DK_NO_DIRECTIVE) {2000 // There are several entities interested in parsing directives:2001 //2002 // 1. Asm parser extensions. For example, platform-specific parsers2003 // (like the ELF parser) register themselves as extensions.2004 // 2. The target-specific assembly parser. Some directives are target2005 // specific or may potentially behave differently on certain targets.2006 // 3. The generic directive parser implemented by this class. These are2007 // all the directives that behave in a target and platform independent2008 // manner, or at least have a default behavior that's shared between2009 // all targets and platforms.2010 2011 // Special-case handling of structure-end directives at higher priority,2012 // since ENDS is overloaded as a segment-end directive.2013 if (IDVal.equals_insensitive("ends") && StructInProgress.size() > 1 &&2014 getTok().is(AsmToken::EndOfStatement)) {2015 return parseDirectiveNestedEnds();2016 }2017 2018 // First, check the extension directive map to see if any extension has2019 // registered itself to parse this directive.2020 std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2021 ExtensionDirectiveMap.lookup(IDVal.lower());2022 if (Handler.first)2023 return (*Handler.second)(Handler.first, IDVal, IDLoc);2024 2025 // Next, let the target-specific assembly parser try.2026 if (ID.isNot(AsmToken::Identifier))2027 return false;2028 2029 ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);2030 assert(TPDirectiveReturn.isFailure() == hasPendingError() &&2031 "Should only return Failure iff there was an error");2032 if (TPDirectiveReturn.isFailure())2033 return true;2034 if (TPDirectiveReturn.isSuccess())2035 return false;2036 2037 // Finally, if no one else is interested in this directive, it must be2038 // generic and familiar to this class.2039 switch (DirKind) {2040 default:2041 break;2042 case DK_ASCII:2043 return parseDirectiveAscii(IDVal, false);2044 case DK_ASCIZ:2045 case DK_STRING:2046 return parseDirectiveAscii(IDVal, true);2047 case DK_BYTE:2048 case DK_SBYTE:2049 case DK_DB:2050 return parseDirectiveValue(IDVal, 1);2051 case DK_WORD:2052 case DK_SWORD:2053 case DK_DW:2054 return parseDirectiveValue(IDVal, 2);2055 case DK_DWORD:2056 case DK_SDWORD:2057 case DK_DD:2058 return parseDirectiveValue(IDVal, 4);2059 case DK_FWORD:2060 case DK_DF:2061 return parseDirectiveValue(IDVal, 6);2062 case DK_QWORD:2063 case DK_SQWORD:2064 case DK_DQ:2065 return parseDirectiveValue(IDVal, 8);2066 case DK_REAL4:2067 return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle(), 4);2068 case DK_REAL8:2069 return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble(), 8);2070 case DK_REAL10:2071 return parseDirectiveRealValue(IDVal, APFloat::x87DoubleExtended(), 10);2072 case DK_STRUCT:2073 case DK_UNION:2074 return parseDirectiveNestedStruct(IDVal, DirKind);2075 case DK_ENDS:2076 return parseDirectiveNestedEnds();2077 case DK_ALIGN:2078 return parseDirectiveAlign();2079 case DK_EVEN:2080 return parseDirectiveEven();2081 case DK_ORG:2082 return parseDirectiveOrg();2083 case DK_EXTERN:2084 return parseDirectiveExtern();2085 case DK_PUBLIC:2086 return parseDirectiveSymbolAttribute(MCSA_Global);2087 case DK_COMM:2088 return parseDirectiveComm(/*IsLocal=*/false);2089 case DK_COMMENT:2090 return parseDirectiveComment(IDLoc);2091 case DK_INCLUDE:2092 return parseDirectiveInclude();2093 case DK_REPEAT:2094 return parseDirectiveRepeat(IDLoc, IDVal);2095 case DK_WHILE:2096 return parseDirectiveWhile(IDLoc);2097 case DK_FOR:2098 return parseDirectiveFor(IDLoc, IDVal);2099 case DK_FORC:2100 return parseDirectiveForc(IDLoc, IDVal);2101 case DK_EXITM:2102 Info.ExitValue = "";2103 return parseDirectiveExitMacro(IDLoc, IDVal, *Info.ExitValue);2104 case DK_ENDM:2105 Info.ExitValue = "";2106 return parseDirectiveEndMacro(IDVal);2107 case DK_PURGE:2108 return parseDirectivePurgeMacro(IDLoc);2109 case DK_END:2110 return parseDirectiveEnd(IDLoc);2111 case DK_ERR:2112 return parseDirectiveError(IDLoc);2113 case DK_ERRB:2114 return parseDirectiveErrorIfb(IDLoc, true);2115 case DK_ERRNB:2116 return parseDirectiveErrorIfb(IDLoc, false);2117 case DK_ERRDEF:2118 return parseDirectiveErrorIfdef(IDLoc, true);2119 case DK_ERRNDEF:2120 return parseDirectiveErrorIfdef(IDLoc, false);2121 case DK_ERRDIF:2122 return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2123 /*CaseInsensitive=*/false);2124 case DK_ERRDIFI:2125 return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2126 /*CaseInsensitive=*/true);2127 case DK_ERRIDN:2128 return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2129 /*CaseInsensitive=*/false);2130 case DK_ERRIDNI:2131 return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2132 /*CaseInsensitive=*/true);2133 case DK_ERRE:2134 return parseDirectiveErrorIfe(IDLoc, true);2135 case DK_ERRNZ:2136 return parseDirectiveErrorIfe(IDLoc, false);2137 case DK_RADIX:2138 return parseDirectiveRadix(IDLoc);2139 case DK_ECHO:2140 return parseDirectiveEcho(IDLoc);2141 }2142 2143 return Error(IDLoc, "unknown directive");2144 }2145 2146 // We also check if this is allocating memory with user-defined type.2147 auto IDIt = Structs.find(IDVal.lower());2148 if (IDIt != Structs.end())2149 return parseDirectiveStructValue(/*Structure=*/IDIt->getValue(), IDVal,2150 IDLoc);2151 2152 // Non-conditional Microsoft directives sometimes follow their first argument.2153 const AsmToken nextTok = getTok();2154 const StringRef nextVal = nextTok.getString();2155 const SMLoc nextLoc = nextTok.getLoc();2156 2157 const AsmToken afterNextTok = peekTok();2158 2159 // There are several entities interested in parsing infix directives:2160 //2161 // 1. Asm parser extensions. For example, platform-specific parsers2162 // (like the ELF parser) register themselves as extensions.2163 // 2. The generic directive parser implemented by this class. These are2164 // all the directives that behave in a target and platform independent2165 // manner, or at least have a default behavior that's shared between2166 // all targets and platforms.2167 2168 getTargetParser().flushPendingInstructions(getStreamer());2169 2170 // Special-case handling of structure-end directives at higher priority, since2171 // ENDS is overloaded as a segment-end directive.2172 if (nextVal.equals_insensitive("ends") && StructInProgress.size() == 1) {2173 Lex();2174 return parseDirectiveEnds(IDVal, IDLoc);2175 }2176 2177 // First, check the extension directive map to see if any extension has2178 // registered itself to parse this directive.2179 std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2180 ExtensionDirectiveMap.lookup(nextVal.lower());2181 if (Handler.first) {2182 Lex();2183 Lexer.UnLex(ID);2184 return (*Handler.second)(Handler.first, nextVal, nextLoc);2185 }2186 2187 // If no one else is interested in this directive, it must be2188 // generic and familiar to this class.2189 DirKindIt = DirectiveKindMap.find(nextVal.lower());2190 DirKind = (DirKindIt == DirectiveKindMap.end())2191 ? DK_NO_DIRECTIVE2192 : DirKindIt->getValue();2193 switch (DirKind) {2194 default:2195 break;2196 case DK_ASSIGN:2197 case DK_EQU:2198 case DK_TEXTEQU:2199 Lex();2200 return parseDirectiveEquate(nextVal, IDVal, DirKind, IDLoc);2201 case DK_BYTE:2202 if (afterNextTok.is(AsmToken::Identifier) &&2203 afterNextTok.getString().equals_insensitive("ptr")) {2204 // Size directive; part of an instruction.2205 break;2206 }2207 [[fallthrough]];2208 case DK_SBYTE:2209 case DK_DB:2210 Lex();2211 return parseDirectiveNamedValue(nextVal, 1, IDVal, IDLoc);2212 case DK_WORD:2213 if (afterNextTok.is(AsmToken::Identifier) &&2214 afterNextTok.getString().equals_insensitive("ptr")) {2215 // Size directive; part of an instruction.2216 break;2217 }2218 [[fallthrough]];2219 case DK_SWORD:2220 case DK_DW:2221 Lex();2222 return parseDirectiveNamedValue(nextVal, 2, IDVal, IDLoc);2223 case DK_DWORD:2224 if (afterNextTok.is(AsmToken::Identifier) &&2225 afterNextTok.getString().equals_insensitive("ptr")) {2226 // Size directive; part of an instruction.2227 break;2228 }2229 [[fallthrough]];2230 case DK_SDWORD:2231 case DK_DD:2232 Lex();2233 return parseDirectiveNamedValue(nextVal, 4, IDVal, IDLoc);2234 case DK_FWORD:2235 if (afterNextTok.is(AsmToken::Identifier) &&2236 afterNextTok.getString().equals_insensitive("ptr")) {2237 // Size directive; part of an instruction.2238 break;2239 }2240 [[fallthrough]];2241 case DK_DF:2242 Lex();2243 return parseDirectiveNamedValue(nextVal, 6, IDVal, IDLoc);2244 case DK_QWORD:2245 if (afterNextTok.is(AsmToken::Identifier) &&2246 afterNextTok.getString().equals_insensitive("ptr")) {2247 // Size directive; part of an instruction.2248 break;2249 }2250 [[fallthrough]];2251 case DK_SQWORD:2252 case DK_DQ:2253 Lex();2254 return parseDirectiveNamedValue(nextVal, 8, IDVal, IDLoc);2255 case DK_REAL4:2256 Lex();2257 return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEsingle(), 4,2258 IDVal, IDLoc);2259 case DK_REAL8:2260 Lex();2261 return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEdouble(), 8,2262 IDVal, IDLoc);2263 case DK_REAL10:2264 Lex();2265 return parseDirectiveNamedRealValue(nextVal, APFloat::x87DoubleExtended(),2266 10, IDVal, IDLoc);2267 case DK_STRUCT:2268 case DK_UNION:2269 Lex();2270 return parseDirectiveStruct(nextVal, DirKind, IDVal, IDLoc);2271 case DK_ENDS:2272 Lex();2273 return parseDirectiveEnds(IDVal, IDLoc);2274 case DK_MACRO:2275 Lex();2276 return parseDirectiveMacro(IDVal, IDLoc);2277 }2278 2279 // Finally, we check if this is allocating a variable with user-defined type.2280 auto NextIt = Structs.find(nextVal.lower());2281 if (NextIt != Structs.end()) {2282 Lex();2283 return parseDirectiveNamedStructValue(/*Structure=*/NextIt->getValue(),2284 nextVal, nextLoc, IDVal);2285 }2286 2287 // __asm _emit or __asm __emit2288 if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||2289 IDVal == "_EMIT" || IDVal == "__EMIT"))2290 return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());2291 2292 // __asm align2293 if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))2294 return parseDirectiveMSAlign(IDLoc, Info);2295 2296 if (ParsingMSInlineAsm && (IDVal == "even" || IDVal == "EVEN"))2297 Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);2298 if (checkForValidSection())2299 return true;2300 2301 // Canonicalize the opcode to lower case.2302 std::string OpcodeStr = IDVal.lower();2303 ParseInstructionInfo IInfo(Info.AsmRewrites);2304 bool ParseHadError = getTargetParser().parseInstruction(IInfo, OpcodeStr, ID,2305 Info.ParsedOperands);2306 Info.ParseError = ParseHadError;2307 2308 // Dump the parsed representation, if requested.2309 if (getShowParsedOperands()) {2310 SmallString<256> Str;2311 raw_svector_ostream OS(Str);2312 OS << "parsed instruction: [";2313 for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {2314 if (i != 0)2315 OS << ", ";2316 Info.ParsedOperands[i]->print(OS, MAI);2317 }2318 OS << "]";2319 2320 printMessage(IDLoc, SourceMgr::DK_Note, OS.str());2321 }2322 2323 // Fail even if ParseInstruction erroneously returns false.2324 if (hasPendingError() || ParseHadError)2325 return true;2326 2327 // If parsing succeeded, match the instruction.2328 if (!ParseHadError) {2329 uint64_t ErrorInfo;2330 if (getTargetParser().matchAndEmitInstruction(2331 IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,2332 getTargetParser().isParsingMSInlineAsm()))2333 return true;2334 }2335 return false;2336}2337 2338// Parse and erase curly braces marking block start/end.2339bool MasmParser::parseCurlyBlockScope(2340 SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {2341 // Identify curly brace marking block start/end.2342 if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))2343 return false;2344 2345 SMLoc StartLoc = Lexer.getLoc();2346 Lex(); // Eat the brace.2347 if (Lexer.is(AsmToken::EndOfStatement))2348 Lex(); // Eat EndOfStatement following the brace.2349 2350 // Erase the block start/end brace from the output asm string.2351 AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -2352 StartLoc.getPointer());2353 return true;2354}2355 2356/// parseCppHashLineFilenameComment as this:2357/// ::= # number "filename"2358bool MasmParser::parseCppHashLineFilenameComment(SMLoc L) {2359 Lex(); // Eat the hash token.2360 // Lexer only ever emits HashDirective if it fully formed if it's2361 // done the checking already so this is an internal error.2362 assert(getTok().is(AsmToken::Integer) &&2363 "Lexing Cpp line comment: Expected Integer");2364 int64_t LineNumber = getTok().getIntVal();2365 Lex();2366 assert(getTok().is(AsmToken::String) &&2367 "Lexing Cpp line comment: Expected String");2368 StringRef Filename = getTok().getString();2369 Lex();2370 2371 // Get rid of the enclosing quotes.2372 Filename = Filename.substr(1, Filename.size() - 2);2373 2374 // Save the SMLoc, Filename and LineNumber for later use by diagnostics2375 // and possibly DWARF file info.2376 CppHashInfo.Loc = L;2377 CppHashInfo.Filename = Filename;2378 CppHashInfo.LineNumber = LineNumber;2379 CppHashInfo.Buf = CurBuffer;2380 if (FirstCppHashFilename.empty())2381 FirstCppHashFilename = Filename;2382 return false;2383}2384 2385/// will use the last parsed cpp hash line filename comment2386/// for the Filename and LineNo if any in the diagnostic.2387void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {2388 const MasmParser *Parser = static_cast<const MasmParser *>(Context);2389 raw_ostream &OS = errs();2390 2391 const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();2392 SMLoc DiagLoc = Diag.getLoc();2393 unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2394 unsigned CppHashBuf =2395 Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);2396 2397 // Like SourceMgr::printMessage() we need to print the include stack if any2398 // before printing the message.2399 unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2400 if (!Parser->SavedDiagHandler && DiagCurBuffer &&2401 DiagCurBuffer != DiagSrcMgr.getMainFileID()) {2402 SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);2403 DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);2404 }2405 2406 // If we have not parsed a cpp hash line filename comment or the source2407 // manager changed or buffer changed (like in a nested include) then just2408 // print the normal diagnostic using its Filename and LineNo.2409 if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||2410 DiagBuf != CppHashBuf) {2411 if (Parser->SavedDiagHandler)2412 Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);2413 else2414 Diag.print(nullptr, OS);2415 return;2416 }2417 2418 // Use the CppHashFilename and calculate a line number based on the2419 // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc2420 // for the diagnostic.2421 const std::string &Filename = std::string(Parser->CppHashInfo.Filename);2422 2423 int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);2424 int CppHashLocLineNo =2425 Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);2426 int LineNo =2427 Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);2428 2429 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,2430 Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),2431 Diag.getLineContents(), Diag.getRanges());2432 2433 if (Parser->SavedDiagHandler)2434 Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);2435 else2436 NewDiag.print(nullptr, OS);2437}2438 2439// This is similar to the IsIdentifierChar function in AsmLexer.cpp, but does2440// not accept '.'.2441static bool isMacroParameterChar(char C) {2442 return isAlnum(C) || C == '_' || C == '$' || C == '@' || C == '?';2443}2444 2445bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,2446 ArrayRef<MCAsmMacroParameter> Parameters,2447 ArrayRef<MCAsmMacroArgument> A,2448 const std::vector<std::string> &Locals, SMLoc L) {2449 unsigned NParameters = Parameters.size();2450 if (NParameters != A.size())2451 return Error(L, "Wrong number of arguments");2452 StringMap<std::string> LocalSymbols;2453 std::string Name;2454 Name.reserve(6);2455 for (StringRef Local : Locals) {2456 raw_string_ostream LocalName(Name);2457 LocalName << "??"2458 << format_hex_no_prefix(LocalCounter++, 4, /*Upper=*/true);2459 LocalSymbols.insert({Local, Name});2460 Name.clear();2461 }2462 2463 std::optional<char> CurrentQuote;2464 while (!Body.empty()) {2465 // Scan for the next substitution.2466 std::size_t End = Body.size(), Pos = 0;2467 std::size_t IdentifierPos = End;2468 for (; Pos != End; ++Pos) {2469 // Find the next possible macro parameter, including preceding a '&'2470 // inside quotes.2471 if (Body[Pos] == '&')2472 break;2473 if (isMacroParameterChar(Body[Pos])) {2474 if (!CurrentQuote)2475 break;2476 if (IdentifierPos == End)2477 IdentifierPos = Pos;2478 } else {2479 IdentifierPos = End;2480 }2481 2482 // Track quotation status2483 if (!CurrentQuote) {2484 if (Body[Pos] == '\'' || Body[Pos] == '"')2485 CurrentQuote = Body[Pos];2486 } else if (Body[Pos] == CurrentQuote) {2487 if (Pos + 1 != End && Body[Pos + 1] == CurrentQuote) {2488 // Escaped quote, and quotes aren't identifier chars; skip2489 ++Pos;2490 continue;2491 } else {2492 CurrentQuote.reset();2493 }2494 }2495 }2496 if (IdentifierPos != End) {2497 // We've recognized an identifier before an apostrophe inside quotes;2498 // check once to see if we can expand it.2499 Pos = IdentifierPos;2500 IdentifierPos = End;2501 }2502 2503 // Add the prefix.2504 OS << Body.slice(0, Pos);2505 2506 // Check if we reached the end.2507 if (Pos == End)2508 break;2509 2510 unsigned I = Pos;2511 bool InitialAmpersand = (Body[I] == '&');2512 if (InitialAmpersand) {2513 ++I;2514 ++Pos;2515 }2516 while (I < End && isMacroParameterChar(Body[I]))2517 ++I;2518 2519 const char *Begin = Body.data() + Pos;2520 StringRef Argument(Begin, I - Pos);2521 const std::string ArgumentLower = Argument.lower();2522 unsigned Index = 0;2523 2524 for (; Index < NParameters; ++Index)2525 if (Parameters[Index].Name.equals_insensitive(ArgumentLower))2526 break;2527 2528 if (Index == NParameters) {2529 if (InitialAmpersand)2530 OS << '&';2531 auto it = LocalSymbols.find(ArgumentLower);2532 if (it != LocalSymbols.end())2533 OS << it->second;2534 else2535 OS << Argument;2536 Pos = I;2537 } else {2538 for (const AsmToken &Token : A[Index]) {2539 // In MASM, you can write '%expr'.2540 // The prefix '%' evaluates the expression 'expr'2541 // and uses the result as a string (e.g. replace %(1+2) with the2542 // string "3").2543 // Here, we identify the integer token which is the result of the2544 // absolute expression evaluation and replace it with its string2545 // representation.2546 if (Token.getString().front() == '%' && Token.is(AsmToken::Integer))2547 // Emit an integer value to the buffer.2548 OS << Token.getIntVal();2549 else2550 OS << Token.getString();2551 }2552 2553 Pos += Argument.size();2554 if (Pos < End && Body[Pos] == '&') {2555 ++Pos;2556 }2557 }2558 // Update the scan point.2559 Body = Body.substr(Pos);2560 }2561 2562 return false;2563}2564 2565bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP,2566 MCAsmMacroArgument &MA,2567 AsmToken::TokenKind EndTok) {2568 if (MP && MP->Vararg) {2569 if (Lexer.isNot(EndTok)) {2570 SmallVector<StringRef, 1> Str = parseStringRefsTo(EndTok);2571 for (StringRef S : Str) {2572 MA.emplace_back(AsmToken::String, S);2573 }2574 }2575 return false;2576 }2577 2578 SMLoc StrLoc = Lexer.getLoc(), EndLoc;2579 if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) {2580 const char *StrChar = StrLoc.getPointer() + 1;2581 const char *EndChar = EndLoc.getPointer() - 1;2582 jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());2583 /// Eat from '<' to '>'.2584 Lex();2585 MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar));2586 return false;2587 }2588 2589 unsigned ParenLevel = 0;2590 2591 while (true) {2592 if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))2593 return TokError("unexpected token");2594 2595 if (ParenLevel == 0 && Lexer.is(AsmToken::Comma))2596 break;2597 2598 // handleMacroEntry relies on not advancing the lexer here2599 // to be able to fill in the remaining default parameter values2600 if (Lexer.is(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0))2601 break;2602 2603 // Adjust the current parentheses level.2604 if (Lexer.is(AsmToken::LParen))2605 ++ParenLevel;2606 else if (Lexer.is(AsmToken::RParen) && ParenLevel)2607 --ParenLevel;2608 2609 // Append the token to the current argument list.2610 MA.push_back(getTok());2611 Lex();2612 }2613 2614 if (ParenLevel != 0)2615 return TokError("unbalanced parentheses in argument");2616 2617 if (MA.empty() && MP) {2618 if (MP->Required) {2619 return TokError("missing value for required parameter '" + MP->Name +2620 "'");2621 } else {2622 MA = MP->Value;2623 }2624 }2625 return false;2626}2627 2628// Parse the macro instantiation arguments.2629bool MasmParser::parseMacroArguments(const MCAsmMacro *M,2630 MCAsmMacroArguments &A,2631 AsmToken::TokenKind EndTok) {2632 const unsigned NParameters = M ? M->Parameters.size() : 0;2633 bool NamedParametersFound = false;2634 SmallVector<SMLoc, 4> FALocs;2635 2636 A.resize(NParameters);2637 FALocs.resize(NParameters);2638 2639 // Parse two kinds of macro invocations:2640 // - macros defined without any parameters accept an arbitrary number of them2641 // - macros defined with parameters accept at most that many of them2642 for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;2643 ++Parameter) {2644 SMLoc IDLoc = Lexer.getLoc();2645 MCAsmMacroParameter FA;2646 2647 if (Lexer.is(AsmToken::Identifier) && peekTok().is(AsmToken::Equal)) {2648 if (parseIdentifier(FA.Name))2649 return Error(IDLoc, "invalid argument identifier for formal argument");2650 2651 if (Lexer.isNot(AsmToken::Equal))2652 return TokError("expected '=' after formal parameter identifier");2653 2654 Lex();2655 2656 NamedParametersFound = true;2657 }2658 2659 if (NamedParametersFound && FA.Name.empty())2660 return Error(IDLoc, "cannot mix positional and keyword arguments");2661 2662 unsigned PI = Parameter;2663 if (!FA.Name.empty()) {2664 assert(M && "expected macro to be defined");2665 unsigned FAI = 0;2666 for (FAI = 0; FAI < NParameters; ++FAI)2667 if (M->Parameters[FAI].Name == FA.Name)2668 break;2669 2670 if (FAI >= NParameters) {2671 return Error(IDLoc, "parameter named '" + FA.Name +2672 "' does not exist for macro '" + M->Name + "'");2673 }2674 PI = FAI;2675 }2676 const MCAsmMacroParameter *MP = nullptr;2677 if (M && PI < NParameters)2678 MP = &M->Parameters[PI];2679 2680 SMLoc StrLoc = Lexer.getLoc();2681 SMLoc EndLoc;2682 if (Lexer.is(AsmToken::Percent)) {2683 const MCExpr *AbsoluteExp;2684 int64_t Value;2685 /// Eat '%'.2686 Lex();2687 if (parseExpression(AbsoluteExp, EndLoc))2688 return false;2689 if (!AbsoluteExp->evaluateAsAbsolute(Value,2690 getStreamer().getAssemblerPtr()))2691 return Error(StrLoc, "expected absolute expression");2692 const char *StrChar = StrLoc.getPointer();2693 const char *EndChar = EndLoc.getPointer();2694 AsmToken newToken(AsmToken::Integer,2695 StringRef(StrChar, EndChar - StrChar), Value);2696 FA.Value.push_back(newToken);2697 } else if (parseMacroArgument(MP, FA.Value, EndTok)) {2698 if (M)2699 return addErrorSuffix(" in '" + M->Name + "' macro");2700 else2701 return true;2702 }2703 2704 if (!FA.Value.empty()) {2705 if (A.size() <= PI)2706 A.resize(PI + 1);2707 A[PI] = FA.Value;2708 2709 if (FALocs.size() <= PI)2710 FALocs.resize(PI + 1);2711 2712 FALocs[PI] = Lexer.getLoc();2713 }2714 2715 // At the end of the statement, fill in remaining arguments that have2716 // default values. If there aren't any, then the next argument is2717 // required but missing2718 if (Lexer.is(EndTok)) {2719 bool Failure = false;2720 for (unsigned FAI = 0; FAI < NParameters; ++FAI) {2721 if (A[FAI].empty()) {2722 if (M->Parameters[FAI].Required) {2723 Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),2724 "missing value for required parameter "2725 "'" +2726 M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");2727 Failure = true;2728 }2729 2730 if (!M->Parameters[FAI].Value.empty())2731 A[FAI] = M->Parameters[FAI].Value;2732 }2733 }2734 return Failure;2735 }2736 2737 if (Lexer.is(AsmToken::Comma))2738 Lex();2739 }2740 2741 return TokError("too many positional arguments");2742}2743 2744bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,2745 AsmToken::TokenKind ArgumentEndTok) {2746 // Arbitrarily limit macro nesting depth (default matches 'as'). We can2747 // eliminate this, although we should protect against infinite loops.2748 unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;2749 if (ActiveMacros.size() == MaxNestingDepth) {2750 std::ostringstream MaxNestingDepthError;2751 MaxNestingDepthError << "macros cannot be nested more than "2752 << MaxNestingDepth << " levels deep."2753 << " Use -asm-macro-max-nesting-depth to increase "2754 "this limit.";2755 return TokError(MaxNestingDepthError.str());2756 }2757 2758 MCAsmMacroArguments A;2759 if (parseMacroArguments(M, A, ArgumentEndTok) || parseToken(ArgumentEndTok))2760 return true;2761 2762 // Macro instantiation is lexical, unfortunately. We construct a new buffer2763 // to hold the macro body with substitutions.2764 SmallString<256> Buf;2765 StringRef Body = M->Body;2766 raw_svector_ostream OS(Buf);2767 2768 if (expandMacro(OS, Body, M->Parameters, A, M->Locals, getTok().getLoc()))2769 return true;2770 2771 // We include the endm in the buffer as our cue to exit the macro2772 // instantiation.2773 OS << "endm\n";2774 2775 std::unique_ptr<MemoryBuffer> Instantiation =2776 MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");2777 2778 // Create the macro instantiation object and add to the current macro2779 // instantiation stack.2780 MacroInstantiation *MI = new MacroInstantiation{2781 NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};2782 ActiveMacros.push_back(MI);2783 2784 ++NumOfMacroInstantiations;2785 2786 // Jump to the macro instantiation and prime the lexer.2787 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());2788 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());2789 EndStatementAtEOFStack.push_back(true);2790 Lex();2791 2792 return false;2793}2794 2795void MasmParser::handleMacroExit() {2796 // Jump to the token we should return to, and consume it.2797 EndStatementAtEOFStack.pop_back();2798 jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer,2799 EndStatementAtEOFStack.back());2800 Lex();2801 2802 // Pop the instantiation entry.2803 delete ActiveMacros.back();2804 ActiveMacros.pop_back();2805}2806 2807bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) {2808 if (!M->IsFunction)2809 return Error(NameLoc, "cannot invoke macro procedure as function");2810 2811 if (parseToken(AsmToken::LParen, "invoking macro function '" + M->Name +2812 "' requires arguments in parentheses") ||2813 handleMacroEntry(M, NameLoc, AsmToken::RParen))2814 return true;2815 2816 // Parse all statements in the macro, retrieving the exit value when it ends.2817 std::string ExitValue;2818 SmallVector<AsmRewrite, 4> AsmStrRewrites;2819 while (Lexer.isNot(AsmToken::Eof)) {2820 ParseStatementInfo Info(&AsmStrRewrites);2821 bool HasError = parseStatement(Info, nullptr);2822 2823 if (!HasError && Info.ExitValue) {2824 ExitValue = std::move(*Info.ExitValue);2825 break;2826 }2827 2828 // If we have a Lexer Error we are on an Error Token. Load in Lexer Error2829 // for printing ErrMsg via Lex() only if no (presumably better) parser error2830 // exists.2831 if (HasError && !hasPendingError() && Lexer.getTok().is(AsmToken::Error))2832 Lex();2833 2834 // parseStatement returned true so may need to emit an error.2835 printPendingErrors();2836 2837 // Skipping to the next line if needed.2838 if (HasError && !getLexer().justConsumedEOL())2839 eatToEndOfStatement();2840 }2841 2842 // Exit values may require lexing, unfortunately. We construct a new buffer to2843 // hold the exit value.2844 std::unique_ptr<MemoryBuffer> MacroValue =2845 MemoryBuffer::getMemBufferCopy(ExitValue, "<macro-value>");2846 2847 // Jump from this location to the instantiated exit value, and prime the2848 // lexer.2849 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(MacroValue), Lexer.getLoc());2850 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,2851 /*EndStatementAtEOF=*/false);2852 EndStatementAtEOFStack.push_back(false);2853 Lex();2854 2855 return false;2856}2857 2858/// parseIdentifier:2859/// ::= identifier2860/// ::= string2861bool MasmParser::parseIdentifier(StringRef &Res,2862 IdentifierPositionKind Position) {2863 // The assembler has relaxed rules for accepting identifiers, in particular we2864 // allow things like '.globl $foo' and '.def @feat.00', which would normally2865 // be separate tokens. At this level, we have already lexed so we cannot2866 // (currently) handle this as a context dependent token, instead we detect2867 // adjacent tokens and return the combined identifier.2868 if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {2869 SMLoc PrefixLoc = getLexer().getLoc();2870 2871 // Consume the prefix character, and check for a following identifier.2872 2873 AsmToken nextTok = peekTok(false);2874 2875 if (nextTok.isNot(AsmToken::Identifier))2876 return true;2877 2878 // We have a '$' or '@' followed by an identifier, make sure they are adjacent.2879 if (PrefixLoc.getPointer() + 1 != nextTok.getLoc().getPointer())2880 return true;2881 2882 // eat $ or @2883 Lexer.Lex(); // Lexer's Lex guarantees consecutive token.2884 // Construct the joined identifier and consume the token.2885 Res =2886 StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);2887 Lex(); // Parser Lex to maintain invariants.2888 return false;2889 }2890 2891 if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))2892 return true;2893 2894 Res = getTok().getIdentifier();2895 2896 // Consume the identifier token - but if parsing certain directives, avoid2897 // lexical expansion of the next token.2898 ExpandKind ExpandNextToken = ExpandMacros;2899 if (Position == StartOfStatement &&2900 StringSwitch<bool>(Res)2901 .CaseLower("echo", true)2902 .CasesLower({"ifdef", "ifndef", "elseifdef", "elseifndef"}, true)2903 .Default(false)) {2904 ExpandNextToken = DoNotExpandMacros;2905 }2906 Lex(ExpandNextToken);2907 2908 return false;2909}2910 2911/// parseDirectiveEquate:2912/// ::= name "=" expression2913/// | name "equ" expression (not redefinable)2914/// | name "equ" text-list2915/// | name "textequ" text-list (redefinability unspecified)2916bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,2917 DirectiveKind DirKind, SMLoc NameLoc) {2918 auto BuiltinIt = BuiltinSymbolMap.find(Name.lower());2919 if (BuiltinIt != BuiltinSymbolMap.end())2920 return Error(NameLoc, "cannot redefine a built-in symbol");2921 2922 Variable &Var = Variables[Name.lower()];2923 if (Var.Name.empty()) {2924 Var.Name = Name;2925 }2926 2927 SMLoc StartLoc = Lexer.getLoc();2928 if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {2929 // "equ" and "textequ" both allow text expressions.2930 std::string Value;2931 std::string TextItem;2932 if (!parseTextItem(TextItem)) {2933 Value += TextItem;2934 2935 // Accept a text-list, not just one text-item.2936 auto parseItem = [&]() -> bool {2937 if (parseTextItem(TextItem))2938 return TokError("expected text item");2939 Value += TextItem;2940 return false;2941 };2942 if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))2943 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");2944 2945 if (!Var.IsText || Var.TextValue != Value) {2946 switch (Var.Redefinable) {2947 case Variable::NOT_REDEFINABLE:2948 return Error(getTok().getLoc(), "invalid variable redefinition");2949 case Variable::WARN_ON_REDEFINITION:2950 if (Warning(NameLoc, "redefining '" + Name +2951 "', already defined on the command line")) {2952 return true;2953 }2954 break;2955 default:2956 break;2957 }2958 }2959 Var.IsText = true;2960 Var.TextValue = Value;2961 Var.Redefinable = Variable::REDEFINABLE;2962 2963 return false;2964 }2965 }2966 if (DirKind == DK_TEXTEQU)2967 return TokError("expected <text> in '" + Twine(IDVal) + "' directive");2968 2969 // Parse as expression assignment.2970 const MCExpr *Expr;2971 SMLoc EndLoc;2972 if (parseExpression(Expr, EndLoc))2973 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");2974 StringRef ExprAsString = StringRef(2975 StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());2976 2977 int64_t Value;2978 if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) {2979 if (DirKind == DK_ASSIGN)2980 return Error(2981 StartLoc,2982 "expected absolute expression; not all symbols have known values",2983 {StartLoc, EndLoc});2984 2985 // Not an absolute expression; define as a text replacement.2986 if (!Var.IsText || Var.TextValue != ExprAsString) {2987 switch (Var.Redefinable) {2988 case Variable::NOT_REDEFINABLE:2989 return Error(getTok().getLoc(), "invalid variable redefinition");2990 case Variable::WARN_ON_REDEFINITION:2991 if (Warning(NameLoc, "redefining '" + Name +2992 "', already defined on the command line")) {2993 return true;2994 }2995 break;2996 default:2997 break;2998 }2999 }3000 3001 Var.IsText = true;3002 Var.TextValue = ExprAsString.str();3003 Var.Redefinable = Variable::REDEFINABLE;3004 3005 return false;3006 }3007 3008 auto *Sym = static_cast<MCSymbolCOFF *>(getContext().parseSymbol(Var.Name));3009 const MCConstantExpr *PrevValue =3010 Sym->isVariable()3011 ? dyn_cast_or_null<MCConstantExpr>(Sym->getVariableValue())3012 : nullptr;3013 if (Var.IsText || !PrevValue || PrevValue->getValue() != Value) {3014 switch (Var.Redefinable) {3015 case Variable::NOT_REDEFINABLE:3016 return Error(getTok().getLoc(), "invalid variable redefinition");3017 case Variable::WARN_ON_REDEFINITION:3018 if (Warning(NameLoc, "redefining '" + Name +3019 "', already defined on the command line")) {3020 return true;3021 }3022 break;3023 default:3024 break;3025 }3026 }3027 3028 Var.IsText = false;3029 Var.TextValue.clear();3030 Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE3031 : Variable::NOT_REDEFINABLE;3032 3033 Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE);3034 Sym->setVariableValue(Expr);3035 Sym->setExternal(false);3036 3037 return false;3038}3039 3040bool MasmParser::parseEscapedString(std::string &Data) {3041 if (check(getTok().isNot(AsmToken::String), "expected string"))3042 return true;3043 3044 Data = "";3045 char Quote = getTok().getString().front();3046 StringRef Str = getTok().getStringContents();3047 Data.reserve(Str.size());3048 for (size_t i = 0, e = Str.size(); i != e; ++i) {3049 Data.push_back(Str[i]);3050 if (Str[i] == Quote) {3051 // MASM treats doubled delimiting quotes as an escaped delimiting quote.3052 // If we're escaping the string's trailing delimiter, we're definitely3053 // missing a quotation mark.3054 if (i + 1 == Str.size())3055 return Error(getTok().getLoc(), "missing quotation mark in string");3056 if (Str[i + 1] == Quote)3057 ++i;3058 }3059 }3060 3061 Lex();3062 return false;3063}3064 3065bool MasmParser::parseAngleBracketString(std::string &Data) {3066 SMLoc EndLoc, StartLoc = getTok().getLoc();3067 if (isAngleBracketString(StartLoc, EndLoc)) {3068 const char *StartChar = StartLoc.getPointer() + 1;3069 const char *EndChar = EndLoc.getPointer() - 1;3070 jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());3071 // Eat from '<' to '>'.3072 Lex();3073 3074 Data = angleBracketString(StringRef(StartChar, EndChar - StartChar));3075 return false;3076 }3077 return true;3078}3079 3080/// textItem ::= textLiteral | textMacroID | % constExpr3081bool MasmParser::parseTextItem(std::string &Data) {3082 switch (getTok().getKind()) {3083 default:3084 return true;3085 case AsmToken::Percent: {3086 int64_t Res;3087 if (parseToken(AsmToken::Percent) || parseAbsoluteExpression(Res))3088 return true;3089 Data = std::to_string(Res);3090 return false;3091 }3092 case AsmToken::Less:3093 case AsmToken::LessEqual:3094 case AsmToken::LessLess:3095 case AsmToken::LessGreater:3096 return parseAngleBracketString(Data);3097 case AsmToken::Identifier: {3098 // This must be a text macro; we need to expand it accordingly.3099 StringRef ID;3100 SMLoc StartLoc = getTok().getLoc();3101 if (parseIdentifier(ID))3102 return true;3103 Data = ID.str();3104 3105 bool Expanded = false;3106 while (true) {3107 // Try to resolve as a built-in text macro3108 auto BuiltinIt = BuiltinSymbolMap.find(ID.lower());3109 if (BuiltinIt != BuiltinSymbolMap.end()) {3110 std::optional<std::string> BuiltinText =3111 evaluateBuiltinTextMacro(BuiltinIt->getValue(), StartLoc);3112 if (!BuiltinText) {3113 // Not a text macro; break without substituting3114 break;3115 }3116 Data = std::move(*BuiltinText);3117 ID = StringRef(Data);3118 Expanded = true;3119 continue;3120 }3121 3122 // Try to resolve as a built-in macro function3123 auto BuiltinFuncIt = BuiltinFunctionMap.find(ID.lower());3124 if (BuiltinFuncIt != BuiltinFunctionMap.end()) {3125 Data.clear();3126 if (evaluateBuiltinMacroFunction(BuiltinFuncIt->getValue(), ID, Data)) {3127 return true;3128 }3129 ID = StringRef(Data);3130 Expanded = true;3131 continue;3132 }3133 3134 // Try to resolve as a variable text macro3135 auto VarIt = Variables.find(ID.lower());3136 if (VarIt != Variables.end()) {3137 const Variable &Var = VarIt->getValue();3138 if (!Var.IsText) {3139 // Not a text macro; break without substituting3140 break;3141 }3142 Data = Var.TextValue;3143 ID = StringRef(Data);3144 Expanded = true;3145 continue;3146 }3147 3148 break;3149 }3150 3151 if (!Expanded) {3152 // Not a text macro; not usable in TextItem context. Since we haven't used3153 // the token, put it back for better error recovery.3154 getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));3155 return true;3156 }3157 return false;3158 }3159 }3160 llvm_unreachable("unhandled token kind");3161}3162 3163/// parseDirectiveAscii:3164/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]3165bool MasmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {3166 auto parseOp = [&]() -> bool {3167 std::string Data;3168 if (checkForValidSection() || parseEscapedString(Data))3169 return true;3170 getStreamer().emitBytes(Data);3171 if (ZeroTerminated)3172 getStreamer().emitBytes(StringRef("\0", 1));3173 return false;3174 };3175 3176 if (parseMany(parseOp))3177 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3178 return false;3179}3180 3181bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) {3182 // Special case constant expressions to match code generator.3183 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3184 assert(Size <= 8 && "Invalid size");3185 int64_t IntValue = MCE->getValue();3186 if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))3187 return Error(MCE->getLoc(), "out of range literal value");3188 getStreamer().emitIntValue(IntValue, Size);3189 } else {3190 const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Value);3191 if (MSE && MSE->getSymbol().getName() == "?") {3192 // ? initializer; treat as 0.3193 getStreamer().emitIntValue(0, Size);3194 } else {3195 getStreamer().emitValue(Value, Size, Value->getLoc());3196 }3197 }3198 return false;3199}3200 3201bool MasmParser::parseScalarInitializer(unsigned Size,3202 SmallVectorImpl<const MCExpr *> &Values,3203 unsigned StringPadLength) {3204 if (Size == 1 && getTok().is(AsmToken::String)) {3205 std::string Value;3206 if (parseEscapedString(Value))3207 return true;3208 // Treat each character as an initializer.3209 for (const unsigned char CharVal : Value)3210 Values.push_back(MCConstantExpr::create(CharVal, getContext()));3211 3212 // Pad the string with spaces to the specified length.3213 for (size_t i = Value.size(); i < StringPadLength; ++i)3214 Values.push_back(MCConstantExpr::create(' ', getContext()));3215 } else {3216 const MCExpr *Value;3217 if (parseExpression(Value))3218 return true;3219 if (getTok().is(AsmToken::Identifier) &&3220 getTok().getString().equals_insensitive("dup")) {3221 Lex(); // Eat 'dup'.3222 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3223 if (!MCE)3224 return Error(Value->getLoc(),3225 "cannot repeat value a non-constant number of times");3226 const int64_t Repetitions = MCE->getValue();3227 if (Repetitions < 0)3228 return Error(Value->getLoc(),3229 "cannot repeat value a negative number of times");3230 3231 SmallVector<const MCExpr *, 1> DuplicatedValues;3232 if (parseToken(AsmToken::LParen,3233 "parentheses required for 'dup' contents") ||3234 parseScalarInstList(Size, DuplicatedValues) || parseRParen())3235 return true;3236 3237 for (int i = 0; i < Repetitions; ++i)3238 Values.append(DuplicatedValues.begin(), DuplicatedValues.end());3239 } else {3240 Values.push_back(Value);3241 }3242 }3243 return false;3244}3245 3246bool MasmParser::parseScalarInstList(unsigned Size,3247 SmallVectorImpl<const MCExpr *> &Values,3248 const AsmToken::TokenKind EndToken) {3249 while (getTok().isNot(EndToken) &&3250 (EndToken != AsmToken::Greater ||3251 getTok().isNot(AsmToken::GreaterGreater))) {3252 parseScalarInitializer(Size, Values);3253 3254 // If we see a comma, continue, and allow line continuation.3255 if (!parseOptionalToken(AsmToken::Comma))3256 break;3257 parseOptionalToken(AsmToken::EndOfStatement);3258 }3259 return false;3260}3261 3262bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) {3263 SmallVector<const MCExpr *, 1> Values;3264 if (checkForValidSection() || parseScalarInstList(Size, Values))3265 return true;3266 3267 for (const auto *Value : Values) {3268 emitIntValue(Value, Size);3269 }3270 if (Count)3271 *Count = Values.size();3272 return false;3273}3274 3275// Add a field to the current structure.3276bool MasmParser::addIntegralField(StringRef Name, unsigned Size) {3277 StructInfo &Struct = StructInProgress.back();3278 FieldInfo &Field = Struct.addField(Name, FT_INTEGRAL, Size);3279 IntFieldInfo &IntInfo = Field.Contents.IntInfo;3280 3281 Field.Type = Size;3282 3283 if (parseScalarInstList(Size, IntInfo.Values))3284 return true;3285 3286 Field.SizeOf = Field.Type * IntInfo.Values.size();3287 Field.LengthOf = IntInfo.Values.size();3288 const unsigned FieldEnd = Field.Offset + Field.SizeOf;3289 if (!Struct.IsUnion) {3290 Struct.NextOffset = FieldEnd;3291 }3292 Struct.Size = std::max(Struct.Size, FieldEnd);3293 return false;3294}3295 3296/// parseDirectiveValue3297/// ::= (byte | word | ... ) [ expression (, expression)* ]3298bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {3299 if (StructInProgress.empty()) {3300 // Initialize data value.3301 if (emitIntegralValues(Size))3302 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3303 } else if (addIntegralField("", Size)) {3304 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3305 }3306 3307 return false;3308}3309 3310/// parseDirectiveNamedValue3311/// ::= name (byte | word | ... ) [ expression (, expression)* ]3312bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size,3313 StringRef Name, SMLoc NameLoc) {3314 if (StructInProgress.empty()) {3315 // Initialize named data value.3316 MCSymbol *Sym = getContext().parseSymbol(Name);3317 getStreamer().emitLabel(Sym);3318 unsigned Count;3319 if (emitIntegralValues(Size, &Count))3320 return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");3321 3322 AsmTypeInfo Type;3323 Type.Name = TypeName;3324 Type.Size = Size * Count;3325 Type.ElementSize = Size;3326 Type.Length = Count;3327 KnownType[Name.lower()] = Type;3328 } else if (addIntegralField(Name, Size)) {3329 return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");3330 }3331 3332 return false;3333}3334 3335bool MasmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {3336 // We don't truly support arithmetic on floating point expressions, so we3337 // have to manually parse unary prefixes.3338 bool IsNeg = false;3339 SMLoc SignLoc;3340 if (getLexer().is(AsmToken::Minus)) {3341 SignLoc = getLexer().getLoc();3342 Lexer.Lex();3343 IsNeg = true;3344 } else if (getLexer().is(AsmToken::Plus)) {3345 SignLoc = getLexer().getLoc();3346 Lexer.Lex();3347 }3348 3349 if (Lexer.is(AsmToken::Error))3350 return TokError(Lexer.getErr());3351 if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&3352 Lexer.isNot(AsmToken::Identifier))3353 return TokError("unexpected token in directive");3354 3355 // Convert to an APFloat.3356 APFloat Value(Semantics);3357 StringRef IDVal = getTok().getString();3358 if (getLexer().is(AsmToken::Identifier)) {3359 if (IDVal.equals_insensitive("infinity") || IDVal.equals_insensitive("inf"))3360 Value = APFloat::getInf(Semantics);3361 else if (IDVal.equals_insensitive("nan"))3362 Value = APFloat::getNaN(Semantics, false, ~0);3363 else if (IDVal.equals_insensitive("?"))3364 Value = APFloat::getZero(Semantics);3365 else3366 return TokError("invalid floating point literal");3367 } else if (IDVal.consume_back("r") || IDVal.consume_back("R")) {3368 // MASM hexadecimal floating-point literal; no APFloat conversion needed.3369 // To match ML64.exe, ignore the initial sign.3370 unsigned SizeInBits = Value.getSizeInBits(Semantics);3371 if (SizeInBits != (IDVal.size() << 2))3372 return TokError("invalid floating point literal");3373 3374 // Consume the numeric token.3375 Lex();3376 3377 Res = APInt(SizeInBits, IDVal, 16);3378 if (SignLoc.isValid())3379 return Warning(SignLoc, "MASM-style hex floats ignore explicit sign");3380 return false;3381 } else if (errorToBool(3382 Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven)3383 .takeError())) {3384 return TokError("invalid floating point literal");3385 }3386 if (IsNeg)3387 Value.changeSign();3388 3389 // Consume the numeric token.3390 Lex();3391 3392 Res = Value.bitcastToAPInt();3393 3394 return false;3395}3396 3397bool MasmParser::parseRealInstList(const fltSemantics &Semantics,3398 SmallVectorImpl<APInt> &ValuesAsInt,3399 const AsmToken::TokenKind EndToken) {3400 while (getTok().isNot(EndToken) ||3401 (EndToken == AsmToken::Greater &&3402 getTok().isNot(AsmToken::GreaterGreater))) {3403 const AsmToken NextTok = peekTok();3404 if (NextTok.is(AsmToken::Identifier) &&3405 NextTok.getString().equals_insensitive("dup")) {3406 const MCExpr *Value;3407 if (parseExpression(Value) || parseToken(AsmToken::Identifier))3408 return true;3409 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3410 if (!MCE)3411 return Error(Value->getLoc(),3412 "cannot repeat value a non-constant number of times");3413 const int64_t Repetitions = MCE->getValue();3414 if (Repetitions < 0)3415 return Error(Value->getLoc(),3416 "cannot repeat value a negative number of times");3417 3418 SmallVector<APInt, 1> DuplicatedValues;3419 if (parseToken(AsmToken::LParen,3420 "parentheses required for 'dup' contents") ||3421 parseRealInstList(Semantics, DuplicatedValues) || parseRParen())3422 return true;3423 3424 for (int i = 0; i < Repetitions; ++i)3425 ValuesAsInt.append(DuplicatedValues.begin(), DuplicatedValues.end());3426 } else {3427 APInt AsInt;3428 if (parseRealValue(Semantics, AsInt))3429 return true;3430 ValuesAsInt.push_back(AsInt);3431 }3432 3433 // Continue if we see a comma. (Also, allow line continuation.)3434 if (!parseOptionalToken(AsmToken::Comma))3435 break;3436 parseOptionalToken(AsmToken::EndOfStatement);3437 }3438 3439 return false;3440}3441 3442// Initialize real data values.3443bool MasmParser::emitRealValues(const fltSemantics &Semantics,3444 unsigned *Count) {3445 if (checkForValidSection())3446 return true;3447 3448 SmallVector<APInt, 1> ValuesAsInt;3449 if (parseRealInstList(Semantics, ValuesAsInt))3450 return true;3451 3452 for (const APInt &AsInt : ValuesAsInt) {3453 getStreamer().emitIntValue(AsInt);3454 }3455 if (Count)3456 *Count = ValuesAsInt.size();3457 return false;3458}3459 3460// Add a real field to the current struct.3461bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics,3462 size_t Size) {3463 StructInfo &Struct = StructInProgress.back();3464 FieldInfo &Field = Struct.addField(Name, FT_REAL, Size);3465 RealFieldInfo &RealInfo = Field.Contents.RealInfo;3466 3467 Field.SizeOf = 0;3468 3469 if (parseRealInstList(Semantics, RealInfo.AsIntValues))3470 return true;3471 3472 Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8;3473 Field.LengthOf = RealInfo.AsIntValues.size();3474 Field.SizeOf = Field.Type * Field.LengthOf;3475 3476 const unsigned FieldEnd = Field.Offset + Field.SizeOf;3477 if (!Struct.IsUnion) {3478 Struct.NextOffset = FieldEnd;3479 }3480 Struct.Size = std::max(Struct.Size, FieldEnd);3481 return false;3482}3483 3484/// parseDirectiveRealValue3485/// ::= (real4 | real8 | real10) [ expression (, expression)* ]3486bool MasmParser::parseDirectiveRealValue(StringRef IDVal,3487 const fltSemantics &Semantics,3488 size_t Size) {3489 if (StructInProgress.empty()) {3490 // Initialize data value.3491 if (emitRealValues(Semantics))3492 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3493 } else if (addRealField("", Semantics, Size)) {3494 return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3495 }3496 return false;3497}3498 3499/// parseDirectiveNamedRealValue3500/// ::= name (real4 | real8 | real10) [ expression (, expression)* ]3501bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName,3502 const fltSemantics &Semantics,3503 unsigned Size, StringRef Name,3504 SMLoc NameLoc) {3505 if (StructInProgress.empty()) {3506 // Initialize named data value.3507 MCSymbol *Sym = getContext().parseSymbol(Name);3508 getStreamer().emitLabel(Sym);3509 unsigned Count;3510 if (emitRealValues(Semantics, &Count))3511 return addErrorSuffix(" in '" + TypeName + "' directive");3512 3513 AsmTypeInfo Type;3514 Type.Name = TypeName;3515 Type.Size = Size * Count;3516 Type.ElementSize = Size;3517 Type.Length = Count;3518 KnownType[Name.lower()] = Type;3519 } else if (addRealField(Name, Semantics, Size)) {3520 return addErrorSuffix(" in '" + TypeName + "' directive");3521 }3522 return false;3523}3524 3525bool MasmParser::parseOptionalAngleBracketOpen() {3526 const AsmToken Tok = getTok();3527 if (parseOptionalToken(AsmToken::LessLess)) {3528 AngleBracketDepth++;3529 Lexer.UnLex(AsmToken(AsmToken::Less, Tok.getString().substr(1)));3530 return true;3531 } else if (parseOptionalToken(AsmToken::LessGreater)) {3532 AngleBracketDepth++;3533 Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));3534 return true;3535 } else if (parseOptionalToken(AsmToken::Less)) {3536 AngleBracketDepth++;3537 return true;3538 }3539 3540 return false;3541}3542 3543bool MasmParser::parseAngleBracketClose(const Twine &Msg) {3544 const AsmToken Tok = getTok();3545 if (parseOptionalToken(AsmToken::GreaterGreater)) {3546 Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));3547 } else if (parseToken(AsmToken::Greater, Msg)) {3548 return true;3549 }3550 AngleBracketDepth--;3551 return false;3552}3553 3554bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3555 const IntFieldInfo &Contents,3556 FieldInitializer &Initializer) {3557 SMLoc Loc = getTok().getLoc();3558 3559 SmallVector<const MCExpr *, 1> Values;3560 if (parseOptionalToken(AsmToken::LCurly)) {3561 if (Field.LengthOf == 1 && Field.Type > 1)3562 return Error(Loc, "Cannot initialize scalar field with array value");3563 if (parseScalarInstList(Field.Type, Values, AsmToken::RCurly) ||3564 parseToken(AsmToken::RCurly))3565 return true;3566 } else if (parseOptionalAngleBracketOpen()) {3567 if (Field.LengthOf == 1 && Field.Type > 1)3568 return Error(Loc, "Cannot initialize scalar field with array value");3569 if (parseScalarInstList(Field.Type, Values, AsmToken::Greater) ||3570 parseAngleBracketClose())3571 return true;3572 } else if (Field.LengthOf > 1 && Field.Type > 1) {3573 return Error(Loc, "Cannot initialize array field with scalar value");3574 } else if (parseScalarInitializer(Field.Type, Values,3575 /*StringPadLength=*/Field.LengthOf)) {3576 return true;3577 }3578 3579 if (Values.size() > Field.LengthOf) {3580 return Error(Loc, "Initializer too long for field; expected at most " +3581 std::to_string(Field.LengthOf) + " elements, got " +3582 std::to_string(Values.size()));3583 }3584 // Default-initialize all remaining values.3585 Values.append(Contents.Values.begin() + Values.size(), Contents.Values.end());3586 3587 Initializer = FieldInitializer(std::move(Values));3588 return false;3589}3590 3591bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3592 const RealFieldInfo &Contents,3593 FieldInitializer &Initializer) {3594 const fltSemantics *Semantics;3595 switch (Field.Type) {3596 case 4:3597 Semantics = &APFloat::IEEEsingle();3598 break;3599 case 8:3600 Semantics = &APFloat::IEEEdouble();3601 break;3602 case 10:3603 Semantics = &APFloat::x87DoubleExtended();3604 break;3605 default:3606 llvm_unreachable("unknown real field type");3607 }3608 3609 SMLoc Loc = getTok().getLoc();3610 3611 SmallVector<APInt, 1> AsIntValues;3612 if (parseOptionalToken(AsmToken::LCurly)) {3613 if (Field.LengthOf == 1)3614 return Error(Loc, "Cannot initialize scalar field with array value");3615 if (parseRealInstList(*Semantics, AsIntValues, AsmToken::RCurly) ||3616 parseToken(AsmToken::RCurly))3617 return true;3618 } else if (parseOptionalAngleBracketOpen()) {3619 if (Field.LengthOf == 1)3620 return Error(Loc, "Cannot initialize scalar field with array value");3621 if (parseRealInstList(*Semantics, AsIntValues, AsmToken::Greater) ||3622 parseAngleBracketClose())3623 return true;3624 } else if (Field.LengthOf > 1) {3625 return Error(Loc, "Cannot initialize array field with scalar value");3626 } else {3627 AsIntValues.emplace_back();3628 if (parseRealValue(*Semantics, AsIntValues.back()))3629 return true;3630 }3631 3632 if (AsIntValues.size() > Field.LengthOf) {3633 return Error(Loc, "Initializer too long for field; expected at most " +3634 std::to_string(Field.LengthOf) + " elements, got " +3635 std::to_string(AsIntValues.size()));3636 }3637 // Default-initialize all remaining values.3638 AsIntValues.append(Contents.AsIntValues.begin() + AsIntValues.size(),3639 Contents.AsIntValues.end());3640 3641 Initializer = FieldInitializer(std::move(AsIntValues));3642 return false;3643}3644 3645bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3646 const StructFieldInfo &Contents,3647 FieldInitializer &Initializer) {3648 SMLoc Loc = getTok().getLoc();3649 3650 std::vector<StructInitializer> Initializers;3651 if (Field.LengthOf > 1) {3652 if (parseOptionalToken(AsmToken::LCurly)) {3653 if (parseStructInstList(Contents.Structure, Initializers,3654 AsmToken::RCurly) ||3655 parseToken(AsmToken::RCurly))3656 return true;3657 } else if (parseOptionalAngleBracketOpen()) {3658 if (parseStructInstList(Contents.Structure, Initializers,3659 AsmToken::Greater) ||3660 parseAngleBracketClose())3661 return true;3662 } else {3663 return Error(Loc, "Cannot initialize array field with scalar value");3664 }3665 } else {3666 Initializers.emplace_back();3667 if (parseStructInitializer(Contents.Structure, Initializers.back()))3668 return true;3669 }3670 3671 if (Initializers.size() > Field.LengthOf) {3672 return Error(Loc, "Initializer too long for field; expected at most " +3673 std::to_string(Field.LengthOf) + " elements, got " +3674 std::to_string(Initializers.size()));3675 }3676 // Default-initialize all remaining values.3677 llvm::append_range(Initializers, llvm::drop_begin(Contents.Initializers,3678 Initializers.size()));3679 3680 Initializer = FieldInitializer(std::move(Initializers), Contents.Structure);3681 return false;3682}3683 3684bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3685 FieldInitializer &Initializer) {3686 switch (Field.Contents.FT) {3687 case FT_INTEGRAL:3688 return parseFieldInitializer(Field, Field.Contents.IntInfo, Initializer);3689 case FT_REAL:3690 return parseFieldInitializer(Field, Field.Contents.RealInfo, Initializer);3691 case FT_STRUCT:3692 return parseFieldInitializer(Field, Field.Contents.StructInfo, Initializer);3693 }3694 llvm_unreachable("Unhandled FieldType enum");3695}3696 3697bool MasmParser::parseStructInitializer(const StructInfo &Structure,3698 StructInitializer &Initializer) {3699 const AsmToken FirstToken = getTok();3700 3701 std::optional<AsmToken::TokenKind> EndToken;3702 if (parseOptionalToken(AsmToken::LCurly)) {3703 EndToken = AsmToken::RCurly;3704 } else if (parseOptionalAngleBracketOpen()) {3705 EndToken = AsmToken::Greater;3706 AngleBracketDepth++;3707 } else if (FirstToken.is(AsmToken::Identifier) &&3708 FirstToken.getString() == "?") {3709 // ? initializer; leave EndToken uninitialized to treat as empty.3710 if (parseToken(AsmToken::Identifier))3711 return true;3712 } else {3713 return Error(FirstToken.getLoc(), "Expected struct initializer");3714 }3715 3716 auto &FieldInitializers = Initializer.FieldInitializers;3717 size_t FieldIndex = 0;3718 if (EndToken) {3719 // Initialize all fields with given initializers.3720 while (getTok().isNot(*EndToken) && FieldIndex < Structure.Fields.size()) {3721 const FieldInfo &Field = Structure.Fields[FieldIndex++];3722 if (parseOptionalToken(AsmToken::Comma)) {3723 // Empty initializer; use the default and continue. (Also, allow line3724 // continuation.)3725 FieldInitializers.push_back(Field.Contents);3726 parseOptionalToken(AsmToken::EndOfStatement);3727 continue;3728 }3729 FieldInitializers.emplace_back(Field.Contents.FT);3730 if (parseFieldInitializer(Field, FieldInitializers.back()))3731 return true;3732 3733 // Continue if we see a comma. (Also, allow line continuation.)3734 SMLoc CommaLoc = getTok().getLoc();3735 if (!parseOptionalToken(AsmToken::Comma))3736 break;3737 if (FieldIndex == Structure.Fields.size())3738 return Error(CommaLoc, "'" + Structure.Name +3739 "' initializer initializes too many fields");3740 parseOptionalToken(AsmToken::EndOfStatement);3741 }3742 }3743 // Default-initialize all remaining fields.3744 for (const FieldInfo &Field : llvm::drop_begin(Structure.Fields, FieldIndex))3745 FieldInitializers.push_back(Field.Contents);3746 3747 if (EndToken) {3748 if (*EndToken == AsmToken::Greater)3749 return parseAngleBracketClose();3750 3751 return parseToken(*EndToken);3752 }3753 3754 return false;3755}3756 3757bool MasmParser::parseStructInstList(3758 const StructInfo &Structure, std::vector<StructInitializer> &Initializers,3759 const AsmToken::TokenKind EndToken) {3760 while (getTok().isNot(EndToken) ||3761 (EndToken == AsmToken::Greater &&3762 getTok().isNot(AsmToken::GreaterGreater))) {3763 const AsmToken NextTok = peekTok();3764 if (NextTok.is(AsmToken::Identifier) &&3765 NextTok.getString().equals_insensitive("dup")) {3766 const MCExpr *Value;3767 if (parseExpression(Value) || parseToken(AsmToken::Identifier))3768 return true;3769 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3770 if (!MCE)3771 return Error(Value->getLoc(),3772 "cannot repeat value a non-constant number of times");3773 const int64_t Repetitions = MCE->getValue();3774 if (Repetitions < 0)3775 return Error(Value->getLoc(),3776 "cannot repeat value a negative number of times");3777 3778 std::vector<StructInitializer> DuplicatedValues;3779 if (parseToken(AsmToken::LParen,3780 "parentheses required for 'dup' contents") ||3781 parseStructInstList(Structure, DuplicatedValues) || parseRParen())3782 return true;3783 3784 for (int i = 0; i < Repetitions; ++i)3785 llvm::append_range(Initializers, DuplicatedValues);3786 } else {3787 Initializers.emplace_back();3788 if (parseStructInitializer(Structure, Initializers.back()))3789 return true;3790 }3791 3792 // Continue if we see a comma. (Also, allow line continuation.)3793 if (!parseOptionalToken(AsmToken::Comma))3794 break;3795 parseOptionalToken(AsmToken::EndOfStatement);3796 }3797 3798 return false;3799}3800 3801bool MasmParser::emitFieldValue(const FieldInfo &Field,3802 const IntFieldInfo &Contents) {3803 // Default-initialize all values.3804 for (const MCExpr *Value : Contents.Values) {3805 if (emitIntValue(Value, Field.Type))3806 return true;3807 }3808 return false;3809}3810 3811bool MasmParser::emitFieldValue(const FieldInfo &Field,3812 const RealFieldInfo &Contents) {3813 for (const APInt &AsInt : Contents.AsIntValues) {3814 getStreamer().emitIntValue(AsInt.getLimitedValue(),3815 AsInt.getBitWidth() / 8);3816 }3817 return false;3818}3819 3820bool MasmParser::emitFieldValue(const FieldInfo &Field,3821 const StructFieldInfo &Contents) {3822 for (const auto &Initializer : Contents.Initializers) {3823 size_t Index = 0, Offset = 0;3824 for (const auto &SubField : Contents.Structure.Fields) {3825 getStreamer().emitZeros(SubField.Offset - Offset);3826 Offset = SubField.Offset + SubField.SizeOf;3827 emitFieldInitializer(SubField, Initializer.FieldInitializers[Index++]);3828 }3829 }3830 return false;3831}3832 3833bool MasmParser::emitFieldValue(const FieldInfo &Field) {3834 switch (Field.Contents.FT) {3835 case FT_INTEGRAL:3836 return emitFieldValue(Field, Field.Contents.IntInfo);3837 case FT_REAL:3838 return emitFieldValue(Field, Field.Contents.RealInfo);3839 case FT_STRUCT:3840 return emitFieldValue(Field, Field.Contents.StructInfo);3841 }3842 llvm_unreachable("Unhandled FieldType enum");3843}3844 3845bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3846 const IntFieldInfo &Contents,3847 const IntFieldInfo &Initializer) {3848 for (const auto &Value : Initializer.Values) {3849 if (emitIntValue(Value, Field.Type))3850 return true;3851 }3852 // Default-initialize all remaining values.3853 for (const auto &Value :3854 llvm::drop_begin(Contents.Values, Initializer.Values.size())) {3855 if (emitIntValue(Value, Field.Type))3856 return true;3857 }3858 return false;3859}3860 3861bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3862 const RealFieldInfo &Contents,3863 const RealFieldInfo &Initializer) {3864 for (const auto &AsInt : Initializer.AsIntValues) {3865 getStreamer().emitIntValue(AsInt.getLimitedValue(),3866 AsInt.getBitWidth() / 8);3867 }3868 // Default-initialize all remaining values.3869 for (const auto &AsInt :3870 llvm::drop_begin(Contents.AsIntValues, Initializer.AsIntValues.size())) {3871 getStreamer().emitIntValue(AsInt.getLimitedValue(),3872 AsInt.getBitWidth() / 8);3873 }3874 return false;3875}3876 3877bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3878 const StructFieldInfo &Contents,3879 const StructFieldInfo &Initializer) {3880 for (const auto &Init : Initializer.Initializers) {3881 if (emitStructInitializer(Contents.Structure, Init))3882 return true;3883 }3884 // Default-initialize all remaining values.3885 for (const auto &Init : llvm::drop_begin(Contents.Initializers,3886 Initializer.Initializers.size())) {3887 if (emitStructInitializer(Contents.Structure, Init))3888 return true;3889 }3890 return false;3891}3892 3893bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3894 const FieldInitializer &Initializer) {3895 switch (Field.Contents.FT) {3896 case FT_INTEGRAL:3897 return emitFieldInitializer(Field, Field.Contents.IntInfo,3898 Initializer.IntInfo);3899 case FT_REAL:3900 return emitFieldInitializer(Field, Field.Contents.RealInfo,3901 Initializer.RealInfo);3902 case FT_STRUCT:3903 return emitFieldInitializer(Field, Field.Contents.StructInfo,3904 Initializer.StructInfo);3905 }3906 llvm_unreachable("Unhandled FieldType enum");3907}3908 3909bool MasmParser::emitStructInitializer(const StructInfo &Structure,3910 const StructInitializer &Initializer) {3911 if (!Structure.Initializable)3912 return Error(getLexer().getLoc(),3913 "cannot initialize a value of type '" + Structure.Name +3914 "'; 'org' was used in the type's declaration");3915 size_t Index = 0, Offset = 0;3916 for (const auto &Init : Initializer.FieldInitializers) {3917 const auto &Field = Structure.Fields[Index++];3918 getStreamer().emitZeros(Field.Offset - Offset);3919 Offset = Field.Offset + Field.SizeOf;3920 if (emitFieldInitializer(Field, Init))3921 return true;3922 }3923 // Default-initialize all remaining fields.3924 for (const auto &Field : llvm::drop_begin(3925 Structure.Fields, Initializer.FieldInitializers.size())) {3926 getStreamer().emitZeros(Field.Offset - Offset);3927 Offset = Field.Offset + Field.SizeOf;3928 if (emitFieldValue(Field))3929 return true;3930 }3931 // Add final padding.3932 if (Offset != Structure.Size)3933 getStreamer().emitZeros(Structure.Size - Offset);3934 return false;3935}3936 3937// Set data values from initializers.3938bool MasmParser::emitStructValues(const StructInfo &Structure,3939 unsigned *Count) {3940 std::vector<StructInitializer> Initializers;3941 if (parseStructInstList(Structure, Initializers))3942 return true;3943 3944 for (const auto &Initializer : Initializers) {3945 if (emitStructInitializer(Structure, Initializer))3946 return true;3947 }3948 3949 if (Count)3950 *Count = Initializers.size();3951 return false;3952}3953 3954// Declare a field in the current struct.3955bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) {3956 StructInfo &OwningStruct = StructInProgress.back();3957 FieldInfo &Field =3958 OwningStruct.addField(Name, FT_STRUCT, Structure.AlignmentSize);3959 StructFieldInfo &StructInfo = Field.Contents.StructInfo;3960 3961 StructInfo.Structure = Structure;3962 Field.Type = Structure.Size;3963 3964 if (parseStructInstList(Structure, StructInfo.Initializers))3965 return true;3966 3967 Field.LengthOf = StructInfo.Initializers.size();3968 Field.SizeOf = Field.Type * Field.LengthOf;3969 3970 const unsigned FieldEnd = Field.Offset + Field.SizeOf;3971 if (!OwningStruct.IsUnion) {3972 OwningStruct.NextOffset = FieldEnd;3973 }3974 OwningStruct.Size = std::max(OwningStruct.Size, FieldEnd);3975 3976 return false;3977}3978 3979/// parseDirectiveStructValue3980/// ::= struct-id (<struct-initializer> | {struct-initializer})3981/// [, (<struct-initializer> | {struct-initializer})]*3982bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure,3983 StringRef Directive, SMLoc DirLoc) {3984 if (StructInProgress.empty()) {3985 if (emitStructValues(Structure))3986 return true;3987 } else if (addStructField("", Structure)) {3988 return addErrorSuffix(" in '" + Twine(Directive) + "' directive");3989 }3990 3991 return false;3992}3993 3994/// parseDirectiveNamedValue3995/// ::= name (byte | word | ... ) [ expression (, expression)* ]3996bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure,3997 StringRef Directive,3998 SMLoc DirLoc, StringRef Name) {3999 if (StructInProgress.empty()) {4000 // Initialize named data value.4001 MCSymbol *Sym = getContext().parseSymbol(Name);4002 getStreamer().emitLabel(Sym);4003 unsigned Count;4004 if (emitStructValues(Structure, &Count))4005 return true;4006 AsmTypeInfo Type;4007 Type.Name = Structure.Name;4008 Type.Size = Structure.Size * Count;4009 Type.ElementSize = Structure.Size;4010 Type.Length = Count;4011 KnownType[Name.lower()] = Type;4012 } else if (addStructField(Name, Structure)) {4013 return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4014 }4015 4016 return false;4017}4018 4019/// parseDirectiveStruct4020/// ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE]4021/// (dataDir | generalDir | offsetDir | nestedStruct)+4022/// <name> ENDS4023////// dataDir = data declaration4024////// offsetDir = EVEN, ORG, ALIGN4025bool MasmParser::parseDirectiveStruct(StringRef Directive,4026 DirectiveKind DirKind, StringRef Name,4027 SMLoc NameLoc) {4028 // We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS4029 // anyway, so all field accesses must be qualified.4030 AsmToken NextTok = getTok();4031 int64_t AlignmentValue = 1;4032 if (NextTok.isNot(AsmToken::Comma) &&4033 NextTok.isNot(AsmToken::EndOfStatement) &&4034 parseAbsoluteExpression(AlignmentValue)) {4035 return addErrorSuffix(" in alignment value for '" + Twine(Directive) +4036 "' directive");4037 }4038 if (!isPowerOf2_64(AlignmentValue)) {4039 return Error(NextTok.getLoc(), "alignment must be a power of two; was " +4040 std::to_string(AlignmentValue));4041 }4042 4043 StringRef Qualifier;4044 SMLoc QualifierLoc;4045 if (parseOptionalToken(AsmToken::Comma)) {4046 QualifierLoc = getTok().getLoc();4047 if (parseIdentifier(Qualifier))4048 return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4049 if (!Qualifier.equals_insensitive("nonunique"))4050 return Error(QualifierLoc, "Unrecognized qualifier for '" +4051 Twine(Directive) +4052 "' directive; expected none or NONUNIQUE");4053 }4054 4055 if (parseEOL())4056 return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4057 4058 StructInProgress.emplace_back(Name, DirKind == DK_UNION, AlignmentValue);4059 return false;4060}4061 4062/// parseDirectiveNestedStruct4063/// ::= (STRUC | STRUCT | UNION) [name]4064/// (dataDir | generalDir | offsetDir | nestedStruct)+4065/// ENDS4066bool MasmParser::parseDirectiveNestedStruct(StringRef Directive,4067 DirectiveKind DirKind) {4068 if (StructInProgress.empty())4069 return TokError("missing name in top-level '" + Twine(Directive) +4070 "' directive");4071 4072 StringRef Name;4073 if (getTok().is(AsmToken::Identifier)) {4074 Name = getTok().getIdentifier();4075 parseToken(AsmToken::Identifier);4076 }4077 if (parseEOL())4078 return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4079 4080 // Reserve space to ensure Alignment doesn't get invalidated when4081 // StructInProgress grows.4082 StructInProgress.reserve(StructInProgress.size() + 1);4083 StructInProgress.emplace_back(Name, DirKind == DK_UNION,4084 StructInProgress.back().Alignment);4085 return false;4086}4087 4088bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) {4089 if (StructInProgress.empty())4090 return Error(NameLoc, "ENDS directive without matching STRUC/STRUCT/UNION");4091 if (StructInProgress.size() > 1)4092 return Error(NameLoc, "unexpected name in nested ENDS directive");4093 if (StructInProgress.back().Name.compare_insensitive(Name))4094 return Error(NameLoc, "mismatched name in ENDS directive; expected '" +4095 StructInProgress.back().Name + "'");4096 StructInfo Structure = StructInProgress.pop_back_val();4097 // Pad to make the structure's size divisible by the smaller of its alignment4098 // and the size of its largest field.4099 Structure.Size = llvm::alignTo(4100 Structure.Size, std::min(Structure.Alignment, Structure.AlignmentSize));4101 Structs[Name.lower()] = Structure;4102 4103 if (parseEOL())4104 return addErrorSuffix(" in ENDS directive");4105 4106 return false;4107}4108 4109bool MasmParser::parseDirectiveNestedEnds() {4110 if (StructInProgress.empty())4111 return TokError("ENDS directive without matching STRUC/STRUCT/UNION");4112 if (StructInProgress.size() == 1)4113 return TokError("missing name in top-level ENDS directive");4114 4115 if (parseEOL())4116 return addErrorSuffix(" in nested ENDS directive");4117 4118 StructInfo Structure = StructInProgress.pop_back_val();4119 // Pad to make the structure's size divisible by its alignment.4120 Structure.Size = llvm::alignTo(Structure.Size, Structure.Alignment);4121 4122 StructInfo &ParentStruct = StructInProgress.back();4123 if (Structure.Name.empty()) {4124 // Anonymous substructures' fields are addressed as if they belong to the4125 // parent structure - so we transfer them to the parent here.4126 const size_t OldFields = ParentStruct.Fields.size();4127 ParentStruct.Fields.insert(4128 ParentStruct.Fields.end(),4129 std::make_move_iterator(Structure.Fields.begin()),4130 std::make_move_iterator(Structure.Fields.end()));4131 for (const auto &FieldByName : Structure.FieldsByName) {4132 ParentStruct.FieldsByName[FieldByName.getKey()] =4133 FieldByName.getValue() + OldFields;4134 }4135 4136 unsigned FirstFieldOffset = 0;4137 if (!Structure.Fields.empty() && !ParentStruct.IsUnion) {4138 FirstFieldOffset = llvm::alignTo(4139 ParentStruct.NextOffset,4140 std::min(ParentStruct.Alignment, Structure.AlignmentSize));4141 }4142 4143 if (ParentStruct.IsUnion) {4144 ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size);4145 } else {4146 for (auto &Field : llvm::drop_begin(ParentStruct.Fields, OldFields))4147 Field.Offset += FirstFieldOffset;4148 4149 const unsigned StructureEnd = FirstFieldOffset + Structure.Size;4150 if (!ParentStruct.IsUnion) {4151 ParentStruct.NextOffset = StructureEnd;4152 }4153 ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);4154 }4155 } else {4156 FieldInfo &Field = ParentStruct.addField(Structure.Name, FT_STRUCT,4157 Structure.AlignmentSize);4158 StructFieldInfo &StructInfo = Field.Contents.StructInfo;4159 Field.Type = Structure.Size;4160 Field.LengthOf = 1;4161 Field.SizeOf = Structure.Size;4162 4163 const unsigned StructureEnd = Field.Offset + Field.SizeOf;4164 if (!ParentStruct.IsUnion) {4165 ParentStruct.NextOffset = StructureEnd;4166 }4167 ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);4168 4169 StructInfo.Structure = Structure;4170 StructInfo.Initializers.emplace_back();4171 auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers;4172 for (const auto &SubField : Structure.Fields) {4173 FieldInitializers.push_back(SubField.Contents);4174 }4175 }4176 4177 return false;4178}4179 4180/// parseDirectiveOrg4181/// ::= org expression4182bool MasmParser::parseDirectiveOrg() {4183 const MCExpr *Offset;4184 SMLoc OffsetLoc = Lexer.getLoc();4185 if (checkForValidSection() || parseExpression(Offset))4186 return true;4187 if (parseEOL())4188 return addErrorSuffix(" in 'org' directive");4189 4190 if (StructInProgress.empty()) {4191 // Not in a struct; change the offset for the next instruction or data4192 if (checkForValidSection())4193 return addErrorSuffix(" in 'org' directive");4194 4195 getStreamer().emitValueToOffset(Offset, 0, OffsetLoc);4196 } else {4197 // Offset the next field of this struct4198 StructInfo &Structure = StructInProgress.back();4199 int64_t OffsetRes;4200 if (!Offset->evaluateAsAbsolute(OffsetRes, getStreamer().getAssemblerPtr()))4201 return Error(OffsetLoc,4202 "expected absolute expression in 'org' directive");4203 if (OffsetRes < 0)4204 return Error(4205 OffsetLoc,4206 "expected non-negative value in struct's 'org' directive; was " +4207 std::to_string(OffsetRes));4208 Structure.NextOffset = static_cast<unsigned>(OffsetRes);4209 4210 // ORG-affected structures cannot be initialized4211 Structure.Initializable = false;4212 }4213 4214 return false;4215}4216 4217bool MasmParser::emitAlignTo(int64_t Alignment) {4218 if (StructInProgress.empty()) {4219 // Not in a struct; align the next instruction or data4220 if (checkForValidSection())4221 return true;4222 4223 // Check whether we should use optimal code alignment for this align4224 // directive.4225 const MCSection *Section = getStreamer().getCurrentSectionOnly();4226 if (MAI.useCodeAlign(*Section)) {4227 getStreamer().emitCodeAlignment(Align(Alignment),4228 &getTargetParser().getSTI(),4229 /*MaxBytesToEmit=*/0);4230 } else {4231 // FIXME: Target specific behavior about how the "extra" bytes are filled.4232 getStreamer().emitValueToAlignment(Align(Alignment), /*Value=*/0,4233 /*ValueSize=*/1,4234 /*MaxBytesToEmit=*/0);4235 }4236 } else {4237 // Align the next field of this struct4238 StructInfo &Structure = StructInProgress.back();4239 Structure.NextOffset = llvm::alignTo(Structure.NextOffset, Alignment);4240 }4241 4242 return false;4243}4244 4245/// parseDirectiveAlign4246/// ::= align expression4247bool MasmParser::parseDirectiveAlign() {4248 SMLoc AlignmentLoc = getLexer().getLoc();4249 int64_t Alignment;4250 4251 // Ignore empty 'align' directives.4252 if (getTok().is(AsmToken::EndOfStatement)) {4253 return Warning(AlignmentLoc,4254 "align directive with no operand is ignored") &&4255 parseEOL();4256 }4257 if (parseAbsoluteExpression(Alignment) || parseEOL())4258 return addErrorSuffix(" in align directive");4259 4260 // Always emit an alignment here even if we throw an error.4261 bool ReturnVal = false;4262 4263 // Reject alignments that aren't either a power of two or zero, for ML.exe4264 // compatibility. Alignment of zero is silently rounded up to one.4265 if (Alignment == 0)4266 Alignment = 1;4267 if (!isPowerOf2_64(Alignment))4268 ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2; was " +4269 std::to_string(Alignment));4270 4271 if (emitAlignTo(Alignment))4272 ReturnVal |= addErrorSuffix(" in align directive");4273 4274 return ReturnVal;4275}4276 4277/// parseDirectiveEven4278/// ::= even4279bool MasmParser::parseDirectiveEven() {4280 if (parseEOL() || emitAlignTo(2))4281 return addErrorSuffix(" in even directive");4282 4283 return false;4284}4285 4286/// parseDirectiveMacro4287/// ::= name macro [parameters]4288/// ["LOCAL" identifiers]4289/// parameters ::= parameter [, parameter]*4290/// parameter ::= name ":" qualifier4291/// qualifier ::= "req" | "vararg" | "=" macro_argument4292bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {4293 MCAsmMacroParameters Parameters;4294 while (getLexer().isNot(AsmToken::EndOfStatement)) {4295 if (!Parameters.empty() && Parameters.back().Vararg)4296 return Error(Lexer.getLoc(),4297 "Vararg parameter '" + Parameters.back().Name +4298 "' should be last in the list of parameters");4299 4300 MCAsmMacroParameter Parameter;4301 if (parseIdentifier(Parameter.Name))4302 return TokError("expected identifier in 'macro' directive");4303 4304 // Emit an error if two (or more) named parameters share the same name.4305 for (const MCAsmMacroParameter& CurrParam : Parameters)4306 if (CurrParam.Name.equals_insensitive(Parameter.Name))4307 return TokError("macro '" + Name + "' has multiple parameters"4308 " named '" + Parameter.Name + "'");4309 4310 if (Lexer.is(AsmToken::Colon)) {4311 Lex(); // consume ':'4312 4313 if (parseOptionalToken(AsmToken::Equal)) {4314 // Default value4315 SMLoc ParamLoc;4316 4317 ParamLoc = Lexer.getLoc();4318 if (parseMacroArgument(nullptr, Parameter.Value))4319 return true;4320 } else {4321 SMLoc QualLoc;4322 StringRef Qualifier;4323 4324 QualLoc = Lexer.getLoc();4325 if (parseIdentifier(Qualifier))4326 return Error(QualLoc, "missing parameter qualifier for "4327 "'" +4328 Parameter.Name + "' in macro '" + Name +4329 "'");4330 4331 if (Qualifier.equals_insensitive("req"))4332 Parameter.Required = true;4333 else if (Qualifier.equals_insensitive("vararg"))4334 Parameter.Vararg = true;4335 else4336 return Error(QualLoc,4337 Qualifier + " is not a valid parameter qualifier for '" +4338 Parameter.Name + "' in macro '" + Name + "'");4339 }4340 }4341 4342 Parameters.push_back(std::move(Parameter));4343 4344 if (getLexer().is(AsmToken::Comma))4345 Lex();4346 }4347 4348 // Eat just the end of statement.4349 Lexer.Lex();4350 4351 std::vector<std::string> Locals;4352 if (getTok().is(AsmToken::Identifier) &&4353 getTok().getIdentifier().equals_insensitive("local")) {4354 Lex(); // Eat the LOCAL directive.4355 4356 StringRef ID;4357 while (true) {4358 if (parseIdentifier(ID))4359 return true;4360 Locals.push_back(ID.lower());4361 4362 // If we see a comma, continue (and allow line continuation).4363 if (!parseOptionalToken(AsmToken::Comma))4364 break;4365 parseOptionalToken(AsmToken::EndOfStatement);4366 }4367 }4368 4369 // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors.4370 AsmToken EndToken, StartToken = getTok();4371 unsigned MacroDepth = 0;4372 bool IsMacroFunction = false;4373 // Lex the macro definition.4374 while (true) {4375 // Ignore Lexing errors in macros.4376 while (Lexer.is(AsmToken::Error)) {4377 Lexer.Lex();4378 }4379 4380 // Check whether we have reached the end of the file.4381 if (getLexer().is(AsmToken::Eof))4382 return Error(NameLoc, "no matching 'endm' in definition");4383 4384 // Otherwise, check whether we have reached the 'endm'... and determine if4385 // this is a macro function.4386 if (getLexer().is(AsmToken::Identifier)) {4387 if (getTok().getIdentifier().equals_insensitive("endm")) {4388 if (MacroDepth == 0) { // Outermost macro.4389 EndToken = getTok();4390 Lexer.Lex();4391 if (getLexer().isNot(AsmToken::EndOfStatement))4392 return TokError("unexpected token in '" + EndToken.getIdentifier() +4393 "' directive");4394 break;4395 } else {4396 // Otherwise we just found the end of an inner macro.4397 --MacroDepth;4398 }4399 } else if (getTok().getIdentifier().equals_insensitive("exitm")) {4400 if (MacroDepth == 0 && peekTok().isNot(AsmToken::EndOfStatement)) {4401 IsMacroFunction = true;4402 }4403 } else if (isMacroLikeDirective()) {4404 // We allow nested macros. Those aren't instantiated until the4405 // outermost macro is expanded so just ignore them for now.4406 ++MacroDepth;4407 }4408 }4409 4410 // Otherwise, scan til the end of the statement.4411 eatToEndOfStatement();4412 }4413 4414 if (getContext().lookupMacro(Name.lower())) {4415 return Error(NameLoc, "macro '" + Name + "' is already defined");4416 }4417 4418 const char *BodyStart = StartToken.getLoc().getPointer();4419 const char *BodyEnd = EndToken.getLoc().getPointer();4420 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);4421 MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals),4422 IsMacroFunction);4423 DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";4424 Macro.dump());4425 getContext().defineMacro(Name.lower(), std::move(Macro));4426 return false;4427}4428 4429/// parseDirectiveExitMacro4430/// ::= "exitm" [textitem]4431bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc,4432 StringRef Directive,4433 std::string &Value) {4434 SMLoc EndLoc = getTok().getLoc();4435 if (getTok().isNot(AsmToken::EndOfStatement) && parseTextItem(Value))4436 return Error(EndLoc,4437 "unable to parse text item in '" + Directive + "' directive");4438 eatToEndOfStatement();4439 4440 if (!isInsideMacroInstantiation())4441 return TokError("unexpected '" + Directive + "' in file, "4442 "no current macro definition");4443 4444 // Exit all conditionals that are active in the current macro.4445 while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {4446 TheCondState = TheCondStack.back();4447 TheCondStack.pop_back();4448 }4449 4450 handleMacroExit();4451 return false;4452}4453 4454/// parseDirectiveEndMacro4455/// ::= endm4456bool MasmParser::parseDirectiveEndMacro(StringRef Directive) {4457 if (getLexer().isNot(AsmToken::EndOfStatement))4458 return TokError("unexpected token in '" + Directive + "' directive");4459 4460 // If we are inside a macro instantiation, terminate the current4461 // instantiation.4462 if (isInsideMacroInstantiation()) {4463 handleMacroExit();4464 return false;4465 }4466 4467 // Otherwise, this .endmacro is a stray entry in the file; well formed4468 // .endmacro directives are handled during the macro definition parsing.4469 return TokError("unexpected '" + Directive + "' in file, "4470 "no current macro definition");4471}4472 4473/// parseDirectivePurgeMacro4474/// ::= purge identifier ( , identifier )*4475bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {4476 StringRef Name;4477 while (true) {4478 SMLoc NameLoc;4479 if (parseTokenLoc(NameLoc) ||4480 check(parseIdentifier(Name), NameLoc,4481 "expected identifier in 'purge' directive"))4482 return true;4483 4484 DEBUG_WITH_TYPE("asm-macros", dbgs()4485 << "Un-defining macro: " << Name << "\n");4486 if (!getContext().lookupMacro(Name.lower()))4487 return Error(NameLoc, "macro '" + Name + "' is not defined");4488 getContext().undefineMacro(Name.lower());4489 4490 if (!parseOptionalToken(AsmToken::Comma))4491 break;4492 parseOptionalToken(AsmToken::EndOfStatement);4493 }4494 4495 return false;4496}4497 4498bool MasmParser::parseDirectiveExtern() {4499 // .extern is the default - but we still need to take any provided type info.4500 auto parseOp = [&]() -> bool {4501 MCSymbol *Sym;4502 SMLoc NameLoc = getTok().getLoc();4503 if (parseSymbol(Sym))4504 return Error(NameLoc, "expected name");4505 if (parseToken(AsmToken::Colon))4506 return true;4507 4508 StringRef TypeName;4509 SMLoc TypeLoc = getTok().getLoc();4510 if (parseIdentifier(TypeName))4511 return Error(TypeLoc, "expected type");4512 if (!TypeName.equals_insensitive("proc")) {4513 AsmTypeInfo Type;4514 if (lookUpType(TypeName, Type))4515 return Error(TypeLoc, "unrecognized type");4516 KnownType[Sym->getName().lower()] = Type;4517 }4518 4519 static_cast<MCSymbolCOFF *>(Sym)->setExternal(true);4520 getStreamer().emitSymbolAttribute(Sym, MCSA_Extern);4521 4522 return false;4523 };4524 4525 if (parseMany(parseOp))4526 return addErrorSuffix(" in directive 'extern'");4527 return false;4528}4529 4530/// parseDirectiveSymbolAttribute4531/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]4532bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {4533 auto parseOp = [&]() -> bool {4534 SMLoc Loc = getTok().getLoc();4535 MCSymbol *Sym;4536 if (parseSymbol(Sym))4537 return Error(Loc, "expected identifier");4538 4539 // Assembler local symbols don't make any sense here. Complain loudly.4540 if (Sym->isTemporary())4541 return Error(Loc, "non-local symbol required");4542 4543 if (!getStreamer().emitSymbolAttribute(Sym, Attr))4544 return Error(Loc, "unable to emit symbol attribute");4545 return false;4546 };4547 4548 if (parseMany(parseOp))4549 return addErrorSuffix(" in directive");4550 return false;4551}4552 4553/// parseDirectiveComm4554/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]4555bool MasmParser::parseDirectiveComm(bool IsLocal) {4556 if (checkForValidSection())4557 return true;4558 4559 SMLoc IDLoc = getLexer().getLoc();4560 MCSymbol *Sym;4561 if (parseSymbol(Sym))4562 return TokError("expected identifier in directive");4563 4564 if (getLexer().isNot(AsmToken::Comma))4565 return TokError("unexpected token in directive");4566 Lex();4567 4568 int64_t Size;4569 SMLoc SizeLoc = getLexer().getLoc();4570 if (parseAbsoluteExpression(Size))4571 return true;4572 4573 int64_t Pow2Alignment = 0;4574 SMLoc Pow2AlignmentLoc;4575 if (getLexer().is(AsmToken::Comma)) {4576 Lex();4577 Pow2AlignmentLoc = getLexer().getLoc();4578 if (parseAbsoluteExpression(Pow2Alignment))4579 return true;4580 4581 LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();4582 if (IsLocal && LCOMM == LCOMM::NoAlignment)4583 return Error(Pow2AlignmentLoc, "alignment not supported on this target");4584 4585 // If this target takes alignments in bytes (not log) validate and convert.4586 if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||4587 (IsLocal && LCOMM == LCOMM::ByteAlignment)) {4588 if (!isPowerOf2_64(Pow2Alignment))4589 return Error(Pow2AlignmentLoc, "alignment must be a power of 2");4590 Pow2Alignment = Log2_64(Pow2Alignment);4591 }4592 }4593 4594 if (parseEOL())4595 return true;4596 4597 // NOTE: a size of zero for a .comm should create a undefined symbol4598 // but a size of .lcomm creates a bss symbol of size zero.4599 if (Size < 0)4600 return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "4601 "be less than zero");4602 4603 // NOTE: The alignment in the directive is a power of 2 value, the assembler4604 // may internally end up wanting an alignment in bytes.4605 // FIXME: Diagnose overflow.4606 if (Pow2Alignment < 0)4607 return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive "4608 "alignment, can't be less than zero");4609 4610 Sym->redefineIfPossible();4611 if (!Sym->isUndefined())4612 return Error(IDLoc, "invalid symbol redefinition");4613 4614 // Create the Symbol as a common or local common with Size and Pow2Alignment.4615 if (IsLocal) {4616 getStreamer().emitLocalCommonSymbol(Sym, Size,4617 Align(1ULL << Pow2Alignment));4618 return false;4619 }4620 4621 getStreamer().emitCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));4622 return false;4623}4624 4625/// parseDirectiveComment4626/// ::= comment delimiter [[text]]4627/// [[text]]4628/// [[text]] delimiter [[text]]4629bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) {4630 std::string FirstLine = parseStringTo(AsmToken::EndOfStatement);4631 size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A ");4632 assert(DelimiterEnd != std::string::npos);4633 StringRef Delimiter = StringRef(FirstLine).take_front(DelimiterEnd);4634 if (Delimiter.empty())4635 return Error(DirectiveLoc, "no delimiter in 'comment' directive");4636 do {4637 if (getTok().is(AsmToken::Eof))4638 return Error(DirectiveLoc, "unmatched delimiter in 'comment' directive");4639 Lex(); // eat end of statement4640 } while (4641 !StringRef(parseStringTo(AsmToken::EndOfStatement)).contains(Delimiter));4642 return parseEOL();4643}4644 4645/// parseDirectiveInclude4646/// ::= include <filename>4647/// | include filename4648bool MasmParser::parseDirectiveInclude() {4649 // Allow the strings to have escaped octal character sequence.4650 std::string Filename;4651 SMLoc IncludeLoc = getTok().getLoc();4652 4653 if (parseAngleBracketString(Filename))4654 Filename = parseStringTo(AsmToken::EndOfStatement);4655 if (check(Filename.empty(), "missing filename in 'include' directive") ||4656 check(getTok().isNot(AsmToken::EndOfStatement),4657 "unexpected token in 'include' directive") ||4658 // Attempt to switch the lexer to the included file before consuming the4659 // end of statement to avoid losing it when we switch.4660 check(enterIncludeFile(Filename), IncludeLoc,4661 "Could not find include file '" + Filename + "'"))4662 return true;4663 4664 return false;4665}4666 4667/// parseDirectiveIf4668/// ::= .if{,eq,ge,gt,le,lt,ne} expression4669bool MasmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {4670 TheCondStack.push_back(TheCondState);4671 TheCondState.TheCond = AsmCond::IfCond;4672 if (TheCondState.Ignore) {4673 eatToEndOfStatement();4674 } else {4675 int64_t ExprValue;4676 if (parseAbsoluteExpression(ExprValue) || parseEOL())4677 return true;4678 4679 switch (DirKind) {4680 default:4681 llvm_unreachable("unsupported directive");4682 case DK_IF:4683 break;4684 case DK_IFE:4685 ExprValue = ExprValue == 0;4686 break;4687 }4688 4689 TheCondState.CondMet = ExprValue;4690 TheCondState.Ignore = !TheCondState.CondMet;4691 }4692 4693 return false;4694}4695 4696/// parseDirectiveIfb4697/// ::= .ifb textitem4698bool MasmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {4699 TheCondStack.push_back(TheCondState);4700 TheCondState.TheCond = AsmCond::IfCond;4701 4702 if (TheCondState.Ignore) {4703 eatToEndOfStatement();4704 } else {4705 std::string Str;4706 if (parseTextItem(Str))4707 return TokError("expected text item parameter for 'ifb' directive");4708 4709 if (parseEOL())4710 return true;4711 4712 TheCondState.CondMet = ExpectBlank == Str.empty();4713 TheCondState.Ignore = !TheCondState.CondMet;4714 }4715 4716 return false;4717}4718 4719/// parseDirectiveIfidn4720/// ::= ifidn textitem, textitem4721bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,4722 bool CaseInsensitive) {4723 std::string String1, String2;4724 4725 if (parseTextItem(String1)) {4726 if (ExpectEqual)4727 return TokError("expected text item parameter for 'ifidn' directive");4728 return TokError("expected text item parameter for 'ifdif' directive");4729 }4730 4731 if (Lexer.isNot(AsmToken::Comma)) {4732 if (ExpectEqual)4733 return TokError(4734 "expected comma after first string for 'ifidn' directive");4735 return TokError("expected comma after first string for 'ifdif' directive");4736 }4737 Lex();4738 4739 if (parseTextItem(String2)) {4740 if (ExpectEqual)4741 return TokError("expected text item parameter for 'ifidn' directive");4742 return TokError("expected text item parameter for 'ifdif' directive");4743 }4744 4745 TheCondStack.push_back(TheCondState);4746 TheCondState.TheCond = AsmCond::IfCond;4747 if (CaseInsensitive)4748 TheCondState.CondMet =4749 ExpectEqual == (StringRef(String1).equals_insensitive(String2));4750 else4751 TheCondState.CondMet = ExpectEqual == (String1 == String2);4752 TheCondState.Ignore = !TheCondState.CondMet;4753 4754 return false;4755}4756 4757/// parseDirectiveIfdef4758/// ::= ifdef symbol4759/// | ifdef variable4760bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {4761 TheCondStack.push_back(TheCondState);4762 TheCondState.TheCond = AsmCond::IfCond;4763 4764 if (TheCondState.Ignore) {4765 eatToEndOfStatement();4766 } else {4767 bool is_defined = false;4768 MCRegister Reg;4769 SMLoc StartLoc, EndLoc;4770 is_defined =4771 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();4772 if (!is_defined) {4773 StringRef Name;4774 if (check(parseIdentifier(Name), "expected identifier after 'ifdef'") ||4775 parseEOL())4776 return true;4777 4778 if (BuiltinSymbolMap.contains(Name.lower())) {4779 is_defined = true;4780 } else if (Variables.contains(Name.lower())) {4781 is_defined = true;4782 } else {4783 MCSymbol *Sym = getContext().lookupSymbol(Name.lower());4784 is_defined = (Sym && !Sym->isUndefined());4785 }4786 }4787 4788 TheCondState.CondMet = (is_defined == expect_defined);4789 TheCondState.Ignore = !TheCondState.CondMet;4790 }4791 4792 return false;4793}4794 4795/// parseDirectiveElseIf4796/// ::= elseif expression4797bool MasmParser::parseDirectiveElseIf(SMLoc DirectiveLoc,4798 DirectiveKind DirKind) {4799 if (TheCondState.TheCond != AsmCond::IfCond &&4800 TheCondState.TheCond != AsmCond::ElseIfCond)4801 return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"4802 " .if or an .elseif");4803 TheCondState.TheCond = AsmCond::ElseIfCond;4804 4805 bool LastIgnoreState = false;4806 if (!TheCondStack.empty())4807 LastIgnoreState = TheCondStack.back().Ignore;4808 if (LastIgnoreState || TheCondState.CondMet) {4809 TheCondState.Ignore = true;4810 eatToEndOfStatement();4811 } else {4812 int64_t ExprValue;4813 if (parseAbsoluteExpression(ExprValue))4814 return true;4815 4816 if (parseEOL())4817 return true;4818 4819 switch (DirKind) {4820 default:4821 llvm_unreachable("unsupported directive");4822 case DK_ELSEIF:4823 break;4824 case DK_ELSEIFE:4825 ExprValue = ExprValue == 0;4826 break;4827 }4828 4829 TheCondState.CondMet = ExprValue;4830 TheCondState.Ignore = !TheCondState.CondMet;4831 }4832 4833 return false;4834}4835 4836/// parseDirectiveElseIfb4837/// ::= elseifb textitem4838bool MasmParser::parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank) {4839 if (TheCondState.TheCond != AsmCond::IfCond &&4840 TheCondState.TheCond != AsmCond::ElseIfCond)4841 return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4842 " if or an elseif");4843 TheCondState.TheCond = AsmCond::ElseIfCond;4844 4845 bool LastIgnoreState = false;4846 if (!TheCondStack.empty())4847 LastIgnoreState = TheCondStack.back().Ignore;4848 if (LastIgnoreState || TheCondState.CondMet) {4849 TheCondState.Ignore = true;4850 eatToEndOfStatement();4851 } else {4852 std::string Str;4853 if (parseTextItem(Str)) {4854 if (ExpectBlank)4855 return TokError("expected text item parameter for 'elseifb' directive");4856 return TokError("expected text item parameter for 'elseifnb' directive");4857 }4858 4859 if (parseEOL())4860 return true;4861 4862 TheCondState.CondMet = ExpectBlank == Str.empty();4863 TheCondState.Ignore = !TheCondState.CondMet;4864 }4865 4866 return false;4867}4868 4869/// parseDirectiveElseIfdef4870/// ::= elseifdef symbol4871/// | elseifdef variable4872bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc,4873 bool expect_defined) {4874 if (TheCondState.TheCond != AsmCond::IfCond &&4875 TheCondState.TheCond != AsmCond::ElseIfCond)4876 return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4877 " if or an elseif");4878 TheCondState.TheCond = AsmCond::ElseIfCond;4879 4880 bool LastIgnoreState = false;4881 if (!TheCondStack.empty())4882 LastIgnoreState = TheCondStack.back().Ignore;4883 if (LastIgnoreState || TheCondState.CondMet) {4884 TheCondState.Ignore = true;4885 eatToEndOfStatement();4886 } else {4887 bool is_defined = false;4888 MCRegister Reg;4889 SMLoc StartLoc, EndLoc;4890 is_defined =4891 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();4892 if (!is_defined) {4893 StringRef Name;4894 if (check(parseIdentifier(Name),4895 "expected identifier after 'elseifdef'") ||4896 parseEOL())4897 return true;4898 4899 if (BuiltinSymbolMap.contains(Name.lower())) {4900 is_defined = true;4901 } else if (Variables.contains(Name.lower())) {4902 is_defined = true;4903 } else {4904 MCSymbol *Sym = getContext().lookupSymbol(Name);4905 is_defined = (Sym && !Sym->isUndefined());4906 }4907 }4908 4909 TheCondState.CondMet = (is_defined == expect_defined);4910 TheCondState.Ignore = !TheCondState.CondMet;4911 }4912 4913 return false;4914}4915 4916/// parseDirectiveElseIfidn4917/// ::= elseifidn textitem, textitem4918bool MasmParser::parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,4919 bool CaseInsensitive) {4920 if (TheCondState.TheCond != AsmCond::IfCond &&4921 TheCondState.TheCond != AsmCond::ElseIfCond)4922 return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4923 " if or an elseif");4924 TheCondState.TheCond = AsmCond::ElseIfCond;4925 4926 bool LastIgnoreState = false;4927 if (!TheCondStack.empty())4928 LastIgnoreState = TheCondStack.back().Ignore;4929 if (LastIgnoreState || TheCondState.CondMet) {4930 TheCondState.Ignore = true;4931 eatToEndOfStatement();4932 } else {4933 std::string String1, String2;4934 4935 if (parseTextItem(String1)) {4936 if (ExpectEqual)4937 return TokError(4938 "expected text item parameter for 'elseifidn' directive");4939 return TokError("expected text item parameter for 'elseifdif' directive");4940 }4941 4942 if (Lexer.isNot(AsmToken::Comma)) {4943 if (ExpectEqual)4944 return TokError(4945 "expected comma after first string for 'elseifidn' directive");4946 return TokError(4947 "expected comma after first string for 'elseifdif' directive");4948 }4949 Lex();4950 4951 if (parseTextItem(String2)) {4952 if (ExpectEqual)4953 return TokError(4954 "expected text item parameter for 'elseifidn' directive");4955 return TokError("expected text item parameter for 'elseifdif' directive");4956 }4957 4958 if (CaseInsensitive)4959 TheCondState.CondMet =4960 ExpectEqual == (StringRef(String1).equals_insensitive(String2));4961 else4962 TheCondState.CondMet = ExpectEqual == (String1 == String2);4963 TheCondState.Ignore = !TheCondState.CondMet;4964 }4965 4966 return false;4967}4968 4969/// parseDirectiveElse4970/// ::= else4971bool MasmParser::parseDirectiveElse(SMLoc DirectiveLoc) {4972 if (parseEOL())4973 return true;4974 4975 if (TheCondState.TheCond != AsmCond::IfCond &&4976 TheCondState.TheCond != AsmCond::ElseIfCond)4977 return Error(DirectiveLoc, "Encountered an else that doesn't follow an if"4978 " or an elseif");4979 TheCondState.TheCond = AsmCond::ElseCond;4980 bool LastIgnoreState = false;4981 if (!TheCondStack.empty())4982 LastIgnoreState = TheCondStack.back().Ignore;4983 if (LastIgnoreState || TheCondState.CondMet)4984 TheCondState.Ignore = true;4985 else4986 TheCondState.Ignore = false;4987 4988 return false;4989}4990 4991/// parseDirectiveEnd4992/// ::= end4993bool MasmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {4994 if (parseEOL())4995 return true;4996 4997 while (Lexer.isNot(AsmToken::Eof))4998 Lexer.Lex();4999 5000 return false;5001}5002 5003/// parseDirectiveError5004/// ::= .err [message]5005bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) {5006 if (!TheCondStack.empty()) {5007 if (TheCondStack.back().Ignore) {5008 eatToEndOfStatement();5009 return false;5010 }5011 }5012 5013 std::string Message = ".err directive invoked in source file";5014 if (Lexer.isNot(AsmToken::EndOfStatement))5015 Message = parseStringTo(AsmToken::EndOfStatement);5016 Lex();5017 5018 return Error(DirectiveLoc, Message);5019}5020 5021/// parseDirectiveErrorIfb5022/// ::= .errb textitem[, message]5023bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) {5024 if (!TheCondStack.empty()) {5025 if (TheCondStack.back().Ignore) {5026 eatToEndOfStatement();5027 return false;5028 }5029 }5030 5031 std::string Text;5032 if (parseTextItem(Text))5033 return Error(getTok().getLoc(), "missing text item in '.errb' directive");5034 5035 std::string Message = ".errb directive invoked in source file";5036 if (Lexer.isNot(AsmToken::EndOfStatement)) {5037 if (parseToken(AsmToken::Comma))5038 return addErrorSuffix(" in '.errb' directive");5039 Message = parseStringTo(AsmToken::EndOfStatement);5040 }5041 Lex();5042 5043 if (Text.empty() == ExpectBlank)5044 return Error(DirectiveLoc, Message);5045 return false;5046}5047 5048/// parseDirectiveErrorIfdef5049/// ::= .errdef name[, message]5050bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc,5051 bool ExpectDefined) {5052 if (!TheCondStack.empty()) {5053 if (TheCondStack.back().Ignore) {5054 eatToEndOfStatement();5055 return false;5056 }5057 }5058 5059 bool IsDefined = false;5060 MCRegister Reg;5061 SMLoc StartLoc, EndLoc;5062 IsDefined =5063 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();5064 if (!IsDefined) {5065 StringRef Name;5066 if (check(parseIdentifier(Name), "expected identifier after '.errdef'"))5067 return true;5068 5069 if (BuiltinSymbolMap.contains(Name.lower())) {5070 IsDefined = true;5071 } else if (Variables.contains(Name.lower())) {5072 IsDefined = true;5073 } else {5074 MCSymbol *Sym = getContext().lookupSymbol(Name);5075 IsDefined = (Sym && !Sym->isUndefined());5076 }5077 }5078 5079 std::string Message = ".errdef directive invoked in source file";5080 if (Lexer.isNot(AsmToken::EndOfStatement)) {5081 if (parseToken(AsmToken::Comma))5082 return addErrorSuffix(" in '.errdef' directive");5083 Message = parseStringTo(AsmToken::EndOfStatement);5084 }5085 Lex();5086 5087 if (IsDefined == ExpectDefined)5088 return Error(DirectiveLoc, Message);5089 return false;5090}5091 5092/// parseDirectiveErrorIfidn5093/// ::= .erridn textitem, textitem[, message]5094bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,5095 bool CaseInsensitive) {5096 if (!TheCondStack.empty()) {5097 if (TheCondStack.back().Ignore) {5098 eatToEndOfStatement();5099 return false;5100 }5101 }5102 5103 std::string String1, String2;5104 5105 if (parseTextItem(String1)) {5106 if (ExpectEqual)5107 return TokError("expected string parameter for '.erridn' directive");5108 return TokError("expected string parameter for '.errdif' directive");5109 }5110 5111 if (Lexer.isNot(AsmToken::Comma)) {5112 if (ExpectEqual)5113 return TokError(5114 "expected comma after first string for '.erridn' directive");5115 return TokError(5116 "expected comma after first string for '.errdif' directive");5117 }5118 Lex();5119 5120 if (parseTextItem(String2)) {5121 if (ExpectEqual)5122 return TokError("expected string parameter for '.erridn' directive");5123 return TokError("expected string parameter for '.errdif' directive");5124 }5125 5126 std::string Message;5127 if (ExpectEqual)5128 Message = ".erridn directive invoked in source file";5129 else5130 Message = ".errdif directive invoked in source file";5131 if (Lexer.isNot(AsmToken::EndOfStatement)) {5132 if (parseToken(AsmToken::Comma))5133 return addErrorSuffix(" in '.erridn' directive");5134 Message = parseStringTo(AsmToken::EndOfStatement);5135 }5136 Lex();5137 5138 if (CaseInsensitive)5139 TheCondState.CondMet =5140 ExpectEqual == (StringRef(String1).equals_insensitive(String2));5141 else5142 TheCondState.CondMet = ExpectEqual == (String1 == String2);5143 TheCondState.Ignore = !TheCondState.CondMet;5144 5145 if ((CaseInsensitive &&5146 ExpectEqual == StringRef(String1).equals_insensitive(String2)) ||5147 (ExpectEqual == (String1 == String2)))5148 return Error(DirectiveLoc, Message);5149 return false;5150}5151 5152/// parseDirectiveErrorIfe5153/// ::= .erre expression[, message]5154bool MasmParser::parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero) {5155 if (!TheCondStack.empty()) {5156 if (TheCondStack.back().Ignore) {5157 eatToEndOfStatement();5158 return false;5159 }5160 }5161 5162 int64_t ExprValue;5163 if (parseAbsoluteExpression(ExprValue))5164 return addErrorSuffix(" in '.erre' directive");5165 5166 std::string Message = ".erre directive invoked in source file";5167 if (Lexer.isNot(AsmToken::EndOfStatement)) {5168 if (parseToken(AsmToken::Comma))5169 return addErrorSuffix(" in '.erre' directive");5170 Message = parseStringTo(AsmToken::EndOfStatement);5171 }5172 Lex();5173 5174 if ((ExprValue == 0) == ExpectZero)5175 return Error(DirectiveLoc, Message);5176 return false;5177}5178 5179/// parseDirectiveEndIf5180/// ::= .endif5181bool MasmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {5182 if (parseEOL())5183 return true;5184 5185 if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())5186 return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "5187 "an .if or .else");5188 if (!TheCondStack.empty()) {5189 TheCondState = TheCondStack.back();5190 TheCondStack.pop_back();5191 }5192 5193 return false;5194}5195 5196void MasmParser::initializeDirectiveKindMap() {5197 DirectiveKindMap["="] = DK_ASSIGN;5198 DirectiveKindMap["equ"] = DK_EQU;5199 DirectiveKindMap["textequ"] = DK_TEXTEQU;5200 // DirectiveKindMap[".ascii"] = DK_ASCII;5201 // DirectiveKindMap[".asciz"] = DK_ASCIZ;5202 // DirectiveKindMap[".string"] = DK_STRING;5203 DirectiveKindMap["byte"] = DK_BYTE;5204 DirectiveKindMap["sbyte"] = DK_SBYTE;5205 DirectiveKindMap["word"] = DK_WORD;5206 DirectiveKindMap["sword"] = DK_SWORD;5207 DirectiveKindMap["dword"] = DK_DWORD;5208 DirectiveKindMap["sdword"] = DK_SDWORD;5209 DirectiveKindMap["fword"] = DK_FWORD;5210 DirectiveKindMap["qword"] = DK_QWORD;5211 DirectiveKindMap["sqword"] = DK_SQWORD;5212 DirectiveKindMap["real4"] = DK_REAL4;5213 DirectiveKindMap["real8"] = DK_REAL8;5214 DirectiveKindMap["real10"] = DK_REAL10;5215 DirectiveKindMap["align"] = DK_ALIGN;5216 DirectiveKindMap["even"] = DK_EVEN;5217 DirectiveKindMap["org"] = DK_ORG;5218 DirectiveKindMap["extern"] = DK_EXTERN;5219 DirectiveKindMap["extrn"] = DK_EXTERN;5220 DirectiveKindMap["public"] = DK_PUBLIC;5221 // DirectiveKindMap[".comm"] = DK_COMM;5222 DirectiveKindMap["comment"] = DK_COMMENT;5223 DirectiveKindMap["include"] = DK_INCLUDE;5224 DirectiveKindMap["repeat"] = DK_REPEAT;5225 DirectiveKindMap["rept"] = DK_REPEAT;5226 DirectiveKindMap["while"] = DK_WHILE;5227 DirectiveKindMap["for"] = DK_FOR;5228 DirectiveKindMap["irp"] = DK_FOR;5229 DirectiveKindMap["forc"] = DK_FORC;5230 DirectiveKindMap["irpc"] = DK_FORC;5231 DirectiveKindMap["if"] = DK_IF;5232 DirectiveKindMap["ife"] = DK_IFE;5233 DirectiveKindMap["ifb"] = DK_IFB;5234 DirectiveKindMap["ifnb"] = DK_IFNB;5235 DirectiveKindMap["ifdef"] = DK_IFDEF;5236 DirectiveKindMap["ifndef"] = DK_IFNDEF;5237 DirectiveKindMap["ifdif"] = DK_IFDIF;5238 DirectiveKindMap["ifdifi"] = DK_IFDIFI;5239 DirectiveKindMap["ifidn"] = DK_IFIDN;5240 DirectiveKindMap["ifidni"] = DK_IFIDNI;5241 DirectiveKindMap["elseif"] = DK_ELSEIF;5242 DirectiveKindMap["elseifdef"] = DK_ELSEIFDEF;5243 DirectiveKindMap["elseifndef"] = DK_ELSEIFNDEF;5244 DirectiveKindMap["elseifdif"] = DK_ELSEIFDIF;5245 DirectiveKindMap["elseifidn"] = DK_ELSEIFIDN;5246 DirectiveKindMap["else"] = DK_ELSE;5247 DirectiveKindMap["end"] = DK_END;5248 DirectiveKindMap["endif"] = DK_ENDIF;5249 // DirectiveKindMap[".file"] = DK_FILE;5250 // DirectiveKindMap[".line"] = DK_LINE;5251 // DirectiveKindMap[".loc"] = DK_LOC;5252 // DirectiveKindMap[".stabs"] = DK_STABS;5253 // DirectiveKindMap[".cv_file"] = DK_CV_FILE;5254 // DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;5255 // DirectiveKindMap[".cv_loc"] = DK_CV_LOC;5256 // DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;5257 // DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;5258 // DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;5259 // DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;5260 // DirectiveKindMap[".cv_string"] = DK_CV_STRING;5261 // DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;5262 // DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;5263 // DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;5264 // DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;5265 // DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;5266 // DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;5267 // DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;5268 // DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;5269 // DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;5270 // DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;5271 // DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;5272 // DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;5273 // DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;5274 // DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;5275 // DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;5276 // DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;5277 // DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;5278 // DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;5279 // DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;5280 // DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;5281 // DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;5282 // DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;5283 // DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;5284 // DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;5285 // DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;5286 // DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;5287 // DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;5288 DirectiveKindMap["macro"] = DK_MACRO;5289 DirectiveKindMap["exitm"] = DK_EXITM;5290 DirectiveKindMap["endm"] = DK_ENDM;5291 DirectiveKindMap["purge"] = DK_PURGE;5292 DirectiveKindMap[".err"] = DK_ERR;5293 DirectiveKindMap[".errb"] = DK_ERRB;5294 DirectiveKindMap[".errnb"] = DK_ERRNB;5295 DirectiveKindMap[".errdef"] = DK_ERRDEF;5296 DirectiveKindMap[".errndef"] = DK_ERRNDEF;5297 DirectiveKindMap[".errdif"] = DK_ERRDIF;5298 DirectiveKindMap[".errdifi"] = DK_ERRDIFI;5299 DirectiveKindMap[".erridn"] = DK_ERRIDN;5300 DirectiveKindMap[".erridni"] = DK_ERRIDNI;5301 DirectiveKindMap[".erre"] = DK_ERRE;5302 DirectiveKindMap[".errnz"] = DK_ERRNZ;5303 DirectiveKindMap[".pushframe"] = DK_PUSHFRAME;5304 DirectiveKindMap[".pushreg"] = DK_PUSHREG;5305 DirectiveKindMap[".savereg"] = DK_SAVEREG;5306 DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;5307 DirectiveKindMap[".setframe"] = DK_SETFRAME;5308 DirectiveKindMap[".radix"] = DK_RADIX;5309 DirectiveKindMap["db"] = DK_DB;5310 DirectiveKindMap["dd"] = DK_DD;5311 DirectiveKindMap["df"] = DK_DF;5312 DirectiveKindMap["dq"] = DK_DQ;5313 DirectiveKindMap["dw"] = DK_DW;5314 DirectiveKindMap["echo"] = DK_ECHO;5315 DirectiveKindMap["struc"] = DK_STRUCT;5316 DirectiveKindMap["struct"] = DK_STRUCT;5317 DirectiveKindMap["union"] = DK_UNION;5318 DirectiveKindMap["ends"] = DK_ENDS;5319}5320 5321bool MasmParser::isMacroLikeDirective() {5322 if (getLexer().is(AsmToken::Identifier)) {5323 bool IsMacroLike = StringSwitch<bool>(getTok().getIdentifier())5324 .CasesLower({"repeat", "rept"}, true)5325 .CaseLower("while", true)5326 .CasesLower({"for", "irp"}, true)5327 .CasesLower({"forc", "irpc"}, true)5328 .Default(false);5329 if (IsMacroLike)5330 return true;5331 }5332 if (peekTok().is(AsmToken::Identifier) &&5333 peekTok().getIdentifier().equals_insensitive("macro"))5334 return true;5335 5336 return false;5337}5338 5339MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {5340 AsmToken EndToken, StartToken = getTok();5341 5342 unsigned NestLevel = 0;5343 while (true) {5344 // Check whether we have reached the end of the file.5345 if (getLexer().is(AsmToken::Eof)) {5346 printError(DirectiveLoc, "no matching 'endm' in definition");5347 return nullptr;5348 }5349 5350 if (isMacroLikeDirective())5351 ++NestLevel;5352 5353 // Otherwise, check whether we have reached the endm.5354 if (Lexer.is(AsmToken::Identifier) &&5355 getTok().getIdentifier().equals_insensitive("endm")) {5356 if (NestLevel == 0) {5357 EndToken = getTok();5358 Lex();5359 if (Lexer.isNot(AsmToken::EndOfStatement)) {5360 printError(getTok().getLoc(), "unexpected token in 'endm' directive");5361 return nullptr;5362 }5363 break;5364 }5365 --NestLevel;5366 }5367 5368 // Otherwise, scan till the end of the statement.5369 eatToEndOfStatement();5370 }5371 5372 const char *BodyStart = StartToken.getLoc().getPointer();5373 const char *BodyEnd = EndToken.getLoc().getPointer();5374 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);5375 5376 // We Are Anonymous.5377 MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());5378 return &MacroLikeBodies.back();5379}5380 5381bool MasmParser::expandStatement(SMLoc Loc) {5382 std::string Body = parseStringTo(AsmToken::EndOfStatement);5383 SMLoc EndLoc = getTok().getLoc();5384 5385 MCAsmMacroParameters Parameters;5386 MCAsmMacroArguments Arguments;5387 5388 StringMap<std::string> BuiltinValues;5389 for (const auto &S : BuiltinSymbolMap) {5390 const BuiltinSymbol &Sym = S.getValue();5391 if (std::optional<std::string> Text = evaluateBuiltinTextMacro(Sym, Loc)) {5392 BuiltinValues[S.getKey().lower()] = std::move(*Text);5393 }5394 }5395 for (const auto &B : BuiltinValues) {5396 MCAsmMacroParameter P;5397 MCAsmMacroArgument A;5398 P.Name = B.getKey();5399 P.Required = true;5400 A.push_back(AsmToken(AsmToken::String, B.getValue()));5401 5402 Parameters.push_back(std::move(P));5403 Arguments.push_back(std::move(A));5404 }5405 5406 for (const auto &V : Variables) {5407 const Variable &Var = V.getValue();5408 if (Var.IsText) {5409 MCAsmMacroParameter P;5410 MCAsmMacroArgument A;5411 P.Name = Var.Name;5412 P.Required = true;5413 A.push_back(AsmToken(AsmToken::String, Var.TextValue));5414 5415 Parameters.push_back(std::move(P));5416 Arguments.push_back(std::move(A));5417 }5418 }5419 MacroLikeBodies.emplace_back(StringRef(), Body, Parameters);5420 MCAsmMacro M = MacroLikeBodies.back();5421 5422 // Expand the statement in a new buffer.5423 SmallString<80> Buf;5424 raw_svector_ostream OS(Buf);5425 if (expandMacro(OS, M.Body, M.Parameters, Arguments, M.Locals, EndLoc))5426 return true;5427 std::unique_ptr<MemoryBuffer> Expansion =5428 MemoryBuffer::getMemBufferCopy(OS.str(), "<expansion>");5429 5430 // Jump to the expanded statement and prime the lexer.5431 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Expansion), EndLoc);5432 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());5433 EndStatementAtEOFStack.push_back(false);5434 Lex();5435 return false;5436}5437 5438void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,5439 raw_svector_ostream &OS) {5440 instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/getTok().getLoc(), OS);5441}5442void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,5443 SMLoc ExitLoc,5444 raw_svector_ostream &OS) {5445 OS << "endm\n";5446 5447 std::unique_ptr<MemoryBuffer> Instantiation =5448 MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");5449 5450 // Create the macro instantiation object and add to the current macro5451 // instantiation stack.5452 MacroInstantiation *MI = new MacroInstantiation{DirectiveLoc, CurBuffer,5453 ExitLoc, TheCondStack.size()};5454 ActiveMacros.push_back(MI);5455 5456 // Jump to the macro instantiation and prime the lexer.5457 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());5458 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());5459 EndStatementAtEOFStack.push_back(true);5460 Lex();5461}5462 5463/// parseDirectiveRepeat5464/// ::= ("repeat" | "rept") count5465/// body5466/// endm5467bool MasmParser::parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Dir) {5468 const MCExpr *CountExpr;5469 SMLoc CountLoc = getTok().getLoc();5470 if (parseExpression(CountExpr))5471 return true;5472 5473 int64_t Count;5474 if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {5475 return Error(CountLoc, "unexpected token in '" + Dir + "' directive");5476 }5477 5478 if (check(Count < 0, CountLoc, "Count is negative") || parseEOL())5479 return true;5480 5481 // Lex the repeat definition.5482 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5483 if (!M)5484 return true;5485 5486 // Macro instantiation is lexical, unfortunately. We construct a new buffer5487 // to hold the macro body with substitutions.5488 SmallString<256> Buf;5489 raw_svector_ostream OS(Buf);5490 while (Count--) {5491 if (expandMacro(OS, M->Body, {}, {}, M->Locals, getTok().getLoc()))5492 return true;5493 }5494 instantiateMacroLikeBody(M, DirectiveLoc, OS);5495 5496 return false;5497}5498 5499/// parseDirectiveWhile5500/// ::= "while" expression5501/// body5502/// endm5503bool MasmParser::parseDirectiveWhile(SMLoc DirectiveLoc) {5504 const MCExpr *CondExpr;5505 SMLoc CondLoc = getTok().getLoc();5506 if (parseExpression(CondExpr))5507 return true;5508 5509 // Lex the repeat definition.5510 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5511 if (!M)5512 return true;5513 5514 // Macro instantiation is lexical, unfortunately. We construct a new buffer5515 // to hold the macro body with substitutions.5516 SmallString<256> Buf;5517 raw_svector_ostream OS(Buf);5518 int64_t Condition;5519 if (!CondExpr->evaluateAsAbsolute(Condition, getStreamer().getAssemblerPtr()))5520 return Error(CondLoc, "expected absolute expression in 'while' directive");5521 if (Condition) {5522 // Instantiate the macro, then resume at this directive to recheck the5523 // condition.5524 if (expandMacro(OS, M->Body, {}, {}, M->Locals, getTok().getLoc()))5525 return true;5526 instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/DirectiveLoc, OS);5527 }5528 5529 return false;5530}5531 5532/// parseDirectiveFor5533/// ::= ("for" | "irp") symbol [":" qualifier], <values>5534/// body5535/// endm5536bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) {5537 MCAsmMacroParameter Parameter;5538 MCAsmMacroArguments A;5539 if (check(parseIdentifier(Parameter.Name),5540 "expected identifier in '" + Dir + "' directive"))5541 return true;5542 5543 // Parse optional qualifier (default value, or "req")5544 if (parseOptionalToken(AsmToken::Colon)) {5545 if (parseOptionalToken(AsmToken::Equal)) {5546 // Default value5547 SMLoc ParamLoc;5548 5549 ParamLoc = Lexer.getLoc();5550 if (parseMacroArgument(nullptr, Parameter.Value))5551 return true;5552 } else {5553 SMLoc QualLoc;5554 StringRef Qualifier;5555 5556 QualLoc = Lexer.getLoc();5557 if (parseIdentifier(Qualifier))5558 return Error(QualLoc, "missing parameter qualifier for "5559 "'" +5560 Parameter.Name + "' in '" + Dir +5561 "' directive");5562 5563 if (Qualifier.equals_insensitive("req"))5564 Parameter.Required = true;5565 else5566 return Error(QualLoc,5567 Qualifier + " is not a valid parameter qualifier for '" +5568 Parameter.Name + "' in '" + Dir + "' directive");5569 }5570 }5571 5572 if (parseToken(AsmToken::Comma,5573 "expected comma in '" + Dir + "' directive") ||5574 parseToken(AsmToken::Less,5575 "values in '" + Dir +5576 "' directive must be enclosed in angle brackets"))5577 return true;5578 5579 while (true) {5580 A.emplace_back();5581 if (parseMacroArgument(&Parameter, A.back(), /*EndTok=*/AsmToken::Greater))5582 return addErrorSuffix(" in arguments for '" + Dir + "' directive");5583 5584 // If we see a comma, continue, and allow line continuation.5585 if (!parseOptionalToken(AsmToken::Comma))5586 break;5587 parseOptionalToken(AsmToken::EndOfStatement);5588 }5589 5590 if (parseToken(AsmToken::Greater,5591 "values in '" + Dir +5592 "' directive must be enclosed in angle brackets") ||5593 parseEOL())5594 return true;5595 5596 // Lex the for definition.5597 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5598 if (!M)5599 return true;5600 5601 // Macro instantiation is lexical, unfortunately. We construct a new buffer5602 // to hold the macro body with substitutions.5603 SmallString<256> Buf;5604 raw_svector_ostream OS(Buf);5605 5606 for (const MCAsmMacroArgument &Arg : A) {5607 if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))5608 return true;5609 }5610 5611 instantiateMacroLikeBody(M, DirectiveLoc, OS);5612 5613 return false;5614}5615 5616/// parseDirectiveForc5617/// ::= ("forc" | "irpc") symbol, <string>5618/// body5619/// endm5620bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) {5621 MCAsmMacroParameter Parameter;5622 5623 std::string Argument;5624 if (check(parseIdentifier(Parameter.Name),5625 "expected identifier in '" + Directive + "' directive") ||5626 parseToken(AsmToken::Comma,5627 "expected comma in '" + Directive + "' directive"))5628 return true;5629 if (parseAngleBracketString(Argument)) {5630 // Match ml64.exe; treat all characters to end of statement as a string,5631 // ignoring comment markers, then discard anything following a space (using5632 // the C locale).5633 Argument = parseStringTo(AsmToken::EndOfStatement);5634 if (getTok().is(AsmToken::EndOfStatement))5635 Argument += getTok().getString();5636 size_t End = 0;5637 for (; End < Argument.size(); ++End) {5638 if (isSpace(Argument[End]))5639 break;5640 }5641 Argument.resize(End);5642 }5643 if (parseEOL())5644 return true;5645 5646 // Lex the irpc definition.5647 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5648 if (!M)5649 return true;5650 5651 // Macro instantiation is lexical, unfortunately. We construct a new buffer5652 // to hold the macro body with substitutions.5653 SmallString<256> Buf;5654 raw_svector_ostream OS(Buf);5655 5656 StringRef Values(Argument);5657 for (std::size_t I = 0, End = Values.size(); I != End; ++I) {5658 MCAsmMacroArgument Arg;5659 Arg.emplace_back(AsmToken::Identifier, Values.substr(I, 1));5660 5661 if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))5662 return true;5663 }5664 5665 instantiateMacroLikeBody(M, DirectiveLoc, OS);5666 5667 return false;5668}5669 5670bool MasmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,5671 size_t Len) {5672 const MCExpr *Value;5673 SMLoc ExprLoc = getLexer().getLoc();5674 if (parseExpression(Value))5675 return true;5676 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5677 if (!MCE)5678 return Error(ExprLoc, "unexpected expression in _emit");5679 uint64_t IntValue = MCE->getValue();5680 if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))5681 return Error(ExprLoc, "literal value out of range for directive");5682 5683 Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);5684 return false;5685}5686 5687bool MasmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {5688 const MCExpr *Value;5689 SMLoc ExprLoc = getLexer().getLoc();5690 if (parseExpression(Value))5691 return true;5692 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5693 if (!MCE)5694 return Error(ExprLoc, "unexpected expression in align");5695 uint64_t IntValue = MCE->getValue();5696 if (!isPowerOf2_64(IntValue))5697 return Error(ExprLoc, "literal value not a power of two greater then zero");5698 5699 Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));5700 return false;5701}5702 5703bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) {5704 const SMLoc Loc = getLexer().getLoc();5705 std::string RadixStringRaw = parseStringTo(AsmToken::EndOfStatement);5706 StringRef RadixString = StringRef(RadixStringRaw).trim();5707 unsigned Radix;5708 if (RadixString.getAsInteger(10, Radix)) {5709 return Error(Loc,5710 "radix must be a decimal number in the range 2 to 16; was " +5711 RadixString);5712 }5713 if (Radix < 2 || Radix > 16)5714 return Error(Loc, "radix must be in the range 2 to 16; was " +5715 std::to_string(Radix));5716 getLexer().setMasmDefaultRadix(Radix);5717 return false;5718}5719 5720/// parseDirectiveEcho5721/// ::= "echo" message5722bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) {5723 std::string Message = parseStringTo(AsmToken::EndOfStatement);5724 llvm::outs() << Message;5725 if (!StringRef(Message).ends_with("\n"))5726 llvm::outs() << '\n';5727 return false;5728}5729 5730// We are comparing pointers, but the pointers are relative to a single string.5731// Thus, this should always be deterministic.5732static int rewritesSort(const AsmRewrite *AsmRewriteA,5733 const AsmRewrite *AsmRewriteB) {5734 if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())5735 return -1;5736 if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())5737 return 1;5738 5739 // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output5740 // rewrite to the same location. Make sure the SizeDirective rewrite is5741 // performed first, then the Imm/ImmPrefix and finally the Input/Output. This5742 // ensures the sort algorithm is stable.5743 if (AsmRewritePrecedence[AsmRewriteA->Kind] >5744 AsmRewritePrecedence[AsmRewriteB->Kind])5745 return -1;5746 5747 if (AsmRewritePrecedence[AsmRewriteA->Kind] <5748 AsmRewritePrecedence[AsmRewriteB->Kind])5749 return 1;5750 llvm_unreachable("Unstable rewrite sort.");5751}5752 5753bool MasmParser::defineMacro(StringRef Name, StringRef Value) {5754 Variable &Var = Variables[Name.lower()];5755 if (Var.Name.empty()) {5756 Var.Name = Name;5757 } else if (Var.Redefinable == Variable::NOT_REDEFINABLE) {5758 return Error(SMLoc(), "invalid variable redefinition");5759 } else if (Var.Redefinable == Variable::WARN_ON_REDEFINITION &&5760 Warning(SMLoc(), "redefining '" + Name +5761 "', already defined on the command line")) {5762 return true;5763 }5764 Var.Redefinable = Variable::WARN_ON_REDEFINITION;5765 Var.IsText = true;5766 Var.TextValue = Value.str();5767 return false;5768}5769 5770bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const {5771 const std::pair<StringRef, StringRef> BaseMember = Name.split('.');5772 const StringRef Base = BaseMember.first, Member = BaseMember.second;5773 return lookUpField(Base, Member, Info);5774}5775 5776bool MasmParser::lookUpField(StringRef Base, StringRef Member,5777 AsmFieldInfo &Info) const {5778 if (Base.empty())5779 return true;5780 5781 AsmFieldInfo BaseInfo;5782 if (Base.contains('.') && !lookUpField(Base, BaseInfo))5783 Base = BaseInfo.Type.Name;5784 5785 auto StructIt = Structs.find(Base.lower());5786 auto TypeIt = KnownType.find(Base.lower());5787 if (TypeIt != KnownType.end()) {5788 StructIt = Structs.find(TypeIt->second.Name.lower());5789 }5790 if (StructIt != Structs.end())5791 return lookUpField(StructIt->second, Member, Info);5792 5793 return true;5794}5795 5796bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member,5797 AsmFieldInfo &Info) const {5798 if (Member.empty()) {5799 Info.Type.Name = Structure.Name;5800 Info.Type.Size = Structure.Size;5801 Info.Type.ElementSize = Structure.Size;5802 Info.Type.Length = 1;5803 return false;5804 }5805 5806 std::pair<StringRef, StringRef> Split = Member.split('.');5807 const StringRef FieldName = Split.first, FieldMember = Split.second;5808 5809 auto StructIt = Structs.find(FieldName.lower());5810 if (StructIt != Structs.end())5811 return lookUpField(StructIt->second, FieldMember, Info);5812 5813 auto FieldIt = Structure.FieldsByName.find(FieldName.lower());5814 if (FieldIt == Structure.FieldsByName.end())5815 return true;5816 5817 const FieldInfo &Field = Structure.Fields[FieldIt->second];5818 if (FieldMember.empty()) {5819 Info.Offset += Field.Offset;5820 Info.Type.Size = Field.SizeOf;5821 Info.Type.ElementSize = Field.Type;5822 Info.Type.Length = Field.LengthOf;5823 if (Field.Contents.FT == FT_STRUCT)5824 Info.Type.Name = Field.Contents.StructInfo.Structure.Name;5825 else5826 Info.Type.Name = "";5827 return false;5828 }5829 5830 if (Field.Contents.FT != FT_STRUCT)5831 return true;5832 const StructFieldInfo &StructInfo = Field.Contents.StructInfo;5833 5834 if (lookUpField(StructInfo.Structure, FieldMember, Info))5835 return true;5836 5837 Info.Offset += Field.Offset;5838 return false;5839}5840 5841bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const {5842 unsigned Size = StringSwitch<unsigned>(Name)5843 .CasesLower({"byte", "db", "sbyte"}, 1)5844 .CasesLower({"word", "dw", "sword"}, 2)5845 .CasesLower({"dword", "dd", "sdword"}, 4)5846 .CasesLower({"fword", "df"}, 6)5847 .CasesLower({"qword", "dq", "sqword"}, 8)5848 .CaseLower("real4", 4)5849 .CaseLower("real8", 8)5850 .CaseLower("real10", 10)5851 .Default(0);5852 if (Size) {5853 Info.Name = Name;5854 Info.ElementSize = Size;5855 Info.Length = 1;5856 Info.Size = Size;5857 return false;5858 }5859 5860 auto StructIt = Structs.find(Name.lower());5861 if (StructIt != Structs.end()) {5862 const StructInfo &Structure = StructIt->second;5863 Info.Name = Name;5864 Info.ElementSize = Structure.Size;5865 Info.Length = 1;5866 Info.Size = Structure.Size;5867 return false;5868 }5869 5870 return true;5871}5872 5873bool MasmParser::parseMSInlineAsm(5874 std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs,5875 SmallVectorImpl<std::pair<void *, bool>> &OpDecls,5876 SmallVectorImpl<std::string> &Constraints,5877 SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,5878 MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {5879 SmallVector<void *, 4> InputDecls;5880 SmallVector<void *, 4> OutputDecls;5881 SmallVector<bool, 4> InputDeclsAddressOf;5882 SmallVector<bool, 4> OutputDeclsAddressOf;5883 SmallVector<std::string, 4> InputConstraints;5884 SmallVector<std::string, 4> OutputConstraints;5885 SmallVector<MCRegister, 4> ClobberRegs;5886 5887 SmallVector<AsmRewrite, 4> AsmStrRewrites;5888 5889 // Prime the lexer.5890 Lex();5891 5892 // While we have input, parse each statement.5893 unsigned InputIdx = 0;5894 unsigned OutputIdx = 0;5895 while (getLexer().isNot(AsmToken::Eof)) {5896 // Parse curly braces marking block start/end.5897 if (parseCurlyBlockScope(AsmStrRewrites))5898 continue;5899 5900 ParseStatementInfo Info(&AsmStrRewrites);5901 bool StatementErr = parseStatement(Info, &SI);5902 5903 if (StatementErr || Info.ParseError) {5904 // Emit pending errors if any exist.5905 printPendingErrors();5906 return true;5907 }5908 5909 // No pending error should exist here.5910 assert(!hasPendingError() && "unexpected error from parseStatement");5911 5912 if (Info.Opcode == ~0U)5913 continue;5914 5915 const MCInstrDesc &Desc = MII->get(Info.Opcode);5916 5917 // Build the list of clobbers, outputs and inputs.5918 for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {5919 MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];5920 5921 // Register operand.5922 if (Operand.isReg() && !Operand.needAddressOf() &&5923 !getTargetParser().omitRegisterFromClobberLists(Operand.getReg())) {5924 unsigned NumDefs = Desc.getNumDefs();5925 // Clobber.5926 if (NumDefs && Operand.getMCOperandNum() < NumDefs)5927 ClobberRegs.push_back(Operand.getReg());5928 continue;5929 }5930 5931 // Expr/Input or Output.5932 StringRef SymName = Operand.getSymName();5933 if (SymName.empty())5934 continue;5935 5936 void *OpDecl = Operand.getOpDecl();5937 if (!OpDecl)5938 continue;5939 5940 StringRef Constraint = Operand.getConstraint();5941 if (Operand.isImm()) {5942 // Offset as immediate.5943 if (Operand.isOffsetOfLocal())5944 Constraint = "r";5945 else5946 Constraint = "i";5947 }5948 5949 bool isOutput = (i == 1) && Desc.mayStore();5950 SMLoc Start = SMLoc::getFromPointer(SymName.data());5951 if (isOutput) {5952 ++InputIdx;5953 OutputDecls.push_back(OpDecl);5954 OutputDeclsAddressOf.push_back(Operand.needAddressOf());5955 OutputConstraints.push_back(("=" + Constraint).str());5956 AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());5957 } else {5958 InputDecls.push_back(OpDecl);5959 InputDeclsAddressOf.push_back(Operand.needAddressOf());5960 InputConstraints.push_back(Constraint.str());5961 if (Desc.operands()[i - 1].isBranchTarget())5962 AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());5963 else5964 AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());5965 }5966 }5967 5968 // Consider implicit defs to be clobbers. Think of cpuid and push.5969 llvm::append_range(ClobberRegs, Desc.implicit_defs());5970 }5971 5972 // Set the number of Outputs and Inputs.5973 NumOutputs = OutputDecls.size();5974 NumInputs = InputDecls.size();5975 5976 // Set the unique clobbers.5977 array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());5978 ClobberRegs.erase(llvm::unique(ClobberRegs), ClobberRegs.end());5979 Clobbers.assign(ClobberRegs.size(), std::string());5980 for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {5981 raw_string_ostream OS(Clobbers[I]);5982 IP->printRegName(OS, ClobberRegs[I]);5983 }5984 5985 // Merge the various outputs and inputs. Output are expected first.5986 if (NumOutputs || NumInputs) {5987 unsigned NumExprs = NumOutputs + NumInputs;5988 OpDecls.resize(NumExprs);5989 Constraints.resize(NumExprs);5990 for (unsigned i = 0; i < NumOutputs; ++i) {5991 OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);5992 Constraints[i] = OutputConstraints[i];5993 }5994 for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {5995 OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);5996 Constraints[j] = InputConstraints[i];5997 }5998 }5999 6000 // Build the IR assembly string.6001 std::string AsmStringIR;6002 raw_string_ostream OS(AsmStringIR);6003 StringRef ASMString =6004 SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();6005 const char *AsmStart = ASMString.begin();6006 const char *AsmEnd = ASMString.end();6007 array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);6008 for (auto I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) {6009 const AsmRewrite &AR = *I;6010 // Check if this has already been covered by another rewrite...6011 if (AR.Done)6012 continue;6013 AsmRewriteKind Kind = AR.Kind;6014 6015 const char *Loc = AR.Loc.getPointer();6016 assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");6017 6018 // Emit everything up to the immediate/expression.6019 if (unsigned Len = Loc - AsmStart)6020 OS << StringRef(AsmStart, Len);6021 6022 // Skip the original expression.6023 if (Kind == AOK_Skip) {6024 AsmStart = Loc + AR.Len;6025 continue;6026 }6027 6028 unsigned AdditionalSkip = 0;6029 // Rewrite expressions in $N notation.6030 switch (Kind) {6031 default:6032 break;6033 case AOK_IntelExpr:6034 assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");6035 if (AR.IntelExp.NeedBracs)6036 OS << "[";6037 if (AR.IntelExp.hasBaseReg())6038 OS << AR.IntelExp.BaseReg;6039 if (AR.IntelExp.hasIndexReg())6040 OS << (AR.IntelExp.hasBaseReg() ? " + " : "")6041 << AR.IntelExp.IndexReg;6042 if (AR.IntelExp.Scale > 1)6043 OS << " * $$" << AR.IntelExp.Scale;6044 if (AR.IntelExp.hasOffset()) {6045 if (AR.IntelExp.hasRegs())6046 OS << " + ";6047 // Fuse this rewrite with a rewrite of the offset name, if present.6048 StringRef OffsetName = AR.IntelExp.OffsetName;6049 SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());6050 size_t OffsetLen = OffsetName.size();6051 auto rewrite_it = std::find_if(6052 I, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) {6053 return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&6054 (FusingAR.Kind == AOK_Input ||6055 FusingAR.Kind == AOK_CallInput);6056 });6057 if (rewrite_it == AsmStrRewrites.end()) {6058 OS << "offset " << OffsetName;6059 } else if (rewrite_it->Kind == AOK_CallInput) {6060 OS << "${" << InputIdx++ << ":P}";6061 rewrite_it->Done = true;6062 } else {6063 OS << '$' << InputIdx++;6064 rewrite_it->Done = true;6065 }6066 }6067 if (AR.IntelExp.Imm || AR.IntelExp.emitImm())6068 OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;6069 if (AR.IntelExp.NeedBracs)6070 OS << "]";6071 break;6072 case AOK_Label:6073 OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;6074 break;6075 case AOK_Input:6076 OS << '$' << InputIdx++;6077 break;6078 case AOK_CallInput:6079 OS << "${" << InputIdx++ << ":P}";6080 break;6081 case AOK_Output:6082 OS << '$' << OutputIdx++;6083 break;6084 case AOK_SizeDirective:6085 switch (AR.Val) {6086 default: break;6087 case 8: OS << "byte ptr "; break;6088 case 16: OS << "word ptr "; break;6089 case 32: OS << "dword ptr "; break;6090 case 64: OS << "qword ptr "; break;6091 case 80: OS << "xword ptr "; break;6092 case 128: OS << "xmmword ptr "; break;6093 case 256: OS << "ymmword ptr "; break;6094 }6095 break;6096 case AOK_Emit:6097 OS << ".byte";6098 break;6099 case AOK_Align: {6100 // MS alignment directives are measured in bytes. If the native assembler6101 // measures alignment in bytes, we can pass it straight through.6102 OS << ".align";6103 if (getContext().getAsmInfo()->getAlignmentIsInBytes())6104 break;6105 6106 // Alignment is in log2 form, so print that instead and skip the original6107 // immediate.6108 unsigned Val = AR.Val;6109 OS << ' ' << Val;6110 assert(Val < 10 && "Expected alignment less then 2^10.");6111 AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;6112 break;6113 }6114 case AOK_EVEN:6115 OS << ".even";6116 break;6117 case AOK_EndOfStatement:6118 OS << "\n\t";6119 break;6120 }6121 6122 // Skip the original expression.6123 AsmStart = Loc + AR.Len + AdditionalSkip;6124 }6125 6126 // Emit the remainder of the asm string.6127 if (AsmStart != AsmEnd)6128 OS << StringRef(AsmStart, AsmEnd - AsmStart);6129 6130 AsmString = OS.str();6131 return false;6132}6133 6134void MasmParser::initializeBuiltinSymbolMaps() {6135 // Numeric built-ins (supported in all versions)6136 BuiltinSymbolMap["@version"] = BI_VERSION;6137 BuiltinSymbolMap["@line"] = BI_LINE;6138 6139 // Text built-ins (supported in all versions)6140 BuiltinSymbolMap["@date"] = BI_DATE;6141 BuiltinSymbolMap["@time"] = BI_TIME;6142 BuiltinSymbolMap["@filecur"] = BI_FILECUR;6143 BuiltinSymbolMap["@filename"] = BI_FILENAME;6144 BuiltinSymbolMap["@curseg"] = BI_CURSEG;6145 6146 // Function built-ins (supported in all versions)6147 BuiltinFunctionMap["@catstr"] = BI_CATSTR;6148 6149 // Some built-ins exist only for MASM32 (32-bit x86)6150 if (getContext().getSubtargetInfo()->getTargetTriple().getArch() ==6151 Triple::x86) {6152 // Numeric built-ins6153 // BuiltinSymbolMap["@cpu"] = BI_CPU;6154 // BuiltinSymbolMap["@interface"] = BI_INTERFACE;6155 // BuiltinSymbolMap["@wordsize"] = BI_WORDSIZE;6156 // BuiltinSymbolMap["@codesize"] = BI_CODESIZE;6157 // BuiltinSymbolMap["@datasize"] = BI_DATASIZE;6158 // BuiltinSymbolMap["@model"] = BI_MODEL;6159 6160 // Text built-ins6161 // BuiltinSymbolMap["@code"] = BI_CODE;6162 // BuiltinSymbolMap["@data"] = BI_DATA;6163 // BuiltinSymbolMap["@fardata?"] = BI_FARDATA;6164 // BuiltinSymbolMap["@stack"] = BI_STACK;6165 }6166}6167 6168const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,6169 SMLoc StartLoc) {6170 switch (Symbol) {6171 default:6172 return nullptr;6173 case BI_VERSION:6174 // Match a recent version of ML.EXE.6175 return MCConstantExpr::create(1427, getContext());6176 case BI_LINE: {6177 int64_t Line;6178 if (ActiveMacros.empty())6179 Line = SrcMgr.FindLineNumber(StartLoc, CurBuffer);6180 else6181 Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,6182 ActiveMacros.front()->ExitBuffer);6183 return MCConstantExpr::create(Line, getContext());6184 }6185 }6186 llvm_unreachable("unhandled built-in symbol");6187}6188 6189std::optional<std::string>6190MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {6191 switch (Symbol) {6192 default:6193 return {};6194 case BI_DATE: {6195 // Current local date, formatted MM/DD/YY6196 char TmpBuffer[sizeof("mm/dd/yy")];6197 const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%D", &TM);6198 return std::string(TmpBuffer, Len);6199 }6200 case BI_TIME: {6201 // Current local time, formatted HH:MM:SS (24-hour clock)6202 char TmpBuffer[sizeof("hh:mm:ss")];6203 const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%T", &TM);6204 return std::string(TmpBuffer, Len);6205 }6206 case BI_FILECUR:6207 return SrcMgr6208 .getMemoryBuffer(6209 ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)6210 ->getBufferIdentifier()6211 .str();6212 case BI_FILENAME:6213 return sys::path::stem(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())6214 ->getBufferIdentifier())6215 .upper();6216 case BI_CURSEG:6217 return getStreamer().getCurrentSectionOnly()->getName().str();6218 }6219 llvm_unreachable("unhandled built-in symbol");6220}6221 6222bool MasmParser::evaluateBuiltinMacroFunction(BuiltinFunction Function,6223 StringRef Name,6224 std::string &Res) {6225 if (parseToken(AsmToken::LParen, "invoking macro function '" + Name +6226 "' requires arguments in parentheses")) {6227 return true;6228 }6229 6230 MCAsmMacroParameters P;6231 switch (Function) {6232 default:6233 return true;6234 case BI_CATSTR:6235 break;6236 }6237 MCAsmMacro M(Name, "", P, {}, true);6238 6239 MCAsmMacroArguments A;6240 if (parseMacroArguments(&M, A, AsmToken::RParen) || parseRParen()) {6241 return true;6242 }6243 6244 switch (Function) {6245 default:6246 llvm_unreachable("unhandled built-in function");6247 case BI_CATSTR: {6248 for (const MCAsmMacroArgument &Arg : A) {6249 for (const AsmToken &Tok : Arg) {6250 if (Tok.is(AsmToken::String)) {6251 Res.append(Tok.getStringContents());6252 } else {6253 Res.append(Tok.getString());6254 }6255 }6256 }6257 return false;6258 }6259 }6260 llvm_unreachable("unhandled built-in function");6261 return true;6262}6263 6264/// Create an MCAsmParser instance.6265MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,6266 MCStreamer &Out, const MCAsmInfo &MAI,6267 struct tm TM, unsigned CB) {6268 return new MasmParser(SM, C, Out, MAI, TM, CB);6269}6270