23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/DebugLog.h"
25 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/FormatVariadic.h"
27 #include "llvm/Support/LEB128.h"
28 #include "llvm/Support/LogicalResult.h"
34 #define DEBUG_TYPE "wasm-translate"
36 static_assert(CHAR_BIT == 8,
37 "This code expects std::byte to be exactly 8 bits");
44 using section_id_t = uint8_t;
45 enum struct WasmSectionType : section_id_t {
61 constexpr section_id_t highestWasmSectionID{
62 static_cast<section_id_t
>(WasmSectionType::DATACOUNT)};
64 #define APPLY_WASM_SEC_TRANSFORM \
65 WASM_SEC_TRANSFORM(CUSTOM) \
66 WASM_SEC_TRANSFORM(TYPE) \
67 WASM_SEC_TRANSFORM(IMPORT) \
68 WASM_SEC_TRANSFORM(FUNCTION) \
69 WASM_SEC_TRANSFORM(TABLE) \
70 WASM_SEC_TRANSFORM(MEMORY) \
71 WASM_SEC_TRANSFORM(GLOBAL) \
72 WASM_SEC_TRANSFORM(EXPORT) \
73 WASM_SEC_TRANSFORM(START) \
74 WASM_SEC_TRANSFORM(ELEMENT) \
75 WASM_SEC_TRANSFORM(CODE) \
76 WASM_SEC_TRANSFORM(DATA) \
77 WASM_SEC_TRANSFORM(DATACOUNT)
79 template <WasmSectionType>
80 constexpr
const char *wasmSectionName =
"";
82 #define WASM_SEC_TRANSFORM(section) \
84 [[maybe_unused]] constexpr const char \
85 *wasmSectionName<WasmSectionType::section> = #section;
87 #undef WASM_SEC_TRANSFORM
89 constexpr
bool sectionShouldBeUnique(WasmSectionType secType) {
90 return secType != WasmSectionType::CUSTOM;
93 template <std::byte... Bytes>
94 struct ByteSequence {};
97 template <std::
byte Byte>
98 struct UniqueByte : ByteSequence<Byte> {};
100 [[maybe_unused]] constexpr ByteSequence<
105 template <std::byte... allowedFlags>
106 constexpr
bool isValueOneOf(std::byte value,
107 ByteSequence<allowedFlags...> = {}) {
108 return ((value == allowedFlags) | ... |
false);
111 template <std::byte... flags>
112 constexpr
bool isNotIn(std::byte value, ByteSequence<flags...> = {}) {
113 return !isValueOneOf<flags...>(value);
116 struct GlobalTypeRecord {
121 struct TypeIdxRecord {
125 struct SymbolRefContainer {
129 struct GlobalSymbolRefContainer : SymbolRefContainer {
133 struct FunctionSymbolRefContainer : SymbolRefContainer {
134 FunctionType functionType;
138 std::variant<TypeIdxRecord, TableType, LimitType, GlobalTypeRecord>;
140 using parsed_inst_t = FailureOr<SmallVector<Value>>;
142 struct EmptyBlockMarker {};
143 using BlockTypeParseResult =
144 std::variant<EmptyBlockMarker, TypeIdxRecord, Type>;
146 struct WasmModuleSymbolTables {
153 std::string getNewSymbolName(StringRef prefix,
size_t id)
const {
154 return (prefix + Twine{
id}).str();
157 std::string getNewFuncSymbolName()
const {
158 size_t id = funcSymbols.size();
159 return getNewSymbolName(
"func_",
id);
162 std::string getNewGlobalSymbolName()
const {
163 size_t id = globalSymbols.size();
164 return getNewSymbolName(
"global_",
id);
167 std::string getNewMemorySymbolName()
const {
168 size_t id = memSymbols.size();
169 return getNewSymbolName(
"mem_",
id);
172 std::string getNewTableSymbolName()
const {
173 size_t id = tableSymbols.size();
174 return getNewSymbolName(
"table_",
id);
190 LabelLevelOpInterface levelOp;
194 bool empty()
const {
return values.empty(); }
196 size_t size()
const {
return values.size(); }
206 FailureOr<SmallVector<Value>> popOperands(
TypeRange operandTypes,
217 void addLabelLevel(LabelLevelOpInterface levelOp) {
218 labelLevel.push_back({values.size(), levelOp});
219 LDBG() <<
"Adding a new frame context to ValueStack";
222 void dropLabelLevel() {
223 assert(!labelLevel.empty() &&
"Trying to drop a frame from empty context");
224 auto newSize = labelLevel.pop_back_val().stackIdx;
225 values.truncate(newSize);
227 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
230 LLVM_DUMP_METHOD
void dump()
const;
240 class ExpressionParser {
243 ExpressionParser(ParserHead &parser, WasmModuleSymbolTables
const &symbols,
245 : parser{parser}, symbols{symbols}, locals{initLocal} {}
248 template <std::
byte opCode>
249 inline parsed_inst_t parseSpecificInstruction(
OpBuilder &builder);
251 template <
typename valueT>
254 std::enable_if_t<std::is_arithmetic_v<valueT>> * =
nullptr);
265 template <
typename opcode,
typename valueType,
unsigned int numOperands>
268 std::enable_if_t<std::is_arithmetic_v<valueType>> * =
nullptr);
279 template <
typename opType,
typename inputType,
typename outputType,
280 typename... extraArgsT>
281 inline parsed_inst_t buildConvertOp(
OpBuilder &builder, extraArgsT...);
294 template <
size_t patternBitSize = 0, std::byte highBitPattern = std::byte{0}>
295 inline parsed_inst_t dispatchToInstParser(std::byte opCode,
297 static_assert(patternBitSize <= 8,
298 "PatternBitSize is outside of range of opcode space! "
299 "(expected at most 8 bits)");
300 if constexpr (patternBitSize < 8) {
301 constexpr std::byte bitSelect{1 << (7 - patternBitSize)};
302 constexpr std::byte nextHighBitPatternStem = highBitPattern << 1;
303 constexpr
size_t nextPatternBitSize = patternBitSize + 1;
304 if ((opCode & bitSelect) != std::byte{0})
305 return dispatchToInstParser<nextPatternBitSize,
306 nextHighBitPatternStem | std::byte{1}>(
308 return dispatchToInstParser<nextPatternBitSize, nextHighBitPatternStem>(
311 return parseSpecificInstruction<highBitPattern>(builder);
318 struct NestingContextGuard {
319 NestingContextGuard(ExpressionParser &parser, LabelLevelOpInterface levelOp)
321 parser.addNestingContextLevel(levelOp);
323 NestingContextGuard(NestingContextGuard &&other) : parser{other.parser} {
324 other.shouldDropOnDestruct =
false;
326 NestingContextGuard(NestingContextGuard
const &) =
delete;
327 ~NestingContextGuard() {
328 if (shouldDropOnDestruct)
329 parser.dropNestingContextLevel();
331 ExpressionParser &parser;
332 bool shouldDropOnDestruct =
true;
335 void addNestingContextLevel(LabelLevelOpInterface levelOp) {
336 valueStack.addLabelLevel(levelOp);
339 void dropNestingContextLevel() {
342 valueStack.dropLabelLevel();
345 llvm::FailureOr<FunctionType> getFuncTypeFor(
OpBuilder &builder,
350 llvm::FailureOr<FunctionType> getFuncTypeFor(
OpBuilder &builder,
351 TypeIdxRecord type) {
352 if (type.id >= symbols.moduleFuncTypes.size())
354 "type index references nonexistent type (")
355 << type.id <<
"). Only " << symbols.moduleFuncTypes.size()
356 <<
" types are registered";
357 return symbols.moduleFuncTypes[type.id];
360 llvm::FailureOr<FunctionType> getFuncTypeFor(
OpBuilder &builder,
365 llvm::FailureOr<FunctionType>
366 getFuncTypeFor(
OpBuilder &builder, BlockTypeParseResult parseResult) {
368 [
this, &builder](
auto value) {
return getFuncTypeFor(builder, value); },
372 llvm::FailureOr<FunctionType>
374 llvm::FailureOr<BlockTypeParseResult> parseResult) {
377 return getFuncTypeFor(builder, *parseResult);
380 llvm::FailureOr<FunctionType> parseBlockFuncType(
OpBuilder &builder);
382 struct ParseResultWithInfo {
384 std::byte endingByte;
387 template <
typename FilterT = ByteSequence<WasmBinaryEncoding::endByte>>
390 llvm::FailureOr<std::byte>
392 Location opLoc, LabelLevelOpInterface levelOp,
393 FilterT parseEndBytes = {}) {
396 LDBG() <<
"parsing a block of type "
399 auto nC = addNesting(levelOp);
403 auto bodyParsingRes =
parse(builder, parseEndBytes);
404 if (
failed(bodyParsingRes))
406 auto returnOperands = popOperands(resTypes);
407 if (
failed(returnOperands))
409 BlockReturnOp::create(builder, opLoc, *returnOperands);
410 LDBG() <<
"end of parsing of a block";
411 return bodyParsingRes->endingByte;
415 template <std::
byte ParseEndByte = WasmBinaryEncoding::endByte>
416 parsed_inst_t
parse(
OpBuilder &builder, UniqueByte<ParseEndByte> = {});
418 template <std::byte... ExpressionParseEnd>
419 FailureOr<ParseResultWithInfo>
421 ByteSequence<ExpressionParseEnd...> parsingEndFilters);
423 NestingContextGuard addNesting(LabelLevelOpInterface levelOp) {
424 return NestingContextGuard{*
this, levelOp};
427 FailureOr<llvm::SmallVector<Value>> popOperands(
TypeRange operandTypes) {
428 return valueStack.popOperands(operandTypes, ¤tOpLoc.value());
431 LogicalResult pushResults(
ValueRange results) {
432 return valueStack.pushResults(results, ¤tOpLoc.value());
438 template <
typename OpToCreate>
439 parsed_inst_t parseSetOrTee(
OpBuilder &);
444 template <
typename OpToCreate>
445 parsed_inst_t parseBlockLikeOp(
OpBuilder &);
448 std::optional<Location> currentOpLoc;
450 WasmModuleSymbolTables
const &symbols;
452 ValueStack valueStack;
457 ParserHead(StringRef src, StringAttr name) : head{src}, locName{name} {}
458 ParserHead(ParserHead &&) =
default;
461 ParserHead(ParserHead
const &other) =
default;
464 auto getLocation()
const {
468 FailureOr<StringRef> consumeNBytes(
size_t nBytes) {
469 LDBG() <<
"Consume " << nBytes <<
" bytes";
470 LDBG() <<
" Bytes remaining: " << size();
471 LDBG() <<
" Current offset: " << offset;
473 return emitError(getLocation(),
"trying to extract ")
474 << nBytes <<
"bytes when only " << size() <<
"are available";
476 StringRef res = head.slice(offset, offset + nBytes);
478 LDBG() <<
" Updated offset (+" << nBytes <<
"): " << offset;
482 FailureOr<std::byte> consumeByte() {
483 FailureOr<StringRef> res = consumeNBytes(1);
486 return std::byte{*res->bytes_begin()};
489 template <
typename T>
490 FailureOr<T> parseLiteral();
492 FailureOr<uint32_t> parseVectorSize();
498 inline FailureOr<uint32_t> parseUI32();
499 inline FailureOr<int64_t> parseI64();
502 FailureOr<StringRef> parseName() {
503 FailureOr<uint32_t> size = parseVectorSize();
507 return consumeNBytes(*size);
510 FailureOr<WasmSectionType> parseWasmSectionType() {
511 FailureOr<std::byte>
id = consumeByte();
514 if (std::to_integer<unsigned>(*
id) > highestWasmSectionID)
515 return emitError(getLocation(),
"invalid section ID: ")
516 <<
static_cast<int>(*id);
517 return static_cast<WasmSectionType
>(*id);
520 FailureOr<LimitType> parseLimit(
MLIRContext *ctx) {
523 FailureOr<std::byte> limitHeader = consumeByte();
527 if (isNotIn<WasmLimits::bothLimits, WasmLimits::lowLimitOnly>(*limitHeader))
528 return emitError(limitLocation,
"invalid limit header: ")
529 <<
static_cast<int>(*limitHeader);
530 FailureOr<uint32_t> minParse = parseUI32();
533 std::optional<uint32_t>
max{std::nullopt};
534 if (*limitHeader == WasmLimits::bothLimits) {
535 FailureOr<uint32_t> maxParse = parseUI32();
545 FailureOr<std::byte> typeEncoding = consumeByte();
548 switch (*typeEncoding) {
564 return emitError(typeLoc,
"invalid value type encoding: ")
565 <<
static_cast<int>(*typeEncoding);
569 FailureOr<GlobalTypeRecord> parseGlobalType(
MLIRContext *ctx) {
571 FailureOr<Type> typeParsed = parseValueType(ctx);
575 FailureOr<std::byte> mutSpec = consumeByte();
578 if (isNotIn<WasmGlobalMut::isConst, WasmGlobalMut::isMutable>(*mutSpec))
579 return emitError(mutLoc,
"invalid global mutability specifier: ")
580 <<
static_cast<int>(*mutSpec);
581 return GlobalTypeRecord{*typeParsed, *mutSpec == WasmGlobalMut::isMutable};
584 FailureOr<TupleType> parseResultType(
MLIRContext *ctx) {
585 FailureOr<uint32_t> nParamsParsed = parseVectorSize();
586 if (
failed(nParamsParsed))
588 uint32_t nParams = *nParamsParsed;
590 res.reserve(nParams);
591 for (
size_t i = 0; i < nParams; ++i) {
592 FailureOr<Type> parsedType = parseValueType(ctx);
595 res.push_back(*parsedType);
600 FailureOr<FunctionType> parseFunctionType(
MLIRContext *ctx) {
602 FailureOr<std::byte> funcTypeHeader = consumeByte();
603 if (
failed(funcTypeHeader))
606 return emitError(typeLoc,
"invalid function type header byte. Expecting ")
608 <<
" got " << std::to_integer<unsigned>(*funcTypeHeader);
609 FailureOr<TupleType> inputTypes = parseResultType(ctx);
613 FailureOr<TupleType> resTypes = parseResultType(ctx);
620 FailureOr<TypeIdxRecord> parseTypeIndex() {
621 FailureOr<uint32_t> res = parseUI32();
624 return TypeIdxRecord{*res};
627 FailureOr<TableType> parseTableType(
MLIRContext *ctx) {
628 FailureOr<Type> elmTypeParse = parseValueType(ctx);
631 if (!isWasmRefType(*elmTypeParse))
632 return emitError(getLocation(),
"invalid element type for table");
633 FailureOr<LimitType> limitParse = parseLimit(ctx);
639 FailureOr<ImportDesc> parseImportDesc(
MLIRContext *ctx) {
641 FailureOr<std::byte> importType = consumeByte();
642 auto packager = [](
auto parseResult) -> FailureOr<ImportDesc> {
645 return {*parseResult};
649 switch (*importType) {
651 return packager(parseTypeIndex());
653 return packager(parseTableType(ctx));
655 return packager(parseLimit(ctx));
657 return packager(parseGlobalType(ctx));
659 return emitError(importLoc,
"invalid import type descriptor: ")
660 <<
static_cast<int>(*importType);
664 parsed_inst_t parseExpression(
OpBuilder &builder,
665 WasmModuleSymbolTables
const &symbols,
667 auto eParser = ExpressionParser{*
this, symbols, locals};
668 return eParser.parse(builder);
671 LogicalResult parseCodeFor(FuncOp func,
672 WasmModuleSymbolTables
const &symbols) {
677 assert(func.getBody().getBlocks().size() == 1 &&
678 "Function should only have its default created block at this point");
680 "Only the placeholder return op should be present at this point");
681 auto returnOp = cast<ReturnOp>(&block.
back());
684 FailureOr<uint32_t> codeSizeInBytes = parseUI32();
685 if (
failed(codeSizeInBytes))
687 FailureOr<StringRef> codeContent = consumeNBytes(*codeSizeInBytes);
691 locName.str() +
"::" + func.getSymName());
692 auto cParser = ParserHead{*codeContent, name};
693 FailureOr<uint32_t> localVecSize = cParser.parseVectorSize();
696 OpBuilder builder{&func.getBody().front().back()};
700 uint32_t nVarVec = *localVecSize;
701 for (
size_t i = 0; i < nVarVec; ++i) {
703 FailureOr<uint32_t> nSubVar = cParser.parseUI32();
706 FailureOr<Type> varT = cParser.parseValueType(func->getContext());
709 for (
size_t j = 0;
j < *nSubVar; ++
j) {
710 auto local = LocalOp::create(builder, varLoc, *varT);
711 locals.push_back(local.getResult());
714 parsed_inst_t res = cParser.parseExpression(builder, symbols, locals);
719 "unparsed garbage remaining at end of code block");
720 ReturnOp::create(builder, func->getLoc(), *res);
725 llvm::FailureOr<BlockTypeParseResult> parseBlockType(
MLIRContext *ctx) {
726 auto loc = getLocation();
727 auto blockIndicator = peek();
728 if (
failed(blockIndicator))
732 return {EmptyBlockMarker{}};
734 if (isValueOneOf(*blockIndicator, valueTypesEncodings))
735 return parseValueType(ctx);
738 auto typeIdx = parseI64();
742 return emitError(loc,
"type ID should be representable with an unsigned "
743 "32 bits integer. Got ")
745 return {TypeIdxRecord{
static_cast<uint32_t
>(*typeIdx)}};
748 bool end()
const {
return curHead().empty(); }
750 ParserHead
copy()
const {
return *
this; }
753 StringRef curHead()
const {
return head.drop_front(offset); }
755 FailureOr<std::byte> peek()
const {
759 "trying to peek at next byte, but input stream is empty");
760 return static_cast<std::byte
>(curHead().front());
763 size_t size()
const {
return head.size() - offset; }
767 unsigned anchorOffset{0};
772 FailureOr<float> ParserHead::parseLiteral<float>() {
773 FailureOr<StringRef> bytes = consumeNBytes(4);
776 return llvm::support::endian::read<float>(bytes->bytes_begin(),
777 llvm::endianness::little);
781 FailureOr<double> ParserHead::parseLiteral<double>() {
782 FailureOr<StringRef> bytes = consumeNBytes(8);
785 return llvm::support::endian::read<double>(bytes->bytes_begin(),
786 llvm::endianness::little);
790 FailureOr<uint32_t> ParserHead::parseLiteral<uint32_t>() {
791 char const *error =
nullptr;
793 unsigned encodingSize{0};
794 StringRef src = curHead();
795 uint64_t decoded = llvm::decodeULEB128(src.bytes_begin(), &encodingSize,
796 src.bytes_end(), &error);
801 return emitError(getLocation()) <<
"literal does not fit on 32 bits";
803 res =
static_cast<uint32_t
>(decoded);
804 offset += encodingSize;
809 FailureOr<int32_t> ParserHead::parseLiteral<int32_t>() {
810 char const *error =
nullptr;
812 unsigned encodingSize{0};
813 StringRef src = curHead();
814 int64_t decoded = llvm::decodeSLEB128(src.bytes_begin(), &encodingSize,
815 src.bytes_end(), &error);
820 return emitError(getLocation()) <<
"literal does not fit on 32 bits";
822 res =
static_cast<int32_t
>(decoded);
823 offset += encodingSize;
828 FailureOr<int64_t> ParserHead::parseLiteral<int64_t>() {
829 char const *error =
nullptr;
830 unsigned encodingSize{0};
831 StringRef src = curHead();
832 int64_t res = llvm::decodeSLEB128(src.bytes_begin(), &encodingSize,
833 src.bytes_end(), &error);
837 offset += encodingSize;
841 FailureOr<uint32_t> ParserHead::parseVectorSize() {
842 return parseLiteral<uint32_t>();
845 inline FailureOr<uint32_t> ParserHead::parseUI32() {
846 return parseLiteral<uint32_t>();
849 inline FailureOr<int64_t> ParserHead::parseI64() {
850 return parseLiteral<int64_t>();
853 template <std::
byte opCode>
854 inline parsed_inst_t ExpressionParser::parseSpecificInstruction(
OpBuilder &) {
855 return emitError(*currentOpLoc,
"unknown instruction opcode: ")
856 <<
static_cast<int>(opCode);
859 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
860 void ValueStack::dump()
const {
861 llvm::dbgs() <<
"================= Wasm ValueStack =======================\n";
862 llvm::dbgs() <<
"size: " << size() <<
"\n";
863 llvm::dbgs() <<
"nbFrames: " << labelLevel.size() <<
'\n';
864 llvm::dbgs() <<
"<Top>"
869 auto indexGetter = [
this]() {
870 size_t idx = labelLevel.size();
871 return [
this, idx]()
mutable -> std::optional<std::pair<size_t, size_t>> {
872 llvm::dbgs() <<
"IDX: " << idx <<
'\n';
875 auto frameId = idx - 1;
876 auto frameLimit = labelLevel[frameId].stackIdx;
878 return {{frameId, frameLimit}};
881 auto getNextFrameIndex = indexGetter();
882 auto nextFrameIdx = getNextFrameIndex();
883 size_t stackSize = size();
884 for (
size_t idx = 0; idx < stackSize; ++idx) {
885 size_t actualIdx = stackSize - 1 - idx;
886 while (nextFrameIdx && (nextFrameIdx->second > actualIdx)) {
887 llvm::dbgs() <<
" --------------- Frame (" << nextFrameIdx->first
889 nextFrameIdx = getNextFrameIndex();
892 values[actualIdx].dump();
894 while (nextFrameIdx) {
895 llvm::dbgs() <<
" --------------- Frame (" << nextFrameIdx->first <<
")\n";
896 nextFrameIdx = getNextFrameIndex();
898 llvm::dbgs() <<
"<Bottom>"
900 llvm::dbgs() <<
"=========================================================\n";
905 LDBG() <<
"Popping from ValueStack\n"
906 <<
" Elements(s) to pop: " << operandTypes.size() <<
"\n"
907 <<
" Current stack size: " << values.size();
908 if (operandTypes.size() > values.size())
910 "stack doesn't contain enough values. trying to get ")
911 << operandTypes.size() <<
" operands on a stack containing only "
912 << values.size() <<
" values";
913 size_t stackIdxOffset = values.size() - operandTypes.size();
915 res.reserve(operandTypes.size());
916 for (
size_t i{0}; i < operandTypes.size(); ++i) {
917 Value operand = values[i + stackIdxOffset];
919 if (stackType != operandTypes[i])
920 return emitError(*opLoc,
"invalid operand type on stack. expecting ")
921 << operandTypes[i] <<
", value on stack is of type " << stackType;
922 LDBG() <<
" POP: " << operand;
923 res.push_back(operand);
925 values.resize(values.size() - operandTypes.size());
926 LDBG() <<
" Updated stack size: " << values.size();
931 LDBG() <<
"Pushing to ValueStack\n"
932 <<
" Elements(s) to push: " << results.size() <<
"\n"
933 <<
" Current stack size: " << values.size();
934 for (
Value val : results) {
935 if (!isWasmValueType(val.getType()))
936 return emitError(*opLoc,
"invalid value type on stack: ")
938 LDBG() <<
" PUSH: " << val;
939 values.push_back(val);
942 LDBG() <<
" Updated stack size: " << values.size();
946 template <std::
byte EndParseByte>
948 UniqueByte<EndParseByte> endByte) {
949 auto res =
parse(builder, ByteSequence<EndParseByte>{});
952 return res->opResults;
955 template <std::byte... ExpressionParseEnd>
956 FailureOr<ExpressionParser::ParseResultWithInfo>
958 ByteSequence<ExpressionParseEnd...> parsingEndFilters) {
961 currentOpLoc = parser.getLocation();
962 FailureOr<std::byte> opCode = parser.consumeByte();
965 if (isValueOneOf(*opCode, parsingEndFilters))
966 return {{res, *opCode}};
967 parsed_inst_t resParsed;
968 resParsed = dispatchToInstParser(*opCode, builder);
971 std::swap(res, *resParsed);
972 if (
failed(pushResults(res)))
977 llvm::FailureOr<FunctionType>
978 ExpressionParser::parseBlockFuncType(
OpBuilder &builder) {
979 return getFuncTypeFor(builder, parser.parseBlockType(builder.
getContext()));
982 template <
typename OpToCreate>
983 parsed_inst_t ExpressionParser::parseBlockLikeOp(
OpBuilder &builder) {
984 auto opLoc = currentOpLoc;
985 auto funcType = parseBlockFuncType(builder);
989 auto inputTypes = funcType->getInputs();
990 auto inputOps = popOperands(inputTypes);
996 auto resTypes = funcType->getResults();
998 locations.resize(resTypes.size(), *currentOpLoc);
1000 builder.
createBlock(curRegion, curRegion->
end(), resTypes, locations);
1003 OpToCreate::create(builder, *currentOpLoc, *inputOps, successor);
1004 auto *blockBody = blockOp.createBlock();
1005 if (
failed(parseBlockContent(builder, blockBody, resTypes, *opLoc, blockOp)))
1008 return {
ValueRange{successor->getArguments()}};
1012 inline parsed_inst_t
1013 ExpressionParser::parseSpecificInstruction<WasmBinaryEncoding::OpCode::block>(
1015 return parseBlockLikeOp<BlockOp>(builder);
1019 inline parsed_inst_t
1020 ExpressionParser::parseSpecificInstruction<WasmBinaryEncoding::OpCode::loop>(
1022 return parseBlockLikeOp<LoopOp>(builder);
1026 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1028 auto opLoc = currentOpLoc;
1029 auto funcType = parseBlockFuncType(builder);
1033 LDBG() <<
"Parsing an if instruction of type " << *funcType;
1034 auto inputTypes = funcType->getInputs();
1035 auto conditionValue = popOperands(builder.
getI32Type());
1036 if (
failed(conditionValue))
1038 auto inputOps = popOperands(inputTypes);
1044 auto resTypes = funcType->getResults();
1046 locations.resize(resTypes.size(), *currentOpLoc);
1048 builder.
createBlock(curRegion, curRegion->
end(), resTypes, locations);
1050 auto ifOp = IfOp::create(builder, *currentOpLoc, conditionValue->front(),
1051 *inputOps, successor);
1052 auto *ifEntryBlock = ifOp.createIfBlock();
1053 constexpr
auto ifElseFilter =
1056 auto parseIfRes = parseBlockContent(builder, ifEntryBlock, resTypes, *opLoc,
1057 ifOp, ifElseFilter);
1061 LDBG() <<
" else block is present.";
1062 Block *elseEntryBlock = ifOp.createElseBlock();
1064 parseBlockContent(builder, elseEntryBlock, resTypes, *opLoc, ifOp);
1065 if (
failed(parseElseRes))
1069 return {
ValueRange{successor->getArguments()}};
1073 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1075 auto level = parser.parseLiteral<uint32_t>();
1082 auto condition = popOperands(builder.
getI32Type());
1087 LabelBranchingOpInterface::getTargetOpFromBlock(curBlock, *level);
1090 auto inputTypes = targetOp->getLabelTarget()->getArgumentTypes();
1091 auto branchArgs = popOperands(inputTypes);
1094 BranchIfOp::create(builder, *currentOpLoc, condition->front(),
1098 return {*branchArgs};
1102 inline parsed_inst_t
1103 ExpressionParser::parseSpecificInstruction<WasmBinaryEncoding::OpCode::call>(
1105 auto loc = *currentOpLoc;
1106 auto funcIdx = parser.parseLiteral<uint32_t>();
1109 if (*funcIdx >= symbols.funcSymbols.size())
1110 return emitError(loc,
"Invalid function index: ") << *funcIdx;
1111 auto callee = symbols.funcSymbols[*funcIdx];
1114 parsed_inst_t inOperands = popOperands(inTypes);
1118 FuncCallOp::create(builder, loc, resTypes, callee.symbol, *inOperands);
1119 return {callOp.getResults()};
1123 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1125 FailureOr<uint32_t>
id = parser.parseLiteral<uint32_t>();
1129 if (*
id >= locals.size())
1130 return emitError(instLoc,
"invalid local index. function has ")
1131 << locals.size() <<
" accessible locals, received index " << *id;
1132 return {{LocalGetOp::create(builder, instLoc, locals[*
id]).getResult()}};
1136 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1138 FailureOr<uint32_t>
id = parser.parseLiteral<uint32_t>();
1142 if (*
id >= symbols.globalSymbols.size())
1143 return emitError(instLoc,
"invalid global index. function has ")
1144 << symbols.globalSymbols.size()
1145 <<
" accessible globals, received index " << *id;
1146 GlobalSymbolRefContainer globalVar = symbols.globalSymbols[*id];
1147 auto globalOp = GlobalGetOp::create(builder, instLoc, globalVar.globalType,
1150 return {{globalOp.getResult()}};
1153 template <
typename OpToCreate>
1154 parsed_inst_t ExpressionParser::parseSetOrTee(
OpBuilder &builder) {
1155 FailureOr<uint32_t>
id = parser.parseLiteral<uint32_t>();
1158 if (*
id >= locals.size())
1159 return emitError(*currentOpLoc,
"invalid local index. function has ")
1160 << locals.size() <<
" accessible locals, received index " << *id;
1161 if (valueStack.empty())
1164 "invalid stack access, trying to access a value on an empty stack");
1170 OpToCreate::create(builder, *currentOpLoc, locals[*
id], poppedOp->front())
1175 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1177 return parseSetOrTee<LocalSetOp>(builder);
1181 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1183 return parseSetOrTee<LocalTeeOp>(builder);
1186 template <
typename T>
1200 [[maybe_unused]]
inline Type buildLiteralType<uint32_t>(
OpBuilder &builder) {
1205 [[maybe_unused]]
inline Type buildLiteralType<uint64_t>(
OpBuilder &builder) {
1219 template <
typename ValT,
1220 typename E = std::enable_if_t<std::is_arithmetic_v<ValT>>>
1223 template <
typename ValT>
1224 struct AttrHolder<ValT, std::enable_if_t<std::is_integral_v<ValT>>> {
1225 using type = IntegerAttr;
1228 template <
typename ValT>
1229 struct AttrHolder<ValT, std::enable_if_t<std::is_floating_point_v<ValT>>> {
1230 using type = FloatAttr;
1233 template <
typename ValT>
1234 using attr_holder_t =
typename AttrHolder<ValT>::type;
1236 template <
typename ValT,
1237 typename EnableT = std::enable_if_t<std::is_arithmetic_v<ValT>>>
1238 attr_holder_t<ValT> buildLiteralAttr(
OpBuilder &builder, ValT val) {
1242 template <
typename valueT>
1243 parsed_inst_t ExpressionParser::parseConstInst(
1244 OpBuilder &builder, std::enable_if_t<std::is_arithmetic_v<valueT>> *) {
1245 auto parsedConstant = parser.parseLiteral<valueT>();
1246 if (
failed(parsedConstant))
1249 ConstOp::create(builder, *currentOpLoc,
1250 buildLiteralAttr<valueT>(builder, *parsedConstant));
1251 return {{constOp.getResult()}};
1255 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1257 return parseConstInst<int32_t>(builder);
1261 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1263 return parseConstInst<int64_t>(builder);
1267 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1269 return parseConstInst<float>(builder);
1273 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1275 return parseConstInst<double>(builder);
1278 template <
typename opcode,
typename valueType,
unsigned int numOperands>
1279 inline parsed_inst_t ExpressionParser::buildNumericOp(
1280 OpBuilder &builder, std::enable_if_t<std::is_arithmetic_v<valueType>> *) {
1281 auto ty = buildLiteralType<valueType>(builder);
1282 LDBG() <<
"*** buildNumericOp: numOperands = " << numOperands
1283 <<
", type = " << ty <<
" ***";
1285 tysToPop.resize(numOperands);
1286 llvm::fill(tysToPop, ty);
1287 auto operands = popOperands(tysToPop);
1290 auto op = opcode::create(builder, *currentOpLoc, *operands).getResult();
1291 LDBG() <<
"Built operation: " << op;
1296 #define BUILD_NUMERIC_OP(OP_NAME, N_ARGS, PREFIX, SUFFIX, TYPE) \
1298 inline parsed_inst_t ExpressionParser::parseSpecificInstruction< \
1299 WasmBinaryEncoding::OpCode::PREFIX##SUFFIX>(OpBuilder & builder) { \
1300 return buildNumericOp<OP_NAME, TYPE, N_ARGS>(builder); \
1304 #define BUILD_NUMERIC_BINOP_INT(OP_NAME, PREFIX) \
1305 BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, I32, int32_t) \
1306 BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, I64, int64_t)
1309 #define BUILD_NUMERIC_BINOP_FP(OP_NAME, PREFIX) \
1310 BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, F32, float) \
1311 BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, F64, double)
1314 #define BUILD_NUMERIC_BINOP_INTFP(OP_NAME, PREFIX) \
1315 BUILD_NUMERIC_BINOP_INT(OP_NAME, PREFIX) \
1316 BUILD_NUMERIC_BINOP_FP(OP_NAME, PREFIX)
1319 #define BUILD_NUMERIC_UNARY_OP_INT(OP_NAME, PREFIX) \
1320 BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, I32, int32_t) \
1321 BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, I64, int64_t)
1324 #define BUILD_NUMERIC_UNARY_OP_FP(OP_NAME, PREFIX) \
1325 BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, F32, float) \
1326 BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, F64, double)
1373 #undef BUILD_NUMERIC_BINOP_FP
1374 #undef BUILD_NUMERIC_BINOP_INT
1375 #undef BUILD_NUMERIC_BINOP_INTFP
1376 #undef BUILD_NUMERIC_UNARY_OP_FP
1377 #undef BUILD_NUMERIC_UNARY_OP_INT
1378 #undef BUILD_NUMERIC_OP
1379 #undef BUILD_NUMERIC_CAST_OP
1381 template <
typename opType,
typename inputType,
typename outputType,
1382 typename... extraArgsT>
1383 inline parsed_inst_t ExpressionParser::buildConvertOp(
OpBuilder &builder,
1384 extraArgsT... extraArgs) {
1385 static_assert(std::is_arithmetic_v<inputType>,
1386 "InputType should be an arithmetic type");
1387 static_assert(std::is_arithmetic_v<outputType>,
1388 "OutputType should be an arithmetic type");
1389 auto intype = buildLiteralType<inputType>(builder);
1390 auto outType = buildLiteralType<outputType>(builder);
1391 auto operand = popOperands(intype);
1394 auto op = opType::create(builder, *currentOpLoc, outType, operand->front(),
1396 LDBG() <<
"Built operation: " << op;
1397 return {{op.getResult()}};
1401 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1403 return buildConvertOp<DemoteOp, double, float>(builder);
1407 inline parsed_inst_t
1408 ExpressionParser::parseSpecificInstruction<WasmBinaryEncoding::OpCode::wrap>(
1410 return buildConvertOp<WrapOp, int64_t, int32_t>(builder);
1413 #define BUILD_CONVERSION_OP(IN_T, OUT_T, SOURCE_OP, TARGET_OP) \
1415 inline parsed_inst_t ExpressionParser::parseSpecificInstruction< \
1416 WasmBinaryEncoding::OpCode::SOURCE_OP>(OpBuilder & builder) { \
1417 return buildConvertOp<TARGET_OP, IN_T, OUT_T>(builder); \
1420 #define BUILD_CONVERT_OP_FOR(DEST_T, WIDTH) \
1421 BUILD_CONVERSION_OP(uint32_t, DEST_T, convertUI32F##WIDTH, ConvertUOp) \
1422 BUILD_CONVERSION_OP(int32_t, DEST_T, convertSI32F##WIDTH, ConvertSOp) \
1423 BUILD_CONVERSION_OP(uint64_t, DEST_T, convertUI64F##WIDTH, ConvertUOp) \
1424 BUILD_CONVERSION_OP(int64_t, DEST_T, convertSI64F##WIDTH, ConvertSOp)
1429 #undef BUILD_CONVERT_OP_FOR
1434 #undef BUILD_CONVERSION_OP
1436 #define BUILD_SLICE_EXTEND_PARSER(IT_WIDTH, EXTRACT_WIDTH) \
1438 parsed_inst_t ExpressionParser::parseSpecificInstruction< \
1439 WasmBinaryEncoding::OpCode::extendI##IT_WIDTH##EXTRACT_WIDTH##S>( \
1440 OpBuilder & builder) { \
1441 using inout_t = int##IT_WIDTH##_t; \
1442 auto attr = builder.getUI32IntegerAttr(EXTRACT_WIDTH); \
1443 return buildConvertOp<ExtendLowBitsSOp, inout_t, inout_t>(builder, attr); \
1452 #undef BUILD_SLICE_EXTEND_PARSER
1455 inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
1457 return buildConvertOp<PromoteOp, float, double>(builder);
1460 #define BUILD_REINTERPRET_PARSER(WIDTH, FP_TYPE) \
1462 inline parsed_inst_t ExpressionParser::parseSpecificInstruction< \
1463 WasmBinaryEncoding::OpCode::reinterpretF##WIDTH##AsI##WIDTH>(OpBuilder & \
1465 return buildConvertOp<ReinterpretOp, FP_TYPE, int##WIDTH##_t>(builder); \
1469 inline parsed_inst_t ExpressionParser::parseSpecificInstruction< \
1470 WasmBinaryEncoding::OpCode::reinterpretI##WIDTH##AsF##WIDTH>(OpBuilder & \
1472 return buildConvertOp<ReinterpretOp, int##WIDTH##_t, FP_TYPE>(builder); \
1478 #undef BUILD_REINTERPRET_PARSER
1480 class WasmBinaryParser {
1482 struct SectionRegistry {
1483 using section_location_t = StringRef;
1485 std::array<SmallVector<section_location_t>, highestWasmSectionID + 1>
1488 template <WasmSectionType SecType>
1489 std::conditional_t<sectionShouldBeUnique(SecType),
1490 std::optional<section_location_t>,
1492 getContentForSection()
const {
1493 constexpr
auto idx =
static_cast<size_t>(SecType);
1494 if constexpr (sectionShouldBeUnique(SecType)) {
1495 return registry[idx].empty() ? std::nullopt
1496 : std::make_optional(registry[idx][0]);
1498 return registry[idx];
1502 bool hasSection(WasmSectionType secType)
const {
1503 return !registry[
static_cast<size_t>(secType)].empty();
1511 LogicalResult registerSection(WasmSectionType secType,
1512 section_location_t location,
Location loc) {
1513 if (sectionShouldBeUnique(secType) && hasSection(secType))
1515 "trying to add a second instance of unique section");
1517 registry[
static_cast<size_t>(secType)].push_back(location);
1518 emitRemark(loc,
"Adding section with section ID ")
1519 <<
static_cast<uint8_t
>(secType);
1523 LogicalResult populateFromBody(ParserHead ph) {
1526 FailureOr<WasmSectionType> secType = ph.parseWasmSectionType();
1530 FailureOr<uint32_t> secSizeParsed = ph.parseLiteral<uint32_t>();
1531 if (
failed(secSizeParsed))
1534 uint32_t secSize = *secSizeParsed;
1535 FailureOr<StringRef> sectionContent = ph.consumeNBytes(secSize);
1536 if (
failed(sectionContent))
1539 LogicalResult registration =
1540 registerSection(*secType, *sectionContent, sectionLoc);
1542 if (
failed(registration))
1549 auto getLocation(
int offset = 0)
const {
1553 template <WasmSectionType>
1554 LogicalResult parseSectionItem(ParserHead &,
size_t);
1556 template <WasmSectionType section>
1557 LogicalResult parseSection() {
1558 auto secName = std::string{wasmSectionName<section>};
1559 auto sectionNameAttr =
1561 unsigned offset = 0;
1562 auto getLocation = [sectionNameAttr, &offset]() {
1565 auto secContent = registry.getContentForSection<section>();
1567 LDBG() << secName <<
" section is not present in file.";
1571 auto secSrc = secContent.value();
1572 ParserHead ph{secSrc, sectionNameAttr};
1573 FailureOr<uint32_t> nElemsParsed = ph.parseVectorSize();
1574 if (
failed(nElemsParsed))
1576 uint32_t nElems = *nElemsParsed;
1577 LDBG() <<
"starting to parse " << nElems <<
" items for section "
1579 for (
size_t i = 0; i < nElems; ++i) {
1580 if (
failed(parseSectionItem<section>(ph, i)))
1585 return emitError(getLocation(),
"unparsed garbage at end of section ")
1591 LogicalResult visitImport(
Location loc, StringRef moduleName,
1592 StringRef importName, TypeIdxRecord tid) {
1594 if (tid.id >= symbols.moduleFuncTypes.size())
1595 return emitError(loc,
"invalid type id: ")
1596 << tid.id <<
". Only " << symbols.moduleFuncTypes.size()
1597 <<
" type registrations";
1598 FunctionType type = symbols.moduleFuncTypes[tid.id];
1599 std::string symbol = symbols.getNewFuncSymbolName();
1600 auto funcOp = FuncImportOp::create(builder, loc, symbol, moduleName,
1603 return funcOp.verify();
1607 LogicalResult visitImport(
Location loc, StringRef moduleName,
1608 StringRef importName, LimitType limitType) {
1609 std::string symbol = symbols.getNewMemorySymbolName();
1610 auto memOp = MemImportOp::create(builder, loc, symbol, moduleName,
1611 importName, limitType);
1613 return memOp.verify();
1617 LogicalResult visitImport(
Location loc, StringRef moduleName,
1618 StringRef importName, TableType tableType) {
1619 std::string symbol = symbols.getNewTableSymbolName();
1620 auto tableOp = TableImportOp::create(builder, loc, symbol, moduleName,
1621 importName, tableType);
1623 return tableOp.verify();
1627 LogicalResult visitImport(
Location loc, StringRef moduleName,
1628 StringRef importName, GlobalTypeRecord globalType) {
1629 std::string symbol = symbols.getNewGlobalSymbolName();
1631 GlobalImportOp::create(builder, loc, symbol, moduleName, importName,
1632 globalType.type, globalType.isMutable);
1633 symbols.globalSymbols.push_back(
1635 return giOp.verify();
1646 WasmBinaryParser(llvm::SourceMgr &sourceMgr,
MLIRContext *ctx)
1647 : builder{ctx}, ctx{ctx} {
1651 if (sourceMgr.getNumBuffers() != 1) {
1655 uint32_t sourceBufId = sourceMgr.getMainFileID();
1656 StringRef source = sourceMgr.getMemoryBuffer(sourceBufId)->getBuffer();
1658 ctx, sourceMgr.getMemoryBuffer(sourceBufId)->getBufferIdentifier());
1660 auto parser = ParserHead{source, srcName};
1661 auto const wasmHeader = StringRef{
"\0asm", 4};
1663 FailureOr<StringRef> magic = parser.consumeNBytes(wasmHeader.size());
1664 if (
failed(magic) || magic->compare(wasmHeader)) {
1665 emitError(magicLoc,
"source file does not contain valid Wasm header");
1668 auto const expectedVersionString = StringRef{
"\1\0\0\0", 4};
1670 FailureOr<StringRef> version =
1671 parser.consumeNBytes(expectedVersionString.size());
1674 if (version->compare(expectedVersionString)) {
1676 "unsupported Wasm version. only version 1 is supported");
1679 LogicalResult fillRegistry = registry.populateFromBody(parser.copy());
1680 if (
failed(fillRegistry))
1683 mOp = ModuleOp::create(builder, getLocation());
1685 LogicalResult parsingTypes = parseSection<WasmSectionType::TYPE>();
1686 if (
failed(parsingTypes))
1689 LogicalResult parsingImports = parseSection<WasmSectionType::IMPORT>();
1690 if (
failed(parsingImports))
1693 firstInternalFuncID = symbols.funcSymbols.size();
1695 LogicalResult parsingFunctions = parseSection<WasmSectionType::FUNCTION>();
1696 if (
failed(parsingFunctions))
1699 LogicalResult parsingTables = parseSection<WasmSectionType::TABLE>();
1700 if (
failed(parsingTables))
1703 LogicalResult parsingMems = parseSection<WasmSectionType::MEMORY>();
1707 LogicalResult parsingGlobals = parseSection<WasmSectionType::GLOBAL>();
1708 if (
failed(parsingGlobals))
1711 LogicalResult parsingCode = parseSection<WasmSectionType::CODE>();
1715 LogicalResult parsingExports = parseSection<WasmSectionType::EXPORT>();
1716 if (
failed(parsingExports))
1720 LDBG() <<
"WASM Imports:"
1722 <<
" - Num functions: " << symbols.funcSymbols.size() <<
"\n"
1723 <<
" - Num globals: " << symbols.globalSymbols.size() <<
"\n"
1724 <<
" - Num memories: " << symbols.memSymbols.size() <<
"\n"
1725 <<
" - Num tables: " << symbols.tableSymbols.size();
1728 ModuleOp getModule() {
1737 mlir::StringAttr srcName;
1739 WasmModuleSymbolTables symbols;
1742 SectionRegistry registry;
1743 size_t firstInternalFuncID{0};
1749 WasmBinaryParser::parseSectionItem<WasmSectionType::IMPORT>(ParserHead &ph,
1752 auto moduleName = ph.parseName();
1756 auto importName = ph.parseName();
1760 FailureOr<ImportDesc>
import = ph.parseImportDesc(ctx);
1765 [
this, importLoc, &moduleName, &importName](
auto import) {
1766 return visitImport(importLoc, *moduleName, *importName,
import);
1773 WasmBinaryParser::parseSectionItem<WasmSectionType::EXPORT>(ParserHead &ph,
1777 auto exportName = ph.parseName();
1781 FailureOr<std::byte> opcode = ph.consumeByte();
1785 FailureOr<uint32_t> idx = ph.parseLiteral<uint32_t>();
1789 using SymbolRefDesc = std::variant<SmallVector<SymbolRefContainer>,
1793 SymbolRefDesc currentSymbolList;
1794 std::string symbolType =
"";
1797 symbolType =
"function";
1798 currentSymbolList = symbols.funcSymbols;
1801 symbolType =
"table";
1802 currentSymbolList = symbols.tableSymbols;
1805 symbolType =
"memory";
1806 currentSymbolList = symbols.memSymbols;
1809 symbolType =
"global";
1810 currentSymbolList = symbols.globalSymbols;
1813 return emitError(exportLoc,
"invalid value for export type: ")
1814 << std::to_integer<unsigned>(*opcode);
1818 [&](
const auto &list) -> FailureOr<FlatSymbolRefAttr> {
1819 if (*idx > list.size()) {
1823 "trying to export {0} {1} which is undefined in this scope",
1827 return list[*idx].symbol;
1831 if (
failed(currentSymbol))
1842 WasmBinaryParser::parseSectionItem<WasmSectionType::TABLE>(ParserHead &ph,
1845 FailureOr<TableType> tableType = ph.parseTableType(ctx);
1848 LDBG() <<
" Parsed table description: " << *tableType;
1849 StringAttr symbol = builder.
getStringAttr(symbols.getNewTableSymbolName());
1851 TableOp::create(builder, opLocation, symbol.strref(), *tableType);
1858 WasmBinaryParser::parseSectionItem<WasmSectionType::FUNCTION>(ParserHead &ph,
1861 auto typeIdxParsed = ph.parseLiteral<uint32_t>();
1862 if (
failed(typeIdxParsed))
1864 uint32_t typeIdx = *typeIdxParsed;
1865 if (typeIdx >= symbols.moduleFuncTypes.size())
1866 return emitError(getLocation(),
"invalid type index: ") << typeIdx;
1867 std::string symbol = symbols.getNewFuncSymbolName();
1869 FuncOp::create(builder, opLoc, symbol, symbols.moduleFuncTypes[typeIdx]);
1870 Block *block = funcOp.addEntryBlock();
1873 ReturnOp::create(builder, opLoc);
1874 symbols.funcSymbols.push_back(
1876 symbols.moduleFuncTypes[typeIdx]});
1877 return funcOp.verify();
1882 WasmBinaryParser::parseSectionItem<WasmSectionType::TYPE>(ParserHead &ph,
1884 FailureOr<FunctionType> funcType = ph.parseFunctionType(ctx);
1887 LDBG() <<
"Parsed function type " << *funcType;
1888 symbols.moduleFuncTypes.push_back(*funcType);
1894 WasmBinaryParser::parseSectionItem<WasmSectionType::MEMORY>(ParserHead &ph,
1897 FailureOr<LimitType> memory = ph.parseLimit(ctx);
1901 LDBG() <<
" Registering memory " << *memory;
1902 std::string symbol = symbols.getNewMemorySymbolName();
1903 auto memOp = MemOp::create(builder, opLocation, symbol, *memory);
1910 WasmBinaryParser::parseSectionItem<WasmSectionType::GLOBAL>(ParserHead &ph,
1913 auto globalTypeParsed = ph.parseGlobalType(ctx);
1914 if (
failed(globalTypeParsed))
1917 GlobalTypeRecord globalType = *globalTypeParsed;
1918 auto symbol = builder.
getStringAttr(symbols.getNewGlobalSymbolName());
1919 auto globalOp = wasmssa::GlobalOp::create(
1920 builder, globalLocation, symbol, globalType.type, globalType.isMutable);
1921 symbols.globalSymbols.push_back(
1926 parsed_inst_t expr = ph.parseExpression(builder, symbols);
1930 return emitError(globalLocation,
"global with empty initializer");
1931 if (expr->size() != 1 && (*expr)[0].getType() != globalType.type)
1934 "initializer result type does not match global declaration type");
1935 ReturnOp::create(builder, globalLocation, *expr);
1940 LogicalResult WasmBinaryParser::parseSectionItem<WasmSectionType::CODE>(
1941 ParserHead &ph,
size_t innerFunctionId) {
1942 unsigned long funcId = innerFunctionId + firstInternalFuncID;
1943 FunctionSymbolRefContainer symRef = symbols.funcSymbols[funcId];
1947 if (
failed(ph.parseCodeFor(funcOp, symbols)))
1956 WasmBinaryParser wBN{source, context};
1957 ModuleOp mOp = wBN.getModule();
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static Type getElementType(Type type)
Determine the element type of type.
static std::string diag(const llvm::Value &value)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
#define BUILD_NUMERIC_BINOP_INTFP(OP_NAME, PREFIX)
#define BUILD_CONVERT_OP_FOR(DEST_T, WIDTH)
#define APPLY_WASM_SEC_TRANSFORM
#define BUILD_REINTERPRET_PARSER(WIDTH, FP_TYPE)
#define BUILD_CONVERSION_OP(IN_T, OUT_T, SOURCE_OP, TARGET_OP)
#define BUILD_SLICE_EXTEND_PARSER(IT_WIDTH, EXTRACT_WIDTH)
#define BUILD_NUMERIC_UNARY_OP_INT(OP_NAME, PREFIX)
#define BUILD_NUMERIC_BINOP_INT(OP_NAME, PREFIX)
#define BUILD_NUMERIC_BINOP_FP(OP_NAME, PREFIX)
#define BUILD_NUMERIC_UNARY_OP_FP(OP_NAME, PREFIX)
Block represents an ordered list of Operations.
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
BlockArgListType getArguments()
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
StringAttr getStringAttr(const Twine &bytes)
MLIRContext * getContext() const
IntegerAttr getUI32IntegerAttr(uint32_t value)
HandlerID registerHandler(HandlerTy handler)
Register a new handler for diagnostics to the engine.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
An instance of this location represents a tuple of file, line number, and column number.
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
A symbol reference with a reference path containing a single element.
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
void loadAllAvailableDialects()
Load all dialects available in the registry in this context.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
InsertPoint saveInsertionPoint() const
Return a saved insertion point.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
void restoreInsertionPoint(InsertPoint ip)
Restore the insert point to a previously saved point.
Block * getBlock() const
Returns the current block of the builder.
Operation is the basic unit of execution within MLIR.
MLIRContext * getContext()
Return the context this operation is associated with.
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
This class allows for representing and managing the symbol table used by operations with the 'SymbolT...
LogicalResult rename(StringAttr from, StringAttr to)
Renames the given op or the op refered to by the given name to the given new name and updates the sym...
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
static StringAttr getSymbolName(Operation *symbol)
Returns the name of the given symbol operation, aborting if no symbol is present.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
DynamicAPInt floor(const Fraction &f)
DynamicAPInt ceil(const Fraction &f)
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
OwningOpRef< ModuleOp > importWebAssemblyToModule(llvm::SourceMgr &source, MLIRContext *context)
If source contains a valid Wasm binary file, this function returns a a ModuleOp containing the repres...
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
static constexpr std::byte memory
static constexpr std::byte table
static constexpr std::byte global
static constexpr std::byte function
Byte encodings describing the mutability of globals.
static constexpr std::byte memType
static constexpr std::byte typeID
static constexpr std::byte tableType
static constexpr std::byte globalType
static constexpr std::byte globalGet
static constexpr std::byte elseOpCode
static constexpr std::byte promoteF32ToF64
static constexpr std::byte demoteF64ToF32
static constexpr std::byte constI64
static constexpr std::byte constFP64
static constexpr std::byte localTee
static constexpr std::byte ifOpCode
static constexpr std::byte localGet
static constexpr std::byte branchIf
static constexpr std::byte localSet
static constexpr std::byte constI32
static constexpr std::byte constFP32
static constexpr std::byte externRef
static constexpr std::byte i32
static constexpr std::byte funcType
static constexpr std::byte i64
static constexpr std::byte emptyBlockType
static constexpr std::byte funcRef
static constexpr std::byte v128
static constexpr std::byte f64
static constexpr std::byte f32
static constexpr std::byte endByte
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.