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