1 //==- WebAssemblyAsmTypeCheck.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/MCParsedAsmOperand.h" 26 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 27 #include "llvm/MC/MCSectionWasm.h" 28 #include "llvm/MC/MCStreamer.h" 29 #include "llvm/MC/MCSubtargetInfo.h" 30 #include "llvm/MC/MCSymbol.h" 31 #include "llvm/MC/MCSymbolWasm.h" 32 #include "llvm/MC/TargetRegistry.h" 33 #include "llvm/Support/Compiler.h" 34 #include "llvm/Support/SourceMgr.h" 35 #include <sstream> 36 37 using namespace llvm; 38 39 #define DEBUG_TYPE "wasm-asm-parser" 40 41 extern StringRef getMnemonic(unsigned Opc); 42 43 namespace llvm { 44 45 WebAssemblyAsmTypeCheck::WebAssemblyAsmTypeCheck(MCAsmParser &Parser, 46 const MCInstrInfo &MII, 47 bool Is64) 48 : Parser(Parser), MII(MII), Is64(Is64) {} 49 50 void WebAssemblyAsmTypeCheck::funcDecl(const wasm::WasmSignature &Sig) { 51 LocalTypes.assign(Sig.Params.begin(), Sig.Params.end()); 52 BlockInfoStack.push_back({Sig, 0, false}); 53 } 54 55 void WebAssemblyAsmTypeCheck::localDecl( 56 const SmallVectorImpl<wasm::ValType> &Locals) { 57 LocalTypes.insert(LocalTypes.end(), Locals.begin(), Locals.end()); 58 } 59 60 void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) { 61 LLVM_DEBUG({ dbgs() << Msg << getTypesString(Stack) << "\n"; }); 62 } 63 64 bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { 65 dumpTypeStack("current stack: "); 66 return Parser.Error(ErrorLoc, Msg); 67 } 68 69 bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) { 70 // These should have been filtered out in checkTypes() 71 assert(!std::get_if<Polymorphic>(&TypeA) && 72 !std::get_if<Polymorphic>(&TypeB)); 73 74 if (TypeA == TypeB) 75 return false; 76 if (std::get_if<Any>(&TypeA) || std::get_if<Any>(&TypeB)) 77 return false; 78 79 if (std::get_if<Ref>(&TypeB)) 80 std::swap(TypeA, TypeB); 81 assert(std::get_if<wasm::ValType>(&TypeB)); 82 if (std::get_if<Ref>(&TypeA) && 83 WebAssembly::isRefType(std::get<wasm::ValType>(TypeB))) 84 return false; 85 return true; 86 } 87 88 std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef<StackType> Types, 89 size_t StartPos) { 90 SmallVector<std::string, 4> TypeStrs; 91 for (auto I = Types.size(); I > StartPos; I--) { 92 if (std::get_if<Polymorphic>(&Types[I - 1])) { 93 TypeStrs.push_back("..."); 94 break; 95 } 96 if (std::get_if<Any>(&Types[I - 1])) 97 TypeStrs.push_back("any"); 98 else if (std::get_if<Ref>(&Types[I - 1])) 99 TypeStrs.push_back("ref"); 100 else 101 TypeStrs.push_back( 102 WebAssembly::typeToString(std::get<wasm::ValType>(Types[I - 1]))); 103 } 104 105 std::stringstream SS; 106 SS << "["; 107 bool First = true; 108 for (auto It = TypeStrs.rbegin(); It != TypeStrs.rend(); ++It) { 109 if (!First) 110 SS << ", "; 111 SS << *It; 112 First = false; 113 } 114 SS << "]"; 115 return SS.str(); 116 } 117 118 std::string 119 WebAssemblyAsmTypeCheck::getTypesString(ArrayRef<wasm::ValType> Types, 120 size_t StartPos) { 121 return getTypesString(valTypesToStackTypes(Types), StartPos); 122 } 123 124 SmallVector<WebAssemblyAsmTypeCheck::StackType, 4> 125 WebAssemblyAsmTypeCheck::valTypesToStackTypes( 126 ArrayRef<wasm::ValType> ValTypes) { 127 SmallVector<StackType, 4> Types(ValTypes.size()); 128 std::transform(ValTypes.begin(), ValTypes.end(), Types.begin(), 129 [](wasm::ValType Val) -> StackType { return Val; }); 130 return Types; 131 } 132 133 bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, 134 ArrayRef<wasm::ValType> ValTypes, 135 bool ExactMatch) { 136 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch); 137 } 138 139 bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, 140 ArrayRef<StackType> Types, 141 bool ExactMatch) { 142 auto StackI = Stack.size(); 143 auto TypeI = Types.size(); 144 assert(!BlockInfoStack.empty()); 145 auto BlockStackStartPos = BlockInfoStack.back().StackStartPos; 146 bool Error = false; 147 bool PolymorphicStack = false; 148 // Compare elements one by one from the stack top 149 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) { 150 // If the stack is polymorphic, we assume all types in 'Types' have been 151 // compared and matched 152 if (std::get_if<Polymorphic>(&Stack[StackI - 1])) { 153 TypeI = 0; 154 break; 155 } 156 if (match(Stack[StackI - 1], Types[TypeI - 1])) { 157 Error = true; 158 break; 159 } 160 } 161 162 // If the stack top is polymorphic, the stack is in the polymorphic state. 163 if (StackI > BlockStackStartPos && 164 std::get_if<Polymorphic>(&Stack[StackI - 1])) 165 PolymorphicStack = true; 166 167 // Even if no match failure has happened in the loop above, if not all 168 // elements of Types has been matched, that means we don't have enough 169 // elements on the stack. 170 // 171 // Also, if not all elements of the Stack has been matched and when 172 // 'ExactMatch' is true and the current stack is not polymorphic, that means 173 // we have superfluous elements remaining on the stack (e.g. at the end of a 174 // function). 175 if (TypeI > 0 || 176 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos)) 177 Error = true; 178 179 if (!Error) 180 return false; 181 182 auto StackStartPos = ExactMatch 183 ? BlockStackStartPos 184 : std::max((int)BlockStackStartPos, 185 (int)Stack.size() - (int)Types.size()); 186 return typeError(ErrorLoc, "type mismatch, expected " + 187 getTypesString(Types) + " but got " + 188 getTypesString(Stack, StackStartPos)); 189 } 190 191 bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc, 192 ArrayRef<wasm::ValType> ValTypes, 193 bool ExactMatch) { 194 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch); 195 } 196 197 bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc, 198 ArrayRef<StackType> Types, 199 bool ExactMatch) { 200 bool Error = checkTypes(ErrorLoc, Types, ExactMatch); 201 auto NumPops = std::min(Stack.size() - BlockInfoStack.back().StackStartPos, 202 Types.size()); 203 for (size_t I = 0, E = NumPops; I != E; I++) { 204 if (std::get_if<Polymorphic>(&Stack.back())) 205 break; 206 Stack.pop_back(); 207 } 208 return Error; 209 } 210 211 bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) { 212 return popTypes(ErrorLoc, {Type}); 213 } 214 215 bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { 216 return popType(ErrorLoc, Ref{}); 217 } 218 219 bool WebAssemblyAsmTypeCheck::popAnyType(SMLoc ErrorLoc) { 220 return popType(ErrorLoc, Any{}); 221 } 222 223 void WebAssemblyAsmTypeCheck::pushTypes(ArrayRef<wasm::ValType> ValTypes) { 224 Stack.append(valTypesToStackTypes(ValTypes)); 225 } 226 227 bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, 228 wasm::ValType &Type) { 229 auto Local = static_cast<size_t>(LocalOp.getImm()); 230 if (Local >= LocalTypes.size()) 231 return typeError(ErrorLoc, StringRef("no local type specified for index ") + 232 std::to_string(Local)); 233 Type = LocalTypes[Local]; 234 return false; 235 } 236 237 bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc, 238 const wasm::WasmSignature &Sig) { 239 bool Error = popTypes(ErrorLoc, Sig.Params); 240 pushTypes(Sig.Returns); 241 return Error; 242 } 243 244 bool WebAssemblyAsmTypeCheck::getSymRef(SMLoc ErrorLoc, const MCOperand &SymOp, 245 const MCSymbolRefExpr *&SymRef) { 246 if (!SymOp.isExpr()) 247 return typeError(ErrorLoc, StringRef("expected expression operand")); 248 SymRef = dyn_cast<MCSymbolRefExpr>(SymOp.getExpr()); 249 if (!SymRef) 250 return typeError(ErrorLoc, StringRef("expected symbol operand")); 251 return false; 252 } 253 254 bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc, 255 const MCOperand &GlobalOp, 256 wasm::ValType &Type) { 257 const MCSymbolRefExpr *SymRef; 258 if (getSymRef(ErrorLoc, GlobalOp, SymRef)) 259 return true; 260 const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); 261 switch (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA)) { 262 case wasm::WASM_SYMBOL_TYPE_GLOBAL: 263 Type = static_cast<wasm::ValType>(WasmSym->getGlobalType().Type); 264 break; 265 case wasm::WASM_SYMBOL_TYPE_FUNCTION: 266 case wasm::WASM_SYMBOL_TYPE_DATA: 267 switch (SymRef->getKind()) { 268 case MCSymbolRefExpr::VK_GOT: 269 case MCSymbolRefExpr::VK_WASM_GOT_TLS: 270 Type = Is64 ? wasm::ValType::I64 : wasm::ValType::I32; 271 return false; 272 default: 273 break; 274 } 275 [[fallthrough]]; 276 default: 277 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + 278 ": missing .globaltype"); 279 } 280 return false; 281 } 282 283 bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCOperand &TableOp, 284 wasm::ValType &Type) { 285 const MCSymbolRefExpr *SymRef; 286 if (getSymRef(ErrorLoc, TableOp, SymRef)) 287 return true; 288 const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); 289 if (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA) != 290 wasm::WASM_SYMBOL_TYPE_TABLE) 291 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + 292 ": missing .tabletype"); 293 Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType); 294 return false; 295 } 296 297 bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc, 298 const MCOperand &SigOp, 299 wasm::WasmSymbolType Type, 300 const wasm::WasmSignature *&Sig) { 301 const MCSymbolRefExpr *SymRef = nullptr; 302 if (getSymRef(ErrorLoc, SigOp, SymRef)) 303 return true; 304 const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol()); 305 Sig = WasmSym->getSignature(); 306 307 if (!Sig || WasmSym->getType() != Type) { 308 const char *TypeName = nullptr; 309 switch (Type) { 310 case wasm::WASM_SYMBOL_TYPE_FUNCTION: 311 TypeName = "func"; 312 break; 313 case wasm::WASM_SYMBOL_TYPE_TAG: 314 TypeName = "tag"; 315 break; 316 default: 317 llvm_unreachable("Signature symbol should either be a function or a tag"); 318 } 319 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + 320 ": missing ." + TypeName + "type"); 321 } 322 return false; 323 } 324 325 bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc, bool ExactMatch) { 326 assert(!BlockInfoStack.empty()); 327 const auto &FuncInfo = BlockInfoStack[0]; 328 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch); 329 } 330 331 // Unlike checkTypes() family, this just compare the equivalence of the two 332 // ValType vectors 333 static bool compareTypes(ArrayRef<wasm::ValType> TypesA, 334 ArrayRef<wasm::ValType> TypesB) { 335 if (TypesA.size() != TypesB.size()) 336 return true; 337 for (size_t I = 0, E = TypesA.size(); I < E; I++) 338 if (TypesA[I] != TypesB[I]) 339 return true; 340 return false; 341 } 342 343 bool WebAssemblyAsmTypeCheck::checkTryTable(SMLoc ErrorLoc, 344 const MCInst &Inst) { 345 bool Error = false; 346 unsigned OpIdx = 1; // OpIdx 0 is the block type 347 int64_t NumCatches = Inst.getOperand(OpIdx++).getImm(); 348 for (int64_t I = 0; I < NumCatches; I++) { 349 int64_t Opcode = Inst.getOperand(OpIdx++).getImm(); 350 std::string ErrorMsgBase = 351 "try_table: catch index " + std::to_string(I) + ": "; 352 353 const wasm::WasmSignature *Sig = nullptr; 354 SmallVector<wasm::ValType> SentTypes; 355 if (Opcode == wasm::WASM_OPCODE_CATCH || 356 Opcode == wasm::WASM_OPCODE_CATCH_REF) { 357 if (!getSignature(ErrorLoc, Inst.getOperand(OpIdx++), 358 wasm::WASM_SYMBOL_TYPE_TAG, Sig)) 359 SentTypes.insert(SentTypes.end(), Sig->Params.begin(), 360 Sig->Params.end()); 361 else 362 Error = true; 363 } 364 if (Opcode == wasm::WASM_OPCODE_CATCH_REF || 365 Opcode == wasm::WASM_OPCODE_CATCH_ALL_REF) { 366 SentTypes.push_back(wasm::ValType::EXNREF); 367 } 368 369 unsigned Level = Inst.getOperand(OpIdx++).getImm(); 370 if (Level < BlockInfoStack.size()) { 371 const auto &DestBlockInfo = 372 BlockInfoStack[BlockInfoStack.size() - Level - 1]; 373 ArrayRef<wasm::ValType> DestTypes; 374 if (DestBlockInfo.IsLoop) 375 DestTypes = DestBlockInfo.Sig.Params; 376 else 377 DestTypes = DestBlockInfo.Sig.Returns; 378 if (compareTypes(SentTypes, DestTypes)) { 379 std::string ErrorMsg = 380 ErrorMsgBase + "type mismatch, catch tag type is " + 381 getTypesString(SentTypes) + ", but destination's type is " + 382 getTypesString(DestTypes); 383 Error |= typeError(ErrorLoc, ErrorMsg); 384 } 385 } else { 386 Error = typeError(ErrorLoc, ErrorMsgBase + "invalid depth " + 387 std::to_string(Level)); 388 } 389 } 390 return Error; 391 } 392 393 bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, 394 OperandVector &Operands) { 395 auto Opc = Inst.getOpcode(); 396 auto Name = getMnemonic(Opc); 397 dumpTypeStack("typechecking " + Name + ": "); 398 wasm::ValType Type; 399 400 if (Name == "local.get") { 401 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 402 pushType(Type); 403 return false; 404 } 405 pushType(Any{}); 406 return true; 407 } 408 409 if (Name == "local.set") { 410 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) 411 return popType(ErrorLoc, Type); 412 popType(ErrorLoc, Any{}); 413 return true; 414 } 415 416 if (Name == "local.tee") { 417 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 418 bool Error = popType(ErrorLoc, Type); 419 pushType(Type); 420 return Error; 421 } 422 popType(ErrorLoc, Any{}); 423 pushType(Any{}); 424 return true; 425 } 426 427 if (Name == "global.get") { 428 if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 429 pushType(Type); 430 return false; 431 } 432 pushType(Any{}); 433 return true; 434 } 435 436 if (Name == "global.set") { 437 if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) 438 return popType(ErrorLoc, Type); 439 popType(ErrorLoc, Any{}); 440 return true; 441 } 442 443 if (Name == "table.get") { 444 bool Error = popType(ErrorLoc, wasm::ValType::I32); 445 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 446 pushType(Type); 447 return Error; 448 } 449 pushType(Any{}); 450 return true; 451 } 452 453 if (Name == "table.set") { 454 bool Error = false; 455 SmallVector<StackType, 2> PopTypes; 456 PopTypes.push_back(wasm::ValType::I32); 457 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 458 PopTypes.push_back(Type); 459 } else { 460 Error = true; 461 PopTypes.push_back(Any{}); 462 } 463 Error |= popTypes(ErrorLoc, PopTypes); 464 return Error; 465 } 466 467 if (Name == "table.size") { 468 bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type); 469 pushType(wasm::ValType::I32); 470 return Error; 471 } 472 473 if (Name == "table.grow") { 474 bool Error = false; 475 SmallVector<StackType, 2> PopTypes; 476 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 477 PopTypes.push_back(Type); 478 } else { 479 Error = true; 480 PopTypes.push_back(Any{}); 481 } 482 PopTypes.push_back(wasm::ValType::I32); 483 Error |= popTypes(ErrorLoc, PopTypes); 484 pushType(wasm::ValType::I32); 485 return Error; 486 } 487 488 if (Name == "table.fill") { 489 bool Error = false; 490 SmallVector<StackType, 2> PopTypes; 491 PopTypes.push_back(wasm::ValType::I32); 492 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { 493 PopTypes.push_back(Type); 494 } else { 495 Error = true; 496 PopTypes.push_back(Any{}); 497 } 498 PopTypes.push_back(wasm::ValType::I32); 499 Error |= popTypes(ErrorLoc, PopTypes); 500 return Error; 501 } 502 503 if (Name == "memory.fill") { 504 Type = Is64 ? wasm::ValType::I64 : wasm::ValType::I32; 505 bool Error = popType(ErrorLoc, Type); 506 Error |= popType(ErrorLoc, wasm::ValType::I32); 507 Error |= popType(ErrorLoc, Type); 508 return Error; 509 } 510 511 if (Name == "memory.copy") { 512 Type = Is64 ? wasm::ValType::I64 : wasm::ValType::I32; 513 bool Error = popType(ErrorLoc, Type); 514 Error |= popType(ErrorLoc, Type); 515 Error |= popType(ErrorLoc, Type); 516 return Error; 517 } 518 519 if (Name == "memory.init") { 520 Type = Is64 ? wasm::ValType::I64 : wasm::ValType::I32; 521 bool Error = popType(ErrorLoc, wasm::ValType::I32); 522 Error |= popType(ErrorLoc, wasm::ValType::I32); 523 Error |= popType(ErrorLoc, Type); 524 return Error; 525 } 526 527 if (Name == "drop") { 528 return popType(ErrorLoc, Any{}); 529 } 530 531 if (Name == "block" || Name == "loop" || Name == "if" || Name == "try" || 532 Name == "try_table") { 533 bool Error = Name == "if" && popType(ErrorLoc, wasm::ValType::I32); 534 // Pop block input parameters and check their types are correct 535 Error |= popTypes(ErrorLoc, LastSig.Params); 536 if (Name == "try_table") 537 Error |= checkTryTable(ErrorLoc, Inst); 538 // Push a new block info 539 BlockInfoStack.push_back({LastSig, Stack.size(), Name == "loop"}); 540 // Push back block input parameters 541 pushTypes(LastSig.Params); 542 return Error; 543 } 544 545 if (Name == "end_block" || Name == "end_loop" || Name == "end_if" || 546 Name == "end_try" || Name == "delegate" || Name == "end_try_table" || 547 Name == "else" || Name == "catch" || Name == "catch_all") { 548 assert(!BlockInfoStack.empty()); 549 // Check if the types on the stack match with the block return type 550 const auto &LastBlockInfo = BlockInfoStack.back(); 551 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns, true); 552 // Pop all types added to the stack for the current block level 553 Stack.truncate(LastBlockInfo.StackStartPos); 554 if (Name == "else") { 555 // 'else' expects the block input parameters to be on the stack, in the 556 // same way we entered 'if' 557 pushTypes(LastBlockInfo.Sig.Params); 558 } else if (Name == "catch") { 559 // 'catch' instruction pushes values whose types are specified in the 560 // tag's 'params' part 561 const wasm::WasmSignature *Sig = nullptr; 562 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0), 563 wasm::WASM_SYMBOL_TYPE_TAG, Sig)) 564 pushTypes(Sig->Params); 565 else 566 Error = true; 567 } else if (Name == "catch_all") { 568 // 'catch_all' does not push anything onto the stack 569 } else { 570 // For normal end markers, push block return value types onto the stack 571 // and pop the block info 572 pushTypes(LastBlockInfo.Sig.Returns); 573 BlockInfoStack.pop_back(); 574 } 575 return Error; 576 } 577 578 if (Name == "br" || Name == "br_if") { 579 bool Error = false; 580 if (Name == "br_if") 581 Error |= popType(ErrorLoc, wasm::ValType::I32); // cond 582 const MCOperand &Operand = Inst.getOperand(0); 583 if (Operand.isImm()) { 584 unsigned Level = Operand.getImm(); 585 if (Level < BlockInfoStack.size()) { 586 const auto &DestBlockInfo = 587 BlockInfoStack[BlockInfoStack.size() - Level - 1]; 588 if (DestBlockInfo.IsLoop) 589 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Params, false); 590 else 591 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Returns, false); 592 } else { 593 Error = typeError(ErrorLoc, StringRef("br: invalid depth ") + 594 std::to_string(Level)); 595 } 596 } else { 597 Error = 598 typeError(Operands[1]->getStartLoc(), "depth should be an integer"); 599 } 600 if (Name == "br") 601 pushType(Polymorphic{}); 602 return Error; 603 } 604 605 if (Name == "return") { 606 bool Error = endOfFunction(ErrorLoc, false); 607 pushType(Polymorphic{}); 608 return Error; 609 } 610 611 if (Name == "call_indirect" || Name == "return_call_indirect") { 612 // Function value. 613 bool Error = popType(ErrorLoc, wasm::ValType::I32); 614 Error |= checkSig(ErrorLoc, LastSig); 615 if (Name == "return_call_indirect") { 616 Error |= endOfFunction(ErrorLoc, false); 617 pushType(Polymorphic{}); 618 } 619 return Error; 620 } 621 622 if (Name == "call" || Name == "return_call") { 623 bool Error = false; 624 const wasm::WasmSignature *Sig = nullptr; 625 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0), 626 wasm::WASM_SYMBOL_TYPE_FUNCTION, Sig)) 627 Error |= checkSig(ErrorLoc, *Sig); 628 else 629 Error = true; 630 if (Name == "return_call") { 631 Error |= endOfFunction(ErrorLoc, false); 632 pushType(Polymorphic{}); 633 } 634 return Error; 635 } 636 637 if (Name == "unreachable") { 638 pushType(Polymorphic{}); 639 return false; 640 } 641 642 if (Name == "ref.is_null") { 643 bool Error = popRefType(ErrorLoc); 644 pushType(wasm::ValType::I32); 645 return Error; 646 } 647 648 if (Name == "throw") { 649 bool Error = false; 650 const wasm::WasmSignature *Sig = nullptr; 651 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0), 652 wasm::WASM_SYMBOL_TYPE_TAG, Sig)) 653 Error |= checkSig(ErrorLoc, *Sig); 654 else 655 Error = true; 656 pushType(Polymorphic{}); 657 return Error; 658 } 659 660 if (Name == "throw_ref") { 661 bool Error = popType(ErrorLoc, wasm::ValType::EXNREF); 662 pushType(Polymorphic{}); 663 return Error; 664 } 665 666 // The current instruction is a stack instruction which doesn't have 667 // explicit operands that indicate push/pop types, so we get those from 668 // the register version of the same instruction. 669 auto RegOpc = WebAssembly::getRegisterOpcode(Opc); 670 assert(RegOpc != -1 && "Failed to get register version of MC instruction"); 671 const auto &II = MII.get(RegOpc); 672 // First pop all the uses off the stack and check them. 673 SmallVector<wasm::ValType, 4> PopTypes; 674 for (unsigned I = II.getNumDefs(); I < II.getNumOperands(); I++) { 675 const auto &Op = II.operands()[I]; 676 if (Op.OperandType == MCOI::OPERAND_REGISTER) 677 PopTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); 678 } 679 bool Error = popTypes(ErrorLoc, PopTypes); 680 SmallVector<wasm::ValType, 4> PushTypes; 681 // Now push all the defs onto the stack. 682 for (unsigned I = 0; I < II.getNumDefs(); I++) { 683 const auto &Op = II.operands()[I]; 684 assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected"); 685 PushTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); 686 } 687 pushTypes(PushTypes); 688 return Error; 689 } 690 691 } // end namespace llvm 692