LLVM: lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

36#include

37

38using namespace llvm;

39

40#define DEBUG_TYPE "wasm-asm-parser"

41

43

44namespace llvm {

45

48 bool Is64)

49 : Parser(Parser), MII(MII), Is64(Is64) {}

50

53 BlockInfoStack.push_back({Sig, 0, false});

54}

55

60

61void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) {

62 LLVM_DEBUG({ dbgs() << Msg << getTypesString(Stack) << "\n"; });

63}

64

65bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) {

66 dumpTypeStack("current stack: ");

67 return Parser.Error(ErrorLoc, Msg);

68}

69

70bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) {

71

72 assert(!std::get_if(&TypeA) &&

73 !std::get_if(&TypeB));

74

75 if (TypeA == TypeB)

76 return false;

77 if (std::get_if(&TypeA) || std::get_if(&TypeB))

78 return false;

79

80 if (std::get_if(&TypeB))

82 assert(std::get_ifwasm::ValType(&TypeB));

83 if (std::get_if(&TypeA) &&

85 return false;

86 return true;

87}

88

89std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef Types,

90 size_t StartPos) {

91 SmallVector<std::string, 4> TypeStrs;

92 for (auto I = Types.size(); I > StartPos; I--) {

93 if (std::get_if(&Types[I - 1])) {

95 break;

96 }

97 if (std::get_if(&Types[I - 1]))

99 else if (std::get_if(&Types[I - 1]))

101 else

104 }

105

106 std::stringstream SS;

107 SS << "[";

108 bool First = true;

109 for (auto It = TypeStrs.rbegin(); It != TypeStrs.rend(); ++It) {

111 SS << ", ";

112 SS << *It;

114 }

115 SS << "]";

116 return SS.str();

117}

118

119std::string

121 size_t StartPos) {

122 return getTypesString(valTypesToStackTypes(Types), StartPos);

123}

124

126WebAssemblyAsmTypeCheck::valTypesToStackTypes(

130 [](wasm::ValType Val) -> StackType { return Val; });

132}

133

134bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc,

136 bool ExactMatch) {

137 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);

138}

139

140bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc,

142 bool ExactMatch) {

143 auto StackI = Stack.size();

144 auto TypeI = Types.size();

145 assert(!BlockInfoStack.empty());

146 auto BlockStackStartPos = BlockInfoStack.back().StackStartPos;

147 bool Error = false;

148 bool PolymorphicStack = false;

149

150 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) {

151

152

153 if (std::get_if(&Stack[StackI - 1])) {

154 TypeI = 0;

155 break;

156 }

157 if (match(Stack[StackI - 1], Types[TypeI - 1])) {

159 break;

160 }

161 }

162

163

164 if (StackI > BlockStackStartPos &&

165 std::get_if(&Stack[StackI - 1]))

166 PolymorphicStack = true;

167

168

169

170

171

172

173

174

175

176 if (TypeI > 0 ||

177 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos))

179

181 return false;

182

183 auto StackStartPos = ExactMatch

184 ? BlockStackStartPos

185 : std::max((int)BlockStackStartPos,

186 (int)Stack.size() - (int)Types.size());

187 return typeError(ErrorLoc, "type mismatch, expected " +

188 getTypesString(Types) + " but got " +

189 getTypesString(Stack, StackStartPos));

190}

191

192bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,

194 bool ExactMatch) {

195 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);

196}

197

198bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,

200 bool ExactMatch) {

201 bool Error = checkTypes(ErrorLoc, Types, ExactMatch);

202 auto NumPops = std::min(Stack.size() - BlockInfoStack.back().StackStartPos,

204 for (size_t I = 0, E = NumPops; I != E; I++) {

205 if (std::get_if(&Stack.back()))

206 break;

207 Stack.pop_back();

208 }

210}

211

212bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) {

213 return popTypes(ErrorLoc, {Type});

214}

215

216bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) {

217 return popType(ErrorLoc, Ref{});

218}

219

220bool WebAssemblyAsmTypeCheck::popAnyType(SMLoc ErrorLoc) {

221 return popType(ErrorLoc, Any{});

222}

223

225 Stack.append(valTypesToStackTypes(ValTypes));

226}

227

228bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp,

230 auto Local = static_cast<size_t>(LocalOp.getImm());

231 if (Local >= LocalTypes.size())

232 return typeError(ErrorLoc, StringRef("no local type specified for index ") +

233 std::to_string(Local));

235 return false;

236}

237

238bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc,

240 bool Error = popTypes(ErrorLoc, Sig.Params);

243}

244

