LLVM 24.0.0git
WebAssemblyAsmTypeCheck.cpp
Go to the documentation of this file.
1//==- WebAssemblyAsmTypeCheck.cpp - Assembler for WebAssembly -*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file is part of the WebAssembly Assembler.
11///
12/// It contains code to translate a parsed .s file into MCInsts.
13///
14//===----------------------------------------------------------------------===//
15
23#include "llvm/MC/MCContext.h"
24#include "llvm/MC/MCExpr.h"
25#include "llvm/MC/MCInst.h"
26#include "llvm/MC/MCInstrInfo.h"
30#include "llvm/MC/MCStreamer.h"
32#include "llvm/MC/MCSymbol.h"
37
38using namespace llvm;
39
40#define DEBUG_TYPE "wasm-asm-parser"
41
42extern StringRef getMnemonic(unsigned Opc);
43
44namespace llvm {
45
47 const MCInstrInfo &MII,
48 bool Is64)
49 : Parser(Parser), MII(MII), Is64(Is64) {}
50
52 LocalTypes.assign(Sig.Params.begin(), Sig.Params.end());
53 BlockInfoStack.push_back({Sig, 0, false});
54}
55
57 const SmallVectorImpl<wasm::ValType> &Locals) {
58 llvm::append_range(LocalTypes, Locals);
59}
60
61void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) {
62 LLVM_DEBUG({ dbgs() << Msg << getTypesString(Stack) << "\n"; });
63}
64
65bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) {
66 dumpTypeStack("current stack: ");
67 return Parser.Error(ErrorLoc, Msg);
68}
69
70bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) {
71 // These should have been filtered out in checkTypes()
72 assert(!std::get_if<Polymorphic>(&TypeA) &&
73 !std::get_if<Polymorphic>(&TypeB));
74
75 if (TypeA == TypeB)
76 return false;
77 if (std::get_if<Any>(&TypeA) || std::get_if<Any>(&TypeB))
78 return false;
79
80 if (std::get_if<Ref>(&TypeB))
81 std::swap(TypeA, TypeB);
82 assert(std::get_if<wasm::ValType>(&TypeB));
83 if (std::get_if<Ref>(&TypeA) &&
84 WebAssembly::isRefType(std::get<wasm::ValType>(TypeB)))
85 return false;
86 return true;
87}
88
89std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef<StackType> Types,
90 size_t StartPos) {
91 SmallVector<std::string, 4> TypeStrs;
92 for (auto I = Types.size(); I > StartPos; I--) {
93 if (std::get_if<Polymorphic>(&Types[I - 1])) {
94 TypeStrs.push_back("...");
95 break;
96 }
97 if (std::get_if<Any>(&Types[I - 1]))
98 TypeStrs.push_back("any");
99 else if (std::get_if<Ref>(&Types[I - 1]))
100 TypeStrs.push_back("ref");
101 else
102 TypeStrs.push_back(
103 WebAssembly::typeToString(std::get<wasm::ValType>(Types[I - 1])));
104 }
105
106 std::string S;
107 raw_string_ostream SS(S);
108 SS << "[";
109 ListSeparator LS;
110 for (StringRef Type : reverse(TypeStrs))
111 SS << LS << Type;
112 SS << "]";
113 return SS.str();
114}
115
116std::string
117WebAssemblyAsmTypeCheck::getTypesString(ArrayRef<wasm::ValType> Types,
118 size_t StartPos) {
119 return getTypesString(valTypesToStackTypes(Types), StartPos);
120}
121
123WebAssemblyAsmTypeCheck::valTypesToStackTypes(
124 ArrayRef<wasm::ValType> ValTypes) {
126 llvm::transform(ValTypes, Types.begin(),
127 [](wasm::ValType Val) -> StackType { return Val; });
128 return Types;
129}
130
131bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc,
133 bool ExactMatch) {
134 return checkTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
135}
136
137bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc,
139 bool ExactMatch) {
140 auto StackI = Stack.size();
141 auto TypeI = Types.size();
142 assert(!BlockInfoStack.empty());
143 auto BlockStackStartPos = BlockInfoStack.back().StackStartPos;
144 bool Error = false;
145 bool PolymorphicStack = false;
146 // Compare elements one by one from the stack top
147 for (; StackI > BlockStackStartPos && TypeI > 0; StackI--, TypeI--) {
148 // If the stack is polymorphic, we assume all types in 'Types' have been
149 // compared and matched
150 if (std::get_if<Polymorphic>(&Stack[StackI - 1])) {
151 TypeI = 0;
152 break;
153 }
154 if (match(Stack[StackI - 1], Types[TypeI - 1])) {
155 Error = true;
156 break;
157 }
158 }
159
160 // If the stack top is polymorphic, the stack is in the polymorphic state.
161 if (StackI > BlockStackStartPos &&
162 std::get_if<Polymorphic>(&Stack[StackI - 1]))
163 PolymorphicStack = true;
164
165 // Even if no match failure has happened in the loop above, if not all
166 // elements of Types has been matched, that means we don't have enough
167 // elements on the stack.
168 //
169 // Also, if not all elements of the Stack has been matched and when
170 // 'ExactMatch' is true and the current stack is not polymorphic, that means
171 // we have superfluous elements remaining on the stack (e.g. at the end of a
172 // function).
173 if (TypeI > 0 ||
174 (ExactMatch && !PolymorphicStack && StackI > BlockStackStartPos))
175 Error = true;
176
177 if (!Error)
178 return false;
179
180 auto StackStartPos = ExactMatch
181 ? BlockStackStartPos
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));
187}
188
189bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,
191 bool ExactMatch) {
192 return popTypes(ErrorLoc, valTypesToStackTypes(ValTypes), ExactMatch);
193}
194
195bool WebAssemblyAsmTypeCheck::popTypes(SMLoc ErrorLoc,
197 bool ExactMatch) {
198 bool Error = checkTypes(ErrorLoc, Types, ExactMatch);
199 auto NumPops = std::min(Stack.size() - BlockInfoStack.back().StackStartPos,
200 Types.size());
201 for (size_t I = 0, E = NumPops; I != E; I++) {
202 if (std::get_if<Polymorphic>(&Stack.back()))
203 break;
204 Stack.pop_back();
205 }
206 return Error;
207}
208
209bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) {
210 return popTypes(ErrorLoc, {Type});
211}
212
213bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) {
214 return popType(ErrorLoc, Ref{});
215}
216
217bool WebAssemblyAsmTypeCheck::popAnyType(SMLoc ErrorLoc) {
218 return popType(ErrorLoc, Any{});
219}
220
221void WebAssemblyAsmTypeCheck::pushTypes(ArrayRef<wasm::ValType> ValTypes) {
222 Stack.append(valTypesToStackTypes(ValTypes));
223}
224
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));
231 Type = LocalTypes[Local];
232 return false;
233}
234
235bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc,
236 const wasm::WasmSignature &Sig) {
237 bool Error = popTypes(ErrorLoc, Sig.Params);
238 pushTypes(Sig.Returns);
239 return Error;
240}
241
242bool WebAssemblyAsmTypeCheck::getSymRef(SMLoc ErrorLoc, const MCOperand &SymOp,
243 const MCSymbolRefExpr *&SymRef) {
244 if (!SymOp.isExpr())
245 return typeError(ErrorLoc, StringRef("expected expression operand"));
246 SymRef = dyn_cast<MCSymbolRefExpr>(SymOp.getExpr());
247 if (!SymRef)
248 return typeError(ErrorLoc, StringRef("expected symbol operand"));
249 return false;
250}
251
252bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc,
253 const MCOperand &GlobalOp,
255 const MCSymbolRefExpr *SymRef;
256 if (getSymRef(ErrorLoc, GlobalOp, SymRef))
257 return true;
258 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());
259 switch (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA)) {
261 Type = static_cast<wasm::ValType>(WasmSym->getGlobalType().Type);
262 break;
265 switch (SymRef->getSpecifier()) {
269 return false;
270 default:
271 break;
272 }
273 [[fallthrough]];
274 default:
275 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
276 ": missing .globaltype");
277 }
278 return false;
279}
280
281bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCOperand &TableOp,
283 const MCSymbolRefExpr *SymRef;
284 if (getSymRef(ErrorLoc, TableOp, SymRef))
285 return true;
286 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());
287 if (WasmSym->getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA) !=
289 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
290 ": missing .tabletype");
291 Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType);
292 return false;
293}
294
295bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc,
296 const MCOperand &SigOp,
298 const wasm::WasmSignature *&Sig) {
299 const MCSymbolRefExpr *SymRef = nullptr;
300 if (getSymRef(ErrorLoc, SigOp, SymRef))
301 return true;
302 auto *WasmSym = static_cast<const MCSymbolWasm *>(&SymRef->getSymbol());
303 Sig = WasmSym->getSignature();
304
305 if (!Sig || WasmSym->getType() != Type) {
306 const char *TypeName = nullptr;
307 switch (Type) {
309 TypeName = "func";
310 break;
312 TypeName = "tag";
313 break;
314 default:
315 llvm_unreachable("Signature symbol should either be a function or a tag");
316 }
317 return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
318 ": missing ." + TypeName + "type");
319 }
320 return false;
321}
322
323bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc, bool ExactMatch) {
324 assert(!BlockInfoStack.empty());
325 const auto &FuncInfo = BlockInfoStack[0];
326 return checkTypes(ErrorLoc, FuncInfo.Sig.Returns, ExactMatch);
327}
328
329// Unlike checkTypes() family, this just compare the equivalence of the two
330// ValType vectors
333 if (TypesA.size() != TypesB.size())
334 return true;
335 for (size_t I = 0, E = TypesA.size(); I < E; I++)
336 if (TypesA[I] != TypesB[I])
337 return true;
338 return false;
339}
340
341bool WebAssemblyAsmTypeCheck::checkTryTable(SMLoc ErrorLoc,
342 const MCInst &Inst) {
343 bool Error = false;
344 unsigned OpIdx = 1; // OpIdx 0 is the block type
345 int64_t NumCatches = Inst.getOperand(OpIdx++).getImm();
346 for (int64_t I = 0; I < NumCatches; I++) {
347 int64_t Opcode = Inst.getOperand(OpIdx++).getImm();
348 std::string ErrorMsgBase =
349 "try_table: catch index " + std::to_string(I) + ": ";
350
351 const wasm::WasmSignature *Sig = nullptr;
353 if (Opcode == wasm::WASM_OPCODE_CATCH ||
354 Opcode == wasm::WASM_OPCODE_CATCH_REF) {
355 if (!getSignature(ErrorLoc, Inst.getOperand(OpIdx++),
357 llvm::append_range(SentTypes, Sig->Params);
358 else
359 Error = true;
360 }
361 if (Opcode == wasm::WASM_OPCODE_CATCH_REF ||
364 }
365
366 unsigned Level = Inst.getOperand(OpIdx++).getImm();
367 if (Level < BlockInfoStack.size()) {
368 const auto &DestBlockInfo =
369 BlockInfoStack[BlockInfoStack.size() - Level - 1];
370 ArrayRef<wasm::ValType> DestTypes;
371 if (DestBlockInfo.IsLoop)
372 DestTypes = DestBlockInfo.Sig.Params;
373 else
374 DestTypes = DestBlockInfo.Sig.Returns;
375 if (compareTypes(SentTypes, DestTypes)) {
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);
381 }
382 } else {
383 Error = typeError(ErrorLoc, ErrorMsgBase + "invalid depth " +
384 std::to_string(Level));
385 }
386 }
387 return Error;
388}
389
392 auto Opc = Inst.getOpcode();
393 auto Name = getMnemonic(Opc);
394 dumpTypeStack("typechecking " + Name + ": ");
396
397 if (Name == "local.get") {
398 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
399 pushType(Type);
400 return false;
401 }
402 pushType(Any{});
403 return true;
404 }
405
406 if (Name == "local.set") {
407 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
408 return popType(ErrorLoc, Type);
409 popType(ErrorLoc, Any{});
410 return true;
411 }
412
413 if (Name == "local.tee") {
414 if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
415 bool Error = popType(ErrorLoc, Type);
416 pushType(Type);
417 return Error;
418 }
419 popType(ErrorLoc, Any{});
420 pushType(Any{});
421 return true;
422 }
423
424 if (Name == "global.get") {
425 if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
426 pushType(Type);
427 return false;
428 }
429 pushType(Any{});
430 return true;
431 }
432
433 if (Name == "global.set") {
434 if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type))
435 return popType(ErrorLoc, Type);
436 popType(ErrorLoc, Any{});
437 return true;
438 }
439
440 if (Name == "table.get") {
441 bool Error = popType(ErrorLoc, wasm::ValType::I32);
442 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
443 pushType(Type);
444 return Error;
445 }
446 pushType(Any{});
447 return true;
448 }
449
450 if (Name == "table.set") {
451 bool Error = false;
454 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
455 PopTypes.push_back(Type);
456 } else {
457 Error = true;
458 PopTypes.push_back(Any{});
459 }
460 Error |= popTypes(ErrorLoc, PopTypes);
461 return Error;
462 }
463
464 if (Name == "table.size") {
465 bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type);
466 pushType(wasm::ValType::I32);
467 return Error;
468 }
469
470 if (Name == "table.grow") {
471 bool Error = false;
473 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
474 PopTypes.push_back(Type);
475 } else {
476 Error = true;
477 PopTypes.push_back(Any{});
478 }
480 Error |= popTypes(ErrorLoc, PopTypes);
481 pushType(wasm::ValType::I32);
482 return Error;
483 }
484
485 if (Name == "table.fill") {
486 bool Error = false;
489 if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
490 PopTypes.push_back(Type);
491 } else {
492 Error = true;
493 PopTypes.push_back(Any{});
494 }
496 Error |= popTypes(ErrorLoc, PopTypes);
497 return Error;
498 }
499
500 if (Name == "memory.fill") {
502 bool Error = popType(ErrorLoc, Type);
503 Error |= popType(ErrorLoc, wasm::ValType::I32);
504 Error |= popType(ErrorLoc, Type);
505 return Error;
506 }
507
508 if (Name == "memory.copy") {
510 bool Error = popType(ErrorLoc, Type);
511 Error |= popType(ErrorLoc, Type);
512 Error |= popType(ErrorLoc, Type);
513 return Error;
514 }
515
516 if (Name == "memory.init") {
518 bool Error = popType(ErrorLoc, wasm::ValType::I32);
519 Error |= popType(ErrorLoc, wasm::ValType::I32);
520 Error |= popType(ErrorLoc, Type);
521 return Error;
522 }
523
524 if (Name == "drop") {
525 return popType(ErrorLoc, Any{});
526 }
527
528 if (Name == "block" || Name == "loop" || Name == "if" || Name == "try" ||
529 Name == "try_table") {
530 bool Error = Name == "if" && popType(ErrorLoc, wasm::ValType::I32);
531 // Pop block input parameters and check their types are correct
532 Error |= popTypes(ErrorLoc, LastSig.Params);
533 if (Name == "try_table")
534 Error |= checkTryTable(ErrorLoc, Inst);
535 // Push a new block info
536 BlockInfoStack.push_back({LastSig, Stack.size(), Name == "loop"});
537 // Push back block input parameters
538 pushTypes(LastSig.Params);
539 return Error;
540 }
541
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());
546 // Check if the types on the stack match with the block return type
547 const auto &LastBlockInfo = BlockInfoStack.back();
548 bool Error = checkTypes(ErrorLoc, LastBlockInfo.Sig.Returns, true);
549 // Pop all types added to the stack for the current block level
550 Stack.truncate(LastBlockInfo.StackStartPos);
551 if (Name == "else") {
552 // 'else' expects the block input parameters to be on the stack, in the
553 // same way we entered 'if'
554 pushTypes(LastBlockInfo.Sig.Params);
555 } else if (Name == "catch") {
556 // 'catch' instruction pushes values whose types are specified in the
557 // tag's 'params' part
558 const wasm::WasmSignature *Sig = nullptr;
559 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),
561 pushTypes(Sig->Params);
562 else
563 Error = true;
564 } else if (Name == "catch_all") {
565 // 'catch_all' does not push anything onto the stack
566 } else {
567 // For normal end markers, push block return value types onto the stack
568 // and pop the block info
569 pushTypes(LastBlockInfo.Sig.Returns);
570 BlockInfoStack.pop_back();
571 }
572 return Error;
573 }
574
575 if (Name == "br" || Name == "br_if") {
576 bool Error = false;
577 if (Name == "br_if")
578 Error |= popType(ErrorLoc, wasm::ValType::I32); // cond
579 const MCOperand &Operand = Inst.getOperand(0);
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);
587 else
588 Error |= checkTypes(ErrorLoc, DestBlockInfo.Sig.Returns, false);
589 } else {
590 Error = typeError(ErrorLoc, StringRef("br: invalid depth ") +
591 std::to_string(Level));
592 }
593 } else {
594 Error =
595 typeError(Operands[1]->getStartLoc(), "depth should be an integer");
596 }
597 if (Name == "br")
598 pushType(Polymorphic{});
599 return Error;
600 }
601
602 if (Name == "return") {
603 bool Error = endOfFunction(ErrorLoc, false);
604 pushType(Polymorphic{});
605 return Error;
606 }
607
608 if (Name == "call_indirect" || Name == "return_call_indirect") {
609 // Function value.
610 bool Error = popType(ErrorLoc, wasm::ValType::I32);
611 Error |= checkSig(ErrorLoc, LastSig);
612 if (Name == "return_call_indirect") {
613 Error |= endOfFunction(ErrorLoc, false);
614 pushType(Polymorphic{});
615 }
616 return Error;
617 }
618
619 if (Name == "call_ref" || Name == "return_call_ref") {
620 // Funcref target popped from the stack, followed by the signature's
621 // parameters; pushes the signature's results.
622 bool Error = popType(ErrorLoc, wasm::ValType::FUNCREF);
623 Error |= checkSig(ErrorLoc, LastSig);
624 if (Name == "return_call_ref") {
625 Error |= endOfFunction(ErrorLoc, false);
626 pushType(Polymorphic{});
627 }
628 return Error;
629 }
630
631 if (Name == "select") {
632 // Typed select pops an i32 condition and two values of each declared
633 // type, then pushes the declared types back. The result type list lives
634 // in the MCInst operands as a count followed by that many valtype bytes.
635 bool Error = popType(ErrorLoc, wasm::ValType::I32);
636 if (Inst.getNumOperands() == 0)
637 return typeError(ErrorLoc, "select missing type-list operand");
638 uint64_t Count = uint64_t(Inst.getOperand(0).getImm());
639 if (Count > uint64_t(Inst.getNumOperands() - 1))
640 return typeError(ErrorLoc,
641 "select type-list count exceeds operand count");
643 Types.reserve(Count);
644 for (uint64_t I = 0; I < Count; ++I)
645 Types.push_back(
646 static_cast<wasm::ValType>(Inst.getOperand(1 + I).getImm()));
647 Error |= popTypes(ErrorLoc, Types);
648 Error |= popTypes(ErrorLoc, Types);
649 pushTypes(Types);
650 return Error;
651 }
652
653 if (Name == "call" || Name == "return_call") {
654 bool Error = false;
655 const wasm::WasmSignature *Sig = nullptr;
656 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),
658 Error |= checkSig(ErrorLoc, *Sig);
659 else
660 Error = true;
661 if (Name == "return_call") {
662 Error |= endOfFunction(ErrorLoc, false);
663 pushType(Polymorphic{});
664 }
665 return Error;
666 }
667
668 if (Name == "unreachable") {
669 pushType(Polymorphic{});
670 return false;
671 }
672
673 if (Name == "ref.is_null") {
674 bool Error = popRefType(ErrorLoc);
675 pushType(wasm::ValType::I32);
676 return Error;
677 }
678
679 if (Name == "throw") {
680 bool Error = false;
681 const wasm::WasmSignature *Sig = nullptr;
682 if (!getSignature(Operands[1]->getStartLoc(), Inst.getOperand(0),
684 Error |= checkSig(ErrorLoc, *Sig);
685 else
686 Error = true;
687 pushType(Polymorphic{});
688 return Error;
689 }
690
691 if (Name == "throw_ref") {
692 bool Error = popType(ErrorLoc, wasm::ValType::EXNREF);
693 pushType(Polymorphic{});
694 return Error;
695 }
696
697 // The current instruction is a stack instruction which doesn't have
698 // explicit operands that indicate push/pop types, so we get those from
699 // the register version of the same instruction.
700 auto RegOpc = WebAssembly::getRegisterOpcode(Opc);
701 assert(RegOpc != -1 && "Failed to get register version of MC instruction");
702 const auto &II = MII.get(RegOpc);
703 // First pop all the uses off the stack and check them.
705 for (unsigned I = II.getNumDefs(); I < II.getNumOperands(); I++) {
706 const auto &Op = II.operands()[I];
707 if (Op.OperandType == MCOI::OPERAND_REGISTER)
708 PopTypes.push_back(WebAssembly::regClassToValType(Op.RegClass));
709 }
710 bool Error = popTypes(ErrorLoc, PopTypes);
712 // Now push all the defs onto the stack.
713 for (unsigned I = 0; I < II.getNumDefs(); I++) {
714 const auto &Op = II.operands()[I];
715 assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected");
716 PushTypes.push_back(WebAssembly::regClassToValType(Op.RegClass));
717 }
718 pushTypes(PushTypes);
719 return Error;
720}
721
722} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
SI Fold Operands
const char * Msg
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
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),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Generic assembler parser interface, for use by target specific assembly parsers.
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
unsigned getNumOperands() const
Definition MCInst.h:212
unsigned getOpcode() const
Definition MCInst.h:202
const MCOperand & getOperand(unsigned i) const
Definition MCInst.h:210
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
int64_t getImm() const
Definition MCInst.h:84
bool isImm() const
Definition MCInst.h:66
const MCExpr * getExpr() const
Definition MCInst.h:118
bool isExpr() const
Definition MCInst.h:69
Represent a reference to a symbol from inside an expression.
Definition MCExpr.h:190
const MCSymbol & getSymbol() const
Definition MCExpr.h:226
uint16_t getSpecifier() const
Definition MCExpr.h:232
Represents a location in source code.
Definition SMLoc.h:22
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.
Definition StringRef.h:56
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
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
Definition Wasm.h:163
@ WASM_OPCODE_CATCH
Definition Wasm.h:160
@ WASM_OPCODE_CATCH_REF
Definition Wasm.h:161
WasmSymbolType
Definition Wasm.h:228
@ WASM_SYMBOL_TYPE_GLOBAL
Definition Wasm.h:231
@ WASM_SYMBOL_TYPE_DATA
Definition Wasm.h:230
@ WASM_SYMBOL_TYPE_TAG
Definition Wasm.h:233
@ WASM_SYMBOL_TYPE_TABLE
Definition Wasm.h:234
@ WASM_SYMBOL_TYPE_FUNCTION
Definition Wasm.h:229
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.
Definition Casting.h:643
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.
Definition STLExtras.h:2208
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.
Definition STLExtras.h:2026
SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
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.
Definition BitVector.h:880
SmallVector< ValType, 1 > Returns
Definition Wasm.h:524
SmallVector< ValType, 4 > Params
Definition Wasm.h:525