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