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