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