xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file is part of the WebAssembly Assembler.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric /// It contains code to translate a parsed .s file into MCInsts.
130b57cec5SDimitry Andric ///
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
16fe6060f1SDimitry Andric #include "AsmParser/WebAssemblyAsmTypeCheck.h"
170b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1806c3fb27SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
190b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
200b57cec5SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h"
210b57cec5SDimitry Andric #include "WebAssembly.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
2681ad6265SDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
280b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
290b57cec5SDimitry Andric #include "llvm/MC/MCSectionWasm.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
310b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
330b57cec5SDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
34349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
35fe6060f1SDimitry Andric #include "llvm/Support/SourceMgr.h"
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric using namespace llvm;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-asm-parser"
400b57cec5SDimitry Andric 
41e8d8bef9SDimitry Andric static const char *getSubtargetFeatureName(uint64_t Val);
42e8d8bef9SDimitry Andric 
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric /// WebAssemblyOperand - Instances of this class represent the operands in a
46e8d8bef9SDimitry Andric /// parsed Wasm machine instruction.
470b57cec5SDimitry Andric struct WebAssemblyOperand : public MCParsedAsmOperand {
480b57cec5SDimitry Andric   enum KindTy { Token, Integer, Float, Symbol, BrList } Kind;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   SMLoc StartLoc, EndLoc;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   struct TokOp {
530b57cec5SDimitry Andric     StringRef Tok;
540b57cec5SDimitry Andric   };
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   struct IntOp {
570b57cec5SDimitry Andric     int64_t Val;
580b57cec5SDimitry Andric   };
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   struct FltOp {
610b57cec5SDimitry Andric     double Val;
620b57cec5SDimitry Andric   };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   struct SymOp {
650b57cec5SDimitry Andric     const MCExpr *Exp;
660b57cec5SDimitry Andric   };
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   struct BrLOp {
690b57cec5SDimitry Andric     std::vector<unsigned> List;
700b57cec5SDimitry Andric   };
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   union {
730b57cec5SDimitry Andric     struct TokOp Tok;
740b57cec5SDimitry Andric     struct IntOp Int;
750b57cec5SDimitry Andric     struct FltOp Flt;
760b57cec5SDimitry Andric     struct SymOp Sym;
770b57cec5SDimitry Andric     struct BrLOp BrL;
780b57cec5SDimitry Andric   };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
810b57cec5SDimitry Andric       : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
820b57cec5SDimitry Andric   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
830b57cec5SDimitry Andric       : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
840b57cec5SDimitry Andric   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
850b57cec5SDimitry Andric       : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
860b57cec5SDimitry Andric   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
870b57cec5SDimitry Andric       : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
880b57cec5SDimitry Andric   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
890b57cec5SDimitry Andric       : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   ~WebAssemblyOperand() {
920b57cec5SDimitry Andric     if (isBrList())
930b57cec5SDimitry Andric       BrL.~BrLOp();
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   bool isToken() const override { return Kind == Token; }
970b57cec5SDimitry Andric   bool isImm() const override { return Kind == Integer || Kind == Symbol; }
980b57cec5SDimitry Andric   bool isFPImm() const { return Kind == Float; }
990b57cec5SDimitry Andric   bool isMem() const override { return false; }
1000b57cec5SDimitry Andric   bool isReg() const override { return false; }
1010b57cec5SDimitry Andric   bool isBrList() const { return Kind == BrList; }
1020b57cec5SDimitry Andric 
103*0fca6ea1SDimitry Andric   MCRegister getReg() const override {
1040b57cec5SDimitry Andric     llvm_unreachable("Assembly inspects a register operand");
1050b57cec5SDimitry Andric     return 0;
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   StringRef getToken() const {
1090b57cec5SDimitry Andric     assert(isToken());
1100b57cec5SDimitry Andric     return Tok.Tok;
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   SMLoc getStartLoc() const override { return StartLoc; }
1140b57cec5SDimitry Andric   SMLoc getEndLoc() const override { return EndLoc; }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   void addRegOperands(MCInst &, unsigned) const {
1170b57cec5SDimitry Andric     // Required by the assembly matcher.
1180b57cec5SDimitry Andric     llvm_unreachable("Assembly matcher creates register operands");
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   void addImmOperands(MCInst &Inst, unsigned N) const {
1220b57cec5SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
1230b57cec5SDimitry Andric     if (Kind == Integer)
1240b57cec5SDimitry Andric       Inst.addOperand(MCOperand::createImm(Int.Val));
1250b57cec5SDimitry Andric     else if (Kind == Symbol)
1260b57cec5SDimitry Andric       Inst.addOperand(MCOperand::createExpr(Sym.Exp));
1270b57cec5SDimitry Andric     else
1280b57cec5SDimitry Andric       llvm_unreachable("Should be integer immediate or symbol!");
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
131fe6060f1SDimitry Andric   void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
1320b57cec5SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
1330b57cec5SDimitry Andric     if (Kind == Float)
134fe6060f1SDimitry Andric       Inst.addOperand(
135fe6060f1SDimitry Andric           MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val))));
136fe6060f1SDimitry Andric     else
137fe6060f1SDimitry Andric       llvm_unreachable("Should be float immediate!");
138fe6060f1SDimitry Andric   }
139fe6060f1SDimitry Andric 
140fe6060f1SDimitry Andric   void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
141fe6060f1SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
142fe6060f1SDimitry Andric     if (Kind == Float)
143fe6060f1SDimitry Andric       Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val)));
1440b57cec5SDimitry Andric     else
1450b57cec5SDimitry Andric       llvm_unreachable("Should be float immediate!");
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   void addBrListOperands(MCInst &Inst, unsigned N) const {
1490b57cec5SDimitry Andric     assert(N == 1 && isBrList() && "Invalid BrList!");
1500b57cec5SDimitry Andric     for (auto Br : BrL.List)
1510b57cec5SDimitry Andric       Inst.addOperand(MCOperand::createImm(Br));
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   void print(raw_ostream &OS) const override {
1550b57cec5SDimitry Andric     switch (Kind) {
1560b57cec5SDimitry Andric     case Token:
1570b57cec5SDimitry Andric       OS << "Tok:" << Tok.Tok;
1580b57cec5SDimitry Andric       break;
1590b57cec5SDimitry Andric     case Integer:
1600b57cec5SDimitry Andric       OS << "Int:" << Int.Val;
1610b57cec5SDimitry Andric       break;
1620b57cec5SDimitry Andric     case Float:
1630b57cec5SDimitry Andric       OS << "Flt:" << Flt.Val;
1640b57cec5SDimitry Andric       break;
1650b57cec5SDimitry Andric     case Symbol:
1660b57cec5SDimitry Andric       OS << "Sym:" << Sym.Exp;
1670b57cec5SDimitry Andric       break;
1680b57cec5SDimitry Andric     case BrList:
1690b57cec5SDimitry Andric       OS << "BrList:" << BrL.List.size();
1700b57cec5SDimitry Andric       break;
1710b57cec5SDimitry Andric     }
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric };
1740b57cec5SDimitry Andric 
175fe6060f1SDimitry Andric // Perhaps this should go somewhere common.
176fe6060f1SDimitry Andric static wasm::WasmLimits DefaultLimits() {
177fe6060f1SDimitry Andric   return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0};
178fe6060f1SDimitry Andric }
179fe6060f1SDimitry Andric 
180e8d8bef9SDimitry Andric static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx,
181*0fca6ea1SDimitry Andric                                                     const StringRef &Name,
182*0fca6ea1SDimitry Andric                                                     bool is64) {
183e8d8bef9SDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
184e8d8bef9SDimitry Andric   if (Sym) {
185e8d8bef9SDimitry Andric     if (!Sym->isFunctionTable())
186e8d8bef9SDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
187e8d8bef9SDimitry Andric   } else {
188e8d8bef9SDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
189*0fca6ea1SDimitry Andric     Sym->setFunctionTable(is64);
190e8d8bef9SDimitry Andric     // The default function table is synthesized by the linker.
191e8d8bef9SDimitry Andric     Sym->setUndefined();
192e8d8bef9SDimitry Andric   }
193e8d8bef9SDimitry Andric   return Sym;
194e8d8bef9SDimitry Andric }
195e8d8bef9SDimitry Andric 
1960b57cec5SDimitry Andric class WebAssemblyAsmParser final : public MCTargetAsmParser {
1970b57cec5SDimitry Andric   MCAsmParser &Parser;
1980b57cec5SDimitry Andric   MCAsmLexer &Lexer;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   // Order of labels, directives and instructions in a .s file have no
2010b57cec5SDimitry Andric   // syntactical enforcement. This class is a callback from the actual parser,
2020b57cec5SDimitry Andric   // and yet we have to be feeding data to the streamer in a very particular
2030b57cec5SDimitry Andric   // order to ensure a correct binary encoding that matches the regular backend
2040b57cec5SDimitry Andric   // (the streamer does not enforce this). This "state machine" enum helps
2050b57cec5SDimitry Andric   // guarantee that correct order.
2060b57cec5SDimitry Andric   enum ParserState {
2070b57cec5SDimitry Andric     FileStart,
208bdd1243dSDimitry Andric     FunctionLabel,
2090b57cec5SDimitry Andric     FunctionStart,
2100b57cec5SDimitry Andric     FunctionLocals,
2110b57cec5SDimitry Andric     Instructions,
2120b57cec5SDimitry Andric     EndFunction,
2130b57cec5SDimitry Andric     DataSection,
2140b57cec5SDimitry Andric   } CurrentState = FileStart;
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   // For ensuring blocks are properly nested.
2170b57cec5SDimitry Andric   enum NestingType {
2180b57cec5SDimitry Andric     Function,
2190b57cec5SDimitry Andric     Block,
2200b57cec5SDimitry Andric     Loop,
2210b57cec5SDimitry Andric     Try,
222fe6060f1SDimitry Andric     CatchAll,
2230b57cec5SDimitry Andric     If,
2240b57cec5SDimitry Andric     Else,
2250b57cec5SDimitry Andric     Undefined,
2260b57cec5SDimitry Andric   };
227fe6060f1SDimitry Andric   struct Nested {
228fe6060f1SDimitry Andric     NestingType NT;
229fe6060f1SDimitry Andric     wasm::WasmSignature Sig;
230fe6060f1SDimitry Andric   };
231fe6060f1SDimitry Andric   std::vector<Nested> NestingStack;
2320b57cec5SDimitry Andric 
233fe6060f1SDimitry Andric   MCSymbolWasm *DefaultFunctionTable = nullptr;
2340b57cec5SDimitry Andric   MCSymbol *LastFunctionLabel = nullptr;
2350b57cec5SDimitry Andric 
236fe6060f1SDimitry Andric   bool is64;
237fe6060f1SDimitry Andric 
238fe6060f1SDimitry Andric   WebAssemblyAsmTypeCheck TC;
239fe6060f1SDimitry Andric   // Don't type check if -no-type-check was set.
240fe6060f1SDimitry Andric   bool SkipTypeCheck;
241fe6060f1SDimitry Andric 
2420b57cec5SDimitry Andric public:
2430b57cec5SDimitry Andric   WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
2440b57cec5SDimitry Andric                        const MCInstrInfo &MII, const MCTargetOptions &Options)
2450b57cec5SDimitry Andric       : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
24606c3fb27SDimitry Andric         Lexer(Parser.getLexer()), is64(STI.getTargetTriple().isArch64Bit()),
247fe6060f1SDimitry Andric         TC(Parser, MII, is64), SkipTypeCheck(Options.MCNoTypeCheck) {
2480b57cec5SDimitry Andric     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
249fe6060f1SDimitry Andric     // Don't type check if this is inline asm, since that is a naked sequence of
250fe6060f1SDimitry Andric     // instructions without a function/locals decl.
251fe6060f1SDimitry Andric     auto &SM = Parser.getSourceManager();
252fe6060f1SDimitry Andric     auto BufferName =
253fe6060f1SDimitry Andric         SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();
254fe6060f1SDimitry Andric     if (BufferName == "<inline asm>")
255fe6060f1SDimitry Andric       SkipTypeCheck = true;
256fe6060f1SDimitry Andric   }
257fe6060f1SDimitry Andric 
258fe6060f1SDimitry Andric   void Initialize(MCAsmParser &Parser) override {
259fe6060f1SDimitry Andric     MCAsmParserExtension::Initialize(Parser);
260fe6060f1SDimitry Andric 
261fe6060f1SDimitry Andric     DefaultFunctionTable = GetOrCreateFunctionTableSymbol(
262*0fca6ea1SDimitry Andric         getContext(), "__indirect_function_table", is64);
263fe6060f1SDimitry Andric     if (!STI->checkFeatures("+reference-types"))
264fe6060f1SDimitry Andric       DefaultFunctionTable->setOmitFromLinkingSection();
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric #define GET_ASSEMBLER_HEADER
2680b57cec5SDimitry Andric #include "WebAssemblyGenAsmMatcher.inc"
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // TODO: This is required to be implemented, but appears unused.
2715f757f3fSDimitry Andric   bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override {
272bdd1243dSDimitry Andric     llvm_unreachable("parseRegister is not implemented.");
2730b57cec5SDimitry Andric   }
2745f757f3fSDimitry Andric   ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
2755f757f3fSDimitry Andric                                SMLoc &EndLoc) override {
2765ffd83dbSDimitry Andric     llvm_unreachable("tryParseRegister is not implemented.");
2775ffd83dbSDimitry Andric   }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   bool error(const Twine &Msg, const AsmToken &Tok) {
2800b57cec5SDimitry Andric     return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
2810b57cec5SDimitry Andric   }
2820b57cec5SDimitry Andric 
283bdd1243dSDimitry Andric   bool error(const Twine &Msg, SMLoc Loc = SMLoc()) {
284bdd1243dSDimitry Andric     return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   std::pair<StringRef, StringRef> nestingString(NestingType NT) {
2880b57cec5SDimitry Andric     switch (NT) {
2890b57cec5SDimitry Andric     case Function:
2900b57cec5SDimitry Andric       return {"function", "end_function"};
2910b57cec5SDimitry Andric     case Block:
2920b57cec5SDimitry Andric       return {"block", "end_block"};
2930b57cec5SDimitry Andric     case Loop:
2940b57cec5SDimitry Andric       return {"loop", "end_loop"};
2950b57cec5SDimitry Andric     case Try:
296fe6060f1SDimitry Andric       return {"try", "end_try/delegate"};
297fe6060f1SDimitry Andric     case CatchAll:
298fe6060f1SDimitry Andric       return {"catch_all", "end_try"};
2990b57cec5SDimitry Andric     case If:
3000b57cec5SDimitry Andric       return {"if", "end_if"};
3010b57cec5SDimitry Andric     case Else:
3020b57cec5SDimitry Andric       return {"else", "end_if"};
3030b57cec5SDimitry Andric     default:
3040b57cec5SDimitry Andric       llvm_unreachable("unknown NestingType");
3050b57cec5SDimitry Andric     }
3060b57cec5SDimitry Andric   }
3070b57cec5SDimitry Andric 
30806c3fb27SDimitry Andric   void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) {
30906c3fb27SDimitry Andric     NestingStack.push_back({NT, Sig});
31006c3fb27SDimitry Andric   }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
3130b57cec5SDimitry Andric     if (NestingStack.empty())
3140b57cec5SDimitry Andric       return error(Twine("End of block construct with no start: ") + Ins);
3150b57cec5SDimitry Andric     auto Top = NestingStack.back();
316fe6060f1SDimitry Andric     if (Top.NT != NT1 && Top.NT != NT2)
3170b57cec5SDimitry Andric       return error(Twine("Block construct type mismatch, expected: ") +
318fe6060f1SDimitry Andric                    nestingString(Top.NT).second + ", instead got: " + Ins);
319fe6060f1SDimitry Andric     TC.setLastSig(Top.Sig);
3200b57cec5SDimitry Andric     NestingStack.pop_back();
3210b57cec5SDimitry Andric     return false;
3220b57cec5SDimitry Andric   }
3230b57cec5SDimitry Andric 
32406c3fb27SDimitry Andric   // Pop a NestingType and push a new NestingType with the same signature. Used
32506c3fb27SDimitry Andric   // for if-else and try-catch(_all).
32606c3fb27SDimitry Andric   bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT,
32706c3fb27SDimitry Andric                                    NestingType PushNT) {
32806c3fb27SDimitry Andric     if (NestingStack.empty())
32906c3fb27SDimitry Andric       return error(Twine("End of block construct with no start: ") + Ins);
33006c3fb27SDimitry Andric     auto Sig = NestingStack.back().Sig;
33106c3fb27SDimitry Andric     if (pop(Ins, PopNT))
33206c3fb27SDimitry Andric       return true;
33306c3fb27SDimitry Andric     push(PushNT, Sig);
33406c3fb27SDimitry Andric     return false;
33506c3fb27SDimitry Andric   }
33606c3fb27SDimitry Andric 
337bdd1243dSDimitry Andric   bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) {
3380b57cec5SDimitry Andric     auto Err = !NestingStack.empty();
3390b57cec5SDimitry Andric     while (!NestingStack.empty()) {
3400b57cec5SDimitry Andric       error(Twine("Unmatched block construct(s) at function end: ") +
341bdd1243dSDimitry Andric                 nestingString(NestingStack.back().NT).first,
342bdd1243dSDimitry Andric             Loc);
3430b57cec5SDimitry Andric       NestingStack.pop_back();
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric     return Err;
3460b57cec5SDimitry Andric   }
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   bool isNext(AsmToken::TokenKind Kind) {
3490b57cec5SDimitry Andric     auto Ok = Lexer.is(Kind);
3500b57cec5SDimitry Andric     if (Ok)
3510b57cec5SDimitry Andric       Parser.Lex();
3520b57cec5SDimitry Andric     return Ok;
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   bool expect(AsmToken::TokenKind Kind, const char *KindName) {
3560b57cec5SDimitry Andric     if (!isNext(Kind))
3570b57cec5SDimitry Andric       return error(std::string("Expected ") + KindName + ", instead got: ",
3580b57cec5SDimitry Andric                    Lexer.getTok());
3590b57cec5SDimitry Andric     return false;
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   StringRef expectIdent() {
3630b57cec5SDimitry Andric     if (!Lexer.is(AsmToken::Identifier)) {
3640b57cec5SDimitry Andric       error("Expected identifier, got: ", Lexer.getTok());
3650b57cec5SDimitry Andric       return StringRef();
3660b57cec5SDimitry Andric     }
3670b57cec5SDimitry Andric     auto Name = Lexer.getTok().getString();
3680b57cec5SDimitry Andric     Parser.Lex();
3690b57cec5SDimitry Andric     return Name;
3700b57cec5SDimitry Andric   }
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
3730b57cec5SDimitry Andric     while (Lexer.is(AsmToken::Identifier)) {
374fe6060f1SDimitry Andric       auto Type = WebAssembly::parseType(Lexer.getTok().getString());
3750b57cec5SDimitry Andric       if (!Type)
3760b57cec5SDimitry Andric         return error("unknown type: ", Lexer.getTok());
37781ad6265SDimitry Andric       Types.push_back(*Type);
3780b57cec5SDimitry Andric       Parser.Lex();
3790b57cec5SDimitry Andric       if (!isNext(AsmToken::Comma))
3800b57cec5SDimitry Andric         break;
3810b57cec5SDimitry Andric     }
3820b57cec5SDimitry Andric     return false;
3830b57cec5SDimitry Andric   }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
3860b57cec5SDimitry Andric     auto &Int = Lexer.getTok();
3870b57cec5SDimitry Andric     int64_t Val = Int.getIntVal();
3880b57cec5SDimitry Andric     if (IsNegative)
3890b57cec5SDimitry Andric       Val = -Val;
3908bcb0991SDimitry Andric     Operands.push_back(std::make_unique<WebAssemblyOperand>(
3910b57cec5SDimitry Andric         WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
3920b57cec5SDimitry Andric         WebAssemblyOperand::IntOp{Val}));
3930b57cec5SDimitry Andric     Parser.Lex();
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
3970b57cec5SDimitry Andric     auto &Flt = Lexer.getTok();
3980b57cec5SDimitry Andric     double Val;
3990b57cec5SDimitry Andric     if (Flt.getString().getAsDouble(Val, false))
4000b57cec5SDimitry Andric       return error("Cannot parse real: ", Flt);
4010b57cec5SDimitry Andric     if (IsNegative)
4020b57cec5SDimitry Andric       Val = -Val;
4038bcb0991SDimitry Andric     Operands.push_back(std::make_unique<WebAssemblyOperand>(
4040b57cec5SDimitry Andric         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
4050b57cec5SDimitry Andric         WebAssemblyOperand::FltOp{Val}));
4060b57cec5SDimitry Andric     Parser.Lex();
4070b57cec5SDimitry Andric     return false;
4080b57cec5SDimitry Andric   }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
4110b57cec5SDimitry Andric     if (Lexer.isNot(AsmToken::Identifier))
4120b57cec5SDimitry Andric       return true;
4130b57cec5SDimitry Andric     auto &Flt = Lexer.getTok();
4140b57cec5SDimitry Andric     auto S = Flt.getString();
4150b57cec5SDimitry Andric     double Val;
416fe6060f1SDimitry Andric     if (S.compare_insensitive("infinity") == 0) {
4170b57cec5SDimitry Andric       Val = std::numeric_limits<double>::infinity();
418fe6060f1SDimitry Andric     } else if (S.compare_insensitive("nan") == 0) {
4190b57cec5SDimitry Andric       Val = std::numeric_limits<double>::quiet_NaN();
4200b57cec5SDimitry Andric     } else {
4210b57cec5SDimitry Andric       return true;
4220b57cec5SDimitry Andric     }
4230b57cec5SDimitry Andric     if (IsNegative)
4240b57cec5SDimitry Andric       Val = -Val;
4258bcb0991SDimitry Andric     Operands.push_back(std::make_unique<WebAssemblyOperand>(
4260b57cec5SDimitry Andric         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
4270b57cec5SDimitry Andric         WebAssemblyOperand::FltOp{Val}));
4280b57cec5SDimitry Andric     Parser.Lex();
4290b57cec5SDimitry Andric     return false;
4300b57cec5SDimitry Andric   }
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
4330b57cec5SDimitry Andric     // FIXME: there is probably a cleaner way to do this.
434349cc55cSDimitry Andric     auto IsLoadStore = InstName.contains(".load") ||
435349cc55cSDimitry Andric                        InstName.contains(".store") ||
436349cc55cSDimitry Andric                        InstName.contains("prefetch");
437349cc55cSDimitry Andric     auto IsAtomic = InstName.contains("atomic.");
4380b57cec5SDimitry Andric     if (IsLoadStore || IsAtomic) {
4390b57cec5SDimitry Andric       // Parse load/store operands of the form: offset:p2align=align
4400b57cec5SDimitry Andric       if (IsLoadStore && isNext(AsmToken::Colon)) {
4410b57cec5SDimitry Andric         auto Id = expectIdent();
4420b57cec5SDimitry Andric         if (Id != "p2align")
4430b57cec5SDimitry Andric           return error("Expected p2align, instead got: " + Id);
4440b57cec5SDimitry Andric         if (expect(AsmToken::Equal, "="))
4450b57cec5SDimitry Andric           return true;
4460b57cec5SDimitry Andric         if (!Lexer.is(AsmToken::Integer))
4470b57cec5SDimitry Andric           return error("Expected integer constant");
4480b57cec5SDimitry Andric         parseSingleInteger(false, Operands);
4490b57cec5SDimitry Andric       } else {
450e8d8bef9SDimitry Andric         // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane
451e8d8bef9SDimitry Andric         // index. We need to avoid parsing an extra alignment operand for the
452e8d8bef9SDimitry Andric         // lane index.
453349cc55cSDimitry Andric         auto IsLoadStoreLane = InstName.contains("_lane");
454e8d8bef9SDimitry Andric         if (IsLoadStoreLane && Operands.size() == 4)
455e8d8bef9SDimitry Andric           return false;
4560b57cec5SDimitry Andric         // Alignment not specified (or atomics, must use default alignment).
4570b57cec5SDimitry Andric         // We can't just call WebAssembly::GetDefaultP2Align since we don't have
4580b57cec5SDimitry Andric         // an opcode until after the assembly matcher, so set a default to fix
4590b57cec5SDimitry Andric         // up later.
4600b57cec5SDimitry Andric         auto Tok = Lexer.getTok();
4618bcb0991SDimitry Andric         Operands.push_back(std::make_unique<WebAssemblyOperand>(
4620b57cec5SDimitry Andric             WebAssemblyOperand::Integer, Tok.getLoc(), Tok.getEndLoc(),
4630b57cec5SDimitry Andric             WebAssemblyOperand::IntOp{-1}));
4640b57cec5SDimitry Andric       }
4650b57cec5SDimitry Andric     }
4660b57cec5SDimitry Andric     return false;
4670b57cec5SDimitry Andric   }
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
4708bcb0991SDimitry Andric                            WebAssembly::BlockType BT) {
471fe6060f1SDimitry Andric     if (BT != WebAssembly::BlockType::Void) {
472fe6060f1SDimitry Andric       wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
473fe6060f1SDimitry Andric       TC.setLastSig(Sig);
474fe6060f1SDimitry Andric       NestingStack.back().Sig = Sig;
475fe6060f1SDimitry Andric     }
4768bcb0991SDimitry Andric     Operands.push_back(std::make_unique<WebAssemblyOperand>(
4770b57cec5SDimitry Andric         WebAssemblyOperand::Integer, NameLoc, NameLoc,
4780b57cec5SDimitry Andric         WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
4790b57cec5SDimitry Andric   }
4800b57cec5SDimitry Andric 
481fe6060f1SDimitry Andric   bool parseLimits(wasm::WasmLimits *Limits) {
482fe6060f1SDimitry Andric     auto Tok = Lexer.getTok();
483fe6060f1SDimitry Andric     if (!Tok.is(AsmToken::Integer))
484fe6060f1SDimitry Andric       return error("Expected integer constant, instead got: ", Tok);
485fe6060f1SDimitry Andric     int64_t Val = Tok.getIntVal();
486fe6060f1SDimitry Andric     assert(Val >= 0);
487fe6060f1SDimitry Andric     Limits->Minimum = Val;
488fe6060f1SDimitry Andric     Parser.Lex();
489fe6060f1SDimitry Andric 
490fe6060f1SDimitry Andric     if (isNext(AsmToken::Comma)) {
491fe6060f1SDimitry Andric       Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX;
492fe6060f1SDimitry Andric       auto Tok = Lexer.getTok();
493fe6060f1SDimitry Andric       if (!Tok.is(AsmToken::Integer))
494fe6060f1SDimitry Andric         return error("Expected integer constant, instead got: ", Tok);
495fe6060f1SDimitry Andric       int64_t Val = Tok.getIntVal();
496fe6060f1SDimitry Andric       assert(Val >= 0);
497fe6060f1SDimitry Andric       Limits->Maximum = Val;
498fe6060f1SDimitry Andric       Parser.Lex();
499fe6060f1SDimitry Andric     }
500fe6060f1SDimitry Andric     return false;
501fe6060f1SDimitry Andric   }
502fe6060f1SDimitry Andric 
503fe6060f1SDimitry Andric   bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
504fe6060f1SDimitry Andric     if (STI->checkFeatures("+reference-types")) {
505fe6060f1SDimitry Andric       // If the reference-types feature is enabled, there is an explicit table
506fe6060f1SDimitry Andric       // operand.  To allow the same assembly to be compiled with or without
507fe6060f1SDimitry Andric       // reference types, we allow the operand to be omitted, in which case we
508fe6060f1SDimitry Andric       // default to __indirect_function_table.
509fe6060f1SDimitry Andric       auto &Tok = Lexer.getTok();
510fe6060f1SDimitry Andric       if (Tok.is(AsmToken::Identifier)) {
511fe6060f1SDimitry Andric         auto *Sym =
512*0fca6ea1SDimitry Andric             GetOrCreateFunctionTableSymbol(getContext(), Tok.getString(), is64);
513fe6060f1SDimitry Andric         const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
514fe6060f1SDimitry Andric         *Op = std::make_unique<WebAssemblyOperand>(
515fe6060f1SDimitry Andric             WebAssemblyOperand::Symbol, Tok.getLoc(), Tok.getEndLoc(),
516fe6060f1SDimitry Andric             WebAssemblyOperand::SymOp{Val});
517fe6060f1SDimitry Andric         Parser.Lex();
518fe6060f1SDimitry Andric         return expect(AsmToken::Comma, ",");
519fe6060f1SDimitry Andric       } else {
520fe6060f1SDimitry Andric         const auto *Val =
521fe6060f1SDimitry Andric             MCSymbolRefExpr::create(DefaultFunctionTable, getContext());
522fe6060f1SDimitry Andric         *Op = std::make_unique<WebAssemblyOperand>(
523fe6060f1SDimitry Andric             WebAssemblyOperand::Symbol, SMLoc(), SMLoc(),
524fe6060f1SDimitry Andric             WebAssemblyOperand::SymOp{Val});
525fe6060f1SDimitry Andric         return false;
526fe6060f1SDimitry Andric       }
527fe6060f1SDimitry Andric     } else {
528fe6060f1SDimitry Andric       // For the MVP there is at most one table whose number is 0, but we can't
529fe6060f1SDimitry Andric       // write a table symbol or issue relocations.  Instead we just ensure the
530fe6060f1SDimitry Andric       // table is live and write a zero.
531fe6060f1SDimitry Andric       getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
532fe6060f1SDimitry Andric       *Op = std::make_unique<WebAssemblyOperand>(WebAssemblyOperand::Integer,
533fe6060f1SDimitry Andric                                                  SMLoc(), SMLoc(),
534fe6060f1SDimitry Andric                                                  WebAssemblyOperand::IntOp{0});
535fe6060f1SDimitry Andric       return false;
536fe6060f1SDimitry Andric     }
537fe6060f1SDimitry Andric   }
538fe6060f1SDimitry Andric 
5390b57cec5SDimitry Andric   bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
5400b57cec5SDimitry Andric                         SMLoc NameLoc, OperandVector &Operands) override {
5410b57cec5SDimitry Andric     // Note: Name does NOT point into the sourcecode, but to a local, so
5420b57cec5SDimitry Andric     // use NameLoc instead.
5430b57cec5SDimitry Andric     Name = StringRef(NameLoc.getPointer(), Name.size());
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric     // WebAssembly has instructions with / in them, which AsmLexer parses
5465ffd83dbSDimitry Andric     // as separate tokens, so if we find such tokens immediately adjacent (no
5470b57cec5SDimitry Andric     // whitespace), expand the name to include them:
5480b57cec5SDimitry Andric     for (;;) {
5490b57cec5SDimitry Andric       auto &Sep = Lexer.getTok();
5500b57cec5SDimitry Andric       if (Sep.getLoc().getPointer() != Name.end() ||
5510b57cec5SDimitry Andric           Sep.getKind() != AsmToken::Slash)
5520b57cec5SDimitry Andric         break;
5530b57cec5SDimitry Andric       // Extend name with /
5540b57cec5SDimitry Andric       Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
5550b57cec5SDimitry Andric       Parser.Lex();
5560b57cec5SDimitry Andric       // We must now find another identifier, or error.
5570b57cec5SDimitry Andric       auto &Id = Lexer.getTok();
5580b57cec5SDimitry Andric       if (Id.getKind() != AsmToken::Identifier ||
5590b57cec5SDimitry Andric           Id.getLoc().getPointer() != Name.end())
5600b57cec5SDimitry Andric         return error("Incomplete instruction name: ", Id);
5610b57cec5SDimitry Andric       Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
5620b57cec5SDimitry Andric       Parser.Lex();
5630b57cec5SDimitry Andric     }
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric     // Now construct the name as first operand.
5668bcb0991SDimitry Andric     Operands.push_back(std::make_unique<WebAssemblyOperand>(
5670b57cec5SDimitry Andric         WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
5680b57cec5SDimitry Andric         WebAssemblyOperand::TokOp{Name}));
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric     // If this instruction is part of a control flow structure, ensure
5710b57cec5SDimitry Andric     // proper nesting.
5720b57cec5SDimitry Andric     bool ExpectBlockType = false;
5738bcb0991SDimitry Andric     bool ExpectFuncType = false;
574fe6060f1SDimitry Andric     std::unique_ptr<WebAssemblyOperand> FunctionTable;
5750b57cec5SDimitry Andric     if (Name == "block") {
5760b57cec5SDimitry Andric       push(Block);
5770b57cec5SDimitry Andric       ExpectBlockType = true;
5780b57cec5SDimitry Andric     } else if (Name == "loop") {
5790b57cec5SDimitry Andric       push(Loop);
5800b57cec5SDimitry Andric       ExpectBlockType = true;
5810b57cec5SDimitry Andric     } else if (Name == "try") {
5820b57cec5SDimitry Andric       push(Try);
5830b57cec5SDimitry Andric       ExpectBlockType = true;
5840b57cec5SDimitry Andric     } else if (Name == "if") {
5850b57cec5SDimitry Andric       push(If);
5860b57cec5SDimitry Andric       ExpectBlockType = true;
5870b57cec5SDimitry Andric     } else if (Name == "else") {
58806c3fb27SDimitry Andric       if (popAndPushWithSameSignature(Name, If, Else))
5890b57cec5SDimitry Andric         return true;
5900b57cec5SDimitry Andric     } else if (Name == "catch") {
59106c3fb27SDimitry Andric       if (popAndPushWithSameSignature(Name, Try, Try))
5920b57cec5SDimitry Andric         return true;
593fe6060f1SDimitry Andric     } else if (Name == "catch_all") {
59406c3fb27SDimitry Andric       if (popAndPushWithSameSignature(Name, Try, CatchAll))
595fe6060f1SDimitry Andric         return true;
5960b57cec5SDimitry Andric     } else if (Name == "end_if") {
5970b57cec5SDimitry Andric       if (pop(Name, If, Else))
5980b57cec5SDimitry Andric         return true;
5990b57cec5SDimitry Andric     } else if (Name == "end_try") {
600fe6060f1SDimitry Andric       if (pop(Name, Try, CatchAll))
601fe6060f1SDimitry Andric         return true;
602fe6060f1SDimitry Andric     } else if (Name == "delegate") {
6030b57cec5SDimitry Andric       if (pop(Name, Try))
6040b57cec5SDimitry Andric         return true;
6050b57cec5SDimitry Andric     } else if (Name == "end_loop") {
6060b57cec5SDimitry Andric       if (pop(Name, Loop))
6070b57cec5SDimitry Andric         return true;
6080b57cec5SDimitry Andric     } else if (Name == "end_block") {
6090b57cec5SDimitry Andric       if (pop(Name, Block))
6100b57cec5SDimitry Andric         return true;
6110b57cec5SDimitry Andric     } else if (Name == "end_function") {
6128bcb0991SDimitry Andric       ensureLocals(getStreamer());
6130b57cec5SDimitry Andric       CurrentState = EndFunction;
6140b57cec5SDimitry Andric       if (pop(Name, Function) || ensureEmptyNestingStack())
6150b57cec5SDimitry Andric         return true;
6168bcb0991SDimitry Andric     } else if (Name == "call_indirect" || Name == "return_call_indirect") {
617fe6060f1SDimitry Andric       // These instructions have differing operand orders in the text format vs
618fe6060f1SDimitry Andric       // the binary formats.  The MC instructions follow the binary format, so
619fe6060f1SDimitry Andric       // here we stash away the operand and append it later.
620fe6060f1SDimitry Andric       if (parseFunctionTableOperand(&FunctionTable))
621fe6060f1SDimitry Andric         return true;
6228bcb0991SDimitry Andric       ExpectFuncType = true;
6238bcb0991SDimitry Andric     }
6248bcb0991SDimitry Andric 
6258bcb0991SDimitry Andric     if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) {
6268bcb0991SDimitry Andric       // This has a special TYPEINDEX operand which in text we
6278bcb0991SDimitry Andric       // represent as a signature, such that we can re-build this signature,
6288bcb0991SDimitry Andric       // attach it to an anonymous symbol, which is what WasmObjectWriter
6298bcb0991SDimitry Andric       // expects to be able to recreate the actual unique-ified type indices.
630*0fca6ea1SDimitry Andric       auto &Ctx = getContext();
6318bcb0991SDimitry Andric       auto Loc = Parser.getTok();
632*0fca6ea1SDimitry Andric       auto Signature = Ctx.createWasmSignature();
633*0fca6ea1SDimitry Andric       if (parseSignature(Signature))
6348bcb0991SDimitry Andric         return true;
6358bcb0991SDimitry Andric       // Got signature as block type, don't need more
636*0fca6ea1SDimitry Andric       TC.setLastSig(*Signature);
637fe6060f1SDimitry Andric       if (ExpectBlockType)
638*0fca6ea1SDimitry Andric         NestingStack.back().Sig = *Signature;
63906c3fb27SDimitry Andric       ExpectBlockType = false;
6408bcb0991SDimitry Andric       // The "true" here will cause this to be a nameless symbol.
6418bcb0991SDimitry Andric       MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
6428bcb0991SDimitry Andric       auto *WasmSym = cast<MCSymbolWasm>(Sym);
643*0fca6ea1SDimitry Andric       WasmSym->setSignature(Signature);
6448bcb0991SDimitry Andric       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
6458bcb0991SDimitry Andric       const MCExpr *Expr = MCSymbolRefExpr::create(
6468bcb0991SDimitry Andric           WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
6478bcb0991SDimitry Andric       Operands.push_back(std::make_unique<WebAssemblyOperand>(
6488bcb0991SDimitry Andric           WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
6498bcb0991SDimitry Andric           WebAssemblyOperand::SymOp{Expr}));
6500b57cec5SDimitry Andric     }
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric     while (Lexer.isNot(AsmToken::EndOfStatement)) {
6530b57cec5SDimitry Andric       auto &Tok = Lexer.getTok();
6540b57cec5SDimitry Andric       switch (Tok.getKind()) {
6550b57cec5SDimitry Andric       case AsmToken::Identifier: {
6560b57cec5SDimitry Andric         if (!parseSpecialFloatMaybe(false, Operands))
6570b57cec5SDimitry Andric           break;
6580b57cec5SDimitry Andric         auto &Id = Lexer.getTok();
6590b57cec5SDimitry Andric         if (ExpectBlockType) {
6600b57cec5SDimitry Andric           // Assume this identifier is a block_type.
661fe6060f1SDimitry Andric           auto BT = WebAssembly::parseBlockType(Id.getString());
6628bcb0991SDimitry Andric           if (BT == WebAssembly::BlockType::Invalid)
6630b57cec5SDimitry Andric             return error("Unknown block type: ", Id);
6640b57cec5SDimitry Andric           addBlockTypeOperand(Operands, NameLoc, BT);
6650b57cec5SDimitry Andric           Parser.Lex();
6660b57cec5SDimitry Andric         } else {
6670b57cec5SDimitry Andric           // Assume this identifier is a label.
6680b57cec5SDimitry Andric           const MCExpr *Val;
66981ad6265SDimitry Andric           SMLoc Start = Id.getLoc();
6700b57cec5SDimitry Andric           SMLoc End;
6710b57cec5SDimitry Andric           if (Parser.parseExpression(Val, End))
6720b57cec5SDimitry Andric             return error("Cannot parse symbol: ", Lexer.getTok());
6738bcb0991SDimitry Andric           Operands.push_back(std::make_unique<WebAssemblyOperand>(
67481ad6265SDimitry Andric               WebAssemblyOperand::Symbol, Start, End,
6750b57cec5SDimitry Andric               WebAssemblyOperand::SymOp{Val}));
6760b57cec5SDimitry Andric           if (checkForP2AlignIfLoadStore(Operands, Name))
6770b57cec5SDimitry Andric             return true;
6780b57cec5SDimitry Andric         }
6790b57cec5SDimitry Andric         break;
6800b57cec5SDimitry Andric       }
6810b57cec5SDimitry Andric       case AsmToken::Minus:
6820b57cec5SDimitry Andric         Parser.Lex();
6830b57cec5SDimitry Andric         if (Lexer.is(AsmToken::Integer)) {
6840b57cec5SDimitry Andric           parseSingleInteger(true, Operands);
6850b57cec5SDimitry Andric           if (checkForP2AlignIfLoadStore(Operands, Name))
6860b57cec5SDimitry Andric             return true;
6870b57cec5SDimitry Andric         } else if (Lexer.is(AsmToken::Real)) {
6880b57cec5SDimitry Andric           if (parseSingleFloat(true, Operands))
6890b57cec5SDimitry Andric             return true;
6900b57cec5SDimitry Andric         } else if (!parseSpecialFloatMaybe(true, Operands)) {
6910b57cec5SDimitry Andric         } else {
6920b57cec5SDimitry Andric           return error("Expected numeric constant instead got: ",
6930b57cec5SDimitry Andric                        Lexer.getTok());
6940b57cec5SDimitry Andric         }
6950b57cec5SDimitry Andric         break;
6960b57cec5SDimitry Andric       case AsmToken::Integer:
6970b57cec5SDimitry Andric         parseSingleInteger(false, Operands);
6980b57cec5SDimitry Andric         if (checkForP2AlignIfLoadStore(Operands, Name))
6990b57cec5SDimitry Andric           return true;
7000b57cec5SDimitry Andric         break;
7010b57cec5SDimitry Andric       case AsmToken::Real: {
7020b57cec5SDimitry Andric         if (parseSingleFloat(false, Operands))
7030b57cec5SDimitry Andric           return true;
7040b57cec5SDimitry Andric         break;
7050b57cec5SDimitry Andric       }
7060b57cec5SDimitry Andric       case AsmToken::LCurly: {
7070b57cec5SDimitry Andric         Parser.Lex();
7088bcb0991SDimitry Andric         auto Op = std::make_unique<WebAssemblyOperand>(
7090b57cec5SDimitry Andric             WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
7100b57cec5SDimitry Andric         if (!Lexer.is(AsmToken::RCurly))
7110b57cec5SDimitry Andric           for (;;) {
7120b57cec5SDimitry Andric             Op->BrL.List.push_back(Lexer.getTok().getIntVal());
7130b57cec5SDimitry Andric             expect(AsmToken::Integer, "integer");
7140b57cec5SDimitry Andric             if (!isNext(AsmToken::Comma))
7150b57cec5SDimitry Andric               break;
7160b57cec5SDimitry Andric           }
7170b57cec5SDimitry Andric         expect(AsmToken::RCurly, "}");
7180b57cec5SDimitry Andric         Operands.push_back(std::move(Op));
7190b57cec5SDimitry Andric         break;
7200b57cec5SDimitry Andric       }
7210b57cec5SDimitry Andric       default:
7220b57cec5SDimitry Andric         return error("Unexpected token in operand: ", Tok);
7230b57cec5SDimitry Andric       }
7240b57cec5SDimitry Andric       if (Lexer.isNot(AsmToken::EndOfStatement)) {
7250b57cec5SDimitry Andric         if (expect(AsmToken::Comma, ","))
7260b57cec5SDimitry Andric           return true;
7270b57cec5SDimitry Andric       }
7280b57cec5SDimitry Andric     }
7290b57cec5SDimitry Andric     if (ExpectBlockType && Operands.size() == 1) {
7300b57cec5SDimitry Andric       // Support blocks with no operands as default to void.
7318bcb0991SDimitry Andric       addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
7320b57cec5SDimitry Andric     }
733fe6060f1SDimitry Andric     if (FunctionTable)
734fe6060f1SDimitry Andric       Operands.push_back(std::move(FunctionTable));
7350b57cec5SDimitry Andric     Parser.Lex();
7360b57cec5SDimitry Andric     return false;
7370b57cec5SDimitry Andric   }
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   bool parseSignature(wasm::WasmSignature *Signature) {
7400b57cec5SDimitry Andric     if (expect(AsmToken::LParen, "("))
7410b57cec5SDimitry Andric       return true;
7420b57cec5SDimitry Andric     if (parseRegTypeList(Signature->Params))
7430b57cec5SDimitry Andric       return true;
7440b57cec5SDimitry Andric     if (expect(AsmToken::RParen, ")"))
7450b57cec5SDimitry Andric       return true;
7460b57cec5SDimitry Andric     if (expect(AsmToken::MinusGreater, "->"))
7470b57cec5SDimitry Andric       return true;
7480b57cec5SDimitry Andric     if (expect(AsmToken::LParen, "("))
7490b57cec5SDimitry Andric       return true;
7500b57cec5SDimitry Andric     if (parseRegTypeList(Signature->Returns))
7510b57cec5SDimitry Andric       return true;
7520b57cec5SDimitry Andric     if (expect(AsmToken::RParen, ")"))
7530b57cec5SDimitry Andric       return true;
7540b57cec5SDimitry Andric     return false;
7550b57cec5SDimitry Andric   }
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   bool CheckDataSection() {
7580b57cec5SDimitry Andric     if (CurrentState != DataSection) {
759*0fca6ea1SDimitry Andric       auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSectionOnly());
760*0fca6ea1SDimitry Andric       if (WS && WS->isText())
7610b57cec5SDimitry Andric         return error("data directive must occur in a data segment: ",
7620b57cec5SDimitry Andric                      Lexer.getTok());
7630b57cec5SDimitry Andric     }
7640b57cec5SDimitry Andric     CurrentState = DataSection;
7650b57cec5SDimitry Andric     return false;
7660b57cec5SDimitry Andric   }
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   // This function processes wasm-specific directives streamed to
7690b57cec5SDimitry Andric   // WebAssemblyTargetStreamer, all others go to the generic parser
7700b57cec5SDimitry Andric   // (see WasmAsmParser).
77106c3fb27SDimitry Andric   ParseStatus parseDirective(AsmToken DirectiveID) override {
7720b57cec5SDimitry Andric     assert(DirectiveID.getKind() == AsmToken::Identifier);
7730b57cec5SDimitry Andric     auto &Out = getStreamer();
7740b57cec5SDimitry Andric     auto &TOut =
7750b57cec5SDimitry Andric         reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
7760b57cec5SDimitry Andric     auto &Ctx = Out.getContext();
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric     if (DirectiveID.getString() == ".globaltype") {
7790b57cec5SDimitry Andric       auto SymName = expectIdent();
7800b57cec5SDimitry Andric       if (SymName.empty())
78106c3fb27SDimitry Andric         return ParseStatus::Failure;
7820b57cec5SDimitry Andric       if (expect(AsmToken::Comma, ","))
78306c3fb27SDimitry Andric         return ParseStatus::Failure;
7840b57cec5SDimitry Andric       auto TypeTok = Lexer.getTok();
7850b57cec5SDimitry Andric       auto TypeName = expectIdent();
7860b57cec5SDimitry Andric       if (TypeName.empty())
78706c3fb27SDimitry Andric         return ParseStatus::Failure;
788fe6060f1SDimitry Andric       auto Type = WebAssembly::parseType(TypeName);
7890b57cec5SDimitry Andric       if (!Type)
7900b57cec5SDimitry Andric         return error("Unknown type in .globaltype directive: ", TypeTok);
791e8d8bef9SDimitry Andric       // Optional mutable modifier. Default to mutable for historical reasons.
792e8d8bef9SDimitry Andric       // Ideally we would have gone with immutable as the default and used `mut`
793e8d8bef9SDimitry Andric       // as the modifier to match the `.wat` format.
794e8d8bef9SDimitry Andric       bool Mutable = true;
795e8d8bef9SDimitry Andric       if (isNext(AsmToken::Comma)) {
796e8d8bef9SDimitry Andric         TypeTok = Lexer.getTok();
797e8d8bef9SDimitry Andric         auto Id = expectIdent();
79806c3fb27SDimitry Andric         if (Id.empty())
79906c3fb27SDimitry Andric           return ParseStatus::Failure;
800e8d8bef9SDimitry Andric         if (Id == "immutable")
801e8d8bef9SDimitry Andric           Mutable = false;
802e8d8bef9SDimitry Andric         else
803e8d8bef9SDimitry Andric           // Should we also allow `mutable` and `mut` here for clarity?
804e8d8bef9SDimitry Andric           return error("Unknown type in .globaltype modifier: ", TypeTok);
805e8d8bef9SDimitry Andric       }
8060b57cec5SDimitry Andric       // Now set this symbol with the correct type.
8070b57cec5SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
8080b57cec5SDimitry Andric       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
80981ad6265SDimitry Andric       WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
8100b57cec5SDimitry Andric       // And emit the directive again.
8110b57cec5SDimitry Andric       TOut.emitGlobalType(WasmSym);
8120b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
8130b57cec5SDimitry Andric     }
8140b57cec5SDimitry Andric 
815e8d8bef9SDimitry Andric     if (DirectiveID.getString() == ".tabletype") {
816fe6060f1SDimitry Andric       // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
817e8d8bef9SDimitry Andric       auto SymName = expectIdent();
818e8d8bef9SDimitry Andric       if (SymName.empty())
81906c3fb27SDimitry Andric         return ParseStatus::Failure;
820e8d8bef9SDimitry Andric       if (expect(AsmToken::Comma, ","))
82106c3fb27SDimitry Andric         return ParseStatus::Failure;
822fe6060f1SDimitry Andric 
823fe6060f1SDimitry Andric       auto ElemTypeTok = Lexer.getTok();
824fe6060f1SDimitry Andric       auto ElemTypeName = expectIdent();
825fe6060f1SDimitry Andric       if (ElemTypeName.empty())
82606c3fb27SDimitry Andric         return ParseStatus::Failure;
827bdd1243dSDimitry Andric       std::optional<wasm::ValType> ElemType =
828bdd1243dSDimitry Andric           WebAssembly::parseType(ElemTypeName);
829fe6060f1SDimitry Andric       if (!ElemType)
830fe6060f1SDimitry Andric         return error("Unknown type in .tabletype directive: ", ElemTypeTok);
831fe6060f1SDimitry Andric 
832fe6060f1SDimitry Andric       wasm::WasmLimits Limits = DefaultLimits();
833fe6060f1SDimitry Andric       if (isNext(AsmToken::Comma) && parseLimits(&Limits))
83406c3fb27SDimitry Andric         return ParseStatus::Failure;
835e8d8bef9SDimitry Andric 
836e8d8bef9SDimitry Andric       // Now that we have the name and table type, we can actually create the
837e8d8bef9SDimitry Andric       // symbol
838e8d8bef9SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
839e8d8bef9SDimitry Andric       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
840*0fca6ea1SDimitry Andric       if (is64) {
841*0fca6ea1SDimitry Andric         Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64;
842*0fca6ea1SDimitry Andric       }
8437a6dacacSDimitry Andric       wasm::WasmTableType Type = {*ElemType, Limits};
844fe6060f1SDimitry Andric       WasmSym->setTableType(Type);
845e8d8bef9SDimitry Andric       TOut.emitTableType(WasmSym);
846e8d8bef9SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
847e8d8bef9SDimitry Andric     }
848e8d8bef9SDimitry Andric 
8490b57cec5SDimitry Andric     if (DirectiveID.getString() == ".functype") {
8500b57cec5SDimitry Andric       // This code has to send things to the streamer similar to
8510b57cec5SDimitry Andric       // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
8520b57cec5SDimitry Andric       // TODO: would be good to factor this into a common function, but the
8530b57cec5SDimitry Andric       // assembler and backend really don't share any common code, and this code
8545ffd83dbSDimitry Andric       // parses the locals separately.
8550b57cec5SDimitry Andric       auto SymName = expectIdent();
8560b57cec5SDimitry Andric       if (SymName.empty())
85706c3fb27SDimitry Andric         return ParseStatus::Failure;
8580b57cec5SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
859fe6060f1SDimitry Andric       if (WasmSym->isDefined()) {
860bdd1243dSDimitry Andric         // We push 'Function' either when a label is parsed or a .functype
861bdd1243dSDimitry Andric         // directive is parsed. The reason it is not easy to do this uniformly
862bdd1243dSDimitry Andric         // in a single place is,
863bdd1243dSDimitry Andric         // 1. We can't do this at label parsing time only because there are
864bdd1243dSDimitry Andric         //    cases we don't have .functype directive before a function label,
865bdd1243dSDimitry Andric         //    in which case we don't know if the label is a function at the time
866bdd1243dSDimitry Andric         //    of parsing.
867bdd1243dSDimitry Andric         // 2. We can't do this at .functype parsing time only because we want to
868bdd1243dSDimitry Andric         //    detect a function started with a label and not ended correctly
869bdd1243dSDimitry Andric         //    without encountering a .functype directive after the label.
870bdd1243dSDimitry Andric         if (CurrentState != FunctionLabel) {
8710b57cec5SDimitry Andric           // This .functype indicates a start of a function.
8720b57cec5SDimitry Andric           if (ensureEmptyNestingStack())
87306c3fb27SDimitry Andric             return ParseStatus::Failure;
874bdd1243dSDimitry Andric           push(Function);
875bdd1243dSDimitry Andric         }
8760b57cec5SDimitry Andric         CurrentState = FunctionStart;
877fe6060f1SDimitry Andric         LastFunctionLabel = WasmSym;
8780b57cec5SDimitry Andric       }
879*0fca6ea1SDimitry Andric       auto Signature = Ctx.createWasmSignature();
880*0fca6ea1SDimitry Andric       if (parseSignature(Signature))
88106c3fb27SDimitry Andric         return ParseStatus::Failure;
882fe6060f1SDimitry Andric       TC.funcDecl(*Signature);
883*0fca6ea1SDimitry Andric       WasmSym->setSignature(Signature);
8840b57cec5SDimitry Andric       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
8850b57cec5SDimitry Andric       TOut.emitFunctionType(WasmSym);
8860b57cec5SDimitry Andric       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
8870b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
8880b57cec5SDimitry Andric     }
8890b57cec5SDimitry Andric 
890480093f4SDimitry Andric     if (DirectiveID.getString() == ".export_name") {
891480093f4SDimitry Andric       auto SymName = expectIdent();
892480093f4SDimitry Andric       if (SymName.empty())
89306c3fb27SDimitry Andric         return ParseStatus::Failure;
894480093f4SDimitry Andric       if (expect(AsmToken::Comma, ","))
89506c3fb27SDimitry Andric         return ParseStatus::Failure;
896480093f4SDimitry Andric       auto ExportName = expectIdent();
89706c3fb27SDimitry Andric       if (ExportName.empty())
89806c3fb27SDimitry Andric         return ParseStatus::Failure;
899480093f4SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
900*0fca6ea1SDimitry Andric       WasmSym->setExportName(Ctx.allocateString(ExportName));
901480093f4SDimitry Andric       TOut.emitExportName(WasmSym, ExportName);
90206c3fb27SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
903480093f4SDimitry Andric     }
904480093f4SDimitry Andric 
905480093f4SDimitry Andric     if (DirectiveID.getString() == ".import_module") {
906480093f4SDimitry Andric       auto SymName = expectIdent();
907480093f4SDimitry Andric       if (SymName.empty())
90806c3fb27SDimitry Andric         return ParseStatus::Failure;
909480093f4SDimitry Andric       if (expect(AsmToken::Comma, ","))
91006c3fb27SDimitry Andric         return ParseStatus::Failure;
911480093f4SDimitry Andric       auto ImportModule = expectIdent();
91206c3fb27SDimitry Andric       if (ImportModule.empty())
91306c3fb27SDimitry Andric         return ParseStatus::Failure;
914480093f4SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
915*0fca6ea1SDimitry Andric       WasmSym->setImportModule(Ctx.allocateString(ImportModule));
916480093f4SDimitry Andric       TOut.emitImportModule(WasmSym, ImportModule);
91706c3fb27SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
918480093f4SDimitry Andric     }
919480093f4SDimitry Andric 
920480093f4SDimitry Andric     if (DirectiveID.getString() == ".import_name") {
921480093f4SDimitry Andric       auto SymName = expectIdent();
922480093f4SDimitry Andric       if (SymName.empty())
92306c3fb27SDimitry Andric         return ParseStatus::Failure;
924480093f4SDimitry Andric       if (expect(AsmToken::Comma, ","))
92506c3fb27SDimitry Andric         return ParseStatus::Failure;
926480093f4SDimitry Andric       auto ImportName = expectIdent();
92706c3fb27SDimitry Andric       if (ImportName.empty())
92806c3fb27SDimitry Andric         return ParseStatus::Failure;
929480093f4SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
930*0fca6ea1SDimitry Andric       WasmSym->setImportName(Ctx.allocateString(ImportName));
931480093f4SDimitry Andric       TOut.emitImportName(WasmSym, ImportName);
93206c3fb27SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
933480093f4SDimitry Andric     }
934480093f4SDimitry Andric 
935fe6060f1SDimitry Andric     if (DirectiveID.getString() == ".tagtype") {
9360b57cec5SDimitry Andric       auto SymName = expectIdent();
9370b57cec5SDimitry Andric       if (SymName.empty())
93806c3fb27SDimitry Andric         return ParseStatus::Failure;
9390b57cec5SDimitry Andric       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
940*0fca6ea1SDimitry Andric       auto Signature = Ctx.createWasmSignature();
9410b57cec5SDimitry Andric       if (parseRegTypeList(Signature->Params))
94206c3fb27SDimitry Andric         return ParseStatus::Failure;
943*0fca6ea1SDimitry Andric       WasmSym->setSignature(Signature);
944fe6060f1SDimitry Andric       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
945fe6060f1SDimitry Andric       TOut.emitTagType(WasmSym);
9460b57cec5SDimitry Andric       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
9470b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
9480b57cec5SDimitry Andric     }
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric     if (DirectiveID.getString() == ".local") {
9510b57cec5SDimitry Andric       if (CurrentState != FunctionStart)
952fe6060f1SDimitry Andric         return error(".local directive should follow the start of a function: ",
9530b57cec5SDimitry Andric                      Lexer.getTok());
9540b57cec5SDimitry Andric       SmallVector<wasm::ValType, 4> Locals;
9550b57cec5SDimitry Andric       if (parseRegTypeList(Locals))
95606c3fb27SDimitry Andric         return ParseStatus::Failure;
957fe6060f1SDimitry Andric       TC.localDecl(Locals);
9580b57cec5SDimitry Andric       TOut.emitLocal(Locals);
9590b57cec5SDimitry Andric       CurrentState = FunctionLocals;
9600b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
9610b57cec5SDimitry Andric     }
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric     if (DirectiveID.getString() == ".int8" ||
9640b57cec5SDimitry Andric         DirectiveID.getString() == ".int16" ||
9650b57cec5SDimitry Andric         DirectiveID.getString() == ".int32" ||
9660b57cec5SDimitry Andric         DirectiveID.getString() == ".int64") {
96706c3fb27SDimitry Andric       if (CheckDataSection())
96806c3fb27SDimitry Andric         return ParseStatus::Failure;
9690b57cec5SDimitry Andric       const MCExpr *Val;
9700b57cec5SDimitry Andric       SMLoc End;
9710b57cec5SDimitry Andric       if (Parser.parseExpression(Val, End))
9720b57cec5SDimitry Andric         return error("Cannot parse .int expression: ", Lexer.getTok());
9730b57cec5SDimitry Andric       size_t NumBits = 0;
9740b57cec5SDimitry Andric       DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
9755ffd83dbSDimitry Andric       Out.emitValue(Val, NumBits / 8, End);
9760b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
9770b57cec5SDimitry Andric     }
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric     if (DirectiveID.getString() == ".asciz") {
98006c3fb27SDimitry Andric       if (CheckDataSection())
98106c3fb27SDimitry Andric         return ParseStatus::Failure;
9820b57cec5SDimitry Andric       std::string S;
9830b57cec5SDimitry Andric       if (Parser.parseEscapedString(S))
9840b57cec5SDimitry Andric         return error("Cannot parse string constant: ", Lexer.getTok());
9855ffd83dbSDimitry Andric       Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
9860b57cec5SDimitry Andric       return expect(AsmToken::EndOfStatement, "EOL");
9870b57cec5SDimitry Andric     }
9880b57cec5SDimitry Andric 
98906c3fb27SDimitry Andric     return ParseStatus::NoMatch; // We didn't process this directive.
9900b57cec5SDimitry Andric   }
9910b57cec5SDimitry Andric 
9928bcb0991SDimitry Andric   // Called either when the first instruction is parsed of the function ends.
9938bcb0991SDimitry Andric   void ensureLocals(MCStreamer &Out) {
9948bcb0991SDimitry Andric     if (CurrentState == FunctionStart) {
9958bcb0991SDimitry Andric       // We haven't seen a .local directive yet. The streamer requires locals to
9968bcb0991SDimitry Andric       // be encoded as a prelude to the instructions, so emit an empty list of
9978bcb0991SDimitry Andric       // locals here.
9988bcb0991SDimitry Andric       auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
9998bcb0991SDimitry Andric           *Out.getTargetStreamer());
10008bcb0991SDimitry Andric       TOut.emitLocal(SmallVector<wasm::ValType, 0>());
10018bcb0991SDimitry Andric       CurrentState = FunctionLocals;
10028bcb0991SDimitry Andric     }
10038bcb0991SDimitry Andric   }
10048bcb0991SDimitry Andric 
10050b57cec5SDimitry Andric   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
10060b57cec5SDimitry Andric                                OperandVector &Operands, MCStreamer &Out,
10070b57cec5SDimitry Andric                                uint64_t &ErrorInfo,
10080b57cec5SDimitry Andric                                bool MatchingInlineAsm) override {
10090b57cec5SDimitry Andric     MCInst Inst;
10108bcb0991SDimitry Andric     Inst.setLoc(IDLoc);
1011e8d8bef9SDimitry Andric     FeatureBitset MissingFeatures;
1012e8d8bef9SDimitry Andric     unsigned MatchResult = MatchInstructionImpl(
1013e8d8bef9SDimitry Andric         Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
10140b57cec5SDimitry Andric     switch (MatchResult) {
10150b57cec5SDimitry Andric     case Match_Success: {
10168bcb0991SDimitry Andric       ensureLocals(Out);
10170b57cec5SDimitry Andric       // Fix unknown p2align operands.
10180b57cec5SDimitry Andric       auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
10190b57cec5SDimitry Andric       if (Align != -1U) {
10200b57cec5SDimitry Andric         auto &Op0 = Inst.getOperand(0);
10210b57cec5SDimitry Andric         if (Op0.getImm() == -1)
10220b57cec5SDimitry Andric           Op0.setImm(Align);
10230b57cec5SDimitry Andric       }
1024fe6060f1SDimitry Andric       if (is64) {
10255ffd83dbSDimitry Andric         // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
10265ffd83dbSDimitry Andric         // an offset64 arg instead of offset32, but to the assembler matcher
10275ffd83dbSDimitry Andric         // they're both immediates so don't get selected for.
10285ffd83dbSDimitry Andric         auto Opc64 = WebAssembly::getWasm64Opcode(
10295ffd83dbSDimitry Andric             static_cast<uint16_t>(Inst.getOpcode()));
10305ffd83dbSDimitry Andric         if (Opc64 >= 0) {
10315ffd83dbSDimitry Andric           Inst.setOpcode(Opc64);
10325ffd83dbSDimitry Andric         }
10335ffd83dbSDimitry Andric       }
103481ad6265SDimitry Andric       if (!SkipTypeCheck && TC.typeCheck(IDLoc, Inst, Operands))
1035fe6060f1SDimitry Andric         return true;
10365ffd83dbSDimitry Andric       Out.emitInstruction(Inst, getSTI());
10370b57cec5SDimitry Andric       if (CurrentState == EndFunction) {
1038fe6060f1SDimitry Andric         onEndOfFunction(IDLoc);
10390b57cec5SDimitry Andric       } else {
10400b57cec5SDimitry Andric         CurrentState = Instructions;
10410b57cec5SDimitry Andric       }
10420b57cec5SDimitry Andric       return false;
10430b57cec5SDimitry Andric     }
1044e8d8bef9SDimitry Andric     case Match_MissingFeature: {
1045e8d8bef9SDimitry Andric       assert(MissingFeatures.count() > 0 && "Expected missing features");
1046e8d8bef9SDimitry Andric       SmallString<128> Message;
1047e8d8bef9SDimitry Andric       raw_svector_ostream OS(Message);
1048e8d8bef9SDimitry Andric       OS << "instruction requires:";
1049e8d8bef9SDimitry Andric       for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)
1050e8d8bef9SDimitry Andric         if (MissingFeatures.test(i))
1051e8d8bef9SDimitry Andric           OS << ' ' << getSubtargetFeatureName(i);
1052e8d8bef9SDimitry Andric       return Parser.Error(IDLoc, Message);
1053e8d8bef9SDimitry Andric     }
10540b57cec5SDimitry Andric     case Match_MnemonicFail:
10550b57cec5SDimitry Andric       return Parser.Error(IDLoc, "invalid instruction");
10560b57cec5SDimitry Andric     case Match_NearMisses:
10570b57cec5SDimitry Andric       return Parser.Error(IDLoc, "ambiguous instruction");
10580b57cec5SDimitry Andric     case Match_InvalidTiedOperand:
10590b57cec5SDimitry Andric     case Match_InvalidOperand: {
10600b57cec5SDimitry Andric       SMLoc ErrorLoc = IDLoc;
10610b57cec5SDimitry Andric       if (ErrorInfo != ~0ULL) {
10620b57cec5SDimitry Andric         if (ErrorInfo >= Operands.size())
10630b57cec5SDimitry Andric           return Parser.Error(IDLoc, "too few operands for instruction");
10640b57cec5SDimitry Andric         ErrorLoc = Operands[ErrorInfo]->getStartLoc();
10650b57cec5SDimitry Andric         if (ErrorLoc == SMLoc())
10660b57cec5SDimitry Andric           ErrorLoc = IDLoc;
10670b57cec5SDimitry Andric       }
10680b57cec5SDimitry Andric       return Parser.Error(ErrorLoc, "invalid operand for instruction");
10690b57cec5SDimitry Andric     }
10700b57cec5SDimitry Andric     }
10710b57cec5SDimitry Andric     llvm_unreachable("Implement any new match types added!");
10720b57cec5SDimitry Andric   }
10730b57cec5SDimitry Andric 
1074bdd1243dSDimitry Andric   void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {
1075fe6060f1SDimitry Andric     // Code below only applies to labels in text sections.
1076*0fca6ea1SDimitry Andric     auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSectionOnly());
1077*0fca6ea1SDimitry Andric     if (!CWS->isText())
1078fe6060f1SDimitry Andric       return;
1079fe6060f1SDimitry Andric 
1080fe6060f1SDimitry Andric     auto WasmSym = cast<MCSymbolWasm>(Symbol);
1081fe6060f1SDimitry Andric     // Unlike other targets, we don't allow data in text sections (labels
1082fe6060f1SDimitry Andric     // declared with .type @object).
1083fe6060f1SDimitry Andric     if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {
1084bdd1243dSDimitry Andric       Parser.Error(IDLoc,
1085fe6060f1SDimitry Andric                    "Wasm doesn\'t support data symbols in text sections");
1086fe6060f1SDimitry Andric       return;
1087fe6060f1SDimitry Andric     }
1088fe6060f1SDimitry Andric 
10890b57cec5SDimitry Andric     // Start a new section for the next function automatically, since our
10900b57cec5SDimitry Andric     // object writer expects each function to have its own section. This way
10910b57cec5SDimitry Andric     // The user can't forget this "convention".
10920b57cec5SDimitry Andric     auto SymName = Symbol->getName();
10935f757f3fSDimitry Andric     if (SymName.starts_with(".L"))
10940b57cec5SDimitry Andric       return; // Local Symbol.
1095e8d8bef9SDimitry Andric 
1096e8d8bef9SDimitry Andric     // TODO: If the user explicitly creates a new function section, we ignore
1097e8d8bef9SDimitry Andric     // its name when we create this one. It would be nice to honor their
1098e8d8bef9SDimitry Andric     // choice, while still ensuring that we create one if they forget.
1099e8d8bef9SDimitry Andric     // (that requires coordination with WasmAsmParser::parseSectionDirective)
11000b57cec5SDimitry Andric     auto SecName = ".text." + SymName;
1101e8d8bef9SDimitry Andric 
1102e8d8bef9SDimitry Andric     auto *Group = CWS->getGroup();
1103e8d8bef9SDimitry Andric     // If the current section is a COMDAT, also set the flag on the symbol.
1104e8d8bef9SDimitry Andric     // TODO: Currently the only place that the symbols' comdat flag matters is
1105e8d8bef9SDimitry Andric     // for importing comdat functions. But there's no way to specify that in
1106e8d8bef9SDimitry Andric     // assembly currently.
1107e8d8bef9SDimitry Andric     if (Group)
1108fe6060f1SDimitry Andric       WasmSym->setComdat(true);
1109*0fca6ea1SDimitry Andric     auto *WS = getContext().getWasmSection(SecName, SectionKind::getText(), 0,
1110*0fca6ea1SDimitry Andric                                            Group, MCContext::GenericSectionID);
111181ad6265SDimitry Andric     getStreamer().switchSection(WS);
11125ffd83dbSDimitry Andric     // Also generate DWARF for this section if requested.
11135ffd83dbSDimitry Andric     if (getContext().getGenDwarfForAssembly())
11145ffd83dbSDimitry Andric       getContext().addGenDwarfSection(WS);
1115bdd1243dSDimitry Andric 
1116bdd1243dSDimitry Andric     if (WasmSym->isFunction()) {
1117bdd1243dSDimitry Andric       // We give the location of the label (IDLoc) here, because otherwise the
1118bdd1243dSDimitry Andric       // lexer's next location will be used, which can be confusing. For
1119bdd1243dSDimitry Andric       // example:
1120bdd1243dSDimitry Andric       //
1121bdd1243dSDimitry Andric       // test0: ; This function does not end properly
1122bdd1243dSDimitry Andric       //   ...
1123bdd1243dSDimitry Andric       //
1124bdd1243dSDimitry Andric       // test1: ; We would like to point to this line for error
1125bdd1243dSDimitry Andric       //   ...  . Not this line, which can contain any instruction
1126bdd1243dSDimitry Andric       ensureEmptyNestingStack(IDLoc);
1127bdd1243dSDimitry Andric       CurrentState = FunctionLabel;
1128bdd1243dSDimitry Andric       LastFunctionLabel = Symbol;
1129bdd1243dSDimitry Andric       push(Function);
1130bdd1243dSDimitry Andric     }
11310b57cec5SDimitry Andric   }
11320b57cec5SDimitry Andric 
1133fe6060f1SDimitry Andric   void onEndOfFunction(SMLoc ErrorLoc) {
113481ad6265SDimitry Andric     if (!SkipTypeCheck)
1135fe6060f1SDimitry Andric       TC.endOfFunction(ErrorLoc);
1136349cc55cSDimitry Andric     // Reset the type checker state.
1137349cc55cSDimitry Andric     TC.Clear();
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric 
11400b57cec5SDimitry Andric   void onEndOfFile() override { ensureEmptyNestingStack(); }
11410b57cec5SDimitry Andric };
11420b57cec5SDimitry Andric } // end anonymous namespace
11430b57cec5SDimitry Andric 
11440b57cec5SDimitry Andric // Force static initialization.
1145480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser() {
11460b57cec5SDimitry Andric   RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
11470b57cec5SDimitry Andric   RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric #define GET_REGISTER_MATCHER
1151e8d8bef9SDimitry Andric #define GET_SUBTARGET_FEATURE_NAME
11520b57cec5SDimitry Andric #define GET_MATCHER_IMPLEMENTATION
11530b57cec5SDimitry Andric #include "WebAssemblyGenAsmMatcher.inc"
1154fe6060f1SDimitry Andric 
1155fe6060f1SDimitry Andric StringRef GetMnemonic(unsigned Opc) {
1156fe6060f1SDimitry Andric   // FIXME: linear search!
1157fe6060f1SDimitry Andric   for (auto &ME : MatchTable0) {
1158fe6060f1SDimitry Andric     if (ME.Opcode == Opc) {
1159fe6060f1SDimitry Andric       return ME.getMnemonic();
1160fe6060f1SDimitry Andric     }
1161fe6060f1SDimitry Andric   }
1162fe6060f1SDimitry Andric   assert(false && "mnemonic not found");
1163fe6060f1SDimitry Andric   return StringRef();
1164fe6060f1SDimitry Andric }
1165