41#define DEBUG_TYPE "wasm-asm-parser"
50 : Parser(Parser), MII(MII), Is64(Is64) {}
54 BlockInfoStack.push_back({Sig, 0,
false});
62void WebAssemblyAsmTypeCheck::dumpTypeStack(
Twine Msg) {
66bool WebAssemblyAsmTypeCheck::typeError(
SMLoc ErrorLoc,
const Twine &Msg) {
67 dumpTypeStack(
"current stack: ");
68 return Parser.Error(ErrorLoc, Msg);
71bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) {
73 assert(!std::get_if<Polymorphic>(&TypeA) &&
74 !std::get_if<Polymorphic>(&TypeB));
78 if (std::get_if<Any>(&TypeA) || std::get_if<Any>(&TypeB))
81 if (std::get_if<Ref>(&TypeB))
83 assert(std::get_if<wasm::ValType>(&TypeB));
84 if (std::get_if<Ref>(&TypeA) &&
92 SmallVector<std::string, 4> TypeStrs;
93 for (
auto I =
Types.size();
I > StartPos;
I--) {
94 if (std::get_if<Polymorphic>(&Types[
I - 1])) {
98 if (std::get_if<Any>(&Types[
I - 1]))
100 else if (std::get_if<Ref>(&Types[
I - 1]))
108 raw_string_ostream
SS(S);
120 return getTypesString(valTypesToStackTypes(Types), StartPos);
124WebAssemblyAsmTypeCheck::valTypesToStackTypes(
132bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
135 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
138bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
141 auto StackI = Stack.size();
142 auto TypeI =
Types.size();
143 assert(!BlockInfoStack.empty());
144 auto BlockStackStartPos = BlockInfoStack.back().StackStartPos;
146 bool PolymorphicStack =
false;
148 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) {
151 if (std::get_if<Polymorphic>(&Stack[StackI - 1])) {
155 if (match(Stack[StackI - 1], Types[TypeI - 1])) {
162 if (StackI > BlockStackStartPos &&
163 std::get_if<Polymorphic>(&Stack[StackI - 1]))
164 PolymorphicStack =
true;
175 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos))
181 auto StackStartPos = ExactMatch
183 : std::max((
int)BlockStackStartPos,
184 (
int)Stack.size() - (
int)
Types.size());
185 return typeError(ErrorLoc,
"type mismatch, expected " +
186 getTypesString(Types) +
" but got " +
187 getTypesString(Stack, StackStartPos));
190bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
193 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
196bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
199 bool Error = checkTypes(ErrorLoc, Types, ExactMatch);
200 auto NumPops = std::min(Stack.size() - BlockInfoStack.back().StackStartPos,
202 for (
size_t I = 0,
E = NumPops;
I !=
E;
I++) {
203 if (std::get_if<Polymorphic>(&Stack.back()))
210bool WebAssemblyAsmTypeCheck::popType(
SMLoc ErrorLoc, StackType
Type) {
211 return popTypes(ErrorLoc, {
Type});
214bool WebAssemblyAsmTypeCheck::popRefType(
SMLoc ErrorLoc) {
215 return popType(ErrorLoc, Ref{});
218bool WebAssemblyAsmTypeCheck::popAnyType(
SMLoc ErrorLoc) {
219 return popType(ErrorLoc, Any{});
223 Stack.append(valTypesToStackTypes(ValTypes));
226bool WebAssemblyAsmTypeCheck::getLocal(
SMLoc ErrorLoc,
const MCOperand &LocalOp,
228 auto Local =
static_cast<size_t>(LocalOp.
getImm());
229 if (
Local >= LocalTypes.size())
230 return typeError(ErrorLoc, StringRef(
"no local type specified for index ") +
231 std::to_string(
Local));
236bool WebAssemblyAsmTypeCheck::checkSig(
SMLoc ErrorLoc,
243bool WebAssemblyAsmTypeCheck::getSymRef(
SMLoc ErrorLoc,
const MCOperand &SymOp,
246 return typeError(ErrorLoc, StringRef(
"expected expression operand"));
249 return typeError(ErrorLoc, StringRef(
"expected symbol operand"));
253bool WebAssemblyAsmTypeCheck::getGlobal(
SMLoc ErrorLoc,
256 const MCSymbolRefExpr *SymRef;
257 if (getSymRef(ErrorLoc, GlobalOp, SymRef))
259 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
276 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
277 ": missing .globaltype");
282bool WebAssemblyAsmTypeCheck::getTable(
SMLoc ErrorLoc,
const MCOperand &TableOp,
284 const MCSymbolRefExpr *SymRef;
285 if (getSymRef(ErrorLoc, TableOp, SymRef))
287 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
290 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
291 ": missing .tabletype");
296bool WebAssemblyAsmTypeCheck::getSignature(
SMLoc ErrorLoc,
300 const MCSymbolRefExpr *SymRef =
nullptr;
301 if (getSymRef(ErrorLoc, SigOp, SymRef))
303 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
304 Sig = WasmSym->getSignature();
306 if (!Sig || WasmSym->getType() !=
Type) {
318 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
319 ": missing ." + TypeName +
"type");
325 assert(!BlockInfoStack.empty());
326 const auto &FuncInfo = BlockInfoStack[0];
327 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch);
336 for (
size_t I = 0, E = TypesA.
size();
I < E;
I++)
337 if (TypesA[
I] != TypesB[
I])
342bool WebAssemblyAsmTypeCheck::checkTryTable(
SMLoc ErrorLoc,
347 for (int64_t
I = 0;
I < NumCatches;
I++) {
349 std::string ErrorMsgBase =
350 "try_table: catch index " + std::to_string(
I) +
": ";
368 if (Level < BlockInfoStack.size()) {
369 const auto &DestBlockInfo =
370 BlockInfoStack[BlockInfoStack.size() -
Level - 1];
372 if (DestBlockInfo.IsLoop)
373 DestTypes = DestBlockInfo.Sig.Params;
375 DestTypes = DestBlockInfo.Sig.Returns;
377 std::string ErrorMsg =
378 ErrorMsgBase +
"type mismatch, catch tag type is " +
379 getTypesString(SentTypes) +
", but destination's type is " +
380 getTypesString(DestTypes);
381 Error |= typeError(ErrorLoc, ErrorMsg);
384 Error = typeError(ErrorLoc, ErrorMsgBase +
"invalid depth " +
385 std::to_string(Level));
395 dumpTypeStack(
"typechecking " + Name +
": ");
398 if (Name ==
"local.get") {
399 if (!getLocal(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
407 if (Name ==
"local.set") {
408 if (!getLocal(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type))
409 return popType(ErrorLoc,
Type);
410 popType(ErrorLoc, Any{});
414 if (Name ==
"local.tee") {
415 if (!getLocal(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
420 popType(ErrorLoc, Any{});
425 if (Name ==
"global.get") {
426 if (!getGlobal(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
434 if (Name ==
"global.set") {
435 if (!getGlobal(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type))
436 return popType(ErrorLoc,
Type);
437 popType(ErrorLoc, Any{});
441 if (Name ==
"table.get") {
443 if (!getTable(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
451 if (Name ==
"table.set") {
455 if (!getTable(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
461 Error |= popTypes(ErrorLoc, PopTypes);
465 if (Name ==
"table.size") {
471 if (Name ==
"table.grow") {
474 if (!getTable(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
481 Error |= popTypes(ErrorLoc, PopTypes);
486 if (Name ==
"table.fill") {
490 if (!getTable(Operands[1]->getStartLoc(), Inst.
getOperand(0),
Type)) {
497 Error |= popTypes(ErrorLoc, PopTypes);
501 if (Name ==
"memory.fill") {
509 if (Name ==
"memory.copy") {
517 if (Name ==
"memory.init") {
525 if (Name ==
"drop") {
526 return popType(ErrorLoc, Any{});
529 if (Name ==
"block" || Name ==
"loop" || Name ==
"if" || Name ==
"try" ||
530 Name ==
"try_table") {
533 Error |= popTypes(ErrorLoc, LastSig.Params);
534 if (Name ==
"try_table")
535 Error |= checkTryTable(ErrorLoc, Inst);
537 BlockInfoStack.push_back({LastSig, Stack.size(), Name ==
"loop"});
539 pushTypes(LastSig.Params);
543 if (Name ==
"end_block" || Name ==
"end_loop" || Name ==
"end_if" ||
544 Name ==
"end_try" || Name ==
"delegate" || Name ==
"end_try_table" ||
545 Name ==
"else" || Name ==
"catch" || Name ==
"catch_all") {
546 assert(!BlockInfoStack.empty());
548 const auto &LastBlockInfo = BlockInfoStack.back();
549 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns,
true);
551 Stack.truncate(LastBlockInfo.StackStartPos);
552 if (Name ==
"else") {
555 pushTypes(LastBlockInfo.Sig.Params);
556 }
else if (Name ==
"catch") {
560 if (!getSignature(Operands[1]->getStartLoc(), Inst.
getOperand(0),
565 }
else if (Name ==
"catch_all") {
570 pushTypes(LastBlockInfo.Sig.Returns);
571 BlockInfoStack.pop_back();
576 if (Name ==
"br" || Name ==
"br_if") {
581 if (Operand.
isImm()) {
582 unsigned Level = Operand.
getImm();
583 if (Level < BlockInfoStack.size()) {
584 const auto &DestBlockInfo =
585 BlockInfoStack[BlockInfoStack.size() - Level - 1];
586 if (DestBlockInfo.IsLoop)
587 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Params,
false);
589 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Returns,
false);
592 std::to_string(Level));
596 typeError(Operands[1]->getStartLoc(),
"depth should be an integer");
599 pushType(Polymorphic{});
603 if (Name ==
"return") {
605 pushType(Polymorphic{});
609 if (Name ==
"call_indirect" || Name ==
"return_call_indirect") {
612 Error |= checkSig(ErrorLoc, LastSig);
613 if (Name ==
"return_call_indirect") {
615 pushType(Polymorphic{});
620 if (Name ==
"call_ref" || Name ==
"return_call_ref") {
624 Error |= checkSig(ErrorLoc, LastSig);
625 if (Name ==
"return_call_ref") {
627 pushType(Polymorphic{});
632 if (Name ==
"select") {
638 return typeError(ErrorLoc,
"select missing type-list operand");
641 return typeError(ErrorLoc,
642 "select type-list count exceeds operand count");
648 Error |= popTypes(ErrorLoc, Types);
649 Error |= popTypes(ErrorLoc, Types);
654 if (Name ==
"call" || Name ==
"return_call") {
657 if (!getSignature(Operands[1]->getStartLoc(), Inst.
getOperand(0),
659 Error |= checkSig(ErrorLoc, *Sig);
662 if (Name ==
"return_call") {
664 pushType(Polymorphic{});
669 if (Name ==
"unreachable") {
670 pushType(Polymorphic{});
674 if (Name ==
"ref.is_null") {
675 bool Error = popRefType(ErrorLoc);
680 if (Name ==
"throw") {
683 if (!getSignature(Operands[1]->getStartLoc(), Inst.
getOperand(0),
685 Error |= checkSig(ErrorLoc, *Sig);
688 pushType(Polymorphic{});
692 if (Name ==
"throw_ref") {
694 pushType(Polymorphic{});
702 assert(RegOpc != -1 &&
"Failed to get register version of MC instruction");
703 const auto &
II = MII.get(RegOpc);
706 for (
unsigned I =
II.getNumDefs();
I <
II.getNumOperands();
I++) {
707 const auto &
Op =
II.operands()[
I];
711 bool Error = popTypes(ErrorLoc, PopTypes);
714 for (
unsigned I = 0;
I <
II.getNumDefs();
I++) {
715 const auto &
Op =
II.operands()[
I];
719 pushTypes(PushTypes);
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
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 getNumOperands() const
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 reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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)
int32_t getRegisterOpcode(uint32_t 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
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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