Path: blob/main/contrib/llvm-project/llvm/lib/MC/MCParser/MasmParser.cpp
35266 views
//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This class implements the parser for assembly files.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ADT/APFloat.h"13#include "llvm/ADT/APInt.h"14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/BitVector.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/SmallString.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/ADT/StringMap.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/ADT/StringSwitch.h"23#include "llvm/ADT/Twine.h"24#include "llvm/BinaryFormat/Dwarf.h"25#include "llvm/DebugInfo/CodeView/SymbolRecord.h"26#include "llvm/MC/MCAsmInfo.h"27#include "llvm/MC/MCCodeView.h"28#include "llvm/MC/MCContext.h"29#include "llvm/MC/MCDirectives.h"30#include "llvm/MC/MCDwarf.h"31#include "llvm/MC/MCExpr.h"32#include "llvm/MC/MCInstPrinter.h"33#include "llvm/MC/MCInstrDesc.h"34#include "llvm/MC/MCInstrInfo.h"35#include "llvm/MC/MCParser/AsmCond.h"36#include "llvm/MC/MCParser/AsmLexer.h"37#include "llvm/MC/MCParser/MCAsmLexer.h"38#include "llvm/MC/MCParser/MCAsmParser.h"39#include "llvm/MC/MCParser/MCAsmParserExtension.h"40#include "llvm/MC/MCParser/MCParsedAsmOperand.h"41#include "llvm/MC/MCParser/MCTargetAsmParser.h"42#include "llvm/MC/MCRegisterInfo.h"43#include "llvm/MC/MCSection.h"44#include "llvm/MC/MCStreamer.h"45#include "llvm/MC/MCSubtargetInfo.h"46#include "llvm/MC/MCSymbol.h"47#include "llvm/MC/MCTargetOptions.h"48#include "llvm/Support/Casting.h"49#include "llvm/Support/CommandLine.h"50#include "llvm/Support/ErrorHandling.h"51#include "llvm/Support/Format.h"52#include "llvm/Support/MD5.h"53#include "llvm/Support/MathExtras.h"54#include "llvm/Support/MemoryBuffer.h"55#include "llvm/Support/Path.h"56#include "llvm/Support/SMLoc.h"57#include "llvm/Support/SourceMgr.h"58#include "llvm/Support/raw_ostream.h"59#include <algorithm>60#include <cassert>61#include <climits>62#include <cstddef>63#include <cstdint>64#include <ctime>65#include <deque>66#include <memory>67#include <optional>68#include <sstream>69#include <string>70#include <tuple>71#include <utility>72#include <vector>7374using namespace llvm;7576namespace {7778/// Helper types for tracking macro definitions.79typedef std::vector<AsmToken> MCAsmMacroArgument;80typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;8182/// Helper class for storing information about an active macro instantiation.83struct MacroInstantiation {84/// The location of the instantiation.85SMLoc InstantiationLoc;8687/// The buffer where parsing should resume upon instantiation completion.88unsigned ExitBuffer;8990/// The location where parsing should resume upon instantiation completion.91SMLoc ExitLoc;9293/// The depth of TheCondStack at the start of the instantiation.94size_t CondStackDepth;95};9697struct ParseStatementInfo {98/// The parsed operands from the last parsed statement.99SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;100101/// The opcode from the last parsed instruction.102unsigned Opcode = ~0U;103104/// Was there an error parsing the inline assembly?105bool ParseError = false;106107/// The value associated with a macro exit.108std::optional<std::string> ExitValue;109110SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;111112ParseStatementInfo() = delete;113ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)114: AsmRewrites(rewrites) {}115};116117enum FieldType {118FT_INTEGRAL, // Initializer: integer expression, stored as an MCExpr.119FT_REAL, // Initializer: real number, stored as an APInt.120FT_STRUCT // Initializer: struct initializer, stored recursively.121};122123struct FieldInfo;124struct StructInfo {125StringRef Name;126bool IsUnion = false;127bool Initializable = true;128unsigned Alignment = 0;129unsigned AlignmentSize = 0;130unsigned NextOffset = 0;131unsigned Size = 0;132std::vector<FieldInfo> Fields;133StringMap<size_t> FieldsByName;134135FieldInfo &addField(StringRef FieldName, FieldType FT,136unsigned FieldAlignmentSize);137138StructInfo() = default;139StructInfo(StringRef StructName, bool Union, unsigned AlignmentValue);140};141142// FIXME: This should probably use a class hierarchy, raw pointers between the143// objects, and dynamic type resolution instead of a union. On the other hand,144// ownership then becomes much more complicated; the obvious thing would be to145// use BumpPtrAllocator, but the lack of a destructor makes that messy.146147struct StructInitializer;148struct IntFieldInfo {149SmallVector<const MCExpr *, 1> Values;150151IntFieldInfo() = default;152IntFieldInfo(const SmallVector<const MCExpr *, 1> &V) { Values = V; }153IntFieldInfo(SmallVector<const MCExpr *, 1> &&V) { Values = std::move(V); }154};155struct RealFieldInfo {156SmallVector<APInt, 1> AsIntValues;157158RealFieldInfo() = default;159RealFieldInfo(const SmallVector<APInt, 1> &V) { AsIntValues = V; }160RealFieldInfo(SmallVector<APInt, 1> &&V) { AsIntValues = std::move(V); }161};162struct StructFieldInfo {163std::vector<StructInitializer> Initializers;164StructInfo Structure;165166StructFieldInfo() = default;167StructFieldInfo(std::vector<StructInitializer> V, StructInfo S);168};169170class FieldInitializer {171public:172FieldType FT;173union {174IntFieldInfo IntInfo;175RealFieldInfo RealInfo;176StructFieldInfo StructInfo;177};178179~FieldInitializer();180FieldInitializer(FieldType FT);181182FieldInitializer(SmallVector<const MCExpr *, 1> &&Values);183FieldInitializer(SmallVector<APInt, 1> &&AsIntValues);184FieldInitializer(std::vector<StructInitializer> &&Initializers,185struct StructInfo Structure);186187FieldInitializer(const FieldInitializer &Initializer);188FieldInitializer(FieldInitializer &&Initializer);189190FieldInitializer &operator=(const FieldInitializer &Initializer);191FieldInitializer &operator=(FieldInitializer &&Initializer);192};193194struct StructInitializer {195std::vector<FieldInitializer> FieldInitializers;196};197198struct FieldInfo {199// Offset of the field within the containing STRUCT.200unsigned Offset = 0;201202// Total size of the field (= LengthOf * Type).203unsigned SizeOf = 0;204205// Number of elements in the field (1 if scalar, >1 if an array).206unsigned LengthOf = 0;207208// Size of a single entry in this field, in bytes ("type" in MASM standards).209unsigned Type = 0;210211FieldInitializer Contents;212213FieldInfo(FieldType FT) : Contents(FT) {}214};215216StructFieldInfo::StructFieldInfo(std::vector<StructInitializer> V,217StructInfo S) {218Initializers = std::move(V);219Structure = S;220}221222StructInfo::StructInfo(StringRef StructName, bool Union,223unsigned AlignmentValue)224: Name(StructName), IsUnion(Union), Alignment(AlignmentValue) {}225226FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT,227unsigned FieldAlignmentSize) {228if (!FieldName.empty())229FieldsByName[FieldName.lower()] = Fields.size();230Fields.emplace_back(FT);231FieldInfo &Field = Fields.back();232Field.Offset =233llvm::alignTo(NextOffset, std::min(Alignment, FieldAlignmentSize));234if (!IsUnion) {235NextOffset = std::max(NextOffset, Field.Offset);236}237AlignmentSize = std::max(AlignmentSize, FieldAlignmentSize);238return Field;239}240241FieldInitializer::~FieldInitializer() {242switch (FT) {243case FT_INTEGRAL:244IntInfo.~IntFieldInfo();245break;246case FT_REAL:247RealInfo.~RealFieldInfo();248break;249case FT_STRUCT:250StructInfo.~StructFieldInfo();251break;252}253}254255FieldInitializer::FieldInitializer(FieldType FT) : FT(FT) {256switch (FT) {257case FT_INTEGRAL:258new (&IntInfo) IntFieldInfo();259break;260case FT_REAL:261new (&RealInfo) RealFieldInfo();262break;263case FT_STRUCT:264new (&StructInfo) StructFieldInfo();265break;266}267}268269FieldInitializer::FieldInitializer(SmallVector<const MCExpr *, 1> &&Values)270: FT(FT_INTEGRAL) {271new (&IntInfo) IntFieldInfo(std::move(Values));272}273274FieldInitializer::FieldInitializer(SmallVector<APInt, 1> &&AsIntValues)275: FT(FT_REAL) {276new (&RealInfo) RealFieldInfo(std::move(AsIntValues));277}278279FieldInitializer::FieldInitializer(280std::vector<StructInitializer> &&Initializers, struct StructInfo Structure)281: FT(FT_STRUCT) {282new (&StructInfo) StructFieldInfo(std::move(Initializers), Structure);283}284285FieldInitializer::FieldInitializer(const FieldInitializer &Initializer)286: FT(Initializer.FT) {287switch (FT) {288case FT_INTEGRAL:289new (&IntInfo) IntFieldInfo(Initializer.IntInfo);290break;291case FT_REAL:292new (&RealInfo) RealFieldInfo(Initializer.RealInfo);293break;294case FT_STRUCT:295new (&StructInfo) StructFieldInfo(Initializer.StructInfo);296break;297}298}299300FieldInitializer::FieldInitializer(FieldInitializer &&Initializer)301: FT(Initializer.FT) {302switch (FT) {303case FT_INTEGRAL:304new (&IntInfo) IntFieldInfo(Initializer.IntInfo);305break;306case FT_REAL:307new (&RealInfo) RealFieldInfo(Initializer.RealInfo);308break;309case FT_STRUCT:310new (&StructInfo) StructFieldInfo(Initializer.StructInfo);311break;312}313}314315FieldInitializer &316FieldInitializer::operator=(const FieldInitializer &Initializer) {317if (FT != Initializer.FT) {318switch (FT) {319case FT_INTEGRAL:320IntInfo.~IntFieldInfo();321break;322case FT_REAL:323RealInfo.~RealFieldInfo();324break;325case FT_STRUCT:326StructInfo.~StructFieldInfo();327break;328}329}330FT = Initializer.FT;331switch (FT) {332case FT_INTEGRAL:333IntInfo = Initializer.IntInfo;334break;335case FT_REAL:336RealInfo = Initializer.RealInfo;337break;338case FT_STRUCT:339StructInfo = Initializer.StructInfo;340break;341}342return *this;343}344345FieldInitializer &FieldInitializer::operator=(FieldInitializer &&Initializer) {346if (FT != Initializer.FT) {347switch (FT) {348case FT_INTEGRAL:349IntInfo.~IntFieldInfo();350break;351case FT_REAL:352RealInfo.~RealFieldInfo();353break;354case FT_STRUCT:355StructInfo.~StructFieldInfo();356break;357}358}359FT = Initializer.FT;360switch (FT) {361case FT_INTEGRAL:362IntInfo = Initializer.IntInfo;363break;364case FT_REAL:365RealInfo = Initializer.RealInfo;366break;367case FT_STRUCT:368StructInfo = Initializer.StructInfo;369break;370}371return *this;372}373374/// The concrete assembly parser instance.375// Note that this is a full MCAsmParser, not an MCAsmParserExtension!376// It's a peer of AsmParser, not of COFFAsmParser, WasmAsmParser, etc.377class MasmParser : public MCAsmParser {378private:379AsmLexer Lexer;380MCContext &Ctx;381MCStreamer &Out;382const MCAsmInfo &MAI;383SourceMgr &SrcMgr;384SourceMgr::DiagHandlerTy SavedDiagHandler;385void *SavedDiagContext;386std::unique_ptr<MCAsmParserExtension> PlatformParser;387388/// This is the current buffer index we're lexing from as managed by the389/// SourceMgr object.390unsigned CurBuffer;391392/// time of assembly393struct tm TM;394395BitVector EndStatementAtEOFStack;396397AsmCond TheCondState;398std::vector<AsmCond> TheCondStack;399400/// maps directive names to handler methods in parser401/// extensions. Extensions register themselves in this map by calling402/// addDirectiveHandler.403StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;404405/// maps assembly-time variable names to variables.406struct Variable {407enum RedefinableKind { NOT_REDEFINABLE, WARN_ON_REDEFINITION, REDEFINABLE };408409StringRef Name;410RedefinableKind Redefinable = REDEFINABLE;411bool IsText = false;412std::string TextValue;413};414StringMap<Variable> Variables;415416/// Stack of active struct definitions.417SmallVector<StructInfo, 1> StructInProgress;418419/// Maps struct tags to struct definitions.420StringMap<StructInfo> Structs;421422/// Maps data location names to types.423StringMap<AsmTypeInfo> KnownType;424425/// Stack of active macro instantiations.426std::vector<MacroInstantiation*> ActiveMacros;427428/// List of bodies of anonymous macros.429std::deque<MCAsmMacro> MacroLikeBodies;430431/// Keeps track of how many .macro's have been instantiated.432unsigned NumOfMacroInstantiations;433434/// The values from the last parsed cpp hash file line comment if any.435struct CppHashInfoTy {436StringRef Filename;437int64_t LineNumber;438SMLoc Loc;439unsigned Buf;440CppHashInfoTy() : LineNumber(0), Buf(0) {}441};442CppHashInfoTy CppHashInfo;443444/// The filename from the first cpp hash file line comment, if any.445StringRef FirstCppHashFilename;446447/// List of forward directional labels for diagnosis at the end.448SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;449450/// AssemblerDialect. ~OU means unset value and use value provided by MAI.451/// Defaults to 1U, meaning Intel.452unsigned AssemblerDialect = 1U;453454/// is Darwin compatibility enabled?455bool IsDarwin = false;456457/// Are we parsing ms-style inline assembly?458bool ParsingMSInlineAsm = false;459460/// Did we already inform the user about inconsistent MD5 usage?461bool ReportedInconsistentMD5 = false;462463// Current <...> expression depth.464unsigned AngleBracketDepth = 0U;465466// Number of locals defined.467uint16_t LocalCounter = 0;468469public:470MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,471const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0);472MasmParser(const MasmParser &) = delete;473MasmParser &operator=(const MasmParser &) = delete;474~MasmParser() override;475476bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;477478void addDirectiveHandler(StringRef Directive,479ExtensionDirectiveHandler Handler) override {480ExtensionDirectiveMap[Directive] = Handler;481if (!DirectiveKindMap.contains(Directive)) {482DirectiveKindMap[Directive] = DK_HANDLER_DIRECTIVE;483}484}485486void addAliasForDirective(StringRef Directive, StringRef Alias) override {487DirectiveKindMap[Directive] = DirectiveKindMap[Alias];488}489490/// @name MCAsmParser Interface491/// {492493SourceMgr &getSourceManager() override { return SrcMgr; }494MCAsmLexer &getLexer() override { return Lexer; }495MCContext &getContext() override { return Ctx; }496MCStreamer &getStreamer() override { return Out; }497498CodeViewContext &getCVContext() { return Ctx.getCVContext(); }499500unsigned getAssemblerDialect() override {501if (AssemblerDialect == ~0U)502return MAI.getAssemblerDialect();503else504return AssemblerDialect;505}506void setAssemblerDialect(unsigned i) override {507AssemblerDialect = i;508}509510void Note(SMLoc L, const Twine &Msg, SMRange Range = std::nullopt) override;511bool Warning(SMLoc L, const Twine &Msg,512SMRange Range = std::nullopt) override;513bool printError(SMLoc L, const Twine &Msg,514SMRange Range = std::nullopt) override;515516enum ExpandKind { ExpandMacros, DoNotExpandMacros };517const AsmToken &Lex(ExpandKind ExpandNextToken);518const AsmToken &Lex() override { return Lex(ExpandMacros); }519520void setParsingMSInlineAsm(bool V) override {521ParsingMSInlineAsm = V;522// When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and523// hex integer literals.524Lexer.setLexMasmIntegers(V);525}526bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; }527528bool isParsingMasm() const override { return true; }529530bool defineMacro(StringRef Name, StringRef Value) override;531532bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override;533bool lookUpField(StringRef Base, StringRef Member,534AsmFieldInfo &Info) const override;535536bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override;537538bool parseMSInlineAsm(std::string &AsmString, unsigned &NumOutputs,539unsigned &NumInputs,540SmallVectorImpl<std::pair<void *, bool>> &OpDecls,541SmallVectorImpl<std::string> &Constraints,542SmallVectorImpl<std::string> &Clobbers,543const MCInstrInfo *MII, const MCInstPrinter *IP,544MCAsmParserSemaCallback &SI) override;545546bool parseExpression(const MCExpr *&Res);547bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;548bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,549AsmTypeInfo *TypeInfo) override;550bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;551bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,552SMLoc &EndLoc) override;553bool parseAbsoluteExpression(int64_t &Res) override;554555/// Parse a floating point expression using the float \p Semantics556/// and set \p Res to the value.557bool parseRealValue(const fltSemantics &Semantics, APInt &Res);558559/// Parse an identifier or string (as a quoted identifier)560/// and set \p Res to the identifier contents.561enum IdentifierPositionKind { StandardPosition, StartOfStatement };562bool parseIdentifier(StringRef &Res, IdentifierPositionKind Position);563bool parseIdentifier(StringRef &Res) override {564return parseIdentifier(Res, StandardPosition);565}566void eatToEndOfStatement() override;567568bool checkForValidSection() override;569570/// }571572private:573bool expandMacros();574const AsmToken peekTok(bool ShouldSkipSpace = true);575576bool parseStatement(ParseStatementInfo &Info,577MCAsmParserSemaCallback *SI);578bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);579bool parseCppHashLineFilenameComment(SMLoc L);580581bool expandMacro(raw_svector_ostream &OS, StringRef Body,582ArrayRef<MCAsmMacroParameter> Parameters,583ArrayRef<MCAsmMacroArgument> A,584const std::vector<std::string> &Locals, SMLoc L);585586/// Are we inside a macro instantiation?587bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}588589/// Handle entry to macro instantiation.590///591/// \param M The macro.592/// \param NameLoc Instantiation location.593bool handleMacroEntry(594const MCAsmMacro *M, SMLoc NameLoc,595AsmToken::TokenKind ArgumentEndTok = AsmToken::EndOfStatement);596597/// Handle invocation of macro function.598///599/// \param M The macro.600/// \param NameLoc Invocation location.601bool handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc);602603/// Handle exit from macro instantiation.604void handleMacroExit();605606/// Extract AsmTokens for a macro argument.607bool608parseMacroArgument(const MCAsmMacroParameter *MP, MCAsmMacroArgument &MA,609AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);610611/// Parse all macro arguments for a given macro.612bool613parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A,614AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);615616void printMacroInstantiations();617618bool expandStatement(SMLoc Loc);619620void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,621SMRange Range = std::nullopt) const {622ArrayRef<SMRange> Ranges(Range);623SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);624}625static void DiagHandler(const SMDiagnostic &Diag, void *Context);626627bool lookUpField(const StructInfo &Structure, StringRef Member,628AsmFieldInfo &Info) const;629630/// Should we emit DWARF describing this assembler source? (Returns false if631/// the source has .file directives, which means we don't want to generate632/// info describing the assembler source itself.)633bool enabledGenDwarfForAssembly();634635/// Enter the specified file. This returns true on failure.636bool enterIncludeFile(const std::string &Filename);637638/// Reset the current lexer position to that given by \p Loc. The639/// current token is not set; clients should ensure Lex() is called640/// subsequently.641///642/// \param InBuffer If not 0, should be the known buffer id that contains the643/// location.644void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0,645bool EndStatementAtEOF = true);646647/// Parse up to a token of kind \p EndTok and return the contents from the648/// current token up to (but not including) this token; the current token on649/// exit will be either this kind or EOF. Reads through instantiated macro650/// functions and text macros.651SmallVector<StringRef, 1> parseStringRefsTo(AsmToken::TokenKind EndTok);652std::string parseStringTo(AsmToken::TokenKind EndTok);653654/// Parse up to the end of statement and return the contents from the current655/// token until the end of the statement; the current token on exit will be656/// either the EndOfStatement or EOF.657StringRef parseStringToEndOfStatement() override;658659bool parseTextItem(std::string &Data);660661unsigned getBinOpPrecedence(AsmToken::TokenKind K,662MCBinaryExpr::Opcode &Kind);663664bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);665bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);666bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);667668bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);669670bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);671bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);672673// Generic (target and platform independent) directive parsing.674enum DirectiveKind {675DK_NO_DIRECTIVE, // Placeholder676DK_HANDLER_DIRECTIVE,677DK_ASSIGN,678DK_EQU,679DK_TEXTEQU,680DK_ASCII,681DK_ASCIZ,682DK_STRING,683DK_BYTE,684DK_SBYTE,685DK_WORD,686DK_SWORD,687DK_DWORD,688DK_SDWORD,689DK_FWORD,690DK_QWORD,691DK_SQWORD,692DK_DB,693DK_DD,694DK_DF,695DK_DQ,696DK_DW,697DK_REAL4,698DK_REAL8,699DK_REAL10,700DK_ALIGN,701DK_EVEN,702DK_ORG,703DK_ENDR,704DK_EXTERN,705DK_PUBLIC,706DK_COMM,707DK_COMMENT,708DK_INCLUDE,709DK_REPEAT,710DK_WHILE,711DK_FOR,712DK_FORC,713DK_IF,714DK_IFE,715DK_IFB,716DK_IFNB,717DK_IFDEF,718DK_IFNDEF,719DK_IFDIF,720DK_IFDIFI,721DK_IFIDN,722DK_IFIDNI,723DK_ELSEIF,724DK_ELSEIFE,725DK_ELSEIFB,726DK_ELSEIFNB,727DK_ELSEIFDEF,728DK_ELSEIFNDEF,729DK_ELSEIFDIF,730DK_ELSEIFDIFI,731DK_ELSEIFIDN,732DK_ELSEIFIDNI,733DK_ELSE,734DK_ENDIF,735DK_FILE,736DK_LINE,737DK_LOC,738DK_STABS,739DK_CV_FILE,740DK_CV_FUNC_ID,741DK_CV_INLINE_SITE_ID,742DK_CV_LOC,743DK_CV_LINETABLE,744DK_CV_INLINE_LINETABLE,745DK_CV_DEF_RANGE,746DK_CV_STRINGTABLE,747DK_CV_STRING,748DK_CV_FILECHECKSUMS,749DK_CV_FILECHECKSUM_OFFSET,750DK_CV_FPO_DATA,751DK_CFI_SECTIONS,752DK_CFI_STARTPROC,753DK_CFI_ENDPROC,754DK_CFI_DEF_CFA,755DK_CFI_DEF_CFA_OFFSET,756DK_CFI_ADJUST_CFA_OFFSET,757DK_CFI_DEF_CFA_REGISTER,758DK_CFI_OFFSET,759DK_CFI_REL_OFFSET,760DK_CFI_PERSONALITY,761DK_CFI_LSDA,762DK_CFI_REMEMBER_STATE,763DK_CFI_RESTORE_STATE,764DK_CFI_SAME_VALUE,765DK_CFI_RESTORE,766DK_CFI_ESCAPE,767DK_CFI_RETURN_COLUMN,768DK_CFI_SIGNAL_FRAME,769DK_CFI_UNDEFINED,770DK_CFI_REGISTER,771DK_CFI_WINDOW_SAVE,772DK_CFI_B_KEY_FRAME,773DK_MACRO,774DK_EXITM,775DK_ENDM,776DK_PURGE,777DK_ERR,778DK_ERRB,779DK_ERRNB,780DK_ERRDEF,781DK_ERRNDEF,782DK_ERRDIF,783DK_ERRDIFI,784DK_ERRIDN,785DK_ERRIDNI,786DK_ERRE,787DK_ERRNZ,788DK_ECHO,789DK_STRUCT,790DK_UNION,791DK_ENDS,792DK_END,793DK_PUSHFRAME,794DK_PUSHREG,795DK_SAVEREG,796DK_SAVEXMM128,797DK_SETFRAME,798DK_RADIX,799};800801/// Maps directive name --> DirectiveKind enum, for directives parsed by this802/// class.803StringMap<DirectiveKind> DirectiveKindMap;804805bool isMacroLikeDirective();806807// Codeview def_range type parsing.808enum CVDefRangeType {809CVDR_DEFRANGE = 0, // Placeholder810CVDR_DEFRANGE_REGISTER,811CVDR_DEFRANGE_FRAMEPOINTER_REL,812CVDR_DEFRANGE_SUBFIELD_REGISTER,813CVDR_DEFRANGE_REGISTER_REL814};815816/// Maps Codeview def_range types --> CVDefRangeType enum, for Codeview817/// def_range types parsed by this class.818StringMap<CVDefRangeType> CVDefRangeTypeMap;819820// Generic (target and platform independent) directive parsing.821enum BuiltinSymbol {822BI_NO_SYMBOL, // Placeholder823BI_DATE,824BI_TIME,825BI_VERSION,826BI_FILECUR,827BI_FILENAME,828BI_LINE,829BI_CURSEG,830BI_CPU,831BI_INTERFACE,832BI_CODE,833BI_DATA,834BI_FARDATA,835BI_WORDSIZE,836BI_CODESIZE,837BI_DATASIZE,838BI_MODEL,839BI_STACK,840};841842/// Maps builtin name --> BuiltinSymbol enum, for builtins handled by this843/// class.844StringMap<BuiltinSymbol> BuiltinSymbolMap;845846const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc);847848std::optional<std::string> evaluateBuiltinTextMacro(BuiltinSymbol Symbol,849SMLoc StartLoc);850851// ".ascii", ".asciz", ".string"852bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);853854// "byte", "word", ...855bool emitIntValue(const MCExpr *Value, unsigned Size);856bool parseScalarInitializer(unsigned Size,857SmallVectorImpl<const MCExpr *> &Values,858unsigned StringPadLength = 0);859bool parseScalarInstList(860unsigned Size, SmallVectorImpl<const MCExpr *> &Values,861const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);862bool emitIntegralValues(unsigned Size, unsigned *Count = nullptr);863bool addIntegralField(StringRef Name, unsigned Size);864bool parseDirectiveValue(StringRef IDVal, unsigned Size);865bool parseDirectiveNamedValue(StringRef TypeName, unsigned Size,866StringRef Name, SMLoc NameLoc);867868// "real4", "real8", "real10"869bool emitRealValues(const fltSemantics &Semantics, unsigned *Count = nullptr);870bool addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size);871bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics,872size_t Size);873bool parseRealInstList(874const fltSemantics &Semantics, SmallVectorImpl<APInt> &Values,875const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);876bool parseDirectiveNamedRealValue(StringRef TypeName,877const fltSemantics &Semantics,878unsigned Size, StringRef Name,879SMLoc NameLoc);880881bool parseOptionalAngleBracketOpen();882bool parseAngleBracketClose(const Twine &Msg = "expected '>'");883884bool parseFieldInitializer(const FieldInfo &Field,885FieldInitializer &Initializer);886bool parseFieldInitializer(const FieldInfo &Field,887const IntFieldInfo &Contents,888FieldInitializer &Initializer);889bool parseFieldInitializer(const FieldInfo &Field,890const RealFieldInfo &Contents,891FieldInitializer &Initializer);892bool parseFieldInitializer(const FieldInfo &Field,893const StructFieldInfo &Contents,894FieldInitializer &Initializer);895896bool parseStructInitializer(const StructInfo &Structure,897StructInitializer &Initializer);898bool parseStructInstList(899const StructInfo &Structure, std::vector<StructInitializer> &Initializers,900const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);901902bool emitFieldValue(const FieldInfo &Field);903bool emitFieldValue(const FieldInfo &Field, const IntFieldInfo &Contents);904bool emitFieldValue(const FieldInfo &Field, const RealFieldInfo &Contents);905bool emitFieldValue(const FieldInfo &Field, const StructFieldInfo &Contents);906907bool emitFieldInitializer(const FieldInfo &Field,908const FieldInitializer &Initializer);909bool emitFieldInitializer(const FieldInfo &Field,910const IntFieldInfo &Contents,911const IntFieldInfo &Initializer);912bool emitFieldInitializer(const FieldInfo &Field,913const RealFieldInfo &Contents,914const RealFieldInfo &Initializer);915bool emitFieldInitializer(const FieldInfo &Field,916const StructFieldInfo &Contents,917const StructFieldInfo &Initializer);918919bool emitStructInitializer(const StructInfo &Structure,920const StructInitializer &Initializer);921922// User-defined types (structs, unions):923bool emitStructValues(const StructInfo &Structure, unsigned *Count = nullptr);924bool addStructField(StringRef Name, const StructInfo &Structure);925bool parseDirectiveStructValue(const StructInfo &Structure,926StringRef Directive, SMLoc DirLoc);927bool parseDirectiveNamedStructValue(const StructInfo &Structure,928StringRef Directive, SMLoc DirLoc,929StringRef Name);930931// "=", "equ", "textequ"932bool parseDirectiveEquate(StringRef IDVal, StringRef Name,933DirectiveKind DirKind, SMLoc NameLoc);934935bool parseDirectiveOrg(); // "org"936937bool emitAlignTo(int64_t Alignment);938bool parseDirectiveAlign(); // "align"939bool parseDirectiveEven(); // "even"940941// ".file", ".line", ".loc", ".stabs"942bool parseDirectiveFile(SMLoc DirectiveLoc);943bool parseDirectiveLine();944bool parseDirectiveLoc();945bool parseDirectiveStabs();946947// ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",948// ".cv_inline_linetable", ".cv_def_range", ".cv_string"949bool parseDirectiveCVFile();950bool parseDirectiveCVFuncId();951bool parseDirectiveCVInlineSiteId();952bool parseDirectiveCVLoc();953bool parseDirectiveCVLinetable();954bool parseDirectiveCVInlineLinetable();955bool parseDirectiveCVDefRange();956bool parseDirectiveCVString();957bool parseDirectiveCVStringTable();958bool parseDirectiveCVFileChecksums();959bool parseDirectiveCVFileChecksumOffset();960bool parseDirectiveCVFPOData();961962// .cfi directives963bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);964bool parseDirectiveCFIWindowSave(SMLoc DirectiveLoc);965bool parseDirectiveCFISections();966bool parseDirectiveCFIStartProc();967bool parseDirectiveCFIEndProc();968bool parseDirectiveCFIDefCfaOffset(SMLoc DirectiveLoc);969bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);970bool parseDirectiveCFIAdjustCfaOffset(SMLoc DirectiveLoc);971bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);972bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);973bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);974bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);975bool parseDirectiveCFIRememberState(SMLoc DirectiveLoc);976bool parseDirectiveCFIRestoreState(SMLoc DirectiveLoc);977bool parseDirectiveCFISameValue(SMLoc DirectiveLoc);978bool parseDirectiveCFIRestore(SMLoc DirectiveLoc);979bool parseDirectiveCFIEscape(SMLoc DirectiveLoc);980bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);981bool parseDirectiveCFISignalFrame();982bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);983984// macro directives985bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);986bool parseDirectiveExitMacro(SMLoc DirectiveLoc, StringRef Directive,987std::string &Value);988bool parseDirectiveEndMacro(StringRef Directive);989bool parseDirectiveMacro(StringRef Name, SMLoc NameLoc);990991bool parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind,992StringRef Name, SMLoc NameLoc);993bool parseDirectiveNestedStruct(StringRef Directive, DirectiveKind DirKind);994bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc);995bool parseDirectiveNestedEnds();996997bool parseDirectiveExtern();998999/// Parse a directive like ".globl" which accepts a single symbol (which1000/// should be a label or an external).1001bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);10021003bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"10041005bool parseDirectiveComment(SMLoc DirectiveLoc); // "comment"10061007bool parseDirectiveInclude(); // "include"10081009// "if" or "ife"1010bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);1011// "ifb" or "ifnb", depending on ExpectBlank.1012bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);1013// "ifidn", "ifdif", "ifidni", or "ifdifi", depending on ExpectEqual and1014// CaseInsensitive.1015bool parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,1016bool CaseInsensitive);1017// "ifdef" or "ifndef", depending on expect_defined1018bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);1019// "elseif" or "elseife"1020bool parseDirectiveElseIf(SMLoc DirectiveLoc, DirectiveKind DirKind);1021// "elseifb" or "elseifnb", depending on ExpectBlank.1022bool parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank);1023// ".elseifdef" or ".elseifndef", depending on expect_defined1024bool parseDirectiveElseIfdef(SMLoc DirectiveLoc, bool expect_defined);1025// "elseifidn", "elseifdif", "elseifidni", or "elseifdifi", depending on1026// ExpectEqual and CaseInsensitive.1027bool parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,1028bool CaseInsensitive);1029bool parseDirectiveElse(SMLoc DirectiveLoc); // "else"1030bool parseDirectiveEndIf(SMLoc DirectiveLoc); // "endif"1031bool parseEscapedString(std::string &Data) override;1032bool parseAngleBracketString(std::string &Data) override;10331034// Macro-like directives1035MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);1036void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,1037raw_svector_ostream &OS);1038void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,1039SMLoc ExitLoc, raw_svector_ostream &OS);1040bool parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Directive);1041bool parseDirectiveFor(SMLoc DirectiveLoc, StringRef Directive);1042bool parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive);1043bool parseDirectiveWhile(SMLoc DirectiveLoc);10441045// "_emit" or "__emit"1046bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,1047size_t Len);10481049// "align"1050bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);10511052// "end"1053bool parseDirectiveEnd(SMLoc DirectiveLoc);10541055// ".err"1056bool parseDirectiveError(SMLoc DirectiveLoc);1057// ".errb" or ".errnb", depending on ExpectBlank.1058bool parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank);1059// ".errdef" or ".errndef", depending on ExpectBlank.1060bool parseDirectiveErrorIfdef(SMLoc DirectiveLoc, bool ExpectDefined);1061// ".erridn", ".errdif", ".erridni", or ".errdifi", depending on ExpectEqual1062// and CaseInsensitive.1063bool parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,1064bool CaseInsensitive);1065// ".erre" or ".errnz", depending on ExpectZero.1066bool parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero);10671068// ".radix"1069bool parseDirectiveRadix(SMLoc DirectiveLoc);10701071// "echo"1072bool parseDirectiveEcho(SMLoc DirectiveLoc);10731074void initializeDirectiveKindMap();1075void initializeCVDefRangeTypeMap();1076void initializeBuiltinSymbolMap();1077};10781079} // end anonymous namespace10801081namespace llvm {10821083extern cl::opt<unsigned> AsmMacroMaxNestingDepth;10841085extern MCAsmParserExtension *createCOFFMasmParser();10861087} // end namespace llvm10881089enum { DEFAULT_ADDRSPACE = 0 };10901091MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,1092const MCAsmInfo &MAI, struct tm TM, unsigned CB)1093: Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),1094CurBuffer(CB ? CB : SM.getMainFileID()), TM(TM) {1095HadError = false;1096// Save the old handler.1097SavedDiagHandler = SrcMgr.getDiagHandler();1098SavedDiagContext = SrcMgr.getDiagContext();1099// Set our own handler which calls the saved handler.1100SrcMgr.setDiagHandler(DiagHandler, this);1101Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());1102EndStatementAtEOFStack.push_back(true);11031104// Initialize the platform / file format parser.1105switch (Ctx.getObjectFileType()) {1106case MCContext::IsCOFF:1107PlatformParser.reset(createCOFFMasmParser());1108break;1109default:1110report_fatal_error("llvm-ml currently supports only COFF output.");1111break;1112}11131114initializeDirectiveKindMap();1115PlatformParser->Initialize(*this);1116initializeCVDefRangeTypeMap();1117initializeBuiltinSymbolMap();11181119NumOfMacroInstantiations = 0;1120}11211122MasmParser::~MasmParser() {1123assert((HadError || ActiveMacros.empty()) &&1124"Unexpected active macro instantiation!");11251126// Restore the saved diagnostics handler and context for use during1127// finalization.1128SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);1129}11301131void MasmParser::printMacroInstantiations() {1132// Print the active macro instantiation stack.1133for (std::vector<MacroInstantiation *>::const_reverse_iterator1134it = ActiveMacros.rbegin(),1135ie = ActiveMacros.rend();1136it != ie; ++it)1137printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,1138"while in macro instantiation");1139}11401141void MasmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {1142printPendingErrors();1143printMessage(L, SourceMgr::DK_Note, Msg, Range);1144printMacroInstantiations();1145}11461147bool MasmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {1148if (getTargetParser().getTargetOptions().MCNoWarn)1149return false;1150if (getTargetParser().getTargetOptions().MCFatalWarnings)1151return Error(L, Msg, Range);1152printMessage(L, SourceMgr::DK_Warning, Msg, Range);1153printMacroInstantiations();1154return false;1155}11561157bool MasmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {1158HadError = true;1159printMessage(L, SourceMgr::DK_Error, Msg, Range);1160printMacroInstantiations();1161return true;1162}11631164bool MasmParser::enterIncludeFile(const std::string &Filename) {1165std::string IncludedFile;1166unsigned NewBuf =1167SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);1168if (!NewBuf)1169return true;11701171CurBuffer = NewBuf;1172Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());1173EndStatementAtEOFStack.push_back(true);1174return false;1175}11761177void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer,1178bool EndStatementAtEOF) {1179CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);1180Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),1181Loc.getPointer(), EndStatementAtEOF);1182}11831184bool MasmParser::expandMacros() {1185const AsmToken &Tok = getTok();1186const std::string IDLower = Tok.getIdentifier().lower();11871188const llvm::MCAsmMacro *M = getContext().lookupMacro(IDLower);1189if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) {1190// This is a macro function invocation; expand it in place.1191const SMLoc MacroLoc = Tok.getLoc();1192const StringRef MacroId = Tok.getIdentifier();1193Lexer.Lex();1194if (handleMacroInvocation(M, MacroLoc)) {1195Lexer.UnLex(AsmToken(AsmToken::Error, MacroId));1196Lexer.Lex();1197}1198return false;1199}12001201std::optional<std::string> ExpandedValue;1202auto BuiltinIt = BuiltinSymbolMap.find(IDLower);1203if (BuiltinIt != BuiltinSymbolMap.end()) {1204ExpandedValue =1205evaluateBuiltinTextMacro(BuiltinIt->getValue(), Tok.getLoc());1206} else {1207auto VarIt = Variables.find(IDLower);1208if (VarIt != Variables.end() && VarIt->getValue().IsText) {1209ExpandedValue = VarIt->getValue().TextValue;1210}1211}12121213if (!ExpandedValue)1214return true;1215std::unique_ptr<MemoryBuffer> Instantiation =1216MemoryBuffer::getMemBufferCopy(*ExpandedValue, "<instantiation>");12171218// Jump to the macro instantiation and prime the lexer.1219CurBuffer =1220SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());1221Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,1222/*EndStatementAtEOF=*/false);1223EndStatementAtEOFStack.push_back(false);1224Lexer.Lex();1225return false;1226}12271228const AsmToken &MasmParser::Lex(ExpandKind ExpandNextToken) {1229if (Lexer.getTok().is(AsmToken::Error))1230Error(Lexer.getErrLoc(), Lexer.getErr());12311232// if it's a end of statement with a comment in it1233if (getTok().is(AsmToken::EndOfStatement)) {1234// if this is a line comment output it.1235if (!getTok().getString().empty() && getTok().getString().front() != '\n' &&1236getTok().getString().front() != '\r' && MAI.preserveAsmComments())1237Out.addExplicitComment(Twine(getTok().getString()));1238}12391240const AsmToken *tok = &Lexer.Lex();1241bool StartOfStatement = Lexer.isAtStartOfStatement();12421243while (ExpandNextToken == ExpandMacros && tok->is(AsmToken::Identifier)) {1244if (StartOfStatement) {1245AsmToken NextTok;1246MutableArrayRef<AsmToken> Buf(NextTok);1247size_t ReadCount = Lexer.peekTokens(Buf);1248if (ReadCount && NextTok.is(AsmToken::Identifier) &&1249(NextTok.getString().equals_insensitive("equ") ||1250NextTok.getString().equals_insensitive("textequ"))) {1251// This looks like an EQU or TEXTEQU directive; don't expand the1252// identifier, allowing for redefinitions.1253break;1254}1255}1256if (expandMacros())1257break;1258}12591260// Parse comments here to be deferred until end of next statement.1261while (tok->is(AsmToken::Comment)) {1262if (MAI.preserveAsmComments())1263Out.addExplicitComment(Twine(tok->getString()));1264tok = &Lexer.Lex();1265}12661267// Recognize and bypass line continuations.1268while (tok->is(AsmToken::BackSlash) &&1269peekTok().is(AsmToken::EndOfStatement)) {1270// Eat both the backslash and the end of statement.1271Lexer.Lex();1272tok = &Lexer.Lex();1273}12741275if (tok->is(AsmToken::Eof)) {1276// If this is the end of an included file, pop the parent file off the1277// include stack.1278SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1279if (ParentIncludeLoc != SMLoc()) {1280EndStatementAtEOFStack.pop_back();1281jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1282return Lex();1283}1284EndStatementAtEOFStack.pop_back();1285assert(EndStatementAtEOFStack.empty());1286}12871288return *tok;1289}12901291const AsmToken MasmParser::peekTok(bool ShouldSkipSpace) {1292AsmToken Tok;12931294MutableArrayRef<AsmToken> Buf(Tok);1295size_t ReadCount = Lexer.peekTokens(Buf, ShouldSkipSpace);12961297if (ReadCount == 0) {1298// If this is the end of an included file, pop the parent file off the1299// include stack.1300SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1301if (ParentIncludeLoc != SMLoc()) {1302EndStatementAtEOFStack.pop_back();1303jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1304return peekTok(ShouldSkipSpace);1305}1306EndStatementAtEOFStack.pop_back();1307assert(EndStatementAtEOFStack.empty());1308}13091310assert(ReadCount == 1);1311return Tok;1312}13131314bool MasmParser::enabledGenDwarfForAssembly() {1315// Check whether the user specified -g.1316if (!getContext().getGenDwarfForAssembly())1317return false;1318// If we haven't encountered any .file directives (which would imply that1319// the assembler source was produced with debug info already) then emit one1320// describing the assembler source file itself.1321if (getContext().getGenDwarfFileNumber() == 0) {1322// Use the first #line directive for this, if any. It's preprocessed, so1323// there is no checksum, and of course no source directive.1324if (!FirstCppHashFilename.empty())1325getContext().setMCLineTableRootFile(1326/*CUID=*/0, getContext().getCompilationDir(), FirstCppHashFilename,1327/*Cksum=*/std::nullopt, /*Source=*/std::nullopt);1328const MCDwarfFile &RootFile =1329getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile();1330getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective(1331/*CUID=*/0, getContext().getCompilationDir(), RootFile.Name,1332RootFile.Checksum, RootFile.Source));1333}1334return true;1335}13361337bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize) {1338// Create the initial section, if requested.1339if (!NoInitialTextSection)1340Out.initSections(false, getTargetParser().getSTI());13411342// Prime the lexer.1343Lex();13441345HadError = false;1346AsmCond StartingCondState = TheCondState;1347SmallVector<AsmRewrite, 4> AsmStrRewrites;13481349// If we are generating dwarf for assembly source files save the initial text1350// section. (Don't use enabledGenDwarfForAssembly() here, as we aren't1351// emitting any actual debug info yet and haven't had a chance to parse any1352// embedded .file directives.)1353if (getContext().getGenDwarfForAssembly()) {1354MCSection *Sec = getStreamer().getCurrentSectionOnly();1355if (!Sec->getBeginSymbol()) {1356MCSymbol *SectionStartSym = getContext().createTempSymbol();1357getStreamer().emitLabel(SectionStartSym);1358Sec->setBeginSymbol(SectionStartSym);1359}1360bool InsertResult = getContext().addGenDwarfSection(Sec);1361assert(InsertResult && ".text section should not have debug info yet");1362(void)InsertResult;1363}13641365getTargetParser().onBeginOfFile();13661367// While we have input, parse each statement.1368while (Lexer.isNot(AsmToken::Eof) ||1369SrcMgr.getParentIncludeLoc(CurBuffer) != SMLoc()) {1370// Skip through the EOF at the end of an inclusion.1371if (Lexer.is(AsmToken::Eof))1372Lex();13731374ParseStatementInfo Info(&AsmStrRewrites);1375bool Parsed = parseStatement(Info, nullptr);13761377// If we have a Lexer Error we are on an Error Token. Load in Lexer Error1378// for printing ErrMsg via Lex() only if no (presumably better) parser error1379// exists.1380if (Parsed && !hasPendingError() && Lexer.getTok().is(AsmToken::Error)) {1381Lex();1382}13831384// parseStatement returned true so may need to emit an error.1385printPendingErrors();13861387// Skipping to the next line if needed.1388if (Parsed && !getLexer().isAtStartOfStatement())1389eatToEndOfStatement();1390}13911392getTargetParser().onEndOfFile();1393printPendingErrors();13941395// All errors should have been emitted.1396assert(!hasPendingError() && "unexpected error from parseStatement");13971398getTargetParser().flushPendingInstructions(getStreamer());13991400if (TheCondState.TheCond != StartingCondState.TheCond ||1401TheCondState.Ignore != StartingCondState.Ignore)1402printError(getTok().getLoc(), "unmatched .ifs or .elses");1403// Check to see there are no empty DwarfFile slots.1404const auto &LineTables = getContext().getMCDwarfLineTables();1405if (!LineTables.empty()) {1406unsigned Index = 0;1407for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) {1408if (File.Name.empty() && Index != 0)1409printError(getTok().getLoc(), "unassigned file number: " +1410Twine(Index) +1411" for .file directives");1412++Index;1413}1414}14151416// Check to see that all assembler local symbols were actually defined.1417// Targets that don't do subsections via symbols may not want this, though,1418// so conservatively exclude them. Only do this if we're finalizing, though,1419// as otherwise we won't necessarilly have seen everything yet.1420if (!NoFinalize) {1421if (MAI.hasSubsectionsViaSymbols()) {1422for (const auto &TableEntry : getContext().getSymbols()) {1423MCSymbol *Sym = TableEntry.getValue().Symbol;1424// Variable symbols may not be marked as defined, so check those1425// explicitly. If we know it's a variable, we have a definition for1426// the purposes of this check.1427if (Sym && Sym->isTemporary() && !Sym->isVariable() &&1428!Sym->isDefined())1429// FIXME: We would really like to refer back to where the symbol was1430// first referenced for a source location. We need to add something1431// to track that. Currently, we just point to the end of the file.1432printError(getTok().getLoc(), "assembler local symbol '" +1433Sym->getName() + "' not defined");1434}1435}14361437// Temporary symbols like the ones for directional jumps don't go in the1438// symbol table. They also need to be diagnosed in all (final) cases.1439for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {1440if (std::get<2>(LocSym)->isUndefined()) {1441// Reset the state of any "# line file" directives we've seen to the1442// context as it was at the diagnostic site.1443CppHashInfo = std::get<1>(LocSym);1444printError(std::get<0>(LocSym), "directional label undefined");1445}1446}1447}14481449// Finalize the output stream if there are no errors and if the client wants1450// us to.1451if (!HadError && !NoFinalize)1452Out.finish(Lexer.getLoc());14531454return HadError || getContext().hadError();1455}14561457bool MasmParser::checkForValidSection() {1458if (!ParsingMSInlineAsm && !getStreamer().getCurrentSectionOnly()) {1459Out.initSections(false, getTargetParser().getSTI());1460return Error(getTok().getLoc(),1461"expected section directive before assembly directive");1462}1463return false;1464}14651466/// Throw away the rest of the line for testing purposes.1467void MasmParser::eatToEndOfStatement() {1468while (Lexer.isNot(AsmToken::EndOfStatement)) {1469if (Lexer.is(AsmToken::Eof)) {1470SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1471if (ParentIncludeLoc == SMLoc()) {1472break;1473}14741475EndStatementAtEOFStack.pop_back();1476jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1477}14781479Lexer.Lex();1480}14811482// Eat EOL.1483if (Lexer.is(AsmToken::EndOfStatement))1484Lexer.Lex();1485}14861487SmallVector<StringRef, 1>1488MasmParser::parseStringRefsTo(AsmToken::TokenKind EndTok) {1489SmallVector<StringRef, 1> Refs;1490const char *Start = getTok().getLoc().getPointer();1491while (Lexer.isNot(EndTok)) {1492if (Lexer.is(AsmToken::Eof)) {1493SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1494if (ParentIncludeLoc == SMLoc()) {1495break;1496}1497Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);14981499EndStatementAtEOFStack.pop_back();1500jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1501Lexer.Lex();1502Start = getTok().getLoc().getPointer();1503} else {1504Lexer.Lex();1505}1506}1507Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);1508return Refs;1509}15101511std::string MasmParser::parseStringTo(AsmToken::TokenKind EndTok) {1512SmallVector<StringRef, 1> Refs = parseStringRefsTo(EndTok);1513std::string Str;1514for (StringRef S : Refs) {1515Str.append(S.str());1516}1517return Str;1518}15191520StringRef MasmParser::parseStringToEndOfStatement() {1521const char *Start = getTok().getLoc().getPointer();15221523while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))1524Lexer.Lex();15251526const char *End = getTok().getLoc().getPointer();1527return StringRef(Start, End - Start);1528}15291530/// Parse a paren expression and return it.1531/// NOTE: This assumes the leading '(' has already been consumed.1532///1533/// parenexpr ::= expr)1534///1535bool MasmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {1536if (parseExpression(Res))1537return true;1538EndLoc = Lexer.getTok().getEndLoc();1539return parseRParen();1540}15411542/// Parse a bracket expression and return it.1543/// NOTE: This assumes the leading '[' has already been consumed.1544///1545/// bracketexpr ::= expr]1546///1547bool MasmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {1548if (parseExpression(Res))1549return true;1550EndLoc = getTok().getEndLoc();1551if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))1552return true;1553return false;1554}15551556/// Parse a primary expression and return it.1557/// primaryexpr ::= (parenexpr1558/// primaryexpr ::= symbol1559/// primaryexpr ::= number1560/// primaryexpr ::= '.'1561/// primaryexpr ::= ~,+,-,'not' primaryexpr1562/// primaryexpr ::= string1563/// (a string is interpreted as a 64-bit number in big-endian base-256)1564bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,1565AsmTypeInfo *TypeInfo) {1566SMLoc FirstTokenLoc = getLexer().getLoc();1567AsmToken::TokenKind FirstTokenKind = Lexer.getKind();1568switch (FirstTokenKind) {1569default:1570return TokError("unknown token in expression");1571// If we have an error assume that we've already handled it.1572case AsmToken::Error:1573return true;1574case AsmToken::Exclaim:1575Lex(); // Eat the operator.1576if (parsePrimaryExpr(Res, EndLoc, nullptr))1577return true;1578Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);1579return false;1580case AsmToken::Dollar:1581case AsmToken::At:1582case AsmToken::Identifier: {1583StringRef Identifier;1584if (parseIdentifier(Identifier)) {1585// We may have failed but $ may be a valid token.1586if (getTok().is(AsmToken::Dollar)) {1587if (Lexer.getMAI().getDollarIsPC()) {1588Lex();1589// This is a '$' reference, which references the current PC. Emit a1590// temporary label to the streamer and refer to it.1591MCSymbol *Sym = Ctx.createTempSymbol();1592Out.emitLabel(Sym);1593Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,1594getContext());1595EndLoc = FirstTokenLoc;1596return false;1597}1598return Error(FirstTokenLoc, "invalid token in expression");1599}1600}1601// Parse named bitwise negation.1602if (Identifier.equals_insensitive("not")) {1603if (parsePrimaryExpr(Res, EndLoc, nullptr))1604return true;1605Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1606return false;1607}1608// Parse directional local label references.1609if (Identifier.equals_insensitive("@b") ||1610Identifier.equals_insensitive("@f")) {1611bool Before = Identifier.equals_insensitive("@b");1612MCSymbol *Sym = getContext().getDirectionalLocalSymbol(0, Before);1613if (Before && Sym->isUndefined())1614return Error(FirstTokenLoc, "Expected @@ label before @B reference");1615Res = MCSymbolRefExpr::create(Sym, getContext());1616return false;1617}1618// Parse symbol variant.1619std::pair<StringRef, StringRef> Split;1620if (!MAI.useParensForSymbolVariant()) {1621Split = Identifier.split('@');1622} else if (Lexer.is(AsmToken::LParen)) {1623Lex(); // eat '('.1624StringRef VName;1625parseIdentifier(VName);1626// eat ')'.1627if (parseToken(AsmToken::RParen,1628"unexpected token in variant, expected ')'"))1629return true;1630Split = std::make_pair(Identifier, VName);1631}16321633EndLoc = SMLoc::getFromPointer(Identifier.end());16341635// This is a symbol reference.1636StringRef SymbolName = Identifier;1637if (SymbolName.empty())1638return Error(getLexer().getLoc(), "expected a symbol reference");16391640MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;16411642// Look up the symbol variant if used.1643if (!Split.second.empty()) {1644Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);1645if (Variant != MCSymbolRefExpr::VK_Invalid) {1646SymbolName = Split.first;1647} else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) {1648Variant = MCSymbolRefExpr::VK_None;1649} else {1650return Error(SMLoc::getFromPointer(Split.second.begin()),1651"invalid variant '" + Split.second + "'");1652}1653}16541655// Find the field offset if used.1656AsmFieldInfo Info;1657Split = SymbolName.split('.');1658if (Split.second.empty()) {1659} else {1660SymbolName = Split.first;1661if (lookUpField(SymbolName, Split.second, Info)) {1662std::pair<StringRef, StringRef> BaseMember = Split.second.split('.');1663StringRef Base = BaseMember.first, Member = BaseMember.second;1664lookUpField(Base, Member, Info);1665} else if (Structs.count(SymbolName.lower())) {1666// This is actually a reference to a field offset.1667Res = MCConstantExpr::create(Info.Offset, getContext());1668return false;1669}1670}16711672MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);1673if (!Sym) {1674// If this is a built-in numeric value, treat it as a constant.1675auto BuiltinIt = BuiltinSymbolMap.find(SymbolName.lower());1676const BuiltinSymbol Symbol = (BuiltinIt == BuiltinSymbolMap.end())1677? BI_NO_SYMBOL1678: BuiltinIt->getValue();1679if (Symbol != BI_NO_SYMBOL) {1680const MCExpr *Value = evaluateBuiltinValue(Symbol, FirstTokenLoc);1681if (Value) {1682Res = Value;1683return false;1684}1685}16861687// Variables use case-insensitive symbol names; if this is a variable, we1688// find the symbol using its canonical name.1689auto VarIt = Variables.find(SymbolName.lower());1690if (VarIt != Variables.end())1691SymbolName = VarIt->second.Name;1692Sym = getContext().getOrCreateSymbol(SymbolName);1693}16941695// If this is an absolute variable reference, substitute it now to preserve1696// semantics in the face of reassignment.1697if (Sym->isVariable()) {1698auto V = Sym->getVariableValue(/*SetUsed=*/false);1699bool DoInline = isa<MCConstantExpr>(V) && !Variant;1700if (auto TV = dyn_cast<MCTargetExpr>(V))1701DoInline = TV->inlineAssignedExpr();1702if (DoInline) {1703if (Variant)1704return Error(EndLoc, "unexpected modifier on variable reference");1705Res = Sym->getVariableValue(/*SetUsed=*/false);1706return false;1707}1708}17091710// Otherwise create a symbol ref.1711const MCExpr *SymRef =1712MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc);1713if (Info.Offset) {1714Res = MCBinaryExpr::create(1715MCBinaryExpr::Add, SymRef,1716MCConstantExpr::create(Info.Offset, getContext()), getContext());1717} else {1718Res = SymRef;1719}1720if (TypeInfo) {1721if (Info.Type.Name.empty()) {1722auto TypeIt = KnownType.find(Identifier.lower());1723if (TypeIt != KnownType.end()) {1724Info.Type = TypeIt->second;1725}1726}17271728*TypeInfo = Info.Type;1729}1730return false;1731}1732case AsmToken::BigNum:1733return TokError("literal value out of range for directive");1734case AsmToken::Integer: {1735int64_t IntVal = getTok().getIntVal();1736Res = MCConstantExpr::create(IntVal, getContext());1737EndLoc = Lexer.getTok().getEndLoc();1738Lex(); // Eat token.1739return false;1740}1741case AsmToken::String: {1742// MASM strings (used as constants) are interpreted as big-endian base-256.1743SMLoc ValueLoc = getTok().getLoc();1744std::string Value;1745if (parseEscapedString(Value))1746return true;1747if (Value.size() > 8)1748return Error(ValueLoc, "literal value out of range");1749uint64_t IntValue = 0;1750for (const unsigned char CharVal : Value)1751IntValue = (IntValue << 8) | CharVal;1752Res = MCConstantExpr::create(IntValue, getContext());1753return false;1754}1755case AsmToken::Real: {1756APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());1757uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();1758Res = MCConstantExpr::create(IntVal, getContext());1759EndLoc = Lexer.getTok().getEndLoc();1760Lex(); // Eat token.1761return false;1762}1763case AsmToken::Dot: {1764// This is a '.' reference, which references the current PC. Emit a1765// temporary label to the streamer and refer to it.1766MCSymbol *Sym = Ctx.createTempSymbol();1767Out.emitLabel(Sym);1768Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());1769EndLoc = Lexer.getTok().getEndLoc();1770Lex(); // Eat identifier.1771return false;1772}1773case AsmToken::LParen:1774Lex(); // Eat the '('.1775return parseParenExpr(Res, EndLoc);1776case AsmToken::LBrac:1777if (!PlatformParser->HasBracketExpressions())1778return TokError("brackets expression not supported on this target");1779Lex(); // Eat the '['.1780return parseBracketExpr(Res, EndLoc);1781case AsmToken::Minus:1782Lex(); // Eat the operator.1783if (parsePrimaryExpr(Res, EndLoc, nullptr))1784return true;1785Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc);1786return false;1787case AsmToken::Plus:1788Lex(); // Eat the operator.1789if (parsePrimaryExpr(Res, EndLoc, nullptr))1790return true;1791Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);1792return false;1793case AsmToken::Tilde:1794Lex(); // Eat the operator.1795if (parsePrimaryExpr(Res, EndLoc, nullptr))1796return true;1797Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1798return false;1799// MIPS unary expression operators. The lexer won't generate these tokens if1800// MCAsmInfo::HasMipsExpressions is false for the target.1801case AsmToken::PercentCall16:1802case AsmToken::PercentCall_Hi:1803case AsmToken::PercentCall_Lo:1804case AsmToken::PercentDtprel_Hi:1805case AsmToken::PercentDtprel_Lo:1806case AsmToken::PercentGot:1807case AsmToken::PercentGot_Disp:1808case AsmToken::PercentGot_Hi:1809case AsmToken::PercentGot_Lo:1810case AsmToken::PercentGot_Ofst:1811case AsmToken::PercentGot_Page:1812case AsmToken::PercentGottprel:1813case AsmToken::PercentGp_Rel:1814case AsmToken::PercentHi:1815case AsmToken::PercentHigher:1816case AsmToken::PercentHighest:1817case AsmToken::PercentLo:1818case AsmToken::PercentNeg:1819case AsmToken::PercentPcrel_Hi:1820case AsmToken::PercentPcrel_Lo:1821case AsmToken::PercentTlsgd:1822case AsmToken::PercentTlsldm:1823case AsmToken::PercentTprel_Hi:1824case AsmToken::PercentTprel_Lo:1825Lex(); // Eat the operator.1826if (Lexer.isNot(AsmToken::LParen))1827return TokError("expected '(' after operator");1828Lex(); // Eat the operator.1829if (parseExpression(Res, EndLoc))1830return true;1831if (parseRParen())1832return true;1833Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx);1834return !Res;1835}1836}18371838bool MasmParser::parseExpression(const MCExpr *&Res) {1839SMLoc EndLoc;1840return parseExpression(Res, EndLoc);1841}18421843/// This function checks if the next token is <string> type or arithmetic.1844/// string that begin with character '<' must end with character '>'.1845/// otherwise it is arithmetics.1846/// If the function returns a 'true' value,1847/// the End argument will be filled with the last location pointed to the '>'1848/// character.1849static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {1850assert((StrLoc.getPointer() != nullptr) &&1851"Argument to the function cannot be a NULL value");1852const char *CharPtr = StrLoc.getPointer();1853while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') &&1854(*CharPtr != '\0')) {1855if (*CharPtr == '!')1856CharPtr++;1857CharPtr++;1858}1859if (*CharPtr == '>') {1860EndLoc = StrLoc.getFromPointer(CharPtr + 1);1861return true;1862}1863return false;1864}18651866/// creating a string without the escape characters '!'.1867static std::string angleBracketString(StringRef BracketContents) {1868std::string Res;1869for (size_t Pos = 0; Pos < BracketContents.size(); Pos++) {1870if (BracketContents[Pos] == '!')1871Pos++;1872Res += BracketContents[Pos];1873}1874return Res;1875}18761877/// Parse an expression and return it.1878///1879/// expr ::= expr &&,|| expr -> lowest.1880/// expr ::= expr |,^,&,! expr1881/// expr ::= expr ==,!=,<>,<,<=,>,>= expr1882/// expr ::= expr <<,>> expr1883/// expr ::= expr +,- expr1884/// expr ::= expr *,/,% expr -> highest.1885/// expr ::= primaryexpr1886///1887bool MasmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {1888// Parse the expression.1889Res = nullptr;1890if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||1891parseBinOpRHS(1, Res, EndLoc))1892return true;18931894// Try to constant fold it up front, if possible. Do not exploit1895// assembler here.1896int64_t Value;1897if (Res->evaluateAsAbsolute(Value))1898Res = MCConstantExpr::create(Value, getContext());18991900return false;1901}19021903bool MasmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {1904Res = nullptr;1905return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);1906}19071908bool MasmParser::parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,1909SMLoc &EndLoc) {1910if (parseParenExpr(Res, EndLoc))1911return true;19121913for (; ParenDepth > 0; --ParenDepth) {1914if (parseBinOpRHS(1, Res, EndLoc))1915return true;19161917// We don't Lex() the last RParen.1918// This is the same behavior as parseParenExpression().1919if (ParenDepth - 1 > 0) {1920EndLoc = getTok().getEndLoc();1921if (parseRParen())1922return true;1923}1924}1925return false;1926}19271928bool MasmParser::parseAbsoluteExpression(int64_t &Res) {1929const MCExpr *Expr;19301931SMLoc StartLoc = Lexer.getLoc();1932if (parseExpression(Expr))1933return true;19341935if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))1936return Error(StartLoc, "expected absolute expression");19371938return false;1939}19401941static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,1942MCBinaryExpr::Opcode &Kind,1943bool ShouldUseLogicalShr,1944bool EndExpressionAtGreater) {1945switch (K) {1946default:1947return 0; // not a binop.19481949// Lowest Precedence: &&, ||1950case AsmToken::AmpAmp:1951Kind = MCBinaryExpr::LAnd;1952return 2;1953case AsmToken::PipePipe:1954Kind = MCBinaryExpr::LOr;1955return 1;19561957// Low Precedence: ==, !=, <>, <, <=, >, >=1958case AsmToken::EqualEqual:1959Kind = MCBinaryExpr::EQ;1960return 3;1961case AsmToken::ExclaimEqual:1962case AsmToken::LessGreater:1963Kind = MCBinaryExpr::NE;1964return 3;1965case AsmToken::Less:1966Kind = MCBinaryExpr::LT;1967return 3;1968case AsmToken::LessEqual:1969Kind = MCBinaryExpr::LTE;1970return 3;1971case AsmToken::Greater:1972if (EndExpressionAtGreater)1973return 0;1974Kind = MCBinaryExpr::GT;1975return 3;1976case AsmToken::GreaterEqual:1977Kind = MCBinaryExpr::GTE;1978return 3;19791980// Low Intermediate Precedence: +, -1981case AsmToken::Plus:1982Kind = MCBinaryExpr::Add;1983return 4;1984case AsmToken::Minus:1985Kind = MCBinaryExpr::Sub;1986return 4;19871988// High Intermediate Precedence: |, &, ^1989case AsmToken::Pipe:1990Kind = MCBinaryExpr::Or;1991return 5;1992case AsmToken::Caret:1993Kind = MCBinaryExpr::Xor;1994return 5;1995case AsmToken::Amp:1996Kind = MCBinaryExpr::And;1997return 5;19981999// Highest Precedence: *, /, %, <<, >>2000case AsmToken::Star:2001Kind = MCBinaryExpr::Mul;2002return 6;2003case AsmToken::Slash:2004Kind = MCBinaryExpr::Div;2005return 6;2006case AsmToken::Percent:2007Kind = MCBinaryExpr::Mod;2008return 6;2009case AsmToken::LessLess:2010Kind = MCBinaryExpr::Shl;2011return 6;2012case AsmToken::GreaterGreater:2013if (EndExpressionAtGreater)2014return 0;2015Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;2016return 6;2017}2018}20192020unsigned MasmParser::getBinOpPrecedence(AsmToken::TokenKind K,2021MCBinaryExpr::Opcode &Kind) {2022bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();2023return getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr,2024AngleBracketDepth > 0);2025}20262027/// Parse all binary operators with precedence >= 'Precedence'.2028/// Res contains the LHS of the expression on input.2029bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,2030SMLoc &EndLoc) {2031SMLoc StartLoc = Lexer.getLoc();2032while (true) {2033AsmToken::TokenKind TokKind = Lexer.getKind();2034if (Lexer.getKind() == AsmToken::Identifier) {2035TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString())2036.CaseLower("and", AsmToken::Amp)2037.CaseLower("not", AsmToken::Exclaim)2038.CaseLower("or", AsmToken::Pipe)2039.CaseLower("xor", AsmToken::Caret)2040.CaseLower("shl", AsmToken::LessLess)2041.CaseLower("shr", AsmToken::GreaterGreater)2042.CaseLower("eq", AsmToken::EqualEqual)2043.CaseLower("ne", AsmToken::ExclaimEqual)2044.CaseLower("lt", AsmToken::Less)2045.CaseLower("le", AsmToken::LessEqual)2046.CaseLower("gt", AsmToken::Greater)2047.CaseLower("ge", AsmToken::GreaterEqual)2048.Default(TokKind);2049}2050MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;2051unsigned TokPrec = getBinOpPrecedence(TokKind, Kind);20522053// If the next token is lower precedence than we are allowed to eat, return2054// successfully with what we ate already.2055if (TokPrec < Precedence)2056return false;20572058Lex();20592060// Eat the next primary expression.2061const MCExpr *RHS;2062if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))2063return true;20642065// If BinOp binds less tightly with RHS than the operator after RHS, let2066// the pending operator take RHS as its LHS.2067MCBinaryExpr::Opcode Dummy;2068unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);2069if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))2070return true;20712072// Merge LHS and RHS according to operator.2073Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc);2074}2075}20762077/// ParseStatement:2078/// ::= % statement2079/// ::= EndOfStatement2080/// ::= Label* Directive ...Operands... EndOfStatement2081/// ::= Label* Identifier OperandList* EndOfStatement2082bool MasmParser::parseStatement(ParseStatementInfo &Info,2083MCAsmParserSemaCallback *SI) {2084assert(!hasPendingError() && "parseStatement started with pending error");2085// Eat initial spaces and comments.2086while (Lexer.is(AsmToken::Space))2087Lex();2088if (Lexer.is(AsmToken::EndOfStatement)) {2089// If this is a line comment we can drop it safely.2090if (getTok().getString().empty() || getTok().getString().front() == '\r' ||2091getTok().getString().front() == '\n')2092Out.addBlankLine();2093Lex();2094return false;2095}20962097// If preceded by an expansion operator, first expand all text macros and2098// macro functions.2099if (getTok().is(AsmToken::Percent)) {2100SMLoc ExpansionLoc = getTok().getLoc();2101if (parseToken(AsmToken::Percent) || expandStatement(ExpansionLoc))2102return true;2103}21042105// Statements always start with an identifier, unless we're dealing with a2106// processor directive (.386, .686, etc.) that lexes as a real.2107AsmToken ID = getTok();2108SMLoc IDLoc = ID.getLoc();2109StringRef IDVal;2110if (Lexer.is(AsmToken::HashDirective))2111return parseCppHashLineFilenameComment(IDLoc);2112if (Lexer.is(AsmToken::Dot)) {2113// Treat '.' as a valid identifier in this context.2114Lex();2115IDVal = ".";2116} else if (Lexer.is(AsmToken::Real)) {2117// Treat ".<number>" as a valid identifier in this context.2118IDVal = getTok().getString();2119Lex(); // always eat a token2120if (!IDVal.starts_with("."))2121return Error(IDLoc, "unexpected token at start of statement");2122} else if (parseIdentifier(IDVal, StartOfStatement)) {2123if (!TheCondState.Ignore) {2124Lex(); // always eat a token2125return Error(IDLoc, "unexpected token at start of statement");2126}2127IDVal = "";2128}21292130// Handle conditional assembly here before checking for skipping. We2131// have to do this so that .endif isn't skipped in a ".if 0" block for2132// example.2133StringMap<DirectiveKind>::const_iterator DirKindIt =2134DirectiveKindMap.find(IDVal.lower());2135DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())2136? DK_NO_DIRECTIVE2137: DirKindIt->getValue();2138switch (DirKind) {2139default:2140break;2141case DK_IF:2142case DK_IFE:2143return parseDirectiveIf(IDLoc, DirKind);2144case DK_IFB:2145return parseDirectiveIfb(IDLoc, true);2146case DK_IFNB:2147return parseDirectiveIfb(IDLoc, false);2148case DK_IFDEF:2149return parseDirectiveIfdef(IDLoc, true);2150case DK_IFNDEF:2151return parseDirectiveIfdef(IDLoc, false);2152case DK_IFDIF:2153return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,2154/*CaseInsensitive=*/false);2155case DK_IFDIFI:2156return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,2157/*CaseInsensitive=*/true);2158case DK_IFIDN:2159return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,2160/*CaseInsensitive=*/false);2161case DK_IFIDNI:2162return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,2163/*CaseInsensitive=*/true);2164case DK_ELSEIF:2165case DK_ELSEIFE:2166return parseDirectiveElseIf(IDLoc, DirKind);2167case DK_ELSEIFB:2168return parseDirectiveElseIfb(IDLoc, true);2169case DK_ELSEIFNB:2170return parseDirectiveElseIfb(IDLoc, false);2171case DK_ELSEIFDEF:2172return parseDirectiveElseIfdef(IDLoc, true);2173case DK_ELSEIFNDEF:2174return parseDirectiveElseIfdef(IDLoc, false);2175case DK_ELSEIFDIF:2176return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,2177/*CaseInsensitive=*/false);2178case DK_ELSEIFDIFI:2179return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,2180/*CaseInsensitive=*/true);2181case DK_ELSEIFIDN:2182return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,2183/*CaseInsensitive=*/false);2184case DK_ELSEIFIDNI:2185return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,2186/*CaseInsensitive=*/true);2187case DK_ELSE:2188return parseDirectiveElse(IDLoc);2189case DK_ENDIF:2190return parseDirectiveEndIf(IDLoc);2191}21922193// Ignore the statement if in the middle of inactive conditional2194// (e.g. ".if 0").2195if (TheCondState.Ignore) {2196eatToEndOfStatement();2197return false;2198}21992200// FIXME: Recurse on local labels?22012202// Check for a label.2203// ::= identifier ':'2204// ::= number ':'2205if (Lexer.is(AsmToken::Colon) && getTargetParser().isLabel(ID)) {2206if (checkForValidSection())2207return true;22082209// identifier ':' -> Label.2210Lex();22112212// Diagnose attempt to use '.' as a label.2213if (IDVal == ".")2214return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");22152216// Diagnose attempt to use a variable as a label.2217//2218// FIXME: Diagnostics. Note the location of the definition as a label.2219// FIXME: This doesn't diagnose assignment to a symbol which has been2220// implicitly marked as external.2221MCSymbol *Sym;2222if (ParsingMSInlineAsm && SI) {2223StringRef RewrittenLabel =2224SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);2225assert(!RewrittenLabel.empty() &&2226"We should have an internal name here.");2227Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),2228RewrittenLabel);2229IDVal = RewrittenLabel;2230}2231// Handle directional local labels2232if (IDVal == "@@") {2233Sym = Ctx.createDirectionalLocalSymbol(0);2234} else {2235Sym = getContext().getOrCreateSymbol(IDVal);2236}22372238// End of Labels should be treated as end of line for lexing2239// purposes but that information is not available to the Lexer who2240// does not understand Labels. This may cause us to see a Hash2241// here instead of a preprocessor line comment.2242if (getTok().is(AsmToken::Hash)) {2243std::string CommentStr = parseStringTo(AsmToken::EndOfStatement);2244Lexer.Lex();2245Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));2246}22472248// Consume any end of statement token, if present, to avoid spurious2249// addBlankLine calls().2250if (getTok().is(AsmToken::EndOfStatement)) {2251Lex();2252}22532254getTargetParser().doBeforeLabelEmit(Sym, IDLoc);22552256// Emit the label.2257if (!getTargetParser().isParsingMSInlineAsm())2258Out.emitLabel(Sym, IDLoc);22592260// If we are generating dwarf for assembly source files then gather the2261// info to make a dwarf label entry for this label if needed.2262if (enabledGenDwarfForAssembly())2263MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),2264IDLoc);22652266getTargetParser().onLabelParsed(Sym);22672268return false;2269}22702271// If macros are enabled, check to see if this is a macro instantiation.2272if (const MCAsmMacro *M = getContext().lookupMacro(IDVal.lower())) {2273return handleMacroEntry(M, IDLoc);2274}22752276// Otherwise, we have a normal instruction or directive.22772278if (DirKind != DK_NO_DIRECTIVE) {2279// There are several entities interested in parsing directives:2280//2281// 1. Asm parser extensions. For example, platform-specific parsers2282// (like the ELF parser) register themselves as extensions.2283// 2. The target-specific assembly parser. Some directives are target2284// specific or may potentially behave differently on certain targets.2285// 3. The generic directive parser implemented by this class. These are2286// all the directives that behave in a target and platform independent2287// manner, or at least have a default behavior that's shared between2288// all targets and platforms.22892290getTargetParser().flushPendingInstructions(getStreamer());22912292// Special-case handling of structure-end directives at higher priority,2293// since ENDS is overloaded as a segment-end directive.2294if (IDVal.equals_insensitive("ends") && StructInProgress.size() > 1 &&2295getTok().is(AsmToken::EndOfStatement)) {2296return parseDirectiveNestedEnds();2297}22982299// First, check the extension directive map to see if any extension has2300// registered itself to parse this directive.2301std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2302ExtensionDirectiveMap.lookup(IDVal.lower());2303if (Handler.first)2304return (*Handler.second)(Handler.first, IDVal, IDLoc);23052306// Next, let the target-specific assembly parser try.2307if (ID.isNot(AsmToken::Identifier))2308return false;23092310ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);2311assert(TPDirectiveReturn.isFailure() == hasPendingError() &&2312"Should only return Failure iff there was an error");2313if (TPDirectiveReturn.isFailure())2314return true;2315if (TPDirectiveReturn.isSuccess())2316return false;23172318// Finally, if no one else is interested in this directive, it must be2319// generic and familiar to this class.2320switch (DirKind) {2321default:2322break;2323case DK_ASCII:2324return parseDirectiveAscii(IDVal, false);2325case DK_ASCIZ:2326case DK_STRING:2327return parseDirectiveAscii(IDVal, true);2328case DK_BYTE:2329case DK_SBYTE:2330case DK_DB:2331return parseDirectiveValue(IDVal, 1);2332case DK_WORD:2333case DK_SWORD:2334case DK_DW:2335return parseDirectiveValue(IDVal, 2);2336case DK_DWORD:2337case DK_SDWORD:2338case DK_DD:2339return parseDirectiveValue(IDVal, 4);2340case DK_FWORD:2341case DK_DF:2342return parseDirectiveValue(IDVal, 6);2343case DK_QWORD:2344case DK_SQWORD:2345case DK_DQ:2346return parseDirectiveValue(IDVal, 8);2347case DK_REAL4:2348return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle(), 4);2349case DK_REAL8:2350return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble(), 8);2351case DK_REAL10:2352return parseDirectiveRealValue(IDVal, APFloat::x87DoubleExtended(), 10);2353case DK_STRUCT:2354case DK_UNION:2355return parseDirectiveNestedStruct(IDVal, DirKind);2356case DK_ENDS:2357return parseDirectiveNestedEnds();2358case DK_ALIGN:2359return parseDirectiveAlign();2360case DK_EVEN:2361return parseDirectiveEven();2362case DK_ORG:2363return parseDirectiveOrg();2364case DK_EXTERN:2365return parseDirectiveExtern();2366case DK_PUBLIC:2367return parseDirectiveSymbolAttribute(MCSA_Global);2368case DK_COMM:2369return parseDirectiveComm(/*IsLocal=*/false);2370case DK_COMMENT:2371return parseDirectiveComment(IDLoc);2372case DK_INCLUDE:2373return parseDirectiveInclude();2374case DK_REPEAT:2375return parseDirectiveRepeat(IDLoc, IDVal);2376case DK_WHILE:2377return parseDirectiveWhile(IDLoc);2378case DK_FOR:2379return parseDirectiveFor(IDLoc, IDVal);2380case DK_FORC:2381return parseDirectiveForc(IDLoc, IDVal);2382case DK_FILE:2383return parseDirectiveFile(IDLoc);2384case DK_LINE:2385return parseDirectiveLine();2386case DK_LOC:2387return parseDirectiveLoc();2388case DK_STABS:2389return parseDirectiveStabs();2390case DK_CV_FILE:2391return parseDirectiveCVFile();2392case DK_CV_FUNC_ID:2393return parseDirectiveCVFuncId();2394case DK_CV_INLINE_SITE_ID:2395return parseDirectiveCVInlineSiteId();2396case DK_CV_LOC:2397return parseDirectiveCVLoc();2398case DK_CV_LINETABLE:2399return parseDirectiveCVLinetable();2400case DK_CV_INLINE_LINETABLE:2401return parseDirectiveCVInlineLinetable();2402case DK_CV_DEF_RANGE:2403return parseDirectiveCVDefRange();2404case DK_CV_STRING:2405return parseDirectiveCVString();2406case DK_CV_STRINGTABLE:2407return parseDirectiveCVStringTable();2408case DK_CV_FILECHECKSUMS:2409return parseDirectiveCVFileChecksums();2410case DK_CV_FILECHECKSUM_OFFSET:2411return parseDirectiveCVFileChecksumOffset();2412case DK_CV_FPO_DATA:2413return parseDirectiveCVFPOData();2414case DK_CFI_SECTIONS:2415return parseDirectiveCFISections();2416case DK_CFI_STARTPROC:2417return parseDirectiveCFIStartProc();2418case DK_CFI_ENDPROC:2419return parseDirectiveCFIEndProc();2420case DK_CFI_DEF_CFA:2421return parseDirectiveCFIDefCfa(IDLoc);2422case DK_CFI_DEF_CFA_OFFSET:2423return parseDirectiveCFIDefCfaOffset(IDLoc);2424case DK_CFI_ADJUST_CFA_OFFSET:2425return parseDirectiveCFIAdjustCfaOffset(IDLoc);2426case DK_CFI_DEF_CFA_REGISTER:2427return parseDirectiveCFIDefCfaRegister(IDLoc);2428case DK_CFI_OFFSET:2429return parseDirectiveCFIOffset(IDLoc);2430case DK_CFI_REL_OFFSET:2431return parseDirectiveCFIRelOffset(IDLoc);2432case DK_CFI_PERSONALITY:2433return parseDirectiveCFIPersonalityOrLsda(true);2434case DK_CFI_LSDA:2435return parseDirectiveCFIPersonalityOrLsda(false);2436case DK_CFI_REMEMBER_STATE:2437return parseDirectiveCFIRememberState(IDLoc);2438case DK_CFI_RESTORE_STATE:2439return parseDirectiveCFIRestoreState(IDLoc);2440case DK_CFI_SAME_VALUE:2441return parseDirectiveCFISameValue(IDLoc);2442case DK_CFI_RESTORE:2443return parseDirectiveCFIRestore(IDLoc);2444case DK_CFI_ESCAPE:2445return parseDirectiveCFIEscape(IDLoc);2446case DK_CFI_RETURN_COLUMN:2447return parseDirectiveCFIReturnColumn(IDLoc);2448case DK_CFI_SIGNAL_FRAME:2449return parseDirectiveCFISignalFrame();2450case DK_CFI_UNDEFINED:2451return parseDirectiveCFIUndefined(IDLoc);2452case DK_CFI_REGISTER:2453return parseDirectiveCFIRegister(IDLoc);2454case DK_CFI_WINDOW_SAVE:2455return parseDirectiveCFIWindowSave(IDLoc);2456case DK_EXITM:2457Info.ExitValue = "";2458return parseDirectiveExitMacro(IDLoc, IDVal, *Info.ExitValue);2459case DK_ENDM:2460Info.ExitValue = "";2461return parseDirectiveEndMacro(IDVal);2462case DK_PURGE:2463return parseDirectivePurgeMacro(IDLoc);2464case DK_END:2465return parseDirectiveEnd(IDLoc);2466case DK_ERR:2467return parseDirectiveError(IDLoc);2468case DK_ERRB:2469return parseDirectiveErrorIfb(IDLoc, true);2470case DK_ERRNB:2471return parseDirectiveErrorIfb(IDLoc, false);2472case DK_ERRDEF:2473return parseDirectiveErrorIfdef(IDLoc, true);2474case DK_ERRNDEF:2475return parseDirectiveErrorIfdef(IDLoc, false);2476case DK_ERRDIF:2477return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2478/*CaseInsensitive=*/false);2479case DK_ERRDIFI:2480return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2481/*CaseInsensitive=*/true);2482case DK_ERRIDN:2483return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2484/*CaseInsensitive=*/false);2485case DK_ERRIDNI:2486return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2487/*CaseInsensitive=*/true);2488case DK_ERRE:2489return parseDirectiveErrorIfe(IDLoc, true);2490case DK_ERRNZ:2491return parseDirectiveErrorIfe(IDLoc, false);2492case DK_RADIX:2493return parseDirectiveRadix(IDLoc);2494case DK_ECHO:2495return parseDirectiveEcho(IDLoc);2496}24972498return Error(IDLoc, "unknown directive");2499}25002501// We also check if this is allocating memory with user-defined type.2502auto IDIt = Structs.find(IDVal.lower());2503if (IDIt != Structs.end())2504return parseDirectiveStructValue(/*Structure=*/IDIt->getValue(), IDVal,2505IDLoc);25062507// Non-conditional Microsoft directives sometimes follow their first argument.2508const AsmToken nextTok = getTok();2509const StringRef nextVal = nextTok.getString();2510const SMLoc nextLoc = nextTok.getLoc();25112512const AsmToken afterNextTok = peekTok();25132514// There are several entities interested in parsing infix directives:2515//2516// 1. Asm parser extensions. For example, platform-specific parsers2517// (like the ELF parser) register themselves as extensions.2518// 2. The generic directive parser implemented by this class. These are2519// all the directives that behave in a target and platform independent2520// manner, or at least have a default behavior that's shared between2521// all targets and platforms.25222523getTargetParser().flushPendingInstructions(getStreamer());25242525// Special-case handling of structure-end directives at higher priority, since2526// ENDS is overloaded as a segment-end directive.2527if (nextVal.equals_insensitive("ends") && StructInProgress.size() == 1) {2528Lex();2529return parseDirectiveEnds(IDVal, IDLoc);2530}25312532// First, check the extension directive map to see if any extension has2533// registered itself to parse this directive.2534std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2535ExtensionDirectiveMap.lookup(nextVal.lower());2536if (Handler.first) {2537Lex();2538Lexer.UnLex(ID);2539return (*Handler.second)(Handler.first, nextVal, nextLoc);2540}25412542// If no one else is interested in this directive, it must be2543// generic and familiar to this class.2544DirKindIt = DirectiveKindMap.find(nextVal.lower());2545DirKind = (DirKindIt == DirectiveKindMap.end())2546? DK_NO_DIRECTIVE2547: DirKindIt->getValue();2548switch (DirKind) {2549default:2550break;2551case DK_ASSIGN:2552case DK_EQU:2553case DK_TEXTEQU:2554Lex();2555return parseDirectiveEquate(nextVal, IDVal, DirKind, IDLoc);2556case DK_BYTE:2557if (afterNextTok.is(AsmToken::Identifier) &&2558afterNextTok.getString().equals_insensitive("ptr")) {2559// Size directive; part of an instruction.2560break;2561}2562[[fallthrough]];2563case DK_SBYTE:2564case DK_DB:2565Lex();2566return parseDirectiveNamedValue(nextVal, 1, IDVal, IDLoc);2567case DK_WORD:2568if (afterNextTok.is(AsmToken::Identifier) &&2569afterNextTok.getString().equals_insensitive("ptr")) {2570// Size directive; part of an instruction.2571break;2572}2573[[fallthrough]];2574case DK_SWORD:2575case DK_DW:2576Lex();2577return parseDirectiveNamedValue(nextVal, 2, IDVal, IDLoc);2578case DK_DWORD:2579if (afterNextTok.is(AsmToken::Identifier) &&2580afterNextTok.getString().equals_insensitive("ptr")) {2581// Size directive; part of an instruction.2582break;2583}2584[[fallthrough]];2585case DK_SDWORD:2586case DK_DD:2587Lex();2588return parseDirectiveNamedValue(nextVal, 4, IDVal, IDLoc);2589case DK_FWORD:2590if (afterNextTok.is(AsmToken::Identifier) &&2591afterNextTok.getString().equals_insensitive("ptr")) {2592// Size directive; part of an instruction.2593break;2594}2595[[fallthrough]];2596case DK_DF:2597Lex();2598return parseDirectiveNamedValue(nextVal, 6, IDVal, IDLoc);2599case DK_QWORD:2600if (afterNextTok.is(AsmToken::Identifier) &&2601afterNextTok.getString().equals_insensitive("ptr")) {2602// Size directive; part of an instruction.2603break;2604}2605[[fallthrough]];2606case DK_SQWORD:2607case DK_DQ:2608Lex();2609return parseDirectiveNamedValue(nextVal, 8, IDVal, IDLoc);2610case DK_REAL4:2611Lex();2612return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEsingle(), 4,2613IDVal, IDLoc);2614case DK_REAL8:2615Lex();2616return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEdouble(), 8,2617IDVal, IDLoc);2618case DK_REAL10:2619Lex();2620return parseDirectiveNamedRealValue(nextVal, APFloat::x87DoubleExtended(),262110, IDVal, IDLoc);2622case DK_STRUCT:2623case DK_UNION:2624Lex();2625return parseDirectiveStruct(nextVal, DirKind, IDVal, IDLoc);2626case DK_ENDS:2627Lex();2628return parseDirectiveEnds(IDVal, IDLoc);2629case DK_MACRO:2630Lex();2631return parseDirectiveMacro(IDVal, IDLoc);2632}26332634// Finally, we check if this is allocating a variable with user-defined type.2635auto NextIt = Structs.find(nextVal.lower());2636if (NextIt != Structs.end()) {2637Lex();2638return parseDirectiveNamedStructValue(/*Structure=*/NextIt->getValue(),2639nextVal, nextLoc, IDVal);2640}26412642// __asm _emit or __asm __emit2643if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||2644IDVal == "_EMIT" || IDVal == "__EMIT"))2645return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());26462647// __asm align2648if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))2649return parseDirectiveMSAlign(IDLoc, Info);26502651if (ParsingMSInlineAsm && (IDVal == "even" || IDVal == "EVEN"))2652Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);2653if (checkForValidSection())2654return true;26552656// Canonicalize the opcode to lower case.2657std::string OpcodeStr = IDVal.lower();2658ParseInstructionInfo IInfo(Info.AsmRewrites);2659bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID,2660Info.ParsedOperands);2661Info.ParseError = ParseHadError;26622663// Dump the parsed representation, if requested.2664if (getShowParsedOperands()) {2665SmallString<256> Str;2666raw_svector_ostream OS(Str);2667OS << "parsed instruction: [";2668for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {2669if (i != 0)2670OS << ", ";2671Info.ParsedOperands[i]->print(OS);2672}2673OS << "]";26742675printMessage(IDLoc, SourceMgr::DK_Note, OS.str());2676}26772678// Fail even if ParseInstruction erroneously returns false.2679if (hasPendingError() || ParseHadError)2680return true;26812682// If we are generating dwarf for the current section then generate a .loc2683// directive for the instruction.2684if (!ParseHadError && enabledGenDwarfForAssembly() &&2685getContext().getGenDwarfSectionSyms().count(2686getStreamer().getCurrentSectionOnly())) {2687unsigned Line;2688if (ActiveMacros.empty())2689Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer);2690else2691Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,2692ActiveMacros.front()->ExitBuffer);26932694// If we previously parsed a cpp hash file line comment then make sure the2695// current Dwarf File is for the CppHashFilename if not then emit the2696// Dwarf File table for it and adjust the line number for the .loc.2697if (!CppHashInfo.Filename.empty()) {2698unsigned FileNumber = getStreamer().emitDwarfFileDirective(26990, StringRef(), CppHashInfo.Filename);2700getContext().setGenDwarfFileNumber(FileNumber);27012702unsigned CppHashLocLineNo =2703SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf);2704Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo);2705}27062707getStreamer().emitDwarfLocDirective(2708getContext().getGenDwarfFileNumber(), Line, 0,2709DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0,2710StringRef());2711}27122713// If parsing succeeded, match the instruction.2714if (!ParseHadError) {2715uint64_t ErrorInfo;2716if (getTargetParser().MatchAndEmitInstruction(2717IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,2718getTargetParser().isParsingMSInlineAsm()))2719return true;2720}2721return false;2722}27232724// Parse and erase curly braces marking block start/end.2725bool MasmParser::parseCurlyBlockScope(2726SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {2727// Identify curly brace marking block start/end.2728if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))2729return false;27302731SMLoc StartLoc = Lexer.getLoc();2732Lex(); // Eat the brace.2733if (Lexer.is(AsmToken::EndOfStatement))2734Lex(); // Eat EndOfStatement following the brace.27352736// Erase the block start/end brace from the output asm string.2737AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -2738StartLoc.getPointer());2739return true;2740}27412742/// parseCppHashLineFilenameComment as this:2743/// ::= # number "filename"2744bool MasmParser::parseCppHashLineFilenameComment(SMLoc L) {2745Lex(); // Eat the hash token.2746// Lexer only ever emits HashDirective if it fully formed if it's2747// done the checking already so this is an internal error.2748assert(getTok().is(AsmToken::Integer) &&2749"Lexing Cpp line comment: Expected Integer");2750int64_t LineNumber = getTok().getIntVal();2751Lex();2752assert(getTok().is(AsmToken::String) &&2753"Lexing Cpp line comment: Expected String");2754StringRef Filename = getTok().getString();2755Lex();27562757// Get rid of the enclosing quotes.2758Filename = Filename.substr(1, Filename.size() - 2);27592760// Save the SMLoc, Filename and LineNumber for later use by diagnostics2761// and possibly DWARF file info.2762CppHashInfo.Loc = L;2763CppHashInfo.Filename = Filename;2764CppHashInfo.LineNumber = LineNumber;2765CppHashInfo.Buf = CurBuffer;2766if (FirstCppHashFilename.empty())2767FirstCppHashFilename = Filename;2768return false;2769}27702771/// will use the last parsed cpp hash line filename comment2772/// for the Filename and LineNo if any in the diagnostic.2773void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {2774const MasmParser *Parser = static_cast<const MasmParser *>(Context);2775raw_ostream &OS = errs();27762777const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();2778SMLoc DiagLoc = Diag.getLoc();2779unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2780unsigned CppHashBuf =2781Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);27822783// Like SourceMgr::printMessage() we need to print the include stack if any2784// before printing the message.2785unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2786if (!Parser->SavedDiagHandler && DiagCurBuffer &&2787DiagCurBuffer != DiagSrcMgr.getMainFileID()) {2788SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);2789DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);2790}27912792// If we have not parsed a cpp hash line filename comment or the source2793// manager changed or buffer changed (like in a nested include) then just2794// print the normal diagnostic using its Filename and LineNo.2795if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||2796DiagBuf != CppHashBuf) {2797if (Parser->SavedDiagHandler)2798Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);2799else2800Diag.print(nullptr, OS);2801return;2802}28032804// Use the CppHashFilename and calculate a line number based on the2805// CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc2806// for the diagnostic.2807const std::string &Filename = std::string(Parser->CppHashInfo.Filename);28082809int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);2810int CppHashLocLineNo =2811Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);2812int LineNo =2813Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);28142815SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,2816Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),2817Diag.getLineContents(), Diag.getRanges());28182819if (Parser->SavedDiagHandler)2820Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);2821else2822NewDiag.print(nullptr, OS);2823}28242825// This is similar to the IsIdentifierChar function in AsmLexer.cpp, but does2826// not accept '.'.2827static bool isMacroParameterChar(char C) {2828return isAlnum(C) || C == '_' || C == '$' || C == '@' || C == '?';2829}28302831bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,2832ArrayRef<MCAsmMacroParameter> Parameters,2833ArrayRef<MCAsmMacroArgument> A,2834const std::vector<std::string> &Locals, SMLoc L) {2835unsigned NParameters = Parameters.size();2836if (NParameters != A.size())2837return Error(L, "Wrong number of arguments");2838StringMap<std::string> LocalSymbols;2839std::string Name;2840Name.reserve(6);2841for (StringRef Local : Locals) {2842raw_string_ostream LocalName(Name);2843LocalName << "??"2844<< format_hex_no_prefix(LocalCounter++, 4, /*Upper=*/true);2845LocalSymbols.insert({Local, Name});2846Name.clear();2847}28482849std::optional<char> CurrentQuote;2850while (!Body.empty()) {2851// Scan for the next substitution.2852std::size_t End = Body.size(), Pos = 0;2853std::size_t IdentifierPos = End;2854for (; Pos != End; ++Pos) {2855// Find the next possible macro parameter, including preceding a '&'2856// inside quotes.2857if (Body[Pos] == '&')2858break;2859if (isMacroParameterChar(Body[Pos])) {2860if (!CurrentQuote)2861break;2862if (IdentifierPos == End)2863IdentifierPos = Pos;2864} else {2865IdentifierPos = End;2866}28672868// Track quotation status2869if (!CurrentQuote) {2870if (Body[Pos] == '\'' || Body[Pos] == '"')2871CurrentQuote = Body[Pos];2872} else if (Body[Pos] == CurrentQuote) {2873if (Pos + 1 != End && Body[Pos + 1] == CurrentQuote) {2874// Escaped quote, and quotes aren't identifier chars; skip2875++Pos;2876continue;2877} else {2878CurrentQuote.reset();2879}2880}2881}2882if (IdentifierPos != End) {2883// We've recognized an identifier before an apostrophe inside quotes;2884// check once to see if we can expand it.2885Pos = IdentifierPos;2886IdentifierPos = End;2887}28882889// Add the prefix.2890OS << Body.slice(0, Pos);28912892// Check if we reached the end.2893if (Pos == End)2894break;28952896unsigned I = Pos;2897bool InitialAmpersand = (Body[I] == '&');2898if (InitialAmpersand) {2899++I;2900++Pos;2901}2902while (I < End && isMacroParameterChar(Body[I]))2903++I;29042905const char *Begin = Body.data() + Pos;2906StringRef Argument(Begin, I - Pos);2907const std::string ArgumentLower = Argument.lower();2908unsigned Index = 0;29092910for (; Index < NParameters; ++Index)2911if (Parameters[Index].Name.equals_insensitive(ArgumentLower))2912break;29132914if (Index == NParameters) {2915if (InitialAmpersand)2916OS << '&';2917auto it = LocalSymbols.find(ArgumentLower);2918if (it != LocalSymbols.end())2919OS << it->second;2920else2921OS << Argument;2922Pos = I;2923} else {2924for (const AsmToken &Token : A[Index]) {2925// In MASM, you can write '%expr'.2926// The prefix '%' evaluates the expression 'expr'2927// and uses the result as a string (e.g. replace %(1+2) with the2928// string "3").2929// Here, we identify the integer token which is the result of the2930// absolute expression evaluation and replace it with its string2931// representation.2932if (Token.getString().front() == '%' && Token.is(AsmToken::Integer))2933// Emit an integer value to the buffer.2934OS << Token.getIntVal();2935else2936OS << Token.getString();2937}29382939Pos += Argument.size();2940if (Pos < End && Body[Pos] == '&') {2941++Pos;2942}2943}2944// Update the scan point.2945Body = Body.substr(Pos);2946}29472948return false;2949}29502951static bool isOperator(AsmToken::TokenKind kind) {2952switch (kind) {2953default:2954return false;2955case AsmToken::Plus:2956case AsmToken::Minus:2957case AsmToken::Tilde:2958case AsmToken::Slash:2959case AsmToken::Star:2960case AsmToken::Dot:2961case AsmToken::Equal:2962case AsmToken::EqualEqual:2963case AsmToken::Pipe:2964case AsmToken::PipePipe:2965case AsmToken::Caret:2966case AsmToken::Amp:2967case AsmToken::AmpAmp:2968case AsmToken::Exclaim:2969case AsmToken::ExclaimEqual:2970case AsmToken::Less:2971case AsmToken::LessEqual:2972case AsmToken::LessLess:2973case AsmToken::LessGreater:2974case AsmToken::Greater:2975case AsmToken::GreaterEqual:2976case AsmToken::GreaterGreater:2977return true;2978}2979}29802981namespace {29822983class AsmLexerSkipSpaceRAII {2984public:2985AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) {2986Lexer.setSkipSpace(SkipSpace);2987}29882989~AsmLexerSkipSpaceRAII() {2990Lexer.setSkipSpace(true);2991}29922993private:2994AsmLexer &Lexer;2995};29962997} // end anonymous namespace29982999bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP,3000MCAsmMacroArgument &MA,3001AsmToken::TokenKind EndTok) {3002if (MP && MP->Vararg) {3003if (Lexer.isNot(EndTok)) {3004SmallVector<StringRef, 1> Str = parseStringRefsTo(EndTok);3005for (StringRef S : Str) {3006MA.emplace_back(AsmToken::String, S);3007}3008}3009return false;3010}30113012SMLoc StrLoc = Lexer.getLoc(), EndLoc;3013if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) {3014const char *StrChar = StrLoc.getPointer() + 1;3015const char *EndChar = EndLoc.getPointer() - 1;3016jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());3017/// Eat from '<' to '>'.3018Lex();3019MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar));3020return false;3021}30223023unsigned ParenLevel = 0;30243025// Darwin doesn't use spaces to delmit arguments.3026AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);30273028bool SpaceEaten;30293030while (true) {3031SpaceEaten = false;3032if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))3033return TokError("unexpected token");30343035if (ParenLevel == 0) {3036if (Lexer.is(AsmToken::Comma))3037break;30383039if (Lexer.is(AsmToken::Space)) {3040SpaceEaten = true;3041Lex(); // Eat spaces.3042}30433044// Spaces can delimit parameters, but could also be part an expression.3045// If the token after a space is an operator, add the token and the next3046// one into this argument3047if (!IsDarwin) {3048if (isOperator(Lexer.getKind()) && Lexer.isNot(EndTok)) {3049MA.push_back(getTok());3050Lex();30513052// Whitespace after an operator can be ignored.3053if (Lexer.is(AsmToken::Space))3054Lex();30553056continue;3057}3058}3059if (SpaceEaten)3060break;3061}30623063// handleMacroEntry relies on not advancing the lexer here3064// to be able to fill in the remaining default parameter values3065if (Lexer.is(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0))3066break;30673068// Adjust the current parentheses level.3069if (Lexer.is(AsmToken::LParen))3070++ParenLevel;3071else if (Lexer.is(AsmToken::RParen) && ParenLevel)3072--ParenLevel;30733074// Append the token to the current argument list.3075MA.push_back(getTok());3076Lex();3077}30783079if (ParenLevel != 0)3080return TokError("unbalanced parentheses in argument");30813082if (MA.empty() && MP) {3083if (MP->Required) {3084return TokError("missing value for required parameter '" + MP->Name +3085"'");3086} else {3087MA = MP->Value;3088}3089}3090return false;3091}30923093// Parse the macro instantiation arguments.3094bool MasmParser::parseMacroArguments(const MCAsmMacro *M,3095MCAsmMacroArguments &A,3096AsmToken::TokenKind EndTok) {3097const unsigned NParameters = M ? M->Parameters.size() : 0;3098bool NamedParametersFound = false;3099SmallVector<SMLoc, 4> FALocs;31003101A.resize(NParameters);3102FALocs.resize(NParameters);31033104// Parse two kinds of macro invocations:3105// - macros defined without any parameters accept an arbitrary number of them3106// - macros defined with parameters accept at most that many of them3107for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;3108++Parameter) {3109SMLoc IDLoc = Lexer.getLoc();3110MCAsmMacroParameter FA;31113112if (Lexer.is(AsmToken::Identifier) && peekTok().is(AsmToken::Equal)) {3113if (parseIdentifier(FA.Name))3114return Error(IDLoc, "invalid argument identifier for formal argument");31153116if (Lexer.isNot(AsmToken::Equal))3117return TokError("expected '=' after formal parameter identifier");31183119Lex();31203121NamedParametersFound = true;3122}31233124if (NamedParametersFound && FA.Name.empty())3125return Error(IDLoc, "cannot mix positional and keyword arguments");31263127unsigned PI = Parameter;3128if (!FA.Name.empty()) {3129assert(M && "expected macro to be defined");3130unsigned FAI = 0;3131for (FAI = 0; FAI < NParameters; ++FAI)3132if (M->Parameters[FAI].Name == FA.Name)3133break;31343135if (FAI >= NParameters) {3136return Error(IDLoc, "parameter named '" + FA.Name +3137"' does not exist for macro '" + M->Name + "'");3138}3139PI = FAI;3140}3141const MCAsmMacroParameter *MP = nullptr;3142if (M && PI < NParameters)3143MP = &M->Parameters[PI];31443145SMLoc StrLoc = Lexer.getLoc();3146SMLoc EndLoc;3147if (Lexer.is(AsmToken::Percent)) {3148const MCExpr *AbsoluteExp;3149int64_t Value;3150/// Eat '%'.3151Lex();3152if (parseExpression(AbsoluteExp, EndLoc))3153return false;3154if (!AbsoluteExp->evaluateAsAbsolute(Value,3155getStreamer().getAssemblerPtr()))3156return Error(StrLoc, "expected absolute expression");3157const char *StrChar = StrLoc.getPointer();3158const char *EndChar = EndLoc.getPointer();3159AsmToken newToken(AsmToken::Integer,3160StringRef(StrChar, EndChar - StrChar), Value);3161FA.Value.push_back(newToken);3162} else if (parseMacroArgument(MP, FA.Value, EndTok)) {3163if (M)3164return addErrorSuffix(" in '" + M->Name + "' macro");3165else3166return true;3167}31683169if (!FA.Value.empty()) {3170if (A.size() <= PI)3171A.resize(PI + 1);3172A[PI] = FA.Value;31733174if (FALocs.size() <= PI)3175FALocs.resize(PI + 1);31763177FALocs[PI] = Lexer.getLoc();3178}31793180// At the end of the statement, fill in remaining arguments that have3181// default values. If there aren't any, then the next argument is3182// required but missing3183if (Lexer.is(EndTok)) {3184bool Failure = false;3185for (unsigned FAI = 0; FAI < NParameters; ++FAI) {3186if (A[FAI].empty()) {3187if (M->Parameters[FAI].Required) {3188Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),3189"missing value for required parameter "3190"'" +3191M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");3192Failure = true;3193}31943195if (!M->Parameters[FAI].Value.empty())3196A[FAI] = M->Parameters[FAI].Value;3197}3198}3199return Failure;3200}32013202if (Lexer.is(AsmToken::Comma))3203Lex();3204}32053206return TokError("too many positional arguments");3207}32083209bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,3210AsmToken::TokenKind ArgumentEndTok) {3211// Arbitrarily limit macro nesting depth (default matches 'as'). We can3212// eliminate this, although we should protect against infinite loops.3213unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;3214if (ActiveMacros.size() == MaxNestingDepth) {3215std::ostringstream MaxNestingDepthError;3216MaxNestingDepthError << "macros cannot be nested more than "3217<< MaxNestingDepth << " levels deep."3218<< " Use -asm-macro-max-nesting-depth to increase "3219"this limit.";3220return TokError(MaxNestingDepthError.str());3221}32223223MCAsmMacroArguments A;3224if (parseMacroArguments(M, A, ArgumentEndTok))3225return true;32263227// Macro instantiation is lexical, unfortunately. We construct a new buffer3228// to hold the macro body with substitutions.3229SmallString<256> Buf;3230StringRef Body = M->Body;3231raw_svector_ostream OS(Buf);32323233if (expandMacro(OS, Body, M->Parameters, A, M->Locals, getTok().getLoc()))3234return true;32353236// We include the endm in the buffer as our cue to exit the macro3237// instantiation.3238OS << "endm\n";32393240std::unique_ptr<MemoryBuffer> Instantiation =3241MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");32423243// Create the macro instantiation object and add to the current macro3244// instantiation stack.3245MacroInstantiation *MI = new MacroInstantiation{3246NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};3247ActiveMacros.push_back(MI);32483249++NumOfMacroInstantiations;32503251// Jump to the macro instantiation and prime the lexer.3252CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());3253Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());3254EndStatementAtEOFStack.push_back(true);3255Lex();32563257return false;3258}32593260void MasmParser::handleMacroExit() {3261// Jump to the token we should return to, and consume it.3262EndStatementAtEOFStack.pop_back();3263jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer,3264EndStatementAtEOFStack.back());3265Lex();32663267// Pop the instantiation entry.3268delete ActiveMacros.back();3269ActiveMacros.pop_back();3270}32713272bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) {3273if (!M->IsFunction)3274return Error(NameLoc, "cannot invoke macro procedure as function");32753276if (parseToken(AsmToken::LParen, "invoking macro function '" + M->Name +3277"' requires arguments in parentheses") ||3278handleMacroEntry(M, NameLoc, AsmToken::RParen))3279return true;32803281// Parse all statements in the macro, retrieving the exit value when it ends.3282std::string ExitValue;3283SmallVector<AsmRewrite, 4> AsmStrRewrites;3284while (Lexer.isNot(AsmToken::Eof)) {3285ParseStatementInfo Info(&AsmStrRewrites);3286bool Parsed = parseStatement(Info, nullptr);32873288if (!Parsed && Info.ExitValue) {3289ExitValue = std::move(*Info.ExitValue);3290break;3291}32923293// If we have a Lexer Error we are on an Error Token. Load in Lexer Error3294// for printing ErrMsg via Lex() only if no (presumably better) parser error3295// exists.3296if (Parsed && !hasPendingError() && Lexer.getTok().is(AsmToken::Error)) {3297Lex();3298}32993300// parseStatement returned true so may need to emit an error.3301printPendingErrors();33023303// Skipping to the next line if needed.3304if (Parsed && !getLexer().isAtStartOfStatement())3305eatToEndOfStatement();3306}33073308// Consume the right-parenthesis on the other side of the arguments.3309if (parseRParen())3310return true;33113312// Exit values may require lexing, unfortunately. We construct a new buffer to3313// hold the exit value.3314std::unique_ptr<MemoryBuffer> MacroValue =3315MemoryBuffer::getMemBufferCopy(ExitValue, "<macro-value>");33163317// Jump from this location to the instantiated exit value, and prime the3318// lexer.3319CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(MacroValue), Lexer.getLoc());3320Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,3321/*EndStatementAtEOF=*/false);3322EndStatementAtEOFStack.push_back(false);3323Lex();33243325return false;3326}33273328/// parseIdentifier:3329/// ::= identifier3330/// ::= string3331bool MasmParser::parseIdentifier(StringRef &Res,3332IdentifierPositionKind Position) {3333// The assembler has relaxed rules for accepting identifiers, in particular we3334// allow things like '.globl $foo' and '.def @feat.00', which would normally3335// be separate tokens. At this level, we have already lexed so we cannot3336// (currently) handle this as a context dependent token, instead we detect3337// adjacent tokens and return the combined identifier.3338if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {3339SMLoc PrefixLoc = getLexer().getLoc();33403341// Consume the prefix character, and check for a following identifier.33423343AsmToken nextTok = peekTok(false);33443345if (nextTok.isNot(AsmToken::Identifier))3346return true;33473348// We have a '$' or '@' followed by an identifier, make sure they are adjacent.3349if (PrefixLoc.getPointer() + 1 != nextTok.getLoc().getPointer())3350return true;33513352// eat $ or @3353Lexer.Lex(); // Lexer's Lex guarantees consecutive token.3354// Construct the joined identifier and consume the token.3355Res =3356StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);3357Lex(); // Parser Lex to maintain invariants.3358return false;3359}33603361if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))3362return true;33633364Res = getTok().getIdentifier();33653366// Consume the identifier token - but if parsing certain directives, avoid3367// lexical expansion of the next token.3368ExpandKind ExpandNextToken = ExpandMacros;3369if (Position == StartOfStatement &&3370StringSwitch<bool>(Res)3371.CaseLower("echo", true)3372.CasesLower("ifdef", "ifndef", "elseifdef", "elseifndef", true)3373.Default(false)) {3374ExpandNextToken = DoNotExpandMacros;3375}3376Lex(ExpandNextToken);33773378return false;3379}33803381/// parseDirectiveEquate:3382/// ::= name "=" expression3383/// | name "equ" expression (not redefinable)3384/// | name "equ" text-list3385/// | name "textequ" text-list (redefinability unspecified)3386bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,3387DirectiveKind DirKind, SMLoc NameLoc) {3388auto BuiltinIt = BuiltinSymbolMap.find(Name.lower());3389if (BuiltinIt != BuiltinSymbolMap.end())3390return Error(NameLoc, "cannot redefine a built-in symbol");33913392Variable &Var = Variables[Name.lower()];3393if (Var.Name.empty()) {3394Var.Name = Name;3395}33963397SMLoc StartLoc = Lexer.getLoc();3398if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {3399// "equ" and "textequ" both allow text expressions.3400std::string Value;3401std::string TextItem;3402if (!parseTextItem(TextItem)) {3403Value += TextItem;34043405// Accept a text-list, not just one text-item.3406auto parseItem = [&]() -> bool {3407if (parseTextItem(TextItem))3408return TokError("expected text item");3409Value += TextItem;3410return false;3411};3412if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))3413return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");34143415if (!Var.IsText || Var.TextValue != Value) {3416switch (Var.Redefinable) {3417case Variable::NOT_REDEFINABLE:3418return Error(getTok().getLoc(), "invalid variable redefinition");3419case Variable::WARN_ON_REDEFINITION:3420if (Warning(NameLoc, "redefining '" + Name +3421"', already defined on the command line")) {3422return true;3423}3424break;3425default:3426break;3427}3428}3429Var.IsText = true;3430Var.TextValue = Value;3431Var.Redefinable = Variable::REDEFINABLE;34323433return false;3434}3435}3436if (DirKind == DK_TEXTEQU)3437return TokError("expected <text> in '" + Twine(IDVal) + "' directive");34383439// Parse as expression assignment.3440const MCExpr *Expr;3441SMLoc EndLoc;3442if (parseExpression(Expr, EndLoc))3443return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3444StringRef ExprAsString = StringRef(3445StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());34463447int64_t Value;3448if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) {3449if (DirKind == DK_ASSIGN)3450return Error(3451StartLoc,3452"expected absolute expression; not all symbols have known values",3453{StartLoc, EndLoc});34543455// Not an absolute expression; define as a text replacement.3456if (!Var.IsText || Var.TextValue != ExprAsString) {3457switch (Var.Redefinable) {3458case Variable::NOT_REDEFINABLE:3459return Error(getTok().getLoc(), "invalid variable redefinition");3460case Variable::WARN_ON_REDEFINITION:3461if (Warning(NameLoc, "redefining '" + Name +3462"', already defined on the command line")) {3463return true;3464}3465break;3466default:3467break;3468}3469}34703471Var.IsText = true;3472Var.TextValue = ExprAsString.str();3473Var.Redefinable = Variable::REDEFINABLE;34743475return false;3476}34773478MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name);34793480const MCConstantExpr *PrevValue =3481Sym->isVariable() ? dyn_cast_or_null<MCConstantExpr>(3482Sym->getVariableValue(/*SetUsed=*/false))3483: nullptr;3484if (Var.IsText || !PrevValue || PrevValue->getValue() != Value) {3485switch (Var.Redefinable) {3486case Variable::NOT_REDEFINABLE:3487return Error(getTok().getLoc(), "invalid variable redefinition");3488case Variable::WARN_ON_REDEFINITION:3489if (Warning(NameLoc, "redefining '" + Name +3490"', already defined on the command line")) {3491return true;3492}3493break;3494default:3495break;3496}3497}34983499Var.IsText = false;3500Var.TextValue.clear();3501Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE3502: Variable::NOT_REDEFINABLE;35033504Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE);3505Sym->setVariableValue(Expr);3506Sym->setExternal(false);35073508return false;3509}35103511bool MasmParser::parseEscapedString(std::string &Data) {3512if (check(getTok().isNot(AsmToken::String), "expected string"))3513return true;35143515Data = "";3516char Quote = getTok().getString().front();3517StringRef Str = getTok().getStringContents();3518Data.reserve(Str.size());3519for (size_t i = 0, e = Str.size(); i != e; ++i) {3520Data.push_back(Str[i]);3521if (Str[i] == Quote) {3522// MASM treats doubled delimiting quotes as an escaped delimiting quote.3523// If we're escaping the string's trailing delimiter, we're definitely3524// missing a quotation mark.3525if (i + 1 == Str.size())3526return Error(getTok().getLoc(), "missing quotation mark in string");3527if (Str[i + 1] == Quote)3528++i;3529}3530}35313532Lex();3533return false;3534}35353536bool MasmParser::parseAngleBracketString(std::string &Data) {3537SMLoc EndLoc, StartLoc = getTok().getLoc();3538if (isAngleBracketString(StartLoc, EndLoc)) {3539const char *StartChar = StartLoc.getPointer() + 1;3540const char *EndChar = EndLoc.getPointer() - 1;3541jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());3542// Eat from '<' to '>'.3543Lex();35443545Data = angleBracketString(StringRef(StartChar, EndChar - StartChar));3546return false;3547}3548return true;3549}35503551/// textItem ::= textLiteral | textMacroID | % constExpr3552bool MasmParser::parseTextItem(std::string &Data) {3553switch (getTok().getKind()) {3554default:3555return true;3556case AsmToken::Percent: {3557int64_t Res;3558if (parseToken(AsmToken::Percent) || parseAbsoluteExpression(Res))3559return true;3560Data = std::to_string(Res);3561return false;3562}3563case AsmToken::Less:3564case AsmToken::LessEqual:3565case AsmToken::LessLess:3566case AsmToken::LessGreater:3567return parseAngleBracketString(Data);3568case AsmToken::Identifier: {3569// This must be a text macro; we need to expand it accordingly.3570StringRef ID;3571SMLoc StartLoc = getTok().getLoc();3572if (parseIdentifier(ID))3573return true;3574Data = ID.str();35753576bool Expanded = false;3577while (true) {3578// Try to resolve as a built-in text macro3579auto BuiltinIt = BuiltinSymbolMap.find(ID.lower());3580if (BuiltinIt != BuiltinSymbolMap.end()) {3581std::optional<std::string> BuiltinText =3582evaluateBuiltinTextMacro(BuiltinIt->getValue(), StartLoc);3583if (!BuiltinText) {3584// Not a text macro; break without substituting3585break;3586}3587Data = std::move(*BuiltinText);3588ID = StringRef(Data);3589Expanded = true;3590continue;3591}35923593// Try to resolve as a variable text macro3594auto VarIt = Variables.find(ID.lower());3595if (VarIt != Variables.end()) {3596const Variable &Var = VarIt->getValue();3597if (!Var.IsText) {3598// Not a text macro; break without substituting3599break;3600}3601Data = Var.TextValue;3602ID = StringRef(Data);3603Expanded = true;3604continue;3605}36063607break;3608}36093610if (!Expanded) {3611// Not a text macro; not usable in TextItem context. Since we haven't used3612// the token, put it back for better error recovery.3613getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));3614return true;3615}3616return false;3617}3618}3619llvm_unreachable("unhandled token kind");3620}36213622/// parseDirectiveAscii:3623/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]3624bool MasmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {3625auto parseOp = [&]() -> bool {3626std::string Data;3627if (checkForValidSection() || parseEscapedString(Data))3628return true;3629getStreamer().emitBytes(Data);3630if (ZeroTerminated)3631getStreamer().emitBytes(StringRef("\0", 1));3632return false;3633};36343635if (parseMany(parseOp))3636return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3637return false;3638}36393640bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) {3641// Special case constant expressions to match code generator.3642if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3643assert(Size <= 8 && "Invalid size");3644int64_t IntValue = MCE->getValue();3645if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))3646return Error(MCE->getLoc(), "out of range literal value");3647getStreamer().emitIntValue(IntValue, Size);3648} else {3649const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Value);3650if (MSE && MSE->getSymbol().getName() == "?") {3651// ? initializer; treat as 0.3652getStreamer().emitIntValue(0, Size);3653} else {3654getStreamer().emitValue(Value, Size, Value->getLoc());3655}3656}3657return false;3658}36593660bool MasmParser::parseScalarInitializer(unsigned Size,3661SmallVectorImpl<const MCExpr *> &Values,3662unsigned StringPadLength) {3663if (Size == 1 && getTok().is(AsmToken::String)) {3664std::string Value;3665if (parseEscapedString(Value))3666return true;3667// Treat each character as an initializer.3668for (const unsigned char CharVal : Value)3669Values.push_back(MCConstantExpr::create(CharVal, getContext()));36703671// Pad the string with spaces to the specified length.3672for (size_t i = Value.size(); i < StringPadLength; ++i)3673Values.push_back(MCConstantExpr::create(' ', getContext()));3674} else {3675const MCExpr *Value;3676if (parseExpression(Value))3677return true;3678if (getTok().is(AsmToken::Identifier) &&3679getTok().getString().equals_insensitive("dup")) {3680Lex(); // Eat 'dup'.3681const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3682if (!MCE)3683return Error(Value->getLoc(),3684"cannot repeat value a non-constant number of times");3685const int64_t Repetitions = MCE->getValue();3686if (Repetitions < 0)3687return Error(Value->getLoc(),3688"cannot repeat value a negative number of times");36893690SmallVector<const MCExpr *, 1> DuplicatedValues;3691if (parseToken(AsmToken::LParen,3692"parentheses required for 'dup' contents") ||3693parseScalarInstList(Size, DuplicatedValues) || parseRParen())3694return true;36953696for (int i = 0; i < Repetitions; ++i)3697Values.append(DuplicatedValues.begin(), DuplicatedValues.end());3698} else {3699Values.push_back(Value);3700}3701}3702return false;3703}37043705bool MasmParser::parseScalarInstList(unsigned Size,3706SmallVectorImpl<const MCExpr *> &Values,3707const AsmToken::TokenKind EndToken) {3708while (getTok().isNot(EndToken) &&3709(EndToken != AsmToken::Greater ||3710getTok().isNot(AsmToken::GreaterGreater))) {3711parseScalarInitializer(Size, Values);37123713// If we see a comma, continue, and allow line continuation.3714if (!parseOptionalToken(AsmToken::Comma))3715break;3716parseOptionalToken(AsmToken::EndOfStatement);3717}3718return false;3719}37203721bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) {3722SmallVector<const MCExpr *, 1> Values;3723if (checkForValidSection() || parseScalarInstList(Size, Values))3724return true;37253726for (const auto *Value : Values) {3727emitIntValue(Value, Size);3728}3729if (Count)3730*Count = Values.size();3731return false;3732}37333734// Add a field to the current structure.3735bool MasmParser::addIntegralField(StringRef Name, unsigned Size) {3736StructInfo &Struct = StructInProgress.back();3737FieldInfo &Field = Struct.addField(Name, FT_INTEGRAL, Size);3738IntFieldInfo &IntInfo = Field.Contents.IntInfo;37393740Field.Type = Size;37413742if (parseScalarInstList(Size, IntInfo.Values))3743return true;37443745Field.SizeOf = Field.Type * IntInfo.Values.size();3746Field.LengthOf = IntInfo.Values.size();3747const unsigned FieldEnd = Field.Offset + Field.SizeOf;3748if (!Struct.IsUnion) {3749Struct.NextOffset = FieldEnd;3750}3751Struct.Size = std::max(Struct.Size, FieldEnd);3752return false;3753}37543755/// parseDirectiveValue3756/// ::= (byte | word | ... ) [ expression (, expression)* ]3757bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {3758if (StructInProgress.empty()) {3759// Initialize data value.3760if (emitIntegralValues(Size))3761return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3762} else if (addIntegralField("", Size)) {3763return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3764}37653766return false;3767}37683769/// parseDirectiveNamedValue3770/// ::= name (byte | word | ... ) [ expression (, expression)* ]3771bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size,3772StringRef Name, SMLoc NameLoc) {3773if (StructInProgress.empty()) {3774// Initialize named data value.3775MCSymbol *Sym = getContext().getOrCreateSymbol(Name);3776getStreamer().emitLabel(Sym);3777unsigned Count;3778if (emitIntegralValues(Size, &Count))3779return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");37803781AsmTypeInfo Type;3782Type.Name = TypeName;3783Type.Size = Size * Count;3784Type.ElementSize = Size;3785Type.Length = Count;3786KnownType[Name.lower()] = Type;3787} else if (addIntegralField(Name, Size)) {3788return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");3789}37903791return false;3792}37933794static bool parseHexOcta(MasmParser &Asm, uint64_t &hi, uint64_t &lo) {3795if (Asm.getTok().isNot(AsmToken::Integer) &&3796Asm.getTok().isNot(AsmToken::BigNum))3797return Asm.TokError("unknown token in expression");3798SMLoc ExprLoc = Asm.getTok().getLoc();3799APInt IntValue = Asm.getTok().getAPIntVal();3800Asm.Lex();3801if (!IntValue.isIntN(128))3802return Asm.Error(ExprLoc, "out of range literal value");3803if (!IntValue.isIntN(64)) {3804hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue();3805lo = IntValue.getLoBits(64).getZExtValue();3806} else {3807hi = 0;3808lo = IntValue.getZExtValue();3809}3810return false;3811}38123813bool MasmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {3814// We don't truly support arithmetic on floating point expressions, so we3815// have to manually parse unary prefixes.3816bool IsNeg = false;3817SMLoc SignLoc;3818if (getLexer().is(AsmToken::Minus)) {3819SignLoc = getLexer().getLoc();3820Lexer.Lex();3821IsNeg = true;3822} else if (getLexer().is(AsmToken::Plus)) {3823SignLoc = getLexer().getLoc();3824Lexer.Lex();3825}38263827if (Lexer.is(AsmToken::Error))3828return TokError(Lexer.getErr());3829if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&3830Lexer.isNot(AsmToken::Identifier))3831return TokError("unexpected token in directive");38323833// Convert to an APFloat.3834APFloat Value(Semantics);3835StringRef IDVal = getTok().getString();3836if (getLexer().is(AsmToken::Identifier)) {3837if (IDVal.equals_insensitive("infinity") || IDVal.equals_insensitive("inf"))3838Value = APFloat::getInf(Semantics);3839else if (IDVal.equals_insensitive("nan"))3840Value = APFloat::getNaN(Semantics, false, ~0);3841else if (IDVal.equals_insensitive("?"))3842Value = APFloat::getZero(Semantics);3843else3844return TokError("invalid floating point literal");3845} else if (IDVal.consume_back("r") || IDVal.consume_back("R")) {3846// MASM hexadecimal floating-point literal; no APFloat conversion needed.3847// To match ML64.exe, ignore the initial sign.3848unsigned SizeInBits = Value.getSizeInBits(Semantics);3849if (SizeInBits != (IDVal.size() << 2))3850return TokError("invalid floating point literal");38513852// Consume the numeric token.3853Lex();38543855Res = APInt(SizeInBits, IDVal, 16);3856if (SignLoc.isValid())3857return Warning(SignLoc, "MASM-style hex floats ignore explicit sign");3858return false;3859} else if (errorToBool(3860Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven)3861.takeError())) {3862return TokError("invalid floating point literal");3863}3864if (IsNeg)3865Value.changeSign();38663867// Consume the numeric token.3868Lex();38693870Res = Value.bitcastToAPInt();38713872return false;3873}38743875bool MasmParser::parseRealInstList(const fltSemantics &Semantics,3876SmallVectorImpl<APInt> &ValuesAsInt,3877const AsmToken::TokenKind EndToken) {3878while (getTok().isNot(EndToken) ||3879(EndToken == AsmToken::Greater &&3880getTok().isNot(AsmToken::GreaterGreater))) {3881const AsmToken NextTok = peekTok();3882if (NextTok.is(AsmToken::Identifier) &&3883NextTok.getString().equals_insensitive("dup")) {3884const MCExpr *Value;3885if (parseExpression(Value) || parseToken(AsmToken::Identifier))3886return true;3887const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3888if (!MCE)3889return Error(Value->getLoc(),3890"cannot repeat value a non-constant number of times");3891const int64_t Repetitions = MCE->getValue();3892if (Repetitions < 0)3893return Error(Value->getLoc(),3894"cannot repeat value a negative number of times");38953896SmallVector<APInt, 1> DuplicatedValues;3897if (parseToken(AsmToken::LParen,3898"parentheses required for 'dup' contents") ||3899parseRealInstList(Semantics, DuplicatedValues) || parseRParen())3900return true;39013902for (int i = 0; i < Repetitions; ++i)3903ValuesAsInt.append(DuplicatedValues.begin(), DuplicatedValues.end());3904} else {3905APInt AsInt;3906if (parseRealValue(Semantics, AsInt))3907return true;3908ValuesAsInt.push_back(AsInt);3909}39103911// Continue if we see a comma. (Also, allow line continuation.)3912if (!parseOptionalToken(AsmToken::Comma))3913break;3914parseOptionalToken(AsmToken::EndOfStatement);3915}39163917return false;3918}39193920// Initialize real data values.3921bool MasmParser::emitRealValues(const fltSemantics &Semantics,3922unsigned *Count) {3923if (checkForValidSection())3924return true;39253926SmallVector<APInt, 1> ValuesAsInt;3927if (parseRealInstList(Semantics, ValuesAsInt))3928return true;39293930for (const APInt &AsInt : ValuesAsInt) {3931getStreamer().emitIntValue(AsInt);3932}3933if (Count)3934*Count = ValuesAsInt.size();3935return false;3936}39373938// Add a real field to the current struct.3939bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics,3940size_t Size) {3941StructInfo &Struct = StructInProgress.back();3942FieldInfo &Field = Struct.addField(Name, FT_REAL, Size);3943RealFieldInfo &RealInfo = Field.Contents.RealInfo;39443945Field.SizeOf = 0;39463947if (parseRealInstList(Semantics, RealInfo.AsIntValues))3948return true;39493950Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8;3951Field.LengthOf = RealInfo.AsIntValues.size();3952Field.SizeOf = Field.Type * Field.LengthOf;39533954const unsigned FieldEnd = Field.Offset + Field.SizeOf;3955if (!Struct.IsUnion) {3956Struct.NextOffset = FieldEnd;3957}3958Struct.Size = std::max(Struct.Size, FieldEnd);3959return false;3960}39613962/// parseDirectiveRealValue3963/// ::= (real4 | real8 | real10) [ expression (, expression)* ]3964bool MasmParser::parseDirectiveRealValue(StringRef IDVal,3965const fltSemantics &Semantics,3966size_t Size) {3967if (StructInProgress.empty()) {3968// Initialize data value.3969if (emitRealValues(Semantics))3970return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3971} else if (addRealField("", Semantics, Size)) {3972return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3973}3974return false;3975}39763977/// parseDirectiveNamedRealValue3978/// ::= name (real4 | real8 | real10) [ expression (, expression)* ]3979bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName,3980const fltSemantics &Semantics,3981unsigned Size, StringRef Name,3982SMLoc NameLoc) {3983if (StructInProgress.empty()) {3984// Initialize named data value.3985MCSymbol *Sym = getContext().getOrCreateSymbol(Name);3986getStreamer().emitLabel(Sym);3987unsigned Count;3988if (emitRealValues(Semantics, &Count))3989return addErrorSuffix(" in '" + TypeName + "' directive");39903991AsmTypeInfo Type;3992Type.Name = TypeName;3993Type.Size = Size * Count;3994Type.ElementSize = Size;3995Type.Length = Count;3996KnownType[Name.lower()] = Type;3997} else if (addRealField(Name, Semantics, Size)) {3998return addErrorSuffix(" in '" + TypeName + "' directive");3999}4000return false;4001}40024003bool MasmParser::parseOptionalAngleBracketOpen() {4004const AsmToken Tok = getTok();4005if (parseOptionalToken(AsmToken::LessLess)) {4006AngleBracketDepth++;4007Lexer.UnLex(AsmToken(AsmToken::Less, Tok.getString().substr(1)));4008return true;4009} else if (parseOptionalToken(AsmToken::LessGreater)) {4010AngleBracketDepth++;4011Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));4012return true;4013} else if (parseOptionalToken(AsmToken::Less)) {4014AngleBracketDepth++;4015return true;4016}40174018return false;4019}40204021bool MasmParser::parseAngleBracketClose(const Twine &Msg) {4022const AsmToken Tok = getTok();4023if (parseOptionalToken(AsmToken::GreaterGreater)) {4024Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));4025} else if (parseToken(AsmToken::Greater, Msg)) {4026return true;4027}4028AngleBracketDepth--;4029return false;4030}40314032bool MasmParser::parseFieldInitializer(const FieldInfo &Field,4033const IntFieldInfo &Contents,4034FieldInitializer &Initializer) {4035SMLoc Loc = getTok().getLoc();40364037SmallVector<const MCExpr *, 1> Values;4038if (parseOptionalToken(AsmToken::LCurly)) {4039if (Field.LengthOf == 1 && Field.Type > 1)4040return Error(Loc, "Cannot initialize scalar field with array value");4041if (parseScalarInstList(Field.Type, Values, AsmToken::RCurly) ||4042parseToken(AsmToken::RCurly))4043return true;4044} else if (parseOptionalAngleBracketOpen()) {4045if (Field.LengthOf == 1 && Field.Type > 1)4046return Error(Loc, "Cannot initialize scalar field with array value");4047if (parseScalarInstList(Field.Type, Values, AsmToken::Greater) ||4048parseAngleBracketClose())4049return true;4050} else if (Field.LengthOf > 1 && Field.Type > 1) {4051return Error(Loc, "Cannot initialize array field with scalar value");4052} else if (parseScalarInitializer(Field.Type, Values,4053/*StringPadLength=*/Field.LengthOf)) {4054return true;4055}40564057if (Values.size() > Field.LengthOf) {4058return Error(Loc, "Initializer too long for field; expected at most " +4059std::to_string(Field.LengthOf) + " elements, got " +4060std::to_string(Values.size()));4061}4062// Default-initialize all remaining values.4063Values.append(Contents.Values.begin() + Values.size(), Contents.Values.end());40644065Initializer = FieldInitializer(std::move(Values));4066return false;4067}40684069bool MasmParser::parseFieldInitializer(const FieldInfo &Field,4070const RealFieldInfo &Contents,4071FieldInitializer &Initializer) {4072const fltSemantics *Semantics;4073switch (Field.Type) {4074case 4:4075Semantics = &APFloat::IEEEsingle();4076break;4077case 8:4078Semantics = &APFloat::IEEEdouble();4079break;4080case 10:4081Semantics = &APFloat::x87DoubleExtended();4082break;4083default:4084llvm_unreachable("unknown real field type");4085}40864087SMLoc Loc = getTok().getLoc();40884089SmallVector<APInt, 1> AsIntValues;4090if (parseOptionalToken(AsmToken::LCurly)) {4091if (Field.LengthOf == 1)4092return Error(Loc, "Cannot initialize scalar field with array value");4093if (parseRealInstList(*Semantics, AsIntValues, AsmToken::RCurly) ||4094parseToken(AsmToken::RCurly))4095return true;4096} else if (parseOptionalAngleBracketOpen()) {4097if (Field.LengthOf == 1)4098return Error(Loc, "Cannot initialize scalar field with array value");4099if (parseRealInstList(*Semantics, AsIntValues, AsmToken::Greater) ||4100parseAngleBracketClose())4101return true;4102} else if (Field.LengthOf > 1) {4103return Error(Loc, "Cannot initialize array field with scalar value");4104} else {4105AsIntValues.emplace_back();4106if (parseRealValue(*Semantics, AsIntValues.back()))4107return true;4108}41094110if (AsIntValues.size() > Field.LengthOf) {4111return Error(Loc, "Initializer too long for field; expected at most " +4112std::to_string(Field.LengthOf) + " elements, got " +4113std::to_string(AsIntValues.size()));4114}4115// Default-initialize all remaining values.4116AsIntValues.append(Contents.AsIntValues.begin() + AsIntValues.size(),4117Contents.AsIntValues.end());41184119Initializer = FieldInitializer(std::move(AsIntValues));4120return false;4121}41224123bool MasmParser::parseFieldInitializer(const FieldInfo &Field,4124const StructFieldInfo &Contents,4125FieldInitializer &Initializer) {4126SMLoc Loc = getTok().getLoc();41274128std::vector<StructInitializer> Initializers;4129if (Field.LengthOf > 1) {4130if (parseOptionalToken(AsmToken::LCurly)) {4131if (parseStructInstList(Contents.Structure, Initializers,4132AsmToken::RCurly) ||4133parseToken(AsmToken::RCurly))4134return true;4135} else if (parseOptionalAngleBracketOpen()) {4136if (parseStructInstList(Contents.Structure, Initializers,4137AsmToken::Greater) ||4138parseAngleBracketClose())4139return true;4140} else {4141return Error(Loc, "Cannot initialize array field with scalar value");4142}4143} else {4144Initializers.emplace_back();4145if (parseStructInitializer(Contents.Structure, Initializers.back()))4146return true;4147}41484149if (Initializers.size() > Field.LengthOf) {4150return Error(Loc, "Initializer too long for field; expected at most " +4151std::to_string(Field.LengthOf) + " elements, got " +4152std::to_string(Initializers.size()));4153}4154// Default-initialize all remaining values.4155Initializers.insert(Initializers.end(),4156Contents.Initializers.begin() + Initializers.size(),4157Contents.Initializers.end());41584159Initializer = FieldInitializer(std::move(Initializers), Contents.Structure);4160return false;4161}41624163bool MasmParser::parseFieldInitializer(const FieldInfo &Field,4164FieldInitializer &Initializer) {4165switch (Field.Contents.FT) {4166case FT_INTEGRAL:4167return parseFieldInitializer(Field, Field.Contents.IntInfo, Initializer);4168case FT_REAL:4169return parseFieldInitializer(Field, Field.Contents.RealInfo, Initializer);4170case FT_STRUCT:4171return parseFieldInitializer(Field, Field.Contents.StructInfo, Initializer);4172}4173llvm_unreachable("Unhandled FieldType enum");4174}41754176bool MasmParser::parseStructInitializer(const StructInfo &Structure,4177StructInitializer &Initializer) {4178const AsmToken FirstToken = getTok();41794180std::optional<AsmToken::TokenKind> EndToken;4181if (parseOptionalToken(AsmToken::LCurly)) {4182EndToken = AsmToken::RCurly;4183} else if (parseOptionalAngleBracketOpen()) {4184EndToken = AsmToken::Greater;4185AngleBracketDepth++;4186} else if (FirstToken.is(AsmToken::Identifier) &&4187FirstToken.getString() == "?") {4188// ? initializer; leave EndToken uninitialized to treat as empty.4189if (parseToken(AsmToken::Identifier))4190return true;4191} else {4192return Error(FirstToken.getLoc(), "Expected struct initializer");4193}41944195auto &FieldInitializers = Initializer.FieldInitializers;4196size_t FieldIndex = 0;4197if (EndToken) {4198// Initialize all fields with given initializers.4199while (getTok().isNot(*EndToken) && FieldIndex < Structure.Fields.size()) {4200const FieldInfo &Field = Structure.Fields[FieldIndex++];4201if (parseOptionalToken(AsmToken::Comma)) {4202// Empty initializer; use the default and continue. (Also, allow line4203// continuation.)4204FieldInitializers.push_back(Field.Contents);4205parseOptionalToken(AsmToken::EndOfStatement);4206continue;4207}4208FieldInitializers.emplace_back(Field.Contents.FT);4209if (parseFieldInitializer(Field, FieldInitializers.back()))4210return true;42114212// Continue if we see a comma. (Also, allow line continuation.)4213SMLoc CommaLoc = getTok().getLoc();4214if (!parseOptionalToken(AsmToken::Comma))4215break;4216if (FieldIndex == Structure.Fields.size())4217return Error(CommaLoc, "'" + Structure.Name +4218"' initializer initializes too many fields");4219parseOptionalToken(AsmToken::EndOfStatement);4220}4221}4222// Default-initialize all remaining fields.4223for (const FieldInfo &Field : llvm::drop_begin(Structure.Fields, FieldIndex))4224FieldInitializers.push_back(Field.Contents);42254226if (EndToken) {4227if (*EndToken == AsmToken::Greater)4228return parseAngleBracketClose();42294230return parseToken(*EndToken);4231}42324233return false;4234}42354236bool MasmParser::parseStructInstList(4237const StructInfo &Structure, std::vector<StructInitializer> &Initializers,4238const AsmToken::TokenKind EndToken) {4239while (getTok().isNot(EndToken) ||4240(EndToken == AsmToken::Greater &&4241getTok().isNot(AsmToken::GreaterGreater))) {4242const AsmToken NextTok = peekTok();4243if (NextTok.is(AsmToken::Identifier) &&4244NextTok.getString().equals_insensitive("dup")) {4245const MCExpr *Value;4246if (parseExpression(Value) || parseToken(AsmToken::Identifier))4247return true;4248const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);4249if (!MCE)4250return Error(Value->getLoc(),4251"cannot repeat value a non-constant number of times");4252const int64_t Repetitions = MCE->getValue();4253if (Repetitions < 0)4254return Error(Value->getLoc(),4255"cannot repeat value a negative number of times");42564257std::vector<StructInitializer> DuplicatedValues;4258if (parseToken(AsmToken::LParen,4259"parentheses required for 'dup' contents") ||4260parseStructInstList(Structure, DuplicatedValues) || parseRParen())4261return true;42624263for (int i = 0; i < Repetitions; ++i)4264llvm::append_range(Initializers, DuplicatedValues);4265} else {4266Initializers.emplace_back();4267if (parseStructInitializer(Structure, Initializers.back()))4268return true;4269}42704271// Continue if we see a comma. (Also, allow line continuation.)4272if (!parseOptionalToken(AsmToken::Comma))4273break;4274parseOptionalToken(AsmToken::EndOfStatement);4275}42764277return false;4278}42794280bool MasmParser::emitFieldValue(const FieldInfo &Field,4281const IntFieldInfo &Contents) {4282// Default-initialize all values.4283for (const MCExpr *Value : Contents.Values) {4284if (emitIntValue(Value, Field.Type))4285return true;4286}4287return false;4288}42894290bool MasmParser::emitFieldValue(const FieldInfo &Field,4291const RealFieldInfo &Contents) {4292for (const APInt &AsInt : Contents.AsIntValues) {4293getStreamer().emitIntValue(AsInt.getLimitedValue(),4294AsInt.getBitWidth() / 8);4295}4296return false;4297}42984299bool MasmParser::emitFieldValue(const FieldInfo &Field,4300const StructFieldInfo &Contents) {4301for (const auto &Initializer : Contents.Initializers) {4302size_t Index = 0, Offset = 0;4303for (const auto &SubField : Contents.Structure.Fields) {4304getStreamer().emitZeros(SubField.Offset - Offset);4305Offset = SubField.Offset + SubField.SizeOf;4306emitFieldInitializer(SubField, Initializer.FieldInitializers[Index++]);4307}4308}4309return false;4310}43114312bool MasmParser::emitFieldValue(const FieldInfo &Field) {4313switch (Field.Contents.FT) {4314case FT_INTEGRAL:4315return emitFieldValue(Field, Field.Contents.IntInfo);4316case FT_REAL:4317return emitFieldValue(Field, Field.Contents.RealInfo);4318case FT_STRUCT:4319return emitFieldValue(Field, Field.Contents.StructInfo);4320}4321llvm_unreachable("Unhandled FieldType enum");4322}43234324bool MasmParser::emitFieldInitializer(const FieldInfo &Field,4325const IntFieldInfo &Contents,4326const IntFieldInfo &Initializer) {4327for (const auto &Value : Initializer.Values) {4328if (emitIntValue(Value, Field.Type))4329return true;4330}4331// Default-initialize all remaining values.4332for (const auto &Value :4333llvm::drop_begin(Contents.Values, Initializer.Values.size())) {4334if (emitIntValue(Value, Field.Type))4335return true;4336}4337return false;4338}43394340bool MasmParser::emitFieldInitializer(const FieldInfo &Field,4341const RealFieldInfo &Contents,4342const RealFieldInfo &Initializer) {4343for (const auto &AsInt : Initializer.AsIntValues) {4344getStreamer().emitIntValue(AsInt.getLimitedValue(),4345AsInt.getBitWidth() / 8);4346}4347// Default-initialize all remaining values.4348for (const auto &AsInt :4349llvm::drop_begin(Contents.AsIntValues, Initializer.AsIntValues.size())) {4350getStreamer().emitIntValue(AsInt.getLimitedValue(),4351AsInt.getBitWidth() / 8);4352}4353return false;4354}43554356bool MasmParser::emitFieldInitializer(const FieldInfo &Field,4357const StructFieldInfo &Contents,4358const StructFieldInfo &Initializer) {4359for (const auto &Init : Initializer.Initializers) {4360if (emitStructInitializer(Contents.Structure, Init))4361return true;4362}4363// Default-initialize all remaining values.4364for (const auto &Init : llvm::drop_begin(Contents.Initializers,4365Initializer.Initializers.size())) {4366if (emitStructInitializer(Contents.Structure, Init))4367return true;4368}4369return false;4370}43714372bool MasmParser::emitFieldInitializer(const FieldInfo &Field,4373const FieldInitializer &Initializer) {4374switch (Field.Contents.FT) {4375case FT_INTEGRAL:4376return emitFieldInitializer(Field, Field.Contents.IntInfo,4377Initializer.IntInfo);4378case FT_REAL:4379return emitFieldInitializer(Field, Field.Contents.RealInfo,4380Initializer.RealInfo);4381case FT_STRUCT:4382return emitFieldInitializer(Field, Field.Contents.StructInfo,4383Initializer.StructInfo);4384}4385llvm_unreachable("Unhandled FieldType enum");4386}43874388bool MasmParser::emitStructInitializer(const StructInfo &Structure,4389const StructInitializer &Initializer) {4390if (!Structure.Initializable)4391return Error(getLexer().getLoc(),4392"cannot initialize a value of type '" + Structure.Name +4393"'; 'org' was used in the type's declaration");4394size_t Index = 0, Offset = 0;4395for (const auto &Init : Initializer.FieldInitializers) {4396const auto &Field = Structure.Fields[Index++];4397getStreamer().emitZeros(Field.Offset - Offset);4398Offset = Field.Offset + Field.SizeOf;4399if (emitFieldInitializer(Field, Init))4400return true;4401}4402// Default-initialize all remaining fields.4403for (const auto &Field : llvm::drop_begin(4404Structure.Fields, Initializer.FieldInitializers.size())) {4405getStreamer().emitZeros(Field.Offset - Offset);4406Offset = Field.Offset + Field.SizeOf;4407if (emitFieldValue(Field))4408return true;4409}4410// Add final padding.4411if (Offset != Structure.Size)4412getStreamer().emitZeros(Structure.Size - Offset);4413return false;4414}44154416// Set data values from initializers.4417bool MasmParser::emitStructValues(const StructInfo &Structure,4418unsigned *Count) {4419std::vector<StructInitializer> Initializers;4420if (parseStructInstList(Structure, Initializers))4421return true;44224423for (const auto &Initializer : Initializers) {4424if (emitStructInitializer(Structure, Initializer))4425return true;4426}44274428if (Count)4429*Count = Initializers.size();4430return false;4431}44324433// Declare a field in the current struct.4434bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) {4435StructInfo &OwningStruct = StructInProgress.back();4436FieldInfo &Field =4437OwningStruct.addField(Name, FT_STRUCT, Structure.AlignmentSize);4438StructFieldInfo &StructInfo = Field.Contents.StructInfo;44394440StructInfo.Structure = Structure;4441Field.Type = Structure.Size;44424443if (parseStructInstList(Structure, StructInfo.Initializers))4444return true;44454446Field.LengthOf = StructInfo.Initializers.size();4447Field.SizeOf = Field.Type * Field.LengthOf;44484449const unsigned FieldEnd = Field.Offset + Field.SizeOf;4450if (!OwningStruct.IsUnion) {4451OwningStruct.NextOffset = FieldEnd;4452}4453OwningStruct.Size = std::max(OwningStruct.Size, FieldEnd);44544455return false;4456}44574458/// parseDirectiveStructValue4459/// ::= struct-id (<struct-initializer> | {struct-initializer})4460/// [, (<struct-initializer> | {struct-initializer})]*4461bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure,4462StringRef Directive, SMLoc DirLoc) {4463if (StructInProgress.empty()) {4464if (emitStructValues(Structure))4465return true;4466} else if (addStructField("", Structure)) {4467return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4468}44694470return false;4471}44724473/// parseDirectiveNamedValue4474/// ::= name (byte | word | ... ) [ expression (, expression)* ]4475bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure,4476StringRef Directive,4477SMLoc DirLoc, StringRef Name) {4478if (StructInProgress.empty()) {4479// Initialize named data value.4480MCSymbol *Sym = getContext().getOrCreateSymbol(Name);4481getStreamer().emitLabel(Sym);4482unsigned Count;4483if (emitStructValues(Structure, &Count))4484return true;4485AsmTypeInfo Type;4486Type.Name = Structure.Name;4487Type.Size = Structure.Size * Count;4488Type.ElementSize = Structure.Size;4489Type.Length = Count;4490KnownType[Name.lower()] = Type;4491} else if (addStructField(Name, Structure)) {4492return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4493}44944495return false;4496}44974498/// parseDirectiveStruct4499/// ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE]4500/// (dataDir | generalDir | offsetDir | nestedStruct)+4501/// <name> ENDS4502////// dataDir = data declaration4503////// offsetDir = EVEN, ORG, ALIGN4504bool MasmParser::parseDirectiveStruct(StringRef Directive,4505DirectiveKind DirKind, StringRef Name,4506SMLoc NameLoc) {4507// We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS4508// anyway, so all field accesses must be qualified.4509AsmToken NextTok = getTok();4510int64_t AlignmentValue = 1;4511if (NextTok.isNot(AsmToken::Comma) &&4512NextTok.isNot(AsmToken::EndOfStatement) &&4513parseAbsoluteExpression(AlignmentValue)) {4514return addErrorSuffix(" in alignment value for '" + Twine(Directive) +4515"' directive");4516}4517if (!isPowerOf2_64(AlignmentValue)) {4518return Error(NextTok.getLoc(), "alignment must be a power of two; was " +4519std::to_string(AlignmentValue));4520}45214522StringRef Qualifier;4523SMLoc QualifierLoc;4524if (parseOptionalToken(AsmToken::Comma)) {4525QualifierLoc = getTok().getLoc();4526if (parseIdentifier(Qualifier))4527return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4528if (!Qualifier.equals_insensitive("nonunique"))4529return Error(QualifierLoc, "Unrecognized qualifier for '" +4530Twine(Directive) +4531"' directive; expected none or NONUNIQUE");4532}45334534if (parseEOL())4535return addErrorSuffix(" in '" + Twine(Directive) + "' directive");45364537StructInProgress.emplace_back(Name, DirKind == DK_UNION, AlignmentValue);4538return false;4539}45404541/// parseDirectiveNestedStruct4542/// ::= (STRUC | STRUCT | UNION) [name]4543/// (dataDir | generalDir | offsetDir | nestedStruct)+4544/// ENDS4545bool MasmParser::parseDirectiveNestedStruct(StringRef Directive,4546DirectiveKind DirKind) {4547if (StructInProgress.empty())4548return TokError("missing name in top-level '" + Twine(Directive) +4549"' directive");45504551StringRef Name;4552if (getTok().is(AsmToken::Identifier)) {4553Name = getTok().getIdentifier();4554parseToken(AsmToken::Identifier);4555}4556if (parseEOL())4557return addErrorSuffix(" in '" + Twine(Directive) + "' directive");45584559// Reserve space to ensure Alignment doesn't get invalidated when4560// StructInProgress grows.4561StructInProgress.reserve(StructInProgress.size() + 1);4562StructInProgress.emplace_back(Name, DirKind == DK_UNION,4563StructInProgress.back().Alignment);4564return false;4565}45664567bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) {4568if (StructInProgress.empty())4569return Error(NameLoc, "ENDS directive without matching STRUC/STRUCT/UNION");4570if (StructInProgress.size() > 1)4571return Error(NameLoc, "unexpected name in nested ENDS directive");4572if (StructInProgress.back().Name.compare_insensitive(Name))4573return Error(NameLoc, "mismatched name in ENDS directive; expected '" +4574StructInProgress.back().Name + "'");4575StructInfo Structure = StructInProgress.pop_back_val();4576// Pad to make the structure's size divisible by the smaller of its alignment4577// and the size of its largest field.4578Structure.Size = llvm::alignTo(4579Structure.Size, std::min(Structure.Alignment, Structure.AlignmentSize));4580Structs[Name.lower()] = Structure;45814582if (parseEOL())4583return addErrorSuffix(" in ENDS directive");45844585return false;4586}45874588bool MasmParser::parseDirectiveNestedEnds() {4589if (StructInProgress.empty())4590return TokError("ENDS directive without matching STRUC/STRUCT/UNION");4591if (StructInProgress.size() == 1)4592return TokError("missing name in top-level ENDS directive");45934594if (parseEOL())4595return addErrorSuffix(" in nested ENDS directive");45964597StructInfo Structure = StructInProgress.pop_back_val();4598// Pad to make the structure's size divisible by its alignment.4599Structure.Size = llvm::alignTo(Structure.Size, Structure.Alignment);46004601StructInfo &ParentStruct = StructInProgress.back();4602if (Structure.Name.empty()) {4603// Anonymous substructures' fields are addressed as if they belong to the4604// parent structure - so we transfer them to the parent here.4605const size_t OldFields = ParentStruct.Fields.size();4606ParentStruct.Fields.insert(4607ParentStruct.Fields.end(),4608std::make_move_iterator(Structure.Fields.begin()),4609std::make_move_iterator(Structure.Fields.end()));4610for (const auto &FieldByName : Structure.FieldsByName) {4611ParentStruct.FieldsByName[FieldByName.getKey()] =4612FieldByName.getValue() + OldFields;4613}46144615unsigned FirstFieldOffset = 0;4616if (!Structure.Fields.empty() && !ParentStruct.IsUnion) {4617FirstFieldOffset = llvm::alignTo(4618ParentStruct.NextOffset,4619std::min(ParentStruct.Alignment, Structure.AlignmentSize));4620}46214622if (ParentStruct.IsUnion) {4623ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size);4624} else {4625for (auto &Field : llvm::drop_begin(ParentStruct.Fields, OldFields))4626Field.Offset += FirstFieldOffset;46274628const unsigned StructureEnd = FirstFieldOffset + Structure.Size;4629if (!ParentStruct.IsUnion) {4630ParentStruct.NextOffset = StructureEnd;4631}4632ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);4633}4634} else {4635FieldInfo &Field = ParentStruct.addField(Structure.Name, FT_STRUCT,4636Structure.AlignmentSize);4637StructFieldInfo &StructInfo = Field.Contents.StructInfo;4638Field.Type = Structure.Size;4639Field.LengthOf = 1;4640Field.SizeOf = Structure.Size;46414642const unsigned StructureEnd = Field.Offset + Field.SizeOf;4643if (!ParentStruct.IsUnion) {4644ParentStruct.NextOffset = StructureEnd;4645}4646ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);46474648StructInfo.Structure = Structure;4649StructInfo.Initializers.emplace_back();4650auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers;4651for (const auto &SubField : Structure.Fields) {4652FieldInitializers.push_back(SubField.Contents);4653}4654}46554656return false;4657}46584659/// parseDirectiveOrg4660/// ::= org expression4661bool MasmParser::parseDirectiveOrg() {4662const MCExpr *Offset;4663SMLoc OffsetLoc = Lexer.getLoc();4664if (checkForValidSection() || parseExpression(Offset))4665return true;4666if (parseEOL())4667return addErrorSuffix(" in 'org' directive");46684669if (StructInProgress.empty()) {4670// Not in a struct; change the offset for the next instruction or data4671if (checkForValidSection())4672return addErrorSuffix(" in 'org' directive");46734674getStreamer().emitValueToOffset(Offset, 0, OffsetLoc);4675} else {4676// Offset the next field of this struct4677StructInfo &Structure = StructInProgress.back();4678int64_t OffsetRes;4679if (!Offset->evaluateAsAbsolute(OffsetRes, getStreamer().getAssemblerPtr()))4680return Error(OffsetLoc,4681"expected absolute expression in 'org' directive");4682if (OffsetRes < 0)4683return Error(4684OffsetLoc,4685"expected non-negative value in struct's 'org' directive; was " +4686std::to_string(OffsetRes));4687Structure.NextOffset = static_cast<unsigned>(OffsetRes);46884689// ORG-affected structures cannot be initialized4690Structure.Initializable = false;4691}46924693return false;4694}46954696bool MasmParser::emitAlignTo(int64_t Alignment) {4697if (StructInProgress.empty()) {4698// Not in a struct; align the next instruction or data4699if (checkForValidSection())4700return true;47014702// Check whether we should use optimal code alignment for this align4703// directive.4704const MCSection *Section = getStreamer().getCurrentSectionOnly();4705assert(Section && "must have section to emit alignment");4706if (Section->useCodeAlign()) {4707getStreamer().emitCodeAlignment(Align(Alignment),4708&getTargetParser().getSTI(),4709/*MaxBytesToEmit=*/0);4710} else {4711// FIXME: Target specific behavior about how the "extra" bytes are filled.4712getStreamer().emitValueToAlignment(Align(Alignment), /*Value=*/0,4713/*ValueSize=*/1,4714/*MaxBytesToEmit=*/0);4715}4716} else {4717// Align the next field of this struct4718StructInfo &Structure = StructInProgress.back();4719Structure.NextOffset = llvm::alignTo(Structure.NextOffset, Alignment);4720}47214722return false;4723}47244725/// parseDirectiveAlign4726/// ::= align expression4727bool MasmParser::parseDirectiveAlign() {4728SMLoc AlignmentLoc = getLexer().getLoc();4729int64_t Alignment;47304731// Ignore empty 'align' directives.4732if (getTok().is(AsmToken::EndOfStatement)) {4733return Warning(AlignmentLoc,4734"align directive with no operand is ignored") &&4735parseEOL();4736}4737if (parseAbsoluteExpression(Alignment) || parseEOL())4738return addErrorSuffix(" in align directive");47394740// Always emit an alignment here even if we throw an error.4741bool ReturnVal = false;47424743// Reject alignments that aren't either a power of two or zero, for ML.exe4744// compatibility. Alignment of zero is silently rounded up to one.4745if (Alignment == 0)4746Alignment = 1;4747if (!isPowerOf2_64(Alignment))4748ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2; was " +4749std::to_string(Alignment));47504751if (emitAlignTo(Alignment))4752ReturnVal |= addErrorSuffix(" in align directive");47534754return ReturnVal;4755}47564757/// parseDirectiveEven4758/// ::= even4759bool MasmParser::parseDirectiveEven() {4760if (parseEOL() || emitAlignTo(2))4761return addErrorSuffix(" in even directive");47624763return false;4764}47654766/// parseDirectiveFile4767/// ::= .file filename4768/// ::= .file number [directory] filename [md5 checksum] [source source-text]4769bool MasmParser::parseDirectiveFile(SMLoc DirectiveLoc) {4770// FIXME: I'm not sure what this is.4771int64_t FileNumber = -1;4772if (getLexer().is(AsmToken::Integer)) {4773FileNumber = getTok().getIntVal();4774Lex();47754776if (FileNumber < 0)4777return TokError("negative file number");4778}47794780std::string Path;47814782// Usually the directory and filename together, otherwise just the directory.4783// Allow the strings to have escaped octal character sequence.4784if (check(getTok().isNot(AsmToken::String),4785"unexpected token in '.file' directive") ||4786parseEscapedString(Path))4787return true;47884789StringRef Directory;4790StringRef Filename;4791std::string FilenameData;4792if (getLexer().is(AsmToken::String)) {4793if (check(FileNumber == -1,4794"explicit path specified, but no file number") ||4795parseEscapedString(FilenameData))4796return true;4797Filename = FilenameData;4798Directory = Path;4799} else {4800Filename = Path;4801}48024803uint64_t MD5Hi, MD5Lo;4804bool HasMD5 = false;48054806std::optional<StringRef> Source;4807bool HasSource = false;4808std::string SourceString;48094810while (!parseOptionalToken(AsmToken::EndOfStatement)) {4811StringRef Keyword;4812if (check(getTok().isNot(AsmToken::Identifier),4813"unexpected token in '.file' directive") ||4814parseIdentifier(Keyword))4815return true;4816if (Keyword == "md5") {4817HasMD5 = true;4818if (check(FileNumber == -1,4819"MD5 checksum specified, but no file number") ||4820parseHexOcta(*this, MD5Hi, MD5Lo))4821return true;4822} else if (Keyword == "source") {4823HasSource = true;4824if (check(FileNumber == -1,4825"source specified, but no file number") ||4826check(getTok().isNot(AsmToken::String),4827"unexpected token in '.file' directive") ||4828parseEscapedString(SourceString))4829return true;4830} else {4831return TokError("unexpected token in '.file' directive");4832}4833}48344835if (FileNumber == -1) {4836// Ignore the directive if there is no number and the target doesn't support4837// numberless .file directives. This allows some portability of assembler4838// between different object file formats.4839if (getContext().getAsmInfo()->hasSingleParameterDotFile())4840getStreamer().emitFileDirective(Filename);4841} else {4842// In case there is a -g option as well as debug info from directive .file,4843// we turn off the -g option, directly use the existing debug info instead.4844// Throw away any implicit file table for the assembler source.4845if (Ctx.getGenDwarfForAssembly()) {4846Ctx.getMCDwarfLineTable(0).resetFileTable();4847Ctx.setGenDwarfForAssembly(false);4848}48494850std::optional<MD5::MD5Result> CKMem;4851if (HasMD5) {4852MD5::MD5Result Sum;4853for (unsigned i = 0; i != 8; ++i) {4854Sum[i] = uint8_t(MD5Hi >> ((7 - i) * 8));4855Sum[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8));4856}4857CKMem = Sum;4858}4859if (HasSource) {4860char *SourceBuf = static_cast<char *>(Ctx.allocate(SourceString.size()));4861memcpy(SourceBuf, SourceString.data(), SourceString.size());4862Source = StringRef(SourceBuf, SourceString.size());4863}4864if (FileNumber == 0) {4865if (Ctx.getDwarfVersion() < 5)4866return Warning(DirectiveLoc, "file 0 not supported prior to DWARF-5");4867getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source);4868} else {4869Expected<unsigned> FileNumOrErr = getStreamer().tryEmitDwarfFileDirective(4870FileNumber, Directory, Filename, CKMem, Source);4871if (!FileNumOrErr)4872return Error(DirectiveLoc, toString(FileNumOrErr.takeError()));4873}4874// Alert the user if there are some .file directives with MD5 and some not.4875// But only do that once.4876if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) {4877ReportedInconsistentMD5 = true;4878return Warning(DirectiveLoc, "inconsistent use of MD5 checksums");4879}4880}48814882return false;4883}48844885/// parseDirectiveLine4886/// ::= .line [number]4887bool MasmParser::parseDirectiveLine() {4888int64_t LineNumber;4889if (getLexer().is(AsmToken::Integer)) {4890if (parseIntToken(LineNumber, "unexpected token in '.line' directive"))4891return true;4892(void)LineNumber;4893// FIXME: Do something with the .line.4894}4895if (parseEOL())4896return true;48974898return false;4899}49004901/// parseDirectiveLoc4902/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end]4903/// [epilogue_begin] [is_stmt VALUE] [isa VALUE]4904/// The first number is a file number, must have been previously assigned with4905/// a .file directive, the second number is the line number and optionally the4906/// third number is a column position (zero if not specified). The remaining4907/// optional items are .loc sub-directives.4908bool MasmParser::parseDirectiveLoc() {4909int64_t FileNumber = 0, LineNumber = 0;4910SMLoc Loc = getTok().getLoc();4911if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") ||4912check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc,4913"file number less than one in '.loc' directive") ||4914check(!getContext().isValidDwarfFileNumber(FileNumber), Loc,4915"unassigned file number in '.loc' directive"))4916return true;49174918// optional4919if (getLexer().is(AsmToken::Integer)) {4920LineNumber = getTok().getIntVal();4921if (LineNumber < 0)4922return TokError("line number less than zero in '.loc' directive");4923Lex();4924}49254926int64_t ColumnPos = 0;4927if (getLexer().is(AsmToken::Integer)) {4928ColumnPos = getTok().getIntVal();4929if (ColumnPos < 0)4930return TokError("column position less than zero in '.loc' directive");4931Lex();4932}49334934auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags();4935unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT;4936unsigned Isa = 0;4937int64_t Discriminator = 0;49384939auto parseLocOp = [&]() -> bool {4940StringRef Name;4941SMLoc Loc = getTok().getLoc();4942if (parseIdentifier(Name))4943return TokError("unexpected token in '.loc' directive");49444945if (Name == "basic_block")4946Flags |= DWARF2_FLAG_BASIC_BLOCK;4947else if (Name == "prologue_end")4948Flags |= DWARF2_FLAG_PROLOGUE_END;4949else if (Name == "epilogue_begin")4950Flags |= DWARF2_FLAG_EPILOGUE_BEGIN;4951else if (Name == "is_stmt") {4952Loc = getTok().getLoc();4953const MCExpr *Value;4954if (parseExpression(Value))4955return true;4956// The expression must be the constant 0 or 1.4957if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {4958int Value = MCE->getValue();4959if (Value == 0)4960Flags &= ~DWARF2_FLAG_IS_STMT;4961else if (Value == 1)4962Flags |= DWARF2_FLAG_IS_STMT;4963else4964return Error(Loc, "is_stmt value not 0 or 1");4965} else {4966return Error(Loc, "is_stmt value not the constant value of 0 or 1");4967}4968} else if (Name == "isa") {4969Loc = getTok().getLoc();4970const MCExpr *Value;4971if (parseExpression(Value))4972return true;4973// The expression must be a constant greater or equal to 0.4974if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {4975int Value = MCE->getValue();4976if (Value < 0)4977return Error(Loc, "isa number less than zero");4978Isa = Value;4979} else {4980return Error(Loc, "isa number not a constant value");4981}4982} else if (Name == "discriminator") {4983if (parseAbsoluteExpression(Discriminator))4984return true;4985} else {4986return Error(Loc, "unknown sub-directive in '.loc' directive");4987}4988return false;4989};49904991if (parseMany(parseLocOp, false /*hasComma*/))4992return true;49934994getStreamer().emitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags,4995Isa, Discriminator, StringRef());49964997return false;4998}49995000/// parseDirectiveStabs5001/// ::= .stabs string, number, number, number5002bool MasmParser::parseDirectiveStabs() {5003return TokError("unsupported directive '.stabs'");5004}50055006/// parseDirectiveCVFile5007/// ::= .cv_file number filename [checksum] [checksumkind]5008bool MasmParser::parseDirectiveCVFile() {5009SMLoc FileNumberLoc = getTok().getLoc();5010int64_t FileNumber;5011std::string Filename;5012std::string Checksum;5013int64_t ChecksumKind = 0;50145015if (parseIntToken(FileNumber,5016"expected file number in '.cv_file' directive") ||5017check(FileNumber < 1, FileNumberLoc, "file number less than one") ||5018check(getTok().isNot(AsmToken::String),5019"unexpected token in '.cv_file' directive") ||5020parseEscapedString(Filename))5021return true;5022if (!parseOptionalToken(AsmToken::EndOfStatement)) {5023if (check(getTok().isNot(AsmToken::String),5024"unexpected token in '.cv_file' directive") ||5025parseEscapedString(Checksum) ||5026parseIntToken(ChecksumKind,5027"expected checksum kind in '.cv_file' directive") ||5028parseEOL())5029return true;5030}50315032Checksum = fromHex(Checksum);5033void *CKMem = Ctx.allocate(Checksum.size(), 1);5034memcpy(CKMem, Checksum.data(), Checksum.size());5035ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem),5036Checksum.size());50375038if (!getStreamer().emitCVFileDirective(FileNumber, Filename, ChecksumAsBytes,5039static_cast<uint8_t>(ChecksumKind)))5040return Error(FileNumberLoc, "file number already allocated");50415042return false;5043}50445045bool MasmParser::parseCVFunctionId(int64_t &FunctionId,5046StringRef DirectiveName) {5047SMLoc Loc;5048return parseTokenLoc(Loc) ||5049parseIntToken(FunctionId, "expected function id in '" + DirectiveName +5050"' directive") ||5051check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,5052"expected function id within range [0, UINT_MAX)");5053}50545055bool MasmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {5056SMLoc Loc;5057return parseTokenLoc(Loc) ||5058parseIntToken(FileNumber, "expected integer in '" + DirectiveName +5059"' directive") ||5060check(FileNumber < 1, Loc, "file number less than one in '" +5061DirectiveName + "' directive") ||5062check(!getCVContext().isValidFileNumber(FileNumber), Loc,5063"unassigned file number in '" + DirectiveName + "' directive");5064}50655066/// parseDirectiveCVFuncId5067/// ::= .cv_func_id FunctionId5068///5069/// Introduces a function ID that can be used with .cv_loc.5070bool MasmParser::parseDirectiveCVFuncId() {5071SMLoc FunctionIdLoc = getTok().getLoc();5072int64_t FunctionId;50735074if (parseCVFunctionId(FunctionId, ".cv_func_id") || parseEOL())5075return true;50765077if (!getStreamer().emitCVFuncIdDirective(FunctionId))5078return Error(FunctionIdLoc, "function id already allocated");50795080return false;5081}50825083/// parseDirectiveCVInlineSiteId5084/// ::= .cv_inline_site_id FunctionId5085/// "within" IAFunc5086/// "inlined_at" IAFile IALine [IACol]5087///5088/// Introduces a function ID that can be used with .cv_loc. Includes "inlined5089/// at" source location information for use in the line table of the caller,5090/// whether the caller is a real function or another inlined call site.5091bool MasmParser::parseDirectiveCVInlineSiteId() {5092SMLoc FunctionIdLoc = getTok().getLoc();5093int64_t FunctionId;5094int64_t IAFunc;5095int64_t IAFile;5096int64_t IALine;5097int64_t IACol = 0;50985099// FunctionId5100if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))5101return true;51025103// "within"5104if (check((getLexer().isNot(AsmToken::Identifier) ||5105getTok().getIdentifier() != "within"),5106"expected 'within' identifier in '.cv_inline_site_id' directive"))5107return true;5108Lex();51095110// IAFunc5111if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))5112return true;51135114// "inlined_at"5115if (check((getLexer().isNot(AsmToken::Identifier) ||5116getTok().getIdentifier() != "inlined_at"),5117"expected 'inlined_at' identifier in '.cv_inline_site_id' "5118"directive") )5119return true;5120Lex();51215122// IAFile IALine5123if (parseCVFileId(IAFile, ".cv_inline_site_id") ||5124parseIntToken(IALine, "expected line number after 'inlined_at'"))5125return true;51265127// [IACol]5128if (getLexer().is(AsmToken::Integer)) {5129IACol = getTok().getIntVal();5130Lex();5131}51325133if (parseEOL())5134return true;51355136if (!getStreamer().emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,5137IALine, IACol, FunctionIdLoc))5138return Error(FunctionIdLoc, "function id already allocated");51395140return false;5141}51425143/// parseDirectiveCVLoc5144/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]5145/// [is_stmt VALUE]5146/// The first number is a file number, must have been previously assigned with5147/// a .file directive, the second number is the line number and optionally the5148/// third number is a column position (zero if not specified). The remaining5149/// optional items are .loc sub-directives.5150bool MasmParser::parseDirectiveCVLoc() {5151SMLoc DirectiveLoc = getTok().getLoc();5152int64_t FunctionId, FileNumber;5153if (parseCVFunctionId(FunctionId, ".cv_loc") ||5154parseCVFileId(FileNumber, ".cv_loc"))5155return true;51565157int64_t LineNumber = 0;5158if (getLexer().is(AsmToken::Integer)) {5159LineNumber = getTok().getIntVal();5160if (LineNumber < 0)5161return TokError("line number less than zero in '.cv_loc' directive");5162Lex();5163}51645165int64_t ColumnPos = 0;5166if (getLexer().is(AsmToken::Integer)) {5167ColumnPos = getTok().getIntVal();5168if (ColumnPos < 0)5169return TokError("column position less than zero in '.cv_loc' directive");5170Lex();5171}51725173bool PrologueEnd = false;5174uint64_t IsStmt = 0;51755176auto parseOp = [&]() -> bool {5177StringRef Name;5178SMLoc Loc = getTok().getLoc();5179if (parseIdentifier(Name))5180return TokError("unexpected token in '.cv_loc' directive");5181if (Name == "prologue_end")5182PrologueEnd = true;5183else if (Name == "is_stmt") {5184Loc = getTok().getLoc();5185const MCExpr *Value;5186if (parseExpression(Value))5187return true;5188// The expression must be the constant 0 or 1.5189IsStmt = ~0ULL;5190if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))5191IsStmt = MCE->getValue();51925193if (IsStmt > 1)5194return Error(Loc, "is_stmt value not 0 or 1");5195} else {5196return Error(Loc, "unknown sub-directive in '.cv_loc' directive");5197}5198return false;5199};52005201if (parseMany(parseOp, false /*hasComma*/))5202return true;52035204getStreamer().emitCVLocDirective(FunctionId, FileNumber, LineNumber,5205ColumnPos, PrologueEnd, IsStmt, StringRef(),5206DirectiveLoc);5207return false;5208}52095210/// parseDirectiveCVLinetable5211/// ::= .cv_linetable FunctionId, FnStart, FnEnd5212bool MasmParser::parseDirectiveCVLinetable() {5213int64_t FunctionId;5214StringRef FnStartName, FnEndName;5215SMLoc Loc = getTok().getLoc();5216if (parseCVFunctionId(FunctionId, ".cv_linetable") ||5217parseToken(AsmToken::Comma,5218"unexpected token in '.cv_linetable' directive") ||5219parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,5220"expected identifier in directive") ||5221parseToken(AsmToken::Comma,5222"unexpected token in '.cv_linetable' directive") ||5223parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,5224"expected identifier in directive"))5225return true;52265227MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);5228MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);52295230getStreamer().emitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);5231return false;5232}52335234/// parseDirectiveCVInlineLinetable5235/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd5236bool MasmParser::parseDirectiveCVInlineLinetable() {5237int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;5238StringRef FnStartName, FnEndName;5239SMLoc Loc = getTok().getLoc();5240if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||5241parseTokenLoc(Loc) ||5242parseIntToken(5243SourceFileId,5244"expected SourceField in '.cv_inline_linetable' directive") ||5245check(SourceFileId <= 0, Loc,5246"File id less than zero in '.cv_inline_linetable' directive") ||5247parseTokenLoc(Loc) ||5248parseIntToken(5249SourceLineNum,5250"expected SourceLineNum in '.cv_inline_linetable' directive") ||5251check(SourceLineNum < 0, Loc,5252"Line number less than zero in '.cv_inline_linetable' directive") ||5253parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,5254"expected identifier in directive") ||5255parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,5256"expected identifier in directive"))5257return true;52585259if (parseEOL())5260return true;52615262MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);5263MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);5264getStreamer().emitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,5265SourceLineNum, FnStartSym,5266FnEndSym);5267return false;5268}52695270void MasmParser::initializeCVDefRangeTypeMap() {5271CVDefRangeTypeMap["reg"] = CVDR_DEFRANGE_REGISTER;5272CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL;5273CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER;5274CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;5275}52765277/// parseDirectiveCVDefRange5278/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*5279bool MasmParser::parseDirectiveCVDefRange() {5280SMLoc Loc;5281std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;5282while (getLexer().is(AsmToken::Identifier)) {5283Loc = getLexer().getLoc();5284StringRef GapStartName;5285if (parseIdentifier(GapStartName))5286return Error(Loc, "expected identifier in directive");5287MCSymbol *GapStartSym = getContext().getOrCreateSymbol(GapStartName);52885289Loc = getLexer().getLoc();5290StringRef GapEndName;5291if (parseIdentifier(GapEndName))5292return Error(Loc, "expected identifier in directive");5293MCSymbol *GapEndSym = getContext().getOrCreateSymbol(GapEndName);52945295Ranges.push_back({GapStartSym, GapEndSym});5296}52975298StringRef CVDefRangeTypeStr;5299if (parseToken(5300AsmToken::Comma,5301"expected comma before def_range type in .cv_def_range directive") ||5302parseIdentifier(CVDefRangeTypeStr))5303return Error(Loc, "expected def_range type in directive");53045305StringMap<CVDefRangeType>::const_iterator CVTypeIt =5306CVDefRangeTypeMap.find(CVDefRangeTypeStr);5307CVDefRangeType CVDRType = (CVTypeIt == CVDefRangeTypeMap.end())5308? CVDR_DEFRANGE5309: CVTypeIt->getValue();5310switch (CVDRType) {5311case CVDR_DEFRANGE_REGISTER: {5312int64_t DRRegister;5313if (parseToken(AsmToken::Comma, "expected comma before register number in "5314".cv_def_range directive") ||5315parseAbsoluteExpression(DRRegister))5316return Error(Loc, "expected register number");53175318codeview::DefRangeRegisterHeader DRHdr;5319DRHdr.Register = DRRegister;5320DRHdr.MayHaveNoName = 0;5321getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);5322break;5323}5324case CVDR_DEFRANGE_FRAMEPOINTER_REL: {5325int64_t DROffset;5326if (parseToken(AsmToken::Comma,5327"expected comma before offset in .cv_def_range directive") ||5328parseAbsoluteExpression(DROffset))5329return Error(Loc, "expected offset value");53305331codeview::DefRangeFramePointerRelHeader DRHdr;5332DRHdr.Offset = DROffset;5333getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);5334break;5335}5336case CVDR_DEFRANGE_SUBFIELD_REGISTER: {5337int64_t DRRegister;5338int64_t DROffsetInParent;5339if (parseToken(AsmToken::Comma, "expected comma before register number in "5340".cv_def_range directive") ||5341parseAbsoluteExpression(DRRegister))5342return Error(Loc, "expected register number");5343if (parseToken(AsmToken::Comma,5344"expected comma before offset in .cv_def_range directive") ||5345parseAbsoluteExpression(DROffsetInParent))5346return Error(Loc, "expected offset value");53475348codeview::DefRangeSubfieldRegisterHeader DRHdr;5349DRHdr.Register = DRRegister;5350DRHdr.MayHaveNoName = 0;5351DRHdr.OffsetInParent = DROffsetInParent;5352getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);5353break;5354}5355case CVDR_DEFRANGE_REGISTER_REL: {5356int64_t DRRegister;5357int64_t DRFlags;5358int64_t DRBasePointerOffset;5359if (parseToken(AsmToken::Comma, "expected comma before register number in "5360".cv_def_range directive") ||5361parseAbsoluteExpression(DRRegister))5362return Error(Loc, "expected register value");5363if (parseToken(5364AsmToken::Comma,5365"expected comma before flag value in .cv_def_range directive") ||5366parseAbsoluteExpression(DRFlags))5367return Error(Loc, "expected flag value");5368if (parseToken(AsmToken::Comma, "expected comma before base pointer offset "5369"in .cv_def_range directive") ||5370parseAbsoluteExpression(DRBasePointerOffset))5371return Error(Loc, "expected base pointer offset value");53725373codeview::DefRangeRegisterRelHeader DRHdr;5374DRHdr.Register = DRRegister;5375DRHdr.Flags = DRFlags;5376DRHdr.BasePointerOffset = DRBasePointerOffset;5377getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);5378break;5379}5380default:5381return Error(Loc, "unexpected def_range type in .cv_def_range directive");5382}5383return true;5384}53855386/// parseDirectiveCVString5387/// ::= .cv_stringtable "string"5388bool MasmParser::parseDirectiveCVString() {5389std::string Data;5390if (checkForValidSection() || parseEscapedString(Data))5391return addErrorSuffix(" in '.cv_string' directive");53925393// Put the string in the table and emit the offset.5394std::pair<StringRef, unsigned> Insertion =5395getCVContext().addToStringTable(Data);5396getStreamer().emitIntValue(Insertion.second, 4);5397return false;5398}53995400/// parseDirectiveCVStringTable5401/// ::= .cv_stringtable5402bool MasmParser::parseDirectiveCVStringTable() {5403getStreamer().emitCVStringTableDirective();5404return false;5405}54065407/// parseDirectiveCVFileChecksums5408/// ::= .cv_filechecksums5409bool MasmParser::parseDirectiveCVFileChecksums() {5410getStreamer().emitCVFileChecksumsDirective();5411return false;5412}54135414/// parseDirectiveCVFileChecksumOffset5415/// ::= .cv_filechecksumoffset fileno5416bool MasmParser::parseDirectiveCVFileChecksumOffset() {5417int64_t FileNo;5418if (parseIntToken(FileNo, "expected identifier in directive"))5419return true;5420if (parseEOL())5421return true;5422getStreamer().emitCVFileChecksumOffsetDirective(FileNo);5423return false;5424}54255426/// parseDirectiveCVFPOData5427/// ::= .cv_fpo_data procsym5428bool MasmParser::parseDirectiveCVFPOData() {5429SMLoc DirLoc = getLexer().getLoc();5430StringRef ProcName;5431if (parseIdentifier(ProcName))5432return TokError("expected symbol name");5433if (parseEOL("unexpected tokens"))5434return addErrorSuffix(" in '.cv_fpo_data' directive");5435MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);5436getStreamer().emitCVFPOData(ProcSym, DirLoc);5437return false;5438}54395440/// parseDirectiveCFISections5441/// ::= .cfi_sections section [, section]5442bool MasmParser::parseDirectiveCFISections() {5443StringRef Name;5444bool EH = false;5445bool Debug = false;54465447if (parseIdentifier(Name))5448return TokError("Expected an identifier");54495450if (Name == ".eh_frame")5451EH = true;5452else if (Name == ".debug_frame")5453Debug = true;54545455if (getLexer().is(AsmToken::Comma)) {5456Lex();54575458if (parseIdentifier(Name))5459return TokError("Expected an identifier");54605461if (Name == ".eh_frame")5462EH = true;5463else if (Name == ".debug_frame")5464Debug = true;5465}54665467getStreamer().emitCFISections(EH, Debug);5468return false;5469}54705471/// parseDirectiveCFIStartProc5472/// ::= .cfi_startproc [simple]5473bool MasmParser::parseDirectiveCFIStartProc() {5474StringRef Simple;5475if (!parseOptionalToken(AsmToken::EndOfStatement)) {5476if (check(parseIdentifier(Simple) || Simple != "simple",5477"unexpected token") ||5478parseEOL())5479return addErrorSuffix(" in '.cfi_startproc' directive");5480}54815482// TODO(kristina): Deal with a corner case of incorrect diagnostic context5483// being produced if this directive is emitted as part of preprocessor macro5484// expansion which can *ONLY* happen if Clang's cc1as is the API consumer.5485// Tools like llvm-mc on the other hand are not affected by it, and report5486// correct context information.5487getStreamer().emitCFIStartProc(!Simple.empty(), Lexer.getLoc());5488return false;5489}54905491/// parseDirectiveCFIEndProc5492/// ::= .cfi_endproc5493bool MasmParser::parseDirectiveCFIEndProc() {5494getStreamer().emitCFIEndProc();5495return false;5496}54975498/// parse register name or number.5499bool MasmParser::parseRegisterOrRegisterNumber(int64_t &Register,5500SMLoc DirectiveLoc) {5501MCRegister RegNo;55025503if (getLexer().isNot(AsmToken::Integer)) {5504if (getTargetParser().parseRegister(RegNo, DirectiveLoc, DirectiveLoc))5505return true;5506Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo, true);5507} else5508return parseAbsoluteExpression(Register);55095510return false;5511}55125513/// parseDirectiveCFIDefCfa5514/// ::= .cfi_def_cfa register, offset5515bool MasmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) {5516int64_t Register = 0, Offset = 0;5517if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||5518parseToken(AsmToken::Comma, "unexpected token in directive") ||5519parseAbsoluteExpression(Offset))5520return true;55215522getStreamer().emitCFIDefCfa(Register, Offset);5523return false;5524}55255526/// parseDirectiveCFIDefCfaOffset5527/// ::= .cfi_def_cfa_offset offset5528bool MasmParser::parseDirectiveCFIDefCfaOffset(SMLoc DirectiveLoc) {5529int64_t Offset = 0;5530if (parseAbsoluteExpression(Offset))5531return true;55325533getStreamer().emitCFIDefCfaOffset(Offset, DirectiveLoc);5534return false;5535}55365537/// parseDirectiveCFIRegister5538/// ::= .cfi_register register, register5539bool MasmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) {5540int64_t Register1 = 0, Register2 = 0;5541if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) ||5542parseToken(AsmToken::Comma, "unexpected token in directive") ||5543parseRegisterOrRegisterNumber(Register2, DirectiveLoc))5544return true;55455546getStreamer().emitCFIRegister(Register1, Register2, DirectiveLoc);5547return false;5548}55495550/// parseDirectiveCFIWindowSave5551/// ::= .cfi_window_save5552bool MasmParser::parseDirectiveCFIWindowSave(SMLoc DirectiveLoc) {5553getStreamer().emitCFIWindowSave(DirectiveLoc);5554return false;5555}55565557/// parseDirectiveCFIAdjustCfaOffset5558/// ::= .cfi_adjust_cfa_offset adjustment5559bool MasmParser::parseDirectiveCFIAdjustCfaOffset(SMLoc DirectiveLoc) {5560int64_t Adjustment = 0;5561if (parseAbsoluteExpression(Adjustment))5562return true;55635564getStreamer().emitCFIAdjustCfaOffset(Adjustment, DirectiveLoc);5565return false;5566}55675568/// parseDirectiveCFIDefCfaRegister5569/// ::= .cfi_def_cfa_register register5570bool MasmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) {5571int64_t Register = 0;5572if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))5573return true;55745575getStreamer().emitCFIDefCfaRegister(Register);5576return false;5577}55785579/// parseDirectiveCFIOffset5580/// ::= .cfi_offset register, offset5581bool MasmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {5582int64_t Register = 0;5583int64_t Offset = 0;55845585if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||5586parseToken(AsmToken::Comma, "unexpected token in directive") ||5587parseAbsoluteExpression(Offset))5588return true;55895590getStreamer().emitCFIOffset(Register, Offset);5591return false;5592}55935594/// parseDirectiveCFIRelOffset5595/// ::= .cfi_rel_offset register, offset5596bool MasmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) {5597int64_t Register = 0, Offset = 0;55985599if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||5600parseToken(AsmToken::Comma, "unexpected token in directive") ||5601parseAbsoluteExpression(Offset))5602return true;56035604getStreamer().emitCFIRelOffset(Register, Offset, DirectiveLoc);5605return false;5606}56075608static bool isValidEncoding(int64_t Encoding) {5609if (Encoding & ~0xff)5610return false;56115612if (Encoding == dwarf::DW_EH_PE_omit)5613return true;56145615const unsigned Format = Encoding & 0xf;5616if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 &&5617Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 &&5618Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 &&5619Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed)5620return false;56215622const unsigned Application = Encoding & 0x70;5623if (Application != dwarf::DW_EH_PE_absptr &&5624Application != dwarf::DW_EH_PE_pcrel)5625return false;56265627return true;5628}56295630/// parseDirectiveCFIPersonalityOrLsda5631/// IsPersonality true for cfi_personality, false for cfi_lsda5632/// ::= .cfi_personality encoding, [symbol_name]5633/// ::= .cfi_lsda encoding, [symbol_name]5634bool MasmParser::parseDirectiveCFIPersonalityOrLsda(bool IsPersonality) {5635int64_t Encoding = 0;5636if (parseAbsoluteExpression(Encoding))5637return true;5638if (Encoding == dwarf::DW_EH_PE_omit)5639return false;56405641StringRef Name;5642if (check(!isValidEncoding(Encoding), "unsupported encoding.") ||5643parseToken(AsmToken::Comma, "unexpected token in directive") ||5644check(parseIdentifier(Name), "expected identifier in directive"))5645return true;56465647MCSymbol *Sym = getContext().getOrCreateSymbol(Name);56485649if (IsPersonality)5650getStreamer().emitCFIPersonality(Sym, Encoding);5651else5652getStreamer().emitCFILsda(Sym, Encoding);5653return false;5654}56555656/// parseDirectiveCFIRememberState5657/// ::= .cfi_remember_state5658bool MasmParser::parseDirectiveCFIRememberState(SMLoc DirectiveLoc) {5659getStreamer().emitCFIRememberState(DirectiveLoc);5660return false;5661}56625663/// parseDirectiveCFIRestoreState5664/// ::= .cfi_remember_state5665bool MasmParser::parseDirectiveCFIRestoreState(SMLoc DirectiveLoc) {5666getStreamer().emitCFIRestoreState(DirectiveLoc);5667return false;5668}56695670/// parseDirectiveCFISameValue5671/// ::= .cfi_same_value register5672bool MasmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) {5673int64_t Register = 0;56745675if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))5676return true;56775678getStreamer().emitCFISameValue(Register, DirectiveLoc);5679return false;5680}56815682/// parseDirectiveCFIRestore5683/// ::= .cfi_restore register5684bool MasmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) {5685int64_t Register = 0;5686if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))5687return true;56885689getStreamer().emitCFIRestore(Register);5690return false;5691}56925693/// parseDirectiveCFIEscape5694/// ::= .cfi_escape expression[,...]5695bool MasmParser::parseDirectiveCFIEscape(SMLoc DirectiveLoc) {5696std::string Values;5697int64_t CurrValue;5698if (parseAbsoluteExpression(CurrValue))5699return true;57005701Values.push_back((uint8_t)CurrValue);57025703while (getLexer().is(AsmToken::Comma)) {5704Lex();57055706if (parseAbsoluteExpression(CurrValue))5707return true;57085709Values.push_back((uint8_t)CurrValue);5710}57115712getStreamer().emitCFIEscape(Values, DirectiveLoc);5713return false;5714}57155716/// parseDirectiveCFIReturnColumn5717/// ::= .cfi_return_column register5718bool MasmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) {5719int64_t Register = 0;5720if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))5721return true;5722getStreamer().emitCFIReturnColumn(Register);5723return false;5724}57255726/// parseDirectiveCFISignalFrame5727/// ::= .cfi_signal_frame5728bool MasmParser::parseDirectiveCFISignalFrame() {5729if (parseEOL())5730return true;57315732getStreamer().emitCFISignalFrame();5733return false;5734}57355736/// parseDirectiveCFIUndefined5737/// ::= .cfi_undefined register5738bool MasmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {5739int64_t Register = 0;57405741if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))5742return true;57435744getStreamer().emitCFIUndefined(Register);5745return false;5746}57475748/// parseDirectiveMacro5749/// ::= name macro [parameters]5750/// ["LOCAL" identifiers]5751/// parameters ::= parameter [, parameter]*5752/// parameter ::= name ":" qualifier5753/// qualifier ::= "req" | "vararg" | "=" macro_argument5754bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {5755MCAsmMacroParameters Parameters;5756while (getLexer().isNot(AsmToken::EndOfStatement)) {5757if (!Parameters.empty() && Parameters.back().Vararg)5758return Error(Lexer.getLoc(),5759"Vararg parameter '" + Parameters.back().Name +5760"' should be last in the list of parameters");57615762MCAsmMacroParameter Parameter;5763if (parseIdentifier(Parameter.Name))5764return TokError("expected identifier in 'macro' directive");57655766// Emit an error if two (or more) named parameters share the same name.5767for (const MCAsmMacroParameter& CurrParam : Parameters)5768if (CurrParam.Name.equals_insensitive(Parameter.Name))5769return TokError("macro '" + Name + "' has multiple parameters"5770" named '" + Parameter.Name + "'");57715772if (Lexer.is(AsmToken::Colon)) {5773Lex(); // consume ':'57745775if (parseOptionalToken(AsmToken::Equal)) {5776// Default value5777SMLoc ParamLoc;57785779ParamLoc = Lexer.getLoc();5780if (parseMacroArgument(nullptr, Parameter.Value))5781return true;5782} else {5783SMLoc QualLoc;5784StringRef Qualifier;57855786QualLoc = Lexer.getLoc();5787if (parseIdentifier(Qualifier))5788return Error(QualLoc, "missing parameter qualifier for "5789"'" +5790Parameter.Name + "' in macro '" + Name +5791"'");57925793if (Qualifier.equals_insensitive("req"))5794Parameter.Required = true;5795else if (Qualifier.equals_insensitive("vararg"))5796Parameter.Vararg = true;5797else5798return Error(QualLoc,5799Qualifier + " is not a valid parameter qualifier for '" +5800Parameter.Name + "' in macro '" + Name + "'");5801}5802}58035804Parameters.push_back(std::move(Parameter));58055806if (getLexer().is(AsmToken::Comma))5807Lex();5808}58095810// Eat just the end of statement.5811Lexer.Lex();58125813std::vector<std::string> Locals;5814if (getTok().is(AsmToken::Identifier) &&5815getTok().getIdentifier().equals_insensitive("local")) {5816Lex(); // Eat the LOCAL directive.58175818StringRef ID;5819while (true) {5820if (parseIdentifier(ID))5821return true;5822Locals.push_back(ID.lower());58235824// If we see a comma, continue (and allow line continuation).5825if (!parseOptionalToken(AsmToken::Comma))5826break;5827parseOptionalToken(AsmToken::EndOfStatement);5828}5829}58305831// Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors.5832AsmToken EndToken, StartToken = getTok();5833unsigned MacroDepth = 0;5834bool IsMacroFunction = false;5835// Lex the macro definition.5836while (true) {5837// Ignore Lexing errors in macros.5838while (Lexer.is(AsmToken::Error)) {5839Lexer.Lex();5840}58415842// Check whether we have reached the end of the file.5843if (getLexer().is(AsmToken::Eof))5844return Error(NameLoc, "no matching 'endm' in definition");58455846// Otherwise, check whether we have reached the 'endm'... and determine if5847// this is a macro function.5848if (getLexer().is(AsmToken::Identifier)) {5849if (getTok().getIdentifier().equals_insensitive("endm")) {5850if (MacroDepth == 0) { // Outermost macro.5851EndToken = getTok();5852Lexer.Lex();5853if (getLexer().isNot(AsmToken::EndOfStatement))5854return TokError("unexpected token in '" + EndToken.getIdentifier() +5855"' directive");5856break;5857} else {5858// Otherwise we just found the end of an inner macro.5859--MacroDepth;5860}5861} else if (getTok().getIdentifier().equals_insensitive("exitm")) {5862if (MacroDepth == 0 && peekTok().isNot(AsmToken::EndOfStatement)) {5863IsMacroFunction = true;5864}5865} else if (isMacroLikeDirective()) {5866// We allow nested macros. Those aren't instantiated until the5867// outermost macro is expanded so just ignore them for now.5868++MacroDepth;5869}5870}58715872// Otherwise, scan til the end of the statement.5873eatToEndOfStatement();5874}58755876if (getContext().lookupMacro(Name.lower())) {5877return Error(NameLoc, "macro '" + Name + "' is already defined");5878}58795880const char *BodyStart = StartToken.getLoc().getPointer();5881const char *BodyEnd = EndToken.getLoc().getPointer();5882StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);5883MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals),5884IsMacroFunction);5885DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";5886Macro.dump());5887getContext().defineMacro(Name.lower(), std::move(Macro));5888return false;5889}58905891/// parseDirectiveExitMacro5892/// ::= "exitm" [textitem]5893bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc,5894StringRef Directive,5895std::string &Value) {5896SMLoc EndLoc = getTok().getLoc();5897if (getTok().isNot(AsmToken::EndOfStatement) && parseTextItem(Value))5898return Error(EndLoc,5899"unable to parse text item in '" + Directive + "' directive");5900eatToEndOfStatement();59015902if (!isInsideMacroInstantiation())5903return TokError("unexpected '" + Directive + "' in file, "5904"no current macro definition");59055906// Exit all conditionals that are active in the current macro.5907while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {5908TheCondState = TheCondStack.back();5909TheCondStack.pop_back();5910}59115912handleMacroExit();5913return false;5914}59155916/// parseDirectiveEndMacro5917/// ::= endm5918bool MasmParser::parseDirectiveEndMacro(StringRef Directive) {5919if (getLexer().isNot(AsmToken::EndOfStatement))5920return TokError("unexpected token in '" + Directive + "' directive");59215922// If we are inside a macro instantiation, terminate the current5923// instantiation.5924if (isInsideMacroInstantiation()) {5925handleMacroExit();5926return false;5927}59285929// Otherwise, this .endmacro is a stray entry in the file; well formed5930// .endmacro directives are handled during the macro definition parsing.5931return TokError("unexpected '" + Directive + "' in file, "5932"no current macro definition");5933}59345935/// parseDirectivePurgeMacro5936/// ::= purge identifier ( , identifier )*5937bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {5938StringRef Name;5939while (true) {5940SMLoc NameLoc;5941if (parseTokenLoc(NameLoc) ||5942check(parseIdentifier(Name), NameLoc,5943"expected identifier in 'purge' directive"))5944return true;59455946DEBUG_WITH_TYPE("asm-macros", dbgs()5947<< "Un-defining macro: " << Name << "\n");5948if (!getContext().lookupMacro(Name.lower()))5949return Error(NameLoc, "macro '" + Name + "' is not defined");5950getContext().undefineMacro(Name.lower());59515952if (!parseOptionalToken(AsmToken::Comma))5953break;5954parseOptionalToken(AsmToken::EndOfStatement);5955}59565957return false;5958}59595960bool MasmParser::parseDirectiveExtern() {5961// .extern is the default - but we still need to take any provided type info.5962auto parseOp = [&]() -> bool {5963StringRef Name;5964SMLoc NameLoc = getTok().getLoc();5965if (parseIdentifier(Name))5966return Error(NameLoc, "expected name");5967if (parseToken(AsmToken::Colon))5968return true;59695970StringRef TypeName;5971SMLoc TypeLoc = getTok().getLoc();5972if (parseIdentifier(TypeName))5973return Error(TypeLoc, "expected type");5974if (!TypeName.equals_insensitive("proc")) {5975AsmTypeInfo Type;5976if (lookUpType(TypeName, Type))5977return Error(TypeLoc, "unrecognized type");5978KnownType[Name.lower()] = Type;5979}59805981MCSymbol *Sym = getContext().getOrCreateSymbol(Name);5982Sym->setExternal(true);5983getStreamer().emitSymbolAttribute(Sym, MCSA_Extern);59845985return false;5986};59875988if (parseMany(parseOp))5989return addErrorSuffix(" in directive 'extern'");5990return false;5991}59925993/// parseDirectiveSymbolAttribute5994/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]5995bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {5996auto parseOp = [&]() -> bool {5997StringRef Name;5998SMLoc Loc = getTok().getLoc();5999if (parseIdentifier(Name))6000return Error(Loc, "expected identifier");6001MCSymbol *Sym = getContext().getOrCreateSymbol(Name);60026003// Assembler local symbols don't make any sense here. Complain loudly.6004if (Sym->isTemporary())6005return Error(Loc, "non-local symbol required");60066007if (!getStreamer().emitSymbolAttribute(Sym, Attr))6008return Error(Loc, "unable to emit symbol attribute");6009return false;6010};60116012if (parseMany(parseOp))6013return addErrorSuffix(" in directive");6014return false;6015}60166017/// parseDirectiveComm6018/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]6019bool MasmParser::parseDirectiveComm(bool IsLocal) {6020if (checkForValidSection())6021return true;60226023SMLoc IDLoc = getLexer().getLoc();6024StringRef Name;6025if (parseIdentifier(Name))6026return TokError("expected identifier in directive");60276028// Handle the identifier as the key symbol.6029MCSymbol *Sym = getContext().getOrCreateSymbol(Name);60306031if (getLexer().isNot(AsmToken::Comma))6032return TokError("unexpected token in directive");6033Lex();60346035int64_t Size;6036SMLoc SizeLoc = getLexer().getLoc();6037if (parseAbsoluteExpression(Size))6038return true;60396040int64_t Pow2Alignment = 0;6041SMLoc Pow2AlignmentLoc;6042if (getLexer().is(AsmToken::Comma)) {6043Lex();6044Pow2AlignmentLoc = getLexer().getLoc();6045if (parseAbsoluteExpression(Pow2Alignment))6046return true;60476048LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();6049if (IsLocal && LCOMM == LCOMM::NoAlignment)6050return Error(Pow2AlignmentLoc, "alignment not supported on this target");60516052// If this target takes alignments in bytes (not log) validate and convert.6053if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||6054(IsLocal && LCOMM == LCOMM::ByteAlignment)) {6055if (!isPowerOf2_64(Pow2Alignment))6056return Error(Pow2AlignmentLoc, "alignment must be a power of 2");6057Pow2Alignment = Log2_64(Pow2Alignment);6058}6059}60606061if (parseEOL())6062return true;60636064// NOTE: a size of zero for a .comm should create a undefined symbol6065// but a size of .lcomm creates a bss symbol of size zero.6066if (Size < 0)6067return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "6068"be less than zero");60696070// NOTE: The alignment in the directive is a power of 2 value, the assembler6071// may internally end up wanting an alignment in bytes.6072// FIXME: Diagnose overflow.6073if (Pow2Alignment < 0)6074return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive "6075"alignment, can't be less than zero");60766077Sym->redefineIfPossible();6078if (!Sym->isUndefined())6079return Error(IDLoc, "invalid symbol redefinition");60806081// Create the Symbol as a common or local common with Size and Pow2Alignment.6082if (IsLocal) {6083getStreamer().emitLocalCommonSymbol(Sym, Size,6084Align(1ULL << Pow2Alignment));6085return false;6086}60876088getStreamer().emitCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));6089return false;6090}60916092/// parseDirectiveComment6093/// ::= comment delimiter [[text]]6094/// [[text]]6095/// [[text]] delimiter [[text]]6096bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) {6097std::string FirstLine = parseStringTo(AsmToken::EndOfStatement);6098size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A ");6099assert(DelimiterEnd != std::string::npos);6100StringRef Delimiter = StringRef(FirstLine).take_front(DelimiterEnd);6101if (Delimiter.empty())6102return Error(DirectiveLoc, "no delimiter in 'comment' directive");6103do {6104if (getTok().is(AsmToken::Eof))6105return Error(DirectiveLoc, "unmatched delimiter in 'comment' directive");6106Lex(); // eat end of statement6107} while (6108!StringRef(parseStringTo(AsmToken::EndOfStatement)).contains(Delimiter));6109return parseEOL();6110}61116112/// parseDirectiveInclude6113/// ::= include <filename>6114/// | include filename6115bool MasmParser::parseDirectiveInclude() {6116// Allow the strings to have escaped octal character sequence.6117std::string Filename;6118SMLoc IncludeLoc = getTok().getLoc();61196120if (parseAngleBracketString(Filename))6121Filename = parseStringTo(AsmToken::EndOfStatement);6122if (check(Filename.empty(), "missing filename in 'include' directive") ||6123check(getTok().isNot(AsmToken::EndOfStatement),6124"unexpected token in 'include' directive") ||6125// Attempt to switch the lexer to the included file before consuming the6126// end of statement to avoid losing it when we switch.6127check(enterIncludeFile(Filename), IncludeLoc,6128"Could not find include file '" + Filename + "'"))6129return true;61306131return false;6132}61336134/// parseDirectiveIf6135/// ::= .if{,eq,ge,gt,le,lt,ne} expression6136bool MasmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {6137TheCondStack.push_back(TheCondState);6138TheCondState.TheCond = AsmCond::IfCond;6139if (TheCondState.Ignore) {6140eatToEndOfStatement();6141} else {6142int64_t ExprValue;6143if (parseAbsoluteExpression(ExprValue) || parseEOL())6144return true;61456146switch (DirKind) {6147default:6148llvm_unreachable("unsupported directive");6149case DK_IF:6150break;6151case DK_IFE:6152ExprValue = ExprValue == 0;6153break;6154}61556156TheCondState.CondMet = ExprValue;6157TheCondState.Ignore = !TheCondState.CondMet;6158}61596160return false;6161}61626163/// parseDirectiveIfb6164/// ::= .ifb textitem6165bool MasmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {6166TheCondStack.push_back(TheCondState);6167TheCondState.TheCond = AsmCond::IfCond;61686169if (TheCondState.Ignore) {6170eatToEndOfStatement();6171} else {6172std::string Str;6173if (parseTextItem(Str))6174return TokError("expected text item parameter for 'ifb' directive");61756176if (parseEOL())6177return true;61786179TheCondState.CondMet = ExpectBlank == Str.empty();6180TheCondState.Ignore = !TheCondState.CondMet;6181}61826183return false;6184}61856186/// parseDirectiveIfidn6187/// ::= ifidn textitem, textitem6188bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,6189bool CaseInsensitive) {6190std::string String1, String2;61916192if (parseTextItem(String1)) {6193if (ExpectEqual)6194return TokError("expected text item parameter for 'ifidn' directive");6195return TokError("expected text item parameter for 'ifdif' directive");6196}61976198if (Lexer.isNot(AsmToken::Comma)) {6199if (ExpectEqual)6200return TokError(6201"expected comma after first string for 'ifidn' directive");6202return TokError("expected comma after first string for 'ifdif' directive");6203}6204Lex();62056206if (parseTextItem(String2)) {6207if (ExpectEqual)6208return TokError("expected text item parameter for 'ifidn' directive");6209return TokError("expected text item parameter for 'ifdif' directive");6210}62116212TheCondStack.push_back(TheCondState);6213TheCondState.TheCond = AsmCond::IfCond;6214if (CaseInsensitive)6215TheCondState.CondMet =6216ExpectEqual == (StringRef(String1).equals_insensitive(String2));6217else6218TheCondState.CondMet = ExpectEqual == (String1 == String2);6219TheCondState.Ignore = !TheCondState.CondMet;62206221return false;6222}62236224/// parseDirectiveIfdef6225/// ::= ifdef symbol6226/// | ifdef variable6227bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {6228TheCondStack.push_back(TheCondState);6229TheCondState.TheCond = AsmCond::IfCond;62306231if (TheCondState.Ignore) {6232eatToEndOfStatement();6233} else {6234bool is_defined = false;6235MCRegister Reg;6236SMLoc StartLoc, EndLoc;6237is_defined =6238getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();6239if (!is_defined) {6240StringRef Name;6241if (check(parseIdentifier(Name), "expected identifier after 'ifdef'") ||6242parseEOL())6243return true;62446245if (BuiltinSymbolMap.contains(Name.lower())) {6246is_defined = true;6247} else if (Variables.contains(Name.lower())) {6248is_defined = true;6249} else {6250MCSymbol *Sym = getContext().lookupSymbol(Name.lower());6251is_defined = (Sym && !Sym->isUndefined(false));6252}6253}62546255TheCondState.CondMet = (is_defined == expect_defined);6256TheCondState.Ignore = !TheCondState.CondMet;6257}62586259return false;6260}62616262/// parseDirectiveElseIf6263/// ::= elseif expression6264bool MasmParser::parseDirectiveElseIf(SMLoc DirectiveLoc,6265DirectiveKind DirKind) {6266if (TheCondState.TheCond != AsmCond::IfCond &&6267TheCondState.TheCond != AsmCond::ElseIfCond)6268return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"6269" .if or an .elseif");6270TheCondState.TheCond = AsmCond::ElseIfCond;62716272bool LastIgnoreState = false;6273if (!TheCondStack.empty())6274LastIgnoreState = TheCondStack.back().Ignore;6275if (LastIgnoreState || TheCondState.CondMet) {6276TheCondState.Ignore = true;6277eatToEndOfStatement();6278} else {6279int64_t ExprValue;6280if (parseAbsoluteExpression(ExprValue))6281return true;62826283if (parseEOL())6284return true;62856286switch (DirKind) {6287default:6288llvm_unreachable("unsupported directive");6289case DK_ELSEIF:6290break;6291case DK_ELSEIFE:6292ExprValue = ExprValue == 0;6293break;6294}62956296TheCondState.CondMet = ExprValue;6297TheCondState.Ignore = !TheCondState.CondMet;6298}62996300return false;6301}63026303/// parseDirectiveElseIfb6304/// ::= elseifb textitem6305bool MasmParser::parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank) {6306if (TheCondState.TheCond != AsmCond::IfCond &&6307TheCondState.TheCond != AsmCond::ElseIfCond)6308return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"6309" if or an elseif");6310TheCondState.TheCond = AsmCond::ElseIfCond;63116312bool LastIgnoreState = false;6313if (!TheCondStack.empty())6314LastIgnoreState = TheCondStack.back().Ignore;6315if (LastIgnoreState || TheCondState.CondMet) {6316TheCondState.Ignore = true;6317eatToEndOfStatement();6318} else {6319std::string Str;6320if (parseTextItem(Str)) {6321if (ExpectBlank)6322return TokError("expected text item parameter for 'elseifb' directive");6323return TokError("expected text item parameter for 'elseifnb' directive");6324}63256326if (parseEOL())6327return true;63286329TheCondState.CondMet = ExpectBlank == Str.empty();6330TheCondState.Ignore = !TheCondState.CondMet;6331}63326333return false;6334}63356336/// parseDirectiveElseIfdef6337/// ::= elseifdef symbol6338/// | elseifdef variable6339bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc,6340bool expect_defined) {6341if (TheCondState.TheCond != AsmCond::IfCond &&6342TheCondState.TheCond != AsmCond::ElseIfCond)6343return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"6344" if or an elseif");6345TheCondState.TheCond = AsmCond::ElseIfCond;63466347bool LastIgnoreState = false;6348if (!TheCondStack.empty())6349LastIgnoreState = TheCondStack.back().Ignore;6350if (LastIgnoreState || TheCondState.CondMet) {6351TheCondState.Ignore = true;6352eatToEndOfStatement();6353} else {6354bool is_defined = false;6355MCRegister Reg;6356SMLoc StartLoc, EndLoc;6357is_defined =6358getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();6359if (!is_defined) {6360StringRef Name;6361if (check(parseIdentifier(Name),6362"expected identifier after 'elseifdef'") ||6363parseEOL())6364return true;63656366if (BuiltinSymbolMap.contains(Name.lower())) {6367is_defined = true;6368} else if (Variables.contains(Name.lower())) {6369is_defined = true;6370} else {6371MCSymbol *Sym = getContext().lookupSymbol(Name);6372is_defined = (Sym && !Sym->isUndefined(false));6373}6374}63756376TheCondState.CondMet = (is_defined == expect_defined);6377TheCondState.Ignore = !TheCondState.CondMet;6378}63796380return false;6381}63826383/// parseDirectiveElseIfidn6384/// ::= elseifidn textitem, textitem6385bool MasmParser::parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,6386bool CaseInsensitive) {6387if (TheCondState.TheCond != AsmCond::IfCond &&6388TheCondState.TheCond != AsmCond::ElseIfCond)6389return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"6390" if or an elseif");6391TheCondState.TheCond = AsmCond::ElseIfCond;63926393bool LastIgnoreState = false;6394if (!TheCondStack.empty())6395LastIgnoreState = TheCondStack.back().Ignore;6396if (LastIgnoreState || TheCondState.CondMet) {6397TheCondState.Ignore = true;6398eatToEndOfStatement();6399} else {6400std::string String1, String2;64016402if (parseTextItem(String1)) {6403if (ExpectEqual)6404return TokError(6405"expected text item parameter for 'elseifidn' directive");6406return TokError("expected text item parameter for 'elseifdif' directive");6407}64086409if (Lexer.isNot(AsmToken::Comma)) {6410if (ExpectEqual)6411return TokError(6412"expected comma after first string for 'elseifidn' directive");6413return TokError(6414"expected comma after first string for 'elseifdif' directive");6415}6416Lex();64176418if (parseTextItem(String2)) {6419if (ExpectEqual)6420return TokError(6421"expected text item parameter for 'elseifidn' directive");6422return TokError("expected text item parameter for 'elseifdif' directive");6423}64246425if (CaseInsensitive)6426TheCondState.CondMet =6427ExpectEqual == (StringRef(String1).equals_insensitive(String2));6428else6429TheCondState.CondMet = ExpectEqual == (String1 == String2);6430TheCondState.Ignore = !TheCondState.CondMet;6431}64326433return false;6434}64356436/// parseDirectiveElse6437/// ::= else6438bool MasmParser::parseDirectiveElse(SMLoc DirectiveLoc) {6439if (parseEOL())6440return true;64416442if (TheCondState.TheCond != AsmCond::IfCond &&6443TheCondState.TheCond != AsmCond::ElseIfCond)6444return Error(DirectiveLoc, "Encountered an else that doesn't follow an if"6445" or an elseif");6446TheCondState.TheCond = AsmCond::ElseCond;6447bool LastIgnoreState = false;6448if (!TheCondStack.empty())6449LastIgnoreState = TheCondStack.back().Ignore;6450if (LastIgnoreState || TheCondState.CondMet)6451TheCondState.Ignore = true;6452else6453TheCondState.Ignore = false;64546455return false;6456}64576458/// parseDirectiveEnd6459/// ::= end6460bool MasmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {6461if (parseEOL())6462return true;64636464while (Lexer.isNot(AsmToken::Eof))6465Lexer.Lex();64666467return false;6468}64696470/// parseDirectiveError6471/// ::= .err [message]6472bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) {6473if (!TheCondStack.empty()) {6474if (TheCondStack.back().Ignore) {6475eatToEndOfStatement();6476return false;6477}6478}64796480std::string Message = ".err directive invoked in source file";6481if (Lexer.isNot(AsmToken::EndOfStatement))6482Message = parseStringTo(AsmToken::EndOfStatement);6483Lex();64846485return Error(DirectiveLoc, Message);6486}64876488/// parseDirectiveErrorIfb6489/// ::= .errb textitem[, message]6490bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) {6491if (!TheCondStack.empty()) {6492if (TheCondStack.back().Ignore) {6493eatToEndOfStatement();6494return false;6495}6496}64976498std::string Text;6499if (parseTextItem(Text))6500return Error(getTok().getLoc(), "missing text item in '.errb' directive");65016502std::string Message = ".errb directive invoked in source file";6503if (Lexer.isNot(AsmToken::EndOfStatement)) {6504if (parseToken(AsmToken::Comma))6505return addErrorSuffix(" in '.errb' directive");6506Message = parseStringTo(AsmToken::EndOfStatement);6507}6508Lex();65096510if (Text.empty() == ExpectBlank)6511return Error(DirectiveLoc, Message);6512return false;6513}65146515/// parseDirectiveErrorIfdef6516/// ::= .errdef name[, message]6517bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc,6518bool ExpectDefined) {6519if (!TheCondStack.empty()) {6520if (TheCondStack.back().Ignore) {6521eatToEndOfStatement();6522return false;6523}6524}65256526bool IsDefined = false;6527MCRegister Reg;6528SMLoc StartLoc, EndLoc;6529IsDefined =6530getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();6531if (!IsDefined) {6532StringRef Name;6533if (check(parseIdentifier(Name), "expected identifier after '.errdef'"))6534return true;65356536if (BuiltinSymbolMap.contains(Name.lower())) {6537IsDefined = true;6538} else if (Variables.contains(Name.lower())) {6539IsDefined = true;6540} else {6541MCSymbol *Sym = getContext().lookupSymbol(Name);6542IsDefined = (Sym && !Sym->isUndefined(false));6543}6544}65456546std::string Message = ".errdef directive invoked in source file";6547if (Lexer.isNot(AsmToken::EndOfStatement)) {6548if (parseToken(AsmToken::Comma))6549return addErrorSuffix(" in '.errdef' directive");6550Message = parseStringTo(AsmToken::EndOfStatement);6551}6552Lex();65536554if (IsDefined == ExpectDefined)6555return Error(DirectiveLoc, Message);6556return false;6557}65586559/// parseDirectiveErrorIfidn6560/// ::= .erridn textitem, textitem[, message]6561bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,6562bool CaseInsensitive) {6563if (!TheCondStack.empty()) {6564if (TheCondStack.back().Ignore) {6565eatToEndOfStatement();6566return false;6567}6568}65696570std::string String1, String2;65716572if (parseTextItem(String1)) {6573if (ExpectEqual)6574return TokError("expected string parameter for '.erridn' directive");6575return TokError("expected string parameter for '.errdif' directive");6576}65776578if (Lexer.isNot(AsmToken::Comma)) {6579if (ExpectEqual)6580return TokError(6581"expected comma after first string for '.erridn' directive");6582return TokError(6583"expected comma after first string for '.errdif' directive");6584}6585Lex();65866587if (parseTextItem(String2)) {6588if (ExpectEqual)6589return TokError("expected string parameter for '.erridn' directive");6590return TokError("expected string parameter for '.errdif' directive");6591}65926593std::string Message;6594if (ExpectEqual)6595Message = ".erridn directive invoked in source file";6596else6597Message = ".errdif directive invoked in source file";6598if (Lexer.isNot(AsmToken::EndOfStatement)) {6599if (parseToken(AsmToken::Comma))6600return addErrorSuffix(" in '.erridn' directive");6601Message = parseStringTo(AsmToken::EndOfStatement);6602}6603Lex();66046605if (CaseInsensitive)6606TheCondState.CondMet =6607ExpectEqual == (StringRef(String1).equals_insensitive(String2));6608else6609TheCondState.CondMet = ExpectEqual == (String1 == String2);6610TheCondState.Ignore = !TheCondState.CondMet;66116612if ((CaseInsensitive &&6613ExpectEqual == StringRef(String1).equals_insensitive(String2)) ||6614(ExpectEqual == (String1 == String2)))6615return Error(DirectiveLoc, Message);6616return false;6617}66186619/// parseDirectiveErrorIfe6620/// ::= .erre expression[, message]6621bool MasmParser::parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero) {6622if (!TheCondStack.empty()) {6623if (TheCondStack.back().Ignore) {6624eatToEndOfStatement();6625return false;6626}6627}66286629int64_t ExprValue;6630if (parseAbsoluteExpression(ExprValue))6631return addErrorSuffix(" in '.erre' directive");66326633std::string Message = ".erre directive invoked in source file";6634if (Lexer.isNot(AsmToken::EndOfStatement)) {6635if (parseToken(AsmToken::Comma))6636return addErrorSuffix(" in '.erre' directive");6637Message = parseStringTo(AsmToken::EndOfStatement);6638}6639Lex();66406641if ((ExprValue == 0) == ExpectZero)6642return Error(DirectiveLoc, Message);6643return false;6644}66456646/// parseDirectiveEndIf6647/// ::= .endif6648bool MasmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {6649if (parseEOL())6650return true;66516652if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())6653return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "6654"an .if or .else");6655if (!TheCondStack.empty()) {6656TheCondState = TheCondStack.back();6657TheCondStack.pop_back();6658}66596660return false;6661}66626663void MasmParser::initializeDirectiveKindMap() {6664DirectiveKindMap["="] = DK_ASSIGN;6665DirectiveKindMap["equ"] = DK_EQU;6666DirectiveKindMap["textequ"] = DK_TEXTEQU;6667// DirectiveKindMap[".ascii"] = DK_ASCII;6668// DirectiveKindMap[".asciz"] = DK_ASCIZ;6669// DirectiveKindMap[".string"] = DK_STRING;6670DirectiveKindMap["byte"] = DK_BYTE;6671DirectiveKindMap["sbyte"] = DK_SBYTE;6672DirectiveKindMap["word"] = DK_WORD;6673DirectiveKindMap["sword"] = DK_SWORD;6674DirectiveKindMap["dword"] = DK_DWORD;6675DirectiveKindMap["sdword"] = DK_SDWORD;6676DirectiveKindMap["fword"] = DK_FWORD;6677DirectiveKindMap["qword"] = DK_QWORD;6678DirectiveKindMap["sqword"] = DK_SQWORD;6679DirectiveKindMap["real4"] = DK_REAL4;6680DirectiveKindMap["real8"] = DK_REAL8;6681DirectiveKindMap["real10"] = DK_REAL10;6682DirectiveKindMap["align"] = DK_ALIGN;6683DirectiveKindMap["even"] = DK_EVEN;6684DirectiveKindMap["org"] = DK_ORG;6685DirectiveKindMap["extern"] = DK_EXTERN;6686DirectiveKindMap["extrn"] = DK_EXTERN;6687DirectiveKindMap["public"] = DK_PUBLIC;6688// DirectiveKindMap[".comm"] = DK_COMM;6689DirectiveKindMap["comment"] = DK_COMMENT;6690DirectiveKindMap["include"] = DK_INCLUDE;6691DirectiveKindMap["repeat"] = DK_REPEAT;6692DirectiveKindMap["rept"] = DK_REPEAT;6693DirectiveKindMap["while"] = DK_WHILE;6694DirectiveKindMap["for"] = DK_FOR;6695DirectiveKindMap["irp"] = DK_FOR;6696DirectiveKindMap["forc"] = DK_FORC;6697DirectiveKindMap["irpc"] = DK_FORC;6698DirectiveKindMap["if"] = DK_IF;6699DirectiveKindMap["ife"] = DK_IFE;6700DirectiveKindMap["ifb"] = DK_IFB;6701DirectiveKindMap["ifnb"] = DK_IFNB;6702DirectiveKindMap["ifdef"] = DK_IFDEF;6703DirectiveKindMap["ifndef"] = DK_IFNDEF;6704DirectiveKindMap["ifdif"] = DK_IFDIF;6705DirectiveKindMap["ifdifi"] = DK_IFDIFI;6706DirectiveKindMap["ifidn"] = DK_IFIDN;6707DirectiveKindMap["ifidni"] = DK_IFIDNI;6708DirectiveKindMap["elseif"] = DK_ELSEIF;6709DirectiveKindMap["elseifdef"] = DK_ELSEIFDEF;6710DirectiveKindMap["elseifndef"] = DK_ELSEIFNDEF;6711DirectiveKindMap["elseifdif"] = DK_ELSEIFDIF;6712DirectiveKindMap["elseifidn"] = DK_ELSEIFIDN;6713DirectiveKindMap["else"] = DK_ELSE;6714DirectiveKindMap["end"] = DK_END;6715DirectiveKindMap["endif"] = DK_ENDIF;6716// DirectiveKindMap[".file"] = DK_FILE;6717// DirectiveKindMap[".line"] = DK_LINE;6718// DirectiveKindMap[".loc"] = DK_LOC;6719// DirectiveKindMap[".stabs"] = DK_STABS;6720// DirectiveKindMap[".cv_file"] = DK_CV_FILE;6721// DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;6722// DirectiveKindMap[".cv_loc"] = DK_CV_LOC;6723// DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;6724// DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;6725// DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;6726// DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;6727// DirectiveKindMap[".cv_string"] = DK_CV_STRING;6728// DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;6729// DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;6730// DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;6731// DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;6732// DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;6733// DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;6734// DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;6735// DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;6736// DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;6737// DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;6738// DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;6739// DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;6740// DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;6741// DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;6742// DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;6743// DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;6744// DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;6745// DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;6746// DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;6747// DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;6748// DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;6749// DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;6750// DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;6751// DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;6752// DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;6753// DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;6754DirectiveKindMap["macro"] = DK_MACRO;6755DirectiveKindMap["exitm"] = DK_EXITM;6756DirectiveKindMap["endm"] = DK_ENDM;6757DirectiveKindMap["purge"] = DK_PURGE;6758DirectiveKindMap[".err"] = DK_ERR;6759DirectiveKindMap[".errb"] = DK_ERRB;6760DirectiveKindMap[".errnb"] = DK_ERRNB;6761DirectiveKindMap[".errdef"] = DK_ERRDEF;6762DirectiveKindMap[".errndef"] = DK_ERRNDEF;6763DirectiveKindMap[".errdif"] = DK_ERRDIF;6764DirectiveKindMap[".errdifi"] = DK_ERRDIFI;6765DirectiveKindMap[".erridn"] = DK_ERRIDN;6766DirectiveKindMap[".erridni"] = DK_ERRIDNI;6767DirectiveKindMap[".erre"] = DK_ERRE;6768DirectiveKindMap[".errnz"] = DK_ERRNZ;6769DirectiveKindMap[".pushframe"] = DK_PUSHFRAME;6770DirectiveKindMap[".pushreg"] = DK_PUSHREG;6771DirectiveKindMap[".savereg"] = DK_SAVEREG;6772DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;6773DirectiveKindMap[".setframe"] = DK_SETFRAME;6774DirectiveKindMap[".radix"] = DK_RADIX;6775DirectiveKindMap["db"] = DK_DB;6776DirectiveKindMap["dd"] = DK_DD;6777DirectiveKindMap["df"] = DK_DF;6778DirectiveKindMap["dq"] = DK_DQ;6779DirectiveKindMap["dw"] = DK_DW;6780DirectiveKindMap["echo"] = DK_ECHO;6781DirectiveKindMap["struc"] = DK_STRUCT;6782DirectiveKindMap["struct"] = DK_STRUCT;6783DirectiveKindMap["union"] = DK_UNION;6784DirectiveKindMap["ends"] = DK_ENDS;6785}67866787bool MasmParser::isMacroLikeDirective() {6788if (getLexer().is(AsmToken::Identifier)) {6789bool IsMacroLike = StringSwitch<bool>(getTok().getIdentifier())6790.CasesLower("repeat", "rept", true)6791.CaseLower("while", true)6792.CasesLower("for", "irp", true)6793.CasesLower("forc", "irpc", true)6794.Default(false);6795if (IsMacroLike)6796return true;6797}6798if (peekTok().is(AsmToken::Identifier) &&6799peekTok().getIdentifier().equals_insensitive("macro"))6800return true;68016802return false;6803}68046805MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {6806AsmToken EndToken, StartToken = getTok();68076808unsigned NestLevel = 0;6809while (true) {6810// Check whether we have reached the end of the file.6811if (getLexer().is(AsmToken::Eof)) {6812printError(DirectiveLoc, "no matching 'endm' in definition");6813return nullptr;6814}68156816if (isMacroLikeDirective())6817++NestLevel;68186819// Otherwise, check whether we have reached the endm.6820if (Lexer.is(AsmToken::Identifier) &&6821getTok().getIdentifier().equals_insensitive("endm")) {6822if (NestLevel == 0) {6823EndToken = getTok();6824Lex();6825if (Lexer.isNot(AsmToken::EndOfStatement)) {6826printError(getTok().getLoc(), "unexpected token in 'endm' directive");6827return nullptr;6828}6829break;6830}6831--NestLevel;6832}68336834// Otherwise, scan till the end of the statement.6835eatToEndOfStatement();6836}68376838const char *BodyStart = StartToken.getLoc().getPointer();6839const char *BodyEnd = EndToken.getLoc().getPointer();6840StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);68416842// We Are Anonymous.6843MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());6844return &MacroLikeBodies.back();6845}68466847bool MasmParser::expandStatement(SMLoc Loc) {6848std::string Body = parseStringTo(AsmToken::EndOfStatement);6849SMLoc EndLoc = getTok().getLoc();68506851MCAsmMacroParameters Parameters;6852MCAsmMacroArguments Arguments;68536854StringMap<std::string> BuiltinValues;6855for (const auto &S : BuiltinSymbolMap) {6856const BuiltinSymbol &Sym = S.getValue();6857if (std::optional<std::string> Text = evaluateBuiltinTextMacro(Sym, Loc)) {6858BuiltinValues[S.getKey().lower()] = std::move(*Text);6859}6860}6861for (const auto &B : BuiltinValues) {6862MCAsmMacroParameter P;6863MCAsmMacroArgument A;6864P.Name = B.getKey();6865P.Required = true;6866A.push_back(AsmToken(AsmToken::String, B.getValue()));68676868Parameters.push_back(std::move(P));6869Arguments.push_back(std::move(A));6870}68716872for (const auto &V : Variables) {6873const Variable &Var = V.getValue();6874if (Var.IsText) {6875MCAsmMacroParameter P;6876MCAsmMacroArgument A;6877P.Name = Var.Name;6878P.Required = true;6879A.push_back(AsmToken(AsmToken::String, Var.TextValue));68806881Parameters.push_back(std::move(P));6882Arguments.push_back(std::move(A));6883}6884}6885MacroLikeBodies.emplace_back(StringRef(), Body, Parameters);6886MCAsmMacro M = MacroLikeBodies.back();68876888// Expand the statement in a new buffer.6889SmallString<80> Buf;6890raw_svector_ostream OS(Buf);6891if (expandMacro(OS, M.Body, M.Parameters, Arguments, M.Locals, EndLoc))6892return true;6893std::unique_ptr<MemoryBuffer> Expansion =6894MemoryBuffer::getMemBufferCopy(OS.str(), "<expansion>");68956896// Jump to the expanded statement and prime the lexer.6897CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Expansion), EndLoc);6898Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());6899EndStatementAtEOFStack.push_back(false);6900Lex();6901return false;6902}69036904void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,6905raw_svector_ostream &OS) {6906instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/getTok().getLoc(), OS);6907}6908void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,6909SMLoc ExitLoc,6910raw_svector_ostream &OS) {6911OS << "endm\n";69126913std::unique_ptr<MemoryBuffer> Instantiation =6914MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");69156916// Create the macro instantiation object and add to the current macro6917// instantiation stack.6918MacroInstantiation *MI = new MacroInstantiation{DirectiveLoc, CurBuffer,6919ExitLoc, TheCondStack.size()};6920ActiveMacros.push_back(MI);69216922// Jump to the macro instantiation and prime the lexer.6923CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());6924Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());6925EndStatementAtEOFStack.push_back(true);6926Lex();6927}69286929/// parseDirectiveRepeat6930/// ::= ("repeat" | "rept") count6931/// body6932/// endm6933bool MasmParser::parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Dir) {6934const MCExpr *CountExpr;6935SMLoc CountLoc = getTok().getLoc();6936if (parseExpression(CountExpr))6937return true;69386939int64_t Count;6940if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {6941return Error(CountLoc, "unexpected token in '" + Dir + "' directive");6942}69436944if (check(Count < 0, CountLoc, "Count is negative") || parseEOL())6945return true;69466947// Lex the repeat definition.6948MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);6949if (!M)6950return true;69516952// Macro instantiation is lexical, unfortunately. We construct a new buffer6953// to hold the macro body with substitutions.6954SmallString<256> Buf;6955raw_svector_ostream OS(Buf);6956while (Count--) {6957if (expandMacro(OS, M->Body, std::nullopt, std::nullopt, M->Locals,6958getTok().getLoc()))6959return true;6960}6961instantiateMacroLikeBody(M, DirectiveLoc, OS);69626963return false;6964}69656966/// parseDirectiveWhile6967/// ::= "while" expression6968/// body6969/// endm6970bool MasmParser::parseDirectiveWhile(SMLoc DirectiveLoc) {6971const MCExpr *CondExpr;6972SMLoc CondLoc = getTok().getLoc();6973if (parseExpression(CondExpr))6974return true;69756976// Lex the repeat definition.6977MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);6978if (!M)6979return true;69806981// Macro instantiation is lexical, unfortunately. We construct a new buffer6982// to hold the macro body with substitutions.6983SmallString<256> Buf;6984raw_svector_ostream OS(Buf);6985int64_t Condition;6986if (!CondExpr->evaluateAsAbsolute(Condition, getStreamer().getAssemblerPtr()))6987return Error(CondLoc, "expected absolute expression in 'while' directive");6988if (Condition) {6989// Instantiate the macro, then resume at this directive to recheck the6990// condition.6991if (expandMacro(OS, M->Body, std::nullopt, std::nullopt, M->Locals,6992getTok().getLoc()))6993return true;6994instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/DirectiveLoc, OS);6995}69966997return false;6998}69997000/// parseDirectiveFor7001/// ::= ("for" | "irp") symbol [":" qualifier], <values>7002/// body7003/// endm7004bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) {7005MCAsmMacroParameter Parameter;7006MCAsmMacroArguments A;7007if (check(parseIdentifier(Parameter.Name),7008"expected identifier in '" + Dir + "' directive"))7009return true;70107011// Parse optional qualifier (default value, or "req")7012if (parseOptionalToken(AsmToken::Colon)) {7013if (parseOptionalToken(AsmToken::Equal)) {7014// Default value7015SMLoc ParamLoc;70167017ParamLoc = Lexer.getLoc();7018if (parseMacroArgument(nullptr, Parameter.Value))7019return true;7020} else {7021SMLoc QualLoc;7022StringRef Qualifier;70237024QualLoc = Lexer.getLoc();7025if (parseIdentifier(Qualifier))7026return Error(QualLoc, "missing parameter qualifier for "7027"'" +7028Parameter.Name + "' in '" + Dir +7029"' directive");70307031if (Qualifier.equals_insensitive("req"))7032Parameter.Required = true;7033else7034return Error(QualLoc,7035Qualifier + " is not a valid parameter qualifier for '" +7036Parameter.Name + "' in '" + Dir + "' directive");7037}7038}70397040if (parseToken(AsmToken::Comma,7041"expected comma in '" + Dir + "' directive") ||7042parseToken(AsmToken::Less,7043"values in '" + Dir +7044"' directive must be enclosed in angle brackets"))7045return true;70467047while (true) {7048A.emplace_back();7049if (parseMacroArgument(&Parameter, A.back(), /*EndTok=*/AsmToken::Greater))7050return addErrorSuffix(" in arguments for '" + Dir + "' directive");70517052// If we see a comma, continue, and allow line continuation.7053if (!parseOptionalToken(AsmToken::Comma))7054break;7055parseOptionalToken(AsmToken::EndOfStatement);7056}70577058if (parseToken(AsmToken::Greater,7059"values in '" + Dir +7060"' directive must be enclosed in angle brackets") ||7061parseEOL())7062return true;70637064// Lex the for definition.7065MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);7066if (!M)7067return true;70687069// Macro instantiation is lexical, unfortunately. We construct a new buffer7070// to hold the macro body with substitutions.7071SmallString<256> Buf;7072raw_svector_ostream OS(Buf);70737074for (const MCAsmMacroArgument &Arg : A) {7075if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))7076return true;7077}70787079instantiateMacroLikeBody(M, DirectiveLoc, OS);70807081return false;7082}70837084/// parseDirectiveForc7085/// ::= ("forc" | "irpc") symbol, <string>7086/// body7087/// endm7088bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) {7089MCAsmMacroParameter Parameter;70907091std::string Argument;7092if (check(parseIdentifier(Parameter.Name),7093"expected identifier in '" + Directive + "' directive") ||7094parseToken(AsmToken::Comma,7095"expected comma in '" + Directive + "' directive"))7096return true;7097if (parseAngleBracketString(Argument)) {7098// Match ml64.exe; treat all characters to end of statement as a string,7099// ignoring comment markers, then discard anything following a space (using7100// the C locale).7101Argument = parseStringTo(AsmToken::EndOfStatement);7102if (getTok().is(AsmToken::EndOfStatement))7103Argument += getTok().getString();7104size_t End = 0;7105for (; End < Argument.size(); ++End) {7106if (isSpace(Argument[End]))7107break;7108}7109Argument.resize(End);7110}7111if (parseEOL())7112return true;71137114// Lex the irpc definition.7115MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);7116if (!M)7117return true;71187119// Macro instantiation is lexical, unfortunately. We construct a new buffer7120// to hold the macro body with substitutions.7121SmallString<256> Buf;7122raw_svector_ostream OS(Buf);71237124StringRef Values(Argument);7125for (std::size_t I = 0, End = Values.size(); I != End; ++I) {7126MCAsmMacroArgument Arg;7127Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1));71287129if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))7130return true;7131}71327133instantiateMacroLikeBody(M, DirectiveLoc, OS);71347135return false;7136}71377138bool MasmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,7139size_t Len) {7140const MCExpr *Value;7141SMLoc ExprLoc = getLexer().getLoc();7142if (parseExpression(Value))7143return true;7144const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);7145if (!MCE)7146return Error(ExprLoc, "unexpected expression in _emit");7147uint64_t IntValue = MCE->getValue();7148if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))7149return Error(ExprLoc, "literal value out of range for directive");71507151Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);7152return false;7153}71547155bool MasmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {7156const MCExpr *Value;7157SMLoc ExprLoc = getLexer().getLoc();7158if (parseExpression(Value))7159return true;7160const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);7161if (!MCE)7162return Error(ExprLoc, "unexpected expression in align");7163uint64_t IntValue = MCE->getValue();7164if (!isPowerOf2_64(IntValue))7165return Error(ExprLoc, "literal value not a power of two greater then zero");71667167Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));7168return false;7169}71707171bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) {7172const SMLoc Loc = getLexer().getLoc();7173std::string RadixStringRaw = parseStringTo(AsmToken::EndOfStatement);7174StringRef RadixString = StringRef(RadixStringRaw).trim();7175unsigned Radix;7176if (RadixString.getAsInteger(10, Radix)) {7177return Error(Loc,7178"radix must be a decimal number in the range 2 to 16; was " +7179RadixString);7180}7181if (Radix < 2 || Radix > 16)7182return Error(Loc, "radix must be in the range 2 to 16; was " +7183std::to_string(Radix));7184getLexer().setMasmDefaultRadix(Radix);7185return false;7186}71877188/// parseDirectiveEcho7189/// ::= "echo" message7190bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) {7191std::string Message = parseStringTo(AsmToken::EndOfStatement);7192llvm::outs() << Message;7193if (!StringRef(Message).ends_with("\n"))7194llvm::outs() << '\n';7195return false;7196}71977198// We are comparing pointers, but the pointers are relative to a single string.7199// Thus, this should always be deterministic.7200static int rewritesSort(const AsmRewrite *AsmRewriteA,7201const AsmRewrite *AsmRewriteB) {7202if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())7203return -1;7204if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())7205return 1;72067207// It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output7208// rewrite to the same location. Make sure the SizeDirective rewrite is7209// performed first, then the Imm/ImmPrefix and finally the Input/Output. This7210// ensures the sort algorithm is stable.7211if (AsmRewritePrecedence[AsmRewriteA->Kind] >7212AsmRewritePrecedence[AsmRewriteB->Kind])7213return -1;72147215if (AsmRewritePrecedence[AsmRewriteA->Kind] <7216AsmRewritePrecedence[AsmRewriteB->Kind])7217return 1;7218llvm_unreachable("Unstable rewrite sort.");7219}72207221bool MasmParser::defineMacro(StringRef Name, StringRef Value) {7222Variable &Var = Variables[Name.lower()];7223if (Var.Name.empty()) {7224Var.Name = Name;7225} else if (Var.Redefinable == Variable::NOT_REDEFINABLE) {7226return Error(SMLoc(), "invalid variable redefinition");7227} else if (Var.Redefinable == Variable::WARN_ON_REDEFINITION &&7228Warning(SMLoc(), "redefining '" + Name +7229"', already defined on the command line")) {7230return true;7231}7232Var.Redefinable = Variable::WARN_ON_REDEFINITION;7233Var.IsText = true;7234Var.TextValue = Value.str();7235return false;7236}72377238bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const {7239const std::pair<StringRef, StringRef> BaseMember = Name.split('.');7240const StringRef Base = BaseMember.first, Member = BaseMember.second;7241return lookUpField(Base, Member, Info);7242}72437244bool MasmParser::lookUpField(StringRef Base, StringRef Member,7245AsmFieldInfo &Info) const {7246if (Base.empty())7247return true;72487249AsmFieldInfo BaseInfo;7250if (Base.contains('.') && !lookUpField(Base, BaseInfo))7251Base = BaseInfo.Type.Name;72527253auto StructIt = Structs.find(Base.lower());7254auto TypeIt = KnownType.find(Base.lower());7255if (TypeIt != KnownType.end()) {7256StructIt = Structs.find(TypeIt->second.Name.lower());7257}7258if (StructIt != Structs.end())7259return lookUpField(StructIt->second, Member, Info);72607261return true;7262}72637264bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member,7265AsmFieldInfo &Info) const {7266if (Member.empty()) {7267Info.Type.Name = Structure.Name;7268Info.Type.Size = Structure.Size;7269Info.Type.ElementSize = Structure.Size;7270Info.Type.Length = 1;7271return false;7272}72737274std::pair<StringRef, StringRef> Split = Member.split('.');7275const StringRef FieldName = Split.first, FieldMember = Split.second;72767277auto StructIt = Structs.find(FieldName.lower());7278if (StructIt != Structs.end())7279return lookUpField(StructIt->second, FieldMember, Info);72807281auto FieldIt = Structure.FieldsByName.find(FieldName.lower());7282if (FieldIt == Structure.FieldsByName.end())7283return true;72847285const FieldInfo &Field = Structure.Fields[FieldIt->second];7286if (FieldMember.empty()) {7287Info.Offset += Field.Offset;7288Info.Type.Size = Field.SizeOf;7289Info.Type.ElementSize = Field.Type;7290Info.Type.Length = Field.LengthOf;7291if (Field.Contents.FT == FT_STRUCT)7292Info.Type.Name = Field.Contents.StructInfo.Structure.Name;7293else7294Info.Type.Name = "";7295return false;7296}72977298if (Field.Contents.FT != FT_STRUCT)7299return true;7300const StructFieldInfo &StructInfo = Field.Contents.StructInfo;73017302if (lookUpField(StructInfo.Structure, FieldMember, Info))7303return true;73047305Info.Offset += Field.Offset;7306return false;7307}73087309bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const {7310unsigned Size = StringSwitch<unsigned>(Name)7311.CasesLower("byte", "db", "sbyte", 1)7312.CasesLower("word", "dw", "sword", 2)7313.CasesLower("dword", "dd", "sdword", 4)7314.CasesLower("fword", "df", 6)7315.CasesLower("qword", "dq", "sqword", 8)7316.CaseLower("real4", 4)7317.CaseLower("real8", 8)7318.CaseLower("real10", 10)7319.Default(0);7320if (Size) {7321Info.Name = Name;7322Info.ElementSize = Size;7323Info.Length = 1;7324Info.Size = Size;7325return false;7326}73277328auto StructIt = Structs.find(Name.lower());7329if (StructIt != Structs.end()) {7330const StructInfo &Structure = StructIt->second;7331Info.Name = Name;7332Info.ElementSize = Structure.Size;7333Info.Length = 1;7334Info.Size = Structure.Size;7335return false;7336}73377338return true;7339}73407341bool MasmParser::parseMSInlineAsm(7342std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs,7343SmallVectorImpl<std::pair<void *, bool>> &OpDecls,7344SmallVectorImpl<std::string> &Constraints,7345SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,7346const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {7347SmallVector<void *, 4> InputDecls;7348SmallVector<void *, 4> OutputDecls;7349SmallVector<bool, 4> InputDeclsAddressOf;7350SmallVector<bool, 4> OutputDeclsAddressOf;7351SmallVector<std::string, 4> InputConstraints;7352SmallVector<std::string, 4> OutputConstraints;7353SmallVector<unsigned, 4> ClobberRegs;73547355SmallVector<AsmRewrite, 4> AsmStrRewrites;73567357// Prime the lexer.7358Lex();73597360// While we have input, parse each statement.7361unsigned InputIdx = 0;7362unsigned OutputIdx = 0;7363while (getLexer().isNot(AsmToken::Eof)) {7364// Parse curly braces marking block start/end.7365if (parseCurlyBlockScope(AsmStrRewrites))7366continue;73677368ParseStatementInfo Info(&AsmStrRewrites);7369bool StatementErr = parseStatement(Info, &SI);73707371if (StatementErr || Info.ParseError) {7372// Emit pending errors if any exist.7373printPendingErrors();7374return true;7375}73767377// No pending error should exist here.7378assert(!hasPendingError() && "unexpected error from parseStatement");73797380if (Info.Opcode == ~0U)7381continue;73827383const MCInstrDesc &Desc = MII->get(Info.Opcode);73847385// Build the list of clobbers, outputs and inputs.7386for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {7387MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];73887389// Register operand.7390if (Operand.isReg() && !Operand.needAddressOf() &&7391!getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) {7392unsigned NumDefs = Desc.getNumDefs();7393// Clobber.7394if (NumDefs && Operand.getMCOperandNum() < NumDefs)7395ClobberRegs.push_back(Operand.getReg());7396continue;7397}73987399// Expr/Input or Output.7400StringRef SymName = Operand.getSymName();7401if (SymName.empty())7402continue;74037404void *OpDecl = Operand.getOpDecl();7405if (!OpDecl)7406continue;74077408StringRef Constraint = Operand.getConstraint();7409if (Operand.isImm()) {7410// Offset as immediate.7411if (Operand.isOffsetOfLocal())7412Constraint = "r";7413else7414Constraint = "i";7415}74167417bool isOutput = (i == 1) && Desc.mayStore();7418SMLoc Start = SMLoc::getFromPointer(SymName.data());7419if (isOutput) {7420++InputIdx;7421OutputDecls.push_back(OpDecl);7422OutputDeclsAddressOf.push_back(Operand.needAddressOf());7423OutputConstraints.push_back(("=" + Constraint).str());7424AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());7425} else {7426InputDecls.push_back(OpDecl);7427InputDeclsAddressOf.push_back(Operand.needAddressOf());7428InputConstraints.push_back(Constraint.str());7429if (Desc.operands()[i - 1].isBranchTarget())7430AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());7431else7432AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());7433}7434}74357436// Consider implicit defs to be clobbers. Think of cpuid and push.7437llvm::append_range(ClobberRegs, Desc.implicit_defs());7438}74397440// Set the number of Outputs and Inputs.7441NumOutputs = OutputDecls.size();7442NumInputs = InputDecls.size();74437444// Set the unique clobbers.7445array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());7446ClobberRegs.erase(llvm::unique(ClobberRegs), ClobberRegs.end());7447Clobbers.assign(ClobberRegs.size(), std::string());7448for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {7449raw_string_ostream OS(Clobbers[I]);7450IP->printRegName(OS, ClobberRegs[I]);7451}74527453// Merge the various outputs and inputs. Output are expected first.7454if (NumOutputs || NumInputs) {7455unsigned NumExprs = NumOutputs + NumInputs;7456OpDecls.resize(NumExprs);7457Constraints.resize(NumExprs);7458for (unsigned i = 0; i < NumOutputs; ++i) {7459OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);7460Constraints[i] = OutputConstraints[i];7461}7462for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {7463OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);7464Constraints[j] = InputConstraints[i];7465}7466}74677468// Build the IR assembly string.7469std::string AsmStringIR;7470raw_string_ostream OS(AsmStringIR);7471StringRef ASMString =7472SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();7473const char *AsmStart = ASMString.begin();7474const char *AsmEnd = ASMString.end();7475array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);7476for (auto I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) {7477const AsmRewrite &AR = *I;7478// Check if this has already been covered by another rewrite...7479if (AR.Done)7480continue;7481AsmRewriteKind Kind = AR.Kind;74827483const char *Loc = AR.Loc.getPointer();7484assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");74857486// Emit everything up to the immediate/expression.7487if (unsigned Len = Loc - AsmStart)7488OS << StringRef(AsmStart, Len);74897490// Skip the original expression.7491if (Kind == AOK_Skip) {7492AsmStart = Loc + AR.Len;7493continue;7494}74957496unsigned AdditionalSkip = 0;7497// Rewrite expressions in $N notation.7498switch (Kind) {7499default:7500break;7501case AOK_IntelExpr:7502assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");7503if (AR.IntelExp.NeedBracs)7504OS << "[";7505if (AR.IntelExp.hasBaseReg())7506OS << AR.IntelExp.BaseReg;7507if (AR.IntelExp.hasIndexReg())7508OS << (AR.IntelExp.hasBaseReg() ? " + " : "")7509<< AR.IntelExp.IndexReg;7510if (AR.IntelExp.Scale > 1)7511OS << " * $$" << AR.IntelExp.Scale;7512if (AR.IntelExp.hasOffset()) {7513if (AR.IntelExp.hasRegs())7514OS << " + ";7515// Fuse this rewrite with a rewrite of the offset name, if present.7516StringRef OffsetName = AR.IntelExp.OffsetName;7517SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());7518size_t OffsetLen = OffsetName.size();7519auto rewrite_it = std::find_if(7520I, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) {7521return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&7522(FusingAR.Kind == AOK_Input ||7523FusingAR.Kind == AOK_CallInput);7524});7525if (rewrite_it == AsmStrRewrites.end()) {7526OS << "offset " << OffsetName;7527} else if (rewrite_it->Kind == AOK_CallInput) {7528OS << "${" << InputIdx++ << ":P}";7529rewrite_it->Done = true;7530} else {7531OS << '$' << InputIdx++;7532rewrite_it->Done = true;7533}7534}7535if (AR.IntelExp.Imm || AR.IntelExp.emitImm())7536OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;7537if (AR.IntelExp.NeedBracs)7538OS << "]";7539break;7540case AOK_Label:7541OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;7542break;7543case AOK_Input:7544OS << '$' << InputIdx++;7545break;7546case AOK_CallInput:7547OS << "${" << InputIdx++ << ":P}";7548break;7549case AOK_Output:7550OS << '$' << OutputIdx++;7551break;7552case AOK_SizeDirective:7553switch (AR.Val) {7554default: break;7555case 8: OS << "byte ptr "; break;7556case 16: OS << "word ptr "; break;7557case 32: OS << "dword ptr "; break;7558case 64: OS << "qword ptr "; break;7559case 80: OS << "xword ptr "; break;7560case 128: OS << "xmmword ptr "; break;7561case 256: OS << "ymmword ptr "; break;7562}7563break;7564case AOK_Emit:7565OS << ".byte";7566break;7567case AOK_Align: {7568// MS alignment directives are measured in bytes. If the native assembler7569// measures alignment in bytes, we can pass it straight through.7570OS << ".align";7571if (getContext().getAsmInfo()->getAlignmentIsInBytes())7572break;75737574// Alignment is in log2 form, so print that instead and skip the original7575// immediate.7576unsigned Val = AR.Val;7577OS << ' ' << Val;7578assert(Val < 10 && "Expected alignment less then 2^10.");7579AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;7580break;7581}7582case AOK_EVEN:7583OS << ".even";7584break;7585case AOK_EndOfStatement:7586OS << "\n\t";7587break;7588}75897590// Skip the original expression.7591AsmStart = Loc + AR.Len + AdditionalSkip;7592}75937594// Emit the remainder of the asm string.7595if (AsmStart != AsmEnd)7596OS << StringRef(AsmStart, AsmEnd - AsmStart);75977598AsmString = OS.str();7599return false;7600}76017602void MasmParser::initializeBuiltinSymbolMap() {7603// Numeric built-ins (supported in all versions)7604BuiltinSymbolMap["@version"] = BI_VERSION;7605BuiltinSymbolMap["@line"] = BI_LINE;76067607// Text built-ins (supported in all versions)7608BuiltinSymbolMap["@date"] = BI_DATE;7609BuiltinSymbolMap["@time"] = BI_TIME;7610BuiltinSymbolMap["@filecur"] = BI_FILECUR;7611BuiltinSymbolMap["@filename"] = BI_FILENAME;7612BuiltinSymbolMap["@curseg"] = BI_CURSEG;76137614// Some built-ins exist only for MASM32 (32-bit x86)7615if (getContext().getSubtargetInfo()->getTargetTriple().getArch() ==7616Triple::x86) {7617// Numeric built-ins7618// BuiltinSymbolMap["@cpu"] = BI_CPU;7619// BuiltinSymbolMap["@interface"] = BI_INTERFACE;7620// BuiltinSymbolMap["@wordsize"] = BI_WORDSIZE;7621// BuiltinSymbolMap["@codesize"] = BI_CODESIZE;7622// BuiltinSymbolMap["@datasize"] = BI_DATASIZE;7623// BuiltinSymbolMap["@model"] = BI_MODEL;76247625// Text built-ins7626// BuiltinSymbolMap["@code"] = BI_CODE;7627// BuiltinSymbolMap["@data"] = BI_DATA;7628// BuiltinSymbolMap["@fardata?"] = BI_FARDATA;7629// BuiltinSymbolMap["@stack"] = BI_STACK;7630}7631}76327633const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,7634SMLoc StartLoc) {7635switch (Symbol) {7636default:7637return nullptr;7638case BI_VERSION:7639// Match a recent version of ML.EXE.7640return MCConstantExpr::create(1427, getContext());7641case BI_LINE: {7642int64_t Line;7643if (ActiveMacros.empty())7644Line = SrcMgr.FindLineNumber(StartLoc, CurBuffer);7645else7646Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,7647ActiveMacros.front()->ExitBuffer);7648return MCConstantExpr::create(Line, getContext());7649}7650}7651llvm_unreachable("unhandled built-in symbol");7652}76537654std::optional<std::string>7655MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {7656switch (Symbol) {7657default:7658return {};7659case BI_DATE: {7660// Current local date, formatted MM/DD/YY7661char TmpBuffer[sizeof("mm/dd/yy")];7662const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%D", &TM);7663return std::string(TmpBuffer, Len);7664}7665case BI_TIME: {7666// Current local time, formatted HH:MM:SS (24-hour clock)7667char TmpBuffer[sizeof("hh:mm:ss")];7668const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%T", &TM);7669return std::string(TmpBuffer, Len);7670}7671case BI_FILECUR:7672return SrcMgr7673.getMemoryBuffer(7674ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)7675->getBufferIdentifier()7676.str();7677case BI_FILENAME:7678return sys::path::stem(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())7679->getBufferIdentifier())7680.upper();7681case BI_CURSEG:7682return getStreamer().getCurrentSectionOnly()->getName().str();7683}7684llvm_unreachable("unhandled built-in symbol");7685}76867687/// Create an MCAsmParser instance.7688MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,7689MCStreamer &Out, const MCAsmInfo &MAI,7690struct tm TM, unsigned CB) {7691return new MasmParser(SM, C, Out, MAI, TM, CB);7692}769376947695