1 //==- WebAssemblyAsmParser.cpp - Assembler for WebAssembly -*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This file is part of the WebAssembly Assembler. 12 /// 13 /// It contains code to translate a parsed .s file into MCInsts. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18 #include "MCTargetDesc/WebAssemblyTargetStreamer.h" 19 #include "WebAssembly.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCInst.h" 22 #include "llvm/MC/MCInstrInfo.h" 23 #include "llvm/MC/MCParser/MCParsedAsmOperand.h" 24 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 25 #include "llvm/MC/MCStreamer.h" 26 #include "llvm/MC/MCSubtargetInfo.h" 27 #include "llvm/MC/MCSymbol.h" 28 #include "llvm/MC/MCSymbolWasm.h" 29 #include "llvm/Support/Endian.h" 30 #include "llvm/Support/TargetRegistry.h" 31 32 using namespace llvm; 33 34 #define DEBUG_TYPE "wasm-asm-parser" 35 36 namespace { 37 38 /// WebAssemblyOperand - Instances of this class represent the operands in a 39 /// parsed WASM machine instruction. 40 struct WebAssemblyOperand : public MCParsedAsmOperand { 41 enum KindTy { Token, Integer, Float, Symbol, BrList } Kind; 42 43 SMLoc StartLoc, EndLoc; 44 45 struct TokOp { 46 StringRef Tok; 47 }; 48 49 struct IntOp { 50 int64_t Val; 51 }; 52 53 struct FltOp { 54 double Val; 55 }; 56 57 struct SymOp { 58 const MCExpr *Exp; 59 }; 60 61 struct BrLOp { 62 std::vector<unsigned> List; 63 }; 64 65 union { 66 struct TokOp Tok; 67 struct IntOp Int; 68 struct FltOp Flt; 69 struct SymOp Sym; 70 struct BrLOp BrL; 71 }; 72 73 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, TokOp T) 74 : Kind(K), StartLoc(Start), EndLoc(End), Tok(T) {} 75 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, IntOp I) 76 : Kind(K), StartLoc(Start), EndLoc(End), Int(I) {} 77 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, FltOp F) 78 : Kind(K), StartLoc(Start), EndLoc(End), Flt(F) {} 79 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End, SymOp S) 80 : Kind(K), StartLoc(Start), EndLoc(End), Sym(S) {} 81 WebAssemblyOperand(KindTy K, SMLoc Start, SMLoc End) 82 : Kind(K), StartLoc(Start), EndLoc(End), BrL() {} 83 84 ~WebAssemblyOperand() { 85 if (isBrList()) 86 BrL.~BrLOp(); 87 } 88 89 bool isToken() const override { return Kind == Token; } 90 bool isImm() const override { 91 return Kind == Integer || Kind == Float || Kind == Symbol; 92 } 93 bool isMem() const override { return false; } 94 bool isReg() const override { return false; } 95 bool isBrList() const { return Kind == BrList; } 96 97 unsigned getReg() const override { 98 llvm_unreachable("Assembly inspects a register operand"); 99 return 0; 100 } 101 102 StringRef getToken() const { 103 assert(isToken()); 104 return Tok.Tok; 105 } 106 107 SMLoc getStartLoc() const override { return StartLoc; } 108 SMLoc getEndLoc() const override { return EndLoc; } 109 110 void addRegOperands(MCInst &, unsigned) const { 111 // Required by the assembly matcher. 112 llvm_unreachable("Assembly matcher creates register operands"); 113 } 114 115 void addImmOperands(MCInst &Inst, unsigned N) const { 116 assert(N == 1 && "Invalid number of operands!"); 117 if (Kind == Integer) 118 Inst.addOperand(MCOperand::createImm(Int.Val)); 119 else if (Kind == Float) 120 Inst.addOperand(MCOperand::createFPImm(Flt.Val)); 121 else if (Kind == Symbol) 122 Inst.addOperand(MCOperand::createExpr(Sym.Exp)); 123 else 124 llvm_unreachable("Should be immediate or symbol!"); 125 } 126 127 void addBrListOperands(MCInst &Inst, unsigned N) const { 128 assert(N == 1 && isBrList() && "Invalid BrList!"); 129 for (auto Br : BrL.List) 130 Inst.addOperand(MCOperand::createImm(Br)); 131 } 132 133 void print(raw_ostream &OS) const override { 134 switch (Kind) { 135 case Token: 136 OS << "Tok:" << Tok.Tok; 137 break; 138 case Integer: 139 OS << "Int:" << Int.Val; 140 break; 141 case Float: 142 OS << "Flt:" << Flt.Val; 143 break; 144 case Symbol: 145 OS << "Sym:" << Sym.Exp; 146 break; 147 case BrList: 148 OS << "BrList:" << BrL.List.size(); 149 break; 150 } 151 } 152 }; 153 154 class WebAssemblyAsmParser final : public MCTargetAsmParser { 155 MCAsmParser &Parser; 156 MCAsmLexer &Lexer; 157 158 // Much like WebAssemblyAsmPrinter in the backend, we have to own these. 159 std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures; 160 161 // Order of labels, directives and instructions in a .s file have no 162 // syntactical enforcement. This class is a callback from the actual parser, 163 // and yet we have to be feeding data to the streamer in a very particular 164 // order to ensure a correct binary encoding that matches the regular backend 165 // (the streamer does not enforce this). This "state machine" enum helps 166 // guarantee that correct order. 167 enum ParserState { 168 FileStart, 169 Label, 170 FunctionStart, 171 FunctionLocals, 172 Instructions, 173 } CurrentState = FileStart; 174 175 // For ensuring blocks are properly nested. 176 enum NestingType { 177 Function, 178 Block, 179 Loop, 180 Try, 181 If, 182 Else, 183 Undefined, 184 }; 185 std::vector<NestingType> NestingStack; 186 187 // We track this to see if a .functype following a label is the same, 188 // as this is how we recognize the start of a function. 189 MCSymbol *LastLabel = nullptr; 190 191 public: 192 WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, 193 const MCInstrInfo &MII, const MCTargetOptions &Options) 194 : MCTargetAsmParser(Options, STI, MII), Parser(Parser), 195 Lexer(Parser.getLexer()) { 196 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); 197 } 198 199 #define GET_ASSEMBLER_HEADER 200 #include "WebAssemblyGenAsmMatcher.inc" 201 202 // TODO: This is required to be implemented, but appears unused. 203 bool ParseRegister(unsigned & /*RegNo*/, SMLoc & /*StartLoc*/, 204 SMLoc & /*EndLoc*/) override { 205 llvm_unreachable("ParseRegister is not implemented."); 206 } 207 208 bool error(const Twine &Msg, const AsmToken &Tok) { 209 return Parser.Error(Tok.getLoc(), Msg + Tok.getString()); 210 } 211 212 bool error(const Twine &Msg) { 213 return Parser.Error(Lexer.getTok().getLoc(), Msg); 214 } 215 216 void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) { 217 Signatures.push_back(std::move(Sig)); 218 } 219 220 std::pair<StringRef, StringRef> nestingString(NestingType NT) { 221 switch (NT) { 222 case Function: 223 return {"function", "end_function"}; 224 case Block: 225 return {"block", "end_block"}; 226 case Loop: 227 return {"loop", "end_loop"}; 228 case Try: 229 return {"try", "end_try"}; 230 case If: 231 return {"if", "end_if"}; 232 case Else: 233 return {"else", "end_if"}; 234 default: 235 llvm_unreachable("unknown NestingType"); 236 } 237 } 238 239 void push(NestingType NT) { NestingStack.push_back(NT); } 240 241 bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) { 242 if (NestingStack.empty()) 243 return error(Twine("End of block construct with no start: ") + Ins); 244 auto Top = NestingStack.back(); 245 if (Top != NT1 && Top != NT2) 246 return error(Twine("Block construct type mismatch, expected: ") + 247 nestingString(Top).second + ", instead got: " + Ins); 248 NestingStack.pop_back(); 249 return false; 250 } 251 252 bool ensureEmptyNestingStack() { 253 auto err = !NestingStack.empty(); 254 while (!NestingStack.empty()) { 255 error(Twine("Unmatched block construct(s) at function end: ") + 256 nestingString(NestingStack.back()).first); 257 NestingStack.pop_back(); 258 } 259 return err; 260 } 261 262 bool isNext(AsmToken::TokenKind Kind) { 263 auto Ok = Lexer.is(Kind); 264 if (Ok) 265 Parser.Lex(); 266 return Ok; 267 } 268 269 bool expect(AsmToken::TokenKind Kind, const char *KindName) { 270 if (!isNext(Kind)) 271 return error(std::string("Expected ") + KindName + ", instead got: ", 272 Lexer.getTok()); 273 return false; 274 } 275 276 StringRef expectIdent() { 277 if (!Lexer.is(AsmToken::Identifier)) { 278 error("Expected identifier, got: ", Lexer.getTok()); 279 return StringRef(); 280 } 281 auto Name = Lexer.getTok().getString(); 282 Parser.Lex(); 283 return Name; 284 } 285 286 Optional<wasm::ValType> parseType(const StringRef &Type) { 287 // FIXME: can't use StringSwitch because wasm::ValType doesn't have a 288 // "invalid" value. 289 if (Type == "i32") 290 return wasm::ValType::I32; 291 if (Type == "i64") 292 return wasm::ValType::I64; 293 if (Type == "f32") 294 return wasm::ValType::F32; 295 if (Type == "f64") 296 return wasm::ValType::F64; 297 if (Type == "v128" || Type == "i8x16" || Type == "i16x8" || 298 Type == "i32x4" || Type == "i64x2" || Type == "f32x4" || 299 Type == "f64x2") 300 return wasm::ValType::V128; 301 return Optional<wasm::ValType>(); 302 } 303 304 WebAssembly::ExprType parseBlockType(StringRef ID) { 305 return StringSwitch<WebAssembly::ExprType>(ID) 306 .Case("i32", WebAssembly::ExprType::I32) 307 .Case("i64", WebAssembly::ExprType::I64) 308 .Case("f32", WebAssembly::ExprType::F32) 309 .Case("f64", WebAssembly::ExprType::F64) 310 .Case("v128", WebAssembly::ExprType::V128) 311 .Case("except_ref", WebAssembly::ExprType::ExceptRef) 312 .Case("void", WebAssembly::ExprType::Void) 313 .Default(WebAssembly::ExprType::Invalid); 314 } 315 316 bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) { 317 while (Lexer.is(AsmToken::Identifier)) { 318 auto Type = parseType(Lexer.getTok().getString()); 319 if (!Type) 320 return true; 321 Types.push_back(Type.getValue()); 322 Parser.Lex(); 323 if (!isNext(AsmToken::Comma)) 324 break; 325 } 326 return false; 327 } 328 329 void parseSingleInteger(bool IsNegative, OperandVector &Operands) { 330 auto &Int = Lexer.getTok(); 331 int64_t Val = Int.getIntVal(); 332 if (IsNegative) 333 Val = -Val; 334 Operands.push_back(make_unique<WebAssemblyOperand>( 335 WebAssemblyOperand::Integer, Int.getLoc(), Int.getEndLoc(), 336 WebAssemblyOperand::IntOp{Val})); 337 Parser.Lex(); 338 } 339 340 bool parseOperandStartingWithInteger(bool IsNegative, OperandVector &Operands, 341 StringRef InstName) { 342 parseSingleInteger(IsNegative, Operands); 343 // FIXME: there is probably a cleaner way to do this. 344 auto IsLoadStore = InstName.startswith("load") || 345 InstName.startswith("store") || 346 InstName.startswith("atomic_load") || 347 InstName.startswith("atomic_store"); 348 if (IsLoadStore) { 349 // Parse load/store operands of the form: offset align 350 auto &Offset = Lexer.getTok(); 351 if (Offset.is(AsmToken::Integer)) { 352 parseSingleInteger(false, Operands); 353 } else { 354 // Alignment not specified. 355 // FIXME: correctly derive a default from the instruction. 356 // We can't just call WebAssembly::GetDefaultP2Align since we don't have 357 // an opcode until after the assembly matcher. 358 Operands.push_back(make_unique<WebAssemblyOperand>( 359 WebAssemblyOperand::Integer, Offset.getLoc(), Offset.getEndLoc(), 360 WebAssemblyOperand::IntOp{0})); 361 } 362 } 363 return false; 364 } 365 366 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc, 367 WebAssembly::ExprType BT) { 368 Operands.push_back(make_unique<WebAssemblyOperand>( 369 WebAssemblyOperand::Integer, NameLoc, NameLoc, 370 WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)})); 371 } 372 373 bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name, 374 SMLoc NameLoc, OperandVector &Operands) override { 375 // Note: Name does NOT point into the sourcecode, but to a local, so 376 // use NameLoc instead. 377 Name = StringRef(NameLoc.getPointer(), Name.size()); 378 379 // WebAssembly has instructions with / in them, which AsmLexer parses 380 // as seperate tokens, so if we find such tokens immediately adjacent (no 381 // whitespace), expand the name to include them: 382 for (;;) { 383 auto &Sep = Lexer.getTok(); 384 if (Sep.getLoc().getPointer() != Name.end() || 385 Sep.getKind() != AsmToken::Slash) 386 break; 387 // Extend name with / 388 Name = StringRef(Name.begin(), Name.size() + Sep.getString().size()); 389 Parser.Lex(); 390 // We must now find another identifier, or error. 391 auto &Id = Lexer.getTok(); 392 if (Id.getKind() != AsmToken::Identifier || 393 Id.getLoc().getPointer() != Name.end()) 394 return error("Incomplete instruction name: ", Id); 395 Name = StringRef(Name.begin(), Name.size() + Id.getString().size()); 396 Parser.Lex(); 397 } 398 399 // Now construct the name as first operand. 400 Operands.push_back(make_unique<WebAssemblyOperand>( 401 WebAssemblyOperand::Token, NameLoc, SMLoc::getFromPointer(Name.end()), 402 WebAssemblyOperand::TokOp{Name})); 403 auto NamePair = Name.split('.'); 404 // If no '.', there is no type prefix. 405 auto BaseName = NamePair.second.empty() ? NamePair.first : NamePair.second; 406 407 // If this instruction is part of a control flow structure, ensure 408 // proper nesting. 409 bool ExpectBlockType = false; 410 if (BaseName == "block") { 411 push(Block); 412 ExpectBlockType = true; 413 } else if (BaseName == "loop") { 414 push(Loop); 415 ExpectBlockType = true; 416 } else if (BaseName == "try") { 417 push(Try); 418 ExpectBlockType = true; 419 } else if (BaseName == "if") { 420 push(If); 421 ExpectBlockType = true; 422 } else if (BaseName == "else") { 423 if (pop(BaseName, If)) 424 return true; 425 push(Else); 426 } else if (BaseName == "catch") { 427 if (pop(BaseName, Try)) 428 return true; 429 push(Try); 430 } else if (BaseName == "catch_all") { 431 if (pop(BaseName, Try)) 432 return true; 433 push(Try); 434 } else if (BaseName == "end_if") { 435 if (pop(BaseName, If, Else)) 436 return true; 437 } else if (BaseName == "end_try") { 438 if (pop(BaseName, Try)) 439 return true; 440 } else if (BaseName == "end_loop") { 441 if (pop(BaseName, Loop)) 442 return true; 443 } else if (BaseName == "end_block") { 444 if (pop(BaseName, Block)) 445 return true; 446 } else if (BaseName == "end_function") { 447 if (pop(BaseName, Function) || ensureEmptyNestingStack()) 448 return true; 449 } 450 451 while (Lexer.isNot(AsmToken::EndOfStatement)) { 452 auto &Tok = Lexer.getTok(); 453 switch (Tok.getKind()) { 454 case AsmToken::Identifier: { 455 auto &Id = Lexer.getTok(); 456 if (ExpectBlockType) { 457 // Assume this identifier is a block_type. 458 auto BT = parseBlockType(Id.getString()); 459 if (BT == WebAssembly::ExprType::Invalid) 460 return error("Unknown block type: ", Id); 461 addBlockTypeOperand(Operands, NameLoc, BT); 462 Parser.Lex(); 463 } else { 464 // Assume this identifier is a label. 465 const MCExpr *Val; 466 SMLoc End; 467 if (Parser.parsePrimaryExpr(Val, End)) 468 return error("Cannot parse symbol: ", Lexer.getTok()); 469 Operands.push_back(make_unique<WebAssemblyOperand>( 470 WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), 471 WebAssemblyOperand::SymOp{Val})); 472 } 473 break; 474 } 475 case AsmToken::Minus: 476 Parser.Lex(); 477 if (Lexer.isNot(AsmToken::Integer)) 478 return error("Expected integer instead got: ", Lexer.getTok()); 479 if (parseOperandStartingWithInteger(true, Operands, BaseName)) 480 return true; 481 break; 482 case AsmToken::Integer: 483 if (parseOperandStartingWithInteger(false, Operands, BaseName)) 484 return true; 485 break; 486 case AsmToken::Real: { 487 double Val; 488 if (Tok.getString().getAsDouble(Val, false)) 489 return error("Cannot parse real: ", Tok); 490 Operands.push_back(make_unique<WebAssemblyOperand>( 491 WebAssemblyOperand::Float, Tok.getLoc(), Tok.getEndLoc(), 492 WebAssemblyOperand::FltOp{Val})); 493 Parser.Lex(); 494 break; 495 } 496 case AsmToken::LCurly: { 497 Parser.Lex(); 498 auto Op = make_unique<WebAssemblyOperand>( 499 WebAssemblyOperand::BrList, Tok.getLoc(), Tok.getEndLoc()); 500 if (!Lexer.is(AsmToken::RCurly)) 501 for (;;) { 502 Op->BrL.List.push_back(Lexer.getTok().getIntVal()); 503 expect(AsmToken::Integer, "integer"); 504 if (!isNext(AsmToken::Comma)) 505 break; 506 } 507 expect(AsmToken::RCurly, "}"); 508 Operands.push_back(std::move(Op)); 509 break; 510 } 511 default: 512 return error("Unexpected token in operand: ", Tok); 513 } 514 if (Lexer.isNot(AsmToken::EndOfStatement)) { 515 if (expect(AsmToken::Comma, ",")) 516 return true; 517 } 518 } 519 if (ExpectBlockType && Operands.size() == 1) { 520 // Support blocks with no operands as default to void. 521 addBlockTypeOperand(Operands, NameLoc, WebAssembly::ExprType::Void); 522 } 523 Parser.Lex(); 524 return false; 525 } 526 527 void onLabelParsed(MCSymbol *Symbol) override { 528 LastLabel = Symbol; 529 CurrentState = Label; 530 } 531 532 bool parseSignature(wasm::WasmSignature *Signature) { 533 if (expect(AsmToken::LParen, "(")) 534 return true; 535 if (parseRegTypeList(Signature->Params)) 536 return true; 537 if (expect(AsmToken::RParen, ")")) 538 return true; 539 if (expect(AsmToken::MinusGreater, "->")) 540 return true; 541 if (expect(AsmToken::LParen, "(")) 542 return true; 543 if (parseRegTypeList(Signature->Returns)) 544 return true; 545 if (expect(AsmToken::RParen, ")")) 546 return true; 547 return false; 548 } 549 550 // This function processes wasm-specific directives streamed to 551 // WebAssemblyTargetStreamer, all others go to the generic parser 552 // (see WasmAsmParser). 553 bool ParseDirective(AsmToken DirectiveID) override { 554 // This function has a really weird return value behavior that is different 555 // from all the other parsing functions: 556 // - return true && no tokens consumed -> don't know this directive / let 557 // the generic parser handle it. 558 // - return true && tokens consumed -> a parsing error occurred. 559 // - return false -> processed this directive successfully. 560 assert(DirectiveID.getKind() == AsmToken::Identifier); 561 auto &Out = getStreamer(); 562 auto &TOut = 563 reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer()); 564 565 // TODO: any time we return an error, at least one token must have been 566 // consumed, otherwise this will not signal an error to the caller. 567 if (DirectiveID.getString() == ".globaltype") { 568 auto SymName = expectIdent(); 569 if (SymName.empty()) 570 return true; 571 if (expect(AsmToken::Comma, ",")) 572 return true; 573 auto TypeTok = Lexer.getTok(); 574 auto TypeName = expectIdent(); 575 if (TypeName.empty()) 576 return true; 577 auto Type = parseType(TypeName); 578 if (!Type) 579 return error("Unknown type in .globaltype directive: ", TypeTok); 580 // Now set this symbol with the correct type. 581 auto WasmSym = cast<MCSymbolWasm>( 582 TOut.getStreamer().getContext().getOrCreateSymbol(SymName)); 583 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 584 WasmSym->setGlobalType( 585 wasm::WasmGlobalType{uint8_t(Type.getValue()), true}); 586 // And emit the directive again. 587 TOut.emitGlobalType(WasmSym); 588 return expect(AsmToken::EndOfStatement, "EOL"); 589 } 590 591 if (DirectiveID.getString() == ".functype") { 592 // This code has to send things to the streamer similar to 593 // WebAssemblyAsmPrinter::EmitFunctionBodyStart. 594 // TODO: would be good to factor this into a common function, but the 595 // assembler and backend really don't share any common code, and this code 596 // parses the locals seperately. 597 auto SymName = expectIdent(); 598 if (SymName.empty()) 599 return true; 600 auto WasmSym = cast<MCSymbolWasm>( 601 TOut.getStreamer().getContext().getOrCreateSymbol(SymName)); 602 if (CurrentState == Label && WasmSym == LastLabel) { 603 // This .functype indicates a start of a function. 604 if (ensureEmptyNestingStack()) 605 return true; 606 CurrentState = FunctionStart; 607 push(Function); 608 } 609 auto Signature = make_unique<wasm::WasmSignature>(); 610 if (parseSignature(Signature.get())) 611 return true; 612 WasmSym->setSignature(Signature.get()); 613 addSignature(std::move(Signature)); 614 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 615 TOut.emitFunctionType(WasmSym); 616 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented. 617 return expect(AsmToken::EndOfStatement, "EOL"); 618 } 619 620 if (DirectiveID.getString() == ".eventtype") { 621 auto SymName = expectIdent(); 622 if (SymName.empty()) 623 return true; 624 auto WasmSym = cast<MCSymbolWasm>( 625 TOut.getStreamer().getContext().getOrCreateSymbol(SymName)); 626 auto Signature = make_unique<wasm::WasmSignature>(); 627 if (parseRegTypeList(Signature->Params)) 628 return true; 629 WasmSym->setSignature(Signature.get()); 630 addSignature(std::move(Signature)); 631 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT); 632 TOut.emitEventType(WasmSym); 633 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented. 634 return expect(AsmToken::EndOfStatement, "EOL"); 635 } 636 637 if (DirectiveID.getString() == ".local") { 638 if (CurrentState != FunctionStart) 639 return error(".local directive should follow the start of a function", 640 Lexer.getTok()); 641 SmallVector<wasm::ValType, 4> Locals; 642 if (parseRegTypeList(Locals)) 643 return true; 644 TOut.emitLocal(Locals); 645 CurrentState = FunctionLocals; 646 return expect(AsmToken::EndOfStatement, "EOL"); 647 } 648 649 return true; // We didn't process this directive. 650 } 651 652 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/, 653 OperandVector &Operands, MCStreamer &Out, 654 uint64_t &ErrorInfo, 655 bool MatchingInlineAsm) override { 656 MCInst Inst; 657 unsigned MatchResult = 658 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); 659 switch (MatchResult) { 660 case Match_Success: { 661 if (CurrentState == FunctionStart) { 662 // This is the first instruction in a function, but we haven't seen 663 // a .local directive yet. The streamer requires locals to be encoded 664 // as a prelude to the instructions, so emit an empty list of locals 665 // here. 666 auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>( 667 *Out.getTargetStreamer()); 668 TOut.emitLocal(SmallVector<wasm::ValType, 0>()); 669 } 670 CurrentState = Instructions; 671 Out.EmitInstruction(Inst, getSTI()); 672 return false; 673 } 674 case Match_MissingFeature: 675 return Parser.Error( 676 IDLoc, "instruction requires a WASM feature not currently enabled"); 677 case Match_MnemonicFail: 678 return Parser.Error(IDLoc, "invalid instruction"); 679 case Match_NearMisses: 680 return Parser.Error(IDLoc, "ambiguous instruction"); 681 case Match_InvalidTiedOperand: 682 case Match_InvalidOperand: { 683 SMLoc ErrorLoc = IDLoc; 684 if (ErrorInfo != ~0ULL) { 685 if (ErrorInfo >= Operands.size()) 686 return Parser.Error(IDLoc, "too few operands for instruction"); 687 ErrorLoc = Operands[ErrorInfo]->getStartLoc(); 688 if (ErrorLoc == SMLoc()) 689 ErrorLoc = IDLoc; 690 } 691 return Parser.Error(ErrorLoc, "invalid operand for instruction"); 692 } 693 } 694 llvm_unreachable("Implement any new match types added!"); 695 } 696 697 void onEndOfFile() override { ensureEmptyNestingStack(); } 698 }; 699 } // end anonymous namespace 700 701 // Force static initialization. 702 extern "C" void LLVMInitializeWebAssemblyAsmParser() { 703 RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32()); 704 RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64()); 705 } 706 707 #define GET_REGISTER_MATCHER 708 #define GET_MATCHER_IMPLEMENTATION 709 #include "WebAssemblyGenAsmMatcher.inc" 710