40#define DEBUG_TYPE "wasm-asm-parser"
49 : Parser(Parser), MII(MII), Is64(Is64) {}
53 BlockInfoStack.
push_back({Sig, 0,
false});
61void WebAssemblyAsmTypeCheck::dumpTypeStack(
Twine Msg) {
65bool WebAssemblyAsmTypeCheck::typeError(
SMLoc ErrorLoc,
const Twine &Msg) {
66 dumpTypeStack(
"current stack: ");
67 return Parser.
Error(ErrorLoc, Msg);
70bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) {
72 assert(!std::get_if<Polymorphic>(&TypeA) &&
73 !std::get_if<Polymorphic>(&TypeB));
77 if (std::get_if<Any>(&TypeA) || std::get_if<Any>(&TypeB))
80 if (std::get_if<Ref>(&TypeB))
82 assert(std::get_if<wasm::ValType>(&TypeB));
83 if (std::get_if<Ref>(&TypeA) &&
92 for (
auto I =
Types.size();
I > StartPos;
I--) {
93 if (std::get_if<Polymorphic>(&Types[
I - 1])) {
97 if (std::get_if<Any>(&Types[
I - 1]))
99 else if (std::get_if<Ref>(&Types[
I - 1]))
106 std::stringstream
SS;
109 for (
auto It = TypeStrs.
rbegin(); It != TypeStrs.
rend(); ++It) {
122 return getTypesString(valTypesToStackTypes(Types), StartPos);
126WebAssemblyAsmTypeCheck::valTypesToStackTypes(
134bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
137 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
140bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
143 auto StackI = Stack.
size();
144 auto TypeI =
Types.size();
146 auto BlockStackStartPos = BlockInfoStack.
back().StackStartPos;
148 bool PolymorphicStack =
false;
150 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) {
153 if (std::get_if<Polymorphic>(&Stack[StackI - 1])) {
157 if (match(Stack[StackI - 1], Types[TypeI - 1])) {
164 if (StackI > BlockStackStartPos &&
165 std::get_if<Polymorphic>(&Stack[StackI - 1]))
166 PolymorphicStack =
true;
177 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos))
183 auto StackStartPos = ExactMatch
185 : std::max((
int)BlockStackStartPos,
187 return typeError(ErrorLoc,
"type mismatch, expected " +
188 getTypesString(Types) +
" but got " +
189 getTypesString(Stack, StackStartPos));
192bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
195 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
198bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
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<Polymorphic>(&Stack.
back()))
212bool WebAssemblyAsmTypeCheck::popType(
SMLoc ErrorLoc, StackType
Type) {
213 return popTypes(ErrorLoc, {
Type});
216bool WebAssemblyAsmTypeCheck::popRefType(
SMLoc ErrorLoc) {
217 return popType(ErrorLoc, Ref{});
220bool WebAssemblyAsmTypeCheck::popAnyType(
SMLoc ErrorLoc) {
221 return popType(ErrorLoc,
Any{});
225 Stack.
append(valTypesToStackTypes(ValTypes));
228bool WebAssemblyAsmTypeCheck::getLocal(
SMLoc ErrorLoc,
const MCOperand &LocalOp,
230 auto Local =
static_cast<size_t>(LocalOp.
getImm());
232 return typeError(ErrorLoc,
StringRef(
"no local type specified for index ") +
233 std::to_string(
Local));
238bool WebAssemblyAsmTypeCheck::checkSig(
SMLoc ErrorLoc,
245bool WebAssemblyAsmTypeCheck::getSymRef(
SMLoc ErrorLoc,
const MCOperand &SymOp,
248 return typeError(ErrorLoc,
StringRef(
"expected expression operand"));
249 SymRef = dyn_cast<MCSymbolRefExpr>(SymOp.
getExpr());
251 return typeError(ErrorLoc,
StringRef(
"expected symbol operand"));
255bool WebAssemblyAsmTypeCheck::getGlobal(
SMLoc ErrorLoc,
259 if (getSymRef(ErrorLoc, GlobalOp, SymRef))
278 return typeError(ErrorLoc,
StringRef(
"symbol ") + WasmSym->getName() +
279 ": missing .globaltype");
284bool WebAssemblyAsmTypeCheck::getTable(
SMLoc ErrorLoc,
const MCOperand &TableOp,
287 if (getSymRef(ErrorLoc, TableOp, SymRef))
292 return typeError(ErrorLoc,
StringRef(
"symbol ") + WasmSym->getName() +
293 ": missing .tabletype");
298bool WebAssemblyAsmTypeCheck::getSignature(
SMLoc ErrorLoc,
303 if (getSymRef(ErrorLoc, SigOp, SymRef))
306 Sig = WasmSym->getSignature();
308 if (!Sig || WasmSym->getType() !=
Type) {
320 return typeError(ErrorLoc,
StringRef(
"symbol ") + WasmSym->getName() +
321 ": missing ." + TypeName +
"type");
328 const auto &FuncInfo = BlockInfoStack[0];
329 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch);
338 for (
size_t I = 0, E = TypesA.
size();
I < E;
I++)
339 if (TypesA[
I] != TypesB[
I])
344bool WebAssemblyAsmTypeCheck::checkTryTable(
SMLoc ErrorLoc,
349 for (int64_t
I = 0;
I < NumCatches;
I++) {
351 std::string ErrorMsgBase =
352 "try_table: catch index " + std::to_string(
I) +
": ";
370 if (Level < BlockInfoStack.
size()) {
371 const auto &DestBlockInfo =
372 BlockInfoStack[BlockInfoStack.
size() - Level - 1];
374 if (DestBlockInfo.IsLoop)
375 DestTypes = DestBlockInfo.Sig.Params;
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);
386 Error = typeError(ErrorLoc, ErrorMsgBase +
"invalid depth " +
387 std::to_string(Level));
397 dumpTypeStack(
"typechecking " +
Name +
": ");
400 if (
Name ==
"local.get") {
409 if (
Name ==
"local.set") {
411 return popType(ErrorLoc,
Type);
412 popType(ErrorLoc,
Any{});
416 if (
Name ==
"local.tee") {
422 popType(ErrorLoc,
Any{});
427 if (
Name ==
"global.get") {
436 if (
Name ==
"global.set") {
438 return popType(ErrorLoc,
Type);
439 popType(ErrorLoc,
Any{});
443 if (
Name ==
"table.get") {
453 if (
Name ==
"table.set") {
463 Error |= popTypes(ErrorLoc, PopTypes);
467 if (
Name ==
"table.size") {
473 if (
Name ==
"table.grow") {
483 Error |= popTypes(ErrorLoc, PopTypes);
488 if (
Name ==
"table.fill") {
499 Error |= popTypes(ErrorLoc, PopTypes);
503 if (
Name ==
"memory.fill") {
511 if (
Name ==
"memory.copy") {
519 if (
Name ==
"memory.init") {
527 if (
Name ==
"drop") {
528 return popType(ErrorLoc,
Any{});
532 Name ==
"try_table") {
536 if (
Name ==
"try_table")
537 Error |= checkTryTable(ErrorLoc, Inst);
541 pushTypes(LastSig.
Params);
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") {
550 const auto &LastBlockInfo = BlockInfoStack.
back();
551 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns,
true);
553 Stack.
truncate(LastBlockInfo.StackStartPos);
554 if (
Name ==
"else") {
557 pushTypes(LastBlockInfo.Sig.Params);
558 }
else if (
Name ==
"catch") {
567 }
else if (
Name ==
"catch_all") {
572 pushTypes(LastBlockInfo.Sig.Returns);
578 if (
Name ==
"br" ||
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);
591 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Returns,
false);
594 std::to_string(Level));
598 typeError(
Operands[1]->getStartLoc(),
"depth should be an integer");
601 pushType(Polymorphic{});
605 if (
Name ==
"return") {
607 pushType(Polymorphic{});
611 if (
Name ==
"call_indirect" ||
Name ==
"return_call_indirect") {
614 Error |= checkSig(ErrorLoc, LastSig);
615 if (
Name ==
"return_call_indirect") {
617 pushType(Polymorphic{});
622 if (
Name ==
"call" ||
Name ==
"return_call") {
627 Error |= checkSig(ErrorLoc, *Sig);
630 if (
Name ==
"return_call") {
632 pushType(Polymorphic{});
637 if (
Name ==
"unreachable") {
638 pushType(Polymorphic{});
642 if (
Name ==
"ref.is_null") {
643 bool Error = popRefType(ErrorLoc);
648 if (
Name ==
"throw") {
653 Error |= checkSig(ErrorLoc, *Sig);
656 pushType(Polymorphic{});
660 if (
Name ==
"throw_ref") {
662 pushType(Polymorphic{});
670 assert(RegOpc != -1 &&
"Failed to get register version of MC instruction");
671 const auto &
II = MII.
get(RegOpc);
674 for (
unsigned I =
II.getNumDefs();
I <
II.getNumOperands();
I++) {
675 const auto &
Op =
II.operands()[
I];
679 bool Error = popTypes(ErrorLoc, PopTypes);
682 for (
unsigned I = 0;
I <
II.getNumDefs();
I++) {
683 const auto &
Op =
II.operands()[
I];
687 pushTypes(PushTypes);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
mir Rename Register Operands
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
StringRef getMnemonic(unsigned Opc)
StringRef getMnemonic(unsigned Opc)
This file is part of the WebAssembly Assembler.
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.
This class represents an Operation in the Expression.
Lightweight error class with error context and mandatory checking.
Generic assembler parser interface, for use by target specific assembly parsers.
bool Error(SMLoc L, const Twine &Msg, SMRange Range=std::nullopt)
Return an error at the location L, with the message Msg.
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.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
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 assign(size_type NumElts, ValueParamT Elt)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void truncate(size_type N)
Like resize, but requires that N is less than size().
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)
WebAssemblyAsmTypeCheck(MCAsmParser &Parser, const MCInstrInfo &MII, bool Is64)
void funcDecl(const wasm::WasmSignature &Sig)
void localDecl(const SmallVectorImpl< wasm::ValType > &Locals)
bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands)
#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_SYMBOL_TYPE_GLOBAL
@ WASM_SYMBOL_TYPE_FUNCTION
@ WASM_OPCODE_CATCH_ALL_REF
This is an optimization pass for GlobalISel generic memory operations.
static bool compareTypes(ArrayRef< wasm::ValType > TypesA, ArrayRef< wasm::ValType > TypesB)
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.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
SmallVector< ValType, 1 > Returns
SmallVector< ValType, 4 > Params