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) &&
91 SmallVector<std::string, 4> TypeStrs;
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();
145 assert(!BlockInfoStack.empty());
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,
186 (
int)Stack.size() - (
int)
Types.size());
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());
231 if (
Local >= LocalTypes.size())
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"));
251 return typeError(ErrorLoc, StringRef(
"expected symbol operand"));
255bool WebAssemblyAsmTypeCheck::getGlobal(
SMLoc ErrorLoc,
258 const MCSymbolRefExpr *SymRef;
259 if (getSymRef(ErrorLoc, GlobalOp, SymRef))
261 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
278 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
279 ": missing .globaltype");
284bool WebAssemblyAsmTypeCheck::getTable(
SMLoc ErrorLoc,
const MCOperand &TableOp,
286 const MCSymbolRefExpr *SymRef;
287 if (getSymRef(ErrorLoc, TableOp, SymRef))
289 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
292 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
293 ": missing .tabletype");
298bool WebAssemblyAsmTypeCheck::getSignature(
SMLoc ErrorLoc,
302 const MCSymbolRefExpr *SymRef =
nullptr;
303 if (getSymRef(ErrorLoc, SigOp, SymRef))
305 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
306 Sig = WasmSym->getSignature();
308 if (!Sig || WasmSym->getType() !=
Type) {
320 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
321 ": missing ." + TypeName +
"type");
327 assert(!BlockInfoStack.empty());
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{});
531 if (Name ==
"block" || Name ==
"loop" || Name ==
"if" || Name ==
"try" ||
532 Name ==
"try_table") {
535 Error |= popTypes(ErrorLoc, LastSig.Params);
536 if (Name ==
"try_table")
537 Error |= checkTryTable(ErrorLoc, Inst);
539 BlockInfoStack.push_back({LastSig, Stack.size(), Name ==
"loop"});
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") {
548 assert(!BlockInfoStack.empty());
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);
573 BlockInfoStack.pop_back();
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!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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.
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)
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_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<X> - Return the argument parameter cast to the specified type.
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.
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