245bool WebAssemblyAsmTypeCheck::getSymRef(SMLoc ErrorLoc, const MCOperand &SymOp,

248 return typeError(ErrorLoc, StringRef("expected expression operand"));

250 if (!SymRef)

251 return typeError(ErrorLoc, StringRef("expected symbol operand"));

252 return false;

253}

254

255bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc,

258 const MCSymbolRefExpr *SymRef;

259 if (getSymRef(ErrorLoc, GlobalOp, SymRef))

260 return true;

261 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());

265 break;

272 return false;

273 default:

274 break;

275 }

276 [[fallthrough]];

277 default:

278 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +

279 ": missing .globaltype");

280 }

281 return false;

282}

283

284bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCOperand &TableOp,

286 const MCSymbolRefExpr *SymRef;

287 if (getSymRef(ErrorLoc, TableOp, SymRef))

288 return true;

289 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());

292 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +

293 ": missing .tabletype");

294 Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType);

295 return false;

296}

297

298bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc,

302 const MCSymbolRefExpr *SymRef = nullptr;

303 if (getSymRef(ErrorLoc, SigOp, SymRef))

304 return true;

305 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());

306 Sig = WasmSym->getSignature();

307

308 if (!Sig || WasmSym->getType() != Type) {

309 const char *TypeName = nullptr;

310 switch (Type) {

313 break;

316 break;

317 default:

318 llvm_unreachable("Signature symbol should either be a function or a tag");

319 }

320 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +

321 ": missing ." + TypeName + "type");

322 }

323 return false;

324}

325

327 assert(!BlockInfoStack.empty());

328 const auto &FuncInfo = BlockInfoStack[0];

329 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch);

330}

331

332

333

336 if (TypesA.size() != TypesB.size())

337 return true;

338 for (size_t I = 0, E = TypesA.size(); I < E; I++)

339 if (TypesA[I] != TypesB[I])

340 return true;

341 return false;

342}

343

344bool WebAssemblyAsmTypeCheck::checkTryTable(SMLoc ErrorLoc,

345 const MCInst &Inst) {

346 bool Error = false;

347 unsigned OpIdx = 1;

349 for (int64_t I = 0; I < NumCatches; I++) {

351 std::string ErrorMsgBase =

352 "try_table: catch index " + std::to_string(I) + ": ";

353

361 else

363 }

367 }

368

370 if (Level < BlockInfoStack.size()) {

371 const auto &DestBlockInfo =

372 BlockInfoStack[BlockInfoStack.size() - Level - 1];

374 if (DestBlockInfo.IsLoop)

375 DestTypes = DestBlockInfo.Sig.Params;

376 else

377 DestTypes = DestBlockInfo.Sig.Returns;

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 }

391}

392

397 dumpTypeStack("typechecking " + Name + ": ");

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);

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") {

445 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {

446 pushType(Type);

448 }

449 pushType(Any{});

450 return true;

451 }

452

453 if (Name == "table.set") {

454 bool Error = false;

457 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {

459 } else {

462 }

463 Error |= popTypes(ErrorLoc, PopTypes);

465 }

466

467 if (Name == "table.size") {

468 bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type);

471 }

472

473 if (Name == "table.grow") {

474 bool Error = false;

476 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {

478 } else {

481 }

483 Error |= popTypes(ErrorLoc, PopTypes);

486 }

487

488 if (Name == "table.fill") {

489 bool Error = false;

492 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {

494 } else {

497 }

499 Error |= popTypes(ErrorLoc, PopTypes);

501 }

502

503 if (Name == "memory.fill") {

505 bool Error = popType(ErrorLoc, Type);

507 Error |= popType(ErrorLoc, Type);

509 }

510

511 if (Name == "memory.copy") {

513 bool Error = popType(ErrorLoc, Type);

514 Error |= popType(ErrorLoc, Type);

515 Error |= popType(ErrorLoc, Type);

517 }

518

519 if (Name == "memory.init") {

523 Error |= popType(ErrorLoc, Type);

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") {

534

535 Error |= popTypes(ErrorLoc, LastSig.Params);

536 if (Name == "try_table")

537 Error |= checkTryTable(ErrorLoc, Inst);

538

539 BlockInfoStack.push_back({LastSig, Stack.size(), Name == "loop"});

540

541 pushTypes(LastSig.Params);

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

550 const auto &LastBlockInfo = BlockInfoStack.back();

551 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns, true);

552

553 Stack.truncate(LastBlockInfo.StackStartPos);

554 if (Name == "else") {

555

556

557 pushTypes(LastBlockInfo.Sig.Params);

558 } else if (Name == "catch") {

559

560

562 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),

564 pushTypes(Sig->Params);

565 else

567 } else if (Name == "catch_all") {

568

569 } else {

570

571

572 pushTypes(LastBlockInfo.Sig.Returns);

573 BlockInfoStack.pop_back();

574 }

