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 "AsmParser/WebAssemblyAsmTypeCheck.h" 17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18 #include "MCTargetDesc/WebAssemblyMCTypeUtilities.h" 19 #include "MCTargetDesc/WebAssemblyTargetStreamer.h" 20 #include "TargetInfo/WebAssemblyTargetInfo.h" 21 #include "llvm/MC/MCContext.h" 22 #include "llvm/MC/MCExpr.h" 23 #include "llvm/MC/MCInst.h" 24 #include "llvm/MC/MCInstrInfo.h" 25 #include "llvm/MC/MCParser/MCAsmLexer.h" 26 #include "llvm/MC/MCParser/MCParsedAsmOperand.h" 27 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 28 #include "llvm/MC/MCSectionWasm.h" 29 #include "llvm/MC/MCStreamer.h" 30 #include "llvm/MC/MCSubtargetInfo.h" 31 #include "llvm/MC/MCSymbol.h" 32 #include "llvm/MC/MCSymbolWasm.h" 33 #include "llvm/MC/TargetRegistry.h" 34 #include "llvm/Support/SourceMgr.h" 35 36 using namespace llvm; 37 38 #define DEBUG_TYPE "wasm-asm-parser" 39 40 static const char *getSubtargetFeatureName(uint64_t Val); 41 42 namespace { 43 44 /// WebAssemblyOperand - Instances of this class represent the operands in a 45 /// parsed Wasm machine instruction. 46 struct WebAssemblyOperand : public MCParsedAsmOperand { 47 enum KindTy { Token, Integer, Float, Symbol, BrList, CatchList } Kind; 48 49 SMLoc StartLoc, EndLoc; 50 51 struct TokOp { 52 StringRef Tok; 53 }; 54 55 struct IntOp { 56 int64_t Val; 57 }; 58 59 struct FltOp { 60 double Val; 61 }; 62 63 struct SymOp { 64 const MCExpr *Exp; 65 }; 66 67 struct BrLOp { 68 std::vector<unsigned> List; 69 }; 70 71 struct CaLOpElem { 72 uint8_t Opcode; 73 const MCExpr *Tag; 74 unsigned Dest; 75 }; 76 77 struct CaLOp { 78 std::vector<CaLOpElem> List; 79 }; 80 81 union { 82 struct TokOp Tok; 83 struct IntOp Int; 84 struct FltOp Flt; 85 struct SymOp Sym; 86 struct BrLOp BrL; 87 struct CaLOp CaL; 88 }; 89 90 WebAssemblyOperand(SMLoc Start, SMLoc End, TokOp T) 91 : Kind(Token), StartLoc(Start), EndLoc(End), Tok(T) {} 92 WebAssemblyOperand(SMLoc Start, SMLoc End, IntOp I) 93 : Kind(Integer), StartLoc(Start), EndLoc(End), Int(I) {} 94 WebAssemblyOperand(SMLoc Start, SMLoc End, FltOp F) 95 : Kind(Float), StartLoc(Start), EndLoc(End), Flt(F) {} 96 WebAssemblyOperand(SMLoc Start, SMLoc End, SymOp S) 97 : Kind(Symbol), StartLoc(Start), EndLoc(End), Sym(S) {} 98 WebAssemblyOperand(SMLoc Start, SMLoc End, BrLOp B) 99 : Kind(BrList), StartLoc(Start), EndLoc(End), BrL(B) {} 100 WebAssemblyOperand(SMLoc Start, SMLoc End, CaLOp C) 101 : Kind(CatchList), StartLoc(Start), EndLoc(End), CaL(C) {} 102 103 ~WebAssemblyOperand() { 104 if (isBrList()) 105 BrL.~BrLOp(); 106 if (isCatchList()) 107 CaL.~CaLOp(); 108 } 109 110 bool isToken() const override { return Kind == Token; } 111 bool isImm() const override { return Kind == Integer || Kind == Symbol; } 112 bool isFPImm() const { return Kind == Float; } 113 bool isMem() const override { return false; } 114 bool isReg() const override { return false; } 115 bool isBrList() const { return Kind == BrList; } 116 bool isCatchList() const { return Kind == CatchList; } 117 118 MCRegister getReg() const override { 119 llvm_unreachable("Assembly inspects a register operand"); 120 return 0; 121 } 122 123 StringRef getToken() const { 124 assert(isToken()); 125 return Tok.Tok; 126 } 127 128 SMLoc getStartLoc() const override { return StartLoc; } 129 SMLoc getEndLoc() const override { return EndLoc; } 130 131 void addRegOperands(MCInst &, unsigned) const { 132 // Required by the assembly matcher. 133 llvm_unreachable("Assembly matcher creates register operands"); 134 } 135 136 void addImmOperands(MCInst &Inst, unsigned N) const { 137 assert(N == 1 && "Invalid number of operands!"); 138 if (Kind == Integer) 139 Inst.addOperand(MCOperand::createImm(Int.Val)); 140 else if (Kind == Symbol) 141 Inst.addOperand(MCOperand::createExpr(Sym.Exp)); 142 else 143 llvm_unreachable("Should be integer immediate or symbol!"); 144 } 145 146 void addFPImmf32Operands(MCInst &Inst, unsigned N) const { 147 assert(N == 1 && "Invalid number of operands!"); 148 if (Kind == Float) 149 Inst.addOperand( 150 MCOperand::createSFPImm(bit_cast<uint32_t>(float(Flt.Val)))); 151 else 152 llvm_unreachable("Should be float immediate!"); 153 } 154 155 void addFPImmf64Operands(MCInst &Inst, unsigned N) const { 156 assert(N == 1 && "Invalid number of operands!"); 157 if (Kind == Float) 158 Inst.addOperand(MCOperand::createDFPImm(bit_cast<uint64_t>(Flt.Val))); 159 else 160 llvm_unreachable("Should be float immediate!"); 161 } 162 163 void addBrListOperands(MCInst &Inst, unsigned N) const { 164 assert(N == 1 && isBrList() && "Invalid BrList!"); 165 for (auto Br : BrL.List) 166 Inst.addOperand(MCOperand::createImm(Br)); 167 } 168 169 void addCatchListOperands(MCInst &Inst, unsigned N) const { 170 assert(N == 1 && isCatchList() && "Invalid CatchList!"); 171 Inst.addOperand(MCOperand::createImm(CaL.List.size())); 172 for (auto Ca : CaL.List) { 173 Inst.addOperand(MCOperand::createImm(Ca.Opcode)); 174 if (Ca.Opcode == wasm::WASM_OPCODE_CATCH || 175 Ca.Opcode == wasm::WASM_OPCODE_CATCH_REF) 176 Inst.addOperand(MCOperand::createExpr(Ca.Tag)); 177 Inst.addOperand(MCOperand::createImm(Ca.Dest)); 178 } 179 } 180 181 void print(raw_ostream &OS) const override { 182 switch (Kind) { 183 case Token: 184 OS << "Tok:" << Tok.Tok; 185 break; 186 case Integer: 187 OS << "Int:" << Int.Val; 188 break; 189 case Float: 190 OS << "Flt:" << Flt.Val; 191 break; 192 case Symbol: 193 OS << "Sym:" << Sym.Exp; 194 break; 195 case BrList: 196 OS << "BrList:" << BrL.List.size(); 197 break; 198 case CatchList: 199 OS << "CaList:" << CaL.List.size(); 200 break; 201 } 202 } 203 }; 204 205 // Perhaps this should go somewhere common. 206 static wasm::WasmLimits defaultLimits() { 207 return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; 208 } 209 210 static MCSymbolWasm *getOrCreateFunctionTableSymbol(MCContext &Ctx, 211 const StringRef &Name, 212 bool Is64) { 213 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 214 if (Sym) { 215 if (!Sym->isFunctionTable()) 216 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 217 } else { 218 Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 219 Sym->setFunctionTable(Is64); 220 // The default function table is synthesized by the linker. 221 Sym->setUndefined(); 222 } 223 return Sym; 224 } 225 226 class WebAssemblyAsmParser final : public MCTargetAsmParser { 227 MCAsmParser &Parser; 228 MCAsmLexer &Lexer; 229 230 // Order of labels, directives and instructions in a .s file have no 231 // syntactical enforcement. This class is a callback from the actual parser, 232 // and yet we have to be feeding data to the streamer in a very particular 233 // order to ensure a correct binary encoding that matches the regular backend 234 // (the streamer does not enforce this). This "state machine" enum helps 235 // guarantee that correct order. 236 enum ParserState { 237 FileStart, 238 FunctionLabel, 239 FunctionStart, 240 FunctionLocals, 241 Instructions, 242 EndFunction, 243 DataSection, 244 } CurrentState = FileStart; 245 246 // For ensuring blocks are properly nested. 247 enum NestingType { 248 Function, 249 Block, 250 Loop, 251 Try, 252 CatchAll, 253 TryTable, 254 If, 255 Else, 256 Undefined, 257 }; 258 struct Nested { 259 NestingType NT; 260 wasm::WasmSignature Sig; 261 }; 262 std::vector<Nested> NestingStack; 263 264 MCSymbolWasm *DefaultFunctionTable = nullptr; 265 MCSymbol *LastFunctionLabel = nullptr; 266 267 bool Is64; 268 269 WebAssemblyAsmTypeCheck TC; 270 // Don't type check if -no-type-check was set. 271 bool SkipTypeCheck; 272 273 public: 274 WebAssemblyAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, 275 const MCInstrInfo &MII, const MCTargetOptions &Options) 276 : MCTargetAsmParser(Options, STI, MII), Parser(Parser), 277 Lexer(Parser.getLexer()), Is64(STI.getTargetTriple().isArch64Bit()), 278 TC(Parser, MII, Is64), SkipTypeCheck(Options.MCNoTypeCheck) { 279 FeatureBitset FBS = ComputeAvailableFeatures(STI.getFeatureBits()); 280 281 // bulk-memory implies bulk-memory-opt 282 if (FBS.test(WebAssembly::FeatureBulkMemory)) { 283 FBS.set(WebAssembly::FeatureBulkMemoryOpt); 284 } 285 // reference-types implies call-indirect-overlong 286 if (FBS.test(WebAssembly::FeatureReferenceTypes)) { 287 FBS.set(WebAssembly::FeatureCallIndirectOverlong); 288 } 289 290 setAvailableFeatures(FBS); 291 // Don't type check if this is inline asm, since that is a naked sequence of 292 // instructions without a function/locals decl. 293 auto &SM = Parser.getSourceManager(); 294 auto BufferName = 295 SM.getBufferInfo(SM.getMainFileID()).Buffer->getBufferIdentifier(); 296 if (BufferName == "<inline asm>") 297 SkipTypeCheck = true; 298 } 299 300 void Initialize(MCAsmParser &Parser) override { 301 MCAsmParserExtension::Initialize(Parser); 302 303 DefaultFunctionTable = getOrCreateFunctionTableSymbol( 304 getContext(), "__indirect_function_table", Is64); 305 if (!STI->checkFeatures("+call-indirect-overlong") && 306 !STI->checkFeatures("+reference-types")) 307 DefaultFunctionTable->setOmitFromLinkingSection(); 308 } 309 310 #define GET_ASSEMBLER_HEADER 311 #include "WebAssemblyGenAsmMatcher.inc" 312 313 // TODO: This is required to be implemented, but appears unused. 314 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override { 315 llvm_unreachable("parseRegister is not implemented."); 316 } 317 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, 318 SMLoc &EndLoc) override { 319 llvm_unreachable("tryParseRegister is not implemented."); 320 } 321 322 bool error(const Twine &Msg, const AsmToken &Tok) { 323 return Parser.Error(Tok.getLoc(), Msg + Tok.getString()); 324 } 325 326 bool error(const Twine &Msg, SMLoc Loc = SMLoc()) { 327 return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg); 328 } 329 330 std::pair<StringRef, StringRef> nestingString(NestingType NT) { 331 switch (NT) { 332 case Function: 333 return {"function", "end_function"}; 334 case Block: 335 return {"block", "end_block"}; 336 case Loop: 337 return {"loop", "end_loop"}; 338 case Try: 339 return {"try", "end_try/delegate"}; 340 case CatchAll: 341 return {"catch_all", "end_try"}; 342 case TryTable: 343 return {"try_table", "end_try_table"}; 344 case If: 345 return {"if", "end_if"}; 346 case Else: 347 return {"else", "end_if"}; 348 default: 349 llvm_unreachable("unknown NestingType"); 350 } 351 } 352 353 void push(NestingType NT, wasm::WasmSignature Sig = wasm::WasmSignature()) { 354 NestingStack.push_back({NT, Sig}); 355 } 356 357 bool pop(StringRef Ins, NestingType NT1, NestingType NT2 = Undefined) { 358 if (NestingStack.empty()) 359 return error(Twine("End of block construct with no start: ") + Ins); 360 auto Top = NestingStack.back(); 361 if (Top.NT != NT1 && Top.NT != NT2) 362 return error(Twine("Block construct type mismatch, expected: ") + 363 nestingString(Top.NT).second + ", instead got: " + Ins); 364 TC.setLastSig(Top.Sig); 365 NestingStack.pop_back(); 366 return false; 367 } 368 369 // Pop a NestingType and push a new NestingType with the same signature. Used 370 // for if-else and try-catch(_all). 371 bool popAndPushWithSameSignature(StringRef Ins, NestingType PopNT, 372 NestingType PushNT) { 373 if (NestingStack.empty()) 374 return error(Twine("End of block construct with no start: ") + Ins); 375 auto Sig = NestingStack.back().Sig; 376 if (pop(Ins, PopNT)) 377 return true; 378 push(PushNT, Sig); 379 return false; 380 } 381 382 bool ensureEmptyNestingStack(SMLoc Loc = SMLoc()) { 383 auto Err = !NestingStack.empty(); 384 while (!NestingStack.empty()) { 385 error(Twine("Unmatched block construct(s) at function end: ") + 386 nestingString(NestingStack.back().NT).first, 387 Loc); 388 NestingStack.pop_back(); 389 } 390 return Err; 391 } 392 393 bool isNext(AsmToken::TokenKind Kind) { 394 auto Ok = Lexer.is(Kind); 395 if (Ok) 396 Parser.Lex(); 397 return Ok; 398 } 399 400 bool expect(AsmToken::TokenKind Kind, const char *KindName) { 401 if (!isNext(Kind)) 402 return error(std::string("Expected ") + KindName + ", instead got: ", 403 Lexer.getTok()); 404 return false; 405 } 406 407 StringRef expectIdent() { 408 if (!Lexer.is(AsmToken::Identifier)) { 409 error("Expected identifier, got: ", Lexer.getTok()); 410 return StringRef(); 411 } 412 auto Name = Lexer.getTok().getString(); 413 Parser.Lex(); 414 return Name; 415 } 416 417 bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) { 418 while (Lexer.is(AsmToken::Identifier)) { 419 auto Type = WebAssembly::parseType(Lexer.getTok().getString()); 420 if (!Type) 421 return error("unknown type: ", Lexer.getTok()); 422 Types.push_back(*Type); 423 Parser.Lex(); 424 if (!isNext(AsmToken::Comma)) 425 break; 426 } 427 return false; 428 } 429 430 void parseSingleInteger(bool IsNegative, OperandVector &Operands) { 431 auto &Int = Lexer.getTok(); 432 int64_t Val = Int.getIntVal(); 433 if (IsNegative) 434 Val = -Val; 435 Operands.push_back(std::make_unique<WebAssemblyOperand>( 436 Int.getLoc(), Int.getEndLoc(), WebAssemblyOperand::IntOp{Val})); 437 Parser.Lex(); 438 } 439 440 bool parseSingleFloat(bool IsNegative, OperandVector &Operands) { 441 auto &Flt = Lexer.getTok(); 442 double Val; 443 if (Flt.getString().getAsDouble(Val, false)) 444 return error("Cannot parse real: ", Flt); 445 if (IsNegative) 446 Val = -Val; 447 Operands.push_back(std::make_unique<WebAssemblyOperand>( 448 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val})); 449 Parser.Lex(); 450 return false; 451 } 452 453 bool parseSpecialFloatMaybe(bool IsNegative, OperandVector &Operands) { 454 if (Lexer.isNot(AsmToken::Identifier)) 455 return true; 456 auto &Flt = Lexer.getTok(); 457 auto S = Flt.getString(); 458 double Val; 459 if (S.compare_insensitive("infinity") == 0) { 460 Val = std::numeric_limits<double>::infinity(); 461 } else if (S.compare_insensitive("nan") == 0) { 462 Val = std::numeric_limits<double>::quiet_NaN(); 463 } else { 464 return true; 465 } 466 if (IsNegative) 467 Val = -Val; 468 Operands.push_back(std::make_unique<WebAssemblyOperand>( 469 Flt.getLoc(), Flt.getEndLoc(), WebAssemblyOperand::FltOp{Val})); 470 Parser.Lex(); 471 return false; 472 } 473 474 bool checkForP2AlignIfLoadStore(OperandVector &Operands, StringRef InstName) { 475 // FIXME: there is probably a cleaner way to do this. 476 auto IsLoadStore = InstName.contains(".load") || 477 InstName.contains(".store") || 478 InstName.contains("prefetch"); 479 auto IsAtomic = InstName.contains("atomic."); 480 if (IsLoadStore || IsAtomic) { 481 // Parse load/store operands of the form: offset:p2align=align 482 if (IsLoadStore && isNext(AsmToken::Colon)) { 483 auto Id = expectIdent(); 484 if (Id != "p2align") 485 return error("Expected p2align, instead got: " + Id); 486 if (expect(AsmToken::Equal, "=")) 487 return true; 488 if (!Lexer.is(AsmToken::Integer)) 489 return error("Expected integer constant"); 490 parseSingleInteger(false, Operands); 491 } else { 492 // v128.{load,store}{8,16,32,64}_lane has both a memarg and a lane 493 // index. We need to avoid parsing an extra alignment operand for the 494 // lane index. 495 auto IsLoadStoreLane = InstName.contains("_lane"); 496 if (IsLoadStoreLane && Operands.size() == 4) 497 return false; 498 // Alignment not specified (or atomics, must use default alignment). 499 // We can't just call WebAssembly::GetDefaultP2Align since we don't have 500 // an opcode until after the assembly matcher, so set a default to fix 501 // up later. 502 auto Tok = Lexer.getTok(); 503 Operands.push_back(std::make_unique<WebAssemblyOperand>( 504 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::IntOp{-1})); 505 } 506 } 507 return false; 508 } 509 510 void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc, 511 WebAssembly::BlockType BT) { 512 if (BT == WebAssembly::BlockType::Void) { 513 TC.setLastSig(wasm::WasmSignature{}); 514 } else { 515 wasm::WasmSignature Sig({static_cast<wasm::ValType>(BT)}, {}); 516 TC.setLastSig(Sig); 517 NestingStack.back().Sig = Sig; 518 } 519 Operands.push_back(std::make_unique<WebAssemblyOperand>( 520 NameLoc, NameLoc, WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)})); 521 } 522 523 bool parseLimits(wasm::WasmLimits *Limits) { 524 auto Tok = Lexer.getTok(); 525 if (!Tok.is(AsmToken::Integer)) 526 return error("Expected integer constant, instead got: ", Tok); 527 int64_t Val = Tok.getIntVal(); 528 assert(Val >= 0); 529 Limits->Minimum = Val; 530 Parser.Lex(); 531 532 if (isNext(AsmToken::Comma)) { 533 Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX; 534 auto Tok = Lexer.getTok(); 535 if (!Tok.is(AsmToken::Integer)) 536 return error("Expected integer constant, instead got: ", Tok); 537 int64_t Val = Tok.getIntVal(); 538 assert(Val >= 0); 539 Limits->Maximum = Val; 540 Parser.Lex(); 541 } 542 return false; 543 } 544 545 bool parseFunctionTableOperand(std::unique_ptr<WebAssemblyOperand> *Op) { 546 if (STI->checkFeatures("+call-indirect-overlong") || 547 STI->checkFeatures("+reference-types")) { 548 // If the call-indirect-overlong feature is enabled, or implied by the 549 // reference-types feature, there is an explicit table operand. To allow 550 // the same assembly to be compiled with or without 551 // call-indirect-overlong, we allow the operand to be omitted, in which 552 // case we default to __indirect_function_table. 553 auto &Tok = Lexer.getTok(); 554 if (Tok.is(AsmToken::Identifier)) { 555 auto *Sym = 556 getOrCreateFunctionTableSymbol(getContext(), Tok.getString(), Is64); 557 const auto *Val = MCSymbolRefExpr::create(Sym, getContext()); 558 *Op = std::make_unique<WebAssemblyOperand>( 559 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::SymOp{Val}); 560 Parser.Lex(); 561 return expect(AsmToken::Comma, ","); 562 } 563 const auto *Val = 564 MCSymbolRefExpr::create(DefaultFunctionTable, getContext()); 565 *Op = std::make_unique<WebAssemblyOperand>( 566 SMLoc(), SMLoc(), WebAssemblyOperand::SymOp{Val}); 567 return false; 568 } 569 // For the MVP there is at most one table whose number is 0, but we can't 570 // write a table symbol or issue relocations. Instead we just ensure the 571 // table is live and write a zero. 572 getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip); 573 *Op = std::make_unique<WebAssemblyOperand>(SMLoc(), SMLoc(), 574 WebAssemblyOperand::IntOp{0}); 575 return false; 576 } 577 578 bool parseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name, 579 SMLoc NameLoc, OperandVector &Operands) override { 580 // Note: Name does NOT point into the sourcecode, but to a local, so 581 // use NameLoc instead. 582 Name = StringRef(NameLoc.getPointer(), Name.size()); 583 584 // WebAssembly has instructions with / in them, which AsmLexer parses 585 // as separate tokens, so if we find such tokens immediately adjacent (no 586 // whitespace), expand the name to include them: 587 for (;;) { 588 auto &Sep = Lexer.getTok(); 589 if (Sep.getLoc().getPointer() != Name.end() || 590 Sep.getKind() != AsmToken::Slash) 591 break; 592 // Extend name with / 593 Name = StringRef(Name.begin(), Name.size() + Sep.getString().size()); 594 Parser.Lex(); 595 // We must now find another identifier, or error. 596 auto &Id = Lexer.getTok(); 597 if (Id.getKind() != AsmToken::Identifier || 598 Id.getLoc().getPointer() != Name.end()) 599 return error("Incomplete instruction name: ", Id); 600 Name = StringRef(Name.begin(), Name.size() + Id.getString().size()); 601 Parser.Lex(); 602 } 603 604 // Now construct the name as first operand. 605 Operands.push_back(std::make_unique<WebAssemblyOperand>( 606 NameLoc, SMLoc::getFromPointer(Name.end()), 607 WebAssemblyOperand::TokOp{Name})); 608 609 // If this instruction is part of a control flow structure, ensure 610 // proper nesting. 611 bool ExpectBlockType = false; 612 bool ExpectFuncType = false; 613 bool ExpectCatchList = false; 614 std::unique_ptr<WebAssemblyOperand> FunctionTable; 615 if (Name == "block") { 616 push(Block); 617 ExpectBlockType = true; 618 } else if (Name == "loop") { 619 push(Loop); 620 ExpectBlockType = true; 621 } else if (Name == "try") { 622 push(Try); 623 ExpectBlockType = true; 624 } else if (Name == "if") { 625 push(If); 626 ExpectBlockType = true; 627 } else if (Name == "else") { 628 if (popAndPushWithSameSignature(Name, If, Else)) 629 return true; 630 } else if (Name == "catch") { 631 if (popAndPushWithSameSignature(Name, Try, Try)) 632 return true; 633 } else if (Name == "catch_all") { 634 if (popAndPushWithSameSignature(Name, Try, CatchAll)) 635 return true; 636 } else if (Name == "try_table") { 637 push(TryTable); 638 ExpectBlockType = true; 639 ExpectCatchList = true; 640 } else if (Name == "end_if") { 641 if (pop(Name, If, Else)) 642 return true; 643 } else if (Name == "end_try") { 644 if (pop(Name, Try, CatchAll)) 645 return true; 646 } else if (Name == "end_try_table") { 647 if (pop(Name, TryTable)) 648 return true; 649 } else if (Name == "delegate") { 650 if (pop(Name, Try)) 651 return true; 652 } else if (Name == "end_loop") { 653 if (pop(Name, Loop)) 654 return true; 655 } else if (Name == "end_block") { 656 if (pop(Name, Block)) 657 return true; 658 } else if (Name == "end_function") { 659 ensureLocals(getStreamer()); 660 CurrentState = EndFunction; 661 if (pop(Name, Function) || ensureEmptyNestingStack()) 662 return true; 663 } else if (Name == "call_indirect" || Name == "return_call_indirect") { 664 // These instructions have differing operand orders in the text format vs 665 // the binary formats. The MC instructions follow the binary format, so 666 // here we stash away the operand and append it later. 667 if (parseFunctionTableOperand(&FunctionTable)) 668 return true; 669 ExpectFuncType = true; 670 } 671 672 // Returns true if the next tokens are a catch clause 673 auto PeekCatchList = [&]() { 674 if (Lexer.isNot(AsmToken::LParen)) 675 return false; 676 AsmToken NextTok = Lexer.peekTok(); 677 return NextTok.getKind() == AsmToken::Identifier && 678 NextTok.getIdentifier().starts_with("catch"); 679 }; 680 681 // Parse a multivalue block type 682 if (ExpectFuncType || 683 (Lexer.is(AsmToken::LParen) && ExpectBlockType && !PeekCatchList())) { 684 // This has a special TYPEINDEX operand which in text we 685 // represent as a signature, such that we can re-build this signature, 686 // attach it to an anonymous symbol, which is what WasmObjectWriter 687 // expects to be able to recreate the actual unique-ified type indices. 688 auto &Ctx = getContext(); 689 auto Loc = Parser.getTok(); 690 auto *Signature = Ctx.createWasmSignature(); 691 if (parseSignature(Signature)) 692 return true; 693 // Got signature as block type, don't need more 694 TC.setLastSig(*Signature); 695 if (ExpectBlockType) 696 NestingStack.back().Sig = *Signature; 697 ExpectBlockType = false; 698 // The "true" here will cause this to be a nameless symbol. 699 MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true); 700 auto *WasmSym = cast<MCSymbolWasm>(Sym); 701 WasmSym->setSignature(Signature); 702 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 703 const MCExpr *Expr = MCSymbolRefExpr::create( 704 WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx); 705 Operands.push_back(std::make_unique<WebAssemblyOperand>( 706 Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr})); 707 } 708 709 // If we are expecting a catch clause list, try to parse it here. 710 // 711 // If there is a multivalue block return type before this catch list, it 712 // should have been parsed above. If there is no return type before 713 // encountering this catch list, this means the type is void. 714 // The case when there is a single block return value and then a catch list 715 // will be handled below in the 'while' loop. 716 if (ExpectCatchList && PeekCatchList()) { 717 if (ExpectBlockType) { 718 ExpectBlockType = false; 719 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void); 720 } 721 if (parseCatchList(Operands)) 722 return true; 723 ExpectCatchList = false; 724 } 725 726 while (Lexer.isNot(AsmToken::EndOfStatement)) { 727 auto &Tok = Lexer.getTok(); 728 switch (Tok.getKind()) { 729 case AsmToken::Identifier: { 730 if (!parseSpecialFloatMaybe(false, Operands)) 731 break; 732 auto &Id = Lexer.getTok(); 733 if (ExpectBlockType) { 734 // Assume this identifier is a block_type. 735 auto BT = WebAssembly::parseBlockType(Id.getString()); 736 if (BT == WebAssembly::BlockType::Invalid) 737 return error("Unknown block type: ", Id); 738 addBlockTypeOperand(Operands, NameLoc, BT); 739 ExpectBlockType = false; 740 Parser.Lex(); 741 // Now that we've parsed a single block return type, if we are 742 // expecting a catch clause list, try to parse it. 743 if (ExpectCatchList && PeekCatchList()) { 744 if (parseCatchList(Operands)) 745 return true; 746 ExpectCatchList = false; 747 } 748 } else { 749 // Assume this identifier is a label. 750 const MCExpr *Val; 751 SMLoc Start = Id.getLoc(); 752 SMLoc End; 753 if (Parser.parseExpression(Val, End)) 754 return error("Cannot parse symbol: ", Lexer.getTok()); 755 Operands.push_back(std::make_unique<WebAssemblyOperand>( 756 Start, End, WebAssemblyOperand::SymOp{Val})); 757 if (checkForP2AlignIfLoadStore(Operands, Name)) 758 return true; 759 } 760 break; 761 } 762 case AsmToken::Minus: 763 Parser.Lex(); 764 if (Lexer.is(AsmToken::Integer)) { 765 parseSingleInteger(true, Operands); 766 if (checkForP2AlignIfLoadStore(Operands, Name)) 767 return true; 768 } else if (Lexer.is(AsmToken::Real)) { 769 if (parseSingleFloat(true, Operands)) 770 return true; 771 } else if (!parseSpecialFloatMaybe(true, Operands)) { 772 } else { 773 return error("Expected numeric constant instead got: ", 774 Lexer.getTok()); 775 } 776 break; 777 case AsmToken::Integer: 778 parseSingleInteger(false, Operands); 779 if (checkForP2AlignIfLoadStore(Operands, Name)) 780 return true; 781 break; 782 case AsmToken::Real: { 783 if (parseSingleFloat(false, Operands)) 784 return true; 785 break; 786 } 787 case AsmToken::LCurly: { 788 Parser.Lex(); 789 auto Op = std::make_unique<WebAssemblyOperand>( 790 Tok.getLoc(), Tok.getEndLoc(), WebAssemblyOperand::BrLOp{}); 791 if (!Lexer.is(AsmToken::RCurly)) 792 for (;;) { 793 Op->BrL.List.push_back(Lexer.getTok().getIntVal()); 794 expect(AsmToken::Integer, "integer"); 795 if (!isNext(AsmToken::Comma)) 796 break; 797 } 798 expect(AsmToken::RCurly, "}"); 799 Operands.push_back(std::move(Op)); 800 break; 801 } 802 default: 803 return error("Unexpected token in operand: ", Tok); 804 } 805 if (Lexer.isNot(AsmToken::EndOfStatement)) { 806 if (expect(AsmToken::Comma, ",")) 807 return true; 808 } 809 } 810 811 // If we are still expecting to parse a block type or a catch list at this 812 // point, we set them to the default/empty state. 813 814 // Support blocks with no operands as default to void. 815 if (ExpectBlockType) 816 addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void); 817 // If no catch list has been parsed, add an empty catch list operand. 818 if (ExpectCatchList) 819 Operands.push_back(std::make_unique<WebAssemblyOperand>( 820 NameLoc, NameLoc, WebAssemblyOperand::CaLOp{})); 821 822 if (FunctionTable) 823 Operands.push_back(std::move(FunctionTable)); 824 Parser.Lex(); 825 return false; 826 } 827 828 bool parseSignature(wasm::WasmSignature *Signature) { 829 if (expect(AsmToken::LParen, "(")) 830 return true; 831 if (parseRegTypeList(Signature->Params)) 832 return true; 833 if (expect(AsmToken::RParen, ")")) 834 return true; 835 if (expect(AsmToken::MinusGreater, "->")) 836 return true; 837 if (expect(AsmToken::LParen, "(")) 838 return true; 839 if (parseRegTypeList(Signature->Returns)) 840 return true; 841 if (expect(AsmToken::RParen, ")")) 842 return true; 843 return false; 844 } 845 846 bool parseCatchList(OperandVector &Operands) { 847 auto Op = std::make_unique<WebAssemblyOperand>( 848 Lexer.getTok().getLoc(), SMLoc(), WebAssemblyOperand::CaLOp{}); 849 SMLoc EndLoc; 850 851 while (Lexer.is(AsmToken::LParen)) { 852 if (expect(AsmToken::LParen, "(")) 853 return true; 854 855 auto CatchStr = expectIdent(); 856 if (CatchStr.empty()) 857 return true; 858 uint8_t CatchOpcode = 859 StringSwitch<uint8_t>(CatchStr) 860 .Case("catch", wasm::WASM_OPCODE_CATCH) 861 .Case("catch_ref", wasm::WASM_OPCODE_CATCH_REF) 862 .Case("catch_all", wasm::WASM_OPCODE_CATCH_ALL) 863 .Case("catch_all_ref", wasm::WASM_OPCODE_CATCH_ALL_REF) 864 .Default(0xff); 865 if (CatchOpcode == 0xff) 866 return error( 867 "Expected catch/catch_ref/catch_all/catch_all_ref, instead got: " + 868 CatchStr); 869 870 const MCExpr *Tag = nullptr; 871 if (CatchOpcode == wasm::WASM_OPCODE_CATCH || 872 CatchOpcode == wasm::WASM_OPCODE_CATCH_REF) { 873 if (Parser.parseExpression(Tag)) 874 return error("Cannot parse symbol: ", Lexer.getTok()); 875 } 876 877 auto &DestTok = Lexer.getTok(); 878 if (DestTok.isNot(AsmToken::Integer)) 879 return error("Expected integer constant, instead got: ", DestTok); 880 unsigned Dest = DestTok.getIntVal(); 881 Parser.Lex(); 882 883 EndLoc = Lexer.getTok().getEndLoc(); 884 if (expect(AsmToken::RParen, ")")) 885 return true; 886 887 Op->CaL.List.push_back({CatchOpcode, Tag, Dest}); 888 } 889 890 Op->EndLoc = EndLoc; 891 Operands.push_back(std::move(Op)); 892 return false; 893 } 894 895 bool checkDataSection() { 896 if (CurrentState != DataSection) { 897 auto *WS = cast<MCSectionWasm>(getStreamer().getCurrentSectionOnly()); 898 if (WS && WS->isText()) 899 return error("data directive must occur in a data segment: ", 900 Lexer.getTok()); 901 } 902 CurrentState = DataSection; 903 return false; 904 } 905 906 // This function processes wasm-specific directives streamed to 907 // WebAssemblyTargetStreamer, all others go to the generic parser 908 // (see WasmAsmParser). 909 ParseStatus parseDirective(AsmToken DirectiveID) override { 910 assert(DirectiveID.getKind() == AsmToken::Identifier); 911 auto &Out = getStreamer(); 912 auto &TOut = 913 reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer()); 914 auto &Ctx = Out.getContext(); 915 916 if (DirectiveID.getString() == ".globaltype") { 917 auto SymName = expectIdent(); 918 if (SymName.empty()) 919 return ParseStatus::Failure; 920 if (expect(AsmToken::Comma, ",")) 921 return ParseStatus::Failure; 922 auto TypeTok = Lexer.getTok(); 923 auto TypeName = expectIdent(); 924 if (TypeName.empty()) 925 return ParseStatus::Failure; 926 auto Type = WebAssembly::parseType(TypeName); 927 if (!Type) 928 return error("Unknown type in .globaltype directive: ", TypeTok); 929 // Optional mutable modifier. Default to mutable for historical reasons. 930 // Ideally we would have gone with immutable as the default and used `mut` 931 // as the modifier to match the `.wat` format. 932 bool Mutable = true; 933 if (isNext(AsmToken::Comma)) { 934 TypeTok = Lexer.getTok(); 935 auto Id = expectIdent(); 936 if (Id.empty()) 937 return ParseStatus::Failure; 938 if (Id == "immutable") 939 Mutable = false; 940 else 941 // Should we also allow `mutable` and `mut` here for clarity? 942 return error("Unknown type in .globaltype modifier: ", TypeTok); 943 } 944 // Now set this symbol with the correct type. 945 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 946 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 947 WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(*Type), Mutable}); 948 // And emit the directive again. 949 TOut.emitGlobalType(WasmSym); 950 return expect(AsmToken::EndOfStatement, "EOL"); 951 } 952 953 if (DirectiveID.getString() == ".tabletype") { 954 // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]] 955 auto SymName = expectIdent(); 956 if (SymName.empty()) 957 return ParseStatus::Failure; 958 if (expect(AsmToken::Comma, ",")) 959 return ParseStatus::Failure; 960 961 auto ElemTypeTok = Lexer.getTok(); 962 auto ElemTypeName = expectIdent(); 963 if (ElemTypeName.empty()) 964 return ParseStatus::Failure; 965 std::optional<wasm::ValType> ElemType = 966 WebAssembly::parseType(ElemTypeName); 967 if (!ElemType) 968 return error("Unknown type in .tabletype directive: ", ElemTypeTok); 969 970 wasm::WasmLimits Limits = defaultLimits(); 971 if (isNext(AsmToken::Comma) && parseLimits(&Limits)) 972 return ParseStatus::Failure; 973 974 // Now that we have the name and table type, we can actually create the 975 // symbol 976 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 977 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); 978 if (Is64) { 979 Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64; 980 } 981 wasm::WasmTableType Type = {*ElemType, Limits}; 982 WasmSym->setTableType(Type); 983 TOut.emitTableType(WasmSym); 984 return expect(AsmToken::EndOfStatement, "EOL"); 985 } 986 987 if (DirectiveID.getString() == ".functype") { 988 // This code has to send things to the streamer similar to 989 // WebAssemblyAsmPrinter::EmitFunctionBodyStart. 990 // TODO: would be good to factor this into a common function, but the 991 // assembler and backend really don't share any common code, and this code 992 // parses the locals separately. 993 auto SymName = expectIdent(); 994 if (SymName.empty()) 995 return ParseStatus::Failure; 996 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 997 if (WasmSym->isDefined()) { 998 // We push 'Function' either when a label is parsed or a .functype 999 // directive is parsed. The reason it is not easy to do this uniformly 1000 // in a single place is, 1001 // 1. We can't do this at label parsing time only because there are 1002 // cases we don't have .functype directive before a function label, 1003 // in which case we don't know if the label is a function at the time 1004 // of parsing. 1005 // 2. We can't do this at .functype parsing time only because we want to 1006 // detect a function started with a label and not ended correctly 1007 // without encountering a .functype directive after the label. 1008 if (CurrentState != FunctionLabel) { 1009 // This .functype indicates a start of a function. 1010 if (ensureEmptyNestingStack()) 1011 return ParseStatus::Failure; 1012 push(Function); 1013 } 1014 CurrentState = FunctionStart; 1015 LastFunctionLabel = WasmSym; 1016 } 1017 auto *Signature = Ctx.createWasmSignature(); 1018 if (parseSignature(Signature)) 1019 return ParseStatus::Failure; 1020 if (CurrentState == FunctionStart) 1021 TC.funcDecl(*Signature); 1022 WasmSym->setSignature(Signature); 1023 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 1024 TOut.emitFunctionType(WasmSym); 1025 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented. 1026 return expect(AsmToken::EndOfStatement, "EOL"); 1027 } 1028 1029 if (DirectiveID.getString() == ".export_name") { 1030 auto SymName = expectIdent(); 1031 if (SymName.empty()) 1032 return ParseStatus::Failure; 1033 if (expect(AsmToken::Comma, ",")) 1034 return ParseStatus::Failure; 1035 auto ExportName = expectIdent(); 1036 if (ExportName.empty()) 1037 return ParseStatus::Failure; 1038 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 1039 WasmSym->setExportName(Ctx.allocateString(ExportName)); 1040 TOut.emitExportName(WasmSym, ExportName); 1041 return expect(AsmToken::EndOfStatement, "EOL"); 1042 } 1043 1044 if (DirectiveID.getString() == ".import_module") { 1045 auto SymName = expectIdent(); 1046 if (SymName.empty()) 1047 return ParseStatus::Failure; 1048 if (expect(AsmToken::Comma, ",")) 1049 return ParseStatus::Failure; 1050 auto ImportModule = expectIdent(); 1051 if (ImportModule.empty()) 1052 return ParseStatus::Failure; 1053 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 1054 WasmSym->setImportModule(Ctx.allocateString(ImportModule)); 1055 TOut.emitImportModule(WasmSym, ImportModule); 1056 return expect(AsmToken::EndOfStatement, "EOL"); 1057 } 1058 1059 if (DirectiveID.getString() == ".import_name") { 1060 auto SymName = expectIdent(); 1061 if (SymName.empty()) 1062 return ParseStatus::Failure; 1063 if (expect(AsmToken::Comma, ",")) 1064 return ParseStatus::Failure; 1065 auto ImportName = expectIdent(); 1066 if (ImportName.empty()) 1067 return ParseStatus::Failure; 1068 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 1069 WasmSym->setImportName(Ctx.allocateString(ImportName)); 1070 TOut.emitImportName(WasmSym, ImportName); 1071 return expect(AsmToken::EndOfStatement, "EOL"); 1072 } 1073 1074 if (DirectiveID.getString() == ".tagtype") { 1075 auto SymName = expectIdent(); 1076 if (SymName.empty()) 1077 return ParseStatus::Failure; 1078 auto *WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); 1079 auto *Signature = Ctx.createWasmSignature(); 1080 if (parseRegTypeList(Signature->Params)) 1081 return ParseStatus::Failure; 1082 WasmSym->setSignature(Signature); 1083 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG); 1084 TOut.emitTagType(WasmSym); 1085 // TODO: backend also calls TOut.emitIndIdx, but that is not implemented. 1086 return expect(AsmToken::EndOfStatement, "EOL"); 1087 } 1088 1089 if (DirectiveID.getString() == ".local") { 1090 if (CurrentState != FunctionStart) 1091 return error(".local directive should follow the start of a function: ", 1092 Lexer.getTok()); 1093 SmallVector<wasm::ValType, 4> Locals; 1094 if (parseRegTypeList(Locals)) 1095 return ParseStatus::Failure; 1096 TC.localDecl(Locals); 1097 TOut.emitLocal(Locals); 1098 CurrentState = FunctionLocals; 1099 return expect(AsmToken::EndOfStatement, "EOL"); 1100 } 1101 1102 if (DirectiveID.getString() == ".int8" || 1103 DirectiveID.getString() == ".int16" || 1104 DirectiveID.getString() == ".int32" || 1105 DirectiveID.getString() == ".int64") { 1106 if (checkDataSection()) 1107 return ParseStatus::Failure; 1108 const MCExpr *Val; 1109 SMLoc End; 1110 if (Parser.parseExpression(Val, End)) 1111 return error("Cannot parse .int expression: ", Lexer.getTok()); 1112 size_t NumBits = 0; 1113 DirectiveID.getString().drop_front(4).getAsInteger(10, NumBits); 1114 Out.emitValue(Val, NumBits / 8, End); 1115 return expect(AsmToken::EndOfStatement, "EOL"); 1116 } 1117 1118 if (DirectiveID.getString() == ".asciz") { 1119 if (checkDataSection()) 1120 return ParseStatus::Failure; 1121 std::string S; 1122 if (Parser.parseEscapedString(S)) 1123 return error("Cannot parse string constant: ", Lexer.getTok()); 1124 Out.emitBytes(StringRef(S.c_str(), S.length() + 1)); 1125 return expect(AsmToken::EndOfStatement, "EOL"); 1126 } 1127 1128 return ParseStatus::NoMatch; // We didn't process this directive. 1129 } 1130 1131 // Called either when the first instruction is parsed of the function ends. 1132 void ensureLocals(MCStreamer &Out) { 1133 if (CurrentState == FunctionStart) { 1134 // We haven't seen a .local directive yet. The streamer requires locals to 1135 // be encoded as a prelude to the instructions, so emit an empty list of 1136 // locals here. 1137 auto &TOut = reinterpret_cast<WebAssemblyTargetStreamer &>( 1138 *Out.getTargetStreamer()); 1139 TOut.emitLocal(SmallVector<wasm::ValType, 0>()); 1140 CurrentState = FunctionLocals; 1141 } 1142 } 1143 1144 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned & /*Opcode*/, 1145 OperandVector &Operands, MCStreamer &Out, 1146 uint64_t &ErrorInfo, 1147 bool MatchingInlineAsm) override { 1148 MCInst Inst; 1149 Inst.setLoc(IDLoc); 1150 FeatureBitset MissingFeatures; 1151 unsigned MatchResult = MatchInstructionImpl( 1152 Operands, Inst, ErrorInfo, MissingFeatures, MatchingInlineAsm); 1153 switch (MatchResult) { 1154 case Match_Success: { 1155 ensureLocals(Out); 1156 // Fix unknown p2align operands. 1157 auto Align = WebAssembly::GetDefaultP2AlignAny(Inst.getOpcode()); 1158 if (Align != -1U) { 1159 auto &Op0 = Inst.getOperand(0); 1160 if (Op0.getImm() == -1) 1161 Op0.setImm(Align); 1162 } 1163 if (Is64) { 1164 // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having 1165 // an offset64 arg instead of offset32, but to the assembler matcher 1166 // they're both immediates so don't get selected for. 1167 auto Opc64 = WebAssembly::getWasm64Opcode( 1168 static_cast<uint16_t>(Inst.getOpcode())); 1169 if (Opc64 >= 0) { 1170 Inst.setOpcode(Opc64); 1171 } 1172 } 1173 if (!SkipTypeCheck) 1174 TC.typeCheck(IDLoc, Inst, Operands); 1175 Out.emitInstruction(Inst, getSTI()); 1176 if (CurrentState == EndFunction) { 1177 onEndOfFunction(IDLoc); 1178 } else { 1179 CurrentState = Instructions; 1180 } 1181 return false; 1182 } 1183 case Match_MissingFeature: { 1184 assert(MissingFeatures.count() > 0 && "Expected missing features"); 1185 SmallString<128> Message; 1186 raw_svector_ostream OS(Message); 1187 OS << "instruction requires:"; 1188 for (unsigned I = 0, E = MissingFeatures.size(); I != E; ++I) 1189 if (MissingFeatures.test(I)) 1190 OS << ' ' << getSubtargetFeatureName(I); 1191 return Parser.Error(IDLoc, Message); 1192 } 1193 case Match_MnemonicFail: 1194 return Parser.Error(IDLoc, "invalid instruction"); 1195 case Match_NearMisses: 1196 return Parser.Error(IDLoc, "ambiguous instruction"); 1197 case Match_InvalidTiedOperand: 1198 case Match_InvalidOperand: { 1199 SMLoc ErrorLoc = IDLoc; 1200 if (ErrorInfo != ~0ULL) { 1201 if (ErrorInfo >= Operands.size()) 1202 return Parser.Error(IDLoc, "too few operands for instruction"); 1203 ErrorLoc = Operands[ErrorInfo]->getStartLoc(); 1204 if (ErrorLoc == SMLoc()) 1205 ErrorLoc = IDLoc; 1206 } 1207 return Parser.Error(ErrorLoc, "invalid operand for instruction"); 1208 } 1209 } 1210 llvm_unreachable("Implement any new match types added!"); 1211 } 1212 1213 void doBeforeLabelEmit(MCSymbol *Symbol, SMLoc IDLoc) override { 1214 // Code below only applies to labels in text sections. 1215 auto *CWS = cast<MCSectionWasm>(getStreamer().getCurrentSectionOnly()); 1216 if (!CWS->isText()) 1217 return; 1218 1219 auto *WasmSym = cast<MCSymbolWasm>(Symbol); 1220 // Unlike other targets, we don't allow data in text sections (labels 1221 // declared with .type @object). 1222 if (WasmSym->getType() == wasm::WASM_SYMBOL_TYPE_DATA) { 1223 Parser.Error(IDLoc, 1224 "Wasm doesn\'t support data symbols in text sections"); 1225 return; 1226 } 1227 1228 // Start a new section for the next function automatically, since our 1229 // object writer expects each function to have its own section. This way 1230 // The user can't forget this "convention". 1231 auto SymName = Symbol->getName(); 1232 if (SymName.starts_with(".L")) 1233 return; // Local Symbol. 1234 1235 // TODO: If the user explicitly creates a new function section, we ignore 1236 // its name when we create this one. It would be nice to honor their 1237 // choice, while still ensuring that we create one if they forget. 1238 // (that requires coordination with WasmAsmParser::parseSectionDirective) 1239 std::string SecName = (".text." + SymName).str(); 1240 1241 auto *Group = CWS->getGroup(); 1242 // If the current section is a COMDAT, also set the flag on the symbol. 1243 // TODO: Currently the only place that the symbols' comdat flag matters is 1244 // for importing comdat functions. But there's no way to specify that in 1245 // assembly currently. 1246 if (Group) 1247 WasmSym->setComdat(true); 1248 auto *WS = getContext().getWasmSection(SecName, SectionKind::getText(), 0, 1249 Group, MCContext::GenericSectionID); 1250 getStreamer().switchSection(WS); 1251 // Also generate DWARF for this section if requested. 1252 if (getContext().getGenDwarfForAssembly()) 1253 getContext().addGenDwarfSection(WS); 1254 1255 if (WasmSym->isFunction()) { 1256 // We give the location of the label (IDLoc) here, because otherwise the 1257 // lexer's next location will be used, which can be confusing. For 1258 // example: 1259 // 1260 // test0: ; This function does not end properly 1261 // ... 1262 // 1263 // test1: ; We would like to point to this line for error 1264 // ... . Not this line, which can contain any instruction 1265 ensureEmptyNestingStack(IDLoc); 1266 CurrentState = FunctionLabel; 1267 LastFunctionLabel = Symbol; 1268 push(Function); 1269 } 1270 } 1271 1272 void onEndOfFunction(SMLoc ErrorLoc) { 1273 if (!SkipTypeCheck) 1274 TC.endOfFunction(ErrorLoc, true); 1275 // Reset the type checker state. 1276 TC.clear(); 1277 } 1278 1279 void onEndOfFile() override { ensureEmptyNestingStack(); } 1280 }; 1281 } // end anonymous namespace 1282 1283 // Force static initialization. 1284 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyAsmParser() { 1285 RegisterMCAsmParser<WebAssemblyAsmParser> X(getTheWebAssemblyTarget32()); 1286 RegisterMCAsmParser<WebAssemblyAsmParser> Y(getTheWebAssemblyTarget64()); 1287 } 1288 1289 #define GET_REGISTER_MATCHER 1290 #define GET_SUBTARGET_FEATURE_NAME 1291 #define GET_MATCHER_IMPLEMENTATION 1292 #include "WebAssemblyGenAsmMatcher.inc" 1293 1294 StringRef getMnemonic(unsigned Opc) { 1295 // FIXME: linear search! 1296 for (auto &ME : MatchTable0) { 1297 if (ME.Opcode == Opc) { 1298 return ME.getMnemonic(); 1299 } 1300 } 1301 assert(false && "mnemonic not found"); 1302 return StringRef(); 1303 } 1304