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