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