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]))
107 raw_string_ostream
SS(S);
119 return getTypesString(valTypesToStackTypes(Types), StartPos);
123WebAssemblyAsmTypeCheck::valTypesToStackTypes(
131bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
134 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
137bool WebAssemblyAsmTypeCheck::checkTypes(
SMLoc ErrorLoc,
140 auto StackI = Stack.size();
141 auto TypeI =
Types.size();
142 assert(!BlockInfoStack.empty());
143 auto BlockStackStartPos = BlockInfoStack.back().StackStartPos;
145 bool PolymorphicStack =
false;
147 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) {
150 if (std::get_if<Polymorphic>(&Stack[StackI - 1])) {
154 if (match(Stack[StackI - 1], Types[TypeI - 1])) {
161 if (StackI > BlockStackStartPos &&
162 std::get_if<Polymorphic>(&Stack[StackI - 1]))
163 PolymorphicStack =
true;
174 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos))
180 auto StackStartPos = ExactMatch
182 : std::max((
int)BlockStackStartPos,
183 (
int)Stack.size() - (
int)
Types.size());
184 return typeError(ErrorLoc,
"type mismatch, expected " +
185 getTypesString(Types) +
" but got " +
186 getTypesString(Stack, StackStartPos));
189bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
192 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
195bool WebAssemblyAsmTypeCheck::popTypes(
SMLoc ErrorLoc,
198 bool Error = checkTypes(ErrorLoc, Types, ExactMatch);
199 auto NumPops = std::min(Stack.size() - BlockInfoStack.back().StackStartPos,
201 for (
size_t I = 0,
E = NumPops;
I !=
E;
I++) {
202 if (std::get_if<Polymorphic>(&Stack.back()))
209bool WebAssemblyAsmTypeCheck::popType(
SMLoc ErrorLoc, StackType
Type) {
210 return popTypes(ErrorLoc, {
Type});
213bool WebAssemblyAsmTypeCheck::popRefType(
SMLoc ErrorLoc) {
214 return popType(ErrorLoc, Ref{});
217bool WebAssemblyAsmTypeCheck::popAnyType(
SMLoc ErrorLoc) {
218 return popType(ErrorLoc, Any{});
222 Stack.append(valTypesToStackTypes(ValTypes));
225bool WebAssemblyAsmTypeCheck::getLocal(
SMLoc ErrorLoc,
const MCOperand &LocalOp,
227 auto Local =
static_cast<size_t>(LocalOp.
getImm());
228 if (
Local >= LocalTypes.size())
229 return typeError(ErrorLoc, StringRef(
"no local type specified for index ") +
230 std::to_string(
Local));
235bool WebAssemblyAsmTypeCheck::checkSig(
SMLoc ErrorLoc,
242bool WebAssemblyAsmTypeCheck::getSymRef(
SMLoc ErrorLoc,
const MCOperand &SymOp,
245 return typeError(ErrorLoc, StringRef(
"expected expression operand"));
248 return typeError(ErrorLoc, StringRef(
"expected symbol operand"));
252bool WebAssemblyAsmTypeCheck::getGlobal(
SMLoc ErrorLoc,
255 const MCSymbolRefExpr *SymRef;
256 if (getSymRef(ErrorLoc, GlobalOp, SymRef))
258 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
275 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
276 ": missing .globaltype");
281bool WebAssemblyAsmTypeCheck::getTable(
SMLoc ErrorLoc,
const MCOperand &TableOp,
283 const MCSymbolRefExpr *SymRef;
284 if (getSymRef(ErrorLoc, TableOp, SymRef))
286 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
289 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
290 ": missing .tabletype");
295bool WebAssemblyAsmTypeCheck::getSignature(
SMLoc ErrorLoc,
299 const MCSymbolRefExpr *SymRef =
nullptr;
300 if (getSymRef(ErrorLoc, SigOp, SymRef))
302 auto *WasmSym =
static_cast<const MCSymbolWasm *
>(&SymRef->
getSymbol());
303 Sig = WasmSym->getSignature();
305 if (!Sig || WasmSym->getType() !=
Type) {
317 return typeError(ErrorLoc, StringRef(
"symbol ") + WasmSym->getName() +
318 ": missing ." + TypeName +
"type");
324 assert(!BlockInfoStack.empty());
325 const auto &FuncInfo = BlockInfoStack[0];
326 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch);
335 for (
size_t I = 0, E = TypesA.
size();
I < E;
I++)
336 if (TypesA[
I] != TypesB[
I])
341bool WebAssemblyAsmTypeCheck::checkTryTable(
SMLoc ErrorLoc,
346 for (int64_t
I = 0;
I < NumCatches;
I++) {
348 std::string ErrorMsgBase =
349 "try_table: catch index " + std::to_string(
I) +
": ";
367 if (Level < BlockInfoStack.size()) {
368 const auto &DestBlockInfo =
369 BlockInfoStack[BlockInfoStack.size() -
Level - 1];
371 if (DestBlockInfo.IsLoop)
372 DestTypes = DestBlockInfo.Sig.Params;
374 DestTypes = DestBlockInfo.Sig.Returns;
376 std::string ErrorMsg =
377 ErrorMsgBase +
"type mismatch, catch tag type is " +
378 getTypesString(SentTypes) +
", but destination's type is " +
379 getTypesString(DestTypes);
380 Error |= typeError(ErrorLoc, ErrorMsg);
383 Error = typeError(ErrorLoc, ErrorMsgBase +
"invalid depth " +
384 std::to_string(Level));
394 dumpTypeStack(
"typechecking " + Name +
": ");
397 if (Name ==
"local.get") {
406 if (Name ==
"local.set") {
408 return popType(ErrorLoc,
Type);
409 popType(ErrorLoc, Any{});
413 if (Name ==
"local.tee") {
419 popType(ErrorLoc, Any{});
424 if (Name ==
"global.get") {
433 if (Name ==
"global.set") {
435 return popType(ErrorLoc,
Type);
436 popType(ErrorLoc, Any{});
440 if (Name ==
"table.get") {
450 if (Name ==
"table.set") {
460 Error |= popTypes(ErrorLoc, PopTypes);
464 if (Name ==
"table.size") {
470 if (Name ==
"table.grow") {
480 Error |= popTypes(ErrorLoc, PopTypes);
485 if (Name ==
"table.fill") {
496 Error |= popTypes(ErrorLoc, PopTypes);
500 if (Name ==
"memory.fill") {
508 if (Name ==
"memory.copy") {
516 if (Name ==
"memory.init") {
524 if (Name ==
"drop") {
525 return popType(ErrorLoc, Any{});
528 if (Name ==
"block" || Name ==
"loop" || Name ==
"if" || Name ==
"try" ||
529 Name ==
"try_table") {
532 Error |= popTypes(ErrorLoc, LastSig.Params);
533 if (Name ==
"try_table")
534 Error |= checkTryTable(ErrorLoc, Inst);
536 BlockInfoStack.push_back({LastSig, Stack.size(), Name ==
"loop"});
538 pushTypes(LastSig.Params);
542 if (Name ==
"end_block" || Name ==
"end_loop" || Name ==
"end_if" ||
543 Name ==
"end_try" || Name ==
"delegate" || Name ==
"end_try_table" ||
544 Name ==
"else" || Name ==
"catch" || Name ==
"catch_all") {
545 assert(!BlockInfoStack.empty());
547 const auto &LastBlockInfo = BlockInfoStack.back();
548 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns,
true);
550 Stack.truncate(LastBlockInfo.StackStartPos);
551 if (Name ==
"else") {
554 pushTypes(LastBlockInfo.Sig.Params);
555 }
else if (Name ==
"catch") {
564 }
else if (Name ==
"catch_all") {
569 pushTypes(LastBlockInfo.Sig.Returns);
570 BlockInfoStack.pop_back();
575 if (Name ==
"br" || Name ==
"br_if") {
580 if (Operand.
isImm()) {
581 unsigned Level = Operand.
getImm();
582 if (Level < BlockInfoStack.size()) {
583 const auto &DestBlockInfo =
584 BlockInfoStack[BlockInfoStack.size() - Level - 1];
585 if (DestBlockInfo.IsLoop)
586 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Params,
false);
588 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Returns,
false);
591 std::to_string(Level));
595 typeError(
Operands[1]->getStartLoc(),
"depth should be an integer");
598 pushType(Polymorphic{});
602 if (Name ==
"return") {
604 pushType(Polymorphic{});
608 if (Name ==
"call_indirect" || Name ==
"return_call_indirect") {
611 Error |= checkSig(ErrorLoc, LastSig);
612 if (Name ==
"return_call_indirect") {
614 pushType(Polymorphic{});
619 if (Name ==
"call_ref" || Name ==
"return_call_ref") {
623 Error |= checkSig(ErrorLoc, LastSig);
624 if (Name ==
"return_call_ref") {
626 pushType(Polymorphic{});
631 if (Name ==
"select") {
637 return typeError(ErrorLoc,
"select missing type-list operand");
640 return typeError(ErrorLoc,
641 "select type-list count exceeds operand count");
644 for (uint64_t
I = 0;
I <
Count; ++
I)
647 Error |= popTypes(ErrorLoc, Types);
648 Error |= popTypes(ErrorLoc, Types);
653 if (Name ==
"call" || Name ==
"return_call") {
658 Error |= checkSig(ErrorLoc, *Sig);
661 if (Name ==
"return_call") {
663 pushType(Polymorphic{});
668 if (Name ==
"unreachable") {
669 pushType(Polymorphic{});
673 if (Name ==
"ref.is_null") {
674 bool Error = popRefType(ErrorLoc);
679 if (Name ==
"throw") {
684 Error |= checkSig(ErrorLoc, *Sig);
687 pushType(Polymorphic{});
691 if (Name ==
"throw_ref") {
693 pushType(Polymorphic{});
701 assert(RegOpc != -1 &&
"Failed to get register version of MC instruction");
702 const auto &
II = MII.get(RegOpc);
705 for (
unsigned I =
II.getNumDefs();
I <
II.getNumOperands();
I++) {
706 const auto &
Op =
II.operands()[
I];
710 bool Error = popTypes(ErrorLoc, PopTypes);
713 for (
unsigned I = 0;
I <
II.getNumDefs();
I++) {
714 const auto &
Op =
II.operands()[
I];
718 pushTypes(PushTypes);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
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