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" || Name ==
"return_call") {
623 if (!getSignature(Operands[1]->getStartLoc(), Inst.
getOperand(0),
625 Error |= checkSig(ErrorLoc, *Sig);
628 if (Name ==
"return_call") {
630 pushType(Polymorphic{});
635 if (Name ==
"unreachable") {
636 pushType(Polymorphic{});
640 if (Name ==
"ref.is_null") {
641 bool Error = popRefType(ErrorLoc);
646 if (Name ==
"throw") {
649 if (!getSignature(Operands[1]->getStartLoc(), Inst.
getOperand(0),
651 Error |= checkSig(ErrorLoc, *Sig);
654 pushType(Polymorphic{});
658 if (Name ==
"throw_ref") {
660 pushType(Polymorphic{});
668 assert(RegOpc != -1 &&
"Failed to get register version of MC instruction");
669 const auto &
II = MII.get(RegOpc);
672 for (
unsigned I =
II.getNumDefs();
I <
II.getNumOperands();
I++) {
673 const auto &
Op =
II.operands()[
I];
677 bool Error = popTypes(ErrorLoc, PopTypes);
680 for (
unsigned I = 0;
I <
II.getNumDefs();
I++) {
681 const auto &
Op =
II.operands()[
I];
685 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.
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)
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
auto reverse(ContainerTy &&C)
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...
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