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