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