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