xref: /llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp (revision f792f14b01605453c7c0c17f3b4564335c0d9d14)
1 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
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 /// \file
10 /// This file is part of the WebAssembly Assembler.
11 ///
12 /// It contains code to translate a parsed .s file into MCInsts.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "AsmParser/WebAssemblyAsmTypeCheck.h"
17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
18 #include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
19 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
20 #include "TargetInfo/WebAssemblyTargetInfo.h"
21 #include "WebAssembly.h"
22 #include "llvm/MC/MCContext.h"
23 #include "llvm/MC/MCExpr.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/MC/MCInstrInfo.h"
26 #include "llvm/MC/MCParser/MCAsmLexer.h"
27 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
28 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
29 #include "llvm/MC/MCSectionWasm.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/MC/MCSubtargetInfo.h"
32 #include "llvm/MC/MCSymbol.h"
33 #include "llvm/MC/MCSymbolWasm.h"
34 #include "llvm/MC/TargetRegistry.h"
35 #include "llvm/Support/SourceMgr.h"
36 
37 using namespace llvm;
38 
39 #define DEBUG_TYPE "wasm-asm-parser"
40 
41 static const char *getSubtargetFeatureName(uint64_t Val);
42 
43 namespace {
44 
45 /// WebAssemblyOperand - Instances of this class represent the operands in a
46 /// parsed Wasm machine instruction.
47 struct WebAssemblyOperand : public MCParsedAsmOperand {
48   enum KindTy { Token, Integer, Float, Symbol, BrList } Kind;
49 
50   SMLoc StartLoc, EndLoc;
51 
52   struct TokOp {
53     StringRef Tok;
54   };
55 
56   struct IntOp {
57     int64_t Val;
58   };
59 
60   struct FltOp {
61     double Val;
62   };
63 
64   struct SymOp {
65     const MCExpr *Exp;
66   };
67 
68   struct BrLOp {
69     std::vector<unsigned> List;
70   };
71 
72   union {
73     struct TokOp Tok;
74     struct IntOp Int;
75     struct FltOp Flt;
76     struct SymOp Sym;
77     struct BrLOp BrL;
78   };
79 
80   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
81       : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
82   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
83       : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
84   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
85       : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
86   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
87       : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
88   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
89       : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
90 
91   ~WebAssemblyOperand() {
92     if (isBrList())
93       BrL.~BrLOp();
94   }
95 
96   bool isToken() const override { return Kind == Token; }
97   bool isImm() const override { return Kind == Integer || Kind == Symbol; }
98   bool isFPImm() const { return Kind == Float; }
99   bool isMem() const override { return false; }
100   bool isReg() const override { return false; }
101   bool isBrList() const { return Kind == BrList; }
102 
103   MCRegister getReg() const override {
104     llvm_unreachable("Assembly inspects a register operand");
105     return 0;
106   }
107 
108   StringRef getToken() const {
109     assert(isToken());
110     return Tok.Tok;
111   }
112 
113   SMLoc getStartLoc() const override { return StartLoc; }
114   SMLoc getEndLoc() const override { return EndLoc; }
115 
116   void addRegOperands(MCInst &, unsigned) const {
117     // Required by the assembly matcher.
118     llvm_unreachable("Assembly matcher creates register operands");
119   }
120 
121   void addImmOperands(MCInst &Inst, unsigned N) const {
122     assert(N == 1 && "Invalid number of operands!");
123     if (Kind == Integer)
124       Inst.addOperand(MCOperand::createImm(Int.Val));
125     else if (Kind == Symbol)
126       Inst.addOperand(MCOperand::createExpr(Sym.Exp));
127     else
128       llvm_unreachable("Should be integer immediate or symbol!");
129   }
130 
131   void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
132     assert(N == 1 && "Invalid number of operands!");
133     if (Kind == Float)
134       Inst.addOperand(
135           MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val))));
136     else
137       llvm_unreachable("Should be float immediate!");
138   }
139 
140   void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
141     assert(N == 1 && "Invalid number of operands!");
142     if (Kind == Float)
143       Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val)));
144     else
145       llvm_unreachable("Should be float immediate!");
146   }
147 
148   void addBrListOperands(MCInst &Inst, unsigned N) const {
149     assert(N == 1 && isBrList() && "Invalid BrList!");
150     for (auto Br : BrL.List)
151       Inst.addOperand(MCOperand::createImm(Br));
152   }
153 
154   void print(raw_ostream &OS) const override {
155     switch (Kind) {
156     case Token:
157       OS << "Tok:" << Tok.Tok;
158       break;
159     case Integer:
160       OS << "Int:" << Int.Val;
161       break;
162     case Float:
163       OS << "Flt:" << Flt.Val;
164       break;
165     case Symbol:
166       OS << "Sym:" << Sym.Exp;
167       break;
168     case BrList:
169       OS << "BrList:" << BrL.List.size();
170       break;
171     }
172   }
173 };
174 
175 // Perhaps this should go somewhere common.
176 static wasm::WasmLimits DefaultLimits() {
177   return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0};
178 }
179 
180 static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx,
181                                                     const StringRef &Name) {
182   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
183   if (Sym) {
184     if (!Sym->isFunctionTable())
185       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
186   } else {
187     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
188     Sym->setFunctionTable();
189     // The default function table is synthesized by the linker.
190     Sym->setUndefined();
191   }
192   return Sym;
193 }
194 
195 class WebAssemblyAsmParser final : public MCTargetAsmParser {
196   MCAsmParser &Parser;
197   MCAsmLexer &Lexer;
198 
199   // Order of labels, directives and instructions in a .s file have no
200   // syntactical enforcement. This class is a callback from the actual parser,
201   // and yet we have to be feeding data to the streamer in a very particular
202   // order to ensure a correct binary encoding that matches the regular backend
203   // (the streamer does not enforce this). This "state machine" enum helps
204   // guarantee that correct order.
205   enum ParserState {
206     FileStart,
207     FunctionLabel,
208     FunctionStart,
209     FunctionLocals,
210     Instructions,
211     EndFunction,
212     DataSection,
213   } CurrentState = FileStart;
214 
215   // For ensuring blocks are properly nested.
216   enum NestingType {
217     Function,
218     Block,
219     Loop,
220     Try,
221     CatchAll,
222     If,
223     Else,
224     Undefined,
225   };
226   struct Nested {
227     NestingType NT;
228     wasm::WasmSignature Sig;
229   };
230   std::vector<Nested> NestingStack;
231 
232   MCSymbolWasm *DefaultFunctionTable = nullptr;
233   MCSymbol *LastFunctionLabel = nullptr;
234 
235   bool is64;
236 
237   WebAssemblyAsmTypeCheck TC;
238   // Don't type check if -no-type-check was set.
239   bool SkipTypeCheck;
240 
241 public:
242   WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
243                        const MCInstrInfo &MII, const MCTargetOptions &Options)
244       : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
245         Lexer(Parser.getLexer()), is64(STI.getTargetTriple().isArch64Bit()),
246         TC(Parser, MII, is64), SkipTypeCheck(Options.MCNoTypeCheck) {
247     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
248     // Don't type check if this is inline asm, since that is a naked sequence of
249     // instructions without a function/locals decl.
250     auto &SM = Parser.getSourceManager();
251     auto BufferName =
252         SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();
253     if (BufferName == "<inline asm>")
254       SkipTypeCheck = true;
255   }
256 
257   void Initialize(MCAsmParser &Parser) override {
258     MCAsmParserExtension::Initialize(Parser);
259 
260     DefaultFunctionTable = GetOrCreateFunctionTableSymbol(
261         getContext(), "__indirect_function_table");
262     if (!STI->checkFeatures("+reference-types"))
263       DefaultFunctionTable->setOmitFromLinkingSection();
264   }
265 
266 #define GET_ASSEMBLER_HEADER
267 #include "WebAssemblyGenAsmMatcher.inc"
268 
269   // TODO: This is required to be implemented, but appears unused.
270   bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override {
271     llvm_unreachable("parseRegister is not implemented.");
272   }
273   ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
274                                SMLoc &EndLoc) override {
275     llvm_unreachable("tryParseRegister is not implemented.");
276   }
277 
278   bool error(const Twine &Msg, const AsmToken &Tok) {
279     return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
280   }
281 
282   bool error(const Twine &Msg, SMLoc Loc = SMLoc()) {
283     return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);
284   }
285 
286   std::pair<StringRef, StringRef> nestingString(NestingType NT) {
287     switch (NT) {
288     case Function:
289       return {"function", "end_function"};
290     case Block:
291       return {"block", "end_block"};
292     case Loop:
293       return {"loop", "end_loop"};
294     case Try:
295       return {"try", "end_try/delegate"};
296     case CatchAll:
297       return {"catch_all", "end_try"};
298     case If:
299       return {"if", "end_if"};
300     case Else:
301       return {"else", "end_if"};
302     default:
303       llvm_unreachable("unknown NestingType");
304     }
305   }
306 
307   void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) {
308     NestingStack.push_back({NT, Sig});
309   }
310 
311   bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
312     if (NestingStack.empty())
313       return error(Twine("End of block construct with no start: ") + Ins);
314     auto Top = NestingStack.back();
315     if (Top.NT != NT1 && Top.NT != NT2)
316       return error(Twine("Block construct type mismatch, expected: ") +
317                    nestingString(Top.NT).second + ", instead got: " + Ins);
318     TC.setLastSig(Top.Sig);
319     NestingStack.pop_back();
320     return false;
321   }
322 
323   // Pop a NestingType and push a new NestingType with the same signature. Used
324   // for if-else and try-catch(_all).
325   bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT,
326                                    NestingType PushNT) {
327     if (NestingStack.empty())
328       return error(Twine("End of block construct with no start: ") + Ins);
329     auto Sig = NestingStack.back().Sig;
330     if (pop(Ins, PopNT))
331       return true;
332     push(PushNT, Sig);
333     return false;
334   }
335 
336   bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) {
337     auto Err = !NestingStack.empty();
338     while (!NestingStack.empty()) {
339       error(Twine("Unmatched block construct(s) at function end: ") +
340                 nestingString(NestingStack.back().NT).first,
341             Loc);
342       NestingStack.pop_back();
343     }
344     return Err;
345   }
346 
347   bool isNext(AsmToken::TokenKind Kind) {
348     auto Ok = Lexer.is(Kind);
349     if (Ok)
350       Parser.Lex();
351     return Ok;
352   }
353 
354   bool expect(AsmToken::TokenKind Kind, const char *KindName) {
355     if (!isNext(Kind))
356       return error(std::string("Expected ") + KindName + ", instead got: ",
357                    Lexer.getTok());
358     return false;
359   }
360 
361   StringRef expectIdent() {
362     if (!Lexer.is(AsmToken::Identifier)) {
363       error("Expected identifier, got: ", Lexer.getTok());
364       return StringRef();
365     }
366     auto Name = Lexer.getTok().getString();
367     Parser.Lex();
368     return Name;
369   }
370 
371   bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
372     while (Lexer.is(AsmToken::Identifier)) {
373       auto Type = WebAssembly::parseType(Lexer.getTok().getString());
374       if (!Type)
375         return error("unknown type: ", Lexer.getTok());
376       Types.push_back(*Type);
377       Parser.Lex();
378       if (!isNext(AsmToken::Comma))
379         break;
380     }
381     return false;
382   }
383 
384   void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
385     auto &Int = Lexer.getTok();
386     int64_t Val = Int.getIntVal();
387     if (IsNegative)
388       Val = -Val;
389     Operands.push_back(std::make_unique<WebAssemblyOperand>(
390         WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
391         WebAssemblyOperand::IntOp{Val}));
392     Parser.Lex();
393   }
394 
395   bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
396     auto &Flt = Lexer.getTok();
397     double Val;
398     if (Flt.getString().getAsDouble(Val, false))
399       return error("Cannot parse real: ", Flt);
400     if (IsNegative)
401       Val = -Val;
402     Operands.push_back(std::make_unique<WebAssemblyOperand>(
403         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
404         WebAssemblyOperand::FltOp{Val}));
405     Parser.Lex();
406     return false;
407   }
408 
409   bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
410     if (Lexer.isNot(AsmToken::Identifier))
411       return true;
412     auto &Flt = Lexer.getTok();
413     auto S = Flt.getString();
414     double Val;
415     if (S.compare_insensitive("infinity") == 0) {
416       Val = std::numeric_limits<double>::infinity();
417     } else if (S.compare_insensitive("nan") == 0) {
418       Val = std::numeric_limits<double>::quiet_NaN();
419     } else {
420       return true;
421     }
422     if (IsNegative)
423       Val = -Val;
424     Operands.push_back(std::make_unique<WebAssemblyOperand>(
425         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
426         WebAssemblyOperand::FltOp{Val}));
427     Parser.Lex();
428     return false;
429   }
430 
431   bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
432     // FIXME: there is probably a cleaner way to do this.
433     auto IsLoadStore = InstName.contains(".load") ||
434                        InstName.contains(".store") ||
435                        InstName.contains("prefetch");
436     auto IsAtomic = InstName.contains("atomic.");
437     if (IsLoadStore || IsAtomic) {
438       // Parse load/store operands of the form: offset:p2align=align
439       if (IsLoadStore && isNext(AsmToken::Colon)) {
440         auto Id = expectIdent();
441         if (Id != "p2align")
442           return error("Expected p2align, instead got: " + Id);
443         if (expect(AsmToken::Equal, "="))
444           return true;
445         if (!Lexer.is(AsmToken::Integer))
446           return error("Expected integer constant");
447         parseSingleInteger(false, Operands);
448       } else {
449         // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane
450         // index. We need to avoid parsing an extra alignment operand for the
451         // lane index.
452         auto IsLoadStoreLane = InstName.contains("_lane");
453         if (IsLoadStoreLane && Operands.size() == 4)
454           return false;
455         // Alignment not specified (or atomics, must use default alignment).
456         // We can't just call WebAssembly::GetDefaultP2Align since we don't have
457         // an opcode until after the assembly matcher, so set a default to fix
458         // up later.
459         auto Tok = Lexer.getTok();
460         Operands.push_back(std::make_unique<WebAssemblyOperand>(
461             WebAssemblyOperand::Integer, Tok.getLoc(), Tok.getEndLoc(),
462             WebAssemblyOperand::IntOp{-1}));
463       }
464     }
465     return false;
466   }
467 
468   void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
469                            WebAssembly::BlockType BT) {
470     if (BT != WebAssembly::BlockType::Void) {
471       wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
472       TC.setLastSig(Sig);
473       NestingStack.back().Sig = Sig;
474     }
475     Operands.push_back(std::make_unique<WebAssemblyOperand>(
476         WebAssemblyOperand::Integer, NameLoc, NameLoc,
477         WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
478   }
479 
480   bool parseLimits(wasm::WasmLimits *Limits) {
481     auto Tok = Lexer.getTok();
482     if (!Tok.is(AsmToken::Integer))
483       return error("Expected integer constant, instead got: ", Tok);
484     int64_t Val = Tok.getIntVal();
485     assert(Val >= 0);
486     Limits->Minimum = Val;
487     Parser.Lex();
488 
489     if (isNext(AsmToken::Comma)) {
490       Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX;
491       auto Tok = Lexer.getTok();
492       if (!Tok.is(AsmToken::Integer))
493         return error("Expected integer constant, instead got: ", Tok);
494       int64_t Val = Tok.getIntVal();
495       assert(Val >= 0);
496       Limits->Maximum = Val;
497       Parser.Lex();
498     }
499     return false;
500   }
501 
502   bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
503     if (STI->checkFeatures("+reference-types")) {
504       // If the reference-types feature is enabled, there is an explicit table
505       // operand.  To allow the same assembly to be compiled with or without
506       // reference types, we allow the operand to be omitted, in which case we
507       // default to __indirect_function_table.
508       auto &Tok = Lexer.getTok();
509       if (Tok.is(AsmToken::Identifier)) {
510         auto *Sym =
511             GetOrCreateFunctionTableSymbol(getContext(), Tok.getString());
512         const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
513         *Op = std::make_unique<WebAssemblyOperand>(
514             WebAssemblyOperand::Symbol, Tok.getLoc(), Tok.getEndLoc(),
515             WebAssemblyOperand::SymOp{Val});
516         Parser.Lex();
517         return expect(AsmToken::Comma, ",");
518       } else {
519         const auto *Val =
520             MCSymbolRefExpr::create(DefaultFunctionTable, getContext());
521         *Op = std::make_unique<WebAssemblyOperand>(
522             WebAssemblyOperand::Symbol, SMLoc(), SMLoc(),
523             WebAssemblyOperand::SymOp{Val});
524         return false;
525       }
526     } else {
527       // For the MVP there is at most one table whose number is 0, but we can't
528       // write a table symbol or issue relocations.  Instead we just ensure the
529       // table is live and write a zero.
530       getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
531       *Op = std::make_unique<WebAssemblyOperand>(WebAssemblyOperand::Integer,
532                                                  SMLoc(), SMLoc(),
533                                                  WebAssemblyOperand::IntOp{0});
534       return false;
535     }
536   }
537 
538   bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
539                         SMLoc NameLoc, OperandVector &Operands) override {
540     // Note: Name does NOT point into the sourcecode, but to a local, so
541     // use NameLoc instead.
542     Name = StringRef(NameLoc.getPointer(), Name.size());
543 
544     // WebAssembly has instructions with / in them, which AsmLexer parses
545     // as separate tokens, so if we find such tokens immediately adjacent (no
546     // whitespace), expand the name to include them:
547     for (;;) {
548       auto &Sep = Lexer.getTok();
549       if (Sep.getLoc().getPointer() != Name.end() ||
550           Sep.getKind() != AsmToken::Slash)
551         break;
552       // Extend name with /
553       Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
554       Parser.Lex();
555       // We must now find another identifier, or error.
556       auto &Id = Lexer.getTok();
557       if (Id.getKind() != AsmToken::Identifier ||
558           Id.getLoc().getPointer() != Name.end())
559         return error("Incomplete instruction name: ", Id);
560       Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
561       Parser.Lex();
562     }
563 
564     // Now construct the name as first operand.
565     Operands.push_back(std::make_unique<WebAssemblyOperand>(
566         WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
567         WebAssemblyOperand::TokOp{Name}));
568 
569     // If this instruction is part of a control flow structure, ensure
570     // proper nesting.
571     bool ExpectBlockType = false;
572     bool ExpectFuncType = false;
573     std::unique_ptr<WebAssemblyOperand> FunctionTable;
574     if (Name == "block") {
575       push(Block);
576       ExpectBlockType = true;
577     } else if (Name == "loop") {
578       push(Loop);
579       ExpectBlockType = true;
580     } else if (Name == "try") {
581       push(Try);
582       ExpectBlockType = true;
583     } else if (Name == "if") {
584       push(If);
585       ExpectBlockType = true;
586     } else if (Name == "else") {
587       if (popAndPushWithSameSignature(Name, If, Else))
588         return true;
589     } else if (Name == "catch") {
590       if (popAndPushWithSameSignature(Name, Try, Try))
591         return true;
592     } else if (Name == "catch_all") {
593       if (popAndPushWithSameSignature(Name, Try, CatchAll))
594         return true;
595     } else if (Name == "end_if") {
596       if (pop(Name, If, Else))
597         return true;
598     } else if (Name == "end_try") {
599       if (pop(Name, Try, CatchAll))
600         return true;
601     } else if (Name == "delegate") {
602       if (pop(Name, Try))
603         return true;
604     } else if (Name == "end_loop") {
605       if (pop(Name, Loop))
606         return true;
607     } else if (Name == "end_block") {
608       if (pop(Name, Block))
609         return true;
610     } else if (Name == "end_function") {
611       ensureLocals(getStreamer());
612       CurrentState = EndFunction;
613       if (pop(Name, Function) || ensureEmptyNestingStack())
614         return true;
615     } else if (Name == "call_indirect" || Name == "return_call_indirect") {
616       // These instructions have differing operand orders in the text format vs
617       // the binary formats.  The MC instructions follow the binary format, so
618       // here we stash away the operand and append it later.
619       if (parseFunctionTableOperand(&FunctionTable))
620         return true;
621       ExpectFuncType = true;
622     }
623 
624     if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) {
625       // This has a special TYPEINDEX operand which in text we
626       // represent as a signature, such that we can re-build this signature,
627       // attach it to an anonymous symbol, which is what WasmObjectWriter
628       // expects to be able to recreate the actual unique-ified type indices.
629       auto &Ctx = getContext();
630       auto Loc = Parser.getTok();
631       auto Signature = Ctx.createWasmSignature();
632       if (parseSignature(Signature))
633         return true;
634       // Got signature as block type, don't need more
635       TC.setLastSig(*Signature);
636       if (ExpectBlockType)
637         NestingStack.back().Sig = *Signature;
638       ExpectBlockType = false;
639       // The "true" here will cause this to be a nameless symbol.
640       MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
641       auto *WasmSym = cast<MCSymbolWasm>(Sym);
642       WasmSym->setSignature(Signature);
643       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
644       const MCExpr *Expr = MCSymbolRefExpr::create(
645           WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
646       Operands.push_back(std::make_unique<WebAssemblyOperand>(
647           WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
648           WebAssemblyOperand::SymOp{Expr}));
649     }
650 
651     while (Lexer.isNot(AsmToken::EndOfStatement)) {
652       auto &Tok = Lexer.getTok();
653       switch (Tok.getKind()) {
654       case AsmToken::Identifier: {
655         if (!parseSpecialFloatMaybe(false, Operands))
656           break;
657         auto &Id = Lexer.getTok();
658         if (ExpectBlockType) {
659           // Assume this identifier is a block_type.
660           auto BT = WebAssembly::parseBlockType(Id.getString());
661           if (BT == WebAssembly::BlockType::Invalid)
662             return error("Unknown block type: ", Id);
663           addBlockTypeOperand(Operands, NameLoc, BT);
664           Parser.Lex();
665         } else {
666           // Assume this identifier is a label.
667           const MCExpr *Val;
668           SMLoc Start = Id.getLoc();
669           SMLoc End;
670           if (Parser.parseExpression(Val, End))
671             return error("Cannot parse symbol: ", Lexer.getTok());
672           Operands.push_back(std::make_unique<WebAssemblyOperand>(
673               WebAssemblyOperand::Symbol, Start, End,
674               WebAssemblyOperand::SymOp{Val}));
675           if (checkForP2AlignIfLoadStore(Operands, Name))
676             return true;
677         }
678         break;
679       }
680       case AsmToken::Minus:
681         Parser.Lex();
682         if (Lexer.is(AsmToken::Integer)) {
683           parseSingleInteger(true, Operands);
684           if (checkForP2AlignIfLoadStore(Operands, Name))
685             return true;
686         } else if (Lexer.is(AsmToken::Real)) {
687           if (parseSingleFloat(true, Operands))
688             return true;
689         } else if (!parseSpecialFloatMaybe(true, Operands)) {
690         } else {
691           return error("Expected numeric constant instead got: ",
692                        Lexer.getTok());
693         }
694         break;
695       case AsmToken::Integer:
696         parseSingleInteger(false, Operands);
697         if (checkForP2AlignIfLoadStore(Operands, Name))
698           return true;
699         break;
700       case AsmToken::Real: {
701         if (parseSingleFloat(false, Operands))
702           return true;
703         break;
704       }
705       case AsmToken::LCurly: {
706         Parser.Lex();
707         auto Op = std::make_unique<WebAssemblyOperand>(
708             WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
709         if (!Lexer.is(AsmToken::RCurly))
710           for (;;) {
711             Op->BrL.List.push_back(Lexer.getTok().getIntVal());
712             expect(AsmToken::Integer, "integer");
713             if (!isNext(AsmToken::Comma))
714               break;
715           }
716         expect(AsmToken::RCurly, "}");
717         Operands.push_back(std::move(Op));
718         break;
719       }
720       default:
721         return error("Unexpected token in operand: ", Tok);
722       }
723       if (Lexer.isNot(AsmToken::EndOfStatement)) {
724         if (expect(AsmToken::Comma, ","))
725           return true;
726       }
727     }
728     if (ExpectBlockType && Operands.size() == 1) {
729       // Support blocks with no operands as default to void.
730       addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
731     }
732     if (FunctionTable)
733       Operands.push_back(std::move(FunctionTable));
734     Parser.Lex();
735     return false;
736   }
737 
738   bool parseSignature(wasm::WasmSignature *Signature) {
739     if (expect(AsmToken::LParen, "("))
740       return true;
741     if (parseRegTypeList(Signature->Params))
742       return true;
743     if (expect(AsmToken::RParen, ")"))
744       return true;
745     if (expect(AsmToken::MinusGreater, "->"))
746       return true;
747     if (expect(AsmToken::LParen, "("))
748       return true;
749     if (parseRegTypeList(Signature->Returns))
750       return true;
751     if (expect(AsmToken::RParen, ")"))
752       return true;
753     return false;
754   }
755 
756   bool CheckDataSection() {
757     if (CurrentState != DataSection) {
758       auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
759       if (WS && WS->getKind().isText())
760         return error("data directive must occur in a data segment: ",
761                      Lexer.getTok());
762     }
763     CurrentState = DataSection;
764     return false;
765   }
766 
767   // This function processes wasm-specific directives streamed to
768   // WebAssemblyTargetStreamer, all others go to the generic parser
769   // (see WasmAsmParser).
770   ParseStatus parseDirective(AsmToken DirectiveID) override {
771     assert(DirectiveID.getKind() == AsmToken::Identifier);
772     auto &Out = getStreamer();
773     auto &TOut =
774         reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
775     auto &Ctx = Out.getContext();
776 
777     if (DirectiveID.getString() == ".globaltype") {
778       auto SymName = expectIdent();
779       if (SymName.empty())
780         return ParseStatus::Failure;
781       if (expect(AsmToken::Comma, ","))
782         return ParseStatus::Failure;
783       auto TypeTok = Lexer.getTok();
784       auto TypeName = expectIdent();
785       if (TypeName.empty())
786         return ParseStatus::Failure;
787       auto Type = WebAssembly::parseType(TypeName);
788       if (!Type)
789         return error("Unknown type in .globaltype directive: ", TypeTok);
790       // Optional mutable modifier. Default to mutable for historical reasons.
791       // Ideally we would have gone with immutable as the default and used `mut`
792       // as the modifier to match the `.wat` format.
793       bool Mutable = true;
794       if (isNext(AsmToken::Comma)) {
795         TypeTok = Lexer.getTok();
796         auto Id = expectIdent();
797         if (Id.empty())
798           return ParseStatus::Failure;
799         if (Id == "immutable")
800           Mutable = false;
801         else
802           // Should we also allow `mutable` and `mut` here for clarity?
803           return error("Unknown type in .globaltype modifier: ", TypeTok);
804       }
805       // Now set this symbol with the correct type.
806       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
807       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
808       WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
809       // And emit the directive again.
810       TOut.emitGlobalType(WasmSym);
811       return expect(AsmToken::EndOfStatement, "EOL");
812     }
813 
814     if (DirectiveID.getString() == ".tabletype") {
815       // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
816       auto SymName = expectIdent();
817       if (SymName.empty())
818         return ParseStatus::Failure;
819       if (expect(AsmToken::Comma, ","))
820         return ParseStatus::Failure;
821 
822       auto ElemTypeTok = Lexer.getTok();
823       auto ElemTypeName = expectIdent();
824       if (ElemTypeName.empty())
825         return ParseStatus::Failure;
826       std::optional<wasm::ValType> ElemType =
827           WebAssembly::parseType(ElemTypeName);
828       if (!ElemType)
829         return error("Unknown type in .tabletype directive: ", ElemTypeTok);
830 
831       wasm::WasmLimits Limits = DefaultLimits();
832       if (isNext(AsmToken::Comma) && parseLimits(&Limits))
833         return ParseStatus::Failure;
834 
835       // Now that we have the name and table type, we can actually create the
836       // symbol
837       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
838       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
839       wasm::WasmTableType Type = {*ElemType, Limits};
840       WasmSym->setTableType(Type);
841       TOut.emitTableType(WasmSym);
842       return expect(AsmToken::EndOfStatement, "EOL");
843     }
844 
845     if (DirectiveID.getString() == ".functype") {
846       // This code has to send things to the streamer similar to
847       // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
848       // TODO: would be good to factor this into a common function, but the
849       // assembler and backend really don't share any common code, and this code
850       // parses the locals separately.
851       auto SymName = expectIdent();
852       if (SymName.empty())
853         return ParseStatus::Failure;
854       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
855       if (WasmSym->isDefined()) {
856         // We push 'Function' either when a label is parsed or a .functype
857         // directive is parsed. The reason it is not easy to do this uniformly
858         // in a single place is,
859         // 1. We can't do this at label parsing time only because there are
860         //    cases we don't have .functype directive before a function label,
861         //    in which case we don't know if the label is a function at the time
862         //    of parsing.
863         // 2. We can't do this at .functype parsing time only because we want to
864         //    detect a function started with a label and not ended correctly
865         //    without encountering a .functype directive after the label.
866         if (CurrentState != FunctionLabel) {
867           // This .functype indicates a start of a function.
868           if (ensureEmptyNestingStack())
869             return ParseStatus::Failure;
870           push(Function);
871         }
872         CurrentState = FunctionStart;
873         LastFunctionLabel = WasmSym;
874       }
875       auto Signature = Ctx.createWasmSignature();
876       if (parseSignature(Signature))
877         return ParseStatus::Failure;
878       TC.funcDecl(*Signature);
879       WasmSym->setSignature(Signature);
880       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
881       TOut.emitFunctionType(WasmSym);
882       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
883       return expect(AsmToken::EndOfStatement, "EOL");
884     }
885 
886     if (DirectiveID.getString() == ".export_name") {
887       auto SymName = expectIdent();
888       if (SymName.empty())
889         return ParseStatus::Failure;
890       if (expect(AsmToken::Comma, ","))
891         return ParseStatus::Failure;
892       auto ExportName = expectIdent();
893       if (ExportName.empty())
894         return ParseStatus::Failure;
895       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
896       WasmSym->setExportName(Ctx.allocateString(ExportName));
897       TOut.emitExportName(WasmSym, ExportName);
898       return expect(AsmToken::EndOfStatement, "EOL");
899     }
900 
901     if (DirectiveID.getString() == ".import_module") {
902       auto SymName = expectIdent();
903       if (SymName.empty())
904         return ParseStatus::Failure;
905       if (expect(AsmToken::Comma, ","))
906         return ParseStatus::Failure;
907       auto ImportModule = expectIdent();
908       if (ImportModule.empty())
909         return ParseStatus::Failure;
910       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
911       WasmSym->setImportModule(Ctx.allocateString(ImportModule));
912       TOut.emitImportModule(WasmSym, ImportModule);
913       return expect(AsmToken::EndOfStatement, "EOL");
914     }
915 
916     if (DirectiveID.getString() == ".import_name") {
917       auto SymName = expectIdent();
918       if (SymName.empty())
919         return ParseStatus::Failure;
920       if (expect(AsmToken::Comma, ","))
921         return ParseStatus::Failure;
922       auto ImportName = expectIdent();
923       if (ImportName.empty())
924         return ParseStatus::Failure;
925       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
926       WasmSym->setImportName(Ctx.allocateString(ImportName));
927       TOut.emitImportName(WasmSym, ImportName);
928       return expect(AsmToken::EndOfStatement, "EOL");
929     }
930 
931     if (DirectiveID.getString() == ".tagtype") {
932       auto SymName = expectIdent();
933       if (SymName.empty())
934         return ParseStatus::Failure;
935       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
936       auto Signature = Ctx.createWasmSignature();
937       if (parseRegTypeList(Signature->Params))
938         return ParseStatus::Failure;
939       WasmSym->setSignature(Signature);
940       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
941       TOut.emitTagType(WasmSym);
942       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
943       return expect(AsmToken::EndOfStatement, "EOL");
944     }
945 
946     if (DirectiveID.getString() == ".local") {
947       if (CurrentState != FunctionStart)
948         return error(".local directive should follow the start of a function: ",
949                      Lexer.getTok());
950       SmallVector<wasm::ValType, 4> Locals;
951       if (parseRegTypeList(Locals))
952         return ParseStatus::Failure;
953       TC.localDecl(Locals);
954       TOut.emitLocal(Locals);
955       CurrentState = FunctionLocals;
956       return expect(AsmToken::EndOfStatement, "EOL");
957     }
958 
959     if (DirectiveID.getString() == ".int8" ||
960         DirectiveID.getString() == ".int16" ||
961         DirectiveID.getString() == ".int32" ||
962         DirectiveID.getString() == ".int64") {
963       if (CheckDataSection())
964         return ParseStatus::Failure;
965       const MCExpr *Val;
966       SMLoc End;
967       if (Parser.parseExpression(Val, End))
968         return error("Cannot parse .int expression: ", Lexer.getTok());
969       size_t NumBits = 0;
970       DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
971       Out.emitValue(Val, NumBits / 8, End);
972       return expect(AsmToken::EndOfStatement, "EOL");
973     }
974 
975     if (DirectiveID.getString() == ".asciz") {
976       if (CheckDataSection())
977         return ParseStatus::Failure;
978       std::string S;
979       if (Parser.parseEscapedString(S))
980         return error("Cannot parse string constant: ", Lexer.getTok());
981       Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
982       return expect(AsmToken::EndOfStatement, "EOL");
983     }
984 
985     return ParseStatus::NoMatch; // We didn't process this directive.
986   }
987 
988   // Called either when the first instruction is parsed of the function ends.
989   void ensureLocals(MCStreamer &Out) {
990     if (CurrentState == FunctionStart) {
991       // We haven't seen a .local directive yet. The streamer requires locals to
992       // be encoded as a prelude to the instructions, so emit an empty list of
993       // locals here.
994       auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
995           *Out.getTargetStreamer());
996       TOut.emitLocal(SmallVector<wasm::ValType, 0>());
997       CurrentState = FunctionLocals;
998     }
999   }
1000 
1001   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
1002                                OperandVector &Operands, MCStreamer &Out,
1003                                uint64_t &ErrorInfo,
1004                                bool MatchingInlineAsm) override {
1005     MCInst Inst;
1006     Inst.setLoc(IDLoc);
1007     FeatureBitset MissingFeatures;
1008     unsigned MatchResult = MatchInstructionImpl(
1009         Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
1010     switch (MatchResult) {
1011     case Match_Success: {
1012       ensureLocals(Out);
1013       // Fix unknown p2align operands.
1014       auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
1015       if (Align != -1U) {
1016         auto &Op0 = Inst.getOperand(0);
1017         if (Op0.getImm() == -1)
1018           Op0.setImm(Align);
1019       }
1020       if (is64) {
1021         // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
1022         // an offset64 arg instead of offset32, but to the assembler matcher
1023         // they're both immediates so don't get selected for.
1024         auto Opc64 = WebAssembly::getWasm64Opcode(
1025             static_cast<uint16_t>(Inst.getOpcode()));
1026         if (Opc64 >= 0) {
1027           Inst.setOpcode(Opc64);
1028         }
1029       }
1030       if (!SkipTypeCheck && TC.typeCheck(IDLoc, Inst, Operands))
1031         return true;
1032       Out.emitInstruction(Inst, getSTI());
1033       if (CurrentState == EndFunction) {
1034         onEndOfFunction(IDLoc);
1035       } else {
1036         CurrentState = Instructions;
1037       }
1038       return false;
1039     }
1040     case Match_MissingFeature: {
1041       assert(MissingFeatures.count() > 0 && "Expected missing features");
1042       SmallString<128> Message;
1043       raw_svector_ostream OS(Message);
1044       OS << "instruction requires:";
1045       for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)
1046         if (MissingFeatures.test(i))
1047           OS << ' ' << getSubtargetFeatureName(i);
1048       return Parser.Error(IDLoc, Message);
1049     }
1050     case Match_MnemonicFail:
1051       return Parser.Error(IDLoc, "invalid instruction");
1052     case Match_NearMisses:
1053       return Parser.Error(IDLoc, "ambiguous instruction");
1054     case Match_InvalidTiedOperand:
1055     case Match_InvalidOperand: {
1056       SMLoc ErrorLoc = IDLoc;
1057       if (ErrorInfo != ~0ULL) {
1058         if (ErrorInfo >= Operands.size())
1059           return Parser.Error(IDLoc, "too few operands for instruction");
1060         ErrorLoc = Operands[ErrorInfo]->getStartLoc();
1061         if (ErrorLoc == SMLoc())
1062           ErrorLoc = IDLoc;
1063       }
1064       return Parser.Error(ErrorLoc, "invalid operand for instruction");
1065     }
1066     }
1067     llvm_unreachable("Implement any new match types added!");
1068   }
1069 
1070   void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {
1071     // Code below only applies to labels in text sections.
1072     auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
1073     if (!CWS || !CWS->getKind().isText())
1074       return;
1075 
1076     auto WasmSym = cast<MCSymbolWasm>(Symbol);
1077     // Unlike other targets, we don't allow data in text sections (labels
1078     // declared with .type @object).
1079     if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {
1080       Parser.Error(IDLoc,
1081                    "Wasm doesn\'t support data symbols in text sections");
1082       return;
1083     }
1084 
1085     // Start a new section for the next function automatically, since our
1086     // object writer expects each function to have its own section. This way
1087     // The user can't forget this "convention".
1088     auto SymName = Symbol->getName();
1089     if (SymName.starts_with(".L"))
1090       return; // Local Symbol.
1091 
1092     // TODO: If the user explicitly creates a new function section, we ignore
1093     // its name when we create this one. It would be nice to honor their
1094     // choice, while still ensuring that we create one if they forget.
1095     // (that requires coordination with WasmAsmParser::parseSectionDirective)
1096     auto SecName = ".text." + SymName;
1097 
1098     auto *Group = CWS->getGroup();
1099     // If the current section is a COMDAT, also set the flag on the symbol.
1100     // TODO: Currently the only place that the symbols' comdat flag matters is
1101     // for importing comdat functions. But there's no way to specify that in
1102     // assembly currently.
1103     if (Group)
1104       WasmSym->setComdat(true);
1105     auto *WS =
1106         getContext().getWasmSection(SecName, SectionKind::getText(), 0, Group,
1107                                     MCContext::GenericSectionID, nullptr);
1108     getStreamer().switchSection(WS);
1109     // Also generate DWARF for this section if requested.
1110     if (getContext().getGenDwarfForAssembly())
1111       getContext().addGenDwarfSection(WS);
1112 
1113     if (WasmSym->isFunction()) {
1114       // We give the location of the label (IDLoc) here, because otherwise the
1115       // lexer's next location will be used, which can be confusing. For
1116       // example:
1117       //
1118       // test0: ; This function does not end properly
1119       //   ...
1120       //
1121       // test1: ; We would like to point to this line for error
1122       //   ...  . Not this line, which can contain any instruction
1123       ensureEmptyNestingStack(IDLoc);
1124       CurrentState = FunctionLabel;
1125       LastFunctionLabel = Symbol;
1126       push(Function);
1127     }
1128   }
1129 
1130   void onEndOfFunction(SMLoc ErrorLoc) {
1131     if (!SkipTypeCheck)
1132       TC.endOfFunction(ErrorLoc);
1133     // Reset the type checker state.
1134     TC.Clear();
1135   }
1136 
1137   void onEndOfFile() override { ensureEmptyNestingStack(); }
1138 };
1139 } // end anonymous namespace
1140 
1141 // Force static initialization.
1142 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser() {
1143   RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
1144   RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
1145 }
1146 
1147 #define GET_REGISTER_MATCHER
1148 #define GET_SUBTARGET_FEATURE_NAME
1149 #define GET_MATCHER_IMPLEMENTATION
1150 #include "WebAssemblyGenAsmMatcher.inc"
1151 
1152 StringRef GetMnemonic(unsigned Opc) {
1153   // FIXME: linear search!
1154   for (auto &ME : MatchTable0) {
1155     if (ME.Opcode == Opc) {
1156       return ME.getMnemonic();
1157     }
1158   }
1159   assert(false && "mnemonic not found");
1160   return StringRef();
1161 }
1162