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