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