576 }

577

578 if (Name == "br" || Name == "br_if") {

579 bool Error = false;

580 if (Name == "br_if")

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 {

598 typeError(Operands[1]->getStartLoc(), "depth should be an integer");

599 }

600 if (Name == "br")

601 pushType(Polymorphic{});

603 }

604

605 if (Name == "return") {

607 pushType(Polymorphic{});

609 }

610

611 if (Name == "call_indirect" || Name == "return_call_indirect") {

612

614 Error |= checkSig(ErrorLoc, LastSig);

615 if (Name == "return_call_indirect") {

617 pushType(Polymorphic{});

618 }

620 }

621

622 if (Name == "call" || Name == "return_call") {

623 bool Error = false;

625 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),

627 Error |= checkSig(ErrorLoc, *Sig);

628 else

630 if (Name == "return_call") {

632 pushType(Polymorphic{});

633 }

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);

646 }

647

648 if (Name == "throw") {

649 bool Error = false;

651 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),

653 Error |= checkSig(ErrorLoc, *Sig);

654 else

656 pushType(Polymorphic{});

658 }

659

660 if (Name == "throw_ref") {

662 pushType(Polymorphic{});

664 }

665

666

667

668

670 assert(RegOpc != -1 && "Failed to get register version of MC instruction");

671 const auto &II = MII.get(RegOpc);

672

674 for (unsigned I = II.getNumDefs(); I < II.getNumOperands(); I++) {

675 const auto &Op = II.operands()[I];

678 }

679 bool Error = popTypes(ErrorLoc, PopTypes);

681

682 for (unsigned I = 0; I < II.getNumDefs(); I++) {

683 const auto &Op = II.operands()[I];

686 }

687 pushTypes(PushTypes);

689}

690

691}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

MachineInstr unsigned OpIdx

uint64_t IntrinsicInst * II

StringRef getMnemonic(unsigned Opc)

StringRef getMnemonic(unsigned Opc)

This file is part of the WebAssembly Assembler.

static std::string getSignature(FunctionType *FTy)

This file contains the declaration of the WebAssemblyMCAsmInfo class.

This file provides WebAssembly-specific target descriptions.

This file contains the declaration of the WebAssembly-specific type parsing utility functions.

This file registers the WebAssembly target.

This file declares WebAssembly-specific target streamer classes.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

size_t size() const

size - Get the array size.

Lightweight error class with error context and mandatory checking.

Generic assembler parser interface, for use by target specific assembly parsers.

Instances of this class represent a single low-level machine instruction.

unsigned getOpcode() const

const MCOperand & getOperand(unsigned i) const

Interface to description of machine instruction set.

Instances of this class represent operands of the MCInst class.

const MCExpr * getExpr() const

Represent a reference to a symbol from inside an expression.

const MCSymbol & getSymbol() const

uint16_t getSpecifier() const

Represents a location in source code.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

reverse_iterator rbegin()

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

The instances of the Type class are immutable: once they are created, they are never changed.

bool endOfFunction(SMLoc ErrorLoc, bool ExactMatch)

Definition WebAssemblyAsmTypeCheck.cpp:326

WebAssemblyAsmTypeCheck(MCAsmParser &Parser, const MCInstrInfo &MII, bool Is64)

Definition WebAssemblyAsmTypeCheck.cpp:46

void funcDecl(const wasm::WasmSignature &Sig)

Definition WebAssemblyAsmTypeCheck.cpp:51

void localDecl(const SmallVectorImpl< wasm::ValType > &Locals)

Definition WebAssemblyAsmTypeCheck.cpp:56

bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands)

Definition WebAssemblyAsmTypeCheck.cpp:393

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

constexpr char TypeName[]

Key for Kernel::Arg::Metadata::mTypeName.

const char * typeToString(wasm::ValType Type)

wasm::ValType regClassToValType(unsigned RC)

bool isRefType(wasm::ValType Type)

int getRegisterOpcode(unsigned short Opcode)

@ WASM_OPCODE_CATCH_ALL_REF

@ WASM_SYMBOL_TYPE_GLOBAL

@ WASM_SYMBOL_TYPE_FUNCTION

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

static bool compareTypes(ArrayRef< wasm::ValType > TypesA, ArrayRef< wasm::ValType > TypesB)

Definition WebAssemblyAsmTypeCheck.cpp:334

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)

Wrapper function around std::transform to apply a function to a range and store the result elsewhere.

SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

DWARFExpression::Operation Op

ArrayRef(const T &OneElt) -> ArrayRef< T >

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.

SmallVector< ValType, 1 > Returns

SmallVector< ValType, 4 > Params