1e4825975SDerek Schuff //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==//
2e4825975SDerek Schuff //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e4825975SDerek Schuff //
7e4825975SDerek Schuff //===----------------------------------------------------------------------===//
8e4825975SDerek Schuff ///
9e4825975SDerek Schuff /// \file
105f8f34e4SAdrian Prantl /// This file is part of the WebAssembly Assembler.
11e4825975SDerek Schuff ///
12e4825975SDerek Schuff /// It contains code to translate a parsed .s file into MCInsts.
13e4825975SDerek Schuff ///
14e4825975SDerek Schuff //===----------------------------------------------------------------------===//
15e4825975SDerek Schuff 
169647a6f7SWouter van Oortmerssen #include "AsmParser/WebAssemblyAsmTypeCheck.h"
17e4825975SDerek Schuff #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
18e4825975SDerek Schuff #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
19c6c42137SRichard Trieu #include "TargetInfo/WebAssemblyTargetInfo.h"
200b2bc69bSHeejin Ahn #include "Utils/WebAssemblyTypeUtilities.h"
210b2bc69bSHeejin Ahn #include "Utils/WebAssemblyUtilities.h"
22e4825975SDerek Schuff #include "WebAssembly.h"
23e4825975SDerek Schuff #include "llvm/MC/MCContext.h"
240b3cf247SWouter van Oortmerssen #include "llvm/MC/MCExpr.h"
25e4825975SDerek Schuff #include "llvm/MC/MCInst.h"
26e4825975SDerek Schuff #include "llvm/MC/MCInstrInfo.h"
2706943537Sserge-sans-paille #include "llvm/MC/MCParser/MCAsmLexer.h"
28f208f631SHeejin Ahn #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
29f208f631SHeejin Ahn #include "llvm/MC/MCParser/MCTargetAsmParser.h"
300b3cf247SWouter van Oortmerssen #include "llvm/MC/MCSectionWasm.h"
31f208f631SHeejin Ahn #include "llvm/MC/MCStreamer.h"
32e4825975SDerek Schuff #include "llvm/MC/MCSubtargetInfo.h"
33e4825975SDerek Schuff #include "llvm/MC/MCSymbol.h"
34de28b5d1SWouter van Oortmerssen #include "llvm/MC/MCSymbolWasm.h"
3589b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
36e4825975SDerek Schuff #include "llvm/Support/Endian.h"
379647a6f7SWouter van Oortmerssen #include "llvm/Support/SourceMgr.h"
38e4825975SDerek Schuff 
39e4825975SDerek Schuff using namespace llvm;
40e4825975SDerek Schuff 
41e4825975SDerek Schuff #define DEBUG_TYPE "wasm-asm-parser"
42e4825975SDerek Schuff 
432985c02fSThomas Lively static const char *getSubtargetFeatureName(uint64_t Val);
442985c02fSThomas Lively 
45e4825975SDerek Schuff namespace {
46e4825975SDerek Schuff 
47e4825975SDerek Schuff /// WebAssemblyOperand - Instances of this class represent the operands in a
481a69f023SThomas Lively /// parsed Wasm machine instruction.
49e4825975SDerek Schuff struct WebAssemblyOperand : public MCParsedAsmOperand {
50d3c544aaSWouter van Oortmerssen   enum KindTy { Token, Integer, Float, Symbol, BrList } Kind;
51e4825975SDerek Schuff 
52e4825975SDerek Schuff   SMLoc StartLoc, EndLoc;
53e4825975SDerek Schuff 
54e4825975SDerek Schuff   struct TokOp {
55e4825975SDerek Schuff     StringRef Tok;
56e4825975SDerek Schuff   };
57e4825975SDerek Schuff 
58e4825975SDerek Schuff   struct IntOp {
59e4825975SDerek Schuff     int64_t Val;
60e4825975SDerek Schuff   };
61e4825975SDerek Schuff 
62e4825975SDerek Schuff   struct FltOp {
63e4825975SDerek Schuff     double Val;
64e4825975SDerek Schuff   };
65e4825975SDerek Schuff 
66e4825975SDerek Schuff   struct SymOp {
67e4825975SDerek Schuff     const MCExpr *Exp;
68e4825975SDerek Schuff   };
69e4825975SDerek Schuff 
70d3c544aaSWouter van Oortmerssen   struct BrLOp {
71d3c544aaSWouter van Oortmerssen     std::vector<unsigned> List;
72d3c544aaSWouter van Oortmerssen   };
73d3c544aaSWouter van Oortmerssen 
74e4825975SDerek Schuff   union {
75e4825975SDerek Schuff     struct TokOp Tok;
76e4825975SDerek Schuff     struct IntOp Int;
77e4825975SDerek Schuff     struct FltOp Flt;
78e4825975SDerek Schuff     struct SymOp Sym;
79d3c544aaSWouter van Oortmerssen     struct BrLOp BrL;
80e4825975SDerek Schuff   };
81e4825975SDerek Schuff 
WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand82e4825975SDerek Schuff   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T)
83e4825975SDerek Schuff       : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {}
WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand84e4825975SDerek Schuff   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I)
85e4825975SDerek Schuff       : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {}
WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand86e4825975SDerek Schuff   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F)
87e4825975SDerek Schuff       : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {}
WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand88e4825975SDerek Schuff   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S)
89e4825975SDerek Schuff       : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {}
WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand90d3c544aaSWouter van Oortmerssen   WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End)
91d3c544aaSWouter van Oortmerssen       : Kind(K), StartLoc(Start), EndLoc(End), BrL() {}
92d3c544aaSWouter van Oortmerssen 
~WebAssemblyOperand__anonb6ef144c0111::WebAssemblyOperand93d3c544aaSWouter van Oortmerssen   ~WebAssemblyOperand() {
94d3c544aaSWouter van Oortmerssen     if (isBrList())
95d3c544aaSWouter van Oortmerssen       BrL.~BrLOp();
96d3c544aaSWouter van Oortmerssen   }
97e4825975SDerek Schuff 
isToken__anonb6ef144c0111::WebAssemblyOperand98e4825975SDerek Schuff   bool isToken() const override { return Kind == Token; }
isImm__anonb6ef144c0111::WebAssemblyOperand9981db9f54SWouter van Oortmerssen   bool isImm() const override { return Kind == Integer || Kind == Symbol; }
isFPImm__anonb6ef144c0111::WebAssemblyOperand10081db9f54SWouter van Oortmerssen   bool isFPImm() const { return Kind == Float; }
isMem__anonb6ef144c0111::WebAssemblyOperand101e4825975SDerek Schuff   bool isMem() const override { return false; }
isReg__anonb6ef144c0111::WebAssemblyOperand1028a9cb242SWouter van Oortmerssen   bool isReg() const override { return false; }
isBrList__anonb6ef144c0111::WebAssemblyOperand103d3c544aaSWouter van Oortmerssen   bool isBrList() const { return Kind == BrList; }
104e4825975SDerek Schuff 
getReg__anonb6ef144c0111::WebAssemblyOperand105e4825975SDerek Schuff   unsigned getReg() const override {
1068a9cb242SWouter van Oortmerssen     llvm_unreachable("Assembly inspects a register operand");
1078a9cb242SWouter van Oortmerssen     return 0;
108e4825975SDerek Schuff   }
109e4825975SDerek Schuff 
getToken__anonb6ef144c0111::WebAssemblyOperand110e4825975SDerek Schuff   StringRef getToken() const {
111e4825975SDerek Schuff     assert(isToken());
112e4825975SDerek Schuff     return Tok.Tok;
113e4825975SDerek Schuff   }
114e4825975SDerek Schuff 
getStartLoc__anonb6ef144c0111::WebAssemblyOperand115e4825975SDerek Schuff   SMLoc getStartLoc() const override { return StartLoc; }
getEndLoc__anonb6ef144c0111::WebAssemblyOperand116e4825975SDerek Schuff   SMLoc getEndLoc() const override { return EndLoc; }
117e4825975SDerek Schuff 
addRegOperands__anonb6ef144c0111::WebAssemblyOperand1188a9cb242SWouter van Oortmerssen   void addRegOperands(MCInst &, unsigned) const {
1198a9cb242SWouter van Oortmerssen     // Required by the assembly matcher.
1208a9cb242SWouter van Oortmerssen     llvm_unreachable("Assembly matcher creates register operands");
121e4825975SDerek Schuff   }
122e4825975SDerek Schuff 
addImmOperands__anonb6ef144c0111::WebAssemblyOperand123e4825975SDerek Schuff   void addImmOperands(MCInst &Inst, unsigned N) const {
124e4825975SDerek Schuff     assert(N == 1 && "Invalid number of operands!");
125e4825975SDerek Schuff     if (Kind == Integer)
126e4825975SDerek Schuff       Inst.addOperand(MCOperand::createImm(Int.Val));
127e4825975SDerek Schuff     else if (Kind == Symbol)
128e4825975SDerek Schuff       Inst.addOperand(MCOperand::createExpr(Sym.Exp));
129e4825975SDerek Schuff     else
13081db9f54SWouter van Oortmerssen       llvm_unreachable("Should be integer immediate or symbol!");
13181db9f54SWouter van Oortmerssen   }
13281db9f54SWouter van Oortmerssen 
addFPImmf32Operands__anonb6ef144c0111::WebAssemblyOperand133698c6b0aSDan Gohman   void addFPImmf32Operands(MCInst &Inst, unsigned N) const {
13481db9f54SWouter van Oortmerssen     assert(N == 1 && "Invalid number of operands!");
13581db9f54SWouter van Oortmerssen     if (Kind == Float)
136698c6b0aSDan Gohman       Inst.addOperand(
137698c6b0aSDan Gohman           MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val))));
138698c6b0aSDan Gohman     else
139698c6b0aSDan Gohman       llvm_unreachable("Should be float immediate!");
140698c6b0aSDan Gohman   }
141698c6b0aSDan Gohman 
addFPImmf64Operands__anonb6ef144c0111::WebAssemblyOperand142698c6b0aSDan Gohman   void addFPImmf64Operands(MCInst &Inst, unsigned N) const {
143698c6b0aSDan Gohman     assert(N == 1 && "Invalid number of operands!");
144698c6b0aSDan Gohman     if (Kind == Float)
145698c6b0aSDan Gohman       Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val)));
14681db9f54SWouter van Oortmerssen     else
14781db9f54SWouter van Oortmerssen       llvm_unreachable("Should be float immediate!");
148e4825975SDerek Schuff   }
149e4825975SDerek Schuff 
addBrListOperands__anonb6ef144c0111::WebAssemblyOperand150d3c544aaSWouter van Oortmerssen   void addBrListOperands(MCInst &Inst, unsigned N) const {
151d3c544aaSWouter van Oortmerssen     assert(N == 1 && isBrList() && "Invalid BrList!");
152d3c544aaSWouter van Oortmerssen     for (auto Br : BrL.List)
153d3c544aaSWouter van Oortmerssen       Inst.addOperand(MCOperand::createImm(Br));
154d3c544aaSWouter van Oortmerssen   }
155d3c544aaSWouter van Oortmerssen 
print__anonb6ef144c0111::WebAssemblyOperand156e4825975SDerek Schuff   void print(raw_ostream &OS) const override {
157e4825975SDerek Schuff     switch (Kind) {
158e4825975SDerek Schuff     case Token:
159e4825975SDerek Schuff       OS << "Tok:" << Tok.Tok;
160e4825975SDerek Schuff       break;
161e4825975SDerek Schuff     case Integer:
162e4825975SDerek Schuff       OS << "Int:" << Int.Val;
163e4825975SDerek Schuff       break;
164e4825975SDerek Schuff     case Float:
165e4825975SDerek Schuff       OS << "Flt:" << Flt.Val;
166e4825975SDerek Schuff       break;
167e4825975SDerek Schuff     case Symbol:
168e4825975SDerek Schuff       OS << "Sym:" << Sym.Exp;
169e4825975SDerek Schuff       break;
170d3c544aaSWouter van Oortmerssen     case BrList:
171d3c544aaSWouter van Oortmerssen       OS << "BrList:" << BrL.List.size();
172d3c544aaSWouter van Oortmerssen       break;
173e4825975SDerek Schuff     }
174e4825975SDerek Schuff   }
175e4825975SDerek Schuff };
176e4825975SDerek Schuff 
177c9801db2SAndy Wingo // Perhaps this should go somewhere common.
DefaultLimits()178c9801db2SAndy Wingo static wasm::WasmLimits DefaultLimits() {
179c9801db2SAndy Wingo   return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0};
180c9801db2SAndy Wingo }
181c9801db2SAndy Wingo 
GetOrCreateFunctionTableSymbol(MCContext & Ctx,const StringRef & Name)1829ad83fd6SAndy Wingo static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx,
1839ad83fd6SAndy Wingo                                                     const StringRef &Name) {
1849ad83fd6SAndy Wingo   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
1859ad83fd6SAndy Wingo   if (Sym) {
1869ad83fd6SAndy Wingo     if (!Sym->isFunctionTable())
1879ad83fd6SAndy Wingo       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
1889ad83fd6SAndy Wingo   } else {
1899ad83fd6SAndy Wingo     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
1909ad83fd6SAndy Wingo     Sym->setFunctionTable();
1919ad83fd6SAndy Wingo     // The default function table is synthesized by the linker.
1929ad83fd6SAndy Wingo     Sym->setUndefined();
1939ad83fd6SAndy Wingo   }
1949ad83fd6SAndy Wingo   return Sym;
1959ad83fd6SAndy Wingo }
1969ad83fd6SAndy Wingo 
197e4825975SDerek Schuff class WebAssemblyAsmParser final : public MCTargetAsmParser {
198e4825975SDerek Schuff   MCAsmParser &Parser;
199e4825975SDerek Schuff   MCAsmLexer &Lexer;
200e4825975SDerek Schuff 
20149482f82SWouter van Oortmerssen   // Much like WebAssemblyAsmPrinter in the backend, we have to own these.
20249482f82SWouter van Oortmerssen   std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
2035be42f36SSam Clegg   std::vector<std::unique_ptr<std::string>> Names;
20449482f82SWouter van Oortmerssen 
205c7b89f0fSWouter van Oortmerssen   // Order of labels, directives and instructions in a .s file have no
206c7b89f0fSWouter van Oortmerssen   // syntactical enforcement. This class is a callback from the actual parser,
207c7b89f0fSWouter van Oortmerssen   // and yet we have to be feeding data to the streamer in a very particular
208c7b89f0fSWouter van Oortmerssen   // order to ensure a correct binary encoding that matches the regular backend
209c7b89f0fSWouter van Oortmerssen   // (the streamer does not enforce this). This "state machine" enum helps
210c7b89f0fSWouter van Oortmerssen   // guarantee that correct order.
211c7b89f0fSWouter van Oortmerssen   enum ParserState {
212c7b89f0fSWouter van Oortmerssen     FileStart,
213c7b89f0fSWouter van Oortmerssen     FunctionStart,
214c7b89f0fSWouter van Oortmerssen     FunctionLocals,
215c7b89f0fSWouter van Oortmerssen     Instructions,
2160b3cf247SWouter van Oortmerssen     EndFunction,
217f3feb6adSWouter van Oortmerssen     DataSection,
218c7b89f0fSWouter van Oortmerssen   } CurrentState = FileStart;
219c7b89f0fSWouter van Oortmerssen 
22029c6ce58SWouter van Oortmerssen   // For ensuring blocks are properly nested.
22129c6ce58SWouter van Oortmerssen   enum NestingType {
22229c6ce58SWouter van Oortmerssen     Function,
22329c6ce58SWouter van Oortmerssen     Block,
22429c6ce58SWouter van Oortmerssen     Loop,
22529c6ce58SWouter van Oortmerssen     Try,
2265afdd64aSHeejin Ahn     CatchAll,
22729c6ce58SWouter van Oortmerssen     If,
22829c6ce58SWouter van Oortmerssen     Else,
22929c6ce58SWouter van Oortmerssen     Undefined,
23029c6ce58SWouter van Oortmerssen   };
2319647a6f7SWouter van Oortmerssen   struct Nested {
2329647a6f7SWouter van Oortmerssen     NestingType NT;
2339647a6f7SWouter van Oortmerssen     wasm::WasmSignature Sig;
2349647a6f7SWouter van Oortmerssen   };
2359647a6f7SWouter van Oortmerssen   std::vector<Nested> NestingStack;
23629c6ce58SWouter van Oortmerssen 
2372632ba6aSAndy Wingo   MCSymbolWasm *DefaultFunctionTable = nullptr;
2380b3cf247SWouter van Oortmerssen   MCSymbol *LastFunctionLabel = nullptr;
239c7b89f0fSWouter van Oortmerssen 
2409647a6f7SWouter van Oortmerssen   bool is64;
2419647a6f7SWouter van Oortmerssen 
2429647a6f7SWouter van Oortmerssen   WebAssemblyAsmTypeCheck TC;
2439647a6f7SWouter van Oortmerssen   // Don't type check if -no-type-check was set.
2449647a6f7SWouter van Oortmerssen   bool SkipTypeCheck;
2459647a6f7SWouter van Oortmerssen 
246e4825975SDerek Schuff public:
WebAssemblyAsmParser(const MCSubtargetInfo & STI,MCAsmParser & Parser,const MCInstrInfo & MII,const MCTargetOptions & Options)247de28b5d1SWouter van Oortmerssen   WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
248de28b5d1SWouter van Oortmerssen                        const MCInstrInfo &MII, const MCTargetOptions &Options)
249de28b5d1SWouter van Oortmerssen       : MCTargetAsmParser(Options, STI, MII), Parser(Parser),
2509647a6f7SWouter van Oortmerssen         Lexer(Parser.getLexer()),
2519647a6f7SWouter van Oortmerssen         is64(STI.getTargetTriple().isArch64Bit()),
2529647a6f7SWouter van Oortmerssen         TC(Parser, MII, is64), SkipTypeCheck(Options.MCNoTypeCheck) {
253de28b5d1SWouter van Oortmerssen     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
2549647a6f7SWouter van Oortmerssen     // Don't type check if this is inline asm, since that is a naked sequence of
2559647a6f7SWouter van Oortmerssen     // instructions without a function/locals decl.
2569647a6f7SWouter van Oortmerssen     auto &SM = Parser.getSourceManager();
2579647a6f7SWouter van Oortmerssen     auto BufferName =
2589647a6f7SWouter van Oortmerssen       SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier();
2599647a6f7SWouter van Oortmerssen     if (BufferName == "<inline asm>")
2609647a6f7SWouter van Oortmerssen       SkipTypeCheck = true;
261e4825975SDerek Schuff   }
262e4825975SDerek Schuff 
Initialize(MCAsmParser & Parser)2632632ba6aSAndy Wingo   void Initialize(MCAsmParser &Parser) override {
2642632ba6aSAndy Wingo     MCAsmParserExtension::Initialize(Parser);
2652632ba6aSAndy Wingo 
2662632ba6aSAndy Wingo     DefaultFunctionTable = GetOrCreateFunctionTableSymbol(
2672632ba6aSAndy Wingo         getContext(), "__indirect_function_table");
2682632ba6aSAndy Wingo     if (!STI->checkFeatures("+reference-types"))
2692632ba6aSAndy Wingo       DefaultFunctionTable->setOmitFromLinkingSection();
2702632ba6aSAndy Wingo   }
2712632ba6aSAndy Wingo 
272e4825975SDerek Schuff #define GET_ASSEMBLER_HEADER
273e4825975SDerek Schuff #include "WebAssemblyGenAsmMatcher.inc"
274e4825975SDerek Schuff 
275e4825975SDerek Schuff   // TODO: This is required to be implemented, but appears unused.
ParseRegister(unsigned &,SMLoc &,SMLoc &)276e4825975SDerek Schuff   bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/,
277e4825975SDerek Schuff                      SMLoc & /*EndLoc*/) override {
278e4825975SDerek Schuff     llvm_unreachable("ParseRegister is not implemented.");
279e4825975SDerek Schuff   }
tryParseRegister(unsigned &,SMLoc &,SMLoc &)2808d5bf042SEric Astor   OperandMatchResultTy tryParseRegister(unsigned & /*RegNo*/,
2818d5bf042SEric Astor                                         SMLoc & /*StartLoc*/,
2828d5bf042SEric Astor                                         SMLoc & /*EndLoc*/) override {
2838d5bf042SEric Astor     llvm_unreachable("tryParseRegister is not implemented.");
2848d5bf042SEric Astor   }
285e4825975SDerek Schuff 
error(const Twine & Msg,const AsmToken & Tok)28629c6ce58SWouter van Oortmerssen   bool error(const Twine &Msg, const AsmToken &Tok) {
2877ce5edf1SHeejin Ahn     return Parser.Error(Tok.getLoc(), Msg + Tok.getString());
288e4825975SDerek Schuff   }
289e4825975SDerek Schuff 
error(const Twine & Msg)29029c6ce58SWouter van Oortmerssen   bool error(const Twine &Msg) {
29129c6ce58SWouter van Oortmerssen     return Parser.Error(Lexer.getTok().getLoc(), Msg);
29229c6ce58SWouter van Oortmerssen   }
29329c6ce58SWouter van Oortmerssen 
addSignature(std::unique_ptr<wasm::WasmSignature> && Sig)29429c6ce58SWouter van Oortmerssen   void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
29529c6ce58SWouter van Oortmerssen     Signatures.push_back(std::move(Sig));
29629c6ce58SWouter van Oortmerssen   }
29729c6ce58SWouter van Oortmerssen 
storeName(StringRef Name)2987baad0c5SSam Clegg   StringRef storeName(StringRef Name) {
2995be42f36SSam Clegg     std::unique_ptr<std::string> N = std::make_unique<std::string>(Name);
3005be42f36SSam Clegg     Names.push_back(std::move(N));
3017baad0c5SSam Clegg     return *Names.back();
3025be42f36SSam Clegg   }
3035be42f36SSam Clegg 
nestingString(NestingType NT)30429c6ce58SWouter van Oortmerssen   std::pair<StringRef, StringRef> nestingString(NestingType NT) {
30529c6ce58SWouter van Oortmerssen     switch (NT) {
30629c6ce58SWouter van Oortmerssen     case Function:
30729c6ce58SWouter van Oortmerssen       return {"function", "end_function"};
30829c6ce58SWouter van Oortmerssen     case Block:
30929c6ce58SWouter van Oortmerssen       return {"block", "end_block"};
31029c6ce58SWouter van Oortmerssen     case Loop:
31129c6ce58SWouter van Oortmerssen       return {"loop", "end_loop"};
31229c6ce58SWouter van Oortmerssen     case Try:
3135afdd64aSHeejin Ahn       return {"try", "end_try/delegate"};
3145afdd64aSHeejin Ahn     case CatchAll:
3155afdd64aSHeejin Ahn       return {"catch_all", "end_try"};
31629c6ce58SWouter van Oortmerssen     case If:
31729c6ce58SWouter van Oortmerssen       return {"if", "end_if"};
31829c6ce58SWouter van Oortmerssen     case Else:
31929c6ce58SWouter van Oortmerssen       return {"else", "end_if"};
32029c6ce58SWouter van Oortmerssen     default:
32129c6ce58SWouter van Oortmerssen       llvm_unreachable("unknown NestingType");
32229c6ce58SWouter van Oortmerssen     }
32329c6ce58SWouter van Oortmerssen   }
32429c6ce58SWouter van Oortmerssen 
push(NestingType NT)3255f306febSKazu Hirata   void push(NestingType NT) { NestingStack.push_back({NT, wasm::WasmSignature()}); }
32629c6ce58SWouter van Oortmerssen 
pop(StringRef Ins,NestingType NT1,NestingType NT2=Undefined)32729c6ce58SWouter van Oortmerssen   bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) {
32829c6ce58SWouter van Oortmerssen     if (NestingStack.empty())
32929c6ce58SWouter van Oortmerssen       return error(Twine("End of block construct with no start: ") + Ins);
33029c6ce58SWouter van Oortmerssen     auto Top = NestingStack.back();
3319647a6f7SWouter van Oortmerssen     if (Top.NT != NT1 && Top.NT != NT2)
33229c6ce58SWouter van Oortmerssen       return error(Twine("Block construct type mismatch, expected: ") +
3339647a6f7SWouter van Oortmerssen                    nestingString(Top.NT).second + ", instead got: " + Ins);
3349647a6f7SWouter van Oortmerssen     TC.setLastSig(Top.Sig);
33529c6ce58SWouter van Oortmerssen     NestingStack.pop_back();
33629c6ce58SWouter van Oortmerssen     return false;
33729c6ce58SWouter van Oortmerssen   }
33829c6ce58SWouter van Oortmerssen 
ensureEmptyNestingStack()33929c6ce58SWouter van Oortmerssen   bool ensureEmptyNestingStack() {
34018c56a07SHeejin Ahn     auto Err = !NestingStack.empty();
34129c6ce58SWouter van Oortmerssen     while (!NestingStack.empty()) {
34229c6ce58SWouter van Oortmerssen       error(Twine("Unmatched block construct(s) at function end: ") +
3439647a6f7SWouter van Oortmerssen             nestingString(NestingStack.back().NT).first);
34429c6ce58SWouter van Oortmerssen       NestingStack.pop_back();
34529c6ce58SWouter van Oortmerssen     }
34618c56a07SHeejin Ahn     return Err;
34729c6ce58SWouter van Oortmerssen   }
34829c6ce58SWouter van Oortmerssen 
isNext(AsmToken::TokenKind Kind)3497ce5edf1SHeejin Ahn   bool isNext(AsmToken::TokenKind Kind) {
3507ce5edf1SHeejin Ahn     auto Ok = Lexer.is(Kind);
3517ce5edf1SHeejin Ahn     if (Ok)
352f208f631SHeejin Ahn       Parser.Lex();
3537ce5edf1SHeejin Ahn     return Ok;
354e4825975SDerek Schuff   }
355e4825975SDerek Schuff 
expect(AsmToken::TokenKind Kind,const char * KindName)3567ce5edf1SHeejin Ahn   bool expect(AsmToken::TokenKind Kind, const char *KindName) {
3577ce5edf1SHeejin Ahn     if (!isNext(Kind))
3587ce5edf1SHeejin Ahn       return error(std::string("Expected ") + KindName + ", instead got: ",
359e4825975SDerek Schuff                    Lexer.getTok());
360e4825975SDerek Schuff     return false;
361e4825975SDerek Schuff   }
362e4825975SDerek Schuff 
expectIdent()3637ce5edf1SHeejin Ahn   StringRef expectIdent() {
36449482f82SWouter van Oortmerssen     if (!Lexer.is(AsmToken::Identifier)) {
3657ce5edf1SHeejin Ahn       error("Expected identifier, got: ", Lexer.getTok());
36649482f82SWouter van Oortmerssen       return StringRef();
36749482f82SWouter van Oortmerssen     }
36849482f82SWouter van Oortmerssen     auto Name = Lexer.getTok().getString();
36949482f82SWouter van Oortmerssen     Parser.Lex();
37049482f82SWouter van Oortmerssen     return Name;
371e4825975SDerek Schuff   }
372e4825975SDerek Schuff 
parseRegTypeList(SmallVectorImpl<wasm::ValType> & Types)3737ce5edf1SHeejin Ahn   bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
374cc75e77dSWouter van Oortmerssen     while (Lexer.is(AsmToken::Identifier)) {
3750b2bc69bSHeejin Ahn       auto Type = WebAssembly::parseType(Lexer.getTok().getString());
37649482f82SWouter van Oortmerssen       if (!Type)
377f3b762a0SWouter van Oortmerssen         return error("unknown type: ", Lexer.getTok());
378*7a47ee51SKazu Hirata       Types.push_back(*Type);
379cc75e77dSWouter van Oortmerssen       Parser.Lex();
3807ce5edf1SHeejin Ahn       if (!isNext(AsmToken::Comma))
381cc75e77dSWouter van Oortmerssen         break;
382cc75e77dSWouter van Oortmerssen     }
38349482f82SWouter van Oortmerssen     return false;
384cc75e77dSWouter van Oortmerssen   }
385cc75e77dSWouter van Oortmerssen 
parseSingleInteger(bool IsNegative,OperandVector & Operands)3867ce5edf1SHeejin Ahn   void parseSingleInteger(bool IsNegative, OperandVector &Operands) {
387e4825975SDerek Schuff     auto &Int = Lexer.getTok();
388e4825975SDerek Schuff     int64_t Val = Int.getIntVal();
389f208f631SHeejin Ahn     if (IsNegative)
390f208f631SHeejin Ahn       Val = -Val;
3910eaee545SJonas Devlieghere     Operands.push_back(std::make_unique<WebAssemblyOperand>(
392f208f631SHeejin Ahn         WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(),
393f208f631SHeejin Ahn         WebAssemblyOperand::IntOp{Val}));
394e4825975SDerek Schuff     Parser.Lex();
395e4825975SDerek Schuff   }
396e4825975SDerek Schuff 
parseSingleFloat(bool IsNegative,OperandVector & Operands)397a617967dSWouter van Oortmerssen   bool parseSingleFloat(bool IsNegative, OperandVector &Operands) {
398a617967dSWouter van Oortmerssen     auto &Flt = Lexer.getTok();
399a617967dSWouter van Oortmerssen     double Val;
400a617967dSWouter van Oortmerssen     if (Flt.getString().getAsDouble(Val, false))
401a617967dSWouter van Oortmerssen       return error("Cannot parse real: ", Flt);
402a617967dSWouter van Oortmerssen     if (IsNegative)
403a617967dSWouter van Oortmerssen       Val = -Val;
4040eaee545SJonas Devlieghere     Operands.push_back(std::make_unique<WebAssemblyOperand>(
405a617967dSWouter van Oortmerssen         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
406a617967dSWouter van Oortmerssen         WebAssemblyOperand::FltOp{Val}));
407a617967dSWouter van Oortmerssen     Parser.Lex();
408a617967dSWouter van Oortmerssen     return false;
409a617967dSWouter van Oortmerssen   }
410a617967dSWouter van Oortmerssen 
parseSpecialFloatMaybe(bool IsNegative,OperandVector & Operands)411292e21d8SWouter van Oortmerssen   bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) {
412292e21d8SWouter van Oortmerssen     if (Lexer.isNot(AsmToken::Identifier))
413292e21d8SWouter van Oortmerssen       return true;
414292e21d8SWouter van Oortmerssen     auto &Flt = Lexer.getTok();
415292e21d8SWouter van Oortmerssen     auto S = Flt.getString();
416292e21d8SWouter van Oortmerssen     double Val;
41742f74e82SMartin Storsjö     if (S.compare_insensitive("infinity") == 0) {
418292e21d8SWouter van Oortmerssen       Val = std::numeric_limits<double>::infinity();
41942f74e82SMartin Storsjö     } else if (S.compare_insensitive("nan") == 0) {
420292e21d8SWouter van Oortmerssen       Val = std::numeric_limits<double>::quiet_NaN();
421292e21d8SWouter van Oortmerssen     } else {
422292e21d8SWouter van Oortmerssen       return true;
423292e21d8SWouter van Oortmerssen     }
424292e21d8SWouter van Oortmerssen     if (IsNegative)
425292e21d8SWouter van Oortmerssen       Val = -Val;
4260eaee545SJonas Devlieghere     Operands.push_back(std::make_unique<WebAssemblyOperand>(
427292e21d8SWouter van Oortmerssen         WebAssemblyOperand::Float, Flt.getLoc(), Flt.getEndLoc(),
428292e21d8SWouter van Oortmerssen         WebAssemblyOperand::FltOp{Val}));
429292e21d8SWouter van Oortmerssen     Parser.Lex();
430292e21d8SWouter van Oortmerssen     return false;
431292e21d8SWouter van Oortmerssen   }
432292e21d8SWouter van Oortmerssen 
checkForP2AlignIfLoadStore(OperandVector & Operands,StringRef InstName)433fc222e23SWouter van Oortmerssen   bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) {
4348a9cb242SWouter van Oortmerssen     // FIXME: there is probably a cleaner way to do this.
4356fe949c4SKazu Hirata     auto IsLoadStore = InstName.contains(".load") ||
4366fe949c4SKazu Hirata                        InstName.contains(".store") ||
4376fe949c4SKazu Hirata                        InstName.contains("prefetch");
4386fe949c4SKazu Hirata     auto IsAtomic = InstName.contains("atomic.");
4396b3f56b6SWouter van Oortmerssen     if (IsLoadStore || IsAtomic) {
4406b3f56b6SWouter van Oortmerssen       // Parse load/store operands of the form: offset:p2align=align
4416b3f56b6SWouter van Oortmerssen       if (IsLoadStore && isNext(AsmToken::Colon)) {
4426b3f56b6SWouter van Oortmerssen         auto Id = expectIdent();
4436b3f56b6SWouter van Oortmerssen         if (Id != "p2align")
4446b3f56b6SWouter van Oortmerssen           return error("Expected p2align, instead got: " + Id);
4456b3f56b6SWouter van Oortmerssen         if (expect(AsmToken::Equal, "="))
4466b3f56b6SWouter van Oortmerssen           return true;
4476b3f56b6SWouter van Oortmerssen         if (!Lexer.is(AsmToken::Integer))
4486b3f56b6SWouter van Oortmerssen           return error("Expected integer constant");
4497ce5edf1SHeejin Ahn         parseSingleInteger(false, Operands);
450e4825975SDerek Schuff       } else {
4513f738d1fSThomas Lively         // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane
4523f738d1fSThomas Lively         // index. We need to avoid parsing an extra alignment operand for the
4533f738d1fSThomas Lively         // lane index.
4546fe949c4SKazu Hirata         auto IsLoadStoreLane = InstName.contains("_lane");
4553f738d1fSThomas Lively         if (IsLoadStoreLane && Operands.size() == 4)
4563f738d1fSThomas Lively           return false;
4576b3f56b6SWouter van Oortmerssen         // Alignment not specified (or atomics, must use default alignment).
4588a9cb242SWouter van Oortmerssen         // We can't just call WebAssembly::GetDefaultP2Align since we don't have
4596b3f56b6SWouter van Oortmerssen         // an opcode until after the assembly matcher, so set a default to fix
4606b3f56b6SWouter van Oortmerssen         // up later.
4616b3f56b6SWouter van Oortmerssen         auto Tok = Lexer.getTok();
4620eaee545SJonas Devlieghere         Operands.push_back(std::make_unique<WebAssemblyOperand>(
4636b3f56b6SWouter van Oortmerssen             WebAssemblyOperand::Integer, Tok.getLoc(), Tok.getEndLoc(),
4646b3f56b6SWouter van Oortmerssen             WebAssemblyOperand::IntOp{-1}));
465e4825975SDerek Schuff       }
466e4825975SDerek Schuff     }
467e4825975SDerek Schuff     return false;
468e4825975SDerek Schuff   }
469e4825975SDerek Schuff 
addBlockTypeOperand(OperandVector & Operands,SMLoc NameLoc,WebAssembly::BlockType BT)470ad72f685SWouter van Oortmerssen   void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
4712cb27072SThomas Lively                            WebAssembly::BlockType BT) {
4729647a6f7SWouter van Oortmerssen     if (BT != WebAssembly::BlockType::Void) {
4739647a6f7SWouter van Oortmerssen       wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {});
4749647a6f7SWouter van Oortmerssen       TC.setLastSig(Sig);
4759647a6f7SWouter van Oortmerssen       NestingStack.back().Sig = Sig;
4769647a6f7SWouter van Oortmerssen     }
4770eaee545SJonas Devlieghere     Operands.push_back(std::make_unique<WebAssemblyOperand>(
478ad72f685SWouter van Oortmerssen         WebAssemblyOperand::Integer, NameLoc, NameLoc,
479ad72f685SWouter van Oortmerssen         WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
480ad72f685SWouter van Oortmerssen   }
481ad72f685SWouter van Oortmerssen 
parseLimits(wasm::WasmLimits * Limits)482c9801db2SAndy Wingo   bool parseLimits(wasm::WasmLimits *Limits) {
483c9801db2SAndy Wingo     auto Tok = Lexer.getTok();
484c9801db2SAndy Wingo     if (!Tok.is(AsmToken::Integer))
485c9801db2SAndy Wingo       return error("Expected integer constant, instead got: ", Tok);
486c9801db2SAndy Wingo     int64_t Val = Tok.getIntVal();
487c9801db2SAndy Wingo     assert(Val >= 0);
488c9801db2SAndy Wingo     Limits->Minimum = Val;
489c9801db2SAndy Wingo     Parser.Lex();
490c9801db2SAndy Wingo 
491c9801db2SAndy Wingo     if (isNext(AsmToken::Comma)) {
492c9801db2SAndy Wingo       Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX;
493c9801db2SAndy Wingo       auto Tok = Lexer.getTok();
494c9801db2SAndy Wingo       if (!Tok.is(AsmToken::Integer))
495c9801db2SAndy Wingo         return error("Expected integer constant, instead got: ", Tok);
496c9801db2SAndy Wingo       int64_t Val = Tok.getIntVal();
497c9801db2SAndy Wingo       assert(Val >= 0);
498c9801db2SAndy Wingo       Limits->Maximum = Val;
499c9801db2SAndy Wingo       Parser.Lex();
500c9801db2SAndy Wingo     }
501c9801db2SAndy Wingo     return false;
502c9801db2SAndy Wingo   }
503c9801db2SAndy Wingo 
parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> * Op)5044307069dSAndy Wingo   bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) {
5054307069dSAndy Wingo     if (STI->checkFeatures("+reference-types")) {
5064307069dSAndy Wingo       // If the reference-types feature is enabled, there is an explicit table
5074307069dSAndy Wingo       // operand.  To allow the same assembly to be compiled with or without
5084307069dSAndy Wingo       // reference types, we allow the operand to be omitted, in which case we
5094307069dSAndy Wingo       // default to __indirect_function_table.
5104307069dSAndy Wingo       auto &Tok = Lexer.getTok();
5114307069dSAndy Wingo       if (Tok.is(AsmToken::Identifier)) {
5124307069dSAndy Wingo         auto *Sym =
5134307069dSAndy Wingo             GetOrCreateFunctionTableSymbol(getContext(), Tok.getString());
5142632ba6aSAndy Wingo         const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
5154307069dSAndy Wingo         *Op = std::make_unique<WebAssemblyOperand>(
5164307069dSAndy Wingo             WebAssemblyOperand::Symbol, Tok.getLoc(), Tok.getEndLoc(),
5174307069dSAndy Wingo             WebAssemblyOperand::SymOp{Val});
5184307069dSAndy Wingo         Parser.Lex();
5194307069dSAndy Wingo         return expect(AsmToken::Comma, ",");
5204307069dSAndy Wingo       } else {
5214307069dSAndy Wingo         const auto *Val =
5224307069dSAndy Wingo             MCSymbolRefExpr::create(DefaultFunctionTable, getContext());
5234307069dSAndy Wingo         *Op = std::make_unique<WebAssemblyOperand>(
5244307069dSAndy Wingo             WebAssemblyOperand::Symbol, SMLoc(), SMLoc(),
5254307069dSAndy Wingo             WebAssemblyOperand::SymOp{Val});
5262632ba6aSAndy Wingo         return false;
5272632ba6aSAndy Wingo       }
5282632ba6aSAndy Wingo     } else {
5292632ba6aSAndy Wingo       // For the MVP there is at most one table whose number is 0, but we can't
5302632ba6aSAndy Wingo       // write a table symbol or issue relocations.  Instead we just ensure the
5312632ba6aSAndy Wingo       // table is live and write a zero.
5322632ba6aSAndy Wingo       getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
5334307069dSAndy Wingo       *Op = std::make_unique<WebAssemblyOperand>(WebAssemblyOperand::Integer,
5344307069dSAndy Wingo                                                  SMLoc(), SMLoc(),
5354307069dSAndy Wingo                                                  WebAssemblyOperand::IntOp{0});
5362632ba6aSAndy Wingo       return false;
5372632ba6aSAndy Wingo     }
5382632ba6aSAndy Wingo   }
5392632ba6aSAndy Wingo 
ParseInstruction(ParseInstructionInfo &,StringRef Name,SMLoc NameLoc,OperandVector & Operands)540e4825975SDerek Schuff   bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
541e4825975SDerek Schuff                         SMLoc NameLoc, OperandVector &Operands) override {
5420c83c3ffSWouter van Oortmerssen     // Note: Name does NOT point into the sourcecode, but to a local, so
5430c83c3ffSWouter van Oortmerssen     // use NameLoc instead.
5440c83c3ffSWouter van Oortmerssen     Name = StringRef(NameLoc.getPointer(), Name.size());
5457ce5edf1SHeejin Ahn 
5460c83c3ffSWouter van Oortmerssen     // WebAssembly has instructions with / in them, which AsmLexer parses
5479301e3aaSMarek Kurdej     // as separate tokens, so if we find such tokens immediately adjacent (no
5480c83c3ffSWouter van Oortmerssen     // whitespace), expand the name to include them:
5490c83c3ffSWouter van Oortmerssen     for (;;) {
5500c83c3ffSWouter van Oortmerssen       auto &Sep = Lexer.getTok();
5510c83c3ffSWouter van Oortmerssen       if (Sep.getLoc().getPointer() != Name.end() ||
5527ce5edf1SHeejin Ahn           Sep.getKind() != AsmToken::Slash)
5537ce5edf1SHeejin Ahn         break;
5540c83c3ffSWouter van Oortmerssen       // Extend name with /
5550c83c3ffSWouter van Oortmerssen       Name = StringRef(Name.begin(), Name.size() + Sep.getString().size());
5560c83c3ffSWouter van Oortmerssen       Parser.Lex();
5570c83c3ffSWouter van Oortmerssen       // We must now find another identifier, or error.
5580c83c3ffSWouter van Oortmerssen       auto &Id = Lexer.getTok();
5590c83c3ffSWouter van Oortmerssen       if (Id.getKind() != AsmToken::Identifier ||
5600c83c3ffSWouter van Oortmerssen           Id.getLoc().getPointer() != Name.end())
5617ce5edf1SHeejin Ahn         return error("Incomplete instruction name: ", Id);
5620c83c3ffSWouter van Oortmerssen       Name = StringRef(Name.begin(), Name.size() + Id.getString().size());
5630c83c3ffSWouter van Oortmerssen       Parser.Lex();
5640c83c3ffSWouter van Oortmerssen     }
5657ce5edf1SHeejin Ahn 
5660c83c3ffSWouter van Oortmerssen     // Now construct the name as first operand.
5670eaee545SJonas Devlieghere     Operands.push_back(std::make_unique<WebAssemblyOperand>(
5680c83c3ffSWouter van Oortmerssen         WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()),
5690c83c3ffSWouter van Oortmerssen         WebAssemblyOperand::TokOp{Name}));
5707ce5edf1SHeejin Ahn 
57129c6ce58SWouter van Oortmerssen     // If this instruction is part of a control flow structure, ensure
57229c6ce58SWouter van Oortmerssen     // proper nesting.
573ad72f685SWouter van Oortmerssen     bool ExpectBlockType = false;
5742cb27072SThomas Lively     bool ExpectFuncType = false;
5754307069dSAndy Wingo     std::unique_ptr<WebAssemblyOperand> FunctionTable;
576bfd3f694SWouter van Oortmerssen     if (Name == "block") {
57729c6ce58SWouter van Oortmerssen       push(Block);
578ad72f685SWouter van Oortmerssen       ExpectBlockType = true;
579bfd3f694SWouter van Oortmerssen     } else if (Name == "loop") {
58029c6ce58SWouter van Oortmerssen       push(Loop);
581ad72f685SWouter van Oortmerssen       ExpectBlockType = true;
582bfd3f694SWouter van Oortmerssen     } else if (Name == "try") {
58329c6ce58SWouter van Oortmerssen       push(Try);
584ad72f685SWouter van Oortmerssen       ExpectBlockType = true;
585bfd3f694SWouter van Oortmerssen     } else if (Name == "if") {
58629c6ce58SWouter van Oortmerssen       push(If);
587ad72f685SWouter van Oortmerssen       ExpectBlockType = true;
588bfd3f694SWouter van Oortmerssen     } else if (Name == "else") {
589bfd3f694SWouter van Oortmerssen       if (pop(Name, If))
59029c6ce58SWouter van Oortmerssen         return true;
59129c6ce58SWouter van Oortmerssen       push(Else);
592bfd3f694SWouter van Oortmerssen     } else if (Name == "catch") {
593bfd3f694SWouter van Oortmerssen       if (pop(Name, Try))
59429c6ce58SWouter van Oortmerssen         return true;
59529c6ce58SWouter van Oortmerssen       push(Try);
5965afdd64aSHeejin Ahn     } else if (Name == "catch_all") {
5975afdd64aSHeejin Ahn       if (pop(Name, Try))
5985afdd64aSHeejin Ahn         return true;
5995afdd64aSHeejin Ahn       push(CatchAll);
600bfd3f694SWouter van Oortmerssen     } else if (Name == "end_if") {
601bfd3f694SWouter van Oortmerssen       if (pop(Name, If, Else))
60229c6ce58SWouter van Oortmerssen         return true;
603bfd3f694SWouter van Oortmerssen     } else if (Name == "end_try") {
6045afdd64aSHeejin Ahn       if (pop(Name, Try, CatchAll))
6055afdd64aSHeejin Ahn         return true;
6065afdd64aSHeejin Ahn     } else if (Name == "delegate") {
607bfd3f694SWouter van Oortmerssen       if (pop(Name, Try))
60829c6ce58SWouter van Oortmerssen         return true;
609bfd3f694SWouter van Oortmerssen     } else if (Name == "end_loop") {
610bfd3f694SWouter van Oortmerssen       if (pop(Name, Loop))
61129c6ce58SWouter van Oortmerssen         return true;
612bfd3f694SWouter van Oortmerssen     } else if (Name == "end_block") {
613bfd3f694SWouter van Oortmerssen       if (pop(Name, Block))
61429c6ce58SWouter van Oortmerssen         return true;
615bfd3f694SWouter van Oortmerssen     } else if (Name == "end_function") {
61619bf637eSSam Clegg       ensureLocals(getStreamer());
6170b3cf247SWouter van Oortmerssen       CurrentState = EndFunction;
618bfd3f694SWouter van Oortmerssen       if (pop(Name, Function) || ensureEmptyNestingStack())
61929c6ce58SWouter van Oortmerssen         return true;
62087af0b19SWouter van Oortmerssen     } else if (Name == "call_indirect" || Name == "return_call_indirect") {
6214307069dSAndy Wingo       // These instructions have differing operand orders in the text format vs
6224307069dSAndy Wingo       // the binary formats.  The MC instructions follow the binary format, so
6234307069dSAndy Wingo       // here we stash away the operand and append it later.
6244307069dSAndy Wingo       if (parseFunctionTableOperand(&FunctionTable))
6254307069dSAndy Wingo         return true;
6262cb27072SThomas Lively       ExpectFuncType = true;
6272cb27072SThomas Lively     }
6282cb27072SThomas Lively 
6292cb27072SThomas Lively     if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) {
63087af0b19SWouter van Oortmerssen       // This has a special TYPEINDEX operand which in text we
63187af0b19SWouter van Oortmerssen       // represent as a signature, such that we can re-build this signature,
63287af0b19SWouter van Oortmerssen       // attach it to an anonymous symbol, which is what WasmObjectWriter
63387af0b19SWouter van Oortmerssen       // expects to be able to recreate the actual unique-ified type indices.
63487af0b19SWouter van Oortmerssen       auto Loc = Parser.getTok();
6350eaee545SJonas Devlieghere       auto Signature = std::make_unique<wasm::WasmSignature>();
63687af0b19SWouter van Oortmerssen       if (parseSignature(Signature.get()))
63787af0b19SWouter van Oortmerssen         return true;
6382cb27072SThomas Lively       // Got signature as block type, don't need more
6392cb27072SThomas Lively       ExpectBlockType = false;
6409647a6f7SWouter van Oortmerssen       TC.setLastSig(*Signature.get());
6419647a6f7SWouter van Oortmerssen       if (ExpectBlockType)
6429647a6f7SWouter van Oortmerssen         NestingStack.back().Sig = *Signature.get();
6432632ba6aSAndy Wingo       auto &Ctx = getContext();
64487af0b19SWouter van Oortmerssen       // The "true" here will cause this to be a nameless symbol.
64587af0b19SWouter van Oortmerssen       MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
64687af0b19SWouter van Oortmerssen       auto *WasmSym = cast<MCSymbolWasm>(Sym);
64787af0b19SWouter van Oortmerssen       WasmSym->setSignature(Signature.get());
64887af0b19SWouter van Oortmerssen       addSignature(std::move(Signature));
64987af0b19SWouter van Oortmerssen       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
65087af0b19SWouter van Oortmerssen       const MCExpr *Expr = MCSymbolRefExpr::create(
65187af0b19SWouter van Oortmerssen           WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
6520eaee545SJonas Devlieghere       Operands.push_back(std::make_unique<WebAssemblyOperand>(
65387af0b19SWouter van Oortmerssen           WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
65487af0b19SWouter van Oortmerssen           WebAssemblyOperand::SymOp{Expr}));
65529c6ce58SWouter van Oortmerssen     }
65629c6ce58SWouter van Oortmerssen 
657e4825975SDerek Schuff     while (Lexer.isNot(AsmToken::EndOfStatement)) {
658e4825975SDerek Schuff       auto &Tok = Lexer.getTok();
659e4825975SDerek Schuff       switch (Tok.getKind()) {
660e4825975SDerek Schuff       case AsmToken::Identifier: {
661292e21d8SWouter van Oortmerssen         if (!parseSpecialFloatMaybe(false, Operands))
662292e21d8SWouter van Oortmerssen           break;
663e4825975SDerek Schuff         auto &Id = Lexer.getTok();
664ad72f685SWouter van Oortmerssen         if (ExpectBlockType) {
665ad72f685SWouter van Oortmerssen           // Assume this identifier is a block_type.
6660b2bc69bSHeejin Ahn           auto BT = WebAssembly::parseBlockType(Id.getString());
6672cb27072SThomas Lively           if (BT == WebAssembly::BlockType::Invalid)
668ad72f685SWouter van Oortmerssen             return error("Unknown block type: ", Id);
669ad72f685SWouter van Oortmerssen           addBlockTypeOperand(Operands, NameLoc, BT);
670ad72f685SWouter van Oortmerssen           Parser.Lex();
671ad72f685SWouter van Oortmerssen         } else {
67296ef4f30SSam Clegg           // Assume this identifier is a label.
673e4825975SDerek Schuff           const MCExpr *Val;
67461d5fa6bSAlex Bradbury           SMLoc Start = Id.getLoc();
675e4825975SDerek Schuff           SMLoc End;
676fc222e23SWouter van Oortmerssen           if (Parser.parseExpression(Val, End))
6777ce5edf1SHeejin Ahn             return error("Cannot parse symbol: ", Lexer.getTok());
6780eaee545SJonas Devlieghere           Operands.push_back(std::make_unique<WebAssemblyOperand>(
67961d5fa6bSAlex Bradbury               WebAssemblyOperand::Symbol, Start, End,
680f208f631SHeejin Ahn               WebAssemblyOperand::SymOp{Val}));
681fc222e23SWouter van Oortmerssen           if (checkForP2AlignIfLoadStore(Operands, Name))
682fc222e23SWouter van Oortmerssen             return true;
683ad72f685SWouter van Oortmerssen         }
684e4825975SDerek Schuff         break;
685e4825975SDerek Schuff       }
686e4825975SDerek Schuff       case AsmToken::Minus:
687e4825975SDerek Schuff         Parser.Lex();
688a617967dSWouter van Oortmerssen         if (Lexer.is(AsmToken::Integer)) {
689fc222e23SWouter van Oortmerssen           parseSingleInteger(true, Operands);
690fc222e23SWouter van Oortmerssen           if (checkForP2AlignIfLoadStore(Operands, Name))
691e4825975SDerek Schuff             return true;
692a617967dSWouter van Oortmerssen         } else if(Lexer.is(AsmToken::Real)) {
693a617967dSWouter van Oortmerssen           if (parseSingleFloat(true, Operands))
694a617967dSWouter van Oortmerssen             return true;
695292e21d8SWouter van Oortmerssen         } else if (!parseSpecialFloatMaybe(true, Operands)) {
696a617967dSWouter van Oortmerssen         } else {
697a617967dSWouter van Oortmerssen           return error("Expected numeric constant instead got: ",
698a617967dSWouter van Oortmerssen                        Lexer.getTok());
699a617967dSWouter van Oortmerssen         }
700e4825975SDerek Schuff         break;
701e4825975SDerek Schuff       case AsmToken::Integer:
702fc222e23SWouter van Oortmerssen         parseSingleInteger(false, Operands);
703fc222e23SWouter van Oortmerssen         if (checkForP2AlignIfLoadStore(Operands, Name))
704e4825975SDerek Schuff           return true;
705e4825975SDerek Schuff         break;
706e4825975SDerek Schuff       case AsmToken::Real: {
707a617967dSWouter van Oortmerssen         if (parseSingleFloat(false, Operands))
708a617967dSWouter van Oortmerssen           return true;
709e4825975SDerek Schuff         break;
710e4825975SDerek Schuff       }
711d3c544aaSWouter van Oortmerssen       case AsmToken::LCurly: {
712d3c544aaSWouter van Oortmerssen         Parser.Lex();
7130eaee545SJonas Devlieghere         auto Op = std::make_unique<WebAssemblyOperand>(
714d3c544aaSWouter van Oortmerssen             WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc());
715d3c544aaSWouter van Oortmerssen         if (!Lexer.is(AsmToken::RCurly))
716d3c544aaSWouter van Oortmerssen           for (;;) {
717d3c544aaSWouter van Oortmerssen             Op->BrL.List.push_back(Lexer.getTok().getIntVal());
718d3c544aaSWouter van Oortmerssen             expect(AsmToken::Integer, "integer");
719d3c544aaSWouter van Oortmerssen             if (!isNext(AsmToken::Comma))
720d3c544aaSWouter van Oortmerssen               break;
721d3c544aaSWouter van Oortmerssen           }
722d3c544aaSWouter van Oortmerssen         expect(AsmToken::RCurly, "}");
723d3c544aaSWouter van Oortmerssen         Operands.push_back(std::move(Op));
724d3c544aaSWouter van Oortmerssen         break;
725d3c544aaSWouter van Oortmerssen       }
726e4825975SDerek Schuff       default:
7277ce5edf1SHeejin Ahn         return error("Unexpected token in operand: ", Tok);
728e4825975SDerek Schuff       }
729e4825975SDerek Schuff       if (Lexer.isNot(AsmToken::EndOfStatement)) {
7307ce5edf1SHeejin Ahn         if (expect(AsmToken::Comma, ","))
731f208f631SHeejin Ahn           return true;
732e4825975SDerek Schuff       }
733e4825975SDerek Schuff     }
734ad72f685SWouter van Oortmerssen     if (ExpectBlockType && Operands.size() == 1) {
735ad72f685SWouter van Oortmerssen       // Support blocks with no operands as default to void.
7362cb27072SThomas Lively       addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
737e4825975SDerek Schuff     }
7384307069dSAndy Wingo     if (FunctionTable)
7394307069dSAndy Wingo       Operands.push_back(std::move(FunctionTable));
740ad72f685SWouter van Oortmerssen     Parser.Lex();
741e4825975SDerek Schuff     return false;
742e4825975SDerek Schuff   }
743e4825975SDerek Schuff 
parseSignature(wasm::WasmSignature * Signature)744be5e5874SHeejin Ahn   bool parseSignature(wasm::WasmSignature *Signature) {
745be5e5874SHeejin Ahn     if (expect(AsmToken::LParen, "("))
746be5e5874SHeejin Ahn       return true;
747be5e5874SHeejin Ahn     if (parseRegTypeList(Signature->Params))
748be5e5874SHeejin Ahn       return true;
749be5e5874SHeejin Ahn     if (expect(AsmToken::RParen, ")"))
750be5e5874SHeejin Ahn       return true;
751be5e5874SHeejin Ahn     if (expect(AsmToken::MinusGreater, "->"))
752be5e5874SHeejin Ahn       return true;
753be5e5874SHeejin Ahn     if (expect(AsmToken::LParen, "("))
754be5e5874SHeejin Ahn       return true;
755be5e5874SHeejin Ahn     if (parseRegTypeList(Signature->Returns))
756be5e5874SHeejin Ahn       return true;
757be5e5874SHeejin Ahn     if (expect(AsmToken::RParen, ")"))
758be5e5874SHeejin Ahn       return true;
759be5e5874SHeejin Ahn     return false;
760be5e5874SHeejin Ahn   }
761be5e5874SHeejin Ahn 
CheckDataSection()762f3feb6adSWouter van Oortmerssen   bool CheckDataSection() {
763f3feb6adSWouter van Oortmerssen     if (CurrentState != DataSection) {
764f3feb6adSWouter van Oortmerssen       auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
765f3feb6adSWouter van Oortmerssen       if (WS && WS->getKind().isText())
766f3feb6adSWouter van Oortmerssen         return error("data directive must occur in a data segment: ",
767f3feb6adSWouter van Oortmerssen                      Lexer.getTok());
768f3feb6adSWouter van Oortmerssen     }
769f3feb6adSWouter van Oortmerssen     CurrentState = DataSection;
770f3feb6adSWouter van Oortmerssen     return false;
771f3feb6adSWouter van Oortmerssen   }
772f3feb6adSWouter van Oortmerssen 
773cc75e77dSWouter van Oortmerssen   // This function processes wasm-specific directives streamed to
774cc75e77dSWouter van Oortmerssen   // WebAssemblyTargetStreamer, all others go to the generic parser
775cc75e77dSWouter van Oortmerssen   // (see WasmAsmParser).
ParseDirective(AsmToken DirectiveID)776e4825975SDerek Schuff   bool ParseDirective(AsmToken DirectiveID) override {
777de28b5d1SWouter van Oortmerssen     // This function has a really weird return value behavior that is different
778de28b5d1SWouter van Oortmerssen     // from all the other parsing functions:
779de28b5d1SWouter van Oortmerssen     // - return true && no tokens consumed -> don't know this directive / let
780de28b5d1SWouter van Oortmerssen     //   the generic parser handle it.
781de28b5d1SWouter van Oortmerssen     // - return true && tokens consumed -> a parsing error occurred.
782de28b5d1SWouter van Oortmerssen     // - return false -> processed this directive successfully.
783e4825975SDerek Schuff     assert(DirectiveID.getKind() == AsmToken::Identifier);
784e4825975SDerek Schuff     auto &Out = getStreamer();
785f208f631SHeejin Ahn     auto &TOut =
786f208f631SHeejin Ahn         reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
787f3b762a0SWouter van Oortmerssen     auto &Ctx = Out.getContext();
7887ce5edf1SHeejin Ahn 
789de28b5d1SWouter van Oortmerssen     // TODO: any time we return an error, at least one token must have been
790de28b5d1SWouter van Oortmerssen     // consumed, otherwise this will not signal an error to the caller.
791cc75e77dSWouter van Oortmerssen     if (DirectiveID.getString() == ".globaltype") {
7927ce5edf1SHeejin Ahn       auto SymName = expectIdent();
7937ce5edf1SHeejin Ahn       if (SymName.empty())
7947ce5edf1SHeejin Ahn         return true;
7957ce5edf1SHeejin Ahn       if (expect(AsmToken::Comma, ","))
7967ce5edf1SHeejin Ahn         return true;
79749482f82SWouter van Oortmerssen       auto TypeTok = Lexer.getTok();
7987ce5edf1SHeejin Ahn       auto TypeName = expectIdent();
7997ce5edf1SHeejin Ahn       if (TypeName.empty())
8007ce5edf1SHeejin Ahn         return true;
8010b2bc69bSHeejin Ahn       auto Type = WebAssembly::parseType(TypeName);
80249482f82SWouter van Oortmerssen       if (!Type)
8037ce5edf1SHeejin Ahn         return error("Unknown type in .globaltype directive: ", TypeTok);
804fa2a8accSSam Clegg       // Optional mutable modifier. Default to mutable for historical reasons.
805fa2a8accSSam Clegg       // Ideally we would have gone with immutable as the default and used `mut`
806fa2a8accSSam Clegg       // as the modifier to match the `.wat` format.
807fa2a8accSSam Clegg       bool Mutable = true;
808fa2a8accSSam Clegg       if (isNext(AsmToken::Comma)) {
809fa2a8accSSam Clegg         TypeTok = Lexer.getTok();
810fa2a8accSSam Clegg         auto Id = expectIdent();
811fa2a8accSSam Clegg         if (Id == "immutable")
812fa2a8accSSam Clegg           Mutable = false;
813fa2a8accSSam Clegg         else
814fa2a8accSSam Clegg           // Should we also allow `mutable` and `mut` here for clarity?
815fa2a8accSSam Clegg           return error("Unknown type in .globaltype modifier: ", TypeTok);
816fa2a8accSSam Clegg       }
817de28b5d1SWouter van Oortmerssen       // Now set this symbol with the correct type.
818f3b762a0SWouter van Oortmerssen       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
819de28b5d1SWouter van Oortmerssen       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
820*7a47ee51SKazu Hirata       WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable});
821de28b5d1SWouter van Oortmerssen       // And emit the directive again.
822de28b5d1SWouter van Oortmerssen       TOut.emitGlobalType(WasmSym);
8237ce5edf1SHeejin Ahn       return expect(AsmToken::EndOfStatement, "EOL");
8247ce5edf1SHeejin Ahn     }
8257ce5edf1SHeejin Ahn 
826388fb67bSPaulo Matos     if (DirectiveID.getString() == ".tabletype") {
827c9801db2SAndy Wingo       // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
828388fb67bSPaulo Matos       auto SymName = expectIdent();
829388fb67bSPaulo Matos       if (SymName.empty())
830388fb67bSPaulo Matos         return true;
831388fb67bSPaulo Matos       if (expect(AsmToken::Comma, ","))
832388fb67bSPaulo Matos         return true;
833c9801db2SAndy Wingo 
834c9801db2SAndy Wingo       auto ElemTypeTok = Lexer.getTok();
835c9801db2SAndy Wingo       auto ElemTypeName = expectIdent();
836c9801db2SAndy Wingo       if (ElemTypeName.empty())
837388fb67bSPaulo Matos         return true;
8380b2bc69bSHeejin Ahn       Optional<wasm::ValType> ElemType = WebAssembly::parseType(ElemTypeName);
839c9801db2SAndy Wingo       if (!ElemType)
840c9801db2SAndy Wingo         return error("Unknown type in .tabletype directive: ", ElemTypeTok);
841c9801db2SAndy Wingo 
842c9801db2SAndy Wingo       wasm::WasmLimits Limits = DefaultLimits();
843c9801db2SAndy Wingo       if (isNext(AsmToken::Comma) && parseLimits(&Limits))
844c9801db2SAndy Wingo         return true;
845388fb67bSPaulo Matos 
846388fb67bSPaulo Matos       // Now that we have the name and table type, we can actually create the
847388fb67bSPaulo Matos       // symbol
848388fb67bSPaulo Matos       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
849388fb67bSPaulo Matos       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
850*7a47ee51SKazu Hirata       wasm::WasmTableType Type = {uint8_t(*ElemType), Limits};
851c9801db2SAndy Wingo       WasmSym->setTableType(Type);
852388fb67bSPaulo Matos       TOut.emitTableType(WasmSym);
853388fb67bSPaulo Matos       return expect(AsmToken::EndOfStatement, "EOL");
854388fb67bSPaulo Matos     }
855388fb67bSPaulo Matos 
8567ce5edf1SHeejin Ahn     if (DirectiveID.getString() == ".functype") {
857c7b89f0fSWouter van Oortmerssen       // This code has to send things to the streamer similar to
858c7b89f0fSWouter van Oortmerssen       // WebAssemblyAsmPrinter::EmitFunctionBodyStart.
859c7b89f0fSWouter van Oortmerssen       // TODO: would be good to factor this into a common function, but the
860c7b89f0fSWouter van Oortmerssen       // assembler and backend really don't share any common code, and this code
8619301e3aaSMarek Kurdej       // parses the locals separately.
8627ce5edf1SHeejin Ahn       auto SymName = expectIdent();
8637ce5edf1SHeejin Ahn       if (SymName.empty())
8647ce5edf1SHeejin Ahn         return true;
865f3b762a0SWouter van Oortmerssen       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
866a872ee2fSWouter van Oortmerssen       if (WasmSym->isDefined()) {
867c7b89f0fSWouter van Oortmerssen         // This .functype indicates a start of a function.
86829c6ce58SWouter van Oortmerssen         if (ensureEmptyNestingStack())
86929c6ce58SWouter van Oortmerssen           return true;
870c7b89f0fSWouter van Oortmerssen         CurrentState = FunctionStart;
871a872ee2fSWouter van Oortmerssen         LastFunctionLabel = WasmSym;
87229c6ce58SWouter van Oortmerssen         push(Function);
873c7b89f0fSWouter van Oortmerssen       }
8740eaee545SJonas Devlieghere       auto Signature = std::make_unique<wasm::WasmSignature>();
875be5e5874SHeejin Ahn       if (parseSignature(Signature.get()))
8767ce5edf1SHeejin Ahn         return true;
8779647a6f7SWouter van Oortmerssen       TC.funcDecl(*Signature);
87849482f82SWouter van Oortmerssen       WasmSym->setSignature(Signature.get());
87949482f82SWouter van Oortmerssen       addSignature(std::move(Signature));
88049482f82SWouter van Oortmerssen       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
88149482f82SWouter van Oortmerssen       TOut.emitFunctionType(WasmSym);
882c7b89f0fSWouter van Oortmerssen       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
8837ce5edf1SHeejin Ahn       return expect(AsmToken::EndOfStatement, "EOL");
8847ce5edf1SHeejin Ahn     }
8857ce5edf1SHeejin Ahn 
886881d8778SSam Clegg     if (DirectiveID.getString() == ".export_name") {
887881d8778SSam Clegg       auto SymName = expectIdent();
888881d8778SSam Clegg       if (SymName.empty())
889881d8778SSam Clegg         return true;
890881d8778SSam Clegg       if (expect(AsmToken::Comma, ","))
891881d8778SSam Clegg         return true;
892881d8778SSam Clegg       auto ExportName = expectIdent();
893881d8778SSam Clegg       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
8945be42f36SSam Clegg       WasmSym->setExportName(storeName(ExportName));
895881d8778SSam Clegg       TOut.emitExportName(WasmSym, ExportName);
896881d8778SSam Clegg     }
897881d8778SSam Clegg 
898b4f4e370SSam Clegg     if (DirectiveID.getString() == ".import_module") {
899b4f4e370SSam Clegg       auto SymName = expectIdent();
900b4f4e370SSam Clegg       if (SymName.empty())
901b4f4e370SSam Clegg         return true;
902b4f4e370SSam Clegg       if (expect(AsmToken::Comma, ","))
903b4f4e370SSam Clegg         return true;
904b4f4e370SSam Clegg       auto ImportModule = expectIdent();
905b4f4e370SSam Clegg       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
9065be42f36SSam Clegg       WasmSym->setImportModule(storeName(ImportModule));
907b4f4e370SSam Clegg       TOut.emitImportModule(WasmSym, ImportModule);
908b4f4e370SSam Clegg     }
909b4f4e370SSam Clegg 
910b4f4e370SSam Clegg     if (DirectiveID.getString() == ".import_name") {
911b4f4e370SSam Clegg       auto SymName = expectIdent();
912b4f4e370SSam Clegg       if (SymName.empty())
913b4f4e370SSam Clegg         return true;
914b4f4e370SSam Clegg       if (expect(AsmToken::Comma, ","))
915b4f4e370SSam Clegg         return true;
916b4f4e370SSam Clegg       auto ImportName = expectIdent();
917b4f4e370SSam Clegg       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
9185be42f36SSam Clegg       WasmSym->setImportName(storeName(ImportName));
919b4f4e370SSam Clegg       TOut.emitImportName(WasmSym, ImportName);
920b4f4e370SSam Clegg     }
921b4f4e370SSam Clegg 
9221d891d44SHeejin Ahn     if (DirectiveID.getString() == ".tagtype") {
923be5e5874SHeejin Ahn       auto SymName = expectIdent();
924be5e5874SHeejin Ahn       if (SymName.empty())
925be5e5874SHeejin Ahn         return true;
926f3b762a0SWouter van Oortmerssen       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
9270eaee545SJonas Devlieghere       auto Signature = std::make_unique<wasm::WasmSignature>();
928be5e5874SHeejin Ahn       if (parseRegTypeList(Signature->Params))
929be5e5874SHeejin Ahn         return true;
930be5e5874SHeejin Ahn       WasmSym->setSignature(Signature.get());
931be5e5874SHeejin Ahn       addSignature(std::move(Signature));
9321d891d44SHeejin Ahn       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
9331d891d44SHeejin Ahn       TOut.emitTagType(WasmSym);
934be5e5874SHeejin Ahn       // TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
935be5e5874SHeejin Ahn       return expect(AsmToken::EndOfStatement, "EOL");
936be5e5874SHeejin Ahn     }
937be5e5874SHeejin Ahn 
9387ce5edf1SHeejin Ahn     if (DirectiveID.getString() == ".local") {
939c7b89f0fSWouter van Oortmerssen       if (CurrentState != FunctionStart)
940a872ee2fSWouter van Oortmerssen         return error(".local directive should follow the start of a function: ",
941c7b89f0fSWouter van Oortmerssen                      Lexer.getTok());
94249482f82SWouter van Oortmerssen       SmallVector<wasm::ValType, 4> Locals;
9437ce5edf1SHeejin Ahn       if (parseRegTypeList(Locals))
9447ce5edf1SHeejin Ahn         return true;
9459647a6f7SWouter van Oortmerssen       TC.localDecl(Locals);
946cc75e77dSWouter van Oortmerssen       TOut.emitLocal(Locals);
947c7b89f0fSWouter van Oortmerssen       CurrentState = FunctionLocals;
9487ce5edf1SHeejin Ahn       return expect(AsmToken::EndOfStatement, "EOL");
949cc75e77dSWouter van Oortmerssen     }
9507ce5edf1SHeejin Ahn 
951319c87d9SWouter van Oortmerssen     if (DirectiveID.getString() == ".int8" ||
952319c87d9SWouter van Oortmerssen         DirectiveID.getString() == ".int16" ||
953319c87d9SWouter van Oortmerssen         DirectiveID.getString() == ".int32" ||
954319c87d9SWouter van Oortmerssen         DirectiveID.getString() == ".int64") {
955f3feb6adSWouter van Oortmerssen       if (CheckDataSection()) return true;
956319c87d9SWouter van Oortmerssen       const MCExpr *Val;
957319c87d9SWouter van Oortmerssen       SMLoc End;
958319c87d9SWouter van Oortmerssen       if (Parser.parseExpression(Val, End))
959319c87d9SWouter van Oortmerssen         return error("Cannot parse .int expression: ", Lexer.getTok());
960319c87d9SWouter van Oortmerssen       size_t NumBits = 0;
961319c87d9SWouter van Oortmerssen       DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits);
96277497103SFangrui Song       Out.emitValue(Val, NumBits / 8, End);
963f3feb6adSWouter van Oortmerssen       return expect(AsmToken::EndOfStatement, "EOL");
964f3feb6adSWouter van Oortmerssen     }
965f3feb6adSWouter van Oortmerssen 
966f3feb6adSWouter van Oortmerssen     if (DirectiveID.getString() == ".asciz") {
967f3feb6adSWouter van Oortmerssen       if (CheckDataSection()) return true;
968f3feb6adSWouter van Oortmerssen       std::string S;
969f3feb6adSWouter van Oortmerssen       if (Parser.parseEscapedString(S))
970f3feb6adSWouter van Oortmerssen         return error("Cannot parse string constant: ", Lexer.getTok());
971a55daa14SFangrui Song       Out.emitBytes(StringRef(S.c_str(), S.length() + 1));
972f3feb6adSWouter van Oortmerssen       return expect(AsmToken::EndOfStatement, "EOL");
973f3feb6adSWouter van Oortmerssen     }
974f3feb6adSWouter van Oortmerssen 
975cc75e77dSWouter van Oortmerssen     return true; // We didn't process this directive.
976de28b5d1SWouter van Oortmerssen   }
977e4825975SDerek Schuff 
97819bf637eSSam Clegg   // Called either when the first instruction is parsed of the function ends.
ensureLocals(MCStreamer & Out)97919bf637eSSam Clegg   void ensureLocals(MCStreamer &Out) {
98019bf637eSSam Clegg     if (CurrentState == FunctionStart) {
98119bf637eSSam Clegg       // We haven't seen a .local directive yet. The streamer requires locals to
98219bf637eSSam Clegg       // be encoded as a prelude to the instructions, so emit an empty list of
98319bf637eSSam Clegg       // locals here.
98419bf637eSSam Clegg       auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>(
98519bf637eSSam Clegg           *Out.getTargetStreamer());
98619bf637eSSam Clegg       TOut.emitLocal(SmallVector<wasm::ValType, 0>());
98719bf637eSSam Clegg       CurrentState = FunctionLocals;
98819bf637eSSam Clegg     }
98919bf637eSSam Clegg   }
99019bf637eSSam Clegg 
MatchAndEmitInstruction(SMLoc IDLoc,unsigned &,OperandVector & Operands,MCStreamer & Out,uint64_t & ErrorInfo,bool MatchingInlineAsm)991e4825975SDerek Schuff   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/,
992f208f631SHeejin Ahn                                OperandVector &Operands, MCStreamer &Out,
993f208f631SHeejin Ahn                                uint64_t &ErrorInfo,
994e4825975SDerek Schuff                                bool MatchingInlineAsm) override {
995e4825975SDerek Schuff     MCInst Inst;
9967fee93edSWouter van Oortmerssen     Inst.setLoc(IDLoc);
9972985c02fSThomas Lively     FeatureBitset MissingFeatures;
9982985c02fSThomas Lively     unsigned MatchResult = MatchInstructionImpl(
9992985c02fSThomas Lively         Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm);
1000e4825975SDerek Schuff     switch (MatchResult) {
1001e4825975SDerek Schuff     case Match_Success: {
100219bf637eSSam Clegg       ensureLocals(Out);
10036b3f56b6SWouter van Oortmerssen       // Fix unknown p2align operands.
10046b3f56b6SWouter van Oortmerssen       auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode());
10056b3f56b6SWouter van Oortmerssen       if (Align != -1U) {
10066b3f56b6SWouter van Oortmerssen         auto &Op0 = Inst.getOperand(0);
10076b3f56b6SWouter van Oortmerssen         if (Op0.getImm() == -1)
10086b3f56b6SWouter van Oortmerssen           Op0.setImm(Align);
10096b3f56b6SWouter van Oortmerssen       }
10109647a6f7SWouter van Oortmerssen       if (is64) {
10113b29376eSWouter van Oortmerssen         // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having
10123b29376eSWouter van Oortmerssen         // an offset64 arg instead of offset32, but to the assembler matcher
10133b29376eSWouter van Oortmerssen         // they're both immediates so don't get selected for.
10143b29376eSWouter van Oortmerssen         auto Opc64 = WebAssembly::getWasm64Opcode(
10153b29376eSWouter van Oortmerssen             static_cast<uint16_t>(Inst.getOpcode()));
10163b29376eSWouter van Oortmerssen         if (Opc64 >= 0) {
10173b29376eSWouter van Oortmerssen           Inst.setOpcode(Opc64);
10183b29376eSWouter van Oortmerssen         }
10193b29376eSWouter van Oortmerssen       }
102001263751SAlex Bradbury       if (!SkipTypeCheck && TC.typeCheck(IDLoc, Inst, Operands))
10219647a6f7SWouter van Oortmerssen         return true;
1022bcd24b2dSFangrui Song       Out.emitInstruction(Inst, getSTI());
10230b3cf247SWouter van Oortmerssen       if (CurrentState == EndFunction) {
10249647a6f7SWouter van Oortmerssen         onEndOfFunction(IDLoc);
10250b3cf247SWouter van Oortmerssen       } else {
10260b3cf247SWouter van Oortmerssen         CurrentState = Instructions;
10270b3cf247SWouter van Oortmerssen       }
1028e4825975SDerek Schuff       return false;
1029e4825975SDerek Schuff     }
10302985c02fSThomas Lively     case Match_MissingFeature: {
10311a67522dSJordan Rupprecht       assert(MissingFeatures.count() > 0 && "Expected missing features");
10322985c02fSThomas Lively       SmallString<128> Message;
10332985c02fSThomas Lively       raw_svector_ostream OS(Message);
10342985c02fSThomas Lively       OS << "instruction requires:";
10352985c02fSThomas Lively       for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)
10362985c02fSThomas Lively         if (MissingFeatures.test(i))
10372985c02fSThomas Lively           OS << ' ' << getSubtargetFeatureName(i);
10382985c02fSThomas Lively       return Parser.Error(IDLoc, Message);
10392985c02fSThomas Lively     }
1040e4825975SDerek Schuff     case Match_MnemonicFail:
1041e4825975SDerek Schuff       return Parser.Error(IDLoc, "invalid instruction");
1042e4825975SDerek Schuff     case Match_NearMisses:
1043e4825975SDerek Schuff       return Parser.Error(IDLoc, "ambiguous instruction");
1044e4825975SDerek Schuff     case Match_InvalidTiedOperand:
1045e4825975SDerek Schuff     case Match_InvalidOperand: {
1046e4825975SDerek Schuff       SMLoc ErrorLoc = IDLoc;
1047e4825975SDerek Schuff       if (ErrorInfo != ~0ULL) {
1048e4825975SDerek Schuff         if (ErrorInfo >= Operands.size())
1049e4825975SDerek Schuff           return Parser.Error(IDLoc, "too few operands for instruction");
1050e4825975SDerek Schuff         ErrorLoc = Operands[ErrorInfo]->getStartLoc();
1051e4825975SDerek Schuff         if (ErrorLoc == SMLoc())
1052e4825975SDerek Schuff           ErrorLoc = IDLoc;
1053e4825975SDerek Schuff       }
1054e4825975SDerek Schuff       return Parser.Error(ErrorLoc, "invalid operand for instruction");
1055e4825975SDerek Schuff     }
1056e4825975SDerek Schuff     }
1057e4825975SDerek Schuff     llvm_unreachable("Implement any new match types added!");
1058e4825975SDerek Schuff   }
105929c6ce58SWouter van Oortmerssen 
doBeforeLabelEmit(MCSymbol * Symbol)10600b3cf247SWouter van Oortmerssen   void doBeforeLabelEmit(MCSymbol *Symbol) override {
10615e5b2cb1SWouter van Oortmerssen     // Code below only applies to labels in text sections.
10625e5b2cb1SWouter van Oortmerssen     auto CWS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
10635e5b2cb1SWouter van Oortmerssen     if (!CWS || !CWS->getKind().isText())
10645e5b2cb1SWouter van Oortmerssen       return;
10655e5b2cb1SWouter van Oortmerssen 
10665e5b2cb1SWouter van Oortmerssen     auto WasmSym = cast<MCSymbolWasm>(Symbol);
10675e5b2cb1SWouter van Oortmerssen     // Unlike other targets, we don't allow data in text sections (labels
10685e5b2cb1SWouter van Oortmerssen     // declared with .type @object).
10695e5b2cb1SWouter van Oortmerssen     if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) {
10705e5b2cb1SWouter van Oortmerssen       Parser.Error(Parser.getTok().getLoc(),
10715e5b2cb1SWouter van Oortmerssen                    "Wasm doesn\'t support data symbols in text sections");
10725e5b2cb1SWouter van Oortmerssen       return;
10735e5b2cb1SWouter van Oortmerssen     }
10745e5b2cb1SWouter van Oortmerssen 
10750b3cf247SWouter van Oortmerssen     // Start a new section for the next function automatically, since our
10760b3cf247SWouter van Oortmerssen     // object writer expects each function to have its own section. This way
10770b3cf247SWouter van Oortmerssen     // The user can't forget this "convention".
10780b3cf247SWouter van Oortmerssen     auto SymName = Symbol->getName();
10790b3cf247SWouter van Oortmerssen     if (SymName.startswith(".L"))
10800b3cf247SWouter van Oortmerssen       return; // Local Symbol.
10818d396acaSDerek Schuff 
10828d396acaSDerek Schuff     // TODO: If the user explicitly creates a new function section, we ignore
10838d396acaSDerek Schuff     // its name when we create this one. It would be nice to honor their
10848d396acaSDerek Schuff     // choice, while still ensuring that we create one if they forget.
10858d396acaSDerek Schuff     // (that requires coordination with WasmAsmParser::parseSectionDirective)
10860b3cf247SWouter van Oortmerssen     auto SecName = ".text." + SymName;
10878d396acaSDerek Schuff 
10888d396acaSDerek Schuff     auto *Group = CWS->getGroup();
10898d396acaSDerek Schuff     // If the current section is a COMDAT, also set the flag on the symbol.
10908d396acaSDerek Schuff     // TODO: Currently the only place that the symbols' comdat flag matters is
10918d396acaSDerek Schuff     // for importing comdat functions. But there's no way to specify that in
10928d396acaSDerek Schuff     // assembly currently.
10938d396acaSDerek Schuff     if (Group)
10945e5b2cb1SWouter van Oortmerssen       WasmSym->setComdat(true);
10958d396acaSDerek Schuff     auto *WS =
10963b8d2be5SSam Clegg         getContext().getWasmSection(SecName, SectionKind::getText(), 0, Group,
10978d396acaSDerek Schuff                                     MCContext::GenericSectionID, nullptr);
1098adf4142fSFangrui Song     getStreamer().switchSection(WS);
1099da6a896eSDerek Schuff     // Also generate DWARF for this section if requested.
1100da6a896eSDerek Schuff     if (getContext().getGenDwarfForAssembly())
1101da6a896eSDerek Schuff       getContext().addGenDwarfSection(WS);
11020b3cf247SWouter van Oortmerssen   }
11030b3cf247SWouter van Oortmerssen 
onEndOfFunction(SMLoc ErrorLoc)11049647a6f7SWouter van Oortmerssen   void onEndOfFunction(SMLoc ErrorLoc) {
11054e8b2ac7SAlex Bradbury     if (!SkipTypeCheck)
11069647a6f7SWouter van Oortmerssen       TC.endOfFunction(ErrorLoc);
1107ac653664SWouter van Oortmerssen     // Reset the type checker state.
1108ac653664SWouter van Oortmerssen     TC.Clear();
11099647a6f7SWouter van Oortmerssen 
11100b3cf247SWouter van Oortmerssen     // Automatically output a .size directive, so it becomes optional for the
11110b3cf247SWouter van Oortmerssen     // user.
1112f3feb6adSWouter van Oortmerssen     if (!LastFunctionLabel) return;
11130b3cf247SWouter van Oortmerssen     auto TempSym = getContext().createLinkerPrivateTempSymbol();
11146d2d589bSFangrui Song     getStreamer().emitLabel(TempSym);
1115f3feb6adSWouter van Oortmerssen     auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
11160b3cf247SWouter van Oortmerssen     auto End = MCSymbolRefExpr::create(TempSym, getContext());
11170b3cf247SWouter van Oortmerssen     auto Expr =
11180b3cf247SWouter van Oortmerssen         MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
11190b3cf247SWouter van Oortmerssen     getStreamer().emitELFSize(LastFunctionLabel, Expr);
11200b3cf247SWouter van Oortmerssen   }
11210b3cf247SWouter van Oortmerssen 
onEndOfFile()112229c6ce58SWouter van Oortmerssen   void onEndOfFile() override { ensureEmptyNestingStack(); }
1123e4825975SDerek Schuff };
1124e4825975SDerek Schuff } // end anonymous namespace
1125e4825975SDerek Schuff 
1126e4825975SDerek Schuff // Force static initialization.
LLVMInitializeWebAssemblyAsmParser()11270dbcb363STom Stellard extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser() {
1128e4825975SDerek Schuff   RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32());
1129e4825975SDerek Schuff   RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64());
1130e4825975SDerek Schuff }
1131e4825975SDerek Schuff 
1132e4825975SDerek Schuff #define GET_REGISTER_MATCHER
11332985c02fSThomas Lively #define GET_SUBTARGET_FEATURE_NAME
1134e4825975SDerek Schuff #define GET_MATCHER_IMPLEMENTATION
1135e4825975SDerek Schuff #include "WebAssemblyGenAsmMatcher.inc"
11369647a6f7SWouter van Oortmerssen 
GetMnemonic(unsigned Opc)11379647a6f7SWouter van Oortmerssen StringRef GetMnemonic(unsigned Opc) {
11389647a6f7SWouter van Oortmerssen   // FIXME: linear search!
11399647a6f7SWouter van Oortmerssen   for (auto &ME : MatchTable0) {
11409647a6f7SWouter van Oortmerssen     if (ME.Opcode == Opc) {
11419647a6f7SWouter van Oortmerssen       return ME.getMnemonic();
11429647a6f7SWouter van Oortmerssen     }
11439647a6f7SWouter van Oortmerssen   }
11449647a6f7SWouter van Oortmerssen   assert(false && "mnemonic not found");
11459647a6f7SWouter van Oortmerssen   return StringRef();
11469647a6f7SWouter van Oortmerssen }
1147