6434 lines · cpp
1//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class implements a parser for assembly files similar to gas syntax.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/APFloat.h"14#include "llvm/ADT/APInt.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/SmallSet.h"18#include "llvm/ADT/SmallString.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/ADT/StringMap.h"22#include "llvm/ADT/StringRef.h"23#include "llvm/ADT/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/MCAsmParser.h"38#include "llvm/MC/MCParser/MCAsmParserExtension.h"39#include "llvm/MC/MCParser/MCAsmParserUtils.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/MCSymbol.h"46#include "llvm/MC/MCSymbolMachO.h"47#include "llvm/MC/MCSymbolWasm.h"48#include "llvm/MC/MCTargetOptions.h"49#include "llvm/MC/MCValue.h"50#include "llvm/Support/Base64.h"51#include "llvm/Support/Casting.h"52#include "llvm/Support/CommandLine.h"53#include "llvm/Support/ErrorHandling.h"54#include "llvm/Support/MD5.h"55#include "llvm/Support/MathExtras.h"56#include "llvm/Support/MemoryBuffer.h"57#include "llvm/Support/SMLoc.h"58#include "llvm/Support/SourceMgr.h"59#include "llvm/Support/raw_ostream.h"60#include <algorithm>61#include <cassert>62#include <cctype>63#include <climits>64#include <cstddef>65#include <cstdint>66#include <deque>67#include <memory>68#include <optional>69#include <sstream>70#include <string>71#include <tuple>72#include <utility>73#include <vector>74 75using namespace llvm;76 77MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default;78 79namespace {80 81/// Helper types for tracking macro definitions.82typedef std::vector<AsmToken> MCAsmMacroArgument;83typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;84 85/// Helper class for storing information about an active macro86/// instantiation.87struct MacroInstantiation {88 /// The location of the instantiation.89 SMLoc InstantiationLoc;90 91 /// The buffer where parsing should resume upon instantiation completion.92 unsigned ExitBuffer;93 94 /// The location where parsing should resume upon instantiation completion.95 SMLoc ExitLoc;96 97 /// The depth of TheCondStack at the start of the instantiation.98 size_t CondStackDepth;99};100 101struct ParseStatementInfo {102 /// The parsed operands from the last parsed statement.103 SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;104 105 /// The opcode from the last parsed instruction.106 unsigned Opcode = ~0U;107 108 /// Was there an error parsing the inline assembly?109 bool ParseError = false;110 111 SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;112 113 ParseStatementInfo() = delete;114 ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)115 : AsmRewrites(rewrites) {}116};117 118/// The concrete assembly parser instance.119class AsmParser : public MCAsmParser {120private:121 SourceMgr::DiagHandlerTy SavedDiagHandler;122 void *SavedDiagContext;123 std::unique_ptr<MCAsmParserExtension> PlatformParser;124 SMLoc StartTokLoc;125 std::optional<SMLoc> CFIStartProcLoc;126 127 /// This is the current buffer index we're lexing from as managed by the128 /// SourceMgr object.129 unsigned CurBuffer;130 131 AsmCond TheCondState;132 std::vector<AsmCond> TheCondStack;133 134 /// maps directive names to handler methods in parser135 /// extensions. Extensions register themselves in this map by calling136 /// addDirectiveHandler.137 StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;138 139 /// Stack of active macro instantiations.140 std::vector<MacroInstantiation*> ActiveMacros;141 142 /// List of bodies of anonymous macros.143 std::deque<MCAsmMacro> MacroLikeBodies;144 145 /// Boolean tracking whether macro substitution is enabled.146 unsigned MacrosEnabledFlag : 1;147 148 /// Keeps track of how many .macro's have been instantiated.149 unsigned NumOfMacroInstantiations = 0;150 151 /// The values from the last parsed cpp hash file line comment if any.152 struct CppHashInfoTy {153 StringRef Filename;154 int64_t LineNumber;155 SMLoc Loc;156 unsigned Buf;157 CppHashInfoTy() : LineNumber(0), Buf(0) {}158 };159 CppHashInfoTy CppHashInfo;160 161 /// Have we seen any file line comment.162 bool HadCppHashFilename = false;163 164 /// List of forward directional labels for diagnosis at the end.165 SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;166 167 SmallSet<StringRef, 2> LTODiscardSymbols;168 169 /// AssemblerDialect. ~OU means unset value and use value provided by MAI.170 unsigned AssemblerDialect = ~0U;171 172 /// is Darwin compatibility enabled?173 bool IsDarwin = false;174 175 /// Are we parsing ms-style inline assembly?176 bool ParsingMSInlineAsm = false;177 178 /// Did we already inform the user about inconsistent MD5 usage?179 bool ReportedInconsistentMD5 = false;180 181 // Is alt macro mode enabled.182 bool AltMacroMode = false;183 184protected:185 virtual bool parseStatement(ParseStatementInfo &Info,186 MCAsmParserSemaCallback *SI);187 188 /// This routine uses the target specific ParseInstruction function to189 /// parse an instruction into Operands, and then call the target specific190 /// MatchAndEmit function to match and emit the instruction.191 bool parseAndMatchAndEmitTargetInstruction(ParseStatementInfo &Info,192 StringRef IDVal, AsmToken ID,193 SMLoc IDLoc);194 195 /// Should we emit DWARF describing this assembler source? (Returns false if196 /// the source has .file directives, which means we don't want to generate197 /// info describing the assembler source itself.)198 bool enabledGenDwarfForAssembly();199 200public:201 AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,202 const MCAsmInfo &MAI, unsigned CB);203 AsmParser(const AsmParser &) = delete;204 AsmParser &operator=(const AsmParser &) = delete;205 ~AsmParser() override;206 207 bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;208 209 void addDirectiveHandler(StringRef Directive,210 ExtensionDirectiveHandler Handler) override {211 ExtensionDirectiveMap[Directive] = Handler;212 }213 214 void addAliasForDirective(StringRef Directive, StringRef Alias) override {215 DirectiveKindMap[Directive.lower()] = DirectiveKindMap[Alias.lower()];216 }217 218 /// @name MCAsmParser Interface219 /// {220 221 CodeViewContext &getCVContext() { return Ctx.getCVContext(); }222 223 unsigned getAssemblerDialect() override {224 if (AssemblerDialect == ~0U)225 return MAI.getAssemblerDialect();226 else227 return AssemblerDialect;228 }229 void setAssemblerDialect(unsigned i) override {230 AssemblerDialect = i;231 }232 233 void Note(SMLoc L, const Twine &Msg, SMRange Range = {}) override;234 bool Warning(SMLoc L, const Twine &Msg, SMRange Range = {}) override;235 bool printError(SMLoc L, const Twine &Msg, SMRange Range = {}) override;236 237 const AsmToken &Lex() override;238 239 void setParsingMSInlineAsm(bool V) override {240 ParsingMSInlineAsm = V;241 // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and242 // hex integer literals.243 Lexer.setLexMasmIntegers(V);244 }245 bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; }246 247 bool discardLTOSymbol(StringRef Name) const override {248 return LTODiscardSymbols.contains(Name);249 }250 251 bool parseMSInlineAsm(std::string &AsmString, unsigned &NumOutputs,252 unsigned &NumInputs,253 SmallVectorImpl<std::pair<void *, bool>> &OpDecls,254 SmallVectorImpl<std::string> &Constraints,255 SmallVectorImpl<std::string> &Clobbers,256 const MCInstrInfo *MII, MCInstPrinter *IP,257 MCAsmParserSemaCallback &SI) override;258 259 bool parseExpression(const MCExpr *&Res);260 bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;261 bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,262 AsmTypeInfo *TypeInfo) override;263 bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;264 bool parseAbsoluteExpression(int64_t &Res) override;265 266 /// Parse a floating point expression using the float \p Semantics267 /// and set \p Res to the value.268 bool parseRealValue(const fltSemantics &Semantics, APInt &Res);269 270 /// Parse an identifier or string (as a quoted identifier)271 /// and set \p Res to the identifier contents.272 bool parseIdentifier(StringRef &Res) override;273 void eatToEndOfStatement() override;274 275 bool checkForValidSection() override;276 277 /// }278 279private:280 bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);281 bool parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo = true);282 283 void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body,284 ArrayRef<MCAsmMacroParameter> Parameters);285 bool expandMacro(raw_svector_ostream &OS, MCAsmMacro &Macro,286 ArrayRef<MCAsmMacroParameter> Parameters,287 ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable);288 289 /// Are macros enabled in the parser?290 bool areMacrosEnabled() {return MacrosEnabledFlag;}291 292 /// Control a flag in the parser that enables or disables macros.293 void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;}294 295 /// Are we inside a macro instantiation?296 bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}297 298 /// Handle entry to macro instantiation.299 ///300 /// \param M The macro.301 /// \param NameLoc Instantiation location.302 bool handleMacroEntry(MCAsmMacro *M, SMLoc NameLoc);303 304 /// Handle exit from macro instantiation.305 void handleMacroExit();306 307 /// Extract AsmTokens for a macro argument.308 bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg);309 310 /// Parse all macro arguments for a given macro.311 bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A);312 313 void printMacroInstantiations();314 void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,315 SMRange Range = {}) const {316 ArrayRef<SMRange> Ranges(Range);317 SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);318 }319 static void DiagHandler(const SMDiagnostic &Diag, void *Context);320 321 /// Enter the specified file. This returns true on failure.322 bool enterIncludeFile(const std::string &Filename);323 324 /// Process the specified file for the .incbin directive.325 /// This returns true on failure.326 bool processIncbinFile(const std::string &Filename, int64_t Skip = 0,327 const MCExpr *Count = nullptr, SMLoc Loc = SMLoc());328 329 /// Reset the current lexer position to that given by \p Loc. The330 /// current token is not set; clients should ensure Lex() is called331 /// subsequently.332 ///333 /// \param InBuffer If not 0, should be the known buffer id that contains the334 /// location.335 void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0);336 337 /// Parse up to the end of statement and a return the contents from the338 /// current token until the end of the statement; the current token on exit339 /// will be either the EndOfStatement or EOF.340 StringRef parseStringToEndOfStatement() override;341 342 /// Parse until the end of a statement or a comma is encountered,343 /// return the contents from the current token up to the end or comma.344 StringRef parseStringToComma();345 346 enum class AssignmentKind {347 Set,348 Equiv,349 Equal,350 LTOSetConditional,351 };352 353 bool parseAssignment(StringRef Name, AssignmentKind Kind);354 355 unsigned getBinOpPrecedence(AsmToken::TokenKind K,356 MCBinaryExpr::Opcode &Kind);357 358 bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);359 bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);360 bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);361 362 bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);363 364 bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);365 bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);366 367 // Generic (target and platform independent) directive parsing.368 enum DirectiveKind {369 DK_NO_DIRECTIVE, // Placeholder370 DK_SET,371 DK_EQU,372 DK_EQUIV,373 DK_ASCII,374 DK_ASCIZ,375 DK_STRING,376 DK_BYTE,377 DK_SHORT,378 DK_RELOC,379 DK_VALUE,380 DK_2BYTE,381 DK_LONG,382 DK_INT,383 DK_4BYTE,384 DK_QUAD,385 DK_8BYTE,386 DK_OCTA,387 DK_DC,388 DK_DC_A,389 DK_DC_B,390 DK_DC_D,391 DK_DC_L,392 DK_DC_S,393 DK_DC_W,394 DK_DC_X,395 DK_DCB,396 DK_DCB_B,397 DK_DCB_D,398 DK_DCB_L,399 DK_DCB_S,400 DK_DCB_W,401 DK_DCB_X,402 DK_DS,403 DK_DS_B,404 DK_DS_D,405 DK_DS_L,406 DK_DS_P,407 DK_DS_S,408 DK_DS_W,409 DK_DS_X,410 DK_SINGLE,411 DK_FLOAT,412 DK_DOUBLE,413 DK_ALIGN,414 DK_ALIGN32,415 DK_BALIGN,416 DK_BALIGNW,417 DK_BALIGNL,418 DK_P2ALIGN,419 DK_P2ALIGNW,420 DK_P2ALIGNL,421 DK_ORG,422 DK_FILL,423 DK_ENDR,424 DK_ZERO,425 DK_EXTERN,426 DK_GLOBL,427 DK_GLOBAL,428 DK_LAZY_REFERENCE,429 DK_NO_DEAD_STRIP,430 DK_SYMBOL_RESOLVER,431 DK_PRIVATE_EXTERN,432 DK_REFERENCE,433 DK_WEAK_DEFINITION,434 DK_WEAK_REFERENCE,435 DK_WEAK_DEF_CAN_BE_HIDDEN,436 DK_COLD,437 DK_COMM,438 DK_COMMON,439 DK_LCOMM,440 DK_ABORT,441 DK_INCLUDE,442 DK_INCBIN,443 DK_CODE16,444 DK_CODE16GCC,445 DK_REPT,446 DK_IRP,447 DK_IRPC,448 DK_IF,449 DK_IFEQ,450 DK_IFGE,451 DK_IFGT,452 DK_IFLE,453 DK_IFLT,454 DK_IFNE,455 DK_IFB,456 DK_IFNB,457 DK_IFC,458 DK_IFEQS,459 DK_IFNC,460 DK_IFNES,461 DK_IFDEF,462 DK_IFNDEF,463 DK_IFNOTDEF,464 DK_ELSEIF,465 DK_ELSE,466 DK_ENDIF,467 DK_SPACE,468 DK_SKIP,469 DK_FILE,470 DK_LINE,471 DK_LOC,472 DK_LOC_LABEL,473 DK_STABS,474 DK_CV_FILE,475 DK_CV_FUNC_ID,476 DK_CV_INLINE_SITE_ID,477 DK_CV_LOC,478 DK_CV_LINETABLE,479 DK_CV_INLINE_LINETABLE,480 DK_CV_DEF_RANGE,481 DK_CV_STRINGTABLE,482 DK_CV_STRING,483 DK_CV_FILECHECKSUMS,484 DK_CV_FILECHECKSUM_OFFSET,485 DK_CV_FPO_DATA,486 DK_CFI_SECTIONS,487 DK_CFI_STARTPROC,488 DK_CFI_ENDPROC,489 DK_CFI_DEF_CFA,490 DK_CFI_DEF_CFA_OFFSET,491 DK_CFI_ADJUST_CFA_OFFSET,492 DK_CFI_DEF_CFA_REGISTER,493 DK_CFI_LLVM_DEF_ASPACE_CFA,494 DK_CFI_OFFSET,495 DK_CFI_REL_OFFSET,496 DK_CFI_PERSONALITY,497 DK_CFI_LSDA,498 DK_CFI_REMEMBER_STATE,499 DK_CFI_RESTORE_STATE,500 DK_CFI_SAME_VALUE,501 DK_CFI_RESTORE,502 DK_CFI_ESCAPE,503 DK_CFI_RETURN_COLUMN,504 DK_CFI_SIGNAL_FRAME,505 DK_CFI_UNDEFINED,506 DK_CFI_REGISTER,507 DK_CFI_WINDOW_SAVE,508 DK_CFI_LABEL,509 DK_CFI_B_KEY_FRAME,510 DK_CFI_VAL_OFFSET,511 DK_MACROS_ON,512 DK_MACROS_OFF,513 DK_ALTMACRO,514 DK_NOALTMACRO,515 DK_MACRO,516 DK_EXITM,517 DK_ENDM,518 DK_ENDMACRO,519 DK_PURGEM,520 DK_SLEB128,521 DK_ULEB128,522 DK_ERR,523 DK_ERROR,524 DK_WARNING,525 DK_PRINT,526 DK_ADDRSIG,527 DK_ADDRSIG_SYM,528 DK_PSEUDO_PROBE,529 DK_LTO_DISCARD,530 DK_LTO_SET_CONDITIONAL,531 DK_CFI_MTE_TAGGED_FRAME,532 DK_MEMTAG,533 DK_BASE64,534 DK_END535 };536 537 /// Maps directive name --> DirectiveKind enum, for538 /// directives parsed by this class.539 StringMap<DirectiveKind> DirectiveKindMap;540 541 // Codeview def_range type parsing.542 enum CVDefRangeType {543 CVDR_DEFRANGE = 0, // Placeholder544 CVDR_DEFRANGE_REGISTER,545 CVDR_DEFRANGE_FRAMEPOINTER_REL,546 CVDR_DEFRANGE_SUBFIELD_REGISTER,547 CVDR_DEFRANGE_REGISTER_REL548 };549 550 /// Maps Codeview def_range types --> CVDefRangeType enum, for551 /// Codeview def_range types parsed by this class.552 StringMap<CVDefRangeType> CVDefRangeTypeMap;553 554 // ".ascii", ".asciz", ".string"555 bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);556 bool parseDirectiveBase64(); // ".base64"557 bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc"558 bool parseDirectiveValue(StringRef IDVal,559 unsigned Size); // ".byte", ".long", ...560 bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ...561 bool parseDirectiveRealValue(StringRef IDVal,562 const fltSemantics &); // ".single", ...563 bool parseDirectiveFill(); // ".fill"564 bool parseDirectiveZero(); // ".zero"565 // ".set", ".equ", ".equiv", ".lto_set_conditional"566 bool parseDirectiveSet(StringRef IDVal, AssignmentKind Kind);567 bool parseDirectiveOrg(); // ".org"568 // ".align{,32}", ".p2align{,w,l}"569 bool parseDirectiveAlign(bool IsPow2, uint8_t ValueSize);570 571 // ".file", ".line", ".loc", ".loc_label", ".stabs"572 bool parseDirectiveFile(SMLoc DirectiveLoc);573 bool parseDirectiveLine();574 bool parseDirectiveLoc();575 bool parseDirectiveLocLabel(SMLoc DirectiveLoc);576 bool parseDirectiveStabs();577 578 // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",579 // ".cv_inline_linetable", ".cv_def_range", ".cv_string"580 bool parseDirectiveCVFile();581 bool parseDirectiveCVFuncId();582 bool parseDirectiveCVInlineSiteId();583 bool parseDirectiveCVLoc();584 bool parseDirectiveCVLinetable();585 bool parseDirectiveCVInlineLinetable();586 bool parseDirectiveCVDefRange();587 bool parseDirectiveCVString();588 bool parseDirectiveCVStringTable();589 bool parseDirectiveCVFileChecksums();590 bool parseDirectiveCVFileChecksumOffset();591 bool parseDirectiveCVFPOData();592 593 // .cfi directives594 bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);595 bool parseDirectiveCFIWindowSave(SMLoc DirectiveLoc);596 bool parseDirectiveCFISections();597 bool parseDirectiveCFIStartProc();598 bool parseDirectiveCFIEndProc();599 bool parseDirectiveCFIDefCfaOffset(SMLoc DirectiveLoc);600 bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);601 bool parseDirectiveCFIAdjustCfaOffset(SMLoc DirectiveLoc);602 bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);603 bool parseDirectiveCFILLVMDefAspaceCfa(SMLoc DirectiveLoc);604 bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);605 bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);606 bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);607 bool parseDirectiveCFIRememberState(SMLoc DirectiveLoc);608 bool parseDirectiveCFIRestoreState(SMLoc DirectiveLoc);609 bool parseDirectiveCFISameValue(SMLoc DirectiveLoc);610 bool parseDirectiveCFIRestore(SMLoc DirectiveLoc);611 bool parseDirectiveCFIEscape(SMLoc DirectiveLoc);612 bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);613 bool parseDirectiveCFISignalFrame(SMLoc DirectiveLoc);614 bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);615 bool parseDirectiveCFILabel(SMLoc DirectiveLoc);616 bool parseDirectiveCFIValOffset(SMLoc DirectiveLoc);617 618 // macro directives619 bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);620 bool parseDirectiveExitMacro(StringRef Directive);621 bool parseDirectiveEndMacro(StringRef Directive);622 bool parseDirectiveMacro(SMLoc DirectiveLoc);623 bool parseDirectiveMacrosOnOff(StringRef Directive);624 // alternate macro mode directives625 bool parseDirectiveAltmacro(StringRef Directive);626 627 // ".space", ".skip"628 bool parseDirectiveSpace(StringRef IDVal);629 630 // ".dcb"631 bool parseDirectiveDCB(StringRef IDVal, unsigned Size);632 bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &);633 // ".ds"634 bool parseDirectiveDS(StringRef IDVal, unsigned Size);635 636 // .sleb128 (Signed=true) and .uleb128 (Signed=false)637 bool parseDirectiveLEB128(bool Signed);638 639 /// Parse a directive like ".globl" which640 /// accepts a single symbol (which should be a label or an external).641 bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);642 643 bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"644 645 bool parseDirectiveAbort(SMLoc DirectiveLoc); // ".abort"646 bool parseDirectiveInclude(); // ".include"647 bool parseDirectiveIncbin(); // ".incbin"648 649 // ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne"650 bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);651 // ".ifb" or ".ifnb", depending on ExpectBlank.652 bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);653 // ".ifc" or ".ifnc", depending on ExpectEqual.654 bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual);655 // ".ifeqs" or ".ifnes", depending on ExpectEqual.656 bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual);657 // ".ifdef" or ".ifndef", depending on expect_defined658 bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);659 bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif"660 bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else"661 bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif662 bool parseEscapedString(std::string &Data) override;663 bool parseAngleBracketString(std::string &Data) override;664 665 // Macro-like directives666 MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);667 void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,668 raw_svector_ostream &OS);669 bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive);670 bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"671 bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"672 bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"673 674 // "_emit" or "__emit"675 bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,676 size_t Len);677 678 // "align"679 bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);680 681 // "end"682 bool parseDirectiveEnd(SMLoc DirectiveLoc);683 684 // ".err" or ".error"685 bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage);686 687 // ".warning"688 bool parseDirectiveWarning(SMLoc DirectiveLoc);689 690 // .print <double-quotes-string>691 bool parseDirectivePrint(SMLoc DirectiveLoc);692 693 // .pseudoprobe694 bool parseDirectivePseudoProbe();695 696 // ".lto_discard"697 bool parseDirectiveLTODiscard();698 699 // Directives to support address-significance tables.700 bool parseDirectiveAddrsig();701 bool parseDirectiveAddrsigSym();702 703 void initializeDirectiveKindMap();704 void initializeCVDefRangeTypeMap();705};706 707class HLASMAsmParser final : public AsmParser {708private:709 AsmLexer &Lexer;710 MCStreamer &Out;711 712 void lexLeadingSpaces() {713 while (Lexer.is(AsmToken::Space))714 Lexer.Lex();715 }716 717 bool parseAsHLASMLabel(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI);718 bool parseAsMachineInstruction(ParseStatementInfo &Info,719 MCAsmParserSemaCallback *SI);720 721public:722 HLASMAsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,723 const MCAsmInfo &MAI, unsigned CB = 0)724 : AsmParser(SM, Ctx, Out, MAI, CB), Lexer(getLexer()), Out(Out) {725 Lexer.setSkipSpace(false);726 Lexer.setAllowHashInIdentifier(true);727 Lexer.setLexHLASMIntegers(true);728 Lexer.setLexHLASMStrings(true);729 }730 731 ~HLASMAsmParser() override { Lexer.setSkipSpace(true); }732 733 bool parseStatement(ParseStatementInfo &Info,734 MCAsmParserSemaCallback *SI) override;735};736 737} // end anonymous namespace738 739namespace llvm {740 741extern cl::opt<unsigned> AsmMacroMaxNestingDepth;742 743} // end namespace llvm744 745AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,746 const MCAsmInfo &MAI, unsigned CB = 0)747 : MCAsmParser(Ctx, Out, SM, MAI), CurBuffer(CB ? CB : SM.getMainFileID()),748 MacrosEnabledFlag(true) {749 HadError = false;750 // Save the old handler.751 SavedDiagHandler = SrcMgr.getDiagHandler();752 SavedDiagContext = SrcMgr.getDiagContext();753 // Set our own handler which calls the saved handler.754 SrcMgr.setDiagHandler(DiagHandler, this);755 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());756 // Make MCStreamer aware of the StartTokLoc for locations in diagnostics.757 Out.setStartTokLocPtr(&StartTokLoc);758 759 // Initialize the platform / file format parser.760 switch (Ctx.getObjectFileType()) {761 case MCContext::IsCOFF:762 PlatformParser.reset(createCOFFAsmParser());763 break;764 case MCContext::IsMachO:765 PlatformParser.reset(createDarwinAsmParser());766 IsDarwin = true;767 break;768 case MCContext::IsELF:769 PlatformParser.reset(createELFAsmParser());770 break;771 case MCContext::IsGOFF:772 PlatformParser.reset(createGOFFAsmParser());773 break;774 case MCContext::IsSPIRV:775 report_fatal_error(776 "Need to implement createSPIRVAsmParser for SPIRV format.");777 break;778 case MCContext::IsWasm:779 PlatformParser.reset(createWasmAsmParser());780 break;781 case MCContext::IsXCOFF:782 PlatformParser.reset(createXCOFFAsmParser());783 break;784 case MCContext::IsDXContainer:785 report_fatal_error("DXContainer is not supported yet");786 break;787 }788 789 PlatformParser->Initialize(*this);790 initializeDirectiveKindMap();791 initializeCVDefRangeTypeMap();792}793 794AsmParser::~AsmParser() {795 assert((HadError || ActiveMacros.empty()) &&796 "Unexpected active macro instantiation!");797 798 // Remove MCStreamer's reference to the parser SMLoc.799 Out.setStartTokLocPtr(nullptr);800 // Restore the saved diagnostics handler and context for use during801 // finalization.802 SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);803}804 805void AsmParser::printMacroInstantiations() {806 // Print the active macro instantiation stack.807 for (MacroInstantiation *M : reverse(ActiveMacros))808 printMessage(M->InstantiationLoc, SourceMgr::DK_Note,809 "while in macro instantiation");810}811 812void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {813 printPendingErrors();814 printMessage(L, SourceMgr::DK_Note, Msg, Range);815 printMacroInstantiations();816}817 818bool AsmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {819 if(getTargetParser().getTargetOptions().MCNoWarn)820 return false;821 if (getTargetParser().getTargetOptions().MCFatalWarnings)822 return Error(L, Msg, Range);823 printMessage(L, SourceMgr::DK_Warning, Msg, Range);824 printMacroInstantiations();825 return false;826}827 828bool AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {829 HadError = true;830 printMessage(L, SourceMgr::DK_Error, Msg, Range);831 printMacroInstantiations();832 return true;833}834 835bool AsmParser::enterIncludeFile(const std::string &Filename) {836 std::string IncludedFile;837 unsigned NewBuf =838 SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);839 if (!NewBuf)840 return true;841 842 CurBuffer = NewBuf;843 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());844 return false;845}846 847/// Process the specified .incbin file by searching for it in the include paths848/// then just emitting the byte contents of the file to the streamer. This849/// returns true on failure.850bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip,851 const MCExpr *Count, SMLoc Loc) {852 std::string IncludedFile;853 unsigned NewBuf =854 SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);855 if (!NewBuf)856 return true;857 858 // Pick up the bytes from the file and emit them.859 StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer();860 Bytes = Bytes.drop_front(Skip);861 if (Count) {862 int64_t Res;863 if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))864 return Error(Loc, "expected absolute expression");865 if (Res < 0)866 return Warning(Loc, "negative count has no effect");867 Bytes = Bytes.take_front(Res);868 }869 getStreamer().emitBytes(Bytes);870 return false;871}872 873void AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) {874 CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);875 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),876 Loc.getPointer());877}878 879const AsmToken &AsmParser::Lex() {880 if (Lexer.getTok().is(AsmToken::Error))881 Error(Lexer.getErrLoc(), Lexer.getErr());882 883 // if it's a end of statement with a comment in it884 if (getTok().is(AsmToken::EndOfStatement)) {885 // if this is a line comment output it.886 if (!getTok().getString().empty() && getTok().getString().front() != '\n' &&887 getTok().getString().front() != '\r' && MAI.preserveAsmComments())888 Out.addExplicitComment(Twine(getTok().getString()));889 }890 891 const AsmToken *tok = &Lexer.Lex();892 893 // Parse comments here to be deferred until end of next statement.894 while (tok->is(AsmToken::Comment)) {895 if (MAI.preserveAsmComments())896 Out.addExplicitComment(Twine(tok->getString()));897 tok = &Lexer.Lex();898 }899 900 if (tok->is(AsmToken::Eof)) {901 // If this is the end of an included file, pop the parent file off the902 // include stack.903 SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);904 if (ParentIncludeLoc != SMLoc()) {905 jumpToLoc(ParentIncludeLoc);906 return Lex();907 }908 }909 910 return *tok;911}912 913bool AsmParser::enabledGenDwarfForAssembly() {914 // Check whether the user specified -g.915 if (!getContext().getGenDwarfForAssembly())916 return false;917 // If we haven't encountered any .file directives (which would imply that918 // the assembler source was produced with debug info already) then emit one919 // describing the assembler source file itself.920 if (getContext().getGenDwarfFileNumber() == 0) {921 const MCDwarfFile &RootFile =922 getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile();923 getContext().setGenDwarfFileNumber(getStreamer().emitDwarfFileDirective(924 /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name,925 RootFile.Checksum, RootFile.Source));926 }927 return true;928}929 930bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {931 LTODiscardSymbols.clear();932 933 // Create the initial section, if requested.934 if (!NoInitialTextSection)935 Out.initSections(false, getTargetParser().getSTI());936 937 // Prime the lexer.938 Lex();939 940 HadError = false;941 AsmCond StartingCondState = TheCondState;942 SmallVector<AsmRewrite, 4> AsmStrRewrites;943 944 // If we are generating dwarf for assembly source files save the initial text945 // section. (Don't use enabledGenDwarfForAssembly() here, as we aren't946 // emitting any actual debug info yet and haven't had a chance to parse any947 // embedded .file directives.)948 if (getContext().getGenDwarfForAssembly()) {949 MCSection *Sec = getStreamer().getCurrentSectionOnly();950 if (!Sec->getBeginSymbol()) {951 MCSymbol *SectionStartSym = getContext().createTempSymbol();952 getStreamer().emitLabel(SectionStartSym);953 Sec->setBeginSymbol(SectionStartSym);954 }955 bool InsertResult = getContext().addGenDwarfSection(Sec);956 assert(InsertResult && ".text section should not have debug info yet");957 (void)InsertResult;958 }959 960 getTargetParser().onBeginOfFile();961 962 // While we have input, parse each statement.963 while (Lexer.isNot(AsmToken::Eof)) {964 ParseStatementInfo Info(&AsmStrRewrites);965 bool HasError = parseStatement(Info, nullptr);966 967 // If we have a Lexer Error we are on an Error Token. Load in Lexer Error968 // for printing ErrMsg via Lex() only if no (presumably better) parser error969 // exists.970 if (HasError && !hasPendingError() && Lexer.getTok().is(AsmToken::Error))971 Lex();972 973 // parseStatement returned true so may need to emit an error.974 printPendingErrors();975 976 // Skipping to the next line if needed.977 if (HasError && !getLexer().justConsumedEOL())978 eatToEndOfStatement();979 }980 981 getTargetParser().onEndOfFile();982 printPendingErrors();983 984 // All errors should have been emitted.985 assert(!hasPendingError() && "unexpected error from parseStatement");986 987 if (TheCondState.TheCond != StartingCondState.TheCond ||988 TheCondState.Ignore != StartingCondState.Ignore)989 printError(getTok().getLoc(), "unmatched .ifs or .elses");990 // Check to see there are no empty DwarfFile slots.991 const auto &LineTables = getContext().getMCDwarfLineTables();992 if (!LineTables.empty()) {993 unsigned Index = 0;994 for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) {995 if (File.Name.empty() && Index != 0)996 printError(getTok().getLoc(), "unassigned file number: " +997 Twine(Index) +998 " for .file directives");999 ++Index;1000 }1001 }1002 1003 // Check to see that all assembler local symbols were actually defined.1004 // Targets that don't do subsections via symbols may not want this, though,1005 // so conservatively exclude them. Only do this if we're finalizing, though,1006 // as otherwise we won't necessarily have seen everything yet.1007 if (!NoFinalize) {1008 if (MAI.hasSubsectionsViaSymbols()) {1009 for (const auto &TableEntry : getContext().getSymbols()) {1010 MCSymbol *Sym = TableEntry.getValue().Symbol;1011 // Variable symbols may not be marked as defined, so check those1012 // explicitly. If we know it's a variable, we have a definition for1013 // the purposes of this check.1014 if (Sym && Sym->isTemporary() && !Sym->isVariable() &&1015 !Sym->isDefined())1016 // FIXME: We would really like to refer back to where the symbol was1017 // first referenced for a source location. We need to add something1018 // to track that. Currently, we just point to the end of the file.1019 printError(getTok().getLoc(), "assembler local symbol '" +1020 Sym->getName() + "' not defined");1021 }1022 }1023 1024 // Temporary symbols like the ones for directional jumps don't go in the1025 // symbol table. They also need to be diagnosed in all (final) cases.1026 for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {1027 if (std::get<2>(LocSym)->isUndefined()) {1028 // Reset the state of any "# line file" directives we've seen to the1029 // context as it was at the diagnostic site.1030 CppHashInfo = std::get<1>(LocSym);1031 printError(std::get<0>(LocSym), "directional label undefined");1032 }1033 }1034 }1035 // Finalize the output stream if there are no errors and if the client wants1036 // us to.1037 if (!HadError && !NoFinalize) {1038 if (auto *TS = Out.getTargetStreamer())1039 TS->emitConstantPools();1040 1041 Out.finish(Lexer.getLoc());1042 }1043 1044 return HadError || getContext().hadError();1045}1046 1047bool AsmParser::checkForValidSection() {1048 if (!ParsingMSInlineAsm && !getStreamer().getCurrentFragment()) {1049 Out.initSections(false, getTargetParser().getSTI());1050 return Error(getTok().getLoc(),1051 "expected section directive before assembly directive");1052 }1053 return false;1054}1055 1056/// Throw away the rest of the line for testing purposes.1057void AsmParser::eatToEndOfStatement() {1058 while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))1059 Lexer.Lex();1060 1061 // Eat EOL.1062 if (Lexer.is(AsmToken::EndOfStatement))1063 Lexer.Lex();1064}1065 1066StringRef AsmParser::parseStringToEndOfStatement() {1067 const char *Start = getTok().getLoc().getPointer();1068 1069 while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))1070 Lexer.Lex();1071 1072 const char *End = getTok().getLoc().getPointer();1073 return StringRef(Start, End - Start);1074}1075 1076StringRef AsmParser::parseStringToComma() {1077 const char *Start = getTok().getLoc().getPointer();1078 1079 while (Lexer.isNot(AsmToken::EndOfStatement) &&1080 Lexer.isNot(AsmToken::Comma) && Lexer.isNot(AsmToken::Eof))1081 Lexer.Lex();1082 1083 const char *End = getTok().getLoc().getPointer();1084 return StringRef(Start, End - Start);1085}1086 1087/// Parse a paren expression and return it.1088/// NOTE: This assumes the leading '(' has already been consumed.1089///1090/// parenexpr ::= expr)1091///1092bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {1093 if (parseExpression(Res))1094 return true;1095 EndLoc = Lexer.getTok().getEndLoc();1096 return parseRParen();1097}1098 1099/// Parse a bracket expression and return it.1100/// NOTE: This assumes the leading '[' has already been consumed.1101///1102/// bracketexpr ::= expr]1103///1104bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {1105 if (parseExpression(Res))1106 return true;1107 EndLoc = getTok().getEndLoc();1108 if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))1109 return true;1110 return false;1111}1112 1113/// Parse a primary expression and return it.1114/// primaryexpr ::= (parenexpr1115/// primaryexpr ::= symbol1116/// primaryexpr ::= number1117/// primaryexpr ::= '.'1118/// primaryexpr ::= ~,+,- primaryexpr1119bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,1120 AsmTypeInfo *TypeInfo) {1121 SMLoc FirstTokenLoc = getLexer().getLoc();1122 AsmToken::TokenKind FirstTokenKind = Lexer.getKind();1123 switch (FirstTokenKind) {1124 default:1125 return TokError("unknown token in expression");1126 // If we have an error assume that we've already handled it.1127 case AsmToken::Error:1128 return true;1129 case AsmToken::Exclaim:1130 Lex(); // Eat the operator.1131 if (parsePrimaryExpr(Res, EndLoc, TypeInfo))1132 return true;1133 Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);1134 return false;1135 case AsmToken::Dollar:1136 case AsmToken::Star:1137 case AsmToken::At:1138 case AsmToken::String:1139 case AsmToken::Identifier: {1140 StringRef Identifier;1141 if (parseIdentifier(Identifier)) {1142 // We may have failed but '$'|'*' may be a valid token in context of1143 // the current PC.1144 if (getTok().is(AsmToken::Dollar) || getTok().is(AsmToken::Star)) {1145 bool ShouldGenerateTempSymbol = false;1146 if ((getTok().is(AsmToken::Dollar) && MAI.getDollarIsPC()) ||1147 (getTok().is(AsmToken::Star) && MAI.isHLASM()))1148 ShouldGenerateTempSymbol = true;1149 1150 if (!ShouldGenerateTempSymbol)1151 return Error(FirstTokenLoc, "invalid token in expression");1152 1153 // Eat the '$'|'*' token.1154 Lex();1155 // This is either a '$'|'*' reference, which references the current PC.1156 // Emit a temporary label to the streamer and refer to it.1157 MCSymbol *Sym = Ctx.createTempSymbol();1158 Out.emitLabel(Sym);1159 Res = MCSymbolRefExpr::create(Sym, getContext());1160 EndLoc = FirstTokenLoc;1161 return false;1162 }1163 }1164 // Parse an optional relocation specifier.1165 std::pair<StringRef, StringRef> Split;1166 if (MAI.useAtForSpecifier()) {1167 if (FirstTokenKind == AsmToken::String) {1168 if (Lexer.is(AsmToken::At)) {1169 Lex(); // eat @1170 SMLoc AtLoc = getLexer().getLoc();1171 StringRef VName;1172 if (parseIdentifier(VName))1173 return Error(AtLoc, "expected symbol variant after '@'");1174 1175 Split = std::make_pair(Identifier, VName);1176 }1177 } else if (Lexer.getAllowAtInIdentifier()) {1178 Split = Identifier.split('@');1179 }1180 } else if (MAI.useParensForSpecifier() &&1181 parseOptionalToken(AsmToken::LParen)) {1182 StringRef VName;1183 parseIdentifier(VName);1184 if (parseRParen())1185 return true;1186 Split = std::make_pair(Identifier, VName);1187 }1188 1189 EndLoc = SMLoc::getFromPointer(Identifier.end());1190 1191 // This is a symbol reference.1192 StringRef SymbolName = Identifier;1193 if (SymbolName.empty())1194 return Error(getLexer().getLoc(), "expected a symbol reference");1195 1196 // Lookup the @specifier if used.1197 uint16_t Spec = 0;1198 if (!Split.second.empty()) {1199 auto MaybeSpecifier = MAI.getSpecifierForName(Split.second);1200 if (MaybeSpecifier) {1201 SymbolName = Split.first;1202 Spec = *MaybeSpecifier;1203 } else if (!MAI.doesAllowAtInName()) {1204 return Error(SMLoc::getFromPointer(Split.second.begin()),1205 "invalid variant '" + Split.second + "'");1206 }1207 }1208 1209 MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);1210 if (!Sym)1211 Sym = getContext().parseSymbol(MAI.isHLASM() ? SymbolName.upper()1212 : SymbolName);1213 1214 // If this is an absolute variable reference, substitute it now to preserve1215 // semantics in the face of reassignment.1216 if (Sym->isVariable()) {1217 auto V = Sym->getVariableValue();1218 bool DoInline = isa<MCConstantExpr>(V) && !Spec;1219 if (auto TV = dyn_cast<MCTargetExpr>(V))1220 DoInline = TV->inlineAssignedExpr();1221 if (DoInline) {1222 if (Spec)1223 return Error(EndLoc, "unexpected modifier on variable reference");1224 Res = Sym->getVariableValue();1225 return false;1226 }1227 }1228 1229 // Otherwise create a symbol ref.1230 Res = MCSymbolRefExpr::create(Sym, Spec, getContext(), FirstTokenLoc);1231 return false;1232 }1233 case AsmToken::BigNum:1234 return TokError("literal value out of range for directive");1235 case AsmToken::Integer: {1236 SMLoc Loc = getTok().getLoc();1237 int64_t IntVal = getTok().getIntVal();1238 Res = MCConstantExpr::create(IntVal, getContext());1239 EndLoc = Lexer.getTok().getEndLoc();1240 Lex(); // Eat token.1241 // Look for 'b' or 'f' following an Integer as a directional label1242 if (Lexer.getKind() == AsmToken::Identifier) {1243 StringRef IDVal = getTok().getString();1244 // Lookup the symbol variant if used.1245 std::pair<StringRef, StringRef> Split = IDVal.split('@');1246 uint16_t Spec = 0;1247 if (Split.first.size() != IDVal.size()) {1248 auto MaybeSpec = MAI.getSpecifierForName(Split.second);1249 if (!MaybeSpec)1250 return TokError("invalid variant '" + Split.second + "'");1251 IDVal = Split.first;1252 Spec = *MaybeSpec;1253 }1254 if (IDVal == "f" || IDVal == "b") {1255 MCSymbol *Sym =1256 Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b");1257 Res = MCSymbolRefExpr::create(Sym, Spec, getContext(), Loc);1258 if (IDVal == "b" && Sym->isUndefined())1259 return Error(Loc, "directional label undefined");1260 DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym));1261 EndLoc = Lexer.getTok().getEndLoc();1262 Lex(); // Eat identifier.1263 }1264 }1265 return false;1266 }1267 case AsmToken::Real: {1268 APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());1269 uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();1270 Res = MCConstantExpr::create(IntVal, getContext());1271 EndLoc = Lexer.getTok().getEndLoc();1272 Lex(); // Eat token.1273 return false;1274 }1275 case AsmToken::Dot: {1276 if (MAI.isHLASM())1277 return TokError("cannot use . as current PC");1278 1279 // This is a '.' reference, which references the current PC. Emit a1280 // temporary label to the streamer and refer to it.1281 MCSymbol *Sym = Ctx.createTempSymbol();1282 Out.emitLabel(Sym);1283 Res = MCSymbolRefExpr::create(Sym, getContext());1284 EndLoc = Lexer.getTok().getEndLoc();1285 Lex(); // Eat identifier.1286 return false;1287 }1288 case AsmToken::LParen:1289 Lex(); // Eat the '('.1290 return parseParenExpr(Res, EndLoc);1291 case AsmToken::LBrac:1292 if (!PlatformParser->HasBracketExpressions())1293 return TokError("brackets expression not supported on this target");1294 Lex(); // Eat the '['.1295 return parseBracketExpr(Res, EndLoc);1296 case AsmToken::Minus:1297 Lex(); // Eat the operator.1298 if (parsePrimaryExpr(Res, EndLoc, TypeInfo))1299 return true;1300 Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc);1301 return false;1302 case AsmToken::Plus:1303 Lex(); // Eat the operator.1304 if (parsePrimaryExpr(Res, EndLoc, TypeInfo))1305 return true;1306 Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);1307 return false;1308 case AsmToken::Tilde:1309 Lex(); // Eat the operator.1310 if (parsePrimaryExpr(Res, EndLoc, TypeInfo))1311 return true;1312 Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1313 return false;1314 }1315}1316 1317bool AsmParser::parseExpression(const MCExpr *&Res) {1318 SMLoc EndLoc;1319 return parseExpression(Res, EndLoc);1320}1321 1322const MCExpr *MCAsmParser::applySpecifier(const MCExpr *E, uint32_t Spec) {1323 // Ask the target implementation about this expression first.1324 const MCExpr *NewE = getTargetParser().applySpecifier(E, Spec, Ctx);1325 if (NewE)1326 return NewE;1327 // Recurse over the given expression, rebuilding it to apply the given variant1328 // if there is exactly one symbol.1329 switch (E->getKind()) {1330 case MCExpr::Specifier:1331 llvm_unreachable("cannot apply another specifier to MCSpecifierExpr");1332 case MCExpr::Target:1333 case MCExpr::Constant:1334 return nullptr;1335 1336 case MCExpr::SymbolRef: {1337 const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);1338 1339 if (SRE->getSpecifier()) {1340 TokError("invalid variant on expression '" + getTok().getIdentifier() +1341 "' (already modified)");1342 return E;1343 }1344 1345 return MCSymbolRefExpr::create(&SRE->getSymbol(), Spec, getContext(),1346 SRE->getLoc());1347 }1348 1349 case MCExpr::Unary: {1350 const MCUnaryExpr *UE = cast<MCUnaryExpr>(E);1351 const MCExpr *Sub = applySpecifier(UE->getSubExpr(), Spec);1352 if (!Sub)1353 return nullptr;1354 return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext(),1355 UE->getLoc());1356 }1357 1358 case MCExpr::Binary: {1359 const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);1360 const MCExpr *LHS = applySpecifier(BE->getLHS(), Spec);1361 const MCExpr *RHS = applySpecifier(BE->getRHS(), Spec);1362 1363 if (!LHS && !RHS)1364 return nullptr;1365 1366 if (!LHS)1367 LHS = BE->getLHS();1368 if (!RHS)1369 RHS = BE->getRHS();1370 1371 return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext(),1372 BE->getLoc());1373 }1374 }1375 1376 llvm_unreachable("Invalid expression kind!");1377}1378 1379/// This function checks if the next token is <string> type or arithmetic.1380/// string that begin with character '<' must end with character '>'.1381/// otherwise it is arithmetics.1382/// If the function returns a 'true' value,1383/// the End argument will be filled with the last location pointed to the '>'1384/// character.1385 1386/// There is a gap between the AltMacro's documentation and the single quote1387/// implementation. GCC does not fully support this feature and so we will not1388/// support it.1389/// TODO: Adding single quote as a string.1390static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {1391 assert((StrLoc.getPointer() != nullptr) &&1392 "Argument to the function cannot be a NULL value");1393 const char *CharPtr = StrLoc.getPointer();1394 while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') &&1395 (*CharPtr != '\0')) {1396 if (*CharPtr == '!')1397 CharPtr++;1398 CharPtr++;1399 }1400 if (*CharPtr == '>') {1401 EndLoc = StrLoc.getFromPointer(CharPtr + 1);1402 return true;1403 }1404 return false;1405}1406 1407/// creating a string without the escape characters '!'.1408static std::string angleBracketString(StringRef AltMacroStr) {1409 std::string Res;1410 for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {1411 if (AltMacroStr[Pos] == '!')1412 Pos++;1413 Res += AltMacroStr[Pos];1414 }1415 return Res;1416}1417 1418bool MCAsmParser::parseAtSpecifier(const MCExpr *&Res, SMLoc &EndLoc) {1419 if (parseOptionalToken(AsmToken::At)) {1420 if (getLexer().isNot(AsmToken::Identifier))1421 return TokError("expected specifier following '@'");1422 1423 auto Spec = MAI.getSpecifierForName(getTok().getIdentifier());1424 if (!Spec)1425 return TokError("invalid specifier '@" + getTok().getIdentifier() + "'");1426 1427 const MCExpr *ModifiedRes = applySpecifier(Res, *Spec);1428 if (ModifiedRes)1429 Res = ModifiedRes;1430 Lex();1431 }1432 return false;1433}1434 1435/// Parse an expression and return it.1436///1437/// expr ::= expr &&,|| expr -> lowest.1438/// expr ::= expr |,^,&,! expr1439/// expr ::= expr ==,!=,<>,<,<=,>,>= expr1440/// expr ::= expr <<,>> expr1441/// expr ::= expr +,- expr1442/// expr ::= expr *,/,% expr -> highest.1443/// expr ::= primaryexpr1444///1445bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {1446 // Parse the expression.1447 Res = nullptr;1448 auto &TS = getTargetParser();1449 if (TS.parsePrimaryExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc))1450 return true;1451 1452 // As a special case, we support 'a op b @ modifier' by rewriting the1453 // expression to include the modifier. This is inefficient, but in general we1454 // expect users to use 'a@modifier op b'.1455 if (Lexer.getAllowAtInIdentifier() && parseOptionalToken(AsmToken::At)) {1456 if (Lexer.isNot(AsmToken::Identifier))1457 return TokError("unexpected symbol modifier following '@'");1458 1459 auto Spec = MAI.getSpecifierForName(getTok().getIdentifier());1460 if (!Spec)1461 return TokError("invalid variant '" + getTok().getIdentifier() + "'");1462 1463 const MCExpr *ModifiedRes = applySpecifier(Res, *Spec);1464 if (!ModifiedRes) {1465 return TokError("invalid modifier '" + getTok().getIdentifier() +1466 "' (no symbols present)");1467 }1468 1469 Res = ModifiedRes;1470 Lex();1471 }1472 1473 // Try to constant fold it up front, if possible. Do not exploit1474 // assembler here.1475 int64_t Value;1476 if (Res->evaluateAsAbsolute(Value))1477 Res = MCConstantExpr::create(Value, getContext());1478 1479 return false;1480}1481 1482bool AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {1483 Res = nullptr;1484 return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);1485}1486 1487bool AsmParser::parseAbsoluteExpression(int64_t &Res) {1488 const MCExpr *Expr;1489 1490 SMLoc StartLoc = Lexer.getLoc();1491 if (parseExpression(Expr))1492 return true;1493 1494 if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))1495 return Error(StartLoc, "expected absolute expression");1496 1497 return false;1498}1499 1500static unsigned getDarwinBinOpPrecedence(AsmToken::TokenKind K,1501 MCBinaryExpr::Opcode &Kind,1502 bool ShouldUseLogicalShr) {1503 switch (K) {1504 default:1505 return 0; // not a binop.1506 1507 // Lowest Precedence: &&, ||1508 case AsmToken::AmpAmp:1509 Kind = MCBinaryExpr::LAnd;1510 return 1;1511 case AsmToken::PipePipe:1512 Kind = MCBinaryExpr::LOr;1513 return 1;1514 1515 // Low Precedence: |, &, ^1516 case AsmToken::Pipe:1517 Kind = MCBinaryExpr::Or;1518 return 2;1519 case AsmToken::Caret:1520 Kind = MCBinaryExpr::Xor;1521 return 2;1522 case AsmToken::Amp:1523 Kind = MCBinaryExpr::And;1524 return 2;1525 1526 // Low Intermediate Precedence: ==, !=, <>, <, <=, >, >=1527 case AsmToken::EqualEqual:1528 Kind = MCBinaryExpr::EQ;1529 return 3;1530 case AsmToken::ExclaimEqual:1531 case AsmToken::LessGreater:1532 Kind = MCBinaryExpr::NE;1533 return 3;1534 case AsmToken::Less:1535 Kind = MCBinaryExpr::LT;1536 return 3;1537 case AsmToken::LessEqual:1538 Kind = MCBinaryExpr::LTE;1539 return 3;1540 case AsmToken::Greater:1541 Kind = MCBinaryExpr::GT;1542 return 3;1543 case AsmToken::GreaterEqual:1544 Kind = MCBinaryExpr::GTE;1545 return 3;1546 1547 // Intermediate Precedence: <<, >>1548 case AsmToken::LessLess:1549 Kind = MCBinaryExpr::Shl;1550 return 4;1551 case AsmToken::GreaterGreater:1552 Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;1553 return 4;1554 1555 // High Intermediate Precedence: +, -1556 case AsmToken::Plus:1557 Kind = MCBinaryExpr::Add;1558 return 5;1559 case AsmToken::Minus:1560 Kind = MCBinaryExpr::Sub;1561 return 5;1562 1563 // Highest Precedence: *, /, %1564 case AsmToken::Star:1565 Kind = MCBinaryExpr::Mul;1566 return 6;1567 case AsmToken::Slash:1568 Kind = MCBinaryExpr::Div;1569 return 6;1570 case AsmToken::Percent:1571 Kind = MCBinaryExpr::Mod;1572 return 6;1573 }1574}1575 1576static unsigned getGNUBinOpPrecedence(const MCAsmInfo &MAI,1577 AsmToken::TokenKind K,1578 MCBinaryExpr::Opcode &Kind,1579 bool ShouldUseLogicalShr) {1580 switch (K) {1581 default:1582 return 0; // not a binop.1583 1584 // Lowest Precedence: &&, ||1585 case AsmToken::AmpAmp:1586 Kind = MCBinaryExpr::LAnd;1587 return 2;1588 case AsmToken::PipePipe:1589 Kind = MCBinaryExpr::LOr;1590 return 1;1591 1592 // Low Precedence: ==, !=, <>, <, <=, >, >=1593 case AsmToken::EqualEqual:1594 Kind = MCBinaryExpr::EQ;1595 return 3;1596 case AsmToken::ExclaimEqual:1597 case AsmToken::LessGreater:1598 Kind = MCBinaryExpr::NE;1599 return 3;1600 case AsmToken::Less:1601 Kind = MCBinaryExpr::LT;1602 return 3;1603 case AsmToken::LessEqual:1604 Kind = MCBinaryExpr::LTE;1605 return 3;1606 case AsmToken::Greater:1607 Kind = MCBinaryExpr::GT;1608 return 3;1609 case AsmToken::GreaterEqual:1610 Kind = MCBinaryExpr::GTE;1611 return 3;1612 1613 // Low Intermediate Precedence: +, -1614 case AsmToken::Plus:1615 Kind = MCBinaryExpr::Add;1616 return 4;1617 case AsmToken::Minus:1618 Kind = MCBinaryExpr::Sub;1619 return 4;1620 1621 // High Intermediate Precedence: |, !, &, ^1622 //1623 case AsmToken::Pipe:1624 Kind = MCBinaryExpr::Or;1625 return 5;1626 case AsmToken::Exclaim:1627 // Hack to support ARM compatible aliases (implied 'sp' operand in 'srs*'1628 // instructions like 'srsda #31!') and not parse ! as an infix operator.1629 if (MAI.getCommentString() == "@")1630 return 0;1631 Kind = MCBinaryExpr::OrNot;1632 return 5;1633 case AsmToken::Caret:1634 Kind = MCBinaryExpr::Xor;1635 return 5;1636 case AsmToken::Amp:1637 Kind = MCBinaryExpr::And;1638 return 5;1639 1640 // Highest Precedence: *, /, %, <<, >>1641 case AsmToken::Star:1642 Kind = MCBinaryExpr::Mul;1643 return 6;1644 case AsmToken::Slash:1645 Kind = MCBinaryExpr::Div;1646 return 6;1647 case AsmToken::Percent:1648 Kind = MCBinaryExpr::Mod;1649 return 6;1650 case AsmToken::LessLess:1651 Kind = MCBinaryExpr::Shl;1652 return 6;1653 case AsmToken::GreaterGreater:1654 Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;1655 return 6;1656 }1657}1658 1659unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K,1660 MCBinaryExpr::Opcode &Kind) {1661 bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();1662 return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr)1663 : getGNUBinOpPrecedence(MAI, K, Kind, ShouldUseLogicalShr);1664}1665 1666/// Parse all binary operators with precedence >= 'Precedence'.1667/// Res contains the LHS of the expression on input.1668bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,1669 SMLoc &EndLoc) {1670 SMLoc StartLoc = Lexer.getLoc();1671 while (true) {1672 MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;1673 unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind);1674 1675 // If the next token is lower precedence than we are allowed to eat, return1676 // successfully with what we ate already.1677 if (TokPrec < Precedence)1678 return false;1679 1680 Lex();1681 1682 // Eat the next primary expression.1683 const MCExpr *RHS;1684 if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))1685 return true;1686 1687 // If BinOp binds less tightly with RHS than the operator after RHS, let1688 // the pending operator take RHS as its LHS.1689 MCBinaryExpr::Opcode Dummy;1690 unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);1691 if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))1692 return true;1693 1694 // Merge LHS and RHS according to operator.1695 Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc);1696 }1697}1698 1699/// ParseStatement:1700/// ::= EndOfStatement1701/// ::= Label* Directive ...Operands... EndOfStatement1702/// ::= Label* Identifier OperandList* EndOfStatement1703bool AsmParser::parseStatement(ParseStatementInfo &Info,1704 MCAsmParserSemaCallback *SI) {1705 assert(!hasPendingError() && "parseStatement started with pending error");1706 // Eat initial spaces and comments1707 while (Lexer.is(AsmToken::Space))1708 Lex();1709 if (Lexer.is(AsmToken::EndOfStatement)) {1710 // if this is a line comment we can drop it safely1711 if (getTok().getString().empty() || getTok().getString().front() == '\r' ||1712 getTok().getString().front() == '\n')1713 Out.addBlankLine();1714 Lex();1715 return false;1716 }1717 // Statements always start with an identifier.1718 AsmToken ID = getTok();1719 SMLoc IDLoc = ID.getLoc();1720 StringRef IDVal;1721 int64_t LocalLabelVal = -1;1722 StartTokLoc = ID.getLoc();1723 if (Lexer.is(AsmToken::HashDirective))1724 return parseCppHashLineFilenameComment(IDLoc,1725 !isInsideMacroInstantiation());1726 1727 // Allow an integer followed by a ':' as a directional local label.1728 if (Lexer.is(AsmToken::Integer)) {1729 LocalLabelVal = getTok().getIntVal();1730 if (LocalLabelVal < 0) {1731 if (!TheCondState.Ignore) {1732 Lex(); // always eat a token1733 return Error(IDLoc, "unexpected token at start of statement");1734 }1735 IDVal = "";1736 } else {1737 IDVal = getTok().getString();1738 Lex(); // Consume the integer token to be used as an identifier token.1739 if (Lexer.getKind() != AsmToken::Colon) {1740 if (!TheCondState.Ignore) {1741 Lex(); // always eat a token1742 return Error(IDLoc, "unexpected token at start of statement");1743 }1744 }1745 }1746 } else if (Lexer.is(AsmToken::Dot)) {1747 // Treat '.' as a valid identifier in this context.1748 Lex();1749 IDVal = ".";1750 } else if (getTargetParser().tokenIsStartOfStatement(ID.getKind())) {1751 Lex();1752 IDVal = ID.getString();1753 } else if (parseIdentifier(IDVal)) {1754 if (!TheCondState.Ignore) {1755 Lex(); // always eat a token1756 return Error(IDLoc, "unexpected token at start of statement");1757 }1758 IDVal = "";1759 }1760 1761 // Handle conditional assembly here before checking for skipping. We1762 // have to do this so that .endif isn't skipped in a ".if 0" block for1763 // example.1764 StringMap<DirectiveKind>::const_iterator DirKindIt =1765 DirectiveKindMap.find(IDVal.lower());1766 DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())1767 ? DK_NO_DIRECTIVE1768 : DirKindIt->getValue();1769 switch (DirKind) {1770 default:1771 break;1772 case DK_IF:1773 case DK_IFEQ:1774 case DK_IFGE:1775 case DK_IFGT:1776 case DK_IFLE:1777 case DK_IFLT:1778 case DK_IFNE:1779 return parseDirectiveIf(IDLoc, DirKind);1780 case DK_IFB:1781 return parseDirectiveIfb(IDLoc, true);1782 case DK_IFNB:1783 return parseDirectiveIfb(IDLoc, false);1784 case DK_IFC:1785 return parseDirectiveIfc(IDLoc, true);1786 case DK_IFEQS:1787 return parseDirectiveIfeqs(IDLoc, true);1788 case DK_IFNC:1789 return parseDirectiveIfc(IDLoc, false);1790 case DK_IFNES:1791 return parseDirectiveIfeqs(IDLoc, false);1792 case DK_IFDEF:1793 return parseDirectiveIfdef(IDLoc, true);1794 case DK_IFNDEF:1795 case DK_IFNOTDEF:1796 return parseDirectiveIfdef(IDLoc, false);1797 case DK_ELSEIF:1798 return parseDirectiveElseIf(IDLoc);1799 case DK_ELSE:1800 return parseDirectiveElse(IDLoc);1801 case DK_ENDIF:1802 return parseDirectiveEndIf(IDLoc);1803 }1804 1805 // Ignore the statement if in the middle of inactive conditional1806 // (e.g. ".if 0").1807 if (TheCondState.Ignore) {1808 eatToEndOfStatement();1809 return false;1810 }1811 1812 // FIXME: Recurse on local labels?1813 1814 // Check for a label.1815 // ::= identifier ':'1816 // ::= number ':'1817 if (Lexer.is(AsmToken::Colon) && getTargetParser().isLabel(ID)) {1818 if (checkForValidSection())1819 return true;1820 1821 Lex(); // Consume the ':'.1822 1823 // Diagnose attempt to use '.' as a label.1824 if (IDVal == ".")1825 return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");1826 1827 // Diagnose attempt to use a variable as a label.1828 //1829 // FIXME: Diagnostics. Note the location of the definition as a label.1830 // FIXME: This doesn't diagnose assignment to a symbol which has been1831 // implicitly marked as external.1832 MCSymbol *Sym;1833 if (LocalLabelVal == -1) {1834 if (ParsingMSInlineAsm && SI) {1835 StringRef RewrittenLabel =1836 SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);1837 assert(!RewrittenLabel.empty() &&1838 "We should have an internal name here.");1839 Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),1840 RewrittenLabel);1841 IDVal = RewrittenLabel;1842 }1843 Sym = getContext().parseSymbol(IDVal);1844 } else1845 Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal);1846 // End of Labels should be treated as end of line for lexing1847 // purposes but that information is not available to the Lexer who1848 // does not understand Labels. This may cause us to see a Hash1849 // here instead of a preprocessor line comment.1850 if (getTok().is(AsmToken::Hash)) {1851 StringRef CommentStr = parseStringToEndOfStatement();1852 Lexer.Lex();1853 Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));1854 }1855 1856 // Consume any end of statement token, if present, to avoid spurious1857 // addBlankLine calls().1858 if (getTok().is(AsmToken::EndOfStatement)) {1859 Lex();1860 }1861 1862 if (MAI.isMachO() && CFIStartProcLoc) {1863 auto *SymM = static_cast<MCSymbolMachO *>(Sym);1864 if (SymM->isExternal() && !SymM->isAltEntry())1865 return Error(StartTokLoc, "non-private labels cannot appear between "1866 ".cfi_startproc / .cfi_endproc pairs") &&1867 Error(*CFIStartProcLoc, "previous .cfi_startproc was here");1868 }1869 1870 if (discardLTOSymbol(IDVal))1871 return false;1872 1873 getTargetParser().doBeforeLabelEmit(Sym, IDLoc);1874 1875 // Emit the label.1876 if (!getTargetParser().isParsingMSInlineAsm())1877 Out.emitLabel(Sym, IDLoc);1878 1879 // If we are generating dwarf for assembly source files then gather the1880 // info to make a dwarf label entry for this label if needed.1881 if (enabledGenDwarfForAssembly())1882 MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),1883 IDLoc);1884 1885 getTargetParser().onLabelParsed(Sym);1886 1887 return false;1888 }1889 1890 // Check for an assignment statement.1891 // ::= identifier '='1892 if (Lexer.is(AsmToken::Equal) && getTargetParser().equalIsAsmAssignment()) {1893 Lex();1894 return parseAssignment(IDVal, AssignmentKind::Equal);1895 }1896 1897 // If macros are enabled, check to see if this is a macro instantiation.1898 if (areMacrosEnabled())1899 if (MCAsmMacro *M = getContext().lookupMacro(IDVal))1900 return handleMacroEntry(M, IDLoc);1901 1902 // Otherwise, we have a normal instruction or directive.1903 1904 // Directives start with "."1905 if (IDVal.starts_with(".") && IDVal != ".") {1906 // There are several entities interested in parsing directives:1907 //1908 // 1. The target-specific assembly parser. Some directives are target1909 // specific or may potentially behave differently on certain targets.1910 // 2. Asm parser extensions. For example, platform-specific parsers1911 // (like the ELF parser) register themselves as extensions.1912 // 3. The generic directive parser implemented by this class. These are1913 // all the directives that behave in a target and platform independent1914 // manner, or at least have a default behavior that's shared between1915 // all targets and platforms.1916 1917 getTargetParser().flushPendingInstructions(getStreamer());1918 1919 ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);1920 assert(TPDirectiveReturn.isFailure() == hasPendingError() &&1921 "Should only return Failure iff there was an error");1922 if (TPDirectiveReturn.isFailure())1923 return true;1924 if (TPDirectiveReturn.isSuccess())1925 return false;1926 1927 // Next, check the extension directive map to see if any extension has1928 // registered itself to parse this directive.1929 std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =1930 ExtensionDirectiveMap.lookup(IDVal);1931 if (Handler.first)1932 return (*Handler.second)(Handler.first, IDVal, IDLoc);1933 1934 // Finally, if no one else is interested in this directive, it must be1935 // generic and familiar to this class.1936 switch (DirKind) {1937 default:1938 break;1939 case DK_SET:1940 case DK_EQU:1941 return parseDirectiveSet(IDVal, AssignmentKind::Set);1942 case DK_EQUIV:1943 return parseDirectiveSet(IDVal, AssignmentKind::Equiv);1944 case DK_LTO_SET_CONDITIONAL:1945 return parseDirectiveSet(IDVal, AssignmentKind::LTOSetConditional);1946 case DK_ASCII:1947 return parseDirectiveAscii(IDVal, false);1948 case DK_ASCIZ:1949 case DK_STRING:1950 return parseDirectiveAscii(IDVal, true);1951 case DK_BASE64:1952 return parseDirectiveBase64();1953 case DK_BYTE:1954 case DK_DC_B:1955 return parseDirectiveValue(IDVal, 1);1956 case DK_DC:1957 case DK_DC_W:1958 case DK_SHORT:1959 case DK_VALUE:1960 case DK_2BYTE:1961 return parseDirectiveValue(IDVal, 2);1962 case DK_LONG:1963 case DK_INT:1964 case DK_4BYTE:1965 case DK_DC_L:1966 return parseDirectiveValue(IDVal, 4);1967 case DK_QUAD:1968 case DK_8BYTE:1969 return parseDirectiveValue(IDVal, 8);1970 case DK_DC_A:1971 return parseDirectiveValue(1972 IDVal, getContext().getAsmInfo()->getCodePointerSize());1973 case DK_OCTA:1974 return parseDirectiveOctaValue(IDVal);1975 case DK_SINGLE:1976 case DK_FLOAT:1977 case DK_DC_S:1978 return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle());1979 case DK_DOUBLE:1980 case DK_DC_D:1981 return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble());1982 case DK_ALIGN: {1983 bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();1984 return parseDirectiveAlign(IsPow2, /*ExprSize=*/1);1985 }1986 case DK_ALIGN32: {1987 bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();1988 return parseDirectiveAlign(IsPow2, /*ExprSize=*/4);1989 }1990 case DK_BALIGN:1991 return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1);1992 case DK_BALIGNW:1993 return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2);1994 case DK_BALIGNL:1995 return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4);1996 case DK_P2ALIGN:1997 return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1);1998 case DK_P2ALIGNW:1999 return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2);2000 case DK_P2ALIGNL:2001 return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);2002 case DK_ORG:2003 return parseDirectiveOrg();2004 case DK_FILL:2005 return parseDirectiveFill();2006 case DK_ZERO:2007 return parseDirectiveZero();2008 case DK_EXTERN:2009 eatToEndOfStatement(); // .extern is the default, ignore it.2010 return false;2011 case DK_GLOBL:2012 case DK_GLOBAL:2013 return parseDirectiveSymbolAttribute(MCSA_Global);2014 case DK_LAZY_REFERENCE:2015 return parseDirectiveSymbolAttribute(MCSA_LazyReference);2016 case DK_NO_DEAD_STRIP:2017 return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip);2018 case DK_SYMBOL_RESOLVER:2019 return parseDirectiveSymbolAttribute(MCSA_SymbolResolver);2020 case DK_PRIVATE_EXTERN:2021 return parseDirectiveSymbolAttribute(MCSA_PrivateExtern);2022 case DK_REFERENCE:2023 return parseDirectiveSymbolAttribute(MCSA_Reference);2024 case DK_WEAK_DEFINITION:2025 return parseDirectiveSymbolAttribute(MCSA_WeakDefinition);2026 case DK_WEAK_REFERENCE:2027 return parseDirectiveSymbolAttribute(MCSA_WeakReference);2028 case DK_WEAK_DEF_CAN_BE_HIDDEN:2029 return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate);2030 case DK_COLD:2031 return parseDirectiveSymbolAttribute(MCSA_Cold);2032 case DK_COMM:2033 case DK_COMMON:2034 return parseDirectiveComm(/*IsLocal=*/false);2035 case DK_LCOMM:2036 return parseDirectiveComm(/*IsLocal=*/true);2037 case DK_ABORT:2038 return parseDirectiveAbort(IDLoc);2039 case DK_INCLUDE:2040 return parseDirectiveInclude();2041 case DK_INCBIN:2042 return parseDirectiveIncbin();2043 case DK_CODE16:2044 case DK_CODE16GCC:2045 return TokError(Twine(IDVal) +2046 " not currently supported for this target");2047 case DK_REPT:2048 return parseDirectiveRept(IDLoc, IDVal);2049 case DK_IRP:2050 return parseDirectiveIrp(IDLoc);2051 case DK_IRPC:2052 return parseDirectiveIrpc(IDLoc);2053 case DK_ENDR:2054 return parseDirectiveEndr(IDLoc);2055 case DK_SLEB128:2056 return parseDirectiveLEB128(true);2057 case DK_ULEB128:2058 return parseDirectiveLEB128(false);2059 case DK_SPACE:2060 case DK_SKIP:2061 return parseDirectiveSpace(IDVal);2062 case DK_FILE:2063 return parseDirectiveFile(IDLoc);2064 case DK_LINE:2065 return parseDirectiveLine();2066 case DK_LOC:2067 return parseDirectiveLoc();2068 case DK_LOC_LABEL:2069 return parseDirectiveLocLabel(IDLoc);2070 case DK_STABS:2071 return parseDirectiveStabs();2072 case DK_CV_FILE:2073 return parseDirectiveCVFile();2074 case DK_CV_FUNC_ID:2075 return parseDirectiveCVFuncId();2076 case DK_CV_INLINE_SITE_ID:2077 return parseDirectiveCVInlineSiteId();2078 case DK_CV_LOC:2079 return parseDirectiveCVLoc();2080 case DK_CV_LINETABLE:2081 return parseDirectiveCVLinetable();2082 case DK_CV_INLINE_LINETABLE:2083 return parseDirectiveCVInlineLinetable();2084 case DK_CV_DEF_RANGE:2085 return parseDirectiveCVDefRange();2086 case DK_CV_STRING:2087 return parseDirectiveCVString();2088 case DK_CV_STRINGTABLE:2089 return parseDirectiveCVStringTable();2090 case DK_CV_FILECHECKSUMS:2091 return parseDirectiveCVFileChecksums();2092 case DK_CV_FILECHECKSUM_OFFSET:2093 return parseDirectiveCVFileChecksumOffset();2094 case DK_CV_FPO_DATA:2095 return parseDirectiveCVFPOData();2096 case DK_CFI_SECTIONS:2097 return parseDirectiveCFISections();2098 case DK_CFI_STARTPROC:2099 return parseDirectiveCFIStartProc();2100 case DK_CFI_ENDPROC:2101 return parseDirectiveCFIEndProc();2102 case DK_CFI_DEF_CFA:2103 return parseDirectiveCFIDefCfa(IDLoc);2104 case DK_CFI_DEF_CFA_OFFSET:2105 return parseDirectiveCFIDefCfaOffset(IDLoc);2106 case DK_CFI_ADJUST_CFA_OFFSET:2107 return parseDirectiveCFIAdjustCfaOffset(IDLoc);2108 case DK_CFI_DEF_CFA_REGISTER:2109 return parseDirectiveCFIDefCfaRegister(IDLoc);2110 case DK_CFI_LLVM_DEF_ASPACE_CFA:2111 return parseDirectiveCFILLVMDefAspaceCfa(IDLoc);2112 case DK_CFI_OFFSET:2113 return parseDirectiveCFIOffset(IDLoc);2114 case DK_CFI_REL_OFFSET:2115 return parseDirectiveCFIRelOffset(IDLoc);2116 case DK_CFI_PERSONALITY:2117 return parseDirectiveCFIPersonalityOrLsda(true);2118 case DK_CFI_LSDA:2119 return parseDirectiveCFIPersonalityOrLsda(false);2120 case DK_CFI_REMEMBER_STATE:2121 return parseDirectiveCFIRememberState(IDLoc);2122 case DK_CFI_RESTORE_STATE:2123 return parseDirectiveCFIRestoreState(IDLoc);2124 case DK_CFI_SAME_VALUE:2125 return parseDirectiveCFISameValue(IDLoc);2126 case DK_CFI_RESTORE:2127 return parseDirectiveCFIRestore(IDLoc);2128 case DK_CFI_ESCAPE:2129 return parseDirectiveCFIEscape(IDLoc);2130 case DK_CFI_RETURN_COLUMN:2131 return parseDirectiveCFIReturnColumn(IDLoc);2132 case DK_CFI_SIGNAL_FRAME:2133 return parseDirectiveCFISignalFrame(IDLoc);2134 case DK_CFI_UNDEFINED:2135 return parseDirectiveCFIUndefined(IDLoc);2136 case DK_CFI_REGISTER:2137 return parseDirectiveCFIRegister(IDLoc);2138 case DK_CFI_WINDOW_SAVE:2139 return parseDirectiveCFIWindowSave(IDLoc);2140 case DK_CFI_LABEL:2141 return parseDirectiveCFILabel(IDLoc);2142 case DK_CFI_VAL_OFFSET:2143 return parseDirectiveCFIValOffset(IDLoc);2144 case DK_MACROS_ON:2145 case DK_MACROS_OFF:2146 return parseDirectiveMacrosOnOff(IDVal);2147 case DK_MACRO:2148 return parseDirectiveMacro(IDLoc);2149 case DK_ALTMACRO:2150 case DK_NOALTMACRO:2151 return parseDirectiveAltmacro(IDVal);2152 case DK_EXITM:2153 return parseDirectiveExitMacro(IDVal);2154 case DK_ENDM:2155 case DK_ENDMACRO:2156 return parseDirectiveEndMacro(IDVal);2157 case DK_PURGEM:2158 return parseDirectivePurgeMacro(IDLoc);2159 case DK_END:2160 return parseDirectiveEnd(IDLoc);2161 case DK_ERR:2162 return parseDirectiveError(IDLoc, false);2163 case DK_ERROR:2164 return parseDirectiveError(IDLoc, true);2165 case DK_WARNING:2166 return parseDirectiveWarning(IDLoc);2167 case DK_RELOC:2168 return parseDirectiveReloc(IDLoc);2169 case DK_DCB:2170 case DK_DCB_W:2171 return parseDirectiveDCB(IDVal, 2);2172 case DK_DCB_B:2173 return parseDirectiveDCB(IDVal, 1);2174 case DK_DCB_D:2175 return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble());2176 case DK_DCB_L:2177 return parseDirectiveDCB(IDVal, 4);2178 case DK_DCB_S:2179 return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle());2180 case DK_DC_X:2181 case DK_DCB_X:2182 return TokError(Twine(IDVal) +2183 " not currently supported for this target");2184 case DK_DS:2185 case DK_DS_W:2186 return parseDirectiveDS(IDVal, 2);2187 case DK_DS_B:2188 return parseDirectiveDS(IDVal, 1);2189 case DK_DS_D:2190 return parseDirectiveDS(IDVal, 8);2191 case DK_DS_L:2192 case DK_DS_S:2193 return parseDirectiveDS(IDVal, 4);2194 case DK_DS_P:2195 case DK_DS_X:2196 return parseDirectiveDS(IDVal, 12);2197 case DK_PRINT:2198 return parseDirectivePrint(IDLoc);2199 case DK_ADDRSIG:2200 return parseDirectiveAddrsig();2201 case DK_ADDRSIG_SYM:2202 return parseDirectiveAddrsigSym();2203 case DK_PSEUDO_PROBE:2204 return parseDirectivePseudoProbe();2205 case DK_LTO_DISCARD:2206 return parseDirectiveLTODiscard();2207 case DK_MEMTAG:2208 return parseDirectiveSymbolAttribute(MCSA_Memtag);2209 }2210 2211 return Error(IDLoc, "unknown directive");2212 }2213 2214 // __asm _emit or __asm __emit2215 if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||2216 IDVal == "_EMIT" || IDVal == "__EMIT"))2217 return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());2218 2219 // __asm align2220 if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))2221 return parseDirectiveMSAlign(IDLoc, Info);2222 2223 if (ParsingMSInlineAsm && (IDVal == "even" || IDVal == "EVEN"))2224 Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);2225 if (checkForValidSection())2226 return true;2227 2228 return parseAndMatchAndEmitTargetInstruction(Info, IDVal, ID, IDLoc);2229}2230 2231bool AsmParser::parseAndMatchAndEmitTargetInstruction(ParseStatementInfo &Info,2232 StringRef IDVal,2233 AsmToken ID,2234 SMLoc IDLoc) {2235 // Canonicalize the opcode to lower case.2236 std::string OpcodeStr = IDVal.lower();2237 ParseInstructionInfo IInfo(Info.AsmRewrites);2238 bool ParseHadError = getTargetParser().parseInstruction(IInfo, OpcodeStr, ID,2239 Info.ParsedOperands);2240 Info.ParseError = ParseHadError;2241 2242 // Dump the parsed representation, if requested.2243 if (getShowParsedOperands()) {2244 SmallString<256> Str;2245 raw_svector_ostream OS(Str);2246 OS << "parsed instruction: [";2247 for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {2248 if (i != 0)2249 OS << ", ";2250 Info.ParsedOperands[i]->print(OS, MAI);2251 }2252 OS << "]";2253 2254 printMessage(IDLoc, SourceMgr::DK_Note, OS.str());2255 }2256 2257 // Fail even if ParseInstruction erroneously returns false.2258 if (hasPendingError() || ParseHadError)2259 return true;2260 2261 // If we are generating dwarf for the current section then generate a .loc2262 // directive for the instruction.2263 if (!ParseHadError && enabledGenDwarfForAssembly() &&2264 getContext().getGenDwarfSectionSyms().count(2265 getStreamer().getCurrentSectionOnly())) {2266 unsigned Line;2267 if (ActiveMacros.empty())2268 Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer);2269 else2270 Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,2271 ActiveMacros.front()->ExitBuffer);2272 2273 // If we previously parsed a cpp hash file line comment then make sure the2274 // current Dwarf File is for the CppHashFilename if not then emit the2275 // Dwarf File table for it and adjust the line number for the .loc.2276 if (!CppHashInfo.Filename.empty()) {2277 unsigned FileNumber = getStreamer().emitDwarfFileDirective(2278 0, StringRef(), CppHashInfo.Filename);2279 getContext().setGenDwarfFileNumber(FileNumber);2280 2281 unsigned CppHashLocLineNo =2282 SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf);2283 Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo);2284 }2285 2286 getStreamer().emitDwarfLocDirective(2287 getContext().getGenDwarfFileNumber(), Line, 0,2288 DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0,2289 StringRef());2290 }2291 2292 // If parsing succeeded, match the instruction.2293 if (!ParseHadError) {2294 uint64_t ErrorInfo;2295 if (getTargetParser().matchAndEmitInstruction(2296 IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,2297 getTargetParser().isParsingMSInlineAsm()))2298 return true;2299 }2300 return false;2301}2302 2303// Parse and erase curly braces marking block start/end2304bool2305AsmParser::parseCurlyBlockScope(SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {2306 // Identify curly brace marking block start/end2307 if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))2308 return false;2309 2310 SMLoc StartLoc = Lexer.getLoc();2311 Lex(); // Eat the brace2312 if (Lexer.is(AsmToken::EndOfStatement))2313 Lex(); // Eat EndOfStatement following the brace2314 2315 // Erase the block start/end brace from the output asm string2316 AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -2317 StartLoc.getPointer());2318 return true;2319}2320 2321/// parseCppHashLineFilenameComment as this:2322/// ::= # number "filename"2323bool AsmParser::parseCppHashLineFilenameComment(SMLoc L, bool SaveLocInfo) {2324 Lex(); // Eat the hash token.2325 // Lexer only ever emits HashDirective if it fully formed if it's2326 // done the checking already so this is an internal error.2327 assert(getTok().is(AsmToken::Integer) &&2328 "Lexing Cpp line comment: Expected Integer");2329 int64_t LineNumber = getTok().getIntVal();2330 Lex();2331 assert(getTok().is(AsmToken::String) &&2332 "Lexing Cpp line comment: Expected String");2333 StringRef Filename = getTok().getString();2334 Lex();2335 2336 if (!SaveLocInfo)2337 return false;2338 2339 // Get rid of the enclosing quotes.2340 Filename = Filename.substr(1, Filename.size() - 2);2341 2342 // Save the SMLoc, Filename and LineNumber for later use by diagnostics2343 // and possibly DWARF file info.2344 CppHashInfo.Loc = L;2345 CppHashInfo.Filename = Filename;2346 CppHashInfo.LineNumber = LineNumber;2347 CppHashInfo.Buf = CurBuffer;2348 if (!HadCppHashFilename) {2349 HadCppHashFilename = true;2350 // If we haven't encountered any .file directives, then the first #line2351 // directive describes the "root" file and directory of the compilation2352 // unit.2353 if (getContext().getGenDwarfForAssembly() &&2354 getContext().getGenDwarfFileNumber() == 0) {2355 // It's preprocessed, so there is no checksum, and of course no source2356 // directive.2357 getContext().setMCLineTableRootFile(2358 /*CUID=*/0, getContext().getCompilationDir(), Filename,2359 /*Cksum=*/std::nullopt, /*Source=*/std::nullopt);2360 }2361 }2362 return false;2363}2364 2365/// will use the last parsed cpp hash line filename comment2366/// for the Filename and LineNo if any in the diagnostic.2367void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {2368 auto *Parser = static_cast<AsmParser *>(Context);2369 raw_ostream &OS = errs();2370 2371 const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();2372 SMLoc DiagLoc = Diag.getLoc();2373 unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2374 unsigned CppHashBuf =2375 Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);2376 2377 // Like SourceMgr::printMessage() we need to print the include stack if any2378 // before printing the message.2379 unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2380 if (!Parser->SavedDiagHandler && DiagCurBuffer &&2381 DiagCurBuffer != DiagSrcMgr.getMainFileID()) {2382 SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);2383 DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);2384 }2385 2386 // If we have not parsed a cpp hash line filename comment or the source2387 // manager changed or buffer changed (like in a nested include) then just2388 // print the normal diagnostic using its Filename and LineNo.2389 if (!Parser->CppHashInfo.LineNumber || DiagBuf != CppHashBuf) {2390 if (Parser->SavedDiagHandler)2391 Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);2392 else2393 Parser->getContext().diagnose(Diag);2394 return;2395 }2396 2397 // Use the CppHashFilename and calculate a line number based on the2398 // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc2399 // for the diagnostic.2400 const std::string &Filename = std::string(Parser->CppHashInfo.Filename);2401 2402 int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);2403 int CppHashLocLineNo =2404 Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);2405 int LineNo =2406 Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);2407 2408 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,2409 Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),2410 Diag.getLineContents(), Diag.getRanges());2411 2412 if (Parser->SavedDiagHandler)2413 Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);2414 else2415 Parser->getContext().diagnose(NewDiag);2416}2417 2418// FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The2419// difference being that that function accepts '@' as part of identifiers and2420// we can't do that. AsmLexer.cpp should probably be changed to handle2421// '@' as a special case when needed.2422static bool isIdentifierChar(char c) {2423 return isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$' ||2424 c == '.';2425}2426 2427bool AsmParser::expandMacro(raw_svector_ostream &OS, MCAsmMacro &Macro,2428 ArrayRef<MCAsmMacroParameter> Parameters,2429 ArrayRef<MCAsmMacroArgument> A,2430 bool EnableAtPseudoVariable) {2431 unsigned NParameters = Parameters.size();2432 auto expandArg = [&](unsigned Index) {2433 bool HasVararg = NParameters ? Parameters.back().Vararg : false;2434 bool VarargParameter = HasVararg && Index == (NParameters - 1);2435 for (const AsmToken &Token : A[Index])2436 // For altmacro mode, you can write '%expr'.2437 // The prefix '%' evaluates the expression 'expr'2438 // and uses the result as a string (e.g. replace %(1+2) with the2439 // string "3").2440 // Here, we identify the integer token which is the result of the2441 // absolute expression evaluation and replace it with its string2442 // representation.2443 if (AltMacroMode && Token.getString().front() == '%' &&2444 Token.is(AsmToken::Integer))2445 // Emit an integer value to the buffer.2446 OS << Token.getIntVal();2447 // Only Token that was validated as a string and begins with '<'2448 // is considered altMacroString!!!2449 else if (AltMacroMode && Token.getString().front() == '<' &&2450 Token.is(AsmToken::String)) {2451 OS << angleBracketString(Token.getStringContents());2452 }2453 // We expect no quotes around the string's contents when2454 // parsing for varargs.2455 else if (Token.isNot(AsmToken::String) || VarargParameter)2456 OS << Token.getString();2457 else2458 OS << Token.getStringContents();2459 };2460 2461 // A macro without parameters is handled differently on Darwin:2462 // gas accepts no arguments and does no substitutions2463 StringRef Body = Macro.Body;2464 size_t I = 0, End = Body.size();2465 while (I != End) {2466 if (Body[I] == '\\' && I + 1 != End) {2467 // Check for \@ and \+ pseudo variables.2468 if (EnableAtPseudoVariable && Body[I + 1] == '@') {2469 OS << NumOfMacroInstantiations;2470 I += 2;2471 continue;2472 }2473 if (Body[I + 1] == '+') {2474 OS << Macro.Count;2475 I += 2;2476 continue;2477 }2478 if (Body[I + 1] == '(' && Body[I + 2] == ')') {2479 I += 3;2480 continue;2481 }2482 2483 size_t Pos = ++I;2484 while (I != End && isIdentifierChar(Body[I]))2485 ++I;2486 StringRef Argument(Body.data() + Pos, I - Pos);2487 if (AltMacroMode && I != End && Body[I] == '&')2488 ++I;2489 unsigned Index = 0;2490 for (; Index < NParameters; ++Index)2491 if (Parameters[Index].Name == Argument)2492 break;2493 if (Index == NParameters)2494 OS << '\\' << Argument;2495 else2496 expandArg(Index);2497 continue;2498 }2499 2500 // In Darwin mode, $ is used for macro expansion, not considered an2501 // identifier char.2502 if (Body[I] == '$' && I + 1 != End && IsDarwin && !NParameters) {2503 // This macro has no parameters, look for $0, $1, etc.2504 switch (Body[I + 1]) {2505 // $$ => $2506 case '$':2507 OS << '$';2508 I += 2;2509 continue;2510 // $n => number of arguments2511 case 'n':2512 OS << A.size();2513 I += 2;2514 continue;2515 default: {2516 if (!isDigit(Body[I + 1]))2517 break;2518 // $[0-9] => argument2519 // Missing arguments are ignored.2520 unsigned Index = Body[I + 1] - '0';2521 if (Index < A.size())2522 for (const AsmToken &Token : A[Index])2523 OS << Token.getString();2524 I += 2;2525 continue;2526 }2527 }2528 }2529 2530 if (!isIdentifierChar(Body[I]) || IsDarwin) {2531 OS << Body[I++];2532 continue;2533 }2534 2535 const size_t Start = I;2536 while (++I && isIdentifierChar(Body[I])) {2537 }2538 StringRef Token(Body.data() + Start, I - Start);2539 if (AltMacroMode) {2540 unsigned Index = 0;2541 for (; Index != NParameters; ++Index)2542 if (Parameters[Index].Name == Token)2543 break;2544 if (Index != NParameters) {2545 expandArg(Index);2546 if (I != End && Body[I] == '&')2547 ++I;2548 continue;2549 }2550 }2551 OS << Token;2552 }2553 2554 ++Macro.Count;2555 return false;2556}2557 2558static bool isOperator(AsmToken::TokenKind kind) {2559 switch (kind) {2560 default:2561 return false;2562 case AsmToken::Plus:2563 case AsmToken::Minus:2564 case AsmToken::Tilde:2565 case AsmToken::Slash:2566 case AsmToken::Star:2567 case AsmToken::Dot:2568 case AsmToken::Equal:2569 case AsmToken::EqualEqual:2570 case AsmToken::Pipe:2571 case AsmToken::PipePipe:2572 case AsmToken::Caret:2573 case AsmToken::Amp:2574 case AsmToken::AmpAmp:2575 case AsmToken::Exclaim:2576 case AsmToken::ExclaimEqual:2577 case AsmToken::Less:2578 case AsmToken::LessEqual:2579 case AsmToken::LessLess:2580 case AsmToken::LessGreater:2581 case AsmToken::Greater:2582 case AsmToken::GreaterEqual:2583 case AsmToken::GreaterGreater:2584 return true;2585 }2586}2587 2588namespace {2589 2590class AsmLexerSkipSpaceRAII {2591public:2592 AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) {2593 Lexer.setSkipSpace(SkipSpace);2594 }2595 2596 ~AsmLexerSkipSpaceRAII() {2597 Lexer.setSkipSpace(true);2598 }2599 2600private:2601 AsmLexer &Lexer;2602};2603 2604} // end anonymous namespace2605 2606bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {2607 2608 if (Vararg) {2609 if (Lexer.isNot(AsmToken::EndOfStatement)) {2610 StringRef Str = parseStringToEndOfStatement();2611 MA.emplace_back(AsmToken::String, Str);2612 }2613 return false;2614 }2615 2616 unsigned ParenLevel = 0;2617 2618 // Darwin doesn't use spaces to delmit arguments.2619 AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);2620 2621 bool SpaceEaten;2622 2623 while (true) {2624 SpaceEaten = false;2625 if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))2626 return TokError("unexpected token in macro instantiation");2627 2628 if (ParenLevel == 0) {2629 2630 if (Lexer.is(AsmToken::Comma))2631 break;2632 2633 if (parseOptionalToken(AsmToken::Space))2634 SpaceEaten = true;2635 2636 // Spaces can delimit parameters, but could also be part an expression.2637 // If the token after a space is an operator, add the token and the next2638 // one into this argument2639 if (!IsDarwin) {2640 if (isOperator(Lexer.getKind())) {2641 MA.push_back(getTok());2642 Lexer.Lex();2643 2644 // Whitespace after an operator can be ignored.2645 parseOptionalToken(AsmToken::Space);2646 continue;2647 }2648 }2649 if (SpaceEaten)2650 break;2651 }2652 2653 // handleMacroEntry relies on not advancing the lexer here2654 // to be able to fill in the remaining default parameter values2655 if (Lexer.is(AsmToken::EndOfStatement))2656 break;2657 2658 // Adjust the current parentheses level.2659 if (Lexer.is(AsmToken::LParen))2660 ++ParenLevel;2661 else if (Lexer.is(AsmToken::RParen) && ParenLevel)2662 --ParenLevel;2663 2664 // Append the token to the current argument list.2665 MA.push_back(getTok());2666 Lexer.Lex();2667 }2668 2669 if (ParenLevel != 0)2670 return TokError("unbalanced parentheses in macro argument");2671 return false;2672}2673 2674// Parse the macro instantiation arguments.2675bool AsmParser::parseMacroArguments(const MCAsmMacro *M,2676 MCAsmMacroArguments &A) {2677 const unsigned NParameters = M ? M->Parameters.size() : 0;2678 bool NamedParametersFound = false;2679 SmallVector<SMLoc, 4> FALocs;2680 2681 A.resize(NParameters);2682 FALocs.resize(NParameters);2683 2684 // Parse two kinds of macro invocations:2685 // - macros defined without any parameters accept an arbitrary number of them2686 // - macros defined with parameters accept at most that many of them2687 bool HasVararg = NParameters ? M->Parameters.back().Vararg : false;2688 for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;2689 ++Parameter) {2690 SMLoc IDLoc = Lexer.getLoc();2691 MCAsmMacroParameter FA;2692 2693 if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {2694 if (parseIdentifier(FA.Name))2695 return Error(IDLoc, "invalid argument identifier for formal argument");2696 2697 if (Lexer.isNot(AsmToken::Equal))2698 return TokError("expected '=' after formal parameter identifier");2699 2700 Lex();2701 2702 NamedParametersFound = true;2703 }2704 bool Vararg = HasVararg && Parameter == (NParameters - 1);2705 2706 if (NamedParametersFound && FA.Name.empty())2707 return Error(IDLoc, "cannot mix positional and keyword arguments");2708 2709 SMLoc StrLoc = Lexer.getLoc();2710 SMLoc EndLoc;2711 if (AltMacroMode && Lexer.is(AsmToken::Percent)) {2712 const MCExpr *AbsoluteExp;2713 int64_t Value;2714 /// Eat '%'2715 Lex();2716 if (parseExpression(AbsoluteExp, EndLoc))2717 return false;2718 if (!AbsoluteExp->evaluateAsAbsolute(Value,2719 getStreamer().getAssemblerPtr()))2720 return Error(StrLoc, "expected absolute expression");2721 const char *StrChar = StrLoc.getPointer();2722 const char *EndChar = EndLoc.getPointer();2723 AsmToken newToken(AsmToken::Integer,2724 StringRef(StrChar, EndChar - StrChar), Value);2725 FA.Value.push_back(newToken);2726 } else if (AltMacroMode && Lexer.is(AsmToken::Less) &&2727 isAngleBracketString(StrLoc, EndLoc)) {2728 const char *StrChar = StrLoc.getPointer();2729 const char *EndChar = EndLoc.getPointer();2730 jumpToLoc(EndLoc, CurBuffer);2731 /// Eat from '<' to '>'2732 Lex();2733 AsmToken newToken(AsmToken::String,2734 StringRef(StrChar, EndChar - StrChar));2735 FA.Value.push_back(newToken);2736 } else if(parseMacroArgument(FA.Value, Vararg))2737 return true;2738 2739 unsigned PI = Parameter;2740 if (!FA.Name.empty()) {2741 unsigned FAI = 0;2742 for (FAI = 0; FAI < NParameters; ++FAI)2743 if (M->Parameters[FAI].Name == FA.Name)2744 break;2745 2746 if (FAI >= NParameters) {2747 assert(M && "expected macro to be defined");2748 return Error(IDLoc, "parameter named '" + FA.Name +2749 "' does not exist for macro '" + M->Name + "'");2750 }2751 PI = FAI;2752 }2753 2754 if (!FA.Value.empty()) {2755 if (A.size() <= PI)2756 A.resize(PI + 1);2757 A[PI] = FA.Value;2758 2759 if (FALocs.size() <= PI)2760 FALocs.resize(PI + 1);2761 2762 FALocs[PI] = Lexer.getLoc();2763 }2764 2765 // At the end of the statement, fill in remaining arguments that have2766 // default values. If there aren't any, then the next argument is2767 // required but missing2768 if (Lexer.is(AsmToken::EndOfStatement)) {2769 bool Failure = false;2770 for (unsigned FAI = 0; FAI < NParameters; ++FAI) {2771 if (A[FAI].empty()) {2772 if (M->Parameters[FAI].Required) {2773 Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),2774 "missing value for required parameter "2775 "'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");2776 Failure = true;2777 }2778 2779 if (!M->Parameters[FAI].Value.empty())2780 A[FAI] = M->Parameters[FAI].Value;2781 }2782 }2783 return Failure;2784 }2785 2786 parseOptionalToken(AsmToken::Comma);2787 }2788 2789 return TokError("too many positional arguments");2790}2791 2792bool AsmParser::handleMacroEntry(MCAsmMacro *M, SMLoc NameLoc) {2793 // Arbitrarily limit macro nesting depth (default matches 'as'). We can2794 // eliminate this, although we should protect against infinite loops.2795 unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;2796 if (ActiveMacros.size() == MaxNestingDepth) {2797 std::ostringstream MaxNestingDepthError;2798 MaxNestingDepthError << "macros cannot be nested more than "2799 << MaxNestingDepth << " levels deep."2800 << " Use -asm-macro-max-nesting-depth to increase "2801 "this limit.";2802 return TokError(MaxNestingDepthError.str());2803 }2804 2805 MCAsmMacroArguments A;2806 if (parseMacroArguments(M, A))2807 return true;2808 2809 // Macro instantiation is lexical, unfortunately. We construct a new buffer2810 // to hold the macro body with substitutions.2811 SmallString<256> Buf;2812 raw_svector_ostream OS(Buf);2813 2814 if ((!IsDarwin || M->Parameters.size()) && M->Parameters.size() != A.size())2815 return Error(getTok().getLoc(), "Wrong number of arguments");2816 if (expandMacro(OS, *M, M->Parameters, A, true))2817 return true;2818 2819 // We include the .endmacro in the buffer as our cue to exit the macro2820 // instantiation.2821 OS << ".endmacro\n";2822 2823 std::unique_ptr<MemoryBuffer> Instantiation =2824 MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");2825 2826 // Create the macro instantiation object and add to the current macro2827 // instantiation stack.2828 MacroInstantiation *MI = new MacroInstantiation{2829 NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};2830 ActiveMacros.push_back(MI);2831 2832 ++NumOfMacroInstantiations;2833 2834 // Jump to the macro instantiation and prime the lexer.2835 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());2836 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());2837 Lex();2838 2839 return false;2840}2841 2842void AsmParser::handleMacroExit() {2843 // Jump to the EndOfStatement we should return to, and consume it.2844 jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer);2845 Lex();2846 // If .endm/.endr is followed by \n instead of a comment, consume it so that2847 // we don't print an excess \n.2848 if (getTok().is(AsmToken::EndOfStatement))2849 Lex();2850 2851 // Pop the instantiation entry.2852 delete ActiveMacros.back();2853 ActiveMacros.pop_back();2854}2855 2856bool AsmParser::parseAssignment(StringRef Name, AssignmentKind Kind) {2857 MCSymbol *Sym;2858 const MCExpr *Value;2859 SMLoc ExprLoc = getTok().getLoc();2860 bool AllowRedef =2861 Kind == AssignmentKind::Set || Kind == AssignmentKind::Equal;2862 if (MCParserUtils::parseAssignmentExpression(Name, AllowRedef, *this, Sym,2863 Value))2864 return true;2865 2866 if (!Sym) {2867 // In the case where we parse an expression starting with a '.', we will2868 // not generate an error, nor will we create a symbol. In this case we2869 // should just return out.2870 return false;2871 }2872 2873 if (discardLTOSymbol(Name))2874 return false;2875 2876 // Do the assignment.2877 switch (Kind) {2878 case AssignmentKind::Equal:2879 Out.emitAssignment(Sym, Value);2880 break;2881 case AssignmentKind::Set:2882 case AssignmentKind::Equiv:2883 Out.emitAssignment(Sym, Value);2884 Out.emitSymbolAttribute(Sym, MCSA_NoDeadStrip);2885 break;2886 case AssignmentKind::LTOSetConditional:2887 if (Value->getKind() != MCExpr::SymbolRef)2888 return Error(ExprLoc, "expected identifier");2889 2890 Out.emitConditionalAssignment(Sym, Value);2891 break;2892 }2893 2894 return false;2895}2896 2897/// parseIdentifier:2898/// ::= identifier2899/// ::= string2900bool AsmParser::parseIdentifier(StringRef &Res) {2901 // The assembler has relaxed rules for accepting identifiers, in particular we2902 // allow things like '.globl $foo' and '.def @feat.00', which would normally be2903 // separate tokens. At this level, we have already lexed so we cannot (currently)2904 // handle this as a context dependent token, instead we detect adjacent tokens2905 // and return the combined identifier.2906 if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {2907 SMLoc PrefixLoc = getLexer().getLoc();2908 2909 // Consume the prefix character, and check for a following identifier.2910 2911 AsmToken Buf[1];2912 Lexer.peekTokens(Buf, false);2913 2914 if (Buf[0].isNot(AsmToken::Identifier) && Buf[0].isNot(AsmToken::Integer))2915 return true;2916 2917 // We have a '$' or '@' followed by an identifier or integer token, make2918 // sure they are adjacent.2919 if (PrefixLoc.getPointer() + 1 != Buf[0].getLoc().getPointer())2920 return true;2921 2922 // eat $ or @2923 Lexer.Lex(); // Lexer's Lex guarantees consecutive token.2924 // Construct the joined identifier and consume the token.2925 Res = StringRef(PrefixLoc.getPointer(), getTok().getString().size() + 1);2926 Lex(); // Parser Lex to maintain invariants.2927 return false;2928 }2929 2930 if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))2931 return true;2932 2933 Res = getTok().getIdentifier();2934 2935 Lex(); // Consume the identifier token.2936 2937 return false;2938}2939 2940/// parseDirectiveSet:2941/// ::= .equ identifier ',' expression2942/// ::= .equiv identifier ',' expression2943/// ::= .set identifier ',' expression2944/// ::= .lto_set_conditional identifier ',' expression2945bool AsmParser::parseDirectiveSet(StringRef IDVal, AssignmentKind Kind) {2946 StringRef Name;2947 if (check(parseIdentifier(Name), "expected identifier") || parseComma() ||2948 parseAssignment(Name, Kind))2949 return true;2950 return false;2951}2952 2953bool AsmParser::parseEscapedString(std::string &Data) {2954 if (check(getTok().isNot(AsmToken::String), "expected string"))2955 return true;2956 2957 Data = "";2958 StringRef Str = getTok().getStringContents();2959 for (unsigned i = 0, e = Str.size(); i != e; ++i) {2960 if (Str[i] != '\\') {2961 if ((Str[i] == '\n') || (Str[i] == '\r')) {2962 // Don't double-warn for Windows newlines.2963 if ((Str[i] == '\n') && (i > 0) && (Str[i - 1] == '\r'))2964 continue;2965 2966 SMLoc NewlineLoc = SMLoc::getFromPointer(Str.data() + i);2967 if (Warning(NewlineLoc, "unterminated string; newline inserted"))2968 return true;2969 }2970 Data += Str[i];2971 continue;2972 }2973 2974 // Recognize escaped characters. Note that this escape semantics currently2975 // loosely follows Darwin 'as'.2976 ++i;2977 if (i == e)2978 return TokError("unexpected backslash at end of string");2979 2980 // Recognize hex sequences similarly to GNU 'as'.2981 if (Str[i] == 'x' || Str[i] == 'X') {2982 size_t length = Str.size();2983 if (i + 1 >= length || !isHexDigit(Str[i + 1]))2984 return TokError("invalid hexadecimal escape sequence");2985 2986 // Consume hex characters. GNU 'as' reads all hexadecimal characters and2987 // then truncates to the lower 16 bits. Seems reasonable.2988 unsigned Value = 0;2989 while (i + 1 < length && isHexDigit(Str[i + 1]))2990 Value = Value * 16 + hexDigitValue(Str[++i]);2991 2992 Data += (unsigned char)(Value & 0xFF);2993 continue;2994 }2995 2996 // Recognize octal sequences.2997 if ((unsigned)(Str[i] - '0') <= 7) {2998 // Consume up to three octal characters.2999 unsigned Value = Str[i] - '0';3000 3001 if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {3002 ++i;3003 Value = Value * 8 + (Str[i] - '0');3004 3005 if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {3006 ++i;3007 Value = Value * 8 + (Str[i] - '0');3008 }3009 }3010 3011 if (Value > 255)3012 return TokError("invalid octal escape sequence (out of range)");3013 3014 Data += (unsigned char)Value;3015 continue;3016 }3017 3018 // Otherwise recognize individual escapes.3019 switch (Str[i]) {3020 default:3021 // Just reject invalid escape sequences for now.3022 return TokError("invalid escape sequence (unrecognized character)");3023 3024 case 'b': Data += '\b'; break;3025 case 'f': Data += '\f'; break;3026 case 'n': Data += '\n'; break;3027 case 'r': Data += '\r'; break;3028 case 't': Data += '\t'; break;3029 case '"': Data += '"'; break;3030 case '\\': Data += '\\'; break;3031 }3032 }3033 3034 Lex();3035 return false;3036}3037 3038bool AsmParser::parseAngleBracketString(std::string &Data) {3039 SMLoc EndLoc, StartLoc = getTok().getLoc();3040 if (isAngleBracketString(StartLoc, EndLoc)) {3041 const char *StartChar = StartLoc.getPointer() + 1;3042 const char *EndChar = EndLoc.getPointer() - 1;3043 jumpToLoc(EndLoc, CurBuffer);3044 /// Eat from '<' to '>'3045 Lex();3046 3047 Data = angleBracketString(StringRef(StartChar, EndChar - StartChar));3048 return false;3049 }3050 return true;3051}3052 3053/// parseDirectiveAscii:3054// ::= .ascii [ "string"+ ( , "string"+ )* ]3055/// ::= ( .asciz | .string ) [ "string" ( , "string" )* ]3056bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {3057 auto parseOp = [&]() -> bool {3058 std::string Data;3059 if (checkForValidSection())3060 return true;3061 // Only support spaces as separators for .ascii directive for now. See the3062 // discusssion at https://reviews.llvm.org/D91460 for more details.3063 do {3064 if (parseEscapedString(Data))3065 return true;3066 getStreamer().emitBytes(Data);3067 } while (!ZeroTerminated && getTok().is(AsmToken::String));3068 if (ZeroTerminated)3069 getStreamer().emitBytes(StringRef("\0", 1));3070 return false;3071 };3072 3073 return parseMany(parseOp);3074}3075 3076/// parseDirectiveBase64:3077// ::= .base64 "string" (, "string" )*3078bool AsmParser::parseDirectiveBase64() {3079 auto parseOp = [&]() -> bool {3080 if (checkForValidSection())3081 return true;3082 3083 if (getTok().isNot(AsmToken::String)) {3084 return true;3085 }3086 3087 std::vector<char> Decoded;3088 std::string const str = getTok().getStringContents().str();3089 if (check(str.empty(), "expected nonempty string")) {3090 return true;3091 }3092 3093 llvm::Error e = decodeBase64(str, Decoded);3094 if (e) {3095 consumeError(std::move(e));3096 return Error(Lexer.getLoc(), "failed to base64 decode string data");3097 }3098 3099 getStreamer().emitBytes(std::string(Decoded.begin(), Decoded.end()));3100 Lex();3101 return false;3102 };3103 3104 return check(parseMany(parseOp), "expected string");3105}3106 3107/// parseDirectiveReloc3108/// ::= .reloc expression , identifier [ , expression ]3109bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {3110 const MCExpr *Offset;3111 const MCExpr *Expr = nullptr;3112 3113 if (parseExpression(Offset))3114 return true;3115 if (parseComma() ||3116 check(getTok().isNot(AsmToken::Identifier), "expected relocation name"))3117 return true;3118 3119 SMLoc NameLoc = Lexer.getTok().getLoc();3120 StringRef Name = Lexer.getTok().getIdentifier();3121 Lex();3122 3123 if (Lexer.is(AsmToken::Comma)) {3124 Lex();3125 SMLoc ExprLoc = Lexer.getLoc();3126 if (parseExpression(Expr))3127 return true;3128 3129 MCValue Value;3130 if (!Expr->evaluateAsRelocatable(Value, nullptr))3131 return Error(ExprLoc, "expression must be relocatable");3132 }3133 3134 if (parseEOL())3135 return true;3136 3137 getStreamer().emitRelocDirective(*Offset, Name, Expr, NameLoc);3138 return false;3139}3140 3141/// parseDirectiveValue3142/// ::= (.byte | .short | ... ) [ expression (, expression)* ]3143bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {3144 auto parseOp = [&]() -> bool {3145 const MCExpr *Value;3146 SMLoc ExprLoc = getLexer().getLoc();3147 if (checkForValidSection() || getTargetParser().parseDataExpr(Value))3148 return true;3149 // Special case constant expressions to match code generator.3150 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3151 assert(Size <= 8 && "Invalid size");3152 uint64_t IntValue = MCE->getValue();3153 if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))3154 return Error(ExprLoc, "out of range literal value");3155 getStreamer().emitIntValue(IntValue, Size);3156 } else3157 getStreamer().emitValue(Value, Size, ExprLoc);3158 return false;3159 };3160 3161 return parseMany(parseOp);3162}3163 3164static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) {3165 if (Asm.getTok().isNot(AsmToken::Integer) &&3166 Asm.getTok().isNot(AsmToken::BigNum))3167 return Asm.TokError("unknown token in expression");3168 SMLoc ExprLoc = Asm.getTok().getLoc();3169 APInt IntValue = Asm.getTok().getAPIntVal();3170 Asm.Lex();3171 if (!IntValue.isIntN(128))3172 return Asm.Error(ExprLoc, "out of range literal value");3173 if (!IntValue.isIntN(64)) {3174 hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue();3175 lo = IntValue.getLoBits(64).getZExtValue();3176 } else {3177 hi = 0;3178 lo = IntValue.getZExtValue();3179 }3180 return false;3181}3182 3183/// ParseDirectiveOctaValue3184/// ::= .octa [ hexconstant (, hexconstant)* ]3185 3186bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) {3187 auto parseOp = [&]() -> bool {3188 if (checkForValidSection())3189 return true;3190 uint64_t hi, lo;3191 if (parseHexOcta(*this, hi, lo))3192 return true;3193 if (MAI.isLittleEndian()) {3194 getStreamer().emitInt64(lo);3195 getStreamer().emitInt64(hi);3196 } else {3197 getStreamer().emitInt64(hi);3198 getStreamer().emitInt64(lo);3199 }3200 return false;3201 };3202 3203 return parseMany(parseOp);3204}3205 3206bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {3207 // We don't truly support arithmetic on floating point expressions, so we3208 // have to manually parse unary prefixes.3209 bool IsNeg = false;3210 if (getLexer().is(AsmToken::Minus)) {3211 Lexer.Lex();3212 IsNeg = true;3213 } else if (getLexer().is(AsmToken::Plus))3214 Lexer.Lex();3215 3216 if (Lexer.is(AsmToken::Error))3217 return TokError(Lexer.getErr());3218 if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&3219 Lexer.isNot(AsmToken::Identifier))3220 return TokError("unexpected token in directive");3221 3222 // Convert to an APFloat.3223 APFloat Value(Semantics);3224 StringRef IDVal = getTok().getString();3225 if (getLexer().is(AsmToken::Identifier)) {3226 if (!IDVal.compare_insensitive("infinity") ||3227 !IDVal.compare_insensitive("inf"))3228 Value = APFloat::getInf(Semantics);3229 else if (!IDVal.compare_insensitive("nan"))3230 Value = APFloat::getNaN(Semantics, false, ~0);3231 else3232 return TokError("invalid floating point literal");3233 } else if (errorToBool(3234 Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven)3235 .takeError()))3236 return TokError("invalid floating point literal");3237 if (IsNeg)3238 Value.changeSign();3239 3240 // Consume the numeric token.3241 Lex();3242 3243 Res = Value.bitcastToAPInt();3244 3245 return false;3246}3247 3248/// parseDirectiveRealValue3249/// ::= (.single | .double) [ expression (, expression)* ]3250bool AsmParser::parseDirectiveRealValue(StringRef IDVal,3251 const fltSemantics &Semantics) {3252 auto parseOp = [&]() -> bool {3253 APInt AsInt;3254 if (checkForValidSection() || parseRealValue(Semantics, AsInt))3255 return true;3256 getStreamer().emitIntValue(AsInt.getLimitedValue(),3257 AsInt.getBitWidth() / 8);3258 return false;3259 };3260 3261 return parseMany(parseOp);3262}3263 3264/// parseDirectiveZero3265/// ::= .zero expression3266bool AsmParser::parseDirectiveZero() {3267 SMLoc NumBytesLoc = Lexer.getLoc();3268 const MCExpr *NumBytes;3269 if (checkForValidSection() || parseExpression(NumBytes))3270 return true;3271 3272 int64_t Val = 0;3273 if (getLexer().is(AsmToken::Comma)) {3274 Lex();3275 if (parseAbsoluteExpression(Val))3276 return true;3277 }3278 3279 if (parseEOL())3280 return true;3281 getStreamer().emitFill(*NumBytes, Val, NumBytesLoc);3282 3283 return false;3284}3285 3286/// parseDirectiveFill3287/// ::= .fill expression [ , expression [ , expression ] ]3288bool AsmParser::parseDirectiveFill() {3289 SMLoc NumValuesLoc = Lexer.getLoc();3290 const MCExpr *NumValues;3291 if (checkForValidSection() || parseExpression(NumValues))3292 return true;3293 3294 int64_t FillSize = 1;3295 int64_t FillExpr = 0;3296 3297 SMLoc SizeLoc, ExprLoc;3298 3299 if (parseOptionalToken(AsmToken::Comma)) {3300 SizeLoc = getTok().getLoc();3301 if (parseAbsoluteExpression(FillSize))3302 return true;3303 if (parseOptionalToken(AsmToken::Comma)) {3304 ExprLoc = getTok().getLoc();3305 if (parseAbsoluteExpression(FillExpr))3306 return true;3307 }3308 }3309 if (parseEOL())3310 return true;3311 3312 if (FillSize < 0) {3313 Warning(SizeLoc, "'.fill' directive with negative size has no effect");3314 return false;3315 }3316 if (FillSize > 8) {3317 Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8");3318 FillSize = 8;3319 }3320 3321 if (!isUInt<32>(FillExpr) && FillSize > 4)3322 Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits");3323 3324 getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc);3325 3326 return false;3327}3328 3329/// parseDirectiveOrg3330/// ::= .org expression [ , expression ]3331bool AsmParser::parseDirectiveOrg() {3332 const MCExpr *Offset;3333 SMLoc OffsetLoc = Lexer.getLoc();3334 if (checkForValidSection() || parseExpression(Offset))3335 return true;3336 3337 // Parse optional fill expression.3338 int64_t FillExpr = 0;3339 if (parseOptionalToken(AsmToken::Comma))3340 if (parseAbsoluteExpression(FillExpr))3341 return true;3342 if (parseEOL())3343 return true;3344 3345 getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc);3346 return false;3347}3348 3349/// parseDirectiveAlign3350/// ::= {.align, ...} expression [ , expression [ , expression ]]3351bool AsmParser::parseDirectiveAlign(bool IsPow2, uint8_t ValueSize) {3352 SMLoc AlignmentLoc = getLexer().getLoc();3353 int64_t Alignment;3354 SMLoc MaxBytesLoc;3355 bool HasFillExpr = false;3356 int64_t FillExpr = 0;3357 int64_t MaxBytesToFill = 0;3358 SMLoc FillExprLoc;3359 3360 auto parseAlign = [&]() -> bool {3361 if (parseAbsoluteExpression(Alignment))3362 return true;3363 if (parseOptionalToken(AsmToken::Comma)) {3364 // The fill expression can be omitted while specifying a maximum number of3365 // alignment bytes, e.g:3366 // .align 3,,43367 if (getTok().isNot(AsmToken::Comma)) {3368 HasFillExpr = true;3369 if (parseTokenLoc(FillExprLoc) || parseAbsoluteExpression(FillExpr))3370 return true;3371 }3372 if (parseOptionalToken(AsmToken::Comma))3373 if (parseTokenLoc(MaxBytesLoc) ||3374 parseAbsoluteExpression(MaxBytesToFill))3375 return true;3376 }3377 return parseEOL();3378 };3379 3380 if (checkForValidSection())3381 return true;3382 // Ignore empty '.p2align' directives for GNU-as compatibility3383 if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) {3384 Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored");3385 return parseEOL();3386 }3387 if (parseAlign())3388 return true;3389 3390 // Always emit an alignment here even if we thrown an error.3391 bool ReturnVal = false;3392 3393 // Compute alignment in bytes.3394 if (IsPow2) {3395 // FIXME: Diagnose overflow.3396 if (Alignment >= 32) {3397 ReturnVal |= Error(AlignmentLoc, "invalid alignment value");3398 Alignment = 31;3399 }3400 3401 Alignment = 1ULL << Alignment;3402 } else {3403 // Reject alignments that aren't either a power of two or zero,3404 // for gas compatibility. Alignment of zero is silently rounded3405 // up to one.3406 if (Alignment == 0)3407 Alignment = 1;3408 else if (!isPowerOf2_64(Alignment)) {3409 ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2");3410 Alignment = llvm::bit_floor<uint64_t>(Alignment);3411 }3412 if (!isUInt<32>(Alignment)) {3413 ReturnVal |= Error(AlignmentLoc, "alignment must be smaller than 2**32");3414 Alignment = 1u << 31;3415 }3416 }3417 3418 // Diagnose non-sensical max bytes to align.3419 if (MaxBytesLoc.isValid()) {3420 if (MaxBytesToFill < 1) {3421 ReturnVal |= Error(MaxBytesLoc,3422 "alignment directive can never be satisfied in this "3423 "many bytes, ignoring maximum bytes expression");3424 MaxBytesToFill = 0;3425 }3426 3427 if (MaxBytesToFill >= Alignment) {3428 Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and "3429 "has no effect");3430 MaxBytesToFill = 0;3431 }3432 }3433 3434 const MCSection *Section = getStreamer().getCurrentSectionOnly();3435 assert(Section && "must have section to emit alignment");3436 3437 if (HasFillExpr && FillExpr != 0 && Section->isBssSection()) {3438 ReturnVal |=3439 Warning(FillExprLoc, "ignoring non-zero fill value in BSS section '" +3440 Section->getName() + "'");3441 FillExpr = 0;3442 }3443 3444 // Check whether we should use optimal code alignment for this .align3445 // directive.3446 if (MAI.useCodeAlign(*Section) && !HasFillExpr) {3447 getStreamer().emitCodeAlignment(3448 Align(Alignment), &getTargetParser().getSTI(), MaxBytesToFill);3449 } else {3450 // FIXME: Target specific behavior about how the "extra" bytes are filled.3451 getStreamer().emitValueToAlignment(Align(Alignment), FillExpr, ValueSize,3452 MaxBytesToFill);3453 }3454 3455 return ReturnVal;3456}3457 3458/// parseDirectiveFile3459/// ::= .file filename3460/// ::= .file number [directory] filename [md5 checksum] [source source-text]3461bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {3462 // FIXME: I'm not sure what this is.3463 int64_t FileNumber = -1;3464 if (getLexer().is(AsmToken::Integer)) {3465 FileNumber = getTok().getIntVal();3466 Lex();3467 3468 if (FileNumber < 0)3469 return TokError("negative file number");3470 }3471 3472 std::string Path;3473 3474 // Usually the directory and filename together, otherwise just the directory.3475 // Allow the strings to have escaped octal character sequence.3476 if (parseEscapedString(Path))3477 return true;3478 3479 StringRef Directory;3480 StringRef Filename;3481 std::string FilenameData;3482 if (getLexer().is(AsmToken::String)) {3483 if (check(FileNumber == -1,3484 "explicit path specified, but no file number") ||3485 parseEscapedString(FilenameData))3486 return true;3487 Filename = FilenameData;3488 Directory = Path;3489 } else {3490 Filename = Path;3491 }3492 3493 uint64_t MD5Hi, MD5Lo;3494 bool HasMD5 = false;3495 3496 std::optional<StringRef> Source;3497 bool HasSource = false;3498 std::string SourceString;3499 3500 while (!parseOptionalToken(AsmToken::EndOfStatement)) {3501 StringRef Keyword;3502 if (check(getTok().isNot(AsmToken::Identifier),3503 "unexpected token in '.file' directive") ||3504 parseIdentifier(Keyword))3505 return true;3506 if (Keyword == "md5") {3507 HasMD5 = true;3508 if (check(FileNumber == -1,3509 "MD5 checksum specified, but no file number") ||3510 parseHexOcta(*this, MD5Hi, MD5Lo))3511 return true;3512 } else if (Keyword == "source") {3513 HasSource = true;3514 if (check(FileNumber == -1,3515 "source specified, but no file number") ||3516 check(getTok().isNot(AsmToken::String),3517 "unexpected token in '.file' directive") ||3518 parseEscapedString(SourceString))3519 return true;3520 } else {3521 return TokError("unexpected token in '.file' directive");3522 }3523 }3524 3525 if (FileNumber == -1) {3526 // Ignore the directive if there is no number and the target doesn't support3527 // numberless .file directives. This allows some portability of assembler3528 // between different object file formats.3529 if (getContext().getAsmInfo()->hasSingleParameterDotFile())3530 getStreamer().emitFileDirective(Filename);3531 } else {3532 // In case there is a -g option as well as debug info from directive .file,3533 // we turn off the -g option, directly use the existing debug info instead.3534 // Throw away any implicit file table for the assembler source.3535 if (Ctx.getGenDwarfForAssembly()) {3536 Ctx.getMCDwarfLineTable(0).resetFileTable();3537 Ctx.setGenDwarfForAssembly(false);3538 }3539 3540 std::optional<MD5::MD5Result> CKMem;3541 if (HasMD5) {3542 MD5::MD5Result Sum;3543 for (unsigned i = 0; i != 8; ++i) {3544 Sum[i] = uint8_t(MD5Hi >> ((7 - i) * 8));3545 Sum[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8));3546 }3547 CKMem = Sum;3548 }3549 if (HasSource) {3550 char *SourceBuf = static_cast<char *>(Ctx.allocate(SourceString.size()));3551 memcpy(SourceBuf, SourceString.data(), SourceString.size());3552 Source = StringRef(SourceBuf, SourceString.size());3553 }3554 if (FileNumber == 0) {3555 // Upgrade to Version 5 for assembly actions like clang -c a.s.3556 if (Ctx.getDwarfVersion() < 5)3557 Ctx.setDwarfVersion(5);3558 getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source);3559 } else {3560 Expected<unsigned> FileNumOrErr = getStreamer().tryEmitDwarfFileDirective(3561 FileNumber, Directory, Filename, CKMem, Source);3562 if (!FileNumOrErr)3563 return Error(DirectiveLoc, toString(FileNumOrErr.takeError()));3564 }3565 // Alert the user if there are some .file directives with MD5 and some not.3566 // But only do that once.3567 if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) {3568 ReportedInconsistentMD5 = true;3569 return Warning(DirectiveLoc, "inconsistent use of MD5 checksums");3570 }3571 }3572 3573 return false;3574}3575 3576/// parseDirectiveLine3577/// ::= .line [number]3578bool AsmParser::parseDirectiveLine() {3579 parseOptionalToken(AsmToken::Integer);3580 return parseEOL();3581}3582 3583/// parseDirectiveLoc3584/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end]3585/// [epilogue_begin] [is_stmt VALUE] [isa VALUE]3586/// The first number is a file number, must have been previously assigned with3587/// a .file directive, the second number is the line number and optionally the3588/// third number is a column position (zero if not specified). The remaining3589/// optional items are .loc sub-directives.3590bool AsmParser::parseDirectiveLoc() {3591 int64_t FileNumber = 0, LineNumber = 0;3592 SMLoc Loc = getTok().getLoc();3593 if (parseIntToken(FileNumber) ||3594 check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc,3595 "file number less than one in '.loc' directive") ||3596 check(!getContext().isValidDwarfFileNumber(FileNumber), Loc,3597 "unassigned file number in '.loc' directive"))3598 return true;3599 3600 // optional3601 if (getLexer().is(AsmToken::Integer)) {3602 LineNumber = getTok().getIntVal();3603 if (LineNumber < 0)3604 return TokError("line number less than zero in '.loc' directive");3605 Lex();3606 }3607 3608 int64_t ColumnPos = 0;3609 if (getLexer().is(AsmToken::Integer)) {3610 ColumnPos = getTok().getIntVal();3611 if (ColumnPos < 0)3612 return TokError("column position less than zero in '.loc' directive");3613 Lex();3614 }3615 3616 auto PrevFlags = getContext().getCurrentDwarfLoc().getFlags();3617 unsigned Flags = PrevFlags & DWARF2_FLAG_IS_STMT;3618 unsigned Isa = 0;3619 int64_t Discriminator = 0;3620 3621 auto parseLocOp = [&]() -> bool {3622 StringRef Name;3623 SMLoc Loc = getTok().getLoc();3624 if (parseIdentifier(Name))3625 return TokError("unexpected token in '.loc' directive");3626 3627 if (Name == "basic_block")3628 Flags |= DWARF2_FLAG_BASIC_BLOCK;3629 else if (Name == "prologue_end")3630 Flags |= DWARF2_FLAG_PROLOGUE_END;3631 else if (Name == "epilogue_begin")3632 Flags |= DWARF2_FLAG_EPILOGUE_BEGIN;3633 else if (Name == "is_stmt") {3634 Loc = getTok().getLoc();3635 const MCExpr *Value;3636 if (parseExpression(Value))3637 return true;3638 // The expression must be the constant 0 or 1.3639 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3640 int Value = MCE->getValue();3641 if (Value == 0)3642 Flags &= ~DWARF2_FLAG_IS_STMT;3643 else if (Value == 1)3644 Flags |= DWARF2_FLAG_IS_STMT;3645 else3646 return Error(Loc, "is_stmt value not 0 or 1");3647 } else {3648 return Error(Loc, "is_stmt value not the constant value of 0 or 1");3649 }3650 } else if (Name == "isa") {3651 Loc = getTok().getLoc();3652 const MCExpr *Value;3653 if (parseExpression(Value))3654 return true;3655 // The expression must be a constant greater or equal to 0.3656 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3657 int Value = MCE->getValue();3658 if (Value < 0)3659 return Error(Loc, "isa number less than zero");3660 Isa = Value;3661 } else {3662 return Error(Loc, "isa number not a constant value");3663 }3664 } else if (Name == "discriminator") {3665 if (parseAbsoluteExpression(Discriminator))3666 return true;3667 } else {3668 return Error(Loc, "unknown sub-directive in '.loc' directive");3669 }3670 return false;3671 };3672 3673 if (parseMany(parseLocOp, false /*hasComma*/))3674 return true;3675 3676 getStreamer().emitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags,3677 Isa, Discriminator, StringRef());3678 3679 return false;3680}3681 3682/// parseDirectiveLoc3683/// ::= .loc_label label3684bool AsmParser::parseDirectiveLocLabel(SMLoc DirectiveLoc) {3685 StringRef Name;3686 DirectiveLoc = Lexer.getLoc();3687 if (parseIdentifier(Name))3688 return TokError("expected identifier");3689 if (parseEOL())3690 return true;3691 getStreamer().emitDwarfLocLabelDirective(DirectiveLoc, Name);3692 return false;3693}3694 3695/// parseDirectiveStabs3696/// ::= .stabs string, number, number, number3697bool AsmParser::parseDirectiveStabs() {3698 return TokError("unsupported directive '.stabs'");3699}3700 3701/// parseDirectiveCVFile3702/// ::= .cv_file number filename [checksum] [checksumkind]3703bool AsmParser::parseDirectiveCVFile() {3704 SMLoc FileNumberLoc = getTok().getLoc();3705 int64_t FileNumber;3706 std::string Filename;3707 std::string Checksum;3708 int64_t ChecksumKind = 0;3709 3710 if (parseIntToken(FileNumber, "expected file number") ||3711 check(FileNumber < 1, FileNumberLoc, "file number less than one") ||3712 check(getTok().isNot(AsmToken::String),3713 "unexpected token in '.cv_file' directive") ||3714 parseEscapedString(Filename))3715 return true;3716 if (!parseOptionalToken(AsmToken::EndOfStatement)) {3717 if (check(getTok().isNot(AsmToken::String),3718 "unexpected token in '.cv_file' directive") ||3719 parseEscapedString(Checksum) ||3720 parseIntToken(ChecksumKind,3721 "expected checksum kind in '.cv_file' directive") ||3722 parseEOL())3723 return true;3724 }3725 3726 Checksum = fromHex(Checksum);3727 void *CKMem = Ctx.allocate(Checksum.size(), 1);3728 memcpy(CKMem, Checksum.data(), Checksum.size());3729 ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem),3730 Checksum.size());3731 3732 if (!getStreamer().emitCVFileDirective(FileNumber, Filename, ChecksumAsBytes,3733 static_cast<uint8_t>(ChecksumKind)))3734 return Error(FileNumberLoc, "file number already allocated");3735 3736 return false;3737}3738 3739bool AsmParser::parseCVFunctionId(int64_t &FunctionId,3740 StringRef DirectiveName) {3741 SMLoc Loc;3742 return parseTokenLoc(Loc) ||3743 parseIntToken(FunctionId, "expected function id") ||3744 check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,3745 "expected function id within range [0, UINT_MAX)");3746}3747 3748bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {3749 SMLoc Loc;3750 return parseTokenLoc(Loc) ||3751 parseIntToken(FileNumber, "expected file number") ||3752 check(FileNumber < 1, Loc,3753 "file number less than one in '" + DirectiveName +3754 "' directive") ||3755 check(!getCVContext().isValidFileNumber(FileNumber), Loc,3756 "unassigned file number in '" + DirectiveName + "' directive");3757}3758 3759/// parseDirectiveCVFuncId3760/// ::= .cv_func_id FunctionId3761///3762/// Introduces a function ID that can be used with .cv_loc.3763bool AsmParser::parseDirectiveCVFuncId() {3764 SMLoc FunctionIdLoc = getTok().getLoc();3765 int64_t FunctionId;3766 3767 if (parseCVFunctionId(FunctionId, ".cv_func_id") || parseEOL())3768 return true;3769 3770 if (!getStreamer().emitCVFuncIdDirective(FunctionId))3771 return Error(FunctionIdLoc, "function id already allocated");3772 3773 return false;3774}3775 3776/// parseDirectiveCVInlineSiteId3777/// ::= .cv_inline_site_id FunctionId3778/// "within" IAFunc3779/// "inlined_at" IAFile IALine [IACol]3780///3781/// Introduces a function ID that can be used with .cv_loc. Includes "inlined3782/// at" source location information for use in the line table of the caller,3783/// whether the caller is a real function or another inlined call site.3784bool AsmParser::parseDirectiveCVInlineSiteId() {3785 SMLoc FunctionIdLoc = getTok().getLoc();3786 int64_t FunctionId;3787 int64_t IAFunc;3788 int64_t IAFile;3789 int64_t IALine;3790 int64_t IACol = 0;3791 3792 // FunctionId3793 if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))3794 return true;3795 3796 // "within"3797 if (check((getLexer().isNot(AsmToken::Identifier) ||3798 getTok().getIdentifier() != "within"),3799 "expected 'within' identifier in '.cv_inline_site_id' directive"))3800 return true;3801 Lex();3802 3803 // IAFunc3804 if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))3805 return true;3806 3807 // "inlined_at"3808 if (check((getLexer().isNot(AsmToken::Identifier) ||3809 getTok().getIdentifier() != "inlined_at"),3810 "expected 'inlined_at' identifier in '.cv_inline_site_id' "3811 "directive") )3812 return true;3813 Lex();3814 3815 // IAFile IALine3816 if (parseCVFileId(IAFile, ".cv_inline_site_id") ||3817 parseIntToken(IALine, "expected line number after 'inlined_at'"))3818 return true;3819 3820 // [IACol]3821 if (getLexer().is(AsmToken::Integer)) {3822 IACol = getTok().getIntVal();3823 Lex();3824 }3825 3826 if (parseEOL())3827 return true;3828 3829 if (!getStreamer().emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,3830 IALine, IACol, FunctionIdLoc))3831 return Error(FunctionIdLoc, "function id already allocated");3832 3833 return false;3834}3835 3836/// parseDirectiveCVLoc3837/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]3838/// [is_stmt VALUE]3839/// The first number is a file number, must have been previously assigned with3840/// a .file directive, the second number is the line number and optionally the3841/// third number is a column position (zero if not specified). The remaining3842/// optional items are .loc sub-directives.3843bool AsmParser::parseDirectiveCVLoc() {3844 SMLoc DirectiveLoc = getTok().getLoc();3845 int64_t FunctionId, FileNumber;3846 if (parseCVFunctionId(FunctionId, ".cv_loc") ||3847 parseCVFileId(FileNumber, ".cv_loc"))3848 return true;3849 3850 int64_t LineNumber = 0;3851 if (getLexer().is(AsmToken::Integer)) {3852 LineNumber = getTok().getIntVal();3853 if (LineNumber < 0)3854 return TokError("line number less than zero in '.cv_loc' directive");3855 Lex();3856 }3857 3858 int64_t ColumnPos = 0;3859 if (getLexer().is(AsmToken::Integer)) {3860 ColumnPos = getTok().getIntVal();3861 if (ColumnPos < 0)3862 return TokError("column position less than zero in '.cv_loc' directive");3863 Lex();3864 }3865 3866 bool PrologueEnd = false;3867 uint64_t IsStmt = 0;3868 3869 auto parseOp = [&]() -> bool {3870 StringRef Name;3871 SMLoc Loc = getTok().getLoc();3872 if (parseIdentifier(Name))3873 return TokError("unexpected token in '.cv_loc' directive");3874 if (Name == "prologue_end")3875 PrologueEnd = true;3876 else if (Name == "is_stmt") {3877 Loc = getTok().getLoc();3878 const MCExpr *Value;3879 if (parseExpression(Value))3880 return true;3881 // The expression must be the constant 0 or 1.3882 IsStmt = ~0ULL;3883 if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))3884 IsStmt = MCE->getValue();3885 3886 if (IsStmt > 1)3887 return Error(Loc, "is_stmt value not 0 or 1");3888 } else {3889 return Error(Loc, "unknown sub-directive in '.cv_loc' directive");3890 }3891 return false;3892 };3893 3894 if (parseMany(parseOp, false /*hasComma*/))3895 return true;3896 3897 getStreamer().emitCVLocDirective(FunctionId, FileNumber, LineNumber,3898 ColumnPos, PrologueEnd, IsStmt, StringRef(),3899 DirectiveLoc);3900 return false;3901}3902 3903/// parseDirectiveCVLinetable3904/// ::= .cv_linetable FunctionId, FnStart, FnEnd3905bool AsmParser::parseDirectiveCVLinetable() {3906 int64_t FunctionId;3907 MCSymbol *FnStartSym, *FnEndSym;3908 SMLoc Loc = getTok().getLoc();3909 if (parseCVFunctionId(FunctionId, ".cv_linetable") || parseComma() ||3910 parseTokenLoc(Loc) ||3911 check(parseSymbol(FnStartSym), Loc, "expected identifier in directive") ||3912 parseComma() || parseTokenLoc(Loc) ||3913 check(parseSymbol(FnEndSym), Loc, "expected identifier in directive"))3914 return true;3915 3916 getStreamer().emitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);3917 return false;3918}3919 3920/// parseDirectiveCVInlineLinetable3921/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd3922bool AsmParser::parseDirectiveCVInlineLinetable() {3923 int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;3924 MCSymbol *FnStartSym, *FnEndSym;3925 SMLoc Loc = getTok().getLoc();3926 if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||3927 parseTokenLoc(Loc) ||3928 parseIntToken(SourceFileId, "expected SourceField") ||3929 check(SourceFileId <= 0, Loc, "File id less than zero") ||3930 parseTokenLoc(Loc) ||3931 parseIntToken(SourceLineNum, "expected SourceLineNum") ||3932 check(SourceLineNum < 0, Loc, "Line number less than zero") ||3933 parseTokenLoc(Loc) ||3934 check(parseSymbol(FnStartSym), Loc, "expected identifier") ||3935 parseTokenLoc(Loc) ||3936 check(parseSymbol(FnEndSym), Loc, "expected identifier"))3937 return true;3938 3939 if (parseEOL())3940 return true;3941 3942 getStreamer().emitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,3943 SourceLineNum, FnStartSym,3944 FnEndSym);3945 return false;3946}3947 3948void AsmParser::initializeCVDefRangeTypeMap() {3949 CVDefRangeTypeMap["reg"] = CVDR_DEFRANGE_REGISTER;3950 CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL;3951 CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER;3952 CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;3953}3954 3955/// parseDirectiveCVDefRange3956/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*3957bool AsmParser::parseDirectiveCVDefRange() {3958 SMLoc Loc;3959 std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;3960 while (getLexer().is(AsmToken::Identifier)) {3961 Loc = getLexer().getLoc();3962 MCSymbol *GapStartSym;3963 if (parseSymbol(GapStartSym))3964 return Error(Loc, "expected identifier in directive");3965 3966 Loc = getLexer().getLoc();3967 MCSymbol *GapEndSym;3968 if (parseSymbol(GapEndSym))3969 return Error(Loc, "expected identifier in directive");3970 3971 Ranges.push_back({GapStartSym, GapEndSym});3972 }3973 3974 StringRef CVDefRangeTypeStr;3975 if (parseToken(3976 AsmToken::Comma,3977 "expected comma before def_range type in .cv_def_range directive") ||3978 parseIdentifier(CVDefRangeTypeStr))3979 return Error(Loc, "expected def_range type in directive");3980 3981 StringMap<CVDefRangeType>::const_iterator CVTypeIt =3982 CVDefRangeTypeMap.find(CVDefRangeTypeStr);3983 CVDefRangeType CVDRType = (CVTypeIt == CVDefRangeTypeMap.end())3984 ? CVDR_DEFRANGE3985 : CVTypeIt->getValue();3986 switch (CVDRType) {3987 case CVDR_DEFRANGE_REGISTER: {3988 int64_t DRRegister;3989 if (parseToken(AsmToken::Comma, "expected comma before register number in "3990 ".cv_def_range directive") ||3991 parseAbsoluteExpression(DRRegister))3992 return Error(Loc, "expected register number");3993 3994 codeview::DefRangeRegisterHeader DRHdr;3995 DRHdr.Register = DRRegister;3996 DRHdr.MayHaveNoName = 0;3997 getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);3998 break;3999 }4000 case CVDR_DEFRANGE_FRAMEPOINTER_REL: {4001 int64_t DROffset;4002 if (parseToken(AsmToken::Comma,4003 "expected comma before offset in .cv_def_range directive") ||4004 parseAbsoluteExpression(DROffset))4005 return Error(Loc, "expected offset value");4006 4007 codeview::DefRangeFramePointerRelHeader DRHdr;4008 DRHdr.Offset = DROffset;4009 getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);4010 break;4011 }4012 case CVDR_DEFRANGE_SUBFIELD_REGISTER: {4013 int64_t DRRegister;4014 int64_t DROffsetInParent;4015 if (parseToken(AsmToken::Comma, "expected comma before register number in "4016 ".cv_def_range directive") ||4017 parseAbsoluteExpression(DRRegister))4018 return Error(Loc, "expected register number");4019 if (parseToken(AsmToken::Comma,4020 "expected comma before offset in .cv_def_range directive") ||4021 parseAbsoluteExpression(DROffsetInParent))4022 return Error(Loc, "expected offset value");4023 4024 codeview::DefRangeSubfieldRegisterHeader DRHdr;4025 DRHdr.Register = DRRegister;4026 DRHdr.MayHaveNoName = 0;4027 DRHdr.OffsetInParent = DROffsetInParent;4028 getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);4029 break;4030 }4031 case CVDR_DEFRANGE_REGISTER_REL: {4032 int64_t DRRegister;4033 int64_t DRFlags;4034 int64_t DRBasePointerOffset;4035 if (parseToken(AsmToken::Comma, "expected comma before register number in "4036 ".cv_def_range directive") ||4037 parseAbsoluteExpression(DRRegister))4038 return Error(Loc, "expected register value");4039 if (parseToken(4040 AsmToken::Comma,4041 "expected comma before flag value in .cv_def_range directive") ||4042 parseAbsoluteExpression(DRFlags))4043 return Error(Loc, "expected flag value");4044 if (parseToken(AsmToken::Comma, "expected comma before base pointer offset "4045 "in .cv_def_range directive") ||4046 parseAbsoluteExpression(DRBasePointerOffset))4047 return Error(Loc, "expected base pointer offset value");4048 4049 codeview::DefRangeRegisterRelHeader DRHdr;4050 DRHdr.Register = DRRegister;4051 DRHdr.Flags = DRFlags;4052 DRHdr.BasePointerOffset = DRBasePointerOffset;4053 getStreamer().emitCVDefRangeDirective(Ranges, DRHdr);4054 break;4055 }4056 default:4057 return Error(Loc, "unexpected def_range type in .cv_def_range directive");4058 }4059 return true;4060}4061 4062/// parseDirectiveCVString4063/// ::= .cv_stringtable "string"4064bool AsmParser::parseDirectiveCVString() {4065 std::string Data;4066 if (checkForValidSection() || parseEscapedString(Data))4067 return true;4068 4069 // Put the string in the table and emit the offset.4070 std::pair<StringRef, unsigned> Insertion =4071 getCVContext().addToStringTable(Data);4072 getStreamer().emitInt32(Insertion.second);4073 return false;4074}4075 4076/// parseDirectiveCVStringTable4077/// ::= .cv_stringtable4078bool AsmParser::parseDirectiveCVStringTable() {4079 getStreamer().emitCVStringTableDirective();4080 return false;4081}4082 4083/// parseDirectiveCVFileChecksums4084/// ::= .cv_filechecksums4085bool AsmParser::parseDirectiveCVFileChecksums() {4086 getStreamer().emitCVFileChecksumsDirective();4087 return false;4088}4089 4090/// parseDirectiveCVFileChecksumOffset4091/// ::= .cv_filechecksumoffset fileno4092bool AsmParser::parseDirectiveCVFileChecksumOffset() {4093 int64_t FileNo;4094 if (parseIntToken(FileNo))4095 return true;4096 if (parseEOL())4097 return true;4098 getStreamer().emitCVFileChecksumOffsetDirective(FileNo);4099 return false;4100}4101 4102/// parseDirectiveCVFPOData4103/// ::= .cv_fpo_data procsym4104bool AsmParser::parseDirectiveCVFPOData() {4105 SMLoc DirLoc = getLexer().getLoc();4106 MCSymbol *ProcSym;4107 if (parseSymbol(ProcSym))4108 return TokError("expected symbol name");4109 if (parseEOL())4110 return true;4111 getStreamer().emitCVFPOData(ProcSym, DirLoc);4112 return false;4113}4114 4115/// parseDirectiveCFISections4116/// ::= .cfi_sections section [, section][, section]4117bool AsmParser::parseDirectiveCFISections() {4118 StringRef Name;4119 bool EH = false;4120 bool Debug = false;4121 bool SFrame = false;4122 4123 if (!parseOptionalToken(AsmToken::EndOfStatement)) {4124 for (;;) {4125 if (parseIdentifier(Name))4126 return TokError("expected .eh_frame, .debug_frame, or .sframe");4127 if (Name == ".eh_frame")4128 EH = true;4129 else if (Name == ".debug_frame")4130 Debug = true;4131 else if (Name == ".sframe")4132 SFrame = true;4133 if (parseOptionalToken(AsmToken::EndOfStatement))4134 break;4135 if (parseComma())4136 return true;4137 }4138 }4139 getStreamer().emitCFISections(EH, Debug, SFrame);4140 return false;4141}4142 4143/// parseDirectiveCFIStartProc4144/// ::= .cfi_startproc [simple]4145bool AsmParser::parseDirectiveCFIStartProc() {4146 CFIStartProcLoc = StartTokLoc;4147 4148 StringRef Simple;4149 if (!parseOptionalToken(AsmToken::EndOfStatement)) {4150 if (check(parseIdentifier(Simple) || Simple != "simple",4151 "unexpected token") ||4152 parseEOL())4153 return true;4154 }4155 4156 // TODO(kristina): Deal with a corner case of incorrect diagnostic context4157 // being produced if this directive is emitted as part of preprocessor macro4158 // expansion which can *ONLY* happen if Clang's cc1as is the API consumer.4159 // Tools like llvm-mc on the other hand are not affected by it, and report4160 // correct context information.4161 getStreamer().emitCFIStartProc(!Simple.empty(), Lexer.getLoc());4162 return false;4163}4164 4165/// parseDirectiveCFIEndProc4166/// ::= .cfi_endproc4167bool AsmParser::parseDirectiveCFIEndProc() {4168 CFIStartProcLoc = std::nullopt;4169 4170 if (parseEOL())4171 return true;4172 4173 getStreamer().emitCFIEndProc();4174 return false;4175}4176 4177/// parse register name or number.4178bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register,4179 SMLoc DirectiveLoc) {4180 MCRegister RegNo;4181 4182 if (getLexer().isNot(AsmToken::Integer)) {4183 if (getTargetParser().parseRegister(RegNo, DirectiveLoc, DirectiveLoc))4184 return true;4185 Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo, true);4186 } else4187 return parseAbsoluteExpression(Register);4188 4189 return false;4190}4191 4192/// parseDirectiveCFIDefCfa4193/// ::= .cfi_def_cfa register, offset4194bool AsmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) {4195 int64_t Register = 0, Offset = 0;4196 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||4197 parseAbsoluteExpression(Offset) || parseEOL())4198 return true;4199 4200 getStreamer().emitCFIDefCfa(Register, Offset, DirectiveLoc);4201 return false;4202}4203 4204/// parseDirectiveCFIDefCfaOffset4205/// ::= .cfi_def_cfa_offset offset4206bool AsmParser::parseDirectiveCFIDefCfaOffset(SMLoc DirectiveLoc) {4207 int64_t Offset = 0;4208 if (parseAbsoluteExpression(Offset) || parseEOL())4209 return true;4210 4211 getStreamer().emitCFIDefCfaOffset(Offset, DirectiveLoc);4212 return false;4213}4214 4215/// parseDirectiveCFIRegister4216/// ::= .cfi_register register, register4217bool AsmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) {4218 int64_t Register1 = 0, Register2 = 0;4219 if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) || parseComma() ||4220 parseRegisterOrRegisterNumber(Register2, DirectiveLoc) || parseEOL())4221 return true;4222 4223 getStreamer().emitCFIRegister(Register1, Register2, DirectiveLoc);4224 return false;4225}4226 4227/// parseDirectiveCFIWindowSave4228/// ::= .cfi_window_save4229bool AsmParser::parseDirectiveCFIWindowSave(SMLoc DirectiveLoc) {4230 if (parseEOL())4231 return true;4232 getStreamer().emitCFIWindowSave(DirectiveLoc);4233 return false;4234}4235 4236/// parseDirectiveCFIAdjustCfaOffset4237/// ::= .cfi_adjust_cfa_offset adjustment4238bool AsmParser::parseDirectiveCFIAdjustCfaOffset(SMLoc DirectiveLoc) {4239 int64_t Adjustment = 0;4240 if (parseAbsoluteExpression(Adjustment) || parseEOL())4241 return true;4242 4243 getStreamer().emitCFIAdjustCfaOffset(Adjustment, DirectiveLoc);4244 return false;4245}4246 4247/// parseDirectiveCFIDefCfaRegister4248/// ::= .cfi_def_cfa_register register4249bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) {4250 int64_t Register = 0;4251 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseEOL())4252 return true;4253 4254 getStreamer().emitCFIDefCfaRegister(Register, DirectiveLoc);4255 return false;4256}4257 4258/// parseDirectiveCFILLVMDefAspaceCfa4259/// ::= .cfi_llvm_def_aspace_cfa register, offset, address_space4260bool AsmParser::parseDirectiveCFILLVMDefAspaceCfa(SMLoc DirectiveLoc) {4261 int64_t Register = 0, Offset = 0, AddressSpace = 0;4262 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||4263 parseAbsoluteExpression(Offset) || parseComma() ||4264 parseAbsoluteExpression(AddressSpace) || parseEOL())4265 return true;4266 4267 getStreamer().emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace,4268 DirectiveLoc);4269 return false;4270}4271 4272/// parseDirectiveCFIOffset4273/// ::= .cfi_offset register, offset4274bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {4275 int64_t Register = 0;4276 int64_t Offset = 0;4277 4278 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||4279 parseAbsoluteExpression(Offset) || parseEOL())4280 return true;4281 4282 getStreamer().emitCFIOffset(Register, Offset, DirectiveLoc);4283 return false;4284}4285 4286/// parseDirectiveCFIRelOffset4287/// ::= .cfi_rel_offset register, offset4288bool AsmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) {4289 int64_t Register = 0, Offset = 0;4290 4291 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||4292 parseAbsoluteExpression(Offset) || parseEOL())4293 return true;4294 4295 getStreamer().emitCFIRelOffset(Register, Offset, DirectiveLoc);4296 return false;4297}4298 4299static bool isValidEncoding(int64_t Encoding) {4300 if (Encoding & ~0xff)4301 return false;4302 4303 if (Encoding == dwarf::DW_EH_PE_omit)4304 return true;4305 4306 const unsigned Format = Encoding & 0xf;4307 if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 &&4308 Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 &&4309 Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 &&4310 Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed)4311 return false;4312 4313 const unsigned Application = Encoding & 0x70;4314 if (Application != dwarf::DW_EH_PE_absptr &&4315 Application != dwarf::DW_EH_PE_pcrel)4316 return false;4317 4318 return true;4319}4320 4321/// parseDirectiveCFIPersonalityOrLsda4322/// IsPersonality true for cfi_personality, false for cfi_lsda4323/// ::= .cfi_personality encoding, [symbol_name]4324/// ::= .cfi_lsda encoding, [symbol_name]4325bool AsmParser::parseDirectiveCFIPersonalityOrLsda(bool IsPersonality) {4326 int64_t Encoding = 0;4327 if (parseAbsoluteExpression(Encoding))4328 return true;4329 if (Encoding == dwarf::DW_EH_PE_omit)4330 return false;4331 4332 MCSymbol *Sym;4333 if (check(!isValidEncoding(Encoding), "unsupported encoding.") ||4334 parseComma() ||4335 check(parseSymbol(Sym), "expected identifier in directive") || parseEOL())4336 return true;4337 4338 if (IsPersonality)4339 getStreamer().emitCFIPersonality(Sym, Encoding);4340 else4341 getStreamer().emitCFILsda(Sym, Encoding);4342 return false;4343}4344 4345/// parseDirectiveCFIRememberState4346/// ::= .cfi_remember_state4347bool AsmParser::parseDirectiveCFIRememberState(SMLoc DirectiveLoc) {4348 if (parseEOL())4349 return true;4350 getStreamer().emitCFIRememberState(DirectiveLoc);4351 return false;4352}4353 4354/// parseDirectiveCFIRestoreState4355/// ::= .cfi_remember_state4356bool AsmParser::parseDirectiveCFIRestoreState(SMLoc DirectiveLoc) {4357 if (parseEOL())4358 return true;4359 getStreamer().emitCFIRestoreState(DirectiveLoc);4360 return false;4361}4362 4363/// parseDirectiveCFISameValue4364/// ::= .cfi_same_value register4365bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) {4366 int64_t Register = 0;4367 4368 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseEOL())4369 return true;4370 4371 getStreamer().emitCFISameValue(Register, DirectiveLoc);4372 return false;4373}4374 4375/// parseDirectiveCFIRestore4376/// ::= .cfi_restore register4377bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) {4378 int64_t Register = 0;4379 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseEOL())4380 return true;4381 4382 getStreamer().emitCFIRestore(Register, DirectiveLoc);4383 return false;4384}4385 4386/// parseDirectiveCFIEscape4387/// ::= .cfi_escape expression[,...]4388bool AsmParser::parseDirectiveCFIEscape(SMLoc DirectiveLoc) {4389 std::string Values;4390 int64_t CurrValue;4391 if (parseAbsoluteExpression(CurrValue))4392 return true;4393 4394 Values.push_back((uint8_t)CurrValue);4395 4396 while (getLexer().is(AsmToken::Comma)) {4397 Lex();4398 4399 if (parseAbsoluteExpression(CurrValue))4400 return true;4401 4402 Values.push_back((uint8_t)CurrValue);4403 }4404 4405 getStreamer().emitCFIEscape(Values, DirectiveLoc);4406 return false;4407}4408 4409/// parseDirectiveCFIReturnColumn4410/// ::= .cfi_return_column register4411bool AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) {4412 int64_t Register = 0;4413 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseEOL())4414 return true;4415 getStreamer().emitCFIReturnColumn(Register);4416 return false;4417}4418 4419/// parseDirectiveCFISignalFrame4420/// ::= .cfi_signal_frame4421bool AsmParser::parseDirectiveCFISignalFrame(SMLoc DirectiveLoc) {4422 if (parseEOL())4423 return true;4424 4425 getStreamer().emitCFISignalFrame();4426 return false;4427}4428 4429/// parseDirectiveCFIUndefined4430/// ::= .cfi_undefined register4431bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {4432 int64_t Register = 0;4433 4434 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseEOL())4435 return true;4436 4437 getStreamer().emitCFIUndefined(Register, DirectiveLoc);4438 return false;4439}4440 4441/// parseDirectiveCFILabel4442/// ::= .cfi_label label4443bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) {4444 StringRef Name;4445 Loc = Lexer.getLoc();4446 if (parseIdentifier(Name))4447 return TokError("expected identifier");4448 if (parseEOL())4449 return true;4450 getStreamer().emitCFILabelDirective(Loc, Name);4451 return false;4452}4453 4454/// parseDirectiveCFIValOffset4455/// ::= .cfi_val_offset register, offset4456bool AsmParser::parseDirectiveCFIValOffset(SMLoc DirectiveLoc) {4457 int64_t Register = 0;4458 int64_t Offset = 0;4459 4460 if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||4461 parseAbsoluteExpression(Offset) || parseEOL())4462 return true;4463 4464 getStreamer().emitCFIValOffset(Register, Offset, DirectiveLoc);4465 return false;4466}4467 4468/// parseDirectiveAltmacro4469/// ::= .altmacro4470/// ::= .noaltmacro4471bool AsmParser::parseDirectiveAltmacro(StringRef Directive) {4472 if (parseEOL())4473 return true;4474 AltMacroMode = (Directive == ".altmacro");4475 return false;4476}4477 4478/// parseDirectiveMacrosOnOff4479/// ::= .macros_on4480/// ::= .macros_off4481bool AsmParser::parseDirectiveMacrosOnOff(StringRef Directive) {4482 if (parseEOL())4483 return true;4484 setMacrosEnabled(Directive == ".macros_on");4485 return false;4486}4487 4488/// parseDirectiveMacro4489/// ::= .macro name[,] [parameters]4490bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {4491 StringRef Name;4492 if (parseIdentifier(Name))4493 return TokError("expected identifier in '.macro' directive");4494 4495 if (getLexer().is(AsmToken::Comma))4496 Lex();4497 4498 MCAsmMacroParameters Parameters;4499 while (getLexer().isNot(AsmToken::EndOfStatement)) {4500 4501 if (!Parameters.empty() && Parameters.back().Vararg)4502 return Error(Lexer.getLoc(), "vararg parameter '" +4503 Parameters.back().Name +4504 "' should be the last parameter");4505 4506 MCAsmMacroParameter Parameter;4507 if (parseIdentifier(Parameter.Name))4508 return TokError("expected identifier in '.macro' directive");4509 4510 // Emit an error if two (or more) named parameters share the same name4511 for (const MCAsmMacroParameter& CurrParam : Parameters)4512 if (CurrParam.Name == Parameter.Name)4513 return TokError("macro '" + Name + "' has multiple parameters"4514 " named '" + Parameter.Name + "'");4515 4516 if (Lexer.is(AsmToken::Colon)) {4517 Lex(); // consume ':'4518 4519 SMLoc QualLoc;4520 StringRef Qualifier;4521 4522 QualLoc = Lexer.getLoc();4523 if (parseIdentifier(Qualifier))4524 return Error(QualLoc, "missing parameter qualifier for "4525 "'" + Parameter.Name + "' in macro '" + Name + "'");4526 4527 if (Qualifier == "req")4528 Parameter.Required = true;4529 else if (Qualifier == "vararg")4530 Parameter.Vararg = true;4531 else4532 return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "4533 "for '" + Parameter.Name + "' in macro '" + Name + "'");4534 }4535 4536 if (getLexer().is(AsmToken::Equal)) {4537 Lex();4538 4539 SMLoc ParamLoc;4540 4541 ParamLoc = Lexer.getLoc();4542 if (parseMacroArgument(Parameter.Value, /*Vararg=*/false ))4543 return true;4544 4545 if (Parameter.Required)4546 Warning(ParamLoc, "pointless default value for required parameter "4547 "'" + Parameter.Name + "' in macro '" + Name + "'");4548 }4549 4550 Parameters.push_back(std::move(Parameter));4551 4552 if (getLexer().is(AsmToken::Comma))4553 Lex();4554 }4555 4556 // Eat just the end of statement.4557 Lexer.Lex();4558 4559 // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors4560 AsmToken EndToken, StartToken = getTok();4561 unsigned MacroDepth = 0;4562 // Lex the macro definition.4563 while (true) {4564 // Ignore Lexing errors in macros.4565 while (Lexer.is(AsmToken::Error)) {4566 Lexer.Lex();4567 }4568 4569 // Check whether we have reached the end of the file.4570 if (getLexer().is(AsmToken::Eof))4571 return Error(DirectiveLoc, "no matching '.endmacro' in definition");4572 4573 // Otherwise, check whether we have reach the .endmacro or the start of a4574 // preprocessor line marker.4575 if (getLexer().is(AsmToken::Identifier)) {4576 if (getTok().getIdentifier() == ".endm" ||4577 getTok().getIdentifier() == ".endmacro") {4578 if (MacroDepth == 0) { // Outermost macro.4579 EndToken = getTok();4580 Lexer.Lex();4581 if (getLexer().isNot(AsmToken::EndOfStatement))4582 return TokError("unexpected token in '" + EndToken.getIdentifier() +4583 "' directive");4584 break;4585 } else {4586 // Otherwise we just found the end of an inner macro.4587 --MacroDepth;4588 }4589 } else if (getTok().getIdentifier() == ".macro") {4590 // We allow nested macros. Those aren't instantiated until the outermost4591 // macro is expanded so just ignore them for now.4592 ++MacroDepth;4593 }4594 } else if (Lexer.is(AsmToken::HashDirective)) {4595 (void)parseCppHashLineFilenameComment(getLexer().getLoc());4596 }4597 4598 // Otherwise, scan til the end of the statement.4599 eatToEndOfStatement();4600 }4601 4602 if (getContext().lookupMacro(Name)) {4603 return Error(DirectiveLoc, "macro '" + Name + "' is already defined");4604 }4605 4606 const char *BodyStart = StartToken.getLoc().getPointer();4607 const char *BodyEnd = EndToken.getLoc().getPointer();4608 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);4609 checkForBadMacro(DirectiveLoc, Name, Body, Parameters);4610 MCAsmMacro Macro(Name, Body, std::move(Parameters));4611 DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";4612 Macro.dump());4613 getContext().defineMacro(Name, std::move(Macro));4614 return false;4615}4616 4617/// checkForBadMacro4618///4619/// With the support added for named parameters there may be code out there that4620/// is transitioning from positional parameters. In versions of gas that did4621/// not support named parameters they would be ignored on the macro definition.4622/// But to support both styles of parameters this is not possible so if a macro4623/// definition has named parameters but does not use them and has what appears4624/// to be positional parameters, strings like $1, $2, ... and $n, then issue a4625/// warning that the positional parameter found in body which have no effect.4626/// Hoping the developer will either remove the named parameters from the macro4627/// definition so the positional parameters get used if that was what was4628/// intended or change the macro to use the named parameters. It is possible4629/// this warning will trigger when the none of the named parameters are used4630/// and the strings like $1 are infact to simply to be passed trough unchanged.4631void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,4632 StringRef Body,4633 ArrayRef<MCAsmMacroParameter> Parameters) {4634 // If this macro is not defined with named parameters the warning we are4635 // checking for here doesn't apply.4636 unsigned NParameters = Parameters.size();4637 if (NParameters == 0)4638 return;4639 4640 bool NamedParametersFound = false;4641 bool PositionalParametersFound = false;4642 4643 // Look at the body of the macro for use of both the named parameters and what4644 // are likely to be positional parameters. This is what expandMacro() is4645 // doing when it finds the parameters in the body.4646 while (!Body.empty()) {4647 // Scan for the next possible parameter.4648 std::size_t End = Body.size(), Pos = 0;4649 for (; Pos != End; ++Pos) {4650 // Check for a substitution or escape.4651 // This macro is defined with parameters, look for \foo, \bar, etc.4652 if (Body[Pos] == '\\' && Pos + 1 != End)4653 break;4654 4655 // This macro should have parameters, but look for $0, $1, ..., $n too.4656 if (Body[Pos] != '$' || Pos + 1 == End)4657 continue;4658 char Next = Body[Pos + 1];4659 if (Next == '$' || Next == 'n' ||4660 isdigit(static_cast<unsigned char>(Next)))4661 break;4662 }4663 4664 // Check if we reached the end.4665 if (Pos == End)4666 break;4667 4668 if (Body[Pos] == '$') {4669 switch (Body[Pos + 1]) {4670 // $$ => $4671 case '$':4672 break;4673 4674 // $n => number of arguments4675 case 'n':4676 PositionalParametersFound = true;4677 break;4678 4679 // $[0-9] => argument4680 default: {4681 PositionalParametersFound = true;4682 break;4683 }4684 }4685 Pos += 2;4686 } else {4687 unsigned I = Pos + 1;4688 while (isIdentifierChar(Body[I]) && I + 1 != End)4689 ++I;4690 4691 const char *Begin = Body.data() + Pos + 1;4692 StringRef Argument(Begin, I - (Pos + 1));4693 unsigned Index = 0;4694 for (; Index < NParameters; ++Index)4695 if (Parameters[Index].Name == Argument)4696 break;4697 4698 if (Index == NParameters) {4699 if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')4700 Pos += 3;4701 else {4702 Pos = I;4703 }4704 } else {4705 NamedParametersFound = true;4706 Pos += 1 + Argument.size();4707 }4708 }4709 // Update the scan point.4710 Body = Body.substr(Pos);4711 }4712 4713 if (!NamedParametersFound && PositionalParametersFound)4714 Warning(DirectiveLoc, "macro defined with named parameters which are not "4715 "used in macro body, possible positional parameter "4716 "found in body which will have no effect");4717}4718 4719/// parseDirectiveExitMacro4720/// ::= .exitm4721bool AsmParser::parseDirectiveExitMacro(StringRef Directive) {4722 if (parseEOL())4723 return true;4724 4725 if (!isInsideMacroInstantiation())4726 return TokError("unexpected '" + Directive + "' in file, "4727 "no current macro definition");4728 4729 // Exit all conditionals that are active in the current macro.4730 while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {4731 TheCondState = TheCondStack.back();4732 TheCondStack.pop_back();4733 }4734 4735 handleMacroExit();4736 return false;4737}4738 4739/// parseDirectiveEndMacro4740/// ::= .endm4741/// ::= .endmacro4742bool AsmParser::parseDirectiveEndMacro(StringRef Directive) {4743 if (getLexer().isNot(AsmToken::EndOfStatement))4744 return TokError("unexpected token in '" + Directive + "' directive");4745 4746 // If we are inside a macro instantiation, terminate the current4747 // instantiation.4748 if (isInsideMacroInstantiation()) {4749 handleMacroExit();4750 return false;4751 }4752 4753 // Otherwise, this .endmacro is a stray entry in the file; well formed4754 // .endmacro directives are handled during the macro definition parsing.4755 return TokError("unexpected '" + Directive + "' in file, "4756 "no current macro definition");4757}4758 4759/// parseDirectivePurgeMacro4760/// ::= .purgem name4761bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {4762 StringRef Name;4763 SMLoc Loc;4764 if (parseTokenLoc(Loc) ||4765 check(parseIdentifier(Name), Loc,4766 "expected identifier in '.purgem' directive") ||4767 parseEOL())4768 return true;4769 4770 if (!getContext().lookupMacro(Name))4771 return Error(DirectiveLoc, "macro '" + Name + "' is not defined");4772 4773 getContext().undefineMacro(Name);4774 DEBUG_WITH_TYPE("asm-macros", dbgs()4775 << "Un-defining macro: " << Name << "\n");4776 return false;4777}4778 4779/// parseDirectiveSpace4780/// ::= (.skip | .space) expression [ , expression ]4781bool AsmParser::parseDirectiveSpace(StringRef IDVal) {4782 SMLoc NumBytesLoc = Lexer.getLoc();4783 const MCExpr *NumBytes;4784 if (checkForValidSection() || parseExpression(NumBytes))4785 return true;4786 4787 int64_t FillExpr = 0;4788 if (parseOptionalToken(AsmToken::Comma))4789 if (parseAbsoluteExpression(FillExpr))4790 return true;4791 if (parseEOL())4792 return true;4793 4794 // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0.4795 getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc);4796 4797 return false;4798}4799 4800/// parseDirectiveDCB4801/// ::= .dcb.{b, l, w} expression, expression4802bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) {4803 SMLoc NumValuesLoc = Lexer.getLoc();4804 int64_t NumValues;4805 if (checkForValidSection() || parseAbsoluteExpression(NumValues))4806 return true;4807 4808 if (NumValues < 0) {4809 Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");4810 return false;4811 }4812 4813 if (parseComma())4814 return true;4815 4816 const MCExpr *Value;4817 SMLoc ExprLoc = getLexer().getLoc();4818 if (parseExpression(Value))4819 return true;4820 4821 // Special case constant expressions to match code generator.4822 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {4823 assert(Size <= 8 && "Invalid size");4824 uint64_t IntValue = MCE->getValue();4825 if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))4826 return Error(ExprLoc, "literal value out of range for directive");4827 for (uint64_t i = 0, e = NumValues; i != e; ++i)4828 getStreamer().emitIntValue(IntValue, Size);4829 } else {4830 for (uint64_t i = 0, e = NumValues; i != e; ++i)4831 getStreamer().emitValue(Value, Size, ExprLoc);4832 }4833 4834 return parseEOL();4835}4836 4837/// parseDirectiveRealDCB4838/// ::= .dcb.{d, s} expression, expression4839bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) {4840 SMLoc NumValuesLoc = Lexer.getLoc();4841 int64_t NumValues;4842 if (checkForValidSection() || parseAbsoluteExpression(NumValues))4843 return true;4844 4845 if (NumValues < 0) {4846 Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");4847 return false;4848 }4849 4850 if (parseComma())4851 return true;4852 4853 APInt AsInt;4854 if (parseRealValue(Semantics, AsInt) || parseEOL())4855 return true;4856 4857 for (uint64_t i = 0, e = NumValues; i != e; ++i)4858 getStreamer().emitIntValue(AsInt.getLimitedValue(),4859 AsInt.getBitWidth() / 8);4860 4861 return false;4862}4863 4864/// parseDirectiveDS4865/// ::= .ds.{b, d, l, p, s, w, x} expression4866bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) {4867 SMLoc NumValuesLoc = Lexer.getLoc();4868 int64_t NumValues;4869 if (checkForValidSection() || parseAbsoluteExpression(NumValues) ||4870 parseEOL())4871 return true;4872 4873 if (NumValues < 0) {4874 Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");4875 return false;4876 }4877 4878 for (uint64_t i = 0, e = NumValues; i != e; ++i)4879 getStreamer().emitFill(Size, 0);4880 4881 return false;4882}4883 4884/// parseDirectiveLEB1284885/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ]4886bool AsmParser::parseDirectiveLEB128(bool Signed) {4887 if (checkForValidSection())4888 return true;4889 4890 auto parseOp = [&]() -> bool {4891 const MCExpr *Value;4892 if (parseExpression(Value))4893 return true;4894 if (Signed)4895 getStreamer().emitSLEB128Value(Value);4896 else4897 getStreamer().emitULEB128Value(Value);4898 return false;4899 };4900 4901 return parseMany(parseOp);4902}4903 4904/// parseDirectiveSymbolAttribute4905/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]4906bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {4907 auto parseOp = [&]() -> bool {4908 StringRef Name;4909 SMLoc Loc = getTok().getLoc();4910 if (parseIdentifier(Name))4911 return Error(Loc, "expected identifier");4912 4913 if (discardLTOSymbol(Name))4914 return false;4915 4916 MCSymbol *Sym = getContext().parseSymbol(Name);4917 4918 // Assembler local symbols don't make any sense here, except for directives4919 // that the symbol should be tagged.4920 if (Sym->isTemporary() && Attr != MCSA_Memtag)4921 return Error(Loc, "non-local symbol required");4922 4923 if (!getStreamer().emitSymbolAttribute(Sym, Attr))4924 return Error(Loc, "unable to emit symbol attribute");4925 return false;4926 };4927 4928 return parseMany(parseOp);4929}4930 4931/// parseDirectiveComm4932/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]4933bool AsmParser::parseDirectiveComm(bool IsLocal) {4934 if (checkForValidSection())4935 return true;4936 4937 SMLoc IDLoc = getLexer().getLoc();4938 MCSymbol *Sym;4939 if (parseSymbol(Sym))4940 return TokError("expected identifier in directive");4941 4942 if (parseComma())4943 return true;4944 4945 int64_t Size;4946 SMLoc SizeLoc = getLexer().getLoc();4947 if (parseAbsoluteExpression(Size))4948 return true;4949 4950 int64_t Pow2Alignment = 0;4951 SMLoc Pow2AlignmentLoc;4952 if (getLexer().is(AsmToken::Comma)) {4953 Lex();4954 Pow2AlignmentLoc = getLexer().getLoc();4955 if (parseAbsoluteExpression(Pow2Alignment))4956 return true;4957 4958 LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();4959 if (IsLocal && LCOMM == LCOMM::NoAlignment)4960 return Error(Pow2AlignmentLoc, "alignment not supported on this target");4961 4962 // If this target takes alignments in bytes (not log) validate and convert.4963 if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||4964 (IsLocal && LCOMM == LCOMM::ByteAlignment)) {4965 if (!isPowerOf2_64(Pow2Alignment))4966 return Error(Pow2AlignmentLoc, "alignment must be a power of 2");4967 Pow2Alignment = Log2_64(Pow2Alignment);4968 }4969 }4970 4971 if (parseEOL())4972 return true;4973 4974 // NOTE: a size of zero for a .comm should create a undefined symbol4975 // but a size of .lcomm creates a bss symbol of size zero.4976 if (Size < 0)4977 return Error(SizeLoc, "size must be non-negative");4978 4979 Sym->redefineIfPossible();4980 if (!Sym->isUndefined())4981 return Error(IDLoc, "invalid symbol redefinition");4982 4983 // Create the Symbol as a common or local common with Size and Pow2Alignment4984 if (IsLocal) {4985 getStreamer().emitLocalCommonSymbol(Sym, Size,4986 Align(1ULL << Pow2Alignment));4987 return false;4988 }4989 4990 getStreamer().emitCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));4991 return false;4992}4993 4994/// parseDirectiveAbort4995/// ::= .abort [... message ...]4996bool AsmParser::parseDirectiveAbort(SMLoc DirectiveLoc) {4997 StringRef Str = parseStringToEndOfStatement();4998 if (parseEOL())4999 return true;5000 5001 if (Str.empty())5002 return Error(DirectiveLoc, ".abort detected. Assembly stopping");5003 5004 // FIXME: Actually abort assembly here.5005 return Error(DirectiveLoc,5006 ".abort '" + Str + "' detected. Assembly stopping");5007}5008 5009/// parseDirectiveInclude5010/// ::= .include "filename"5011bool AsmParser::parseDirectiveInclude() {5012 // Allow the strings to have escaped octal character sequence.5013 std::string Filename;5014 SMLoc IncludeLoc = getTok().getLoc();5015 5016 if (check(getTok().isNot(AsmToken::String),5017 "expected string in '.include' directive") ||5018 parseEscapedString(Filename) ||5019 check(getTok().isNot(AsmToken::EndOfStatement),5020 "unexpected token in '.include' directive") ||5021 // Attempt to switch the lexer to the included file before consuming the5022 // end of statement to avoid losing it when we switch.5023 check(enterIncludeFile(Filename), IncludeLoc,5024 "Could not find include file '" + Filename + "'"))5025 return true;5026 5027 return false;5028}5029 5030/// parseDirectiveIncbin5031/// ::= .incbin "filename" [ , skip [ , count ] ]5032bool AsmParser::parseDirectiveIncbin() {5033 // Allow the strings to have escaped octal character sequence.5034 std::string Filename;5035 SMLoc IncbinLoc = getTok().getLoc();5036 if (check(getTok().isNot(AsmToken::String),5037 "expected string in '.incbin' directive") ||5038 parseEscapedString(Filename))5039 return true;5040 5041 int64_t Skip = 0;5042 const MCExpr *Count = nullptr;5043 SMLoc SkipLoc, CountLoc;5044 if (parseOptionalToken(AsmToken::Comma)) {5045 // The skip expression can be omitted while specifying the count, e.g:5046 // .incbin "filename",,45047 if (getTok().isNot(AsmToken::Comma)) {5048 if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip))5049 return true;5050 }5051 if (parseOptionalToken(AsmToken::Comma)) {5052 CountLoc = getTok().getLoc();5053 if (parseExpression(Count))5054 return true;5055 }5056 }5057 5058 if (parseEOL())5059 return true;5060 5061 if (check(Skip < 0, SkipLoc, "skip is negative"))5062 return true;5063 5064 // Attempt to process the included file.5065 if (processIncbinFile(Filename, Skip, Count, CountLoc))5066 return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'");5067 return false;5068}5069 5070/// parseDirectiveIf5071/// ::= .if{,eq,ge,gt,le,lt,ne} expression5072bool AsmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {5073 TheCondStack.push_back(TheCondState);5074 TheCondState.TheCond = AsmCond::IfCond;5075 if (TheCondState.Ignore) {5076 eatToEndOfStatement();5077 } else {5078 int64_t ExprValue;5079 if (parseAbsoluteExpression(ExprValue) || parseEOL())5080 return true;5081 5082 switch (DirKind) {5083 default:5084 llvm_unreachable("unsupported directive");5085 case DK_IF:5086 case DK_IFNE:5087 break;5088 case DK_IFEQ:5089 ExprValue = ExprValue == 0;5090 break;5091 case DK_IFGE:5092 ExprValue = ExprValue >= 0;5093 break;5094 case DK_IFGT:5095 ExprValue = ExprValue > 0;5096 break;5097 case DK_IFLE:5098 ExprValue = ExprValue <= 0;5099 break;5100 case DK_IFLT:5101 ExprValue = ExprValue < 0;5102 break;5103 }5104 5105 TheCondState.CondMet = ExprValue;5106 TheCondState.Ignore = !TheCondState.CondMet;5107 }5108 5109 return false;5110}5111 5112/// parseDirectiveIfb5113/// ::= .ifb string5114bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {5115 TheCondStack.push_back(TheCondState);5116 TheCondState.TheCond = AsmCond::IfCond;5117 5118 if (TheCondState.Ignore) {5119 eatToEndOfStatement();5120 } else {5121 StringRef Str = parseStringToEndOfStatement();5122 5123 if (parseEOL())5124 return true;5125 5126 TheCondState.CondMet = ExpectBlank == Str.empty();5127 TheCondState.Ignore = !TheCondState.CondMet;5128 }5129 5130 return false;5131}5132 5133/// parseDirectiveIfc5134/// ::= .ifc string1, string25135/// ::= .ifnc string1, string25136bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) {5137 TheCondStack.push_back(TheCondState);5138 TheCondState.TheCond = AsmCond::IfCond;5139 5140 if (TheCondState.Ignore) {5141 eatToEndOfStatement();5142 } else {5143 StringRef Str1 = parseStringToComma();5144 5145 if (parseComma())5146 return true;5147 5148 StringRef Str2 = parseStringToEndOfStatement();5149 5150 if (parseEOL())5151 return true;5152 5153 TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim());5154 TheCondState.Ignore = !TheCondState.CondMet;5155 }5156 5157 return false;5158}5159 5160/// parseDirectiveIfeqs5161/// ::= .ifeqs string1, string25162bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) {5163 TheCondStack.push_back(TheCondState);5164 TheCondState.TheCond = AsmCond::IfCond;5165 5166 if (TheCondState.Ignore) {5167 eatToEndOfStatement();5168 } else {5169 if (Lexer.isNot(AsmToken::String)) {5170 if (ExpectEqual)5171 return TokError("expected string parameter for '.ifeqs' directive");5172 return TokError("expected string parameter for '.ifnes' directive");5173 }5174 5175 StringRef String1 = getTok().getStringContents();5176 Lex();5177 5178 if (Lexer.isNot(AsmToken::Comma)) {5179 if (ExpectEqual)5180 return TokError(5181 "expected comma after first string for '.ifeqs' directive");5182 return TokError(5183 "expected comma after first string for '.ifnes' directive");5184 }5185 5186 Lex();5187 5188 if (Lexer.isNot(AsmToken::String)) {5189 if (ExpectEqual)5190 return TokError("expected string parameter for '.ifeqs' directive");5191 return TokError("expected string parameter for '.ifnes' directive");5192 }5193 5194 StringRef String2 = getTok().getStringContents();5195 Lex();5196 5197 TheCondState.CondMet = ExpectEqual == (String1 == String2);5198 TheCondState.Ignore = !TheCondState.CondMet;5199 }5200 5201 return false;5202}5203 5204/// parseDirectiveIfdef5205/// ::= .ifdef symbol5206bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {5207 StringRef Name;5208 TheCondStack.push_back(TheCondState);5209 TheCondState.TheCond = AsmCond::IfCond;5210 5211 if (TheCondState.Ignore) {5212 eatToEndOfStatement();5213 } else {5214 if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") ||5215 parseEOL())5216 return true;5217 5218 MCSymbol *Sym = getContext().lookupSymbol(Name);5219 5220 if (expect_defined)5221 TheCondState.CondMet = (Sym && !Sym->isUndefined());5222 else5223 TheCondState.CondMet = (!Sym || Sym->isUndefined());5224 TheCondState.Ignore = !TheCondState.CondMet;5225 }5226 5227 return false;5228}5229 5230/// parseDirectiveElseIf5231/// ::= .elseif expression5232bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) {5233 if (TheCondState.TheCond != AsmCond::IfCond &&5234 TheCondState.TheCond != AsmCond::ElseIfCond)5235 return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"5236 " .if or an .elseif");5237 TheCondState.TheCond = AsmCond::ElseIfCond;5238 5239 bool LastIgnoreState = false;5240 if (!TheCondStack.empty())5241 LastIgnoreState = TheCondStack.back().Ignore;5242 if (LastIgnoreState || TheCondState.CondMet) {5243 TheCondState.Ignore = true;5244 eatToEndOfStatement();5245 } else {5246 int64_t ExprValue;5247 if (parseAbsoluteExpression(ExprValue))5248 return true;5249 5250 if (parseEOL())5251 return true;5252 5253 TheCondState.CondMet = ExprValue;5254 TheCondState.Ignore = !TheCondState.CondMet;5255 }5256 5257 return false;5258}5259 5260/// parseDirectiveElse5261/// ::= .else5262bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) {5263 if (parseEOL())5264 return true;5265 5266 if (TheCondState.TheCond != AsmCond::IfCond &&5267 TheCondState.TheCond != AsmCond::ElseIfCond)5268 return Error(DirectiveLoc, "Encountered a .else that doesn't follow "5269 " an .if or an .elseif");5270 TheCondState.TheCond = AsmCond::ElseCond;5271 bool LastIgnoreState = false;5272 if (!TheCondStack.empty())5273 LastIgnoreState = TheCondStack.back().Ignore;5274 if (LastIgnoreState || TheCondState.CondMet)5275 TheCondState.Ignore = true;5276 else5277 TheCondState.Ignore = false;5278 5279 return false;5280}5281 5282/// parseDirectiveEnd5283/// ::= .end5284bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {5285 if (parseEOL())5286 return true;5287 5288 while (Lexer.isNot(AsmToken::Eof))5289 Lexer.Lex();5290 5291 return false;5292}5293 5294/// parseDirectiveError5295/// ::= .err5296/// ::= .error [string]5297bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) {5298 if (!TheCondStack.empty()) {5299 if (TheCondStack.back().Ignore) {5300 eatToEndOfStatement();5301 return false;5302 }5303 }5304 5305 if (!WithMessage)5306 return Error(L, ".err encountered");5307 5308 StringRef Message = ".error directive invoked in source file";5309 if (Lexer.isNot(AsmToken::EndOfStatement)) {5310 if (Lexer.isNot(AsmToken::String))5311 return TokError(".error argument must be a string");5312 5313 Message = getTok().getStringContents();5314 Lex();5315 }5316 5317 return Error(L, Message);5318}5319 5320/// parseDirectiveWarning5321/// ::= .warning [string]5322bool AsmParser::parseDirectiveWarning(SMLoc L) {5323 if (!TheCondStack.empty()) {5324 if (TheCondStack.back().Ignore) {5325 eatToEndOfStatement();5326 return false;5327 }5328 }5329 5330 StringRef Message = ".warning directive invoked in source file";5331 5332 if (!parseOptionalToken(AsmToken::EndOfStatement)) {5333 if (Lexer.isNot(AsmToken::String))5334 return TokError(".warning argument must be a string");5335 5336 Message = getTok().getStringContents();5337 Lex();5338 if (parseEOL())5339 return true;5340 }5341 5342 return Warning(L, Message);5343}5344 5345/// parseDirectiveEndIf5346/// ::= .endif5347bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {5348 if (parseEOL())5349 return true;5350 5351 if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())5352 return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "5353 "an .if or .else");5354 if (!TheCondStack.empty()) {5355 TheCondState = TheCondStack.back();5356 TheCondStack.pop_back();5357 }5358 5359 return false;5360}5361 5362void AsmParser::initializeDirectiveKindMap() {5363 /* Lookup will be done with the directive5364 * converted to lower case, so all these5365 * keys should be lower case.5366 * (target specific directives are handled5367 * elsewhere)5368 */5369 DirectiveKindMap[".set"] = DK_SET;5370 DirectiveKindMap[".equ"] = DK_EQU;5371 DirectiveKindMap[".equiv"] = DK_EQUIV;5372 DirectiveKindMap[".ascii"] = DK_ASCII;5373 DirectiveKindMap[".asciz"] = DK_ASCIZ;5374 DirectiveKindMap[".string"] = DK_STRING;5375 DirectiveKindMap[".byte"] = DK_BYTE;5376 DirectiveKindMap[".base64"] = DK_BASE64;5377 DirectiveKindMap[".short"] = DK_SHORT;5378 DirectiveKindMap[".value"] = DK_VALUE;5379 DirectiveKindMap[".2byte"] = DK_2BYTE;5380 DirectiveKindMap[".long"] = DK_LONG;5381 DirectiveKindMap[".int"] = DK_INT;5382 DirectiveKindMap[".4byte"] = DK_4BYTE;5383 DirectiveKindMap[".quad"] = DK_QUAD;5384 DirectiveKindMap[".8byte"] = DK_8BYTE;5385 DirectiveKindMap[".octa"] = DK_OCTA;5386 DirectiveKindMap[".single"] = DK_SINGLE;5387 DirectiveKindMap[".float"] = DK_FLOAT;5388 DirectiveKindMap[".double"] = DK_DOUBLE;5389 DirectiveKindMap[".align"] = DK_ALIGN;5390 DirectiveKindMap[".align32"] = DK_ALIGN32;5391 DirectiveKindMap[".balign"] = DK_BALIGN;5392 DirectiveKindMap[".balignw"] = DK_BALIGNW;5393 DirectiveKindMap[".balignl"] = DK_BALIGNL;5394 DirectiveKindMap[".p2align"] = DK_P2ALIGN;5395 DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW;5396 DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL;5397 DirectiveKindMap[".org"] = DK_ORG;5398 DirectiveKindMap[".fill"] = DK_FILL;5399 DirectiveKindMap[".zero"] = DK_ZERO;5400 DirectiveKindMap[".extern"] = DK_EXTERN;5401 DirectiveKindMap[".globl"] = DK_GLOBL;5402 DirectiveKindMap[".global"] = DK_GLOBAL;5403 DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE;5404 DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP;5405 DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER;5406 DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN;5407 DirectiveKindMap[".reference"] = DK_REFERENCE;5408 DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION;5409 DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE;5410 DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN;5411 DirectiveKindMap[".cold"] = DK_COLD;5412 DirectiveKindMap[".comm"] = DK_COMM;5413 DirectiveKindMap[".common"] = DK_COMMON;5414 DirectiveKindMap[".lcomm"] = DK_LCOMM;5415 DirectiveKindMap[".abort"] = DK_ABORT;5416 DirectiveKindMap[".include"] = DK_INCLUDE;5417 DirectiveKindMap[".incbin"] = DK_INCBIN;5418 DirectiveKindMap[".code16"] = DK_CODE16;5419 DirectiveKindMap[".code16gcc"] = DK_CODE16GCC;5420 DirectiveKindMap[".rept"] = DK_REPT;5421 DirectiveKindMap[".rep"] = DK_REPT;5422 DirectiveKindMap[".irp"] = DK_IRP;5423 DirectiveKindMap[".irpc"] = DK_IRPC;5424 DirectiveKindMap[".endr"] = DK_ENDR;5425 DirectiveKindMap[".if"] = DK_IF;5426 DirectiveKindMap[".ifeq"] = DK_IFEQ;5427 DirectiveKindMap[".ifge"] = DK_IFGE;5428 DirectiveKindMap[".ifgt"] = DK_IFGT;5429 DirectiveKindMap[".ifle"] = DK_IFLE;5430 DirectiveKindMap[".iflt"] = DK_IFLT;5431 DirectiveKindMap[".ifne"] = DK_IFNE;5432 DirectiveKindMap[".ifb"] = DK_IFB;5433 DirectiveKindMap[".ifnb"] = DK_IFNB;5434 DirectiveKindMap[".ifc"] = DK_IFC;5435 DirectiveKindMap[".ifeqs"] = DK_IFEQS;5436 DirectiveKindMap[".ifnc"] = DK_IFNC;5437 DirectiveKindMap[".ifnes"] = DK_IFNES;5438 DirectiveKindMap[".ifdef"] = DK_IFDEF;5439 DirectiveKindMap[".ifndef"] = DK_IFNDEF;5440 DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF;5441 DirectiveKindMap[".elseif"] = DK_ELSEIF;5442 DirectiveKindMap[".else"] = DK_ELSE;5443 DirectiveKindMap[".end"] = DK_END;5444 DirectiveKindMap[".endif"] = DK_ENDIF;5445 DirectiveKindMap[".skip"] = DK_SKIP;5446 DirectiveKindMap[".space"] = DK_SPACE;5447 DirectiveKindMap[".file"] = DK_FILE;5448 DirectiveKindMap[".line"] = DK_LINE;5449 DirectiveKindMap[".loc"] = DK_LOC;5450 DirectiveKindMap[".loc_label"] = DK_LOC_LABEL;5451 DirectiveKindMap[".stabs"] = DK_STABS;5452 DirectiveKindMap[".cv_file"] = DK_CV_FILE;5453 DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;5454 DirectiveKindMap[".cv_loc"] = DK_CV_LOC;5455 DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;5456 DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;5457 DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;5458 DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;5459 DirectiveKindMap[".cv_string"] = DK_CV_STRING;5460 DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;5461 DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;5462 DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;5463 DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;5464 DirectiveKindMap[".sleb128"] = DK_SLEB128;5465 DirectiveKindMap[".uleb128"] = DK_ULEB128;5466 DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;5467 DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;5468 DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;5469 DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;5470 DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;5471 DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;5472 DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;5473 DirectiveKindMap[".cfi_llvm_def_aspace_cfa"] = DK_CFI_LLVM_DEF_ASPACE_CFA;5474 DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;5475 DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;5476 DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;5477 DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;5478 DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;5479 DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;5480 DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;5481 DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;5482 DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;5483 DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;5484 DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;5485 DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;5486 DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;5487 DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;5488 DirectiveKindMap[".cfi_label"] = DK_CFI_LABEL;5489 DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;5490 DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME;5491 DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;5492 DirectiveKindMap[".macros_on"] = DK_MACROS_ON;5493 DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;5494 DirectiveKindMap[".macro"] = DK_MACRO;5495 DirectiveKindMap[".exitm"] = DK_EXITM;5496 DirectiveKindMap[".endm"] = DK_ENDM;5497 DirectiveKindMap[".endmacro"] = DK_ENDMACRO;5498 DirectiveKindMap[".purgem"] = DK_PURGEM;5499 DirectiveKindMap[".err"] = DK_ERR;5500 DirectiveKindMap[".error"] = DK_ERROR;5501 DirectiveKindMap[".warning"] = DK_WARNING;5502 DirectiveKindMap[".altmacro"] = DK_ALTMACRO;5503 DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;5504 DirectiveKindMap[".reloc"] = DK_RELOC;5505 DirectiveKindMap[".dc"] = DK_DC;5506 DirectiveKindMap[".dc.a"] = DK_DC_A;5507 DirectiveKindMap[".dc.b"] = DK_DC_B;5508 DirectiveKindMap[".dc.d"] = DK_DC_D;5509 DirectiveKindMap[".dc.l"] = DK_DC_L;5510 DirectiveKindMap[".dc.s"] = DK_DC_S;5511 DirectiveKindMap[".dc.w"] = DK_DC_W;5512 DirectiveKindMap[".dc.x"] = DK_DC_X;5513 DirectiveKindMap[".dcb"] = DK_DCB;5514 DirectiveKindMap[".dcb.b"] = DK_DCB_B;5515 DirectiveKindMap[".dcb.d"] = DK_DCB_D;5516 DirectiveKindMap[".dcb.l"] = DK_DCB_L;5517 DirectiveKindMap[".dcb.s"] = DK_DCB_S;5518 DirectiveKindMap[".dcb.w"] = DK_DCB_W;5519 DirectiveKindMap[".dcb.x"] = DK_DCB_X;5520 DirectiveKindMap[".ds"] = DK_DS;5521 DirectiveKindMap[".ds.b"] = DK_DS_B;5522 DirectiveKindMap[".ds.d"] = DK_DS_D;5523 DirectiveKindMap[".ds.l"] = DK_DS_L;5524 DirectiveKindMap[".ds.p"] = DK_DS_P;5525 DirectiveKindMap[".ds.s"] = DK_DS_S;5526 DirectiveKindMap[".ds.w"] = DK_DS_W;5527 DirectiveKindMap[".ds.x"] = DK_DS_X;5528 DirectiveKindMap[".print"] = DK_PRINT;5529 DirectiveKindMap[".addrsig"] = DK_ADDRSIG;5530 DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM;5531 DirectiveKindMap[".pseudoprobe"] = DK_PSEUDO_PROBE;5532 DirectiveKindMap[".lto_discard"] = DK_LTO_DISCARD;5533 DirectiveKindMap[".lto_set_conditional"] = DK_LTO_SET_CONDITIONAL;5534 DirectiveKindMap[".memtag"] = DK_MEMTAG;5535}5536 5537MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {5538 AsmToken EndToken, StartToken = getTok();5539 5540 unsigned NestLevel = 0;5541 while (true) {5542 // Check whether we have reached the end of the file.5543 if (getLexer().is(AsmToken::Eof)) {5544 printError(DirectiveLoc, "no matching '.endr' in definition");5545 return nullptr;5546 }5547 5548 if (Lexer.is(AsmToken::Identifier)) {5549 StringRef Ident = getTok().getIdentifier();5550 if (Ident == ".rep" || Ident == ".rept" || Ident == ".irp" ||5551 Ident == ".irpc") {5552 ++NestLevel;5553 } else if (Ident == ".endr") {5554 if (NestLevel == 0) {5555 EndToken = getTok();5556 Lex();5557 if (Lexer.is(AsmToken::EndOfStatement))5558 break;5559 printError(getTok().getLoc(), "expected newline");5560 return nullptr;5561 }5562 --NestLevel;5563 }5564 }5565 5566 // Otherwise, scan till the end of the statement.5567 eatToEndOfStatement();5568 }5569 5570 const char *BodyStart = StartToken.getLoc().getPointer();5571 const char *BodyEnd = EndToken.getLoc().getPointer();5572 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);5573 5574 // We Are Anonymous.5575 MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());5576 return &MacroLikeBodies.back();5577}5578 5579void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,5580 raw_svector_ostream &OS) {5581 OS << ".endr\n";5582 5583 std::unique_ptr<MemoryBuffer> Instantiation =5584 MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");5585 5586 // Create the macro instantiation object and add to the current macro5587 // instantiation stack.5588 MacroInstantiation *MI = new MacroInstantiation{5589 DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};5590 ActiveMacros.push_back(MI);5591 5592 // Jump to the macro instantiation and prime the lexer.5593 CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());5594 Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());5595 Lex();5596}5597 5598/// parseDirectiveRept5599/// ::= .rep | .rept count5600bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {5601 const MCExpr *CountExpr;5602 SMLoc CountLoc = getTok().getLoc();5603 if (parseExpression(CountExpr))5604 return true;5605 5606 int64_t Count;5607 if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {5608 return Error(CountLoc, "unexpected token in '" + Dir + "' directive");5609 }5610 5611 if (check(Count < 0, CountLoc, "Count is negative") || parseEOL())5612 return true;5613 5614 // Lex the rept definition.5615 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5616 if (!M)5617 return true;5618 5619 // Macro instantiation is lexical, unfortunately. We construct a new buffer5620 // to hold the macro body with substitutions.5621 SmallString<256> Buf;5622 raw_svector_ostream OS(Buf);5623 while (Count--) {5624 // Note that the AtPseudoVariable is disabled for instantiations of .rep(t).5625 if (expandMacro(OS, *M, {}, {}, false))5626 return true;5627 }5628 instantiateMacroLikeBody(M, DirectiveLoc, OS);5629 5630 return false;5631}5632 5633/// parseDirectiveIrp5634/// ::= .irp symbol,values5635bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {5636 MCAsmMacroParameter Parameter;5637 MCAsmMacroArguments A;5638 if (check(parseIdentifier(Parameter.Name),5639 "expected identifier in '.irp' directive") ||5640 parseComma() || parseMacroArguments(nullptr, A) || parseEOL())5641 return true;5642 5643 // Lex the irp definition.5644 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5645 if (!M)5646 return true;5647 5648 // Macro instantiation is lexical, unfortunately. We construct a new buffer5649 // to hold the macro body with substitutions.5650 SmallString<256> Buf;5651 raw_svector_ostream OS(Buf);5652 5653 for (const MCAsmMacroArgument &Arg : A) {5654 // Note that the AtPseudoVariable is enabled for instantiations of .irp.5655 // This is undocumented, but GAS seems to support it.5656 if (expandMacro(OS, *M, Parameter, Arg, true))5657 return true;5658 }5659 5660 instantiateMacroLikeBody(M, DirectiveLoc, OS);5661 5662 return false;5663}5664 5665/// parseDirectiveIrpc5666/// ::= .irpc symbol,values5667bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {5668 MCAsmMacroParameter Parameter;5669 MCAsmMacroArguments A;5670 5671 if (check(parseIdentifier(Parameter.Name),5672 "expected identifier in '.irpc' directive") ||5673 parseComma() || parseMacroArguments(nullptr, A))5674 return true;5675 5676 if (A.size() != 1 || A.front().size() != 1)5677 return TokError("unexpected token in '.irpc' directive");5678 if (parseEOL())5679 return true;5680 5681 // Lex the irpc definition.5682 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5683 if (!M)5684 return true;5685 5686 // Macro instantiation is lexical, unfortunately. We construct a new buffer5687 // to hold the macro body with substitutions.5688 SmallString<256> Buf;5689 raw_svector_ostream OS(Buf);5690 5691 StringRef Values = A[0][0].is(AsmToken::String) ? A[0][0].getStringContents()5692 : A[0][0].getString();5693 for (std::size_t I = 0, End = Values.size(); I != End; ++I) {5694 MCAsmMacroArgument Arg;5695 Arg.emplace_back(AsmToken::Identifier, Values.substr(I, 1));5696 5697 // Note that the AtPseudoVariable is enabled for instantiations of .irpc.5698 // This is undocumented, but GAS seems to support it.5699 if (expandMacro(OS, *M, Parameter, Arg, true))5700 return true;5701 }5702 5703 instantiateMacroLikeBody(M, DirectiveLoc, OS);5704 5705 return false;5706}5707 5708bool AsmParser::parseDirectiveEndr(SMLoc DirectiveLoc) {5709 if (ActiveMacros.empty())5710 return TokError("unmatched '.endr' directive");5711 5712 // The only .repl that should get here are the ones created by5713 // instantiateMacroLikeBody.5714 assert(getLexer().is(AsmToken::EndOfStatement));5715 5716 handleMacroExit();5717 return false;5718}5719 5720bool AsmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,5721 size_t Len) {5722 const MCExpr *Value;5723 SMLoc ExprLoc = getLexer().getLoc();5724 if (parseExpression(Value))5725 return true;5726 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5727 if (!MCE)5728 return Error(ExprLoc, "unexpected expression in _emit");5729 uint64_t IntValue = MCE->getValue();5730 if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))5731 return Error(ExprLoc, "literal value out of range for directive");5732 5733 Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);5734 return false;5735}5736 5737bool AsmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {5738 const MCExpr *Value;5739 SMLoc ExprLoc = getLexer().getLoc();5740 if (parseExpression(Value))5741 return true;5742 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5743 if (!MCE)5744 return Error(ExprLoc, "unexpected expression in align");5745 uint64_t IntValue = MCE->getValue();5746 if (!isPowerOf2_64(IntValue))5747 return Error(ExprLoc, "literal value not a power of two greater then zero");5748 5749 Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));5750 return false;5751}5752 5753bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) {5754 const AsmToken StrTok = getTok();5755 Lex();5756 if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"')5757 return Error(DirectiveLoc, "expected double quoted string after .print");5758 if (parseEOL())5759 return true;5760 llvm::outs() << StrTok.getStringContents() << '\n';5761 return false;5762}5763 5764bool AsmParser::parseDirectiveAddrsig() {5765 if (parseEOL())5766 return true;5767 getStreamer().emitAddrsig();5768 return false;5769}5770 5771bool AsmParser::parseDirectiveAddrsigSym() {5772 MCSymbol *Sym;5773 if (check(parseSymbol(Sym), "expected identifier") || parseEOL())5774 return true;5775 getStreamer().emitAddrsigSym(Sym);5776 return false;5777}5778 5779bool AsmParser::parseDirectivePseudoProbe() {5780 int64_t Guid;5781 int64_t Index;5782 int64_t Type;5783 int64_t Attr;5784 int64_t Discriminator = 0;5785 if (parseIntToken(Guid))5786 return true;5787 if (parseIntToken(Index))5788 return true;5789 if (parseIntToken(Type))5790 return true;5791 if (parseIntToken(Attr))5792 return true;5793 if (hasDiscriminator(Attr) && parseIntToken(Discriminator))5794 return true;5795 5796 // Parse inline stack like @ GUID:11:12 @ GUID:1:11 @ GUID:3:215797 MCPseudoProbeInlineStack InlineStack;5798 5799 while (getLexer().is(AsmToken::At)) {5800 // eat @5801 Lex();5802 5803 int64_t CallerGuid = 0;5804 if (getLexer().is(AsmToken::Integer)) {5805 CallerGuid = getTok().getIntVal();5806 Lex();5807 }5808 5809 // eat colon5810 if (getLexer().is(AsmToken::Colon))5811 Lex();5812 5813 int64_t CallerProbeId = 0;5814 if (getLexer().is(AsmToken::Integer)) {5815 CallerProbeId = getTok().getIntVal();5816 Lex();5817 }5818 5819 InlineSite Site(CallerGuid, CallerProbeId);5820 InlineStack.push_back(Site);5821 }5822 5823 // Parse function entry name5824 StringRef FnName;5825 if (parseIdentifier(FnName))5826 return Error(getLexer().getLoc(), "expected identifier");5827 MCSymbol *FnSym = getContext().lookupSymbol(FnName);5828 5829 if (parseEOL())5830 return true;5831 5832 getStreamer().emitPseudoProbe(Guid, Index, Type, Attr, Discriminator,5833 InlineStack, FnSym);5834 return false;5835}5836 5837/// parseDirectiveLTODiscard5838/// ::= ".lto_discard" [ identifier ( , identifier )* ]5839/// The LTO library emits this directive to discard non-prevailing symbols.5840/// We ignore symbol assignments and attribute changes for the specified5841/// symbols.5842bool AsmParser::parseDirectiveLTODiscard() {5843 auto ParseOp = [&]() -> bool {5844 StringRef Name;5845 SMLoc Loc = getTok().getLoc();5846 if (parseIdentifier(Name))5847 return Error(Loc, "expected identifier");5848 LTODiscardSymbols.insert(Name);5849 return false;5850 };5851 5852 LTODiscardSymbols.clear();5853 return parseMany(ParseOp);5854}5855 5856// We are comparing pointers, but the pointers are relative to a single string.5857// Thus, this should always be deterministic.5858static int rewritesSort(const AsmRewrite *AsmRewriteA,5859 const AsmRewrite *AsmRewriteB) {5860 if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())5861 return -1;5862 if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())5863 return 1;5864 5865 // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output5866 // rewrite to the same location. Make sure the SizeDirective rewrite is5867 // performed first, then the Imm/ImmPrefix and finally the Input/Output. This5868 // ensures the sort algorithm is stable.5869 if (AsmRewritePrecedence[AsmRewriteA->Kind] >5870 AsmRewritePrecedence[AsmRewriteB->Kind])5871 return -1;5872 5873 if (AsmRewritePrecedence[AsmRewriteA->Kind] <5874 AsmRewritePrecedence[AsmRewriteB->Kind])5875 return 1;5876 llvm_unreachable("Unstable rewrite sort.");5877}5878 5879bool AsmParser::parseMSInlineAsm(5880 std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs,5881 SmallVectorImpl<std::pair<void *, bool>> &OpDecls,5882 SmallVectorImpl<std::string> &Constraints,5883 SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,5884 MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {5885 SmallVector<void *, 4> InputDecls;5886 SmallVector<void *, 4> OutputDecls;5887 SmallVector<bool, 4> InputDeclsAddressOf;5888 SmallVector<bool, 4> OutputDeclsAddressOf;5889 SmallVector<std::string, 4> InputConstraints;5890 SmallVector<std::string, 4> OutputConstraints;5891 SmallVector<MCRegister, 4> ClobberRegs;5892 5893 SmallVector<AsmRewrite, 4> AsmStrRewrites;5894 5895 // Prime the lexer.5896 Lex();5897 5898 // While we have input, parse each statement.5899 unsigned InputIdx = 0;5900 unsigned OutputIdx = 0;5901 while (getLexer().isNot(AsmToken::Eof)) {5902 // Parse curly braces marking block start/end5903 if (parseCurlyBlockScope(AsmStrRewrites))5904 continue;5905 5906 ParseStatementInfo Info(&AsmStrRewrites);5907 bool StatementErr = parseStatement(Info, &SI);5908 5909 if (StatementErr || Info.ParseError) {5910 // Emit pending errors if any exist.5911 printPendingErrors();5912 return true;5913 }5914 5915 // No pending error should exist here.5916 assert(!hasPendingError() && "unexpected error from parseStatement");5917 5918 if (Info.Opcode == ~0U)5919 continue;5920 5921 const MCInstrDesc &Desc = MII->get(Info.Opcode);5922 5923 // Build the list of clobbers, outputs and inputs.5924 for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {5925 MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];5926 5927 // Register operand.5928 if (Operand.isReg() && !Operand.needAddressOf() &&5929 !getTargetParser().omitRegisterFromClobberLists(Operand.getReg())) {5930 unsigned NumDefs = Desc.getNumDefs();5931 // Clobber.5932 if (NumDefs && Operand.getMCOperandNum() < NumDefs)5933 ClobberRegs.push_back(Operand.getReg());5934 continue;5935 }5936 5937 // Expr/Input or Output.5938 StringRef SymName = Operand.getSymName();5939 if (SymName.empty())5940 continue;5941 5942 void *OpDecl = Operand.getOpDecl();5943 if (!OpDecl)5944 continue;5945 5946 StringRef Constraint = Operand.getConstraint();5947 if (Operand.isImm()) {5948 // Offset as immediate5949 if (Operand.isOffsetOfLocal())5950 Constraint = "r";5951 else5952 Constraint = "i";5953 }5954 5955 bool isOutput = (i == 1) && Desc.mayStore();5956 bool Restricted = Operand.isMemUseUpRegs();5957 SMLoc Start = SMLoc::getFromPointer(SymName.data());5958 if (isOutput) {5959 ++InputIdx;5960 OutputDecls.push_back(OpDecl);5961 OutputDeclsAddressOf.push_back(Operand.needAddressOf());5962 OutputConstraints.push_back(("=" + Constraint).str());5963 AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size(), 0,5964 Restricted);5965 } else {5966 InputDecls.push_back(OpDecl);5967 InputDeclsAddressOf.push_back(Operand.needAddressOf());5968 InputConstraints.push_back(Constraint.str());5969 if (Desc.operands()[i - 1].isBranchTarget())5970 AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size(), 0,5971 Restricted);5972 else5973 AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size(), 0,5974 Restricted);5975 }5976 }5977 5978 // Consider implicit defs to be clobbers. Think of cpuid and push.5979 llvm::append_range(ClobberRegs, Desc.implicit_defs());5980 }5981 5982 // Set the number of Outputs and Inputs.5983 NumOutputs = OutputDecls.size();5984 NumInputs = InputDecls.size();5985 5986 // Set the unique clobbers.5987 array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());5988 ClobberRegs.erase(llvm::unique(ClobberRegs), ClobberRegs.end());5989 Clobbers.assign(ClobberRegs.size(), std::string());5990 for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {5991 raw_string_ostream OS(Clobbers[I]);5992 IP->printRegName(OS, ClobberRegs[I]);5993 }5994 5995 // Merge the various outputs and inputs. Output are expected first.5996 if (NumOutputs || NumInputs) {5997 unsigned NumExprs = NumOutputs + NumInputs;5998 OpDecls.resize(NumExprs);5999 Constraints.resize(NumExprs);6000 for (unsigned i = 0; i < NumOutputs; ++i) {6001 OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);6002 Constraints[i] = OutputConstraints[i];6003 }6004 for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {6005 OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);6006 Constraints[j] = InputConstraints[i];6007 }6008 }6009 6010 // Build the IR assembly string.6011 std::string AsmStringIR;6012 raw_string_ostream OS(AsmStringIR);6013 StringRef ASMString =6014 SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();6015 const char *AsmStart = ASMString.begin();6016 const char *AsmEnd = ASMString.end();6017 array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);6018 for (auto I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) {6019 const AsmRewrite &AR = *I;6020 // Check if this has already been covered by another rewrite...6021 if (AR.Done)6022 continue;6023 AsmRewriteKind Kind = AR.Kind;6024 6025 const char *Loc = AR.Loc.getPointer();6026 assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");6027 6028 // Emit everything up to the immediate/expression.6029 if (unsigned Len = Loc - AsmStart)6030 OS << StringRef(AsmStart, Len);6031 6032 // Skip the original expression.6033 if (Kind == AOK_Skip) {6034 AsmStart = Loc + AR.Len;6035 continue;6036 }6037 6038 unsigned AdditionalSkip = 0;6039 // Rewrite expressions in $N notation.6040 switch (Kind) {6041 default:6042 break;6043 case AOK_IntelExpr:6044 assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");6045 if (AR.IntelExp.NeedBracs)6046 OS << "[";6047 if (AR.IntelExp.hasBaseReg())6048 OS << AR.IntelExp.BaseReg;6049 if (AR.IntelExp.hasIndexReg())6050 OS << (AR.IntelExp.hasBaseReg() ? " + " : "")6051 << AR.IntelExp.IndexReg;6052 if (AR.IntelExp.Scale > 1)6053 OS << " * $$" << AR.IntelExp.Scale;6054 if (AR.IntelExp.hasOffset()) {6055 if (AR.IntelExp.hasRegs())6056 OS << " + ";6057 // Fuse this rewrite with a rewrite of the offset name, if present.6058 StringRef OffsetName = AR.IntelExp.OffsetName;6059 SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());6060 size_t OffsetLen = OffsetName.size();6061 auto rewrite_it = std::find_if(6062 I, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) {6063 return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&6064 (FusingAR.Kind == AOK_Input ||6065 FusingAR.Kind == AOK_CallInput);6066 });6067 if (rewrite_it == AsmStrRewrites.end()) {6068 OS << "offset " << OffsetName;6069 } else if (rewrite_it->Kind == AOK_CallInput) {6070 OS << "${" << InputIdx++ << ":P}";6071 rewrite_it->Done = true;6072 } else {6073 OS << '$' << InputIdx++;6074 rewrite_it->Done = true;6075 }6076 }6077 if (AR.IntelExp.Imm || AR.IntelExp.emitImm())6078 OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;6079 if (AR.IntelExp.NeedBracs)6080 OS << "]";6081 break;6082 case AOK_Label:6083 OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;6084 break;6085 case AOK_Input:6086 if (AR.IntelExpRestricted)6087 OS << "${" << InputIdx++ << ":P}";6088 else6089 OS << '$' << InputIdx++;6090 break;6091 case AOK_CallInput:6092 OS << "${" << InputIdx++ << ":P}";6093 break;6094 case AOK_Output:6095 if (AR.IntelExpRestricted)6096 OS << "${" << OutputIdx++ << ":P}";6097 else6098 OS << '$' << OutputIdx++;6099 break;6100 case AOK_SizeDirective:6101 switch (AR.Val) {6102 default: break;6103 case 8: OS << "byte ptr "; break;6104 case 16: OS << "word ptr "; break;6105 case 32: OS << "dword ptr "; break;6106 case 64: OS << "qword ptr "; break;6107 case 80: OS << "xword ptr "; break;6108 case 128: OS << "xmmword ptr "; break;6109 case 256: OS << "ymmword ptr "; break;6110 }6111 break;6112 case AOK_Emit:6113 OS << ".byte";6114 break;6115 case AOK_Align: {6116 // MS alignment directives are measured in bytes. If the native assembler6117 // measures alignment in bytes, we can pass it straight through.6118 OS << ".align";6119 if (getContext().getAsmInfo()->getAlignmentIsInBytes())6120 break;6121 6122 // Alignment is in log2 form, so print that instead and skip the original6123 // immediate.6124 unsigned Val = AR.Val;6125 OS << ' ' << Val;6126 assert(Val < 10 && "Expected alignment less then 2^10.");6127 AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;6128 break;6129 }6130 case AOK_EVEN:6131 OS << ".even";6132 break;6133 case AOK_EndOfStatement:6134 OS << "\n\t";6135 break;6136 }6137 6138 // Skip the original expression.6139 AsmStart = Loc + AR.Len + AdditionalSkip;6140 }6141 6142 // Emit the remainder of the asm string.6143 if (AsmStart != AsmEnd)6144 OS << StringRef(AsmStart, AsmEnd - AsmStart);6145 6146 AsmString = std::move(AsmStringIR);6147 return false;6148}6149 6150bool HLASMAsmParser::parseAsHLASMLabel(ParseStatementInfo &Info,6151 MCAsmParserSemaCallback *SI) {6152 AsmToken LabelTok = getTok();6153 SMLoc LabelLoc = LabelTok.getLoc();6154 StringRef LabelVal;6155 6156 if (parseIdentifier(LabelVal))6157 return Error(LabelLoc, "The HLASM Label has to be an Identifier");6158 6159 // We have validated whether the token is an Identifier.6160 // Now we have to validate whether the token is a6161 // valid HLASM Label.6162 if (!getTargetParser().isLabel(LabelTok) || checkForValidSection())6163 return true;6164 6165 // Lex leading spaces to get to the next operand.6166 lexLeadingSpaces();6167 6168 // We shouldn't emit the label if there is nothing else after the label.6169 // i.e asm("<token>\n")6170 if (getTok().is(AsmToken::EndOfStatement))6171 return Error(LabelLoc,6172 "Cannot have just a label for an HLASM inline asm statement");6173 6174 MCSymbol *Sym = getContext().parseSymbol(6175 getContext().getAsmInfo()->isHLASM() ? LabelVal.upper() : LabelVal);6176 6177 // Emit the label.6178 Out.emitLabel(Sym, LabelLoc);6179 6180 // If we are generating dwarf for assembly source files then gather the6181 // info to make a dwarf label entry for this label if needed.6182 if (enabledGenDwarfForAssembly())6183 MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),6184 LabelLoc);6185 6186 return false;6187}6188 6189bool HLASMAsmParser::parseAsMachineInstruction(ParseStatementInfo &Info,6190 MCAsmParserSemaCallback *SI) {6191 AsmToken OperationEntryTok = Lexer.getTok();6192 SMLoc OperationEntryLoc = OperationEntryTok.getLoc();6193 StringRef OperationEntryVal;6194 6195 // Attempt to parse the first token as an Identifier6196 if (parseIdentifier(OperationEntryVal))6197 return Error(OperationEntryLoc, "unexpected token at start of statement");6198 6199 // Once we've parsed the operation entry successfully, lex6200 // any spaces to get to the OperandEntries.6201 lexLeadingSpaces();6202 6203 return parseAndMatchAndEmitTargetInstruction(6204 Info, OperationEntryVal, OperationEntryTok, OperationEntryLoc);6205}6206 6207bool HLASMAsmParser::parseStatement(ParseStatementInfo &Info,6208 MCAsmParserSemaCallback *SI) {6209 assert(!hasPendingError() && "parseStatement started with pending error");6210 6211 // Should the first token be interpreted as a HLASM Label.6212 bool ShouldParseAsHLASMLabel = false;6213 6214 // If a Name Entry exists, it should occur at the very6215 // start of the string. In this case, we should parse the6216 // first non-space token as a Label.6217 // If the Name entry is missing (i.e. there's some other6218 // token), then we attempt to parse the first non-space6219 // token as a Machine Instruction.6220 if (getTok().isNot(AsmToken::Space))6221 ShouldParseAsHLASMLabel = true;6222 6223 // If we have an EndOfStatement (which includes the target's comment6224 // string) we can appropriately lex it early on)6225 if (Lexer.is(AsmToken::EndOfStatement)) {6226 // if this is a line comment we can drop it safely6227 if (getTok().getString().empty() || getTok().getString().front() == '\r' ||6228 getTok().getString().front() == '\n')6229 Out.addBlankLine();6230 Lex();6231 return false;6232 }6233 6234 // We have established how to parse the inline asm statement.6235 // Now we can safely lex any leading spaces to get to the6236 // first token.6237 lexLeadingSpaces();6238 6239 // If we see a new line or carriage return as the first operand,6240 // after lexing leading spaces, emit the new line and lex the6241 // EndOfStatement token.6242 if (Lexer.is(AsmToken::EndOfStatement)) {6243 if (getTok().getString().front() == '\n' ||6244 getTok().getString().front() == '\r') {6245 Out.addBlankLine();6246 Lex();6247 return false;6248 }6249 }6250 6251 // Handle the label first if we have to before processing the rest6252 // of the tokens as a machine instruction.6253 if (ShouldParseAsHLASMLabel) {6254 // If there were any errors while handling and emitting the label,6255 // early return.6256 if (parseAsHLASMLabel(Info, SI)) {6257 // If we know we've failed in parsing, simply eat until end of the6258 // statement. This ensures that we don't process any other statements.6259 eatToEndOfStatement();6260 return true;6261 }6262 }6263 6264 return parseAsMachineInstruction(Info, SI);6265}6266 6267// Structural equality of two assembler-assignment expressions. Used only to6268// decide whether a repeated wasm "=" / ".set" assignment is an identical6269// (idempotent) redefinition; it must never report two genuinely-different6270// expressions as equal (that would silently merge a conflict). Conservative:6271// anything it cannot prove equal is treated as different.6272static bool isEquivalentAssignment(const MCExpr *A, const MCExpr *B) {6273 if (A == B)6274 return true;6275 if (!A || !B || A->getKind() != B->getKind())6276 return false;6277 switch (A->getKind()) {6278 case MCExpr::Constant:6279 return cast<MCConstantExpr>(A)->getValue() ==6280 cast<MCConstantExpr>(B)->getValue();6281 case MCExpr::SymbolRef: {6282 const auto *SA = cast<MCSymbolRefExpr>(A);6283 const auto *SB = cast<MCSymbolRefExpr>(B);6284 return &SA->getSymbol() == &SB->getSymbol() &&6285 SA->getSpecifier() == SB->getSpecifier();6286 }6287 case MCExpr::Unary: {6288 const auto *UA = cast<MCUnaryExpr>(A);6289 const auto *UB = cast<MCUnaryExpr>(B);6290 return UA->getOpcode() == UB->getOpcode() &&6291 isEquivalentAssignment(UA->getSubExpr(), UB->getSubExpr());6292 }6293 case MCExpr::Binary: {6294 const auto *BA = cast<MCBinaryExpr>(A);6295 const auto *BB = cast<MCBinaryExpr>(B);6296 return BA->getOpcode() == BB->getOpcode() &&6297 isEquivalentAssignment(BA->getLHS(), BB->getLHS()) &&6298 isEquivalentAssignment(BA->getRHS(), BB->getRHS());6299 }6300 case MCExpr::Specifier: {6301 const auto *PA = cast<MCSpecifierExpr>(A);6302 const auto *PB = cast<MCSpecifierExpr>(B);6303 return PA->getSpecifier() == PB->getSpecifier() &&6304 isEquivalentAssignment(PA->getSubExpr(), PB->getSubExpr());6305 }6306 case MCExpr::Target:6307 // Target-specific expressions have no generic comparison; treat distinct6308 // instances as different so a conflict is never silently accepted.6309 return false;6310 }6311 llvm_unreachable("invalid MCExpr kind");6312}6313 6314bool llvm::MCParserUtils::parseAssignmentExpression(StringRef Name,6315 bool allow_redef,6316 MCAsmParser &Parser,6317 MCSymbol *&Sym,6318 const MCExpr *&Value) {6319 6320 // FIXME: Use better location, we should use proper tokens.6321 SMLoc EqualLoc = Parser.getTok().getLoc();6322 if (Parser.parseExpression(Value))6323 return Parser.TokError("missing expression");6324 if (Parser.parseEOL())6325 return true;6326 // Relocation specifiers are not permitted. For now, handle just6327 // MCSymbolRefExpr.6328 if (auto *S = dyn_cast<MCSymbolRefExpr>(Value); S && S->getSpecifier())6329 return Parser.Error(6330 EqualLoc, "relocation specifier not permitted in symbol equating");6331 6332 // Validate that the LHS is allowed to be a variable (either it has not been6333 // used as a symbol, or it is an absolute symbol).6334 Sym = Parser.getContext().lookupSymbol(Name);6335 if (Sym) {6336 // wasm: an absolute-constant assignment ("sym = N" / ".set sym, N", no6337 // symbol reference) was lowered to a *defined data object* holding the6338 // constant (MCWasmStreamer::emitAssignment, 751ce8312), so the symbol is no6339 // longer a redefinable variable. glibc emits exactly this for address-taken6340 // linkage markers (e.g. _nl_current_LC_*_used from _NL_CURRENT_DEFINE in6341 // locale/localeinfo.h, x12 LC_* per locale TU), and llvm-link concatenates6342 // the per-TU module-asm without dedup, so the merged module carries several6343 // identical "sym = N" definitions. The first lowers to the data object;6344 // each later one reaches here as a redefinition of a now-defined label and6345 // used to fail loudly ("redefinition of 'sym'"), the surviving duplicate-6346 // definition consequence of the data-object lowering.6347 //6348 // Mirror the alias idempotence (66319942b) for this absolute-constant form,6349 // matching GNU-as where "=" / ".set" is freely reassignable and an identical6350 // reassignment is a no-op: a repeat to the *same* constant is accepted as6351 // idempotent (Sym is cleared so the caller skips re-emitting the label; the6352 // single data object already holds the value), and a repeat to a *different*6353 // value is a genuine conflict that is still rejected loudly -- never-silent,6354 // we never pick one of two differing definitions. wasm-guarded; ELF/COFF/6355 // MachO and the symbol-alias case are untouched. (HWJS-B-1; same module-asm6356 // family as 4f7e79cc9 / ad022aa91 / 751ce8312 / e55169103 / 3cfbb7dd5 /6357 // 66319942b.)6358 if (Parser.getContext().getObjectFileType() == MCContext::IsWasm &&6359 Sym->isDefined() && !Sym->isVariable()) {6360 if (auto *WS = static_cast<MCSymbolWasm *>(Sym);6361 WS->hasAbsoluteConstant()) {6362 int64_t NewConst;6363 if (Value->evaluateAsAbsolute(NewConst) &&6364 NewConst == WS->getAbsoluteConstant()) {6365 // Identical repeat: keep the single existing data object, emit6366 // nothing more.6367 Sym = nullptr;6368 return false;6369 }6370 return Parser.Error(6371 EqualLoc, "conflicting redefinition of '" + Name +6372 "' (wasm: an absolute-constant '=' / '.set' may be "6373 "repeated only with an identical value)");6374 }6375 }6376 if ((Sym->isVariable() || Sym->isDefined()) &&6377 (!allow_redef || !Sym->isRedefinable()))6378 return Parser.Error(EqualLoc, "redefinition of '" + Name + "'");6379 // If the symbol is redefinable, clone it and update the symbol table6380 // to the new symbol. Existing references to the original symbol remain6381 // unchanged.6382 if (Sym->isRedefinable()) {6383 // The wasm object format has no MCSymbol clone path: MCContext::cloneSymbol6384 // aborts with "fatal error: .set redefinition is not supported" for6385 // IsWasm. This is hit en masse when many glibc translation units are6386 // merged into one bitcode module with llvm-link: each TU emits the same6387 // module-level asm symbol assignment (e.g. "mempcpy = __mempcpy" from6388 // libc_hidden_def / weak_alias / __GI_ / <string.h> builtins), and the6389 // merged module's module-asm blocks are concatenated without dedup, so the6390 // identical "X = Y" appears more than once and the second one reaches this6391 // clone.6392 //6393 // Match GNU-as semantics, where "=" / ".set" is freely reassignable and an6394 // identical reassignment is a no-op: accept a redefinition to the *same*6395 // value as idempotent (keep the existing symbol; the caller re-emits the6396 // identical value harmlessly). A redefinition to a *different* value is a6397 // genuine conflict and is still rejected loudly -- never silently pick one.6398 // wasm-guarded; ELF/COFF/MachO keep their existing clone-based semantics.6399 // (HWJS-B-1; same X=Y module-asm family as 4f7e79cc9 / ad022aa91 /6400 // 751ce8312 / e55169103 / 3cfbb7dd5.)6401 if (Parser.getContext().getObjectFileType() == MCContext::IsWasm &&6402 Sym->isVariable()) {6403 if (isEquivalentAssignment(Sym->getVariableValue(), Value)) {6404 Sym->setRedefinable(allow_redef);6405 return false;6406 }6407 return Parser.Error(6408 EqualLoc, "conflicting redefinition of '" + Name +6409 "' (wasm: '=' / '.set' may be repeated only with an "6410 "identical value)");6411 }6412 Sym = Parser.getContext().cloneSymbol(*Sym);6413 }6414 } else if (Name == ".") {6415 Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc);6416 return false;6417 } else6418 Sym = Parser.getContext().parseSymbol(Name);6419 6420 Sym->setRedefinable(allow_redef);6421 6422 return false;6423}6424 6425/// Create an MCAsmParser instance.6426MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C,6427 MCStreamer &Out, const MCAsmInfo &MAI,6428 unsigned CB) {6429 if (C.getTargetTriple().isSystemZ() && C.getTargetTriple().isOSzOS())6430 return new HLASMAsmParser(SM, C, Out, MAI, CB);6431 6432 return new AsmParser(SM, C, Out, MAI, CB);6433}6434