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 unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(Loc: DiagLoc);
2402 if (!Parser->SavedDiagHandler && DiagCurBuffer &&
2403 DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
2404 SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(i: DiagCurBuffer);
2405 DiagSrcMgr.PrintIncludeStack(IncludeLoc: ParentIncludeLoc, OS);
2406 }
2407
2408 // If we have not parsed a cpp hash line filename comment or the source
2409 // manager changed or buffer changed (like in a nested include) then just
2410 // print the normal diagnostic using its Filename and LineNo.
2411 if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||
2412 DiagBuf != CppHashBuf) {
2413 if (Parser->SavedDiagHandler)
2414 Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);
2415 else
2416 Diag.print(ProgName: nullptr, S&: OS);
2417 return;
2418 }
2419
2420 // Use the CppHashFilename and calculate a line number based on the
2421 // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc
2422 // for the diagnostic.
2423 const std::string &Filename = std::string(Parser->CppHashInfo.Filename);
2424
2425 int DiagLocLineNo = DiagSrcMgr.FindLineNumber(Loc: DiagLoc, BufferID: DiagBuf);
2426 int CppHashLocLineNo =
2427 Parser->SrcMgr.FindLineNumber(Loc: Parser->CppHashInfo.Loc, BufferID: CppHashBuf);
2428 int LineNo =
2429 Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);
2430
2431 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,
2432 Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
2433 Diag.getLineContents(), Diag.getRanges());
2434
2435 if (Parser->SavedDiagHandler)
2436 Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);
2437 else
2438 NewDiag.print(ProgName: nullptr, S&: OS);
2439}
2440
2441// This is similar to the IsIdentifierChar function in AsmLexer.cpp, but does
2442// not accept '.'.
2443static bool isMacroParameterChar(char C) {
2444 return isAlnum(C) || C == '_' || C == '$' || C == '@' || C == '?';
2445}
2446
2447bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
2448 ArrayRef<MCAsmMacroParameter> Parameters,
2449 ArrayRef<MCAsmMacroArgument> A,
2450 const std::vector<std::string> &Locals, SMLoc L) {
2451 unsigned NParameters = Parameters.size();
2452 if (NParameters != A.size())
2453 return Error(L, Msg: "Wrong number of arguments");
2454 StringMap<std::string> LocalSymbols;
2455 std::string Name;
2456 Name.reserve(res_arg: 6);
2457 for (StringRef Local : Locals) {
2458 raw_string_ostream LocalName(Name);
2459 LocalName << "??"
2460 << format_hex_no_prefix(N: LocalCounter++, Width: 4, /*Upper=*/true);
2461 LocalSymbols.insert(KV: {Local, Name});
2462 Name.clear();
2463 }
2464
2465 std::optional<char> CurrentQuote;
2466 while (!Body.empty()) {
2467 // Scan for the next substitution.
2468 std::size_t End = Body.size(), Pos = 0;
2469 std::size_t IdentifierPos = End;
2470 for (; Pos != End; ++Pos) {
2471 // Find the next possible macro parameter, including preceding a '&'
2472 // inside quotes.
2473 if (Body[Pos] == '&')
2474 break;
2475 if (isMacroParameterChar(C: Body[Pos])) {
2476 if (!CurrentQuote)
2477 break;
2478 if (IdentifierPos == End)
2479 IdentifierPos = Pos;
2480 } else {
2481 IdentifierPos = End;
2482 }
2483
2484 // Track quotation status
2485 if (!CurrentQuote) {
2486 if (Body[Pos] == '\'' || Body[Pos] == '"')
2487 CurrentQuote = Body[Pos];
2488 } else if (Body[Pos] == CurrentQuote) {
2489 if (Pos + 1 != End && Body[Pos + 1] == CurrentQuote) {
2490 // Escaped quote, and quotes aren't identifier chars; skip
2491 ++Pos;
2492 continue;
2493 } else {
2494 CurrentQuote.reset();
2495 }
2496 }
2497 }
2498 if (IdentifierPos != End) {
2499 // We've recognized an identifier before an apostrophe inside quotes;
2500 // check once to see if we can expand it.
2501 Pos = IdentifierPos;
2502 IdentifierPos = End;
2503 }
2504
2505 // Add the prefix.
2506 OS << Body.slice(Start: 0, End: Pos);
2507
2508 // Check if we reached the end.
2509 if (Pos == End)
2510 break;
2511
2512 unsigned I = Pos;
2513 bool InitialAmpersand = (Body[I] == '&');
2514 if (InitialAmpersand) {
2515 ++I;
2516 ++Pos;
2517 }
2518 while (I < End && isMacroParameterChar(C: Body[I]))
2519 ++I;
2520
2521 const char *Begin = Body.data() + Pos;
2522 StringRef Argument(Begin, I - Pos);
2523 const std::string ArgumentLower = Argument.lower();
2524 unsigned Index = 0;
2525
2526 for (; Index < NParameters; ++Index)
2527 if (Parameters[Index].Name.equals_insensitive(RHS: ArgumentLower))
2528 break;
2529
2530 if (Index == NParameters) {
2531 if (InitialAmpersand)
2532 OS << '&';
2533 auto it = LocalSymbols.find(Key: ArgumentLower);
2534 if (it != LocalSymbols.end())
2535 OS << it->second;
2536 else
2537 OS << Argument;
2538 Pos = I;
2539 } else {
2540 for (const AsmToken &Token : A[Index]) {
2541 // In MASM, you can write '%expr'.
2542 // The prefix '%' evaluates the expression 'expr'
2543 // and uses the result as a string (e.g. replace %(1+2) with the
2544 // string "3").
2545 // Here, we identify the integer token which is the result of the
2546 // absolute expression evaluation and replace it with its string
2547 // representation.
2548 if (Token.getString().front() == '%' && Token.is(K: AsmToken::Integer))
2549 // Emit an integer value to the buffer.
2550 OS << Token.getIntVal();
2551 else
2552 OS << Token.getString();
2553 }
2554
2555 Pos += Argument.size();
2556 if (Pos < End && Body[Pos] == '&') {
2557 ++Pos;
2558 }
2559 }
2560 // Update the scan point.
2561 Body = Body.substr(Start: Pos);
2562 }
2563
2564 return false;
2565}
2566
2567bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP,
2568 MCAsmMacroArgument &MA,
2569 AsmToken::TokenKind EndTok) {
2570 if (MP && MP->Vararg) {
2571 if (Lexer.isNot(K: EndTok)) {
2572 SmallVector<StringRef, 1> Str = parseStringRefsTo(EndTok);
2573 for (StringRef S : Str) {
2574 MA.emplace_back(args: AsmToken::String, args&: S);
2575 }
2576 }
2577 return false;
2578 }
2579
2580 SMLoc StrLoc = Lexer.getLoc(), EndLoc;
2581 if (Lexer.is(K: AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) {
2582 const char *StrChar = StrLoc.getPointer() + 1;
2583 const char *EndChar = EndLoc.getPointer() - 1;
2584 jumpToLoc(Loc: EndLoc, InBuffer: CurBuffer, EndStatementAtEOF: EndStatementAtEOFStack.back());
2585 /// Eat from '<' to '>'.
2586 Lex();
2587 MA.emplace_back(args: AsmToken::String, args: StringRef(StrChar, EndChar - StrChar));
2588 return false;
2589 }
2590
2591 unsigned ParenLevel = 0;
2592
2593 while (true) {
2594 if (Lexer.is(K: AsmToken::Eof) || Lexer.is(K: AsmToken::Equal))
2595 return TokError(Msg: "unexpected token");
2596
2597 if (ParenLevel == 0 && Lexer.is(K: AsmToken::Comma))
2598 break;
2599
2600 // handleMacroEntry relies on not advancing the lexer here
2601 // to be able to fill in the remaining default parameter values
2602 if (Lexer.is(K: EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0))
2603 break;
2604
2605 // Adjust the current parentheses level.
2606 if (Lexer.is(K: AsmToken::LParen))
2607 ++ParenLevel;
2608 else if (Lexer.is(K: AsmToken::RParen) && ParenLevel)
2609 --ParenLevel;
2610
2611 // Append the token to the current argument list.
2612 MA.push_back(x: getTok());
2613 Lex();
2614 }
2615
2616 if (ParenLevel != 0)
2617 return TokError(Msg: "unbalanced parentheses in argument");
2618
2619 if (MA.empty() && MP) {
2620 if (MP->Required) {
2621 return TokError(Msg: "missing value for required parameter '" + MP->Name +
2622 "'");
2623 } else {
2624 MA = MP->Value;
2625 }
2626 }
2627 return false;
2628}
2629
2630// Parse the macro instantiation arguments.
2631bool MasmParser::parseMacroArguments(const MCAsmMacro *M,
2632 MCAsmMacroArguments &A,
2633 AsmToken::TokenKind EndTok) {
2634 const unsigned NParameters = M ? M->Parameters.size() : 0;
2635 bool NamedParametersFound = false;
2636 SmallVector<SMLoc, 4> FALocs;
2637
2638 A.resize(new_size: NParameters);
2639 FALocs.resize(N: NParameters);
2640
2641 // Parse two kinds of macro invocations:
2642 // - macros defined without any parameters accept an arbitrary number of them
2643 // - macros defined with parameters accept at most that many of them
2644 for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;
2645 ++Parameter) {
2646 SMLoc IDLoc = Lexer.getLoc();
2647 MCAsmMacroParameter FA;
2648
2649 if (Lexer.is(K: AsmToken::Identifier) && peekTok().is(K: AsmToken::Equal)) {
2650 if (parseIdentifier(Res&: FA.Name))
2651 return Error(L: IDLoc, Msg: "invalid argument identifier for formal argument");
2652
2653 if (Lexer.isNot(K: AsmToken::Equal))
2654 return TokError(Msg: "expected '=' after formal parameter identifier");
2655
2656 Lex();
2657
2658 NamedParametersFound = true;
2659 }
2660
2661 if (NamedParametersFound && FA.Name.empty())
2662 return Error(L: IDLoc, Msg: "cannot mix positional and keyword arguments");
2663
2664 unsigned PI = Parameter;
2665 if (!FA.Name.empty()) {
2666 assert(M && "expected macro to be defined");
2667 unsigned FAI = 0;
2668 for (FAI = 0; FAI < NParameters; ++FAI)
2669 if (M->Parameters[FAI].Name == FA.Name)
2670 break;
2671
2672 if (FAI >= NParameters) {
2673 return Error(L: IDLoc, Msg: "parameter named '" + FA.Name +
2674 "' does not exist for macro '" + M->Name + "'");
2675 }
2676 PI = FAI;
2677 }
2678 const MCAsmMacroParameter *MP = nullptr;
2679 if (M && PI < NParameters)
2680 MP = &M->Parameters[PI];
2681
2682 SMLoc StrLoc = Lexer.getLoc();
2683 SMLoc EndLoc;
2684 if (Lexer.is(K: AsmToken::Percent)) {
2685 const MCExpr *AbsoluteExp;
2686 int64_t Value;
2687 /// Eat '%'.
2688 Lex();
2689 if (parseExpression(Res&: AbsoluteExp, EndLoc))
2690 return false;
2691 if (!AbsoluteExp->evaluateAsAbsolute(Res&: Value,
2692 Asm: getStreamer().getAssemblerPtr()))
2693 return Error(L: StrLoc, Msg: "expected absolute expression");
2694 const char *StrChar = StrLoc.getPointer();
2695 const char *EndChar = EndLoc.getPointer();
2696 AsmToken newToken(AsmToken::Integer,
2697 StringRef(StrChar, EndChar - StrChar), Value);
2698 FA.Value.push_back(x: newToken);
2699 } else if (parseMacroArgument(MP, MA&: FA.Value, EndTok)) {
2700 if (M)
2701 return addErrorSuffix(Suffix: " in '" + M->Name + "' macro");
2702 else
2703 return true;
2704 }
2705
2706 if (!FA.Value.empty()) {
2707 if (A.size() <= PI)
2708 A.resize(new_size: PI + 1);
2709 A[PI] = FA.Value;
2710
2711 if (FALocs.size() <= PI)
2712 FALocs.resize(N: PI + 1);
2713
2714 FALocs[PI] = Lexer.getLoc();
2715 }
2716
2717 // At the end of the statement, fill in remaining arguments that have
2718 // default values. If there aren't any, then the next argument is
2719 // required but missing
2720 if (Lexer.is(K: EndTok)) {
2721 bool Failure = false;
2722 for (unsigned FAI = 0; FAI < NParameters; ++FAI) {
2723 if (A[FAI].empty()) {
2724 if (M->Parameters[FAI].Required) {
2725 Error(L: FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),
2726 Msg: "missing value for required parameter "
2727 "'" +
2728 M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");
2729 Failure = true;
2730 }
2731
2732 if (!M->Parameters[FAI].Value.empty())
2733 A[FAI] = M->Parameters[FAI].Value;
2734 }
2735 }
2736 return Failure;
2737 }
2738
2739 if (Lexer.is(K: AsmToken::Comma))
2740 Lex();
2741 }
2742
2743 return TokError(Msg: "too many positional arguments");
2744}
2745
2746bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,
2747 AsmToken::TokenKind ArgumentEndTok) {
2748 // Arbitrarily limit macro nesting depth (default matches 'as'). We can
2749 // eliminate this, although we should protect against infinite loops.
2750 unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;
2751 if (ActiveMacros.size() == MaxNestingDepth) {
2752 std::ostringstream MaxNestingDepthError;
2753 MaxNestingDepthError << "macros cannot be nested more than "
2754 << MaxNestingDepth << " levels deep."
2755 << " Use -asm-macro-max-nesting-depth to increase "
2756 "this limit.";
2757 return TokError(Msg: MaxNestingDepthError.str());
2758 }
2759
2760 MCAsmMacroArguments A;
2761 if (parseMacroArguments(M, A, EndTok: ArgumentEndTok) || parseToken(T: ArgumentEndTok))
2762 return true;
2763
2764 // Macro instantiation is lexical, unfortunately. We construct a new buffer
2765 // to hold the macro body with substitutions.
2766 SmallString<256> Buf;
2767 StringRef Body = M->Body;
2768 raw_svector_ostream OS(Buf);
2769
2770 if (expandMacro(OS, Body, Parameters: M->Parameters, A, Locals: M->Locals, L: getTok().getLoc()))
2771 return true;
2772
2773 // We include the endm in the buffer as our cue to exit the macro
2774 // instantiation.
2775 OS << "endm\n";
2776
2777 std::unique_ptr<MemoryBuffer> Instantiation =
2778 MemoryBuffer::getMemBufferCopy(InputData: OS.str(), BufferName: "<instantiation>");
2779
2780 // Create the macro instantiation object and add to the current macro
2781 // instantiation stack.
2782 MacroInstantiation *MI = new MacroInstantiation{
2783 .InstantiationLoc: NameLoc, .ExitBuffer: CurBuffer, .ExitLoc: getTok().getLoc(), .CondStackDepth: TheCondStack.size()};
2784 ActiveMacros.push_back(x: MI);
2785
2786 ++NumOfMacroInstantiations;
2787
2788 // Jump to the macro instantiation and prime the lexer.
2789 CurBuffer = SrcMgr.AddNewSourceBuffer(F: std::move(Instantiation), IncludeLoc: SMLoc());
2790 Lexer.setBuffer(Buf: SrcMgr.getMemoryBuffer(i: CurBuffer)->getBuffer());
2791 EndStatementAtEOFStack.push_back(Val: true);
2792 Lex();
2793
2794 return false;
2795}
2796
2797void MasmParser::handleMacroExit() {
2798 // Jump to the token we should return to, and consume it.
2799 EndStatementAtEOFStack.pop_back();
2800 jumpToLoc(Loc: ActiveMacros.back()->ExitLoc, InBuffer: ActiveMacros.back()->ExitBuffer,
2801 EndStatementAtEOF: EndStatementAtEOFStack.back());
2802 Lex();
2803
2804 // Pop the instantiation entry.
2805 delete ActiveMacros.back();
2806 ActiveMacros.pop_back();
2807}
2808
2809bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) {
2810 if (!M->IsFunction)
2811 return Error(L: NameLoc, Msg: "cannot invoke macro procedure as function");
2812
2813 if (parseToken(T: AsmToken::LParen, Msg: "invoking macro function '" + M->Name +
2814 "' requires arguments in parentheses") ||
2815 handleMacroEntry(M, NameLoc, ArgumentEndTok: AsmToken::RParen))
2816 return true;
2817
2818 // Parse all statements in the macro, retrieving the exit value when it ends.
2819 std::string ExitValue;
2820 SmallVector<AsmRewrite, 4> AsmStrRewrites;
2821 while (Lexer.isNot(K: AsmToken::Eof)) {
2822 ParseStatementInfo Info(&AsmStrRewrites);
2823 bool HasError = parseStatement(Info, SI: nullptr);
2824
2825 if (!HasError && Info.ExitValue) {
2826 ExitValue = std::move(*Info.ExitValue);
2827 break;
2828 }
2829
2830 // If we have a Lexer Error we are on an Error Token. Load in Lexer Error
2831 // for printing ErrMsg via Lex() only if no (presumably better) parser error
2832 // exists.
2833 if (HasError && !hasPendingError() && Lexer.getTok().is(K: AsmToken::Error))
2834 Lex();
2835
2836 // parseStatement returned true so may need to emit an error.
2837 printPendingErrors();
2838
2839 // Skipping to the next line if needed.
2840 if (HasError && !getLexer().justConsumedEOL())
2841 eatToEndOfStatement();
2842 }
2843
2844 // Exit values may require lexing, unfortunately. We construct a new buffer to
2845 // hold the exit value.
2846 std::unique_ptr<MemoryBuffer> MacroValue =
2847 MemoryBuffer::getMemBufferCopy(InputData: ExitValue, BufferName: "<macro-value>");
2848
2849 // Jump from this location to the instantiated exit value, and prime the
2850 // lexer.
2851 CurBuffer = SrcMgr.AddNewSourceBuffer(F: std::move(MacroValue), IncludeLoc: Lexer.getLoc());
2852 Lexer.setBuffer(Buf: SrcMgr.getMemoryBuffer(i: CurBuffer)->getBuffer(), ptr: nullptr,
2853 /*EndStatementAtEOF=*/false);
2854 EndStatementAtEOFStack.push_back(Val: false);
2855 Lex();
2856
2857 return false;
2858}
2859
2860/// parseIdentifier:
2861/// ::= identifier
2862/// ::= string
2863bool MasmParser::parseIdentifier(StringRef &Res,
2864 IdentifierPositionKind Position) {
2865 // The assembler has relaxed rules for accepting identifiers, in particular we
2866 // allow things like '.globl $foo' and '.def @feat.00', which would normally
2867 // be separate tokens. At this level, we have already lexed so we cannot
2868 // (currently) handle this as a context dependent token, instead we detect
2869 // adjacent tokens and return the combined identifier.
2870 if (Lexer.is(K: AsmToken::Dollar) || Lexer.is(K: AsmToken::At)) {
2871 SMLoc PrefixLoc = getLexer().getLoc();
2872
2873 // Consume the prefix character, and check for a following identifier.
2874
2875 AsmToken nextTok = peekTok(ShouldSkipSpace: false);
2876
2877 if (nextTok.isNot(K: AsmToken::Identifier))
2878 return true;
2879
2880 // We have a '$' or '@' followed by an identifier, make sure they are adjacent.
2881 if (PrefixLoc.getPointer() + 1 != nextTok.getLoc().getPointer())
2882 return true;
2883
2884 // eat $ or @
2885 Lexer.Lex(); // Lexer's Lex guarantees consecutive token.
2886 // Construct the joined identifier and consume the token.
2887 Res =
2888 StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);
2889 Lex(); // Parser Lex to maintain invariants.
2890 return false;
2891 }
2892
2893 if (Lexer.isNot(K: AsmToken::Identifier) && Lexer.isNot(K: AsmToken::String))
2894 return true;
2895
2896 Res = getTok().getIdentifier();
2897
2898 // Consume the identifier token - but if parsing certain directives, avoid
2899 // lexical expansion of the next token.
2900 ExpandKind ExpandNextToken = ExpandMacros;
2901 if (Position == StartOfStatement &&
2902 StringSwitch<bool>(Res)
2903 .CaseLower(S: "echo", Value: true)
2904 .CasesLower(CaseStrings: {"ifdef", "ifndef", "elseifdef", "elseifndef"}, Value: true)
2905 .Default(Value: false)) {
2906 ExpandNextToken = DoNotExpandMacros;
2907 }
2908 Lex(ExpandNextToken);
2909
2910 return false;
2911}
2912
2913/// parseDirectiveEquate:
2914/// ::= name "=" expression
2915/// | name "equ" expression (not redefinable)
2916/// | name "equ" text-list
2917/// | name "textequ" text-list (redefinability unspecified)
2918bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,
2919 DirectiveKind DirKind, SMLoc NameLoc) {
2920 auto BuiltinIt = BuiltinSymbolMap.find(Key: Name.lower());
2921 if (BuiltinIt != BuiltinSymbolMap.end())
2922 return Error(L: NameLoc, Msg: "cannot redefine a built-in symbol");
2923
2924 Variable &Var = Variables[Name.lower()];
2925 if (Var.Name.empty()) {
2926 Var.Name = Name;
2927 }
2928
2929 SMLoc StartLoc = Lexer.getLoc();
2930 if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {
2931 // "equ" and "textequ" both allow text expressions.
2932 std::string Value;
2933 std::string TextItem;
2934 if (!parseTextItem(Data&: TextItem)) {
2935 Value += TextItem;
2936
2937 // Accept a text-list, not just one text-item.
2938 auto parseItem = [&]() -> bool {
2939 if (parseTextItem(Data&: TextItem))
2940 return TokError(Msg: "expected text item");
2941 Value += TextItem;
2942 return false;
2943 };
2944 if (parseOptionalToken(T: AsmToken::Comma) && parseMany(parseOne: parseItem))
2945 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
2946
2947 if (!Var.IsText || Var.TextValue != Value) {
2948 switch (Var.Redefinable) {
2949 case Variable::NOT_REDEFINABLE:
2950 return Error(L: getTok().getLoc(), Msg: "invalid variable redefinition");
2951 case Variable::WARN_ON_REDEFINITION:
2952 if (Warning(L: NameLoc, Msg: "redefining '" + Name +
2953 "', already defined on the command line")) {
2954 return true;
2955 }
2956 break;
2957 default:
2958 break;
2959 }
2960 }
2961 Var.IsText = true;
2962 Var.TextValue = Value;
2963 Var.Redefinable = Variable::REDEFINABLE;
2964
2965 return false;
2966 }
2967 }
2968 if (DirKind == DK_TEXTEQU)
2969 return TokError(Msg: "expected <text> in '" + Twine(IDVal) + "' directive");
2970
2971 // Parse as expression assignment.
2972 const MCExpr *Expr;
2973 SMLoc EndLoc;
2974 if (parseExpression(Res&: Expr, EndLoc))
2975 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
2976 StringRef ExprAsString = StringRef(
2977 StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());
2978
2979 int64_t Value;
2980 if (!Expr->evaluateAsAbsolute(Res&: Value, Asm: getStreamer().getAssemblerPtr())) {
2981 if (DirKind == DK_ASSIGN)
2982 return Error(
2983 L: StartLoc,
2984 Msg: "expected absolute expression; not all symbols have known values",
2985 Range: {StartLoc, EndLoc});
2986
2987 // Not an absolute expression; define as a text replacement.
2988 if (!Var.IsText || Var.TextValue != ExprAsString) {
2989 switch (Var.Redefinable) {
2990 case Variable::NOT_REDEFINABLE:
2991 return Error(L: getTok().getLoc(), Msg: "invalid variable redefinition");
2992 case Variable::WARN_ON_REDEFINITION:
2993 if (Warning(L: NameLoc, Msg: "redefining '" + Name +
2994 "', already defined on the command line")) {
2995 return true;
2996 }
2997 break;
2998 default:
2999 break;
3000 }
3001 }
3002
3003 Var.IsText = true;
3004 Var.TextValue = ExprAsString.str();
3005 Var.Redefinable = Variable::REDEFINABLE;
3006
3007 return false;
3008 }
3009
3010 auto *Sym = static_cast<MCSymbolCOFF *>(getContext().parseSymbol(Name: Var.Name));
3011 const MCConstantExpr *PrevValue =
3012 Sym->isVariable()
3013 ? dyn_cast_or_null<MCConstantExpr>(Val: Sym->getVariableValue())
3014 : nullptr;
3015 if (Var.IsText || !PrevValue || PrevValue->getValue() != Value) {
3016 switch (Var.Redefinable) {
3017 case Variable::NOT_REDEFINABLE:
3018 return Error(L: getTok().getLoc(), Msg: "invalid variable redefinition");
3019 case Variable::WARN_ON_REDEFINITION:
3020 if (Warning(L: NameLoc, Msg: "redefining '" + Name +
3021 "', already defined on the command line")) {
3022 return true;
3023 }
3024 break;
3025 default:
3026 break;
3027 }
3028 }
3029
3030 Var.IsText = false;
3031 Var.TextValue.clear();
3032 Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE
3033 : Variable::NOT_REDEFINABLE;
3034
3035 Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE);
3036 Sym->setVariableValue(Expr);
3037 Sym->setExternal(false);
3038
3039 return false;
3040}
3041
3042bool MasmParser::parseEscapedString(std::string &Data) {
3043 if (check(P: getTok().isNot(K: AsmToken::String), Msg: "expected string"))
3044 return true;
3045
3046 Data = "";
3047 char Quote = getTok().getString().front();
3048 StringRef Str = getTok().getStringContents();
3049 Data.reserve(res_arg: Str.size());
3050 for (size_t i = 0, e = Str.size(); i != e; ++i) {
3051 Data.push_back(c: Str[i]);
3052 if (Str[i] == Quote) {
3053 // MASM treats doubled delimiting quotes as an escaped delimiting quote.
3054 // If we're escaping the string's trailing delimiter, we're definitely
3055 // missing a quotation mark.
3056 if (i + 1 == Str.size())
3057 return Error(L: getTok().getLoc(), Msg: "missing quotation mark in string");
3058 if (Str[i + 1] == Quote)
3059 ++i;
3060 }
3061 }
3062
3063 Lex();
3064 return false;
3065}
3066
3067bool MasmParser::parseAngleBracketString(std::string &Data) {
3068 SMLoc EndLoc, StartLoc = getTok().getLoc();
3069 if (isAngleBracketString(StrLoc&: StartLoc, EndLoc)) {
3070 const char *StartChar = StartLoc.getPointer() + 1;
3071 const char *EndChar = EndLoc.getPointer() - 1;
3072 jumpToLoc(Loc: EndLoc, InBuffer: CurBuffer, EndStatementAtEOF: EndStatementAtEOFStack.back());
3073 // Eat from '<' to '>'.
3074 Lex();
3075
3076 Data = angleBracketString(BracketContents: StringRef(StartChar, EndChar - StartChar));
3077 return false;
3078 }
3079 return true;
3080}
3081
3082/// textItem ::= textLiteral | textMacroID | % constExpr
3083bool MasmParser::parseTextItem(std::string &Data) {
3084 switch (getTok().getKind()) {
3085 default:
3086 return true;
3087 case AsmToken::Percent: {
3088 int64_t Res;
3089 if (parseToken(T: AsmToken::Percent) || parseAbsoluteExpression(Res))
3090 return true;
3091 Data = std::to_string(val: Res);
3092 return false;
3093 }
3094 case AsmToken::Less:
3095 case AsmToken::LessEqual:
3096 case AsmToken::LessLess:
3097 case AsmToken::LessGreater:
3098 return parseAngleBracketString(Data);
3099 case AsmToken::Identifier: {
3100 // This must be a text macro; we need to expand it accordingly.
3101 StringRef ID;
3102 SMLoc StartLoc = getTok().getLoc();
3103 if (parseIdentifier(Res&: ID))
3104 return true;
3105 Data = ID.str();
3106
3107 bool Expanded = false;
3108 while (true) {
3109 // Try to resolve as a built-in text macro
3110 auto BuiltinIt = BuiltinSymbolMap.find(Key: ID.lower());
3111 if (BuiltinIt != BuiltinSymbolMap.end()) {
3112 std::optional<std::string> BuiltinText =
3113 evaluateBuiltinTextMacro(Symbol: BuiltinIt->getValue(), StartLoc);
3114 if (!BuiltinText) {
3115 // Not a text macro; break without substituting
3116 break;
3117 }
3118 Data = std::move(*BuiltinText);
3119 ID = StringRef(Data);
3120 Expanded = true;
3121 continue;
3122 }
3123
3124 // Try to resolve as a built-in macro function
3125 auto BuiltinFuncIt = BuiltinFunctionMap.find(Key: ID.lower());
3126 if (BuiltinFuncIt != BuiltinFunctionMap.end()) {
3127 Data.clear();
3128 if (evaluateBuiltinMacroFunction(Function: BuiltinFuncIt->getValue(), Name: ID, Res&: Data)) {
3129 return true;
3130 }
3131 ID = StringRef(Data);
3132 Expanded = true;
3133 continue;
3134 }
3135
3136 // Try to resolve as a variable text macro
3137 auto VarIt = Variables.find(Key: ID.lower());
3138 if (VarIt != Variables.end()) {
3139 const Variable &Var = VarIt->getValue();
3140 if (!Var.IsText) {
3141 // Not a text macro; break without substituting
3142 break;
3143 }
3144 Data = Var.TextValue;
3145 ID = StringRef(Data);
3146 Expanded = true;
3147 continue;
3148 }
3149
3150 break;
3151 }
3152
3153 if (!Expanded) {
3154 // Not a text macro; not usable in TextItem context. Since we haven't used
3155 // the token, put it back for better error recovery.
3156 getLexer().UnLex(Token: AsmToken(AsmToken::Identifier, ID));
3157 return true;
3158 }
3159 return false;
3160 }
3161 }
3162 llvm_unreachable("unhandled token kind");
3163}
3164
3165/// parseDirectiveAscii:
3166/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
3167bool MasmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
3168 auto parseOp = [&]() -> bool {
3169 std::string Data;
3170 if (checkForValidSection() || parseEscapedString(Data))
3171 return true;
3172 getStreamer().emitBytes(Data);
3173 if (ZeroTerminated)
3174 getStreamer().emitBytes(Data: StringRef("\0", 1));
3175 return false;
3176 };
3177
3178 if (parseMany(parseOne: parseOp))
3179 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
3180 return false;
3181}
3182
3183bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) {
3184 // Special case constant expressions to match code generator.
3185 if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value)) {
3186 assert(Size <= 8 && "Invalid size");
3187 int64_t IntValue = MCE->getValue();
3188 if (!isUIntN(N: 8 * Size, x: IntValue) && !isIntN(N: 8 * Size, x: IntValue))
3189 return Error(L: MCE->getLoc(), Msg: "out of range literal value");
3190 getStreamer().emitIntValue(Value: IntValue, Size);
3191 } else {
3192 const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Val: Value);
3193 if (MSE && MSE->getSymbol().getName() == "?") {
3194 // ? initializer; treat as 0.
3195 getStreamer().emitIntValue(Value: 0, Size);
3196 } else {
3197 getStreamer().emitValue(Value, Size, Loc: Value->getLoc());
3198 }
3199 }
3200 return false;
3201}
3202
3203bool MasmParser::parseScalarInitializer(unsigned Size,
3204 SmallVectorImpl<const MCExpr *> &Values,
3205 unsigned StringPadLength) {
3206 if (Size == 1 && getTok().is(K: AsmToken::String)) {
3207 std::string Value;
3208 if (parseEscapedString(Data&: Value))
3209 return true;
3210 // Treat each character as an initializer.
3211 for (const unsigned char CharVal : Value)
3212 Values.push_back(Elt: MCConstantExpr::create(Value: CharVal, Ctx&: getContext()));
3213
3214 // Pad the string with spaces to the specified length.
3215 for (size_t i = Value.size(); i < StringPadLength; ++i)
3216 Values.push_back(Elt: MCConstantExpr::create(Value: ' ', Ctx&: getContext()));
3217 } else {
3218 const MCExpr *Value;
3219 if (parseExpression(Res&: Value))
3220 return true;
3221 if (getTok().is(K: AsmToken::Identifier) &&
3222 getTok().getString().equals_insensitive(RHS: "dup")) {
3223 Lex(); // Eat 'dup'.
3224 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value);
3225 if (!MCE)
3226 return Error(L: Value->getLoc(),
3227 Msg: "cannot repeat value a non-constant number of times");
3228 const int64_t Repetitions = MCE->getValue();
3229 if (Repetitions < 0)
3230 return Error(L: Value->getLoc(),
3231 Msg: "cannot repeat value a negative number of times");
3232
3233 SmallVector<const MCExpr *, 1> DuplicatedValues;
3234 if (parseToken(T: AsmToken::LParen,
3235 Msg: "parentheses required for 'dup' contents") ||
3236 parseScalarInstList(Size, Values&: DuplicatedValues) || parseRParen())
3237 return true;
3238
3239 for (int i = 0; i < Repetitions; ++i)
3240 Values.append(in_start: DuplicatedValues.begin(), in_end: DuplicatedValues.end());
3241 } else {
3242 Values.push_back(Elt: Value);
3243 }
3244 }
3245 return false;
3246}
3247
3248bool MasmParser::parseScalarInstList(unsigned Size,
3249 SmallVectorImpl<const MCExpr *> &Values,
3250 const AsmToken::TokenKind EndToken) {
3251 while (getTok().isNot(K: EndToken) &&
3252 (EndToken != AsmToken::Greater ||
3253 getTok().isNot(K: AsmToken::GreaterGreater))) {
3254 parseScalarInitializer(Size, Values);
3255
3256 // If we see a comma, continue, and allow line continuation.
3257 if (!parseOptionalToken(T: AsmToken::Comma))
3258 break;
3259 parseOptionalToken(T: AsmToken::EndOfStatement);
3260 }
3261 return false;
3262}
3263
3264bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) {
3265 SmallVector<const MCExpr *, 1> Values;
3266 if (checkForValidSection() || parseScalarInstList(Size, Values))
3267 return true;
3268
3269 for (const auto *Value : Values) {
3270 emitIntValue(Value, Size);
3271 }
3272 if (Count)
3273 *Count = Values.size();
3274 return false;
3275}
3276
3277// Add a field to the current structure.
3278bool MasmParser::addIntegralField(StringRef Name, unsigned Size) {
3279 StructInfo &Struct = StructInProgress.back();
3280 FieldInfo &Field = Struct.addField(FieldName: Name, FT: FT_INTEGRAL, FieldAlignmentSize: Size);
3281 IntFieldInfo &IntInfo = Field.Contents.IntInfo;
3282
3283 Field.Type = Size;
3284
3285 if (parseScalarInstList(Size, Values&: IntInfo.Values))
3286 return true;
3287
3288 Field.SizeOf = Field.Type * IntInfo.Values.size();
3289 Field.LengthOf = IntInfo.Values.size();
3290 const unsigned FieldEnd = Field.Offset + Field.SizeOf;
3291 if (!Struct.IsUnion) {
3292 Struct.NextOffset = FieldEnd;
3293 }
3294 Struct.Size = std::max(a: Struct.Size, b: FieldEnd);
3295 return false;
3296}
3297
3298/// parseDirectiveValue
3299/// ::= (byte | word | ... ) [ expression (, expression)* ]
3300bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {
3301 if (StructInProgress.empty()) {
3302 // Initialize data value.
3303 if (emitIntegralValues(Size))
3304 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
3305 } else if (addIntegralField(Name: "", Size)) {
3306 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
3307 }
3308
3309 return false;
3310}
3311
3312/// parseDirectiveNamedValue
3313/// ::= name (byte | word | ... ) [ expression (, expression)* ]
3314bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size,
3315 StringRef Name, SMLoc NameLoc) {
3316 if (StructInProgress.empty()) {
3317 // Initialize named data value.
3318 MCSymbol *Sym = getContext().parseSymbol(Name);
3319 getStreamer().emitLabel(Symbol: Sym);
3320 unsigned Count;
3321 if (emitIntegralValues(Size, Count: &Count))
3322 return addErrorSuffix(Suffix: " in '" + Twine(TypeName) + "' directive");
3323
3324 AsmTypeInfo Type;
3325 Type.Name = TypeName;
3326 Type.Size = Size * Count;
3327 Type.ElementSize = Size;
3328 Type.Length = Count;
3329 KnownType[Name.lower()] = Type;
3330 } else if (addIntegralField(Name, Size)) {
3331 return addErrorSuffix(Suffix: " in '" + Twine(TypeName) + "' directive");
3332 }
3333
3334 return false;
3335}
3336
3337bool MasmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {
3338 // We don't truly support arithmetic on floating point expressions, so we
3339 // have to manually parse unary prefixes.
3340 bool IsNeg = false;
3341 SMLoc SignLoc;
3342 if (getLexer().is(K: AsmToken::Minus)) {
3343 SignLoc = getLexer().getLoc();
3344 Lexer.Lex();
3345 IsNeg = true;
3346 } else if (getLexer().is(K: AsmToken::Plus)) {
3347 SignLoc = getLexer().getLoc();
3348 Lexer.Lex();
3349 }
3350
3351 if (Lexer.is(K: AsmToken::Error))
3352 return TokError(Msg: Lexer.getErr());
3353 if (Lexer.isNot(K: AsmToken::Integer) && Lexer.isNot(K: AsmToken::Real) &&
3354 Lexer.isNot(K: AsmToken::Identifier))
3355 return TokError(Msg: "unexpected token in directive");
3356
3357 // Convert to an APFloat.
3358 APFloat Value(Semantics);
3359 StringRef IDVal = getTok().getString();
3360 if (getLexer().is(K: AsmToken::Identifier)) {
3361 if (IDVal.equals_insensitive(RHS: "infinity") || IDVal.equals_insensitive(RHS: "inf"))
3362 Value = APFloat::getInf(Sem: Semantics);
3363 else if (IDVal.equals_insensitive(RHS: "nan"))
3364 Value = APFloat::getNaN(Sem: Semantics, Negative: false, payload: ~0);
3365 else if (IDVal.equals_insensitive(RHS: "?"))
3366 Value = APFloat::getZero(Sem: Semantics);
3367 else
3368 return TokError(Msg: "invalid floating point literal");
3369 } else if (IDVal.consume_back(Suffix: "r") || IDVal.consume_back(Suffix: "R")) {
3370 // MASM hexadecimal floating-point literal; no APFloat conversion needed.
3371 // To match ML64.exe, ignore the initial sign.
3372 unsigned SizeInBits = Value.getSizeInBits(Sem: Semantics);
3373 if (SizeInBits != (IDVal.size() << 2))
3374 return TokError(Msg: "invalid floating point literal");
3375
3376 // Consume the numeric token.
3377 Lex();
3378
3379 Res = APInt(SizeInBits, IDVal, 16);
3380 if (SignLoc.isValid())
3381 return Warning(L: SignLoc, Msg: "MASM-style hex floats ignore explicit sign");
3382 return false;
3383 } else if (errorToBool(
3384 Err: Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven)
3385 .takeError())) {
3386 return TokError(Msg: "invalid floating point literal");
3387 }
3388 if (IsNeg)
3389 Value.changeSign();
3390
3391 // Consume the numeric token.
3392 Lex();
3393
3394 Res = Value.bitcastToAPInt();
3395
3396 return false;
3397}
3398
3399bool MasmParser::parseRealInstList(const fltSemantics &Semantics,
3400 SmallVectorImpl<APInt> &ValuesAsInt,
3401 const AsmToken::TokenKind EndToken) {
3402 while (getTok().isNot(K: EndToken) ||
3403 (EndToken == AsmToken::Greater &&
3404 getTok().isNot(K: AsmToken::GreaterGreater))) {
3405 const AsmToken NextTok = peekTok();
3406 if (NextTok.is(K: AsmToken::Identifier) &&
3407 NextTok.getString().equals_insensitive(RHS: "dup")) {
3408 const MCExpr *Value;
3409 if (parseExpression(Res&: Value) || parseToken(T: AsmToken::Identifier))
3410 return true;
3411 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value);
3412 if (!MCE)
3413 return Error(L: Value->getLoc(),
3414 Msg: "cannot repeat value a non-constant number of times");
3415 const int64_t Repetitions = MCE->getValue();
3416 if (Repetitions < 0)
3417 return Error(L: Value->getLoc(),
3418 Msg: "cannot repeat value a negative number of times");
3419
3420 SmallVector<APInt, 1> DuplicatedValues;
3421 if (parseToken(T: AsmToken::LParen,
3422 Msg: "parentheses required for 'dup' contents") ||
3423 parseRealInstList(Semantics, ValuesAsInt&: DuplicatedValues) || parseRParen())
3424 return true;
3425
3426 for (int i = 0; i < Repetitions; ++i)
3427 ValuesAsInt.append(in_start: DuplicatedValues.begin(), in_end: DuplicatedValues.end());
3428 } else {
3429 APInt AsInt;
3430 if (parseRealValue(Semantics, Res&: AsInt))
3431 return true;
3432 ValuesAsInt.push_back(Elt: AsInt);
3433 }
3434
3435 // Continue if we see a comma. (Also, allow line continuation.)
3436 if (!parseOptionalToken(T: AsmToken::Comma))
3437 break;
3438 parseOptionalToken(T: AsmToken::EndOfStatement);
3439 }
3440
3441 return false;
3442}
3443
3444// Initialize real data values.
3445bool MasmParser::emitRealValues(const fltSemantics &Semantics,
3446 unsigned *Count) {
3447 if (checkForValidSection())
3448 return true;
3449
3450 SmallVector<APInt, 1> ValuesAsInt;
3451 if (parseRealInstList(Semantics, ValuesAsInt))
3452 return true;
3453
3454 for (const APInt &AsInt : ValuesAsInt) {
3455 getStreamer().emitIntValue(Value: AsInt);
3456 }
3457 if (Count)
3458 *Count = ValuesAsInt.size();
3459 return false;
3460}
3461
3462// Add a real field to the current struct.
3463bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics,
3464 size_t Size) {
3465 StructInfo &Struct = StructInProgress.back();
3466 FieldInfo &Field = Struct.addField(FieldName: Name, FT: FT_REAL, FieldAlignmentSize: Size);
3467 RealFieldInfo &RealInfo = Field.Contents.RealInfo;
3468
3469 Field.SizeOf = 0;
3470
3471 if (parseRealInstList(Semantics, ValuesAsInt&: RealInfo.AsIntValues))
3472 return true;
3473
3474 Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8;
3475 Field.LengthOf = RealInfo.AsIntValues.size();
3476 Field.SizeOf = Field.Type * Field.LengthOf;
3477
3478 const unsigned FieldEnd = Field.Offset + Field.SizeOf;
3479 if (!Struct.IsUnion) {
3480 Struct.NextOffset = FieldEnd;
3481 }
3482 Struct.Size = std::max(a: Struct.Size, b: FieldEnd);
3483 return false;
3484}
3485
3486/// parseDirectiveRealValue
3487/// ::= (real4 | real8 | real10) [ expression (, expression)* ]
3488bool MasmParser::parseDirectiveRealValue(StringRef IDVal,
3489 const fltSemantics &Semantics,
3490 size_t Size) {
3491 if (StructInProgress.empty()) {
3492 // Initialize data value.
3493 if (emitRealValues(Semantics))
3494 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
3495 } else if (addRealField(Name: "", Semantics, Size)) {
3496 return addErrorSuffix(Suffix: " in '" + Twine(IDVal) + "' directive");
3497 }
3498 return false;
3499}
3500
3501/// parseDirectiveNamedRealValue
3502/// ::= name (real4 | real8 | real10) [ expression (, expression)* ]
3503bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName,
3504 const fltSemantics &Semantics,
3505 unsigned Size, StringRef Name,
3506 SMLoc NameLoc) {
3507 if (StructInProgress.empty()) {
3508 // Initialize named data value.
3509 MCSymbol *Sym = getContext().parseSymbol(Name);
3510 getStreamer().emitLabel(Symbol: Sym);
3511 unsigned Count;
3512 if (emitRealValues(Semantics, Count: &Count))
3513 return addErrorSuffix(Suffix: " in '" + TypeName + "' directive");
3514
3515 AsmTypeInfo Type;
3516 Type.Name = TypeName;
3517 Type.Size = Size * Count;
3518 Type.ElementSize = Size;
3519 Type.Length = Count;
3520 KnownType[Name.lower()] = Type;
3521 } else if (addRealField(Name, Semantics, Size)) {
3522 return addErrorSuffix(Suffix: " in '" + TypeName + "' directive");
3523 }
3524 return false;
3525}
3526
3527bool MasmParser::parseOptionalAngleBracketOpen() {
3528 const AsmToken Tok = getTok();
3529 if (parseOptionalToken(T: AsmToken::LessLess)) {
3530 AngleBracketDepth++;
3531 Lexer.UnLex(Token: AsmToken(AsmToken::Less, Tok.getString().substr(Start: 1)));
3532 return true;
3533 } else if (parseOptionalToken(T: AsmToken::LessGreater)) {
3534 AngleBracketDepth++;
3535 Lexer.UnLex(Token: AsmToken(AsmToken::Greater, Tok.getString().substr(Start: 1)));
3536 return true;
3537 } else if (parseOptionalToken(T: AsmToken::Less)) {
3538 AngleBracketDepth++;
3539 return true;
3540 }
3541
3542 return false;
3543}
3544
3545bool MasmParser::parseAngleBracketClose(const Twine &Msg) {
3546 const AsmToken Tok = getTok();
3547 if (parseOptionalToken(T: AsmToken::GreaterGreater)) {
3548 Lexer.UnLex(Token: AsmToken(AsmToken::Greater, Tok.getString().substr(Start: 1)));
3549 } else if (parseToken(T: AsmToken::Greater, Msg)) {
3550 return true;
3551 }
3552 AngleBracketDepth--;
3553 return false;
3554}
3555
3556bool MasmParser::parseFieldInitializer(const FieldInfo &Field,
3557 const IntFieldInfo &Contents,
3558 FieldInitializer &Initializer) {
3559 SMLoc Loc = getTok().getLoc();
3560
3561 SmallVector<const MCExpr *, 1> Values;
3562 if (parseOptionalToken(T: AsmToken::LCurly)) {
3563 if (Field.LengthOf == 1 && Field.Type > 1)
3564 return Error(L: Loc, Msg: "Cannot initialize scalar field with array value");
3565 if (parseScalarInstList(Size: Field.Type, Values, EndToken: AsmToken::RCurly) ||
3566 parseToken(T: AsmToken::RCurly))
3567 return true;
3568 } else if (parseOptionalAngleBracketOpen()) {
3569 if (Field.LengthOf == 1 && Field.Type > 1)
3570 return Error(L: Loc, Msg: "Cannot initialize scalar field with array value");
3571 if (parseScalarInstList(Size: Field.Type, Values, EndToken: AsmToken::Greater) ||
3572 parseAngleBracketClose())
3573 return true;
3574 } else if (Field.LengthOf > 1 && Field.Type > 1) {
3575 return Error(L: Loc, Msg: "Cannot initialize array field with scalar value");
3576 } else if (parseScalarInitializer(Size: Field.Type, Values,
3577 /*StringPadLength=*/Field.LengthOf)) {
3578 return true;
3579 }
3580
3581 if (Values.size() > Field.LengthOf) {
3582 return Error(L: Loc, Msg: "Initializer too long for field; expected at most " +
3583 std::to_string(val: Field.LengthOf) + " elements, got " +
3584 std::to_string(val: Values.size()));
3585 }
3586 // Default-initialize all remaining values.
3587 Values.append(in_start: Contents.Values.begin() + Values.size(), in_end: Contents.Values.end());
3588
3589 Initializer = FieldInitializer(std::move(Values));
3590 return false;
3591}
3592
3593bool MasmParser::parseFieldInitializer(const FieldInfo &Field,
3594 const RealFieldInfo &Contents,
3595 FieldInitializer &Initializer) {
3596 const fltSemantics *Semantics;
3597 switch (Field.Type) {
3598 case 4:
3599 Semantics = &APFloat::IEEEsingle();
3600 break;
3601 case 8:
3602 Semantics = &APFloat::IEEEdouble();
3603 break;
3604 case 10:
3605 Semantics = &APFloat::x87DoubleExtended();
3606 break;
3607 default:
3608 llvm_unreachable("unknown real field type");
3609 }
3610
3611 SMLoc Loc = getTok().getLoc();
3612
3613 SmallVector<APInt, 1> AsIntValues;
3614 if (parseOptionalToken(T: AsmToken::LCurly)) {
3615 if (Field.LengthOf == 1)
3616 return Error(L: Loc, Msg: "Cannot initialize scalar field with array value");
3617 if (parseRealInstList(Semantics: *Semantics, ValuesAsInt&: AsIntValues, EndToken: AsmToken::RCurly) ||
3618 parseToken(T: AsmToken::RCurly))
3619 return true;
3620 } else if (parseOptionalAngleBracketOpen()) {
3621 if (Field.LengthOf == 1)
3622 return Error(L: Loc, Msg: "Cannot initialize scalar field with array value");
3623 if (parseRealInstList(Semantics: *Semantics, ValuesAsInt&: AsIntValues, EndToken: AsmToken::Greater) ||
3624 parseAngleBracketClose())
3625 return true;
3626 } else if (Field.LengthOf > 1) {
3627 return Error(L: Loc, Msg: "Cannot initialize array field with scalar value");
3628 } else {
3629 AsIntValues.emplace_back();
3630 if (parseRealValue(Semantics: *Semantics, Res&: AsIntValues.back()))
3631 return true;
3632 }
3633
3634 if (AsIntValues.size() > Field.LengthOf) {
3635 return Error(L: Loc, Msg: "Initializer too long for field; expected at most " +
3636 std::to_string(val: Field.LengthOf) + " elements, got " +
3637 std::to_string(val: AsIntValues.size()));
3638 }
3639 // Default-initialize all remaining values.
3640 AsIntValues.append(in_start: Contents.AsIntValues.begin() + AsIntValues.size(),
3641 in_end: Contents.AsIntValues.end());
3642
3643 Initializer = FieldInitializer(std::move(AsIntValues));
3644 return false;
3645}
3646
3647bool MasmParser::parseFieldInitializer(const FieldInfo &Field,
3648 const StructFieldInfo &Contents,
3649 FieldInitializer &Initializer) {
3650 SMLoc Loc = getTok().getLoc();
3651
3652 std::vector<StructInitializer> Initializers;
3653 if (Field.LengthOf > 1) {
3654 if (parseOptionalToken(T: AsmToken::LCurly)) {
3655 if (parseStructInstList(Structure: Contents.Structure, Initializers,
3656 EndToken: AsmToken::RCurly) ||
3657 parseToken(T: AsmToken::RCurly))
3658 return true;
3659 } else if (parseOptionalAngleBracketOpen()) {
3660 if (parseStructInstList(Structure: Contents.Structure, Initializers,
3661 EndToken: AsmToken::Greater) ||
3662 parseAngleBracketClose())
3663 return true;
3664 } else {
3665 return Error(L: Loc, Msg: "Cannot initialize array field with scalar value");
3666 }
3667 } else {
3668 Initializers.emplace_back();
3669 if (parseStructInitializer(Structure: Contents.Structure, Initializer&: Initializers.back()))
3670 return true;
3671 }
3672
3673 if (Initializers.size() > Field.LengthOf) {
3674 return Error(L: Loc, Msg: "Initializer too long for field; expected at most " +
3675 std::to_string(val: Field.LengthOf) + " elements, got " +
3676 std::to_string(val: Initializers.size()));
3677 }
3678 // Default-initialize all remaining values.
3679 llvm::append_range(C&: Initializers, R: llvm::drop_begin(RangeOrContainer: Contents.Initializers,
3680 N: Initializers.size()));
3681
3682 Initializer = FieldInitializer(std::move(Initializers), Contents.Structure);
3683 return false;
3684}
3685
3686bool MasmParser::parseFieldInitializer(const FieldInfo &Field,
3687 FieldInitializer &Initializer) {
3688 switch (Field.Contents.FT) {
3689 case FT_INTEGRAL:
3690 return parseFieldInitializer(Field, Contents: Field.Contents.IntInfo, Initializer);
3691 case FT_REAL:
3692 return parseFieldInitializer(Field, Contents: Field.Contents.RealInfo, Initializer);
3693 case FT_STRUCT:
3694 return parseFieldInitializer(Field, Contents: Field.Contents.StructInfo, Initializer);
3695 }
3696 llvm_unreachable("Unhandled FieldType enum");
3697}
3698
3699bool MasmParser::parseStructInitializer(const StructInfo &Structure,
3700 StructInitializer &Initializer) {
3701 const AsmToken FirstToken = getTok();
3702
3703 std::optional<AsmToken::TokenKind> EndToken;
3704 if (parseOptionalToken(T: AsmToken::LCurly)) {
3705 EndToken = AsmToken::RCurly;
3706 } else if (parseOptionalAngleBracketOpen()) {
3707 EndToken = AsmToken::Greater;
3708 AngleBracketDepth++;
3709 } else if (FirstToken.is(K: AsmToken::Identifier) &&
3710 FirstToken.getString() == "?") {
3711 // ? initializer; leave EndToken uninitialized to treat as empty.
3712 if (parseToken(T: AsmToken::Identifier))
3713 return true;
3714 } else {
3715 return Error(L: FirstToken.getLoc(), Msg: "Expected struct initializer");
3716 }
3717
3718 auto &FieldInitializers = Initializer.FieldInitializers;
3719 size_t FieldIndex = 0;
3720 if (EndToken) {
3721 // Initialize all fields with given initializers.
3722 while (getTok().isNot(K: *EndToken) && FieldIndex < Structure.Fields.size()) {
3723 const FieldInfo &Field = Structure.Fields[FieldIndex++];
3724 if (parseOptionalToken(T: AsmToken::Comma)) {
3725 // Empty initializer; use the default and continue. (Also, allow line
3726 // continuation.)
3727 FieldInitializers.push_back(x: Field.Contents);
3728 parseOptionalToken(T: AsmToken::EndOfStatement);
3729 continue;
3730 }
3731 FieldInitializers.emplace_back(args: Field.Contents.FT);
3732 if (parseFieldInitializer(Field, Initializer&: FieldInitializers.back()))
3733 return true;
3734
3735 // Continue if we see a comma. (Also, allow line continuation.)
3736 SMLoc CommaLoc = getTok().getLoc();
3737 if (!parseOptionalToken(T: AsmToken::Comma))
3738 break;
3739 if (FieldIndex == Structure.Fields.size())
3740 return Error(L: CommaLoc, Msg: "'" + Structure.Name +
3741 "' initializer initializes too many fields");
3742 parseOptionalToken(T: AsmToken::EndOfStatement);
3743 }
3744 }
3745 // Default-initialize all remaining fields.
3746 for (const FieldInfo &Field : llvm::drop_begin(RangeOrContainer: Structure.Fields, N: FieldIndex))
3747 FieldInitializers.push_back(x: Field.Contents);
3748
3749 if (EndToken) {
3750 if (*EndToken == AsmToken::Greater)
3751 return parseAngleBracketClose();
3752
3753 return parseToken(T: *EndToken);
3754 }
3755
3756 return false;
3757}
3758
3759bool MasmParser::parseStructInstList(
3760 const StructInfo &Structure, std::vector<StructInitializer> &Initializers,
3761 const AsmToken::TokenKind EndToken) {
3762 while (getTok().isNot(K: EndToken) ||
3763 (EndToken == AsmToken::Greater &&
3764 getTok().isNot(K: AsmToken::GreaterGreater))) {
3765 const AsmToken NextTok = peekTok();
3766 if (NextTok.is(K: AsmToken::Identifier) &&
3767 NextTok.getString().equals_insensitive(RHS: "dup")) {
3768 const MCExpr *Value;
3769 if (parseExpression(Res&: Value) || parseToken(T: AsmToken::Identifier))
3770 return true;
3771 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value);
3772 if (!MCE)
3773 return Error(L: Value->getLoc(),
3774 Msg: "cannot repeat value a non-constant number of times");
3775 const int64_t Repetitions = MCE->getValue();
3776 if (Repetitions < 0)
3777 return Error(L: Value->getLoc(),
3778 Msg: "cannot repeat value a negative number of times");
3779
3780 std::vector<StructInitializer> DuplicatedValues;
3781 if (parseToken(T: AsmToken::LParen,
3782 Msg: "parentheses required for 'dup' contents") ||
3783 parseStructInstList(Structure, Initializers&: DuplicatedValues) || parseRParen())
3784 return true;
3785
3786 for (int i = 0; i < Repetitions; ++i)
3787 llvm::append_range(C&: Initializers, R&: DuplicatedValues);
3788 } else {
3789 Initializers.emplace_back();
3790 if (parseStructInitializer(Structure, Initializer&: Initializers.back()))
3791 return true;
3792 }
3793
3794 // Continue if we see a comma. (Also, allow line continuation.)
3795 if (!parseOptionalToken(T: AsmToken::Comma))
3796 break;
3797 parseOptionalToken(T: AsmToken::EndOfStatement);
3798 }
3799
3800 return false;
3801}
3802
3803bool MasmParser::emitFieldValue(const FieldInfo &Field,
3804 const IntFieldInfo &Contents) {
3805 // Default-initialize all values.
3806 for (const MCExpr *Value : Contents.Values) {
3807 if (emitIntValue(Value, Size: Field.Type))
3808 return true;
3809 }
3810 return false;
3811}
3812
3813bool MasmParser::emitFieldValue(const FieldInfo &Field,
3814 const RealFieldInfo &Contents) {
3815 for (const APInt &AsInt : Contents.AsIntValues) {
3816 getStreamer().emitIntValue(Value: AsInt.getLimitedValue(),
3817 Size: AsInt.getBitWidth() / 8);
3818 }
3819 return false;
3820}
3821
3822bool MasmParser::emitFieldValue(const FieldInfo &Field,
3823 const StructFieldInfo &Contents) {
3824 for (const auto &Initializer : Contents.Initializers) {
3825 size_t Index = 0, Offset = 0;
3826 for (const auto &SubField : Contents.Structure.Fields) {
3827 getStreamer().emitZeros(NumBytes: SubField.Offset - Offset);
3828 Offset = SubField.Offset + SubField.SizeOf;
3829 emitFieldInitializer(Field: SubField, Initializer: Initializer.FieldInitializers[Index++]);
3830 }
3831 }
3832 return false;
3833}
3834
3835bool MasmParser::emitFieldValue(const FieldInfo &Field) {
3836 switch (Field.Contents.FT) {
3837 case FT_INTEGRAL:
3838 return emitFieldValue(Field, Contents: Field.Contents.IntInfo);
3839 case FT_REAL:
3840 return emitFieldValue(Field, Contents: Field.Contents.RealInfo);
3841 case FT_STRUCT:
3842 return emitFieldValue(Field, Contents: Field.Contents.StructInfo);
3843 }
3844 llvm_unreachable("Unhandled FieldType enum");
3845}
3846
3847bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
3848 const IntFieldInfo &Contents,
3849 const IntFieldInfo &Initializer) {
3850 for (const auto &Value : Initializer.Values) {
3851 if (emitIntValue(Value, Size: Field.Type))
3852 return true;
3853 }
3854 // Default-initialize all remaining values.
3855 for (const auto &Value :
3856 llvm::drop_begin(RangeOrContainer: Contents.Values, N: Initializer.Values.size())) {
3857 if (emitIntValue(Value, Size: Field.Type))
3858 return true;
3859 }
3860 return false;
3861}
3862
3863bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
3864 const RealFieldInfo &Contents,
3865 const RealFieldInfo &Initializer) {
3866 for (const auto &AsInt : Initializer.AsIntValues) {
3867 getStreamer().emitIntValue(Value: AsInt.getLimitedValue(),
3868 Size: AsInt.getBitWidth() / 8);
3869 }
3870 // Default-initialize all remaining values.
3871 for (const auto &AsInt :
3872 llvm::drop_begin(RangeOrContainer: Contents.AsIntValues, N: Initializer.AsIntValues.size())) {
3873 getStreamer().emitIntValue(Value: AsInt.getLimitedValue(),
3874 Size: AsInt.getBitWidth() / 8);
3875 }
3876 return false;
3877}
3878
3879bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
3880 const StructFieldInfo &Contents,
3881 const StructFieldInfo &Initializer) {
3882 for (const auto &Init : Initializer.Initializers) {
3883 if (emitStructInitializer(Structure: Contents.Structure, Initializer: Init))
3884 return true;
3885 }
3886 // Default-initialize all remaining values.
3887 for (const auto &Init : llvm::drop_begin(RangeOrContainer: Contents.Initializers,
3888 N: Initializer.Initializers.size())) {
3889 if (emitStructInitializer(Structure: Contents.Structure, Initializer: Init))
3890 return true;
3891 }
3892 return false;
3893}
3894
3895bool MasmParser::emitFieldInitializer(const FieldInfo &Field,
3896 const FieldInitializer &Initializer) {
3897 switch (Field.Contents.FT) {
3898 case FT_INTEGRAL:
3899 return emitFieldInitializer(Field, Contents: Field.Contents.IntInfo,
3900 Initializer: Initializer.IntInfo);
3901 case FT_REAL:
3902 return emitFieldInitializer(Field, Contents: Field.Contents.RealInfo,
3903 Initializer: Initializer.RealInfo);
3904 case FT_STRUCT:
3905 return emitFieldInitializer(Field, Contents: Field.Contents.StructInfo,
3906 Initializer: Initializer.StructInfo);
3907 }
3908 llvm_unreachable("Unhandled FieldType enum");
3909}
3910
3911bool MasmParser::emitStructInitializer(const StructInfo &Structure,
3912 const StructInitializer &Initializer) {
3913 if (!Structure.Initializable)
3914 return Error(L: getLexer().getLoc(),
3915 Msg: "cannot initialize a value of type '" + Structure.Name +
3916 "'; 'org' was used in the type's declaration");
3917 size_t Index = 0, Offset = 0;
3918 for (const auto &Init : Initializer.FieldInitializers) {
3919 const auto &Field = Structure.Fields[Index++];
3920 getStreamer().emitZeros(NumBytes: Field.Offset - Offset);
3921 Offset = Field.Offset + Field.SizeOf;
3922 if (emitFieldInitializer(Field, Initializer: Init))
3923 return true;
3924 }
3925 // Default-initialize all remaining fields.
3926 for (const auto &Field : llvm::drop_begin(
3927 RangeOrContainer: Structure.Fields, N: Initializer.FieldInitializers.size())) {
3928 getStreamer().emitZeros(NumBytes: Field.Offset - Offset);
3929 Offset = Field.Offset + Field.SizeOf;
3930 if (emitFieldValue(Field))
3931 return true;
3932 }
3933 // Add final padding.
3934 if (Offset != Structure.Size)
3935 getStreamer().emitZeros(NumBytes: Structure.Size - Offset);
3936 return false;
3937}
3938
3939// Set data values from initializers.
3940bool MasmParser::emitStructValues(const StructInfo &Structure,
3941 unsigned *Count) {
3942 std::vector<StructInitializer> Initializers;
3943 if (parseStructInstList(Structure, Initializers))
3944 return true;
3945
3946 for (const auto &Initializer : Initializers) {
3947 if (emitStructInitializer(Structure, Initializer))
3948 return true;
3949 }
3950
3951 if (Count)
3952 *Count = Initializers.size();
3953 return false;
3954}
3955
3956// Declare a field in the current struct.
3957bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) {
3958 StructInfo &OwningStruct = StructInProgress.back();
3959 FieldInfo &Field =
3960 OwningStruct.addField(FieldName: Name, FT: FT_STRUCT, FieldAlignmentSize: Structure.AlignmentSize);
3961 StructFieldInfo &StructInfo = Field.Contents.StructInfo;
3962
3963 StructInfo.Structure = Structure;
3964 Field.Type = Structure.Size;
3965
3966 if (parseStructInstList(Structure, Initializers&: StructInfo.Initializers))
3967 return true;
3968
3969 Field.LengthOf = StructInfo.Initializers.size();
3970 Field.SizeOf = Field.Type * Field.LengthOf;
3971
3972 const unsigned FieldEnd = Field.Offset + Field.SizeOf;
3973 if (!OwningStruct.IsUnion) {
3974 OwningStruct.NextOffset = FieldEnd;
3975 }
3976 OwningStruct.Size = std::max(a: OwningStruct.Size, b: FieldEnd);
3977
3978 return false;
3979}
3980
3981/// parseDirectiveStructValue
3982/// ::= struct-id (<struct-initializer> | {struct-initializer})
3983/// [, (<struct-initializer> | {struct-initializer})]*
3984bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure,
3985 StringRef Directive, SMLoc DirLoc) {
3986 if (StructInProgress.empty()) {
3987 if (emitStructValues(Structure))
3988 return true;
3989 } else if (addStructField(Name: "", Structure)) {
3990 return addErrorSuffix(Suffix: " in '" + Twine(Directive) + "' directive");
3991 }
3992
3993 return false;
3994}
3995
3996/// parseDirectiveNamedValue
3997/// ::= name (byte | word | ... ) [ expression (, expression)* ]
3998bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure,
3999 StringRef Directive,
4000 SMLoc DirLoc, StringRef Name) {
4001 if (StructInProgress.empty()) {
4002 // Initialize named data value.
4003 MCSymbol *Sym = getContext().parseSymbol(Name);
4004 getStreamer().emitLabel(Symbol: Sym);
4005 unsigned Count;
4006 if (emitStructValues(Structure, Count: &Count))
4007 return true;
4008 AsmTypeInfo Type;
4009 Type.Name = Structure.Name;
4010 Type.Size = Structure.Size * Count;
4011 Type.ElementSize = Structure.Size;
4012 Type.Length = Count;
4013 KnownType[Name.lower()] = Type;
4014 } else if (addStructField(Name, Structure)) {
4015 return addErrorSuffix(Suffix: " in '" + Twine(Directive) + "' directive");
4016 }
4017
4018 return false;
4019}
4020
4021/// parseDirectiveStruct
4022/// ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE]
4023/// (dataDir | generalDir | offsetDir | nestedStruct)+
4024/// <name> ENDS
4025////// dataDir = data declaration
4026////// offsetDir = EVEN, ORG, ALIGN
4027bool MasmParser::parseDirectiveStruct(StringRef Directive,
4028 DirectiveKind DirKind, StringRef Name,
4029 SMLoc NameLoc) {
4030 // We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS
4031 // anyway, so all field accesses must be qualified.
4032 AsmToken NextTok = getTok();
4033 int64_t AlignmentValue = 1;
4034 if (NextTok.isNot(K: AsmToken::Comma) &&
4035 NextTok.isNot(K: AsmToken::EndOfStatement) &&
4036 parseAbsoluteExpression(Res&: AlignmentValue)) {
4037 return addErrorSuffix(Suffix: " in alignment value for '" + Twine(Directive) +
4038 "' directive");
4039 }
4040 if (!isPowerOf2_64(Value: AlignmentValue)) {
4041 return Error(L: NextTok.getLoc(), Msg: "alignment must be a power of two; was " +
4042 std::to_string(val: AlignmentValue));
4043 }
4044
4045 StringRef Qualifier;
4046 SMLoc QualifierLoc;
4047 if (parseOptionalToken(T: AsmToken::Comma)) {
4048 QualifierLoc = getTok().getLoc();
4049 if (parseIdentifier(Res&: Qualifier))
4050 return addErrorSuffix(Suffix: " in '" + Twine(Directive) + "' directive");
4051 if (!Qualifier.equals_insensitive(RHS: "nonunique"))
4052 return Error(L: QualifierLoc, Msg: "Unrecognized qualifier for '" +
4053 Twine(Directive) +
4054 "' directive; expected none or NONUNIQUE");
4055 }
4056
4057 if (parseEOL())
4058 return addErrorSuffix(Suffix: " in '" + Twine(Directive) + "' directive");
4059
4060 StructInProgress.emplace_back(Args&: Name, Args: DirKind == DK_UNION, Args&: AlignmentValue);
4061 return false;
4062}
4063
4064/// parseDirectiveNestedStruct
4065/// ::= (STRUC | STRUCT | UNION) [name]
4066/// (dataDir | generalDir | offsetDir | nestedStruct)+
4067/// ENDS
4068bool MasmParser::parseDirectiveNestedStruct(StringRef Directive,
4069 DirectiveKind DirKind) {
4070 if (StructInProgress.empty())
4071 return TokError(Msg: "missing name in top-level '" + Twine(Directive) +
4072 "' directive");
4073
4074 StringRef Name;
4075 if (getTok().is(K: AsmToken::Identifier)) {
4076 Name = getTok().getIdentifier();
4077 parseToken(T: AsmToken::Identifier);
4078 }
4079 if (parseEOL())
4080 return addErrorSuffix(Suffix: " in '" + Twine(Directive) + "' directive");
4081
4082 // Reserve space to ensure Alignment doesn't get invalidated when
4083 // StructInProgress grows.
4084 StructInProgress.reserve(N: StructInProgress.size() + 1);
4085 StructInProgress.emplace_back(Args&: Name, Args: DirKind == DK_UNION,
4086 Args&: StructInProgress.back().Alignment);
4087 return false;
4088}
4089
4090bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) {
4091 if (StructInProgress.empty())
4092 return Error(L: NameLoc, Msg: "ENDS directive without matching STRUC/STRUCT/UNION");
4093 if (StructInProgress.size() > 1)
4094 return Error(L: NameLoc, Msg: "unexpected name in nested ENDS directive");
4095 if (StructInProgress.back().Name.compare_insensitive(RHS: Name))
4096 return Error(L: NameLoc, Msg: "mismatched name in ENDS directive; expected '" +
4097 StructInProgress.back().Name + "'");
4098 StructInfo Structure = StructInProgress.pop_back_val();
4099 // Pad to make the structure's size divisible by the smaller of its alignment
4100 // and the size of its largest field.
4101 Structure.Size = llvm::alignTo(
4102 Value: Structure.Size, Align: std::min(a: Structure.Alignment, b: Structure.AlignmentSize));
4103 Structs[Name.lower()] = std::move(Structure);
4104
4105 if (parseEOL())
4106 return addErrorSuffix(Suffix: " in ENDS directive");
4107
4108 return false;
4109}
4110
4111bool MasmParser::parseDirectiveNestedEnds() {
4112 if (StructInProgress.empty())
4113 return TokError(Msg: "ENDS directive without matching STRUC/STRUCT/UNION");
4114 if (StructInProgress.size() == 1)
4115 return TokError(Msg: "missing name in top-level ENDS directive");
4116
4117 if (parseEOL())
4118 return addErrorSuffix(Suffix: " in nested ENDS directive");
4119
4120 StructInfo Structure = StructInProgress.pop_back_val();
4121 // Pad to make the structure's size divisible by its alignment.
4122 Structure.Size = llvm::alignTo(Value: Structure.Size, Align: Structure.Alignment);
4123
4124 StructInfo &ParentStruct = StructInProgress.back();
4125 if (Structure.Name.empty()) {
4126 // Anonymous substructures' fields are addressed as if they belong to the
4127 // parent structure - so we transfer them to the parent here.
4128 const size_t OldFields = ParentStruct.Fields.size();
4129 ParentStruct.Fields.insert(
4130 position: ParentStruct.Fields.end(),
4131 first: std::make_move_iterator(i: Structure.Fields.begin()),
4132 last: std::make_move_iterator(i: Structure.Fields.end()));
4133 for (const auto &FieldByName : Structure.FieldsByName) {
4134 ParentStruct.FieldsByName[FieldByName.getKey()] =
4135 FieldByName.getValue() + OldFields;
4136 }
4137
4138 unsigned FirstFieldOffset = 0;
4139 if (!Structure.Fields.empty() && !ParentStruct.IsUnion) {
4140 FirstFieldOffset = llvm::alignTo(
4141 Value: ParentStruct.NextOffset,
4142 Align: std::min(a: ParentStruct.Alignment, b: Structure.AlignmentSize));
4143 }
4144
4145 if (ParentStruct.IsUnion) {
4146 ParentStruct.Size = std::max(a: ParentStruct.Size, b: Structure.Size);
4147 } else {
4148 for (auto &Field : llvm::drop_begin(RangeOrContainer&: ParentStruct.Fields, N: OldFields))
4149 Field.Offset += FirstFieldOffset;
4150
4151 const unsigned StructureEnd = FirstFieldOffset + Structure.Size;
4152 if (!ParentStruct.IsUnion) {
4153 ParentStruct.NextOffset = StructureEnd;
4154 }
4155 ParentStruct.Size = std::max(a: ParentStruct.Size, b: StructureEnd);
4156 }
4157 } else {
4158 FieldInfo &Field = ParentStruct.addField(FieldName: Structure.Name, FT: FT_STRUCT,
4159 FieldAlignmentSize: Structure.AlignmentSize);
4160 StructFieldInfo &StructInfo = Field.Contents.StructInfo;
4161 Field.Type = Structure.Size;
4162 Field.LengthOf = 1;
4163 Field.SizeOf = Structure.Size;
4164
4165 const unsigned StructureEnd = Field.Offset + Field.SizeOf;
4166 if (!ParentStruct.IsUnion) {
4167 ParentStruct.NextOffset = StructureEnd;
4168 }
4169 ParentStruct.Size = std::max(a: ParentStruct.Size, b: StructureEnd);
4170
4171 StructInfo.Structure = Structure;
4172 StructInfo.Initializers.emplace_back();
4173 auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers;
4174 for (const auto &SubField : Structure.Fields) {
4175 FieldInitializers.push_back(x: SubField.Contents);
4176 }
4177 }
4178
4179 return false;
4180}
4181
4182/// parseDirectiveOrg
4183/// ::= org expression
4184bool MasmParser::parseDirectiveOrg() {
4185 const MCExpr *Offset;
4186 SMLoc OffsetLoc = Lexer.getLoc();
4187 if (checkForValidSection() || parseExpression(Res&: Offset))
4188 return true;
4189 if (parseEOL())
4190 return addErrorSuffix(Suffix: " in 'org' directive");
4191
4192 if (StructInProgress.empty()) {
4193 // Not in a struct; change the offset for the next instruction or data
4194 if (checkForValidSection())
4195 return addErrorSuffix(Suffix: " in 'org' directive");
4196
4197 getStreamer().emitValueToOffset(Offset, Value: 0, Loc: OffsetLoc);
4198 } else {
4199 // Offset the next field of this struct
4200 StructInfo &Structure = StructInProgress.back();
4201 int64_t OffsetRes;
4202 if (!Offset->evaluateAsAbsolute(Res&: OffsetRes, Asm: getStreamer().getAssemblerPtr()))
4203 return Error(L: OffsetLoc,
4204 Msg: "expected absolute expression in 'org' directive");
4205 if (OffsetRes < 0)
4206 return Error(
4207 L: OffsetLoc,
4208 Msg: "expected non-negative value in struct's 'org' directive; was " +
4209 std::to_string(val: OffsetRes));
4210 Structure.NextOffset = static_cast<unsigned>(OffsetRes);
4211
4212 // ORG-affected structures cannot be initialized
4213 Structure.Initializable = false;
4214 }
4215
4216 return false;
4217}
4218
4219bool MasmParser::emitAlignTo(int64_t Alignment) {
4220 if (StructInProgress.empty()) {
4221 // Not in a struct; align the next instruction or data
4222 if (checkForValidSection())
4223 return true;
4224
4225 // Check whether we should use optimal code alignment for this align
4226 // directive.
4227 const MCSection *Section = getStreamer().getCurrentSectionOnly();
4228 if (MAI.useCodeAlign(Sec: *Section)) {
4229 getStreamer().emitCodeAlignment(Alignment: Align(Alignment),
4230 STI: getTargetParser().getSTI(),
4231 /*MaxBytesToEmit=*/0);
4232 } else {
4233 // FIXME: Target specific behavior about how the "extra" bytes are filled.
4234 getStreamer().emitValueToAlignment(Alignment: Align(Alignment), /*Value=*/Fill: 0,
4235 /*ValueSize=*/FillLen: 1,
4236 /*MaxBytesToEmit=*/0);
4237 }
4238 } else {
4239 // Align the next field of this struct
4240 StructInfo &Structure = StructInProgress.back();
4241 Structure.NextOffset = llvm::alignTo(Value: Structure.NextOffset, Align: Alignment);
4242 }
4243
4244 return false;
4245}
4246
4247/// parseDirectiveAlign
4248/// ::= align expression
4249bool MasmParser::parseDirectiveAlign() {
4250 SMLoc AlignmentLoc = getLexer().getLoc();
4251 int64_t Alignment;
4252
4253 // Ignore empty 'align' directives.
4254 if (getTok().is(K: AsmToken::EndOfStatement)) {
4255 return Warning(L: AlignmentLoc,
4256 Msg: "align directive with no operand is ignored") &&
4257 parseEOL();
4258 }
4259 if (parseAbsoluteExpression(Res&: Alignment) || parseEOL())
4260 return addErrorSuffix(Suffix: " in align directive");
4261
4262 // Always emit an alignment here even if we throw an error.
4263 bool ReturnVal = false;
4264
4265 // Reject alignments that aren't either a power of two or zero, for ML.exe
4266 // compatibility. Alignment of zero is silently rounded up to one.
4267 if (Alignment == 0)
4268 Alignment = 1;
4269 if (!isPowerOf2_64(Value: Alignment))
4270 ReturnVal |= Error(L: AlignmentLoc, Msg: "alignment must be a power of 2; was " +
4271 std::to_string(val: Alignment));
4272
4273 if (emitAlignTo(Alignment))
4274 ReturnVal |= addErrorSuffix(Suffix: " in align directive");
4275
4276 return ReturnVal;
4277}
4278
4279/// parseDirectiveEven
4280/// ::= even
4281bool MasmParser::parseDirectiveEven() {
4282 if (parseEOL() || emitAlignTo(Alignment: 2))
4283 return addErrorSuffix(Suffix: " in even directive");
4284
4285 return false;
4286}
4287
4288/// parseDirectiveMacro
4289/// ::= name macro [parameters]
4290/// ["LOCAL" identifiers]
4291/// parameters ::= parameter [, parameter]*
4292/// parameter ::= name ":" qualifier
4293/// qualifier ::= "req" | "vararg" | "=" macro_argument
4294bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {
4295 MCAsmMacroParameters Parameters;
4296 while (getLexer().isNot(K: AsmToken::EndOfStatement)) {
4297 if (!Parameters.empty() && Parameters.back().Vararg)
4298 return Error(L: Lexer.getLoc(),
4299 Msg: "Vararg parameter '" + Parameters.back().Name +
4300 "' should be last in the list of parameters");
4301
4302 MCAsmMacroParameter Parameter;
4303 if (parseIdentifier(Res&: Parameter.Name))
4304 return TokError(Msg: "expected identifier in 'macro' directive");
4305
4306 // Emit an error if two (or more) named parameters share the same name.
4307 for (const MCAsmMacroParameter& CurrParam : Parameters)
4308 if (CurrParam.Name.equals_insensitive(RHS: Parameter.Name))
4309 return TokError(Msg: "macro '" + Name + "' has multiple parameters"
4310 " named '" + Parameter.Name + "'");
4311
4312 if (Lexer.is(K: AsmToken::Colon)) {
4313 Lex(); // consume ':'
4314
4315 if (parseOptionalToken(T: AsmToken::Equal)) {
4316 // Default value
4317 SMLoc ParamLoc;
4318
4319 ParamLoc = Lexer.getLoc();
4320 if (parseMacroArgument(MP: nullptr, MA&: Parameter.Value))
4321 return true;
4322 } else {
4323 SMLoc QualLoc;
4324 StringRef Qualifier;
4325
4326 QualLoc = Lexer.getLoc();
4327 if (parseIdentifier(Res&: Qualifier))
4328 return Error(L: QualLoc, Msg: "missing parameter qualifier for "
4329 "'" +
4330 Parameter.Name + "' in macro '" + Name +
4331 "'");
4332
4333 if (Qualifier.equals_insensitive(RHS: "req"))
4334 Parameter.Required = true;
4335 else if (Qualifier.equals_insensitive(RHS: "vararg"))
4336 Parameter.Vararg = true;
4337 else
4338 return Error(L: QualLoc,
4339 Msg: Qualifier + " is not a valid parameter qualifier for '" +
4340 Parameter.Name + "' in macro '" + Name + "'");
4341 }
4342 }
4343
4344 Parameters.push_back(x: std::move(Parameter));
4345
4346 if (getLexer().is(K: AsmToken::Comma))
4347 Lex();
4348 }
4349
4350 // Eat just the end of statement.
4351 Lexer.Lex();
4352
4353 std::vector<std::string> Locals;
4354 if (getTok().is(K: AsmToken::Identifier) &&
4355 getTok().getIdentifier().equals_insensitive(RHS: "local")) {
4356 Lex(); // Eat the LOCAL directive.
4357
4358 StringRef ID;
4359 while (true) {
4360 if (parseIdentifier(Res&: ID))
4361 return true;
4362 Locals.push_back(x: ID.lower());
4363
4364 // If we see a comma, continue (and allow line continuation).
4365 if (!parseOptionalToken(T: AsmToken::Comma))
4366 break;
4367 parseOptionalToken(T: AsmToken::EndOfStatement);
4368 }
4369 }
4370
4371 // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors.
4372 AsmToken EndToken, StartToken = getTok();
4373 unsigned MacroDepth = 0;
4374 bool IsMacroFunction = false;
4375 // Lex the macro definition.
4376 while (true) {
4377 // Ignore Lexing errors in macros.
4378 while (Lexer.is(K: AsmToken::Error)) {
4379 Lexer.Lex();
4380 }
4381
4382 // Check whether we have reached the end of the file.
4383 if (getLexer().is(K: AsmToken::Eof))
4384 return Error(L: NameLoc, Msg: "no matching 'endm' in definition");
4385
4386 // Otherwise, check whether we have reached the 'endm'... and determine if
4387 // this is a macro function.
4388 if (getLexer().is(K: AsmToken::Identifier)) {
4389 if (getTok().getIdentifier().equals_insensitive(RHS: "endm")) {
4390 if (MacroDepth == 0) { // Outermost macro.
4391 EndToken = getTok();
4392 Lexer.Lex();
4393 if (getLexer().isNot(K: AsmToken::EndOfStatement))
4394 return TokError(Msg: "unexpected token in '" + EndToken.getIdentifier() +
4395 "' directive");
4396 break;
4397 } else {
4398 // Otherwise we just found the end of an inner macro.
4399 --MacroDepth;
4400 }
4401 } else if (getTok().getIdentifier().equals_insensitive(RHS: "exitm")) {
4402 if (MacroDepth == 0 && peekTok().isNot(K: AsmToken::EndOfStatement)) {
4403 IsMacroFunction = true;
4404 }
4405 } else if (isMacroLikeDirective()) {
4406 // We allow nested macros. Those aren't instantiated until the
4407 // outermost macro is expanded so just ignore them for now.
4408 ++MacroDepth;
4409 }
4410 }
4411
4412 // Otherwise, scan til the end of the statement.
4413 eatToEndOfStatement();
4414 }
4415
4416 if (getContext().lookupMacro(Name: Name.lower())) {
4417 return Error(L: NameLoc, Msg: "macro '" + Name + "' is already defined");
4418 }
4419
4420 const char *BodyStart = StartToken.getLoc().getPointer();
4421 const char *BodyEnd = EndToken.getLoc().getPointer();
4422 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
4423 MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals),
4424 IsMacroFunction);
4425 DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";
4426 Macro.dump());
4427 getContext().defineMacro(Name: Name.lower(), Macro: std::move(Macro));
4428 return false;
4429}
4430
4431/// parseDirectiveExitMacro
4432/// ::= "exitm" [textitem]
4433bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc,
4434 StringRef Directive,
4435 std::string &Value) {
4436 SMLoc EndLoc = getTok().getLoc();
4437 if (getTok().isNot(K: AsmToken::EndOfStatement) && parseTextItem(Data&: Value))
4438 return Error(L: EndLoc,
4439 Msg: "unable to parse text item in '" + Directive + "' directive");
4440 eatToEndOfStatement();
4441
4442 if (!isInsideMacroInstantiation())
4443 return TokError(Msg: "unexpected '" + Directive + "' in file, "
4444 "no current macro definition");
4445
4446 // Exit all conditionals that are active in the current macro.
4447 while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {
4448 TheCondState = TheCondStack.back();
4449 TheCondStack.pop_back();
4450 }
4451
4452 handleMacroExit();
4453 return false;
4454}
4455
4456/// parseDirectiveEndMacro
4457/// ::= endm
4458bool MasmParser::parseDirectiveEndMacro(StringRef Directive) {
4459 if (getLexer().isNot(K: AsmToken::EndOfStatement))
4460 return TokError(Msg: "unexpected token in '" + Directive + "' directive");
4461
4462 // If we are inside a macro instantiation, terminate the current
4463 // instantiation.
4464 if (isInsideMacroInstantiation()) {
4465 handleMacroExit();
4466 return false;
4467 }
4468
4469 // Otherwise, this .endmacro is a stray entry in the file; well formed
4470 // .endmacro directives are handled during the macro definition parsing.
4471 return TokError(Msg: "unexpected '" + Directive + "' in file, "
4472 "no current macro definition");
4473}
4474
4475/// parseDirectivePurgeMacro
4476/// ::= purge identifier ( , identifier )*
4477bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {
4478 StringRef Name;
4479 while (true) {
4480 SMLoc NameLoc;
4481 if (parseTokenLoc(Loc&: NameLoc) ||
4482 check(P: parseIdentifier(Res&: Name), Loc: NameLoc,
4483 Msg: "expected identifier in 'purge' directive"))
4484 return true;
4485
4486 DEBUG_WITH_TYPE("asm-macros", dbgs()
4487 << "Un-defining macro: " << Name << "\n");
4488 if (!getContext().lookupMacro(Name: Name.lower()))
4489 return Error(L: NameLoc, Msg: "macro '" + Name + "' is not defined");
4490 getContext().undefineMacro(Name: Name.lower());
4491
4492 if (!parseOptionalToken(T: AsmToken::Comma))
4493 break;
4494 parseOptionalToken(T: AsmToken::EndOfStatement);
4495 }
4496
4497 return false;
4498}
4499
4500bool MasmParser::parseDirectiveExtern() {
4501 // .extern is the default - but we still need to take any provided type info.
4502 auto parseOp = [&]() -> bool {
4503 MCSymbol *Sym;
4504 SMLoc NameLoc = getTok().getLoc();
4505 if (parseSymbol(Res&: Sym))
4506 return Error(L: NameLoc, Msg: "expected name");
4507 if (parseToken(T: AsmToken::Colon))
4508 return true;
4509
4510 StringRef TypeName;
4511 SMLoc TypeLoc = getTok().getLoc();
4512 if (parseIdentifier(Res&: TypeName))
4513 return Error(L: TypeLoc, Msg: "expected type");
4514 if (!TypeName.equals_insensitive(RHS: "proc")) {
4515 AsmTypeInfo Type;
4516 if (lookUpType(Name: TypeName, Info&: Type))
4517 return Error(L: TypeLoc, Msg: "unrecognized type");
4518 KnownType[Sym->getName().lower()] = Type;
4519 }
4520
4521 static_cast<MCSymbolCOFF *>(Sym)->setExternal(true);
4522 getStreamer().emitSymbolAttribute(Symbol: Sym, Attribute: MCSA_Extern);
4523
4524 return false;
4525 };
4526
4527 if (parseMany(parseOne: parseOp))
4528 return addErrorSuffix(Suffix: " in directive 'extern'");
4529 return false;
4530}
4531
4532/// parseDirectiveSymbolAttribute
4533/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
4534bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
4535 auto parseOp = [&]() -> bool {
4536 SMLoc Loc = getTok().getLoc();
4537 MCSymbol *Sym;
4538 if (parseSymbol(Res&: Sym))
4539 return Error(L: Loc, Msg: "expected identifier");
4540
4541 // Assembler local symbols don't make any sense here. Complain loudly.
4542 if (Sym->isTemporary())
4543 return Error(L: Loc, Msg: "non-local symbol required");
4544
4545 if (!getStreamer().emitSymbolAttribute(Symbol: Sym, Attribute: Attr))
4546 return Error(L: Loc, Msg: "unable to emit symbol attribute");
4547 return false;
4548 };
4549
4550 if (parseMany(parseOne: parseOp))
4551 return addErrorSuffix(Suffix: " in directive");
4552 return false;
4553}
4554
4555/// parseDirectiveComm
4556/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]
4557bool MasmParser::parseDirectiveComm(bool IsLocal) {
4558 if (checkForValidSection())
4559 return true;
4560
4561 SMLoc IDLoc = getLexer().getLoc();
4562 MCSymbol *Sym;
4563 if (parseSymbol(Res&: Sym))
4564 return TokError(Msg: "expected identifier in directive");
4565
4566 if (getLexer().isNot(K: AsmToken::Comma))
4567 return TokError(Msg: "unexpected token in directive");
4568 Lex();
4569
4570 int64_t Size;
4571 SMLoc SizeLoc = getLexer().getLoc();
4572 if (parseAbsoluteExpression(Res&: Size))
4573 return true;
4574
4575 int64_t Pow2Alignment = 0;
4576 SMLoc Pow2AlignmentLoc;
4577 if (getLexer().is(K: AsmToken::Comma)) {
4578 Lex();
4579 Pow2AlignmentLoc = getLexer().getLoc();
4580 if (parseAbsoluteExpression(Res&: Pow2Alignment))
4581 return true;
4582
4583 LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();
4584 if (IsLocal && LCOMM == LCOMM::NoAlignment)
4585 return Error(L: Pow2AlignmentLoc, Msg: "alignment not supported on this target");
4586
4587 // If this target takes alignments in bytes (not log) validate and convert.
4588 if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||
4589 (IsLocal && LCOMM == LCOMM::ByteAlignment)) {
4590 if (!isPowerOf2_64(Value: Pow2Alignment))
4591 return Error(L: Pow2AlignmentLoc, Msg: "alignment must be a power of 2");
4592 Pow2Alignment = Log2_64(Value: Pow2Alignment);
4593 }
4594 }
4595
4596 if (parseEOL())
4597 return true;
4598
4599 // NOTE: a size of zero for a .comm should create a undefined symbol
4600 // but a size of .lcomm creates a bss symbol of size zero.
4601 if (Size < 0)
4602 return Error(L: SizeLoc, Msg: "invalid '.comm' or '.lcomm' directive size, can't "
4603 "be less than zero");
4604
4605 // NOTE: The alignment in the directive is a power of 2 value, the assembler
4606 // may internally end up wanting an alignment in bytes.
4607 // FIXME: Diagnose overflow.
4608 if (Pow2Alignment < 0)
4609 return Error(L: Pow2AlignmentLoc, Msg: "invalid '.comm' or '.lcomm' directive "
4610 "alignment, can't be less than zero");
4611
4612 Sym->redefineIfPossible();
4613 if (!Sym->isUndefined())
4614 return Error(L: IDLoc, Msg: "invalid symbol redefinition");
4615
4616 // Create the Symbol as a common or local common with Size and Pow2Alignment.
4617 if (IsLocal) {
4618 getStreamer().emitLocalCommonSymbol(Symbol: Sym, Size,
4619 ByteAlignment: Align(1ULL << Pow2Alignment));
4620 return false;
4621 }
4622
4623 getStreamer().emitCommonSymbol(Symbol: Sym, Size, ByteAlignment: Align(1ULL << Pow2Alignment));
4624 return false;
4625}
4626
4627/// parseDirectiveComment
4628/// ::= comment delimiter [[text]]
4629/// [[text]]
4630/// [[text]] delimiter [[text]]
4631bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) {
4632 std::string FirstLine = parseStringTo(EndTok: AsmToken::EndOfStatement);
4633 size_t DelimiterEnd = FirstLine.find_first_of(s: "\b\t\v\f\r\x1A ");
4634 assert(DelimiterEnd != std::string::npos);
4635 StringRef Delimiter = StringRef(FirstLine).take_front(N: DelimiterEnd);
4636 if (Delimiter.empty())
4637 return Error(L: DirectiveLoc, Msg: "no delimiter in 'comment' directive");
4638 do {
4639 if (getTok().is(K: AsmToken::Eof))
4640 return Error(L: DirectiveLoc, Msg: "unmatched delimiter in 'comment' directive");
4641 Lex(); // eat end of statement
4642 } while (
4643 !StringRef(parseStringTo(EndTok: AsmToken::EndOfStatement)).contains(Other: Delimiter));
4644 return parseEOL();
4645}
4646
4647/// parseDirectiveInclude
4648/// ::= include <filename>
4649/// | include filename
4650bool MasmParser::parseDirectiveInclude() {
4651 // Allow the strings to have escaped octal character sequence.
4652 std::string Filename;
4653 SMLoc IncludeLoc = getTok().getLoc();
4654
4655 if (parseAngleBracketString(Data&: Filename))
4656 Filename = parseStringTo(EndTok: AsmToken::EndOfStatement);
4657 if (check(P: Filename.empty(), Msg: "missing filename in 'include' directive") ||
4658 check(P: getTok().isNot(K: AsmToken::EndOfStatement),
4659 Msg: "unexpected token in 'include' directive") ||
4660 // Attempt to switch the lexer to the included file before consuming the
4661 // end of statement to avoid losing it when we switch.
4662 check(P: enterIncludeFile(Filename), Loc: IncludeLoc,
4663 Msg: "Could not find include file '" + Filename + "'"))
4664 return true;
4665
4666 return false;
4667}
4668
4669/// parseDirectiveIf
4670/// ::= .if{,eq,ge,gt,le,lt,ne} expression
4671bool MasmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {
4672 TheCondStack.push_back(x: TheCondState);
4673 TheCondState.TheCond = AsmCond::IfCond;
4674 if (TheCondState.Ignore) {
4675 eatToEndOfStatement();
4676 } else {
4677 int64_t ExprValue;
4678 if (parseAbsoluteExpression(Res&: ExprValue) || parseEOL())
4679 return true;
4680
4681 switch (DirKind) {
4682 default:
4683 llvm_unreachable("unsupported directive");
4684 case DK_IF:
4685 break;
4686 case DK_IFE:
4687 ExprValue = ExprValue == 0;
4688 break;
4689 }
4690
4691 TheCondState.CondMet = ExprValue;
4692 TheCondState.Ignore = !TheCondState.CondMet;
4693 }
4694
4695 return false;
4696}
4697
4698/// parseDirectiveIfb
4699/// ::= .ifb textitem
4700bool MasmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {
4701 TheCondStack.push_back(x: TheCondState);
4702 TheCondState.TheCond = AsmCond::IfCond;
4703
4704 if (TheCondState.Ignore) {
4705 eatToEndOfStatement();
4706 } else {
4707 std::string Str;
4708 if (parseTextItem(Data&: Str))
4709 return TokError(Msg: "expected text item parameter for 'ifb' directive");
4710
4711 if (parseEOL())
4712 return true;
4713
4714 TheCondState.CondMet = ExpectBlank == Str.empty();
4715 TheCondState.Ignore = !TheCondState.CondMet;
4716 }
4717
4718 return false;
4719}
4720
4721/// parseDirectiveIfidn
4722/// ::= ifidn textitem, textitem
4723bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,
4724 bool CaseInsensitive) {
4725 std::string String1, String2;
4726
4727 if (parseTextItem(Data&: String1)) {
4728 if (ExpectEqual)
4729 return TokError(Msg: "expected text item parameter for 'ifidn' directive");
4730 return TokError(Msg: "expected text item parameter for 'ifdif' directive");
4731 }
4732
4733 if (Lexer.isNot(K: AsmToken::Comma)) {
4734 if (ExpectEqual)
4735 return TokError(
4736 Msg: "expected comma after first string for 'ifidn' directive");
4737 return TokError(Msg: "expected comma after first string for 'ifdif' directive");
4738 }
4739 Lex();
4740
4741 if (parseTextItem(Data&: String2)) {
4742 if (ExpectEqual)
4743 return TokError(Msg: "expected text item parameter for 'ifidn' directive");
4744 return TokError(Msg: "expected text item parameter for 'ifdif' directive");
4745 }
4746
4747 TheCondStack.push_back(x: TheCondState);
4748 TheCondState.TheCond = AsmCond::IfCond;
4749 if (CaseInsensitive)
4750 TheCondState.CondMet =
4751 ExpectEqual == (StringRef(String1).equals_insensitive(RHS: String2));
4752 else
4753 TheCondState.CondMet = ExpectEqual == (String1 == String2);
4754 TheCondState.Ignore = !TheCondState.CondMet;
4755
4756 return false;
4757}
4758
4759/// parseDirectiveIfdef
4760/// ::= ifdef symbol
4761/// | ifdef variable
4762bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {
4763 TheCondStack.push_back(x: TheCondState);
4764 TheCondState.TheCond = AsmCond::IfCond;
4765
4766 if (TheCondState.Ignore) {
4767 eatToEndOfStatement();
4768 } else {
4769 bool is_defined = false;
4770 MCRegister Reg;
4771 SMLoc StartLoc, EndLoc;
4772 is_defined =
4773 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();
4774 if (!is_defined) {
4775 StringRef Name;
4776 if (check(P: parseIdentifier(Res&: Name), Msg: "expected identifier after 'ifdef'") ||
4777 parseEOL())
4778 return true;
4779
4780 if (BuiltinSymbolMap.contains(Key: Name.lower())) {
4781 is_defined = true;
4782 } else if (Variables.contains(Key: Name.lower())) {
4783 is_defined = true;
4784 } else {
4785 MCSymbol *Sym = getContext().lookupSymbol(Name: Name.lower());
4786 is_defined = (Sym && !Sym->isUndefined());
4787 }
4788 }
4789
4790 TheCondState.CondMet = (is_defined == expect_defined);
4791 TheCondState.Ignore = !TheCondState.CondMet;
4792 }
4793
4794 return false;
4795}
4796
4797/// parseDirectiveElseIf
4798/// ::= elseif expression
4799bool MasmParser::parseDirectiveElseIf(SMLoc DirectiveLoc,
4800 DirectiveKind DirKind) {
4801 if (TheCondState.TheCond != AsmCond::IfCond &&
4802 TheCondState.TheCond != AsmCond::ElseIfCond)
4803 return Error(L: DirectiveLoc, Msg: "Encountered a .elseif that doesn't follow an"
4804 " .if or an .elseif");
4805 TheCondState.TheCond = AsmCond::ElseIfCond;
4806
4807 bool LastIgnoreState = false;
4808 if (!TheCondStack.empty())
4809 LastIgnoreState = TheCondStack.back().Ignore;
4810 if (LastIgnoreState || TheCondState.CondMet) {
4811 TheCondState.Ignore = true;
4812 eatToEndOfStatement();
4813 } else {
4814 int64_t ExprValue;
4815 if (parseAbsoluteExpression(Res&: ExprValue))
4816 return true;
4817
4818 if (parseEOL())
4819 return true;
4820
4821 switch (DirKind) {
4822 default:
4823 llvm_unreachable("unsupported directive");
4824 case DK_ELSEIF:
4825 break;
4826 case DK_ELSEIFE:
4827 ExprValue = ExprValue == 0;
4828 break;
4829 }
4830
4831 TheCondState.CondMet = ExprValue;
4832 TheCondState.Ignore = !TheCondState.CondMet;
4833 }
4834
4835 return false;
4836}
4837
4838/// parseDirectiveElseIfb
4839/// ::= elseifb textitem
4840bool MasmParser::parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank) {
4841 if (TheCondState.TheCond != AsmCond::IfCond &&
4842 TheCondState.TheCond != AsmCond::ElseIfCond)
4843 return Error(L: DirectiveLoc, Msg: "Encountered an elseif that doesn't follow an"
4844 " if or an elseif");
4845 TheCondState.TheCond = AsmCond::ElseIfCond;
4846
4847 bool LastIgnoreState = false;
4848 if (!TheCondStack.empty())
4849 LastIgnoreState = TheCondStack.back().Ignore;
4850 if (LastIgnoreState || TheCondState.CondMet) {
4851 TheCondState.Ignore = true;
4852 eatToEndOfStatement();
4853 } else {
4854 std::string Str;
4855 if (parseTextItem(Data&: Str)) {
4856 if (ExpectBlank)
4857 return TokError(Msg: "expected text item parameter for 'elseifb' directive");
4858 return TokError(Msg: "expected text item parameter for 'elseifnb' directive");
4859 }
4860
4861 if (parseEOL())
4862 return true;
4863
4864 TheCondState.CondMet = ExpectBlank == Str.empty();
4865 TheCondState.Ignore = !TheCondState.CondMet;
4866 }
4867
4868 return false;
4869}
4870
4871/// parseDirectiveElseIfdef
4872/// ::= elseifdef symbol
4873/// | elseifdef variable
4874bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc,
4875 bool expect_defined) {
4876 if (TheCondState.TheCond != AsmCond::IfCond &&
4877 TheCondState.TheCond != AsmCond::ElseIfCond)
4878 return Error(L: DirectiveLoc, Msg: "Encountered an elseif that doesn't follow an"
4879 " if or an elseif");
4880 TheCondState.TheCond = AsmCond::ElseIfCond;
4881
4882 bool LastIgnoreState = false;
4883 if (!TheCondStack.empty())
4884 LastIgnoreState = TheCondStack.back().Ignore;
4885 if (LastIgnoreState || TheCondState.CondMet) {
4886 TheCondState.Ignore = true;
4887 eatToEndOfStatement();
4888 } else {
4889 bool is_defined = false;
4890 MCRegister Reg;
4891 SMLoc StartLoc, EndLoc;
4892 is_defined =
4893 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();
4894 if (!is_defined) {
4895 StringRef Name;
4896 if (check(P: parseIdentifier(Res&: Name),
4897 Msg: "expected identifier after 'elseifdef'") ||
4898 parseEOL())
4899 return true;
4900
4901 if (BuiltinSymbolMap.contains(Key: Name.lower())) {
4902 is_defined = true;
4903 } else if (Variables.contains(Key: Name.lower())) {
4904 is_defined = true;
4905 } else {
4906 MCSymbol *Sym = getContext().lookupSymbol(Name);
4907 is_defined = (Sym && !Sym->isUndefined());
4908 }
4909 }
4910
4911 TheCondState.CondMet = (is_defined == expect_defined);
4912 TheCondState.Ignore = !TheCondState.CondMet;
4913 }
4914
4915 return false;
4916}
4917
4918/// parseDirectiveElseIfidn
4919/// ::= elseifidn textitem, textitem
4920bool MasmParser::parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,
4921 bool CaseInsensitive) {
4922 if (TheCondState.TheCond != AsmCond::IfCond &&
4923 TheCondState.TheCond != AsmCond::ElseIfCond)
4924 return Error(L: DirectiveLoc, Msg: "Encountered an elseif that doesn't follow an"
4925 " if or an elseif");
4926 TheCondState.TheCond = AsmCond::ElseIfCond;
4927
4928 bool LastIgnoreState = false;
4929 if (!TheCondStack.empty())
4930 LastIgnoreState = TheCondStack.back().Ignore;
4931 if (LastIgnoreState || TheCondState.CondMet) {
4932 TheCondState.Ignore = true;
4933 eatToEndOfStatement();
4934 } else {
4935 std::string String1, String2;
4936
4937 if (parseTextItem(Data&: String1)) {
4938 if (ExpectEqual)
4939 return TokError(
4940 Msg: "expected text item parameter for 'elseifidn' directive");
4941 return TokError(Msg: "expected text item parameter for 'elseifdif' directive");
4942 }
4943
4944 if (Lexer.isNot(K: AsmToken::Comma)) {
4945 if (ExpectEqual)
4946 return TokError(
4947 Msg: "expected comma after first string for 'elseifidn' directive");
4948 return TokError(
4949 Msg: "expected comma after first string for 'elseifdif' directive");
4950 }
4951 Lex();
4952
4953 if (parseTextItem(Data&: String2)) {
4954 if (ExpectEqual)
4955 return TokError(
4956 Msg: "expected text item parameter for 'elseifidn' directive");
4957 return TokError(Msg: "expected text item parameter for 'elseifdif' directive");
4958 }
4959
4960 if (CaseInsensitive)
4961 TheCondState.CondMet =
4962 ExpectEqual == (StringRef(String1).equals_insensitive(RHS: String2));
4963 else
4964 TheCondState.CondMet = ExpectEqual == (String1 == String2);
4965 TheCondState.Ignore = !TheCondState.CondMet;
4966 }
4967
4968 return false;
4969}
4970
4971/// parseDirectiveElse
4972/// ::= else
4973bool MasmParser::parseDirectiveElse(SMLoc DirectiveLoc) {
4974 if (parseEOL())
4975 return true;
4976
4977 if (TheCondState.TheCond != AsmCond::IfCond &&
4978 TheCondState.TheCond != AsmCond::ElseIfCond)
4979 return Error(L: DirectiveLoc, Msg: "Encountered an else that doesn't follow an if"
4980 " or an elseif");
4981 TheCondState.TheCond = AsmCond::ElseCond;
4982 bool LastIgnoreState = false;
4983 if (!TheCondStack.empty())
4984 LastIgnoreState = TheCondStack.back().Ignore;
4985 if (LastIgnoreState || TheCondState.CondMet)
4986 TheCondState.Ignore = true;
4987 else
4988 TheCondState.Ignore = false;
4989
4990 return false;
4991}
4992
4993/// parseDirectiveEnd
4994/// ::= end
4995bool MasmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {
4996 if (parseEOL())
4997 return true;
4998
4999 while (Lexer.isNot(K: AsmToken::Eof))
5000 Lexer.Lex();
5001
5002 return false;
5003}
5004
5005/// parseDirectiveError
5006/// ::= .err [message]
5007bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) {
5008 if (!TheCondStack.empty()) {
5009 if (TheCondStack.back().Ignore) {
5010 eatToEndOfStatement();
5011 return false;
5012 }
5013 }
5014
5015 std::string Message = ".err directive invoked in source file";
5016 if (Lexer.isNot(K: AsmToken::EndOfStatement))
5017 Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5018 Lex();
5019
5020 return Error(L: DirectiveLoc, Msg: Message);
5021}
5022
5023/// parseDirectiveErrorIfb
5024/// ::= .errb textitem[, message]
5025bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) {
5026 if (!TheCondStack.empty()) {
5027 if (TheCondStack.back().Ignore) {
5028 eatToEndOfStatement();
5029 return false;
5030 }
5031 }
5032
5033 std::string Text;
5034 if (parseTextItem(Data&: Text))
5035 return Error(L: getTok().getLoc(), Msg: "missing text item in '.errb' directive");
5036
5037 std::string Message = ".errb directive invoked in source file";
5038 if (Lexer.isNot(K: AsmToken::EndOfStatement)) {
5039 if (parseToken(T: AsmToken::Comma))
5040 return addErrorSuffix(Suffix: " in '.errb' directive");
5041 Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5042 }
5043 Lex();
5044
5045 if (Text.empty() == ExpectBlank)
5046 return Error(L: DirectiveLoc, Msg: Message);
5047 return false;
5048}
5049
5050/// parseDirectiveErrorIfdef
5051/// ::= .errdef name[, message]
5052bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc,
5053 bool ExpectDefined) {
5054 if (!TheCondStack.empty()) {
5055 if (TheCondStack.back().Ignore) {
5056 eatToEndOfStatement();
5057 return false;
5058 }
5059 }
5060
5061 bool IsDefined = false;
5062 MCRegister Reg;
5063 SMLoc StartLoc, EndLoc;
5064 IsDefined =
5065 getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();
5066 if (!IsDefined) {
5067 StringRef Name;
5068 if (check(P: parseIdentifier(Res&: Name), Msg: "expected identifier after '.errdef'"))
5069 return true;
5070
5071 if (BuiltinSymbolMap.contains(Key: Name.lower())) {
5072 IsDefined = true;
5073 } else if (Variables.contains(Key: Name.lower())) {
5074 IsDefined = true;
5075 } else {
5076 MCSymbol *Sym = getContext().lookupSymbol(Name);
5077 IsDefined = (Sym && !Sym->isUndefined());
5078 }
5079 }
5080
5081 std::string Message = ".errdef directive invoked in source file";
5082 if (Lexer.isNot(K: AsmToken::EndOfStatement)) {
5083 if (parseToken(T: AsmToken::Comma))
5084 return addErrorSuffix(Suffix: " in '.errdef' directive");
5085 Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5086 }
5087 Lex();
5088
5089 if (IsDefined == ExpectDefined)
5090 return Error(L: DirectiveLoc, Msg: Message);
5091 return false;
5092}
5093
5094/// parseDirectiveErrorIfidn
5095/// ::= .erridn textitem, textitem[, message]
5096bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,
5097 bool CaseInsensitive) {
5098 if (!TheCondStack.empty()) {
5099 if (TheCondStack.back().Ignore) {
5100 eatToEndOfStatement();
5101 return false;
5102 }
5103 }
5104
5105 std::string String1, String2;
5106
5107 if (parseTextItem(Data&: String1)) {
5108 if (ExpectEqual)
5109 return TokError(Msg: "expected string parameter for '.erridn' directive");
5110 return TokError(Msg: "expected string parameter for '.errdif' directive");
5111 }
5112
5113 if (Lexer.isNot(K: AsmToken::Comma)) {
5114 if (ExpectEqual)
5115 return TokError(
5116 Msg: "expected comma after first string for '.erridn' directive");
5117 return TokError(
5118 Msg: "expected comma after first string for '.errdif' directive");
5119 }
5120 Lex();
5121
5122 if (parseTextItem(Data&: String2)) {
5123 if (ExpectEqual)
5124 return TokError(Msg: "expected string parameter for '.erridn' directive");
5125 return TokError(Msg: "expected string parameter for '.errdif' directive");
5126 }
5127
5128 std::string Message;
5129 if (ExpectEqual)
5130 Message = ".erridn directive invoked in source file";
5131 else
5132 Message = ".errdif directive invoked in source file";
5133 if (Lexer.isNot(K: AsmToken::EndOfStatement)) {
5134 if (parseToken(T: AsmToken::Comma))
5135 return addErrorSuffix(Suffix: " in '.erridn' directive");
5136 Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5137 }
5138 Lex();
5139
5140 if (CaseInsensitive)
5141 TheCondState.CondMet =
5142 ExpectEqual == (StringRef(String1).equals_insensitive(RHS: String2));
5143 else
5144 TheCondState.CondMet = ExpectEqual == (String1 == String2);
5145 TheCondState.Ignore = !TheCondState.CondMet;
5146
5147 if ((CaseInsensitive &&
5148 ExpectEqual == StringRef(String1).equals_insensitive(RHS: String2)) ||
5149 (ExpectEqual == (String1 == String2)))
5150 return Error(L: DirectiveLoc, Msg: Message);
5151 return false;
5152}
5153
5154/// parseDirectiveErrorIfe
5155/// ::= .erre expression[, message]
5156bool MasmParser::parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero) {
5157 if (!TheCondStack.empty()) {
5158 if (TheCondStack.back().Ignore) {
5159 eatToEndOfStatement();
5160 return false;
5161 }
5162 }
5163
5164 int64_t ExprValue;
5165 if (parseAbsoluteExpression(Res&: ExprValue))
5166 return addErrorSuffix(Suffix: " in '.erre' directive");
5167
5168 std::string Message = ".erre directive invoked in source file";
5169 if (Lexer.isNot(K: AsmToken::EndOfStatement)) {
5170 if (parseToken(T: AsmToken::Comma))
5171 return addErrorSuffix(Suffix: " in '.erre' directive");
5172 Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5173 }
5174 Lex();
5175
5176 if ((ExprValue == 0) == ExpectZero)
5177 return Error(L: DirectiveLoc, Msg: Message);
5178 return false;
5179}
5180
5181/// parseDirectiveEndIf
5182/// ::= .endif
5183bool MasmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {
5184 if (parseEOL())
5185 return true;
5186
5187 if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())
5188 return Error(L: DirectiveLoc, Msg: "Encountered a .endif that doesn't follow "
5189 "an .if or .else");
5190 if (!TheCondStack.empty()) {
5191 TheCondState = TheCondStack.back();
5192 TheCondStack.pop_back();
5193 }
5194
5195 return false;
5196}
5197
5198void MasmParser::initializeDirectiveKindMap() {
5199 DirectiveKindMap["="] = DK_ASSIGN;
5200 DirectiveKindMap["equ"] = DK_EQU;
5201 DirectiveKindMap["textequ"] = DK_TEXTEQU;
5202 // DirectiveKindMap[".ascii"] = DK_ASCII;
5203 // DirectiveKindMap[".asciz"] = DK_ASCIZ;
5204 // DirectiveKindMap[".string"] = DK_STRING;
5205 DirectiveKindMap["byte"] = DK_BYTE;
5206 DirectiveKindMap["sbyte"] = DK_SBYTE;
5207 DirectiveKindMap["word"] = DK_WORD;
5208 DirectiveKindMap["sword"] = DK_SWORD;
5209 DirectiveKindMap["dword"] = DK_DWORD;
5210 DirectiveKindMap["sdword"] = DK_SDWORD;
5211 DirectiveKindMap["fword"] = DK_FWORD;
5212 DirectiveKindMap["qword"] = DK_QWORD;
5213 DirectiveKindMap["sqword"] = DK_SQWORD;
5214 DirectiveKindMap["real4"] = DK_REAL4;
5215 DirectiveKindMap["real8"] = DK_REAL8;
5216 DirectiveKindMap["real10"] = DK_REAL10;
5217 DirectiveKindMap["align"] = DK_ALIGN;
5218 DirectiveKindMap["even"] = DK_EVEN;
5219 DirectiveKindMap["org"] = DK_ORG;
5220 DirectiveKindMap["extern"] = DK_EXTERN;
5221 DirectiveKindMap["extrn"] = DK_EXTERN;
5222 DirectiveKindMap["public"] = DK_PUBLIC;
5223 // DirectiveKindMap[".comm"] = DK_COMM;
5224 DirectiveKindMap["comment"] = DK_COMMENT;
5225 DirectiveKindMap["include"] = DK_INCLUDE;
5226 DirectiveKindMap["repeat"] = DK_REPEAT;
5227 DirectiveKindMap["rept"] = DK_REPEAT;
5228 DirectiveKindMap["while"] = DK_WHILE;
5229 DirectiveKindMap["for"] = DK_FOR;
5230 DirectiveKindMap["irp"] = DK_FOR;
5231 DirectiveKindMap["forc"] = DK_FORC;
5232 DirectiveKindMap["irpc"] = DK_FORC;
5233 DirectiveKindMap["if"] = DK_IF;
5234 DirectiveKindMap["ife"] = DK_IFE;
5235 DirectiveKindMap["ifb"] = DK_IFB;
5236 DirectiveKindMap["ifnb"] = DK_IFNB;
5237 DirectiveKindMap["ifdef"] = DK_IFDEF;
5238 DirectiveKindMap["ifndef"] = DK_IFNDEF;
5239 DirectiveKindMap["ifdif"] = DK_IFDIF;
5240 DirectiveKindMap["ifdifi"] = DK_IFDIFI;
5241 DirectiveKindMap["ifidn"] = DK_IFIDN;
5242 DirectiveKindMap["ifidni"] = DK_IFIDNI;
5243 DirectiveKindMap["elseif"] = DK_ELSEIF;
5244 DirectiveKindMap["elseifdef"] = DK_ELSEIFDEF;
5245 DirectiveKindMap["elseifndef"] = DK_ELSEIFNDEF;
5246 DirectiveKindMap["elseifdif"] = DK_ELSEIFDIF;
5247 DirectiveKindMap["elseifidn"] = DK_ELSEIFIDN;
5248 DirectiveKindMap["else"] = DK_ELSE;
5249 DirectiveKindMap["end"] = DK_END;
5250 DirectiveKindMap["endif"] = DK_ENDIF;
5251 // DirectiveKindMap[".file"] = DK_FILE;
5252 // DirectiveKindMap[".line"] = DK_LINE;
5253 // DirectiveKindMap[".loc"] = DK_LOC;
5254 // DirectiveKindMap[".stabs"] = DK_STABS;
5255 // DirectiveKindMap[".cv_file"] = DK_CV_FILE;
5256 // DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
5257 // DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
5258 // DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
5259 // DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
5260 // DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;
5261 // DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
5262 // DirectiveKindMap[".cv_string"] = DK_CV_STRING;
5263 // DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
5264 // DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
5265 // DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;
5266 // DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;
5267 // DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
5268 // DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;
5269 // DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;
5270 // DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;
5271 // DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;
5272 // DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;
5273 // DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
5274 // DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
5275 // DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
5276 // DirectiveKindMap[".cfi_llvm_register_pair"] = DK_CFI_LLVM_REGISTER_PAIR;
5277 // DirectiveKindMap[".cfi_llvm_vector_registers"] =
5278 // DK_CFI_LLVM_VECTOR_REGISTERS;
5279 // DirectiveKindMap[".cfi_llvm_vector_offset"] = DK_CFI_LLVM_VECTOR_OFFSET;
5280 // DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
5281 // DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
5282 // DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;
5283 // DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;
5284 // DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;
5285 // DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;
5286 // DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;
5287 // DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;
5288 // DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;
5289 // DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
5290 // DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
5291 // DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
5292 // DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
5293 // DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;
5294 DirectiveKindMap["macro"] = DK_MACRO;
5295 DirectiveKindMap["exitm"] = DK_EXITM;
5296 DirectiveKindMap["endm"] = DK_ENDM;
5297 DirectiveKindMap["purge"] = DK_PURGE;
5298 DirectiveKindMap[".err"] = DK_ERR;
5299 DirectiveKindMap[".errb"] = DK_ERRB;
5300 DirectiveKindMap[".errnb"] = DK_ERRNB;
5301 DirectiveKindMap[".errdef"] = DK_ERRDEF;
5302 DirectiveKindMap[".errndef"] = DK_ERRNDEF;
5303 DirectiveKindMap[".errdif"] = DK_ERRDIF;
5304 DirectiveKindMap[".errdifi"] = DK_ERRDIFI;
5305 DirectiveKindMap[".erridn"] = DK_ERRIDN;
5306 DirectiveKindMap[".erridni"] = DK_ERRIDNI;
5307 DirectiveKindMap[".erre"] = DK_ERRE;
5308 DirectiveKindMap[".errnz"] = DK_ERRNZ;
5309 DirectiveKindMap[".pushframe"] = DK_PUSHFRAME;
5310 DirectiveKindMap[".pushreg"] = DK_PUSHREG;
5311 DirectiveKindMap[".push2reg"] = DK_PUSH2REGS;
5312 DirectiveKindMap[".pop2reg"] = DK_PUSH2REGS;
5313 DirectiveKindMap[".popreg"] = DK_PUSHREG;
5314 DirectiveKindMap[".savereg"] = DK_SAVEREG;
5315 DirectiveKindMap[".restorereg"] = DK_SAVEREG;
5316 DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;
5317 DirectiveKindMap[".restorexmm128"] = DK_SAVEXMM128;
5318 DirectiveKindMap[".setframe"] = DK_SETFRAME;
5319 DirectiveKindMap[".unsetframe"] = DK_SETFRAME;
5320 DirectiveKindMap[".radix"] = DK_RADIX;
5321 DirectiveKindMap["db"] = DK_DB;
5322 DirectiveKindMap["dd"] = DK_DD;
5323 DirectiveKindMap["df"] = DK_DF;
5324 DirectiveKindMap["dq"] = DK_DQ;
5325 DirectiveKindMap["dw"] = DK_DW;
5326 DirectiveKindMap["echo"] = DK_ECHO;
5327 DirectiveKindMap["struc"] = DK_STRUCT;
5328 DirectiveKindMap["struct"] = DK_STRUCT;
5329 DirectiveKindMap["union"] = DK_UNION;
5330 DirectiveKindMap["ends"] = DK_ENDS;
5331}
5332
5333bool MasmParser::isMacroLikeDirective() {
5334 if (getLexer().is(K: AsmToken::Identifier)) {
5335 bool IsMacroLike = StringSwitch<bool>(getTok().getIdentifier())
5336 .CasesLower(CaseStrings: {"repeat", "rept"}, Value: true)
5337 .CaseLower(S: "while", Value: true)
5338 .CasesLower(CaseStrings: {"for", "irp"}, Value: true)
5339 .CasesLower(CaseStrings: {"forc", "irpc"}, Value: true)
5340 .Default(Value: false);
5341 if (IsMacroLike)
5342 return true;
5343 }
5344 if (peekTok().is(K: AsmToken::Identifier) &&
5345 peekTok().getIdentifier().equals_insensitive(RHS: "macro"))
5346 return true;
5347
5348 return false;
5349}
5350
5351MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {
5352 AsmToken EndToken, StartToken = getTok();
5353
5354 unsigned NestLevel = 0;
5355 while (true) {
5356 // Check whether we have reached the end of the file.
5357 if (getLexer().is(K: AsmToken::Eof)) {
5358 printError(L: DirectiveLoc, Msg: "no matching 'endm' in definition");
5359 return nullptr;
5360 }
5361
5362 if (isMacroLikeDirective())
5363 ++NestLevel;
5364
5365 // Otherwise, check whether we have reached the endm.
5366 if (Lexer.is(K: AsmToken::Identifier) &&
5367 getTok().getIdentifier().equals_insensitive(RHS: "endm")) {
5368 if (NestLevel == 0) {
5369 EndToken = getTok();
5370 Lex();
5371 if (Lexer.isNot(K: AsmToken::EndOfStatement)) {
5372 printError(L: getTok().getLoc(), Msg: "unexpected token in 'endm' directive");
5373 return nullptr;
5374 }
5375 break;
5376 }
5377 --NestLevel;
5378 }
5379
5380 // Otherwise, scan till the end of the statement.
5381 eatToEndOfStatement();
5382 }
5383
5384 const char *BodyStart = StartToken.getLoc().getPointer();
5385 const char *BodyEnd = EndToken.getLoc().getPointer();
5386 StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
5387
5388 // We Are Anonymous.
5389 MacroLikeBodies.emplace_back(args: StringRef(), args&: Body, args: MCAsmMacroParameters());
5390 return &MacroLikeBodies.back();
5391}
5392
5393bool MasmParser::expandStatement(SMLoc Loc) {
5394 std::string Body = parseStringTo(EndTok: AsmToken::EndOfStatement);
5395 SMLoc EndLoc = getTok().getLoc();
5396
5397 MCAsmMacroParameters Parameters;
5398 MCAsmMacroArguments Arguments;
5399
5400 StringMap<std::string> BuiltinValues;
5401 for (const auto &S : BuiltinSymbolMap) {
5402 const BuiltinSymbol &Sym = S.getValue();
5403 if (std::optional<std::string> Text = evaluateBuiltinTextMacro(Symbol: Sym, StartLoc: Loc)) {
5404 BuiltinValues[S.getKey().lower()] = std::move(*Text);
5405 }
5406 }
5407 for (const auto &B : BuiltinValues) {
5408 MCAsmMacroParameter P;
5409 MCAsmMacroArgument A;
5410 P.Name = B.getKey();
5411 P.Required = true;
5412 A.push_back(x: AsmToken(AsmToken::String, B.getValue()));
5413
5414 Parameters.push_back(x: std::move(P));
5415 Arguments.push_back(x: std::move(A));
5416 }
5417
5418 for (const auto &V : Variables) {
5419 const Variable &Var = V.getValue();
5420 if (Var.IsText) {
5421 MCAsmMacroParameter P;
5422 MCAsmMacroArgument A;
5423 P.Name = Var.Name;
5424 P.Required = true;
5425 A.push_back(x: AsmToken(AsmToken::String, Var.TextValue));
5426
5427 Parameters.push_back(x: std::move(P));
5428 Arguments.push_back(x: std::move(A));
5429 }
5430 }
5431 MacroLikeBodies.emplace_back(args: StringRef(), args&: Body, args&: Parameters);
5432 MCAsmMacro M = MacroLikeBodies.back();
5433
5434 // Expand the statement in a new buffer.
5435 SmallString<80> Buf;
5436 raw_svector_ostream OS(Buf);
5437 if (expandMacro(OS, Body: M.Body, Parameters: M.Parameters, A: Arguments, Locals: M.Locals, L: EndLoc))
5438 return true;
5439 std::unique_ptr<MemoryBuffer> Expansion =
5440 MemoryBuffer::getMemBufferCopy(InputData: OS.str(), BufferName: "<expansion>");
5441
5442 // Jump to the expanded statement and prime the lexer.
5443 CurBuffer = SrcMgr.AddNewSourceBuffer(F: std::move(Expansion), IncludeLoc: EndLoc);
5444 Lexer.setBuffer(Buf: SrcMgr.getMemoryBuffer(i: CurBuffer)->getBuffer());
5445 EndStatementAtEOFStack.push_back(Val: false);
5446 Lex();
5447 return false;
5448}
5449
5450void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
5451 raw_svector_ostream &OS) {
5452 instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/getTok().getLoc(), OS);
5453}
5454void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
5455 SMLoc ExitLoc,
5456 raw_svector_ostream &OS) {
5457 OS << "endm\n";
5458
5459 std::unique_ptr<MemoryBuffer> Instantiation =
5460 MemoryBuffer::getMemBufferCopy(InputData: OS.str(), BufferName: "<instantiation>");
5461
5462 // Create the macro instantiation object and add to the current macro
5463 // instantiation stack.
5464 MacroInstantiation *MI = new MacroInstantiation{.InstantiationLoc: DirectiveLoc, .ExitBuffer: CurBuffer,
5465 .ExitLoc: ExitLoc, .CondStackDepth: TheCondStack.size()};
5466 ActiveMacros.push_back(x: MI);
5467
5468 // Jump to the macro instantiation and prime the lexer.
5469 CurBuffer = SrcMgr.AddNewSourceBuffer(F: std::move(Instantiation), IncludeLoc: SMLoc());
5470 Lexer.setBuffer(Buf: SrcMgr.getMemoryBuffer(i: CurBuffer)->getBuffer());
5471 EndStatementAtEOFStack.push_back(Val: true);
5472 Lex();
5473}
5474
5475/// parseDirectiveRepeat
5476/// ::= ("repeat" | "rept") count
5477/// body
5478/// endm
5479bool MasmParser::parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Dir) {
5480 const MCExpr *CountExpr;
5481 SMLoc CountLoc = getTok().getLoc();
5482 if (parseExpression(Res&: CountExpr))
5483 return true;
5484
5485 int64_t Count;
5486 if (!CountExpr->evaluateAsAbsolute(Res&: Count, Asm: getStreamer().getAssemblerPtr())) {
5487 return Error(L: CountLoc, Msg: "unexpected token in '" + Dir + "' directive");
5488 }
5489
5490 if (check(P: Count < 0, Loc: CountLoc, Msg: "Count is negative") || parseEOL())
5491 return true;
5492
5493 // Lex the repeat definition.
5494 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
5495 if (!M)
5496 return true;
5497
5498 // Macro instantiation is lexical, unfortunately. We construct a new buffer
5499 // to hold the macro body with substitutions.
5500 SmallString<256> Buf;
5501 raw_svector_ostream OS(Buf);
5502 while (Count--) {
5503 if (expandMacro(OS, Body: M->Body, Parameters: {}, A: {}, Locals: M->Locals, L: getTok().getLoc()))
5504 return true;
5505 }
5506 instantiateMacroLikeBody(M, DirectiveLoc, OS);
5507
5508 return false;
5509}
5510
5511/// parseDirectiveWhile
5512/// ::= "while" expression
5513/// body
5514/// endm
5515bool MasmParser::parseDirectiveWhile(SMLoc DirectiveLoc) {
5516 const MCExpr *CondExpr;
5517 SMLoc CondLoc = getTok().getLoc();
5518 if (parseExpression(Res&: CondExpr))
5519 return true;
5520
5521 // Lex the repeat definition.
5522 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
5523 if (!M)
5524 return true;
5525
5526 // Macro instantiation is lexical, unfortunately. We construct a new buffer
5527 // to hold the macro body with substitutions.
5528 SmallString<256> Buf;
5529 raw_svector_ostream OS(Buf);
5530 int64_t Condition;
5531 if (!CondExpr->evaluateAsAbsolute(Res&: Condition, Asm: getStreamer().getAssemblerPtr()))
5532 return Error(L: CondLoc, Msg: "expected absolute expression in 'while' directive");
5533 if (Condition) {
5534 // Instantiate the macro, then resume at this directive to recheck the
5535 // condition.
5536 if (expandMacro(OS, Body: M->Body, Parameters: {}, A: {}, Locals: M->Locals, L: getTok().getLoc()))
5537 return true;
5538 instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/DirectiveLoc, OS);
5539 }
5540
5541 return false;
5542}
5543
5544/// parseDirectiveFor
5545/// ::= ("for" | "irp") symbol [":" qualifier], <values>
5546/// body
5547/// endm
5548bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) {
5549 MCAsmMacroParameter Parameter;
5550 MCAsmMacroArguments A;
5551 if (check(P: parseIdentifier(Res&: Parameter.Name),
5552 Msg: "expected identifier in '" + Dir + "' directive"))
5553 return true;
5554
5555 // Parse optional qualifier (default value, or "req")
5556 if (parseOptionalToken(T: AsmToken::Colon)) {
5557 if (parseOptionalToken(T: AsmToken::Equal)) {
5558 // Default value
5559 SMLoc ParamLoc;
5560
5561 ParamLoc = Lexer.getLoc();
5562 if (parseMacroArgument(MP: nullptr, MA&: Parameter.Value))
5563 return true;
5564 } else {
5565 SMLoc QualLoc;
5566 StringRef Qualifier;
5567
5568 QualLoc = Lexer.getLoc();
5569 if (parseIdentifier(Res&: Qualifier))
5570 return Error(L: QualLoc, Msg: "missing parameter qualifier for "
5571 "'" +
5572 Parameter.Name + "' in '" + Dir +
5573 "' directive");
5574
5575 if (Qualifier.equals_insensitive(RHS: "req"))
5576 Parameter.Required = true;
5577 else
5578 return Error(L: QualLoc,
5579 Msg: Qualifier + " is not a valid parameter qualifier for '" +
5580 Parameter.Name + "' in '" + Dir + "' directive");
5581 }
5582 }
5583
5584 if (parseToken(T: AsmToken::Comma,
5585 Msg: "expected comma in '" + Dir + "' directive") ||
5586 parseToken(T: AsmToken::Less,
5587 Msg: "values in '" + Dir +
5588 "' directive must be enclosed in angle brackets"))
5589 return true;
5590
5591 while (true) {
5592 A.emplace_back();
5593 if (parseMacroArgument(MP: &Parameter, MA&: A.back(), /*EndTok=*/AsmToken::Greater))
5594 return addErrorSuffix(Suffix: " in arguments for '" + Dir + "' directive");
5595
5596 // If we see a comma, continue, and allow line continuation.
5597 if (!parseOptionalToken(T: AsmToken::Comma))
5598 break;
5599 parseOptionalToken(T: AsmToken::EndOfStatement);
5600 }
5601
5602 if (parseToken(T: AsmToken::Greater,
5603 Msg: "values in '" + Dir +
5604 "' directive must be enclosed in angle brackets") ||
5605 parseEOL())
5606 return true;
5607
5608 // Lex the for definition.
5609 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
5610 if (!M)
5611 return true;
5612
5613 // Macro instantiation is lexical, unfortunately. We construct a new buffer
5614 // to hold the macro body with substitutions.
5615 SmallString<256> Buf;
5616 raw_svector_ostream OS(Buf);
5617
5618 for (const MCAsmMacroArgument &Arg : A) {
5619 if (expandMacro(OS, Body: M->Body, Parameters: Parameter, A: Arg, Locals: M->Locals, L: getTok().getLoc()))
5620 return true;
5621 }
5622
5623 instantiateMacroLikeBody(M, DirectiveLoc, OS);
5624
5625 return false;
5626}
5627
5628/// parseDirectiveForc
5629/// ::= ("forc" | "irpc") symbol, <string>
5630/// body
5631/// endm
5632bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) {
5633 MCAsmMacroParameter Parameter;
5634
5635 std::string Argument;
5636 if (check(P: parseIdentifier(Res&: Parameter.Name),
5637 Msg: "expected identifier in '" + Directive + "' directive") ||
5638 parseToken(T: AsmToken::Comma,
5639 Msg: "expected comma in '" + Directive + "' directive"))
5640 return true;
5641 if (parseAngleBracketString(Data&: Argument)) {
5642 // Match ml64.exe; treat all characters to end of statement as a string,
5643 // ignoring comment markers, then discard anything following a space (using
5644 // the C locale).
5645 Argument = parseStringTo(EndTok: AsmToken::EndOfStatement);
5646 if (getTok().is(K: AsmToken::EndOfStatement))
5647 Argument += getTok().getString();
5648 size_t End = 0;
5649 for (; End < Argument.size(); ++End) {
5650 if (isSpace(C: Argument[End]))
5651 break;
5652 }
5653 Argument.resize(n: End);
5654 }
5655 if (parseEOL())
5656 return true;
5657
5658 // Lex the irpc definition.
5659 MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
5660 if (!M)
5661 return true;
5662
5663 // Macro instantiation is lexical, unfortunately. We construct a new buffer
5664 // to hold the macro body with substitutions.
5665 SmallString<256> Buf;
5666 raw_svector_ostream OS(Buf);
5667
5668 StringRef Values(Argument);
5669 for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
5670 MCAsmMacroArgument Arg;
5671 Arg.emplace_back(args: AsmToken::Identifier, args: Values.substr(Start: I, N: 1));
5672
5673 if (expandMacro(OS, Body: M->Body, Parameters: Parameter, A: Arg, Locals: M->Locals, L: getTok().getLoc()))
5674 return true;
5675 }
5676
5677 instantiateMacroLikeBody(M, DirectiveLoc, OS);
5678
5679 return false;
5680}
5681
5682bool MasmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,
5683 size_t Len) {
5684 const MCExpr *Value;
5685 SMLoc ExprLoc = getLexer().getLoc();
5686 if (parseExpression(Res&: Value))
5687 return true;
5688 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value);
5689 if (!MCE)
5690 return Error(L: ExprLoc, Msg: "unexpected expression in _emit");
5691 uint64_t IntValue = MCE->getValue();
5692 if (!isUInt<8>(x: IntValue) && !isInt<8>(x: IntValue))
5693 return Error(L: ExprLoc, Msg: "literal value out of range for directive");
5694
5695 Info.AsmRewrites->emplace_back(Args: AOK_Emit, Args&: IDLoc, Args&: Len);
5696 return false;
5697}
5698
5699bool MasmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {
5700 const MCExpr *Value;
5701 SMLoc ExprLoc = getLexer().getLoc();
5702 if (parseExpression(Res&: Value))
5703 return true;
5704 const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Val: Value);
5705 if (!MCE)
5706 return Error(L: ExprLoc, Msg: "unexpected expression in align");
5707 uint64_t IntValue = MCE->getValue();
5708 if (!isPowerOf2_64(Value: IntValue))
5709 return Error(L: ExprLoc, Msg: "literal value not a power of two greater then zero");
5710
5711 Info.AsmRewrites->emplace_back(Args: AOK_Align, Args&: IDLoc, Args: 5, Args: Log2_64(Value: IntValue));
5712 return false;
5713}
5714
5715bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) {
5716 const SMLoc Loc = getLexer().getLoc();
5717 std::string RadixStringRaw = parseStringTo(EndTok: AsmToken::EndOfStatement);
5718 StringRef RadixString = StringRef(RadixStringRaw).trim();
5719 unsigned Radix;
5720 if (RadixString.getAsInteger(Radix: 10, Result&: Radix)) {
5721 return Error(L: Loc,
5722 Msg: "radix must be a decimal number in the range 2 to 16; was " +
5723 RadixString);
5724 }
5725 if (Radix < 2 || Radix > 16)
5726 return Error(L: Loc, Msg: "radix must be in the range 2 to 16; was " +
5727 std::to_string(val: Radix));
5728 getLexer().setMasmDefaultRadix(Radix);
5729 return false;
5730}
5731
5732/// parseDirectiveEcho
5733/// ::= "echo" message
5734bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) {
5735 std::string Message = parseStringTo(EndTok: AsmToken::EndOfStatement);
5736 llvm::outs() << Message;
5737 if (!StringRef(Message).ends_with(Suffix: "\n"))
5738 llvm::outs() << '\n';
5739 return false;
5740}
5741
5742// We are comparing pointers, but the pointers are relative to a single string.
5743// Thus, this should always be deterministic.
5744static int rewritesSort(const AsmRewrite *AsmRewriteA,
5745 const AsmRewrite *AsmRewriteB) {
5746 if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())
5747 return -1;
5748 if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())
5749 return 1;
5750
5751 // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output
5752 // rewrite to the same location. Make sure the SizeDirective rewrite is
5753 // performed first, then the Imm/ImmPrefix and finally the Input/Output. This
5754 // ensures the sort algorithm is stable.
5755 if (AsmRewritePrecedence[AsmRewriteA->Kind] >
5756 AsmRewritePrecedence[AsmRewriteB->Kind])
5757 return -1;
5758
5759 if (AsmRewritePrecedence[AsmRewriteA->Kind] <
5760 AsmRewritePrecedence[AsmRewriteB->Kind])
5761 return 1;
5762 llvm_unreachable("Unstable rewrite sort.");
5763}
5764
5765bool MasmParser::defineMacro(StringRef Name, StringRef Value) {
5766 Variable &Var = Variables[Name.lower()];
5767 if (Var.Name.empty()) {
5768 Var.Name = Name;
5769 } else if (Var.Redefinable == Variable::NOT_REDEFINABLE) {
5770 return Error(L: SMLoc(), Msg: "invalid variable redefinition");
5771 } else if (Var.Redefinable == Variable::WARN_ON_REDEFINITION &&
5772 Warning(L: SMLoc(), Msg: "redefining '" + Name +
5773 "', already defined on the command line")) {
5774 return true;
5775 }
5776 Var.Redefinable = Variable::WARN_ON_REDEFINITION;
5777 Var.IsText = true;
5778 Var.TextValue = Value.str();
5779 return false;
5780}
5781
5782bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const {
5783 const std::pair<StringRef, StringRef> BaseMember = Name.split(Separator: '.');
5784 const StringRef Base = BaseMember.first, Member = BaseMember.second;
5785 return lookUpField(Base, Member, Info);
5786}
5787
5788bool MasmParser::lookUpField(StringRef Base, StringRef Member,
5789 AsmFieldInfo &Info) const {
5790 if (Base.empty())
5791 return true;
5792
5793 AsmFieldInfo BaseInfo;
5794 if (Base.contains(C: '.') && !lookUpField(Name: Base, Info&: BaseInfo))
5795 Base = BaseInfo.Type.Name;
5796
5797 auto StructIt = Structs.find(Key: Base.lower());
5798 auto TypeIt = KnownType.find(Key: Base.lower());
5799 if (TypeIt != KnownType.end()) {
5800 StructIt = Structs.find(Key: TypeIt->second.Name.lower());
5801 }
5802 if (StructIt != Structs.end())
5803 return lookUpField(Structure: StructIt->second, Member, Info);
5804
5805 return true;
5806}
5807
5808bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member,
5809 AsmFieldInfo &Info) const {
5810 if (Member.empty()) {
5811 Info.Type.Name = Structure.Name;
5812 Info.Type.Size = Structure.Size;
5813 Info.Type.ElementSize = Structure.Size;
5814 Info.Type.Length = 1;
5815 return false;
5816 }
5817
5818 std::pair<StringRef, StringRef> Split = Member.split(Separator: '.');
5819 const StringRef FieldName = Split.first, FieldMember = Split.second;
5820
5821 auto StructIt = Structs.find(Key: FieldName.lower());
5822 if (StructIt != Structs.end())
5823 return lookUpField(Structure: StructIt->second, Member: FieldMember, Info);
5824
5825 auto FieldIt = Structure.FieldsByName.find(Key: FieldName.lower());
5826 if (FieldIt == Structure.FieldsByName.end())
5827 return true;
5828
5829 const FieldInfo &Field = Structure.Fields[FieldIt->second];
5830 if (FieldMember.empty()) {
5831 Info.Offset += Field.Offset;
5832 Info.Type.Size = Field.SizeOf;
5833 Info.Type.ElementSize = Field.Type;
5834 Info.Type.Length = Field.LengthOf;
5835 if (Field.Contents.FT == FT_STRUCT)
5836 Info.Type.Name = Field.Contents.StructInfo.Structure.Name;
5837 else
5838 Info.Type.Name = "";
5839 return false;
5840 }
5841
5842 if (Field.Contents.FT != FT_STRUCT)
5843 return true;
5844 const StructFieldInfo &StructInfo = Field.Contents.StructInfo;
5845
5846 if (lookUpField(Structure: StructInfo.Structure, Member: FieldMember, Info))
5847 return true;
5848
5849 Info.Offset += Field.Offset;
5850 return false;
5851}
5852
5853bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const {
5854 unsigned Size = StringSwitch<unsigned>(Name)
5855 .CasesLower(CaseStrings: {"byte", "db", "sbyte"}, Value: 1)
5856 .CasesLower(CaseStrings: {"word", "dw", "sword"}, Value: 2)
5857 .CasesLower(CaseStrings: {"dword", "dd", "sdword"}, Value: 4)
5858 .CasesLower(CaseStrings: {"fword", "df"}, Value: 6)
5859 .CasesLower(CaseStrings: {"qword", "dq", "sqword"}, Value: 8)
5860 .CaseLower(S: "real4", Value: 4)
5861 .CaseLower(S: "real8", Value: 8)
5862 .CaseLower(S: "real10", Value: 10)
5863 .Default(Value: 0);
5864 if (Size) {
5865 Info.Name = Name;
5866 Info.ElementSize = Size;
5867 Info.Length = 1;
5868 Info.Size = Size;
5869 return false;
5870 }
5871
5872 auto StructIt = Structs.find(Key: Name.lower());
5873 if (StructIt != Structs.end()) {
5874 const StructInfo &Structure = StructIt->second;
5875 Info.Name = Name;
5876 Info.ElementSize = Structure.Size;
5877 Info.Length = 1;
5878 Info.Size = Structure.Size;
5879 return false;
5880 }
5881
5882 return true;
5883}
5884
5885bool MasmParser::parseMSInlineAsm(
5886 std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs,
5887 SmallVectorImpl<std::pair<void *, bool>> &OpDecls,
5888 SmallVectorImpl<std::string> &Constraints,
5889 SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,
5890 MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {
5891 SmallVector<void *, 4> InputDecls;
5892 SmallVector<void *, 4> OutputDecls;
5893 SmallVector<bool, 4> InputDeclsAddressOf;
5894 SmallVector<bool, 4> OutputDeclsAddressOf;
5895 SmallVector<std::string, 4> InputConstraints;
5896 SmallVector<std::string, 4> OutputConstraints;
5897 SmallVector<MCRegister, 4> ClobberRegs;
5898
5899 SmallVector<AsmRewrite, 4> AsmStrRewrites;
5900
5901 // Prime the lexer.
5902 Lex();
5903
5904 // While we have input, parse each statement.
5905 unsigned InputIdx = 0;
5906 unsigned OutputIdx = 0;
5907 while (getLexer().isNot(K: AsmToken::Eof)) {
5908 // Parse curly braces marking block start/end.
5909 if (parseCurlyBlockScope(AsmStrRewrites))
5910 continue;
5911
5912 ParseStatementInfo Info(&AsmStrRewrites);
5913 bool StatementErr = parseStatement(Info, SI: &SI);
5914
5915 if (StatementErr || Info.ParseError) {
5916 // Emit pending errors if any exist.
5917 printPendingErrors();
5918 return true;
5919 }
5920
5921 // No pending error should exist here.
5922 assert(!hasPendingError() && "unexpected error from parseStatement");
5923
5924 if (Info.Opcode == ~0U)
5925 continue;
5926
5927 const MCInstrDesc &Desc = MII->get(Opcode: Info.Opcode);
5928
5929 // Build the list of clobbers, outputs and inputs.
5930 for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {
5931 MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];
5932
5933 // Register operand.
5934 if (Operand.isReg() && !Operand.needAddressOf() &&
5935 !getTargetParser().omitRegisterFromClobberLists(Reg: Operand.getReg())) {
5936 unsigned NumDefs = Desc.getNumDefs();
5937 // Clobber.
5938 if (NumDefs && Operand.getMCOperandNum() < NumDefs)
5939 ClobberRegs.push_back(Elt: Operand.getReg());
5940 continue;
5941 }
5942
5943 // Expr/Input or Output.
5944 StringRef SymName = Operand.getSymName();
5945 if (SymName.empty())
5946 continue;
5947
5948 void *OpDecl = Operand.getOpDecl();
5949 if (!OpDecl)
5950 continue;
5951
5952 StringRef Constraint = Operand.getConstraint();
5953 if (Operand.isImm()) {
5954 // Offset as immediate.
5955 if (Operand.isOffsetOfLocal())
5956 Constraint = "r";
5957 else
5958 Constraint = "i";
5959 }
5960
5961 bool isOutput = (i == 1) && Desc.mayStore();
5962 SMLoc Start = SMLoc::getFromPointer(Ptr: SymName.data());
5963 if (isOutput) {
5964 ++InputIdx;
5965 OutputDecls.push_back(Elt: OpDecl);
5966 OutputDeclsAddressOf.push_back(Elt: Operand.needAddressOf());
5967 OutputConstraints.push_back(Elt: ("=" + Constraint).str());
5968 AsmStrRewrites.emplace_back(Args: AOK_Output, Args&: Start, Args: SymName.size());
5969 } else {
5970 InputDecls.push_back(Elt: OpDecl);
5971 InputDeclsAddressOf.push_back(Elt: Operand.needAddressOf());
5972 InputConstraints.push_back(Elt: Constraint.str());
5973 if (Desc.operands()[i - 1].isBranchTarget())
5974 AsmStrRewrites.emplace_back(Args: AOK_CallInput, Args&: Start, Args: SymName.size());
5975 else
5976 AsmStrRewrites.emplace_back(Args: AOK_Input, Args&: Start, Args: SymName.size());
5977 }
5978 }
5979
5980 // Consider implicit defs to be clobbers. Think of cpuid and push.
5981 llvm::append_range(C&: ClobberRegs, R: Desc.implicit_defs());
5982 }
5983
5984 // Set the number of Outputs and Inputs.
5985 NumOutputs = OutputDecls.size();
5986 NumInputs = InputDecls.size();
5987
5988 // Set the unique clobbers.
5989 array_pod_sort(Start: ClobberRegs.begin(), End: ClobberRegs.end());
5990 ClobberRegs.erase(CS: llvm::unique(R&: ClobberRegs), CE: ClobberRegs.end());
5991 Clobbers.assign(NumElts: ClobberRegs.size(), Elt: std::string());
5992 for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {
5993 raw_string_ostream OS(Clobbers[I]);
5994 IP->printRegName(OS, Reg: ClobberRegs[I]);
5995 }
5996
5997 // Merge the various outputs and inputs. Output are expected first.
5998 if (NumOutputs || NumInputs) {
5999 unsigned NumExprs = NumOutputs + NumInputs;
6000 OpDecls.resize(N: NumExprs);
6001 Constraints.resize(N: NumExprs);
6002 for (unsigned i = 0; i < NumOutputs; ++i) {
6003 OpDecls[i] = std::make_pair(x&: OutputDecls[i], y&: OutputDeclsAddressOf[i]);
6004 Constraints[i] = OutputConstraints[i];
6005 }
6006 for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
6007 OpDecls[j] = std::make_pair(x&: InputDecls[i], y&: InputDeclsAddressOf[i]);
6008 Constraints[j] = InputConstraints[i];
6009 }
6010 }
6011
6012 // Build the IR assembly string.
6013 std::string AsmStringIR;
6014 raw_string_ostream OS(AsmStringIR);
6015 StringRef ASMString =
6016 SrcMgr.getMemoryBuffer(i: SrcMgr.getMainFileID())->getBuffer();
6017 const char *AsmStart = ASMString.begin();
6018 const char *AsmEnd = ASMString.end();
6019 array_pod_sort(Start: AsmStrRewrites.begin(), End: AsmStrRewrites.end(), Compare: rewritesSort);
6020 for (auto I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) {
6021 const AsmRewrite &AR = *I;
6022 // Check if this has already been covered by another rewrite...
6023 if (AR.Done)
6024 continue;
6025 AsmRewriteKind Kind = AR.Kind;
6026
6027 const char *Loc = AR.Loc.getPointer();
6028 assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");
6029
6030 // Emit everything up to the immediate/expression.
6031 if (unsigned Len = Loc - AsmStart)
6032 OS << StringRef(AsmStart, Len);
6033
6034 // Skip the original expression.
6035 if (Kind == AOK_Skip) {
6036 AsmStart = Loc + AR.Len;
6037 continue;
6038 }
6039
6040 unsigned AdditionalSkip = 0;
6041 // Rewrite expressions in $N notation.
6042 switch (Kind) {
6043 default:
6044 break;
6045 case AOK_IntelExpr:
6046 assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");
6047 if (AR.IntelExp.NeedBracs)
6048 OS << "[";
6049 if (AR.IntelExp.hasBaseReg())
6050 OS << AR.IntelExp.BaseReg;
6051 if (AR.IntelExp.hasIndexReg())
6052 OS << (AR.IntelExp.hasBaseReg() ? " + " : "")
6053 << AR.IntelExp.IndexReg;
6054 if (AR.IntelExp.Scale > 1)
6055 OS << " * $$" << AR.IntelExp.Scale;
6056 if (AR.IntelExp.hasOffset()) {
6057 if (AR.IntelExp.hasRegs())
6058 OS << " + ";
6059 // Fuse this rewrite with a rewrite of the offset name, if present.
6060 StringRef OffsetName = AR.IntelExp.OffsetName;
6061 SMLoc OffsetLoc = SMLoc::getFromPointer(Ptr: AR.IntelExp.OffsetName.data());
6062 size_t OffsetLen = OffsetName.size();
6063 auto rewrite_it = std::find_if(
6064 first: I, last: AsmStrRewrites.end(), pred: [&](const AsmRewrite &FusingAR) {
6065 return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&
6066 (FusingAR.Kind == AOK_Input ||
6067 FusingAR.Kind == AOK_CallInput);
6068 });
6069 if (rewrite_it == AsmStrRewrites.end()) {
6070 OS << "offset " << OffsetName;
6071 } else if (rewrite_it->Kind == AOK_CallInput) {
6072 OS << "${" << InputIdx++ << ":P}";
6073 rewrite_it->Done = true;
6074 } else {
6075 OS << '$' << InputIdx++;
6076 rewrite_it->Done = true;
6077 }
6078 }
6079 if (AR.IntelExp.Imm || AR.IntelExp.emitImm())
6080 OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;
6081 if (AR.IntelExp.NeedBracs)
6082 OS << "]";
6083 break;
6084 case AOK_Label:
6085 OS << Ctx.getAsmInfo().getInternalSymbolPrefix() << AR.Label;
6086 break;
6087 case AOK_Input:
6088 OS << '$' << InputIdx++;
6089 break;
6090 case AOK_CallInput:
6091 OS << "${" << InputIdx++ << ":P}";
6092 break;
6093 case AOK_Output:
6094 OS << '$' << OutputIdx++;
6095 break;
6096 case AOK_SizeDirective:
6097 switch (AR.Val) {
6098 default: break;
6099 case 8: OS << "byte ptr "; break;
6100 case 16: OS << "word ptr "; break;
6101 case 32: OS << "dword ptr "; break;
6102 case 64: OS << "qword ptr "; break;
6103 case 80: OS << "xword ptr "; break;
6104 case 128: OS << "xmmword ptr "; break;
6105 case 256: OS << "ymmword ptr "; break;
6106 }
6107 break;
6108 case AOK_Emit:
6109 OS << ".byte";
6110 break;
6111 case AOK_Align: {
6112 // MS alignment directives are measured in bytes. If the native assembler
6113 // measures alignment in bytes, we can pass it straight through.
6114 OS << ".align";
6115 if (getContext().getAsmInfo().getAlignmentIsInBytes())
6116 break;
6117
6118 // Alignment is in log2 form, so print that instead and skip the original
6119 // immediate.
6120 unsigned Val = AR.Val;
6121 OS << ' ' << Val;
6122 assert(Val < 10 && "Expected alignment less then 2^10.");
6123 AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;
6124 break;
6125 }
6126 case AOK_EVEN:
6127 OS << ".even";
6128 break;
6129 case AOK_EndOfStatement:
6130 OS << "\n\t";
6131 break;
6132 }
6133
6134 // Skip the original expression.
6135 AsmStart = Loc + AR.Len + AdditionalSkip;
6136 }
6137
6138 // Emit the remainder of the asm string.
6139 if (AsmStart != AsmEnd)
6140 OS << StringRef(AsmStart, AsmEnd - AsmStart);
6141
6142 AsmString = OS.str();
6143 return false;
6144}
6145
6146void MasmParser::initializeBuiltinSymbolMaps() {
6147 // Numeric built-ins (supported in all versions)
6148 BuiltinSymbolMap["@version"] = BI_VERSION;
6149 BuiltinSymbolMap["@line"] = BI_LINE;
6150 BuiltinSymbolMap["@unwindversion"] = BI_UNWINDVERSION;
6151
6152 // Text built-ins (supported in all versions)
6153 BuiltinSymbolMap["@date"] = BI_DATE;
6154 BuiltinSymbolMap["@time"] = BI_TIME;
6155 BuiltinSymbolMap["@filecur"] = BI_FILECUR;
6156 BuiltinSymbolMap["@filename"] = BI_FILENAME;
6157 BuiltinSymbolMap["@curseg"] = BI_CURSEG;
6158
6159 // Function built-ins (supported in all versions)
6160 BuiltinFunctionMap["@catstr"] = BI_CATSTR;
6161
6162 // Some built-ins exist only for MASM32 (32-bit x86)
6163 if (getContext().getSubtargetInfo()->getTargetTriple().getArch() ==
6164 Triple::x86) {
6165 // Numeric built-ins
6166 // BuiltinSymbolMap["@cpu"] = BI_CPU;
6167 // BuiltinSymbolMap["@interface"] = BI_INTERFACE;
6168 // BuiltinSymbolMap["@wordsize"] = BI_WORDSIZE;
6169 // BuiltinSymbolMap["@codesize"] = BI_CODESIZE;
6170 // BuiltinSymbolMap["@datasize"] = BI_DATASIZE;
6171 // BuiltinSymbolMap["@model"] = BI_MODEL;
6172
6173 // Text built-ins
6174 // BuiltinSymbolMap["@code"] = BI_CODE;
6175 // BuiltinSymbolMap["@data"] = BI_DATA;
6176 // BuiltinSymbolMap["@fardata?"] = BI_FARDATA;
6177 // BuiltinSymbolMap["@stack"] = BI_STACK;
6178 }
6179}
6180
6181const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,
6182 SMLoc StartLoc) {
6183 switch (Symbol) {
6184 default:
6185 return nullptr;
6186 case BI_VERSION:
6187 // Match a recent version of ML.EXE.
6188 return MCConstantExpr::create(Value: 1427, Ctx&: getContext());
6189 case BI_LINE: {
6190 int64_t Line;
6191 if (ActiveMacros.empty())
6192 Line = SrcMgr.FindLineNumber(Loc: StartLoc, BufferID: CurBuffer);
6193 else
6194 Line = SrcMgr.FindLineNumber(Loc: ActiveMacros.front()->InstantiationLoc,
6195 BufferID: ActiveMacros.front()->ExitBuffer);
6196 return MCConstantExpr::create(Value: Line, Ctx&: getContext());
6197 }
6198 case BI_UNWINDVERSION:
6199 return MCConstantExpr::create(Value: getStreamer().getDefaultWinCFIUnwindVersion(),
6200 Ctx&: getContext());
6201 }
6202 llvm_unreachable("unhandled built-in symbol");
6203}
6204
6205std::optional<std::string>
6206MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {
6207 switch (Symbol) {
6208 default:
6209 return {};
6210 case BI_DATE: {
6211 // Current local date, formatted MM/DD/YY
6212 char TmpBuffer[sizeof("mm/dd/yy")];
6213 const size_t Len = strftime(s: TmpBuffer, maxsize: sizeof(TmpBuffer), format: "%D", tp: &TM);
6214 return std::string(TmpBuffer, Len);
6215 }
6216 case BI_TIME: {
6217 // Current local time, formatted HH:MM:SS (24-hour clock)
6218 char TmpBuffer[sizeof("hh:mm:ss")];
6219 const size_t Len = strftime(s: TmpBuffer, maxsize: sizeof(TmpBuffer), format: "%T", tp: &TM);
6220 return std::string(TmpBuffer, Len);
6221 }
6222 case BI_FILECUR:
6223 return SrcMgr
6224 .getMemoryBuffer(
6225 i: ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)
6226 ->getBufferIdentifier()
6227 .str();
6228 case BI_FILENAME:
6229 return sys::path::stem(path: SrcMgr.getMemoryBuffer(i: SrcMgr.getMainFileID())
6230 ->getBufferIdentifier())
6231 .upper();
6232 case BI_CURSEG:
6233 return getStreamer().getCurrentSectionOnly()->getName().str();
6234 }
6235 llvm_unreachable("unhandled built-in symbol");
6236}
6237
6238bool MasmParser::evaluateBuiltinMacroFunction(BuiltinFunction Function,
6239 StringRef Name,
6240 std::string &Res) {
6241 if (parseToken(T: AsmToken::LParen, Msg: "invoking macro function '" + Name +
6242 "' requires arguments in parentheses")) {
6243 return true;
6244 }
6245
6246 MCAsmMacroParameters P;
6247 switch (Function) {
6248 default:
6249 return true;
6250 case BI_CATSTR:
6251 break;
6252 }
6253 MCAsmMacro M(Name, "", P, {}, true);
6254
6255 MCAsmMacroArguments A;
6256 if (parseMacroArguments(M: &M, A, EndTok: AsmToken::RParen) || parseRParen()) {
6257 return true;
6258 }
6259
6260 switch (Function) {
6261 default:
6262 llvm_unreachable("unhandled built-in function");
6263 case BI_CATSTR: {
6264 for (const MCAsmMacroArgument &Arg : A) {
6265 for (const AsmToken &Tok : Arg) {
6266 if (Tok.is(K: AsmToken::String)) {
6267 Res.append(svt: Tok.getStringContents());
6268 } else {
6269 Res.append(svt: Tok.getString());
6270 }
6271 }
6272 }
6273 return false;
6274 }
6275 }
6276 llvm_unreachable("unhandled built-in function");
6277 return true;
6278}
6279
6280/// Create an MCAsmParser instance.
6281MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,
6282 MCStreamer &Out, const MCAsmInfo &MAI,
6283 struct tm TM, unsigned CB) {
6284 return new MasmParser(SM, C, Out, MAI, TM, CB);
6285}
6286