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