brintos

brintos / llvm-project-archived public Read only

0
0
Text · 46.1 KiB · 9175b27 Raw
1319 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// 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 38using namespace llvm;39 40#define DEBUG_TYPE "wasm-asm-parser"41 42static const char *getSubtargetFeatureName(uint64_t Val);43 44namespace {45 46/// WebAssemblyOperand - Instances of this class represent the operands in a47/// parsed Wasm machine instruction.48struct 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() override {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    else145      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    else154      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    else162      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.208static wasm::WasmLimits defaultLimits() {209  return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0, 0};210}211 212static MCSymbolWasm *getOrCreateFunctionTableSymbol(MCContext &Ctx,213                                                    const StringRef &Name,214                                                    bool Is64) {215  auto *Sym = static_cast<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 = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));221    Sym->setFunctionTable(Is64);222    // The default function table is synthesized by the linker.223  }224  return Sym;225}226 227class WebAssemblyAsmParser final : public MCTargetAsmParser {228  MCAsmParser &Parser;229  AsmLexer &Lexer;230 231  // Order of labels, directives and instructions in a .s file have no232  // syntactical enforcement. This class is a callback from the actual parser,233  // and yet we have to be feeding data to the streamer in a very particular234  // order to ensure a correct binary encoding that matches the regular backend235  // (the streamer does not enforce this). This "state machine" enum helps236  // guarantee that correct order.237  enum ParserState {238    FileStart,239    FunctionLabel,240    FunctionStart,241    FunctionLocals,242    Instructions,243    EndFunction,244    DataSection,245  } CurrentState = FileStart;246 247  // For ensuring blocks are properly nested.248  enum NestingType {249    Function,250    Block,251    Loop,252    Try,253    CatchAll,254    TryTable,255    If,256    Else,257    Undefined,258  };259  struct Nested {260    NestingType NT;261    wasm::WasmSignature Sig;262  };263  std::vector<Nested> NestingStack;264 265  MCSymbolWasm *DefaultFunctionTable = nullptr;266  MCSymbol *LastFunctionLabel = nullptr;267 268  bool Is64;269 270  WebAssemblyAsmTypeCheck TC;271  // Don't type check if -no-type-check was set.272  bool SkipTypeCheck;273 274public:275  WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,276                       const MCInstrInfo &MII, const MCTargetOptions &Options)277      : MCTargetAsmParser(Options, STI, MII), Parser(Parser),278        Lexer(Parser.getLexer()), Is64(STI.getTargetTriple().isArch64Bit()),279        TC(Parser, MII, Is64), SkipTypeCheck(Options.MCNoTypeCheck) {280    FeatureBitset FBS = ComputeAvailableFeatures(STI.getFeatureBits());281 282    // bulk-memory implies bulk-memory-opt283    if (FBS.test(WebAssembly::FeatureBulkMemory)) {284      FBS.set(WebAssembly::FeatureBulkMemoryOpt);285    }286    // reference-types implies call-indirect-overlong287    if (FBS.test(WebAssembly::FeatureReferenceTypes)) {288      FBS.set(WebAssembly::FeatureCallIndirectOverlong);289    }290 291    setAvailableFeatures(FBS);292    // Don't type check if this is inline asm, since that is a naked sequence of293    // instructions without a function/locals decl.294    auto &SM = Parser.getSourceManager();295    auto BufferName =296        SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();297    if (BufferName == "<inline asm>")298      SkipTypeCheck = true;299  }300 301  void Initialize(MCAsmParser &Parser) override {302    MCAsmParserExtension::Initialize(Parser);303 304    DefaultFunctionTable = getOrCreateFunctionTableSymbol(305        getContext(), "__indirect_function_table", Is64);306    if (!STI->checkFeatures("+call-indirect-overlong") &&307        !STI->checkFeatures("+reference-types"))308      DefaultFunctionTable->setOmitFromLinkingSection();309  }310 311#define GET_ASSEMBLER_HEADER312#include "WebAssemblyGenAsmMatcher.inc"313 314  // TODO: This is required to be implemented, but appears unused.315  bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override {316    llvm_unreachable("parseRegister is not implemented.");317  }318  ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,319                               SMLoc &EndLoc) override {320    llvm_unreachable("tryParseRegister is not implemented.");321  }322 323  bool error(const Twine &Msg, const AsmToken &Tok) {324    return Parser.Error(Tok.getLoc(), Msg + Tok.getString());325  }326 327  bool error(const Twine &Msg, SMLoc Loc = SMLoc()) {328    return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);329  }330 331  std::pair<StringRef, StringRef> nestingString(NestingType NT) {332    switch (NT) {333    case Function:334      return {"function", "end_function"};335    case Block:336      return {"block", "end_block"};337    case Loop:338      return {"loop", "end_loop"};339    case Try:340      return {"try", "end_try/delegate"};341    case CatchAll:342      return {"catch_all", "end_try"};343    case TryTable:344      return {"try_table", "end_try_table"};345    case If:346      return {"if", "end_if"};347    case Else:348      return {"else", "end_if"};349    default:350      llvm_unreachable("unknown NestingType");351    }352  }353 354  void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) {355    NestingStack.push_back({NT, Sig});356  }357 358  bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {359    if (NestingStack.empty())360      return error(Twine("End of block construct with no start: ") + Ins);361    auto Top = NestingStack.back();362    if (Top.NT != NT1 && Top.NT != NT2)363      return error(Twine("Block construct type mismatch, expected: ") +364                   nestingString(Top.NT).second + ", instead got: " + Ins);365    TC.setLastSig(Top.Sig);366    NestingStack.pop_back();367    return false;368  }369 370  // Pop a NestingType and push a new NestingType with the same signature. Used371  // for if-else and try-catch(_all).372  bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT,373                                   NestingType PushNT) {374    if (NestingStack.empty())375      return error(Twine("End of block construct with no start: ") + Ins);376    auto Sig = NestingStack.back().Sig;377    if (pop(Ins, PopNT))378      return true;379    push(PushNT, Sig);380    return false;381  }382 383  bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) {384    auto Err = !NestingStack.empty();385    while (!NestingStack.empty()) {386      error(Twine("Unmatched block construct(s) at function end: ") +387                nestingString(NestingStack.back().NT).first,388            Loc);389      NestingStack.pop_back();390    }391    return Err;392  }393 394  bool isNext(AsmToken::TokenKind Kind) {395    auto Ok = Lexer.is(Kind);396    if (Ok)397      Parser.Lex();398    return Ok;399  }400 401  bool expect(AsmToken::TokenKind Kind, const char *KindName) {402    if (!isNext(Kind))403      return error(std::string("Expected ") + KindName + ", instead got: ",404                   Lexer.getTok());405    return false;406  }407 408  StringRef expectIdent() {409    if (!Lexer.is(AsmToken::Identifier)) {410      error("Expected identifier, got: ", Lexer.getTok());411      return StringRef();412    }413    auto Name = Lexer.getTok().getString();414    Parser.Lex();415    return Name;416  }417 418  bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {419    while (Lexer.is(AsmToken::Identifier)) {420      auto Type = WebAssembly::parseType(Lexer.getTok().getString());421      if (!Type)422        return error("unknown type: ", Lexer.getTok());423      Types.push_back(*Type);424      Parser.Lex();425      if (!isNext(AsmToken::Comma))426        break;427    }428    return false;429  }430 431  void parseSingleInteger(bool IsNegative, OperandVector &Operands) {432    auto &Int = Lexer.getTok();433    int64_t Val = Int.getIntVal();434    if (IsNegative)435      Val = -Val;436    Operands.push_back(std::make_unique<WebAssemblyOperand>(437        Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val}));438    Parser.Lex();439  }440 441  bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {442    auto &Flt = Lexer.getTok();443    double Val;444    if (Flt.getString().getAsDouble(Val, false))445      return error("Cannot parse real: ", Flt);446    if (IsNegative)447      Val = -Val;448    Operands.push_back(std::make_unique<WebAssemblyOperand>(449        Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));450    Parser.Lex();451    return false;452  }453 454  bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {455    if (Lexer.isNot(AsmToken::Identifier))456      return true;457    auto &Flt = Lexer.getTok();458    auto S = Flt.getString();459    double Val;460    if (S.compare_insensitive("infinity") == 0) {461      Val = std::numeric_limits<double>::infinity();462    } else if (S.compare_insensitive("nan") == 0) {463      Val = std::numeric_limits<double>::quiet_NaN();464    } else {465      return true;466    }467    if (IsNegative)468      Val = -Val;469    Operands.push_back(std::make_unique<WebAssemblyOperand>(470        Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val}));471    Parser.Lex();472    return false;473  }474 475  bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {476    // FIXME: there is probably a cleaner way to do this.477    auto IsLoadStore = InstName.contains(".load") ||478                       InstName.contains(".store") ||479                       InstName.contains("prefetch");480    auto IsAtomic = InstName.contains("atomic.");481    if (IsLoadStore || IsAtomic) {482      // Parse load/store operands of the form: offset:p2align=align483      if (IsLoadStore && isNext(AsmToken::Colon)) {484        auto Id = expectIdent();485        if (Id != "p2align")486          return error("Expected p2align, instead got: " + Id);487        if (expect(AsmToken::Equal, "="))488          return true;489        if (!Lexer.is(AsmToken::Integer))490          return error("Expected integer constant");491        parseSingleInteger(false, Operands);492      } else {493        // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane494        // index. We need to avoid parsing an extra alignment operand for the495        // lane index.496        auto IsLoadStoreLane = InstName.contains("_lane");497        if (IsLoadStoreLane && Operands.size() == 4)498          return false;499        // Alignment not specified (or atomics, must use default alignment).500        // We can't just call WebAssembly::GetDefaultP2Align since we don't have501        // an opcode until after the assembly matcher, so set a default to fix502        // up later.503        auto Tok = Lexer.getTok();504        Operands.push_back(std::make_unique<WebAssemblyOperand>(505            Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1}));506      }507    }508    return false;509  }510 511  void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,512                           WebAssembly::BlockType BT) {513    if (BT == WebAssembly::BlockType::Void) {514      TC.setLastSig(wasm::WasmSignature{});515    } else {516      wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});517      TC.setLastSig(Sig);518      NestingStack.back().Sig = Sig;519    }520    Operands.push_back(std::make_unique<WebAssemblyOperand>(521        NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));522  }523 524  bool parseLimits(wasm::WasmLimits *Limits) {525    auto Tok = Lexer.getTok();526    if (!Tok.is(AsmToken::Integer))527      return error("Expected integer constant, instead got: ", Tok);528    int64_t Val = Tok.getIntVal();529    assert(Val >= 0);530    Limits->Minimum = Val;531    Parser.Lex();532 533    if (isNext(AsmToken::Comma)) {534      Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX;535      auto Tok = Lexer.getTok();536      if (!Tok.is(AsmToken::Integer))537        return error("Expected integer constant, instead got: ", Tok);538      int64_t Val = Tok.getIntVal();539      assert(Val >= 0);540      Limits->Maximum = Val;541      Parser.Lex();542    }543    return false;544  }545 546  bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {547    if (STI->checkFeatures("+call-indirect-overlong") ||548        STI->checkFeatures("+reference-types")) {549      // If the call-indirect-overlong feature is enabled, or implied by the550      // reference-types feature, there is an explicit table operand.  To allow551      // the same assembly to be compiled with or without552      // call-indirect-overlong, we allow the operand to be omitted, in which553      // case we default to __indirect_function_table.554      auto &Tok = Lexer.getTok();555      if (Tok.is(AsmToken::Identifier)) {556        auto *Sym =557            getOrCreateFunctionTableSymbol(getContext(), Tok.getString(), Is64);558        const auto *Val = MCSymbolRefExpr::create(Sym, getContext());559        *Op = std::make_unique<WebAssemblyOperand>(560            Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::SymOp{Val});561        Parser.Lex();562        return expect(AsmToken::Comma, ",");563      }564      const auto *Val =565          MCSymbolRefExpr::create(DefaultFunctionTable, getContext());566      *Op = std::make_unique<WebAssemblyOperand>(567          SMLoc(), SMLoc(), WebAssemblyOperand::SymOp{Val});568      return false;569    }570    // For the MVP there is at most one table whose number is 0, but we can't571    // write a table symbol or issue relocations.  Instead we just ensure the572    // table is live and write a zero.573    getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);574    *Op = std::make_unique<WebAssemblyOperand>(SMLoc(), SMLoc(),575                                               WebAssemblyOperand::IntOp{0});576    return false;577  }578 579  bool parseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,580                        SMLoc NameLoc, OperandVector &Operands) override {581    // Note: Name does NOT point into the sourcecode, but to a local, so582    // use NameLoc instead.583    Name = StringRef(NameLoc.getPointer(), Name.size());584 585    // WebAssembly has instructions with / in them, which AsmLexer parses586    // as separate tokens, so if we find such tokens immediately adjacent (no587    // whitespace), expand the name to include them:588    for (;;) {589      auto &Sep = Lexer.getTok();590      if (Sep.getLoc().getPointer() != Name.end() ||591          Sep.getKind() != AsmToken::Slash)592        break;593      // Extend name with /594      Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());595      Parser.Lex();596      // We must now find another identifier, or error.597      auto &Id = Lexer.getTok();598      if (Id.getKind() != AsmToken::Identifier ||599          Id.getLoc().getPointer() != Name.end())600        return error("Incomplete instruction name: ", Id);601      Name = StringRef(Name.begin(), Name.size() + Id.getString().size());602      Parser.Lex();603    }604 605    // Now construct the name as first operand.606    Operands.push_back(std::make_unique<WebAssemblyOperand>(607        NameLoc, SMLoc::getFromPointer(Name.end()),608        WebAssemblyOperand::TokOp{Name}));609 610    // If this instruction is part of a control flow structure, ensure611    // proper nesting.612    bool ExpectBlockType = false;613    bool ExpectFuncType = false;614    bool ExpectCatchList = false;615    std::unique_ptr<WebAssemblyOperand> FunctionTable;616    if (Name == "block") {617      push(Block);618      ExpectBlockType = true;619    } else if (Name == "loop") {620      push(Loop);621      ExpectBlockType = true;622    } else if (Name == "try") {623      push(Try);624      ExpectBlockType = true;625    } else if (Name == "if") {626      push(If);627      ExpectBlockType = true;628    } else if (Name == "else") {629      if (popAndPushWithSameSignature(Name, If, Else))630        return true;631    } else if (Name == "catch") {632      if (popAndPushWithSameSignature(Name, Try, Try))633        return true;634    } else if (Name == "catch_all") {635      if (popAndPushWithSameSignature(Name, Try, CatchAll))636        return true;637    } else if (Name == "try_table") {638      push(TryTable);639      ExpectBlockType = true;640      ExpectCatchList = true;641    } else if (Name == "end_if") {642      if (pop(Name, If, Else))643        return true;644    } else if (Name == "end_try") {645      if (pop(Name, Try, CatchAll))646        return true;647    } else if (Name == "end_try_table") {648      if (pop(Name, TryTable))649        return true;650    } else if (Name == "delegate") {651      if (pop(Name, Try))652        return true;653    } else if (Name == "end_loop") {654      if (pop(Name, Loop))655        return true;656    } else if (Name == "end_block") {657      if (pop(Name, Block))658        return true;659    } else if (Name == "end_function") {660      ensureLocals(getStreamer());661      CurrentState = EndFunction;662      if (pop(Name, Function) || ensureEmptyNestingStack())663        return true;664    } else if (Name == "call_indirect" || Name == "return_call_indirect") {665      // These instructions have differing operand orders in the text format vs666      // the binary formats.  The MC instructions follow the binary format, so667      // here we stash away the operand and append it later.668      if (parseFunctionTableOperand(&FunctionTable))669        return true;670      ExpectFuncType = true;671    } else if (Name == "ref.test") {672      // When we get support for wasm-gc types, this should become673      // ExpectRefType.674      ExpectFuncType = true;675    }676 677    // Returns true if the next tokens are a catch clause678    auto PeekCatchList = [&]() {679      if (Lexer.isNot(AsmToken::LParen))680        return false;681      AsmToken NextTok = Lexer.peekTok();682      return NextTok.getKind() == AsmToken::Identifier &&683             NextTok.getIdentifier().starts_with("catch");684    };685 686    // Parse a multivalue block type687    if (ExpectFuncType ||688        (Lexer.is(AsmToken::LParen) && ExpectBlockType && !PeekCatchList())) {689      // This has a special TYPEINDEX operand which in text we690      // represent as a signature, such that we can re-build this signature,691      // attach it to an anonymous symbol, which is what WasmObjectWriter692      // expects to be able to recreate the actual unique-ified type indices.693      auto &Ctx = getContext();694      auto Loc = Parser.getTok();695      auto *Signature = Ctx.createWasmSignature();696      if (parseSignature(Signature))697        return true;698      // Got signature as block type, don't need more699      TC.setLastSig(*Signature);700      if (ExpectBlockType)701        NestingStack.back().Sig = *Signature;702      ExpectBlockType = false;703      // The "true" here will cause this to be a nameless symbol.704      MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);705      auto *WasmSym = static_cast<MCSymbolWasm *>(Sym);706      WasmSym->setSignature(Signature);707      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);708      const MCExpr *Expr =709          MCSymbolRefExpr::create(WasmSym, WebAssembly::S_TYPEINDEX, Ctx);710      Operands.push_back(std::make_unique<WebAssemblyOperand>(711          Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr}));712    }713 714    // If we are expecting a catch clause list, try to parse it here.715    //716    // If there is a multivalue block return type before this catch list, it717    // should have been parsed above. If there is no return type before718    // encountering this catch list, this means the type is void.719    // The case when there is a single block return value and then a catch list720    // will be handled below in the 'while' loop.721    if (ExpectCatchList && PeekCatchList()) {722      if (ExpectBlockType) {723        ExpectBlockType = false;724        addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);725      }726      if (parseCatchList(Operands))727        return true;728      ExpectCatchList = false;729    }730 731    while (Lexer.isNot(AsmToken::EndOfStatement)) {732      auto &Tok = Lexer.getTok();733      switch (Tok.getKind()) {734      case AsmToken::Identifier: {735        if (!parseSpecialFloatMaybe(false, Operands))736          break;737        auto &Id = Lexer.getTok();738        if (ExpectBlockType) {739          // Assume this identifier is a block_type.740          auto BT = WebAssembly::parseBlockType(Id.getString());741          if (BT == WebAssembly::BlockType::Invalid)742            return error("Unknown block type: ", Id);743          addBlockTypeOperand(Operands, NameLoc, BT);744          ExpectBlockType = false;745          Parser.Lex();746          // Now that we've parsed a single block return type, if we are747          // expecting a catch clause list, try to parse it.748          if (ExpectCatchList && PeekCatchList()) {749            if (parseCatchList(Operands))750              return true;751            ExpectCatchList = false;752          }753        } else {754          // Assume this identifier is a label.755          const MCExpr *Val;756          SMLoc Start = Id.getLoc();757          SMLoc End;758          if (Parser.parseExpression(Val, End))759            return error("Cannot parse symbol: ", Lexer.getTok());760          Operands.push_back(std::make_unique<WebAssemblyOperand>(761              Start, End, WebAssemblyOperand::SymOp{Val}));762          if (checkForP2AlignIfLoadStore(Operands, Name))763            return true;764        }765        break;766      }767      case AsmToken::Minus:768        Parser.Lex();769        if (Lexer.is(AsmToken::Integer)) {770          parseSingleInteger(true, Operands);771          if (checkForP2AlignIfLoadStore(Operands, Name))772            return true;773        } else if (Lexer.is(AsmToken::Real)) {774          if (parseSingleFloat(true, Operands))775            return true;776        } else if (!parseSpecialFloatMaybe(true, Operands)) {777        } else {778          return error("Expected numeric constant instead got: ",779                       Lexer.getTok());780        }781        break;782      case AsmToken::Integer:783        parseSingleInteger(false, Operands);784        if (checkForP2AlignIfLoadStore(Operands, Name))785          return true;786        break;787      case AsmToken::Real: {788        if (parseSingleFloat(false, Operands))789          return true;790        break;791      }792      case AsmToken::LCurly: {793        Parser.Lex();794        auto Op = std::make_unique<WebAssemblyOperand>(795            Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::BrLOp{});796        if (!Lexer.is(AsmToken::RCurly))797          for (;;) {798            Op->BrL.List.push_back(Lexer.getTok().getIntVal());799            expect(AsmToken::Integer, "integer");800            if (!isNext(AsmToken::Comma))801              break;802          }803        expect(AsmToken::RCurly, "}");804        Operands.push_back(std::move(Op));805        break;806      }807      default:808        return error("Unexpected token in operand: ", Tok);809      }810      if (Lexer.isNot(AsmToken::EndOfStatement)) {811        if (expect(AsmToken::Comma, ","))812          return true;813      }814    }815 816    // If we are still expecting to parse a block type or a catch list at this817    // point, we set them to the default/empty state.818 819    // Support blocks with no operands as default to void.820    if (ExpectBlockType)821      addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);822    // If no catch list has been parsed, add an empty catch list operand.823    if (ExpectCatchList)824      Operands.push_back(std::make_unique<WebAssemblyOperand>(825          NameLoc, NameLoc, WebAssemblyOperand::CaLOp{}));826 827    if (FunctionTable)828      Operands.push_back(std::move(FunctionTable));829    Parser.Lex();830    return false;831  }832 833  bool parseSignature(wasm::WasmSignature *Signature) {834    if (expect(AsmToken::LParen, "("))835      return true;836    if (parseRegTypeList(Signature->Params))837      return true;838    if (expect(AsmToken::RParen, ")"))839      return true;840    if (expect(AsmToken::MinusGreater, "->"))841      return true;842    if (expect(AsmToken::LParen, "("))843      return true;844    if (parseRegTypeList(Signature->Returns))845      return true;846    if (expect(AsmToken::RParen, ")"))847      return true;848    return false;849  }850 851  bool parseCatchList(OperandVector &Operands) {852    auto Op = std::make_unique<WebAssemblyOperand>(853        Lexer.getTok().getLoc(), SMLoc(), WebAssemblyOperand::CaLOp{});854    SMLoc EndLoc;855 856    while (Lexer.is(AsmToken::LParen)) {857      if (expect(AsmToken::LParen, "("))858        return true;859 860      auto CatchStr = expectIdent();861      if (CatchStr.empty())862        return true;863      uint8_t CatchOpcode =864          StringSwitch<uint8_t>(CatchStr)865              .Case("catch", wasm::WASM_OPCODE_CATCH)866              .Case("catch_ref", wasm::WASM_OPCODE_CATCH_REF)867              .Case("catch_all", wasm::WASM_OPCODE_CATCH_ALL)868              .Case("catch_all_ref", wasm::WASM_OPCODE_CATCH_ALL_REF)869              .Default(0xff);870      if (CatchOpcode == 0xff)871        return error(872            "Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " +873            CatchStr);874 875      const MCExpr *Tag = nullptr;876      if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||877          CatchOpcode == wasm::WASM_OPCODE_CATCH_REF) {878        if (Parser.parseExpression(Tag))879          return error("Cannot parse symbol: ", Lexer.getTok());880      }881 882      auto &DestTok = Lexer.getTok();883      if (DestTok.isNot(AsmToken::Integer))884        return error("Expected integer constant, instead got: ", DestTok);885      unsigned Dest = DestTok.getIntVal();886      Parser.Lex();887 888      EndLoc = Lexer.getTok().getEndLoc();889      if (expect(AsmToken::RParen, ")"))890        return true;891 892      Op->CaL.List.push_back({CatchOpcode, Tag, Dest});893    }894 895    Op->EndLoc = EndLoc;896    Operands.push_back(std::move(Op));897    return false;898  }899 900  bool checkDataSection() {901    if (CurrentState != DataSection) {902      auto *WS = static_cast<const MCSectionWasm *>(903          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 to913  // WebAssemblyTargetStreamer, all others go to the generic parser914  // (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        else947          // 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 =952          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));953      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);954      WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});955      // And emit the directive again.956      TOut.emitGlobalType(WasmSym);957      return expect(AsmToken::EndOfStatement, "EOL");958    }959 960    if (DirectiveID.getString() == ".tabletype") {961      // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]962      auto SymName = expectIdent();963      if (SymName.empty())964        return ParseStatus::Failure;965      if (expect(AsmToken::Comma, ","))966        return ParseStatus::Failure;967 968      auto ElemTypeTok = Lexer.getTok();969      auto ElemTypeName = expectIdent();970      if (ElemTypeName.empty())971        return ParseStatus::Failure;972      std::optional<wasm::ValType> ElemType =973          WebAssembly::parseType(ElemTypeName);974      if (!ElemType)975        return error("Unknown type in .tabletype directive: ", ElemTypeTok);976 977      wasm::WasmLimits Limits = defaultLimits();978      if (isNext(AsmToken::Comma) && parseLimits(&Limits))979        return ParseStatus::Failure;980 981      // Now that we have the name and table type, we can actually create the982      // symbol983      auto *WasmSym =984          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));985      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);986      if (Is64) {987        Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64;988      }989      wasm::WasmTableType Type = {*ElemType, Limits};990      WasmSym->setTableType(Type);991      TOut.emitTableType(WasmSym);992      return expect(AsmToken::EndOfStatement, "EOL");993    }994 995    if (DirectiveID.getString() == ".functype") {996      // This code has to send things to the streamer similar to997      // WebAssemblyAsmPrinter::EmitFunctionBodyStart.998      // TODO: would be good to factor this into a common function, but the999      // assembler and backend really don't share any common code, and this code1000      // parses the locals separately.1001      auto SymName = expectIdent();1002      if (SymName.empty())1003        return ParseStatus::Failure;1004      auto *WasmSym =1005          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));1006      if (WasmSym->isDefined()) {1007        // We push 'Function' either when a label is parsed or a .functype1008        // directive is parsed. The reason it is not easy to do this uniformly1009        // in a single place is,1010        // 1. We can't do this at label parsing time only because there are1011        //    cases we don't have .functype directive before a function label,1012        //    in which case we don't know if the label is a function at the time1013        //    of parsing.1014        // 2. We can't do this at .functype parsing time only because we want to1015        //    detect a function started with a label and not ended correctly1016        //    without encountering a .functype directive after the label.1017        if (CurrentState != FunctionLabel) {1018          // This .functype indicates a start of a function.1019          if (ensureEmptyNestingStack())1020            return ParseStatus::Failure;1021          push(Function);1022        }1023        CurrentState = FunctionStart;1024        LastFunctionLabel = WasmSym;1025      }1026      auto *Signature = Ctx.createWasmSignature();1027      if (parseSignature(Signature))1028        return ParseStatus::Failure;1029      if (CurrentState == FunctionStart)1030        TC.funcDecl(*Signature);1031      WasmSym->setSignature(Signature);1032      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);1033      TOut.emitFunctionType(WasmSym);1034      // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.1035      return expect(AsmToken::EndOfStatement, "EOL");1036    }1037 1038    if (DirectiveID.getString() == ".export_name") {1039      auto SymName = expectIdent();1040      if (SymName.empty())1041        return ParseStatus::Failure;1042      if (expect(AsmToken::Comma, ","))1043        return ParseStatus::Failure;1044      auto ExportName = expectIdent();1045      if (ExportName.empty())1046        return ParseStatus::Failure;1047      auto *WasmSym =1048          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));1049      WasmSym->setExportName(Ctx.allocateString(ExportName));1050      TOut.emitExportName(WasmSym, ExportName);1051      return expect(AsmToken::EndOfStatement, "EOL");1052    }1053 1054    if (DirectiveID.getString() == ".import_module") {1055      auto SymName = expectIdent();1056      if (SymName.empty())1057        return ParseStatus::Failure;1058      if (expect(AsmToken::Comma, ","))1059        return ParseStatus::Failure;1060      auto ImportModule = expectIdent();1061      if (ImportModule.empty())1062        return ParseStatus::Failure;1063      auto *WasmSym =1064          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));1065      WasmSym->setImportModule(Ctx.allocateString(ImportModule));1066      TOut.emitImportModule(WasmSym, ImportModule);1067      return expect(AsmToken::EndOfStatement, "EOL");1068    }1069 1070    if (DirectiveID.getString() == ".import_name") {1071      auto SymName = expectIdent();1072      if (SymName.empty())1073        return ParseStatus::Failure;1074      if (expect(AsmToken::Comma, ","))1075        return ParseStatus::Failure;1076      auto ImportName = expectIdent();1077      if (ImportName.empty())1078        return ParseStatus::Failure;1079      auto *WasmSym =1080          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));1081      WasmSym->setImportName(Ctx.allocateString(ImportName));1082      TOut.emitImportName(WasmSym, ImportName);1083      return expect(AsmToken::EndOfStatement, "EOL");1084    }1085 1086    if (DirectiveID.getString() == ".tagtype") {1087      auto SymName = expectIdent();1088      if (SymName.empty())1089        return ParseStatus::Failure;1090      auto *WasmSym =1091          static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));1092      auto *Signature = Ctx.createWasmSignature();1093      if (parseRegTypeList(Signature->Params))1094        return ParseStatus::Failure;1095      WasmSym->setSignature(Signature);1096      WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);1097      TOut.emitTagType(WasmSym);1098      // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.1099      return expect(AsmToken::EndOfStatement, "EOL");1100    }1101 1102    if (DirectiveID.getString() == ".local") {1103      if (CurrentState != FunctionStart)1104        return error(".local directive should follow the start of a function: ",1105                     Lexer.getTok());1106      SmallVector<wasm::ValType, 4> Locals;1107      if (parseRegTypeList(Locals))1108        return ParseStatus::Failure;1109      TC.localDecl(Locals);1110      TOut.emitLocal(Locals);1111      CurrentState = FunctionLocals;1112      return expect(AsmToken::EndOfStatement, "EOL");1113    }1114 1115    if (DirectiveID.getString() == ".int8" ||1116        DirectiveID.getString() == ".int16" ||1117        DirectiveID.getString() == ".int32" ||1118        DirectiveID.getString() == ".int64") {1119      if (checkDataSection())1120        return ParseStatus::Failure;1121      const MCExpr *Val;1122      SMLoc End;1123      if (Parser.parseExpression(Val, End))1124        return error("Cannot parse .int expression: ", Lexer.getTok());1125      size_t NumBits = 0;1126      DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);1127      Out.emitValue(Val, NumBits / 8, End);1128      return expect(AsmToken::EndOfStatement, "EOL");1129    }1130 1131    if (DirectiveID.getString() == ".asciz") {1132      if (checkDataSection())1133        return ParseStatus::Failure;1134      std::string S;1135      if (Parser.parseEscapedString(S))1136        return error("Cannot parse string constant: ", Lexer.getTok());1137      Out.emitBytes(StringRef(S.c_str(), S.length() + 1));1138      return expect(AsmToken::EndOfStatement, "EOL");1139    }1140 1141    return ParseStatus::NoMatch; // We didn't process this directive.1142  }1143 1144  // Called either when the first instruction is parsed of the function ends.1145  void ensureLocals(MCStreamer &Out) {1146    if (CurrentState == FunctionStart) {1147      // We haven't seen a .local directive yet. The streamer requires locals to1148      // be encoded as a prelude to the instructions, so emit an empty list of1149      // locals here.1150      auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(1151          *Out.getTargetStreamer());1152      TOut.emitLocal(SmallVector<wasm::ValType, 0>());1153      CurrentState = FunctionLocals;1154    }1155  }1156 1157  bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,1158                               OperandVector &Operands, MCStreamer &Out,1159                               uint64_t &ErrorInfo,1160                               bool MatchingInlineAsm) override {1161    MCInst Inst;1162    Inst.setLoc(IDLoc);1163    FeatureBitset MissingFeatures;1164    unsigned MatchResult = MatchInstructionImpl(1165        Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);1166    switch (MatchResult) {1167    case Match_Success: {1168      ensureLocals(Out);1169      // Fix unknown p2align operands.1170      auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());1171      if (Align != -1U) {1172        auto &Op0 = Inst.getOperand(0);1173        if (Op0.getImm() == -1)1174          Op0.setImm(Align);1175      }1176      if (Is64) {1177        // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having1178        // an offset64 arg instead of offset32, but to the assembler matcher1179        // they're both immediates so don't get selected for.1180        auto Opc64 = WebAssembly::getWasm64Opcode(1181            static_cast<uint16_t>(Inst.getOpcode()));1182        if (Opc64 >= 0) {1183          Inst.setOpcode(Opc64);1184        }1185      }1186      if (!SkipTypeCheck)1187        TC.typeCheck(IDLoc, Inst, Operands);1188      Out.emitInstruction(Inst, getSTI());1189      if (CurrentState == EndFunction) {1190        onEndOfFunction(IDLoc);1191      } else {1192        CurrentState = Instructions;1193      }1194      return false;1195    }1196    case Match_MissingFeature: {1197      assert(MissingFeatures.count() > 0 && "Expected missing features");1198      SmallString<128> Message;1199      raw_svector_ostream OS(Message);1200      OS << "instruction requires:";1201      for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I)1202        if (MissingFeatures.test(I))1203          OS << ' ' << getSubtargetFeatureName(I);1204      return Parser.Error(IDLoc, Message);1205    }1206    case Match_MnemonicFail:1207      return Parser.Error(IDLoc, "invalid instruction");1208    case Match_NearMisses:1209      return Parser.Error(IDLoc, "ambiguous instruction");1210    case Match_InvalidTiedOperand:1211    case Match_InvalidOperand: {1212      SMLoc ErrorLoc = IDLoc;1213      if (ErrorInfo != ~0ULL) {1214        if (ErrorInfo >= Operands.size())1215          return Parser.Error(IDLoc, "too few operands for instruction");1216        ErrorLoc = Operands[ErrorInfo]->getStartLoc();1217        if (ErrorLoc == SMLoc())1218          ErrorLoc = IDLoc;1219      }1220      return Parser.Error(ErrorLoc, "invalid operand for instruction");1221    }1222    }1223    llvm_unreachable("Implement any new match types added!");1224  }1225 1226  void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override {1227    // Code below only applies to labels in text sections.1228    auto *CWS = static_cast<const MCSectionWasm *>(1229        getStreamer().getCurrentSectionOnly());1230    if (!CWS->isText())1231      return;1232 1233    auto *WasmSym = static_cast<MCSymbolWasm *>(Symbol);1234    // Unlike other targets, we don't allow data in text sections (labels1235    // declared with .type @object).1236    if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {1237      Parser.Error(IDLoc,1238                   "Wasm doesn\'t support data symbols in text sections");1239      return;1240    }1241 1242    // Start a new section for the next function automatically, since our1243    // object writer expects each function to have its own section. This way1244    // The user can't forget this "convention".1245    auto SymName = Symbol->getName();1246    if (SymName.starts_with(".L"))1247      return; // Local Symbol.1248 1249    // TODO: If the user explicitly creates a new function section, we ignore1250    // its name when we create this one. It would be nice to honor their1251    // choice, while still ensuring that we create one if they forget.1252    // (that requires coordination with WasmAsmParser::parseSectionDirective)1253    std::string SecName = (".text." + SymName).str();1254 1255    auto *Group = CWS->getGroup();1256    // If the current section is a COMDAT, also set the flag on the symbol.1257    // TODO: Currently the only place that the symbols' comdat flag matters is1258    // for importing comdat functions. But there's no way to specify that in1259    // assembly currently.1260    if (Group)1261      WasmSym->setComdat(true);1262    auto *WS = getContext().getWasmSection(SecName, SectionKind::getText(), 0,1263                                           Group, MCSection::NonUniqueID);1264    getStreamer().switchSection(WS);1265    // Also generate DWARF for this section if requested.1266    if (getContext().getGenDwarfForAssembly())1267      getContext().addGenDwarfSection(WS);1268 1269    if (WasmSym->isFunction()) {1270      // We give the location of the label (IDLoc) here, because otherwise the1271      // lexer's next location will be used, which can be confusing. For1272      // example:1273      //1274      // test0: ; This function does not end properly1275      //   ...1276      //1277      // test1: ; We would like to point to this line for error1278      //   ...  . Not this line, which can contain any instruction1279      ensureEmptyNestingStack(IDLoc);1280      CurrentState = FunctionLabel;1281      LastFunctionLabel = Symbol;1282      push(Function);1283    }1284  }1285 1286  void onEndOfFunction(SMLoc ErrorLoc) {1287    if (!SkipTypeCheck)1288      TC.endOfFunction(ErrorLoc, true);1289    // Reset the type checker state.1290    TC.clear();1291  }1292 1293  void onEndOfFile() override { ensureEmptyNestingStack(); }1294};1295} // end anonymous namespace1296 1297// Force static initialization.1298extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void1299LLVMInitializeWebAssemblyAsmParser() {1300  RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());1301  RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());1302}1303 1304#define GET_REGISTER_MATCHER1305#define GET_SUBTARGET_FEATURE_NAME1306#define GET_MATCHER_IMPLEMENTATION1307#include "WebAssemblyGenAsmMatcher.inc"1308 1309StringRef getMnemonic(unsigned Opc) {1310  // FIXME: linear search!1311  for (auto &ME : MatchTable0) {1312    if (ME.Opcode == Opc) {1313      return ME.getMnemonic();1314    }1315  }1316  assert(false && "mnemonic not found");1317  return StringRef();1318}1319