diff --git a/include/wabt/common.h b/include/wabt/common.h index e1411b4870..7d2b8472bf 100644 --- a/include/wabt/common.h +++ b/include/wabt/common.h @@ -186,6 +186,13 @@ void Destruct(T& placement) { placement.~T(); } +template +struct Overload: Fs... { + using Fs::operator()...; +}; +template +Overload(Fs...)->Overload; + enum class LabelType { Func, InitExpr, @@ -297,9 +304,165 @@ enum class RelocType { First = FuncIndexLEB, Last = FuncIndexI32, + None = -1, // Used internally as a sentinel value +}; + +enum class RelocDataType { + None, + I32, I64, + LEB, LEB64, + SLEB, SLEB64, +}; + +constexpr size_t kRelocDataTypeSize[] { + 0, + 4, 8, + 5, 10, + 5, 10 }; + +constexpr RelocDataType kRelocDataType[] { + RelocDataType::LEB, // FuncIndexLEB = 0 + RelocDataType::SLEB, // TableIndexSLEB = 1 + RelocDataType::I32, // TableIndexI32 = 2 + RelocDataType::LEB, // MemoryAddressLEB = 3 + RelocDataType::SLEB, // MemoryAddressSLEB = 4 + RelocDataType::I32, // MemoryAddressI32 = 5 + RelocDataType::LEB, // TypeIndexLEB = 6 + RelocDataType::LEB, // GlobalIndexLEB = 7 + RelocDataType::I32, // FunctionOffsetI32 = 8 + RelocDataType::I32, // SectionOffsetI32 = 9 + RelocDataType::LEB, // TagIndexLEB = 10 + RelocDataType::SLEB, // MemoryAddressRelSLEB = 11 + RelocDataType::SLEB, // TableIndexRelSLEB = 12 + RelocDataType::I32, // GlobalIndexI32 = 13 + RelocDataType::LEB64, // MemoryAddressLEB64 = 14 + RelocDataType::SLEB64, // MemoryAddressSLEB64 = 15 + RelocDataType::I64, // MemoryAddressI64 = 16 + RelocDataType::SLEB64, // MemoryAddressRelSLEB64 = 17 + RelocDataType::SLEB64, // TableIndexSLEB64 = 18 + RelocDataType::I64, // TableIndexI64 = 19 + RelocDataType::LEB, // TableNumberLEB = 20 + RelocDataType::SLEB, // MemoryAddressTLSSLEB = 21 + RelocDataType::I64, // FunctionOffsetI64 = 22 + RelocDataType::I32, // MemoryAddressLocRelI32 = 23 + RelocDataType::SLEB64, // TableIndexRelSLEB64 = 24 + RelocDataType::SLEB64, // MemoryAddressTLSSLEB64 = 25 + RelocDataType::I32, // FuncIndexI32 = 26 +}; + +enum class RelocKind { + None, + Function, + FunctionTbl, + Data, + Global, + Table, + Tag, + Type, + Section, + Text, +}; + +constexpr RelocKind kRelocSymbolType[] { + RelocKind::Function, // FuncIndexLEB = 0 + RelocKind::FunctionTbl, // TableIndexSLEB = 1 + RelocKind::FunctionTbl, // TableIndexI32 = 2 + RelocKind::Data, // MemoryAddressLEB = 3 + RelocKind::Data, // MemoryAddressSLEB = 4 + RelocKind::Data, // MemoryAddressI32 = 5 + RelocKind::Type, // TypeIndexLEB = 6 + RelocKind::Global, // GlobalIndexLEB = 7 + RelocKind::Text, // FunctionOffsetI32 = 8 + RelocKind::Section, // SectionOffsetI32 = 9 + RelocKind::Tag, // TagIndexLEB = 10 + RelocKind::Data, // MemoryAddressRelSLEB = 11 + RelocKind::Table, // TableIndexRelSLEB = 12 + RelocKind::Global, // GlobalIndexI32 = 13 + RelocKind::Data, // MemoryAddressLEB64 = 14 + RelocKind::Data, // MemoryAddressSLEB64 = 15 + RelocKind::Data, // MemoryAddressI64 = 16 + RelocKind::Data, // MemoryAddressRelSLEB64 = 17 + RelocKind::FunctionTbl, // TableIndexSLEB64 = 18 + RelocKind::FunctionTbl, // TableIndexI64 = 19 + RelocKind::Table, // TableNumberLEB = 20 + RelocKind::Data, // MemoryAddressTLSSLEB = 21 + RelocKind::Text, // FunctionOffsetI64 = 22 + RelocKind::Data, // MemoryAddressLocRelI32 = 23 + RelocKind::FunctionTbl, // TableIndexRelSLEB64 = 24 + RelocKind::Data, // MemoryAddressTLSSLEB64 = 25 + RelocKind::Function, // FuncIndexI32 = 26 +}; + +enum class RelocModifiers { + None = 0, + TLS = 1, + PIC = 2, +}; + +inline RelocModifiers operator|(RelocModifiers a, RelocModifiers b) { + using U = std::underlying_type_t; + return RelocModifiers(U(a) | U(b)); +} + +inline RelocModifiers operator&(RelocModifiers a, RelocModifiers b) { + using U = std::underlying_type_t; + return RelocModifiers(U(a) & U(b)); +} + +inline RelocModifiers operator~(RelocModifiers a) { + using U = std::underlying_type_t; + return RelocModifiers(~U(a)); +} + +constexpr RelocModifiers kRelocModifiers[] { + RelocModifiers::None, // FuncIndexLEB = 0 + RelocModifiers::None, // TableIndexSLEB = 1 + RelocModifiers::None, // TableIndexI32 = 2 + RelocModifiers::None, // MemoryAddressLEB = 3 + RelocModifiers::None, // MemoryAddressSLEB = 4 + RelocModifiers::None, // MemoryAddressI32 = 5 + RelocModifiers::None, // TypeIndexLEB = 6 + RelocModifiers::None, // GlobalIndexLEB = 7 + RelocModifiers::None, // FunctionOffsetI32 = 8 + RelocModifiers::None, // SectionOffsetI32 = 9 + RelocModifiers::None, // TagIndexLEB = 10 + RelocModifiers::PIC, // MemoryAddressRelSLEB = 11 + RelocModifiers::PIC, // TableIndexRelSLEB = 12 + RelocModifiers::None, // GlobalIndexI32 = 13 + RelocModifiers::None, // MemoryAddressLEB64 = 14 + RelocModifiers::None, // MemoryAddressSLEB64 = 15 + RelocModifiers::None, // MemoryAddressI64 = 16 + RelocModifiers::PIC, // MemoryAddressRelSLEB64 = 17 + RelocModifiers::None, // TableIndexSLEB64 = 18 + RelocModifiers::None, // TableIndexI64 = 19 + RelocModifiers::None, // TableNumberLEB = 20 + RelocModifiers::TLS, // MemoryAddressTLSSLEB = 21 + RelocModifiers::None, // FunctionOffsetI64 = 22 + RelocModifiers::PIC, // MemoryAddressLocRelI32 = 23 + RelocModifiers::PIC, // TableIndexRelSLEB64 = 24 + RelocModifiers::TLS, // MemoryAddressTLSSLEB64 = 25 + RelocModifiers::None, // FuncIndexI32 = 26 +}; + + constexpr int kRelocTypeCount = WABT_ENUM_COUNT(RelocType); +constexpr RelocType RecognizeReloc(RelocKind kind, + RelocDataType type, + RelocModifiers mod) { + for (int i = 0; i < kRelocTypeCount; ++i) { + if (kind != kRelocSymbolType[i]) + continue; + if (type != kRelocDataType[i]) + continue; + if (mod != kRelocModifiers[i]) + continue; + return RelocType(i); + } + return RelocType::None; +} + struct Reloc { Reloc(RelocType, size_t offset, Index index, int32_t addend = 0); diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 5fa4439a0c..01da26107c 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -21,11 +21,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "wabt/binding-hash.h" #include "wabt/common.h" @@ -203,6 +205,83 @@ struct Const { }; using ConstVector = std::vector; +struct IrReloc { + IrReloc(): type(RelocType::None) {} + IrReloc(RelocType type, Var symbol, int32_t addend = 0) + : type(type), symbol(symbol), addend(addend) { + static constexpr RelocType addend_allowed[] = { + RelocType::MemoryAddressI32, RelocType::MemoryAddressI64, + RelocType::MemoryAddressLEB, RelocType::MemoryAddressLEB64, + RelocType::MemoryAddressSLEB, RelocType::MemoryAddressSLEB64, + RelocType::MemoryAddressTLSSLEB, RelocType::MemoryAddressTLSSLEB64, + RelocType::MemoryAddressRelSLEB, RelocType::MemoryAddressRelSLEB64, + RelocType::MemoryAddressLocRelI32, RelocType::SectionOffsetI32, + RelocType::FunctionOffsetI32, RelocType::FunctionOffsetI64, + }; + if (addend) { + for (auto allowed_type: addend_allowed) + if (allowed_type == this->type) + return; + assert(!"Forbidden addend for relocation type"); + } + } + RelocType type; + Var symbol; + int32_t addend; +}; + +class SymbolCommon { +public: + std::string name_; + uint32_t flags_; + SymbolCommon(uint32_t flags = 0, std::string name = "") + : name_(name), flags_(flags) {} + const std::string& name() const { return name_; } + uint32_t flags() const { return flags_; } + + SymbolVisibility visibility() const { + return static_cast(flags() & WABT_SYMBOL_MASK_VISIBILITY); + } + SymbolBinding binding() const { + return static_cast(flags() & WABT_SYMBOL_MASK_BINDING); + } + bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; } + bool defined() const { return !undefined(); } + bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; } + bool explicit_name() const { + return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } + bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } + bool non_default(bool imported) const { + uint32_t flags = + flags_ & ~WABT_SYMBOL_FLAG_EXPORTED & ~WABT_SYMBOL_FLAG_UNDEFINED; + if (!undefined() && !exported() && name().empty()) + flags &= ~WABT_SYMBOL_MASK_BINDING & ~WABT_SYMBOL_MASK_VISIBILITY; + return flags != 0; + } +}; + +struct DataSym: SymbolCommon { + static DataSym MakeForSearch(Index segment, Index idx) { + return {{0}, "", segment, idx, 0}; + } + bool imported() const { + return segment == kInvalidIndex; + } + std::string name; + Index segment; + Address offset; + Address size; + bool operator<(const DataSym& other) const { + if (imported() && other.imported()) + return offset < other.offset; + if (!imported() && !other.imported()) + return std::tuple(segment, offset) < + std::tuple(other.segment, other.offset); + return !imported() < !other.imported(); + }; +}; + enum class ExpectationType { Values, Either, @@ -789,6 +868,7 @@ class ConstExpr : public ExprMixin { : ExprMixin(loc), const_(c) {} Const const_; + IrReloc reloc; }; // TODO(binji): Rename this, it is used for more than loads/stores now. @@ -808,6 +888,7 @@ class LoadStoreExpr : public MemoryExpr { Opcode opcode; Address align; Address offset; + IrReloc reloc; }; using LoadExpr = LoadStoreExpr; @@ -832,7 +913,7 @@ class AtomicFenceExpr : public ExprMixin { uint32_t consistency_model; }; -struct Tag { +struct Tag: SymbolCommon { explicit Tag(std::string_view name) : name(name) {} std::string name; @@ -900,7 +981,7 @@ inline bool operator!=(const LocalTypes::const_iterator& lhs, return !operator==(lhs, rhs); } -struct Func { +struct Func: SymbolCommon { explicit Func(std::string_view name) : name(name) {} Type GetParamType(Index index) const { return decl.GetParamType(index); } @@ -928,9 +1009,12 @@ struct Func { struct { bool tailcall = false; } features_used; + + // For relocatable binaries, if a function is an init function, its priority + std::optional priority = {}; }; -struct Global { +struct Global: SymbolCommon { explicit Global(std::string_view name) : name(name) {} std::string name; @@ -939,7 +1023,7 @@ struct Global { ExprList init_expr; }; -struct Table { +struct Table: SymbolCommon { explicit Table(std::string_view name) : name(name), elem_type(Type::FuncRef) {} @@ -979,6 +1063,17 @@ struct DataSegment { Var memory_var; ExprList offset; std::vector data; + std::vector> relocs; + std::pair symbol_range = {}; + struct SymInfo { + std::string name = ""; + Offset align = 0; + enum Flags: uint32_t { + WASM_SEGMENT_FLAG_STRINGS = 1, + WASM_SEGMENT_FLAG_TLS = 2, + WASM_SEG_FLAG_RETAIN = 4, + } flags = {}; + } sym; }; class Import { @@ -1211,6 +1306,191 @@ struct Custom { Location loc; }; +class Symbol: public SymbolCommon { + public: + struct Function { + static const SymbolType type = SymbolType::Function; + Index index; + }; + struct Data { + static const SymbolType type = SymbolType::Data; + Index index; + Offset offset; + Address size; + }; + struct Global { + static const SymbolType type = SymbolType::Global; + Index index; + }; + struct Section { + static const SymbolType type = SymbolType::Section; + Index section; + }; + struct Tag { + static const SymbolType type = SymbolType::Tag; + Index index; + }; + struct Table { + static const SymbolType type = SymbolType::Table; + Index index; + }; + + private: + SymbolType type_; + union { + Function function_; + Data data_; + Global global_; + Section section_; + Tag tag_; + Table table_; + }; + + public: + Symbol(const std::string& name, uint32_t flags, const Function& f) + : SymbolCommon{flags, name}, type_(Function::type), function_(f) {} + Symbol(const std::string& name, uint32_t flags, const Data& d) + : SymbolCommon{flags, name}, type_(Data::type), data_(d) {} + Symbol(const std::string& name, uint32_t flags, const Global& g) + : SymbolCommon{flags, name}, type_(Global::type), global_(g) {} + Symbol(const std::string& name, uint32_t flags, const Section& s) + : SymbolCommon{flags, name}, type_(Section::type), section_(s) {} + Symbol(const std::string& name, uint32_t flags, const Tag& e) + : SymbolCommon{flags, name}, type_(Tag::type), tag_(e) {} + Symbol(const std::string& name, uint32_t flags, const Table& t) + : SymbolCommon{flags, name}, type_(Table::type), table_(t) {} + + template + auto visit(F f) { + switch (type()) { + case Function::type: + return f(AsFunction()); + case Data::type: + return f(AsData()); + case Global::type: + return f(AsGlobal()); + case Section::type: + return f(AsSection()); + case Tag::type: + return f(AsTag()); + case Table::type: + return f(AsTable()); + } + } + + SymbolType type() const { return type_; } + + bool IsFunction() const { return type() == Function::type; } + bool IsData() const { return type() == Data::type; } + bool IsGlobal() const { return type() == Global::type; } + bool IsSection() const { return type() == Section::type; } + bool IsTag() const { return type() == Tag::type; } + bool IsTable() const { return type() == Table::type; } + + const Function& AsFunction() const { + assert(IsFunction()); + return function_; + } + const Data& AsData() const { + assert(IsData()); + return data_; + } + const Global& AsGlobal() const { + assert(IsGlobal()); + return global_; + } + const Section& AsSection() const { + assert(IsSection()); + return section_; + } + const Tag& AsTag() const { + assert(IsTag()); + return tag_; + } + const Table& AsTable() const { + assert(IsTable()); + return table_; + } +}; + +class SymbolTable { + std::vector symbols_; + + // Maps from wasm entities to symbol entry indices + std::vector functions_; + std::vector tables_; + std::vector globals_; + std::vector tags_; + std::vector datas_; + + std::set seen_names_; + + Result EnsureUnique(const std::string_view& name) { + if (seen_names_.count(name)) { + fprintf(stderr, + "error: duplicate symbol when writing relocatable " + "binary: %s\n", + &name[0]); + return Result::Error; + } + seen_names_.insert(name); + return Result::Ok; + }; + + template + std::vector& GetTable() = delete; + + template + auto GetTable() const + -> const decltype(std::declval().GetTable())& { + return const_cast(this)->GetTable(); + } + + public: + SymbolTable() {} + + Result Populate(const Module* module); + + Result AddSymbol(Symbol sym); + + std::vector& symbols() { return symbols_; } + const std::vector& symbols() const { return symbols_; } + + template + Index SymbolIndex(Index index) const { + // For well-formed modules, an index into (e.g.) functions_ will always be + // within bounds; the out-of-bounds case here is just to allow --relocatable + // to write known-invalid modules. + return index < GetTable().size() ? GetTable()[index] : kInvalidIndex; + } + + Index FunctionSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index TableSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index GlobalSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index TagSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index DataSymbolIndex(Index index) const { + return SymbolIndex(index); + } +}; +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); + struct Module { Index GetFuncTypeIndex(const Var&) const; Index GetFuncTypeIndex(const FuncDeclaration&) const; @@ -1238,6 +1518,8 @@ struct Module { const ElemSegment* GetElemSegment(const Var&) const; ElemSegment* GetElemSegment(const Var&); Index GetElemSegmentIndex(const Var&) const; + DataSym* GetDataSym(const Var&); + Index GetDataSymIndex(const Var&) const; bool IsImport(ExternalKind kind, const Var&) const; bool IsImport(const Export& export_) const { @@ -1268,6 +1550,7 @@ struct Module { Index num_table_imports = 0; Index num_memory_imports = 0; Index num_global_imports = 0; + Index num_data_imports = 0; // Cached for convenience; the pointers are shared with values that are // stored in either ModuleField or Import. @@ -1283,6 +1566,7 @@ struct Module { std::vector data_segments; std::vector starts; std::vector customs; + std::vector data_symbols; BindingHash tag_bindings; BindingHash func_bindings; @@ -1293,6 +1577,7 @@ struct Module { BindingHash memory_bindings; BindingHash data_segment_bindings; BindingHash elem_segment_bindings; + BindingHash data_symbol_bindings; // For a subset of features, the BinaryReaderIR tracks whether they are // actually used by the module. wasm2c (CWriter) uses this information to diff --git a/include/wabt/leb128.h b/include/wabt/leb128.h index e7290475b3..72571cf5c1 100644 --- a/include/wabt/leb128.h +++ b/include/wabt/leb128.h @@ -34,6 +34,8 @@ void WriteU64Leb128(Stream* stream, uint64_t value, const char* desc); void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc); void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc); void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc); +void WriteFixedS64Leb128(Stream* stream, uint64_t value, const char* desc); +void WriteFixedU64Leb128(Stream* stream, uint64_t value, const char* desc); Offset WriteU32Leb128At(Stream* stream, Offset offset, diff --git a/include/wabt/result.h b/include/wabt/result.h index a40faab78b..a425fd15f7 100644 --- a/include/wabt/result.h +++ b/include/wabt/result.h @@ -28,6 +28,7 @@ struct Result { Result() : Result(Ok) {} Result(Enum e) : enum_(e) {} operator Enum() const { return enum_; } + operator bool() const { return enum_ == Ok; } Result& operator|=(Result rhs); private: diff --git a/include/wabt/token.def b/include/wabt/token.def index f2f05aec34..39fb663eb7 100644 --- a/include/wabt/token.def +++ b/include/wabt/token.def @@ -21,6 +21,7 @@ /* Tokens with no additional data (i.e. bare). */ WABT_TOKEN(Invalid, "Invalid") WABT_TOKEN(After, "after") +WABT_TOKEN(Align, "align") WABT_TOKEN(Array, "array") WABT_TOKEN(AssertException, "assert_exception") WABT_TOKEN(AssertExhaustion, "assert_exhaustion") @@ -45,7 +46,9 @@ WABT_TOKEN(Field, "field") WABT_TOKEN(Function, "function") WABT_TOKEN(Get, "get") WABT_TOKEN(Global, "global") +WABT_TOKEN(Hidden, "hidden") WABT_TOKEN(Import, "import") +WABT_TOKEN(InitPrio, "init_prio") WABT_TOKEN(Invoke, "invoke") WABT_TOKEN(Input, "input") WABT_TOKEN(Local, "local") @@ -53,6 +56,7 @@ WABT_TOKEN(Lpar, "(") WABT_TOKEN(Memory, "memory") WABT_TOKEN(Module, "module") WABT_TOKEN(Mut, "mut") +WABT_TOKEN(Name, "name") WABT_TOKEN(NanArithmetic, "nan:arithmetic") WABT_TOKEN(NanCanonical, "nan:canonical") WABT_TOKEN(Offset, "offset") @@ -62,13 +66,17 @@ WABT_TOKEN(Param, "param") WABT_TOKEN(Ref, "ref") WABT_TOKEN(Quote, "quote") WABT_TOKEN(Register, "register") +WABT_TOKEN(Retain, "retain") WABT_TOKEN(Result, "result") WABT_TOKEN(Rpar, ")") WABT_TOKEN(Shared, "shared") +WABT_TOKEN(Size, "size") WABT_TOKEN(Start, "start") +WABT_TOKEN(Strings, "strings") WABT_TOKEN(Struct, "struct") WABT_TOKEN(Table, "table") WABT_TOKEN(Then, "then") +WABT_TOKEN(TLS, "tls") WABT_TOKEN(Type, "type") WABT_TOKEN(I8X16, "i8x16") WABT_TOKEN(I16X8, "i16x8") @@ -76,8 +84,9 @@ WABT_TOKEN(I32X4, "i32x4") WABT_TOKEN(I64X2, "i64x2") WABT_TOKEN(F32X4, "f32x4") WABT_TOKEN(F64X2, "f64x2") +WABT_TOKEN(Weak, "weak") WABT_TOKEN_FIRST(Bare, Invalid) -WABT_TOKEN_LAST(Bare, F64X2) +WABT_TOKEN_LAST(Bare, Weak) /* Tokens with Literal data. */ WABT_TOKEN(Float, "FLOAT") diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 7a60af23b5..5b6479b42b 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "wabt/error.h" #include "wabt/feature.h" @@ -64,6 +65,15 @@ class WastParser { Var var; }; + struct DatasymAux { + Var name; + Address size; + }; + struct FuncsymAux { + std::optional priority; + }; + using SymAux = std::variant; + typedef std::vector ReferenceVars; struct ResolveTypes { @@ -83,6 +93,9 @@ class WastParser { ReferenceVars vars; }; + static std::optional TryTrimPfx(std::string_view string, + std::string_view prefix); + void ErrorUnlessOpcodeEnabled(const Token&); // Print an error message listing the expected tokens, as well as an example @@ -132,6 +145,15 @@ class WastParser { // token is equal to the parameter. If so, then the token is consumed. bool MatchLpar(TokenType); + // Returns true if the next token's type is equal to the parameter, and if + // token's text matches parameter. If so, then the token is consumed. + bool MatchText(TokenType, std::string_view); + + // Returns true if the next token's type is equal to the parameter, and if + // token's text starts with parameter. If so, then the token is consumed and + // the rest of token's text is returned. + std::optional MatchTextPrefix(TokenType, std::string_view); + // Like Match(), but prints an error message if the token doesn't match, and // returns Result::Error. Result Expect(TokenType); @@ -196,7 +218,13 @@ class WastParser { Result ParseCustomSectionAnnotation(Module*); bool PeekIsCustom(); + bool PeekIsDataImport(); + std::optional ParseSymAttrString(TokenType tag); + std::optional ParseSymAttrNumber(TokenType tag); + Result ParseSymSegment(DataSegment::SymInfo*); + Result ParseSymOpt(SymbolCommon *, bool in_import, SymAux dat_sym = {}); + Result ParseDataImport(Module* module); Result ParseExportDesc(Export*); Result ParseInlineExports(ModuleFieldList*, ExternalKind); Result ParseInlineImport(Import*); @@ -216,6 +244,22 @@ class WastParser { Result ParseInstrList(ExprList*); Result ParseTerminatingInstrList(ExprList*); Result ParseInstr(ExprList*); + Result ParseRejectReloc(); + Result ParseUnwindReloc(int curr_indent); + Result ParseRelocAddend( + uint32_t* addend, + Var* name = nullptr); + Result ParseRelocModifiers(RelocModifiers*); + Result ParseRelocKind(RelocKind*); + Result ParseRelocDataType(RelocDataType*); + Result ParseReloc(bool opt, + IrReloc*, + RelocDataType = RelocDataType::None, + RelocKind = RelocKind::None, + Var* = nullptr, + bool data_default = false, + bool kind_default = false, + bool name_default = false); Result ParseCodeMetadataAnnotation(ExprList*); Result ParsePlainInstr(std::unique_ptr*); Result ParseF32(Const*, ConstType type); diff --git a/include/wabt/wat-writer.h b/include/wabt/wat-writer.h index 0f19ba2465..c10337adb0 100644 --- a/include/wabt/wat-writer.h +++ b/include/wabt/wat-writer.h @@ -32,6 +32,7 @@ struct WriteWatOptions { bool fold_exprs = false; // Write folded expressions. bool inline_export = false; bool inline_import = false; + bool relocatable = false; }; Result WriteWat(Stream*, const Module*, const WriteWatOptions&); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 11e88da549..b305e235c0 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -361,6 +361,23 @@ class BinaryReaderIR : public BinaryReaderNop { std::string_view name, Index table_index) override; + /* Relocation handling */ + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override; + Result BeginCodeSection(Offset size) override; + Result BeginDataSection(Offset size) override; + Result BeginGenericCustomSection(Offset size) override; + Result BeginElemSection(Offset size) override; + Result OnRelocCount(Index count, Index section_index) override; + Result EndRelocSection() override; + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override; + Result OnInitFunction(uint32_t priority, Index sym) override; + Result EndModule() override; + private: Location GetLocation() const; void PrintError(const char* format, ...); @@ -398,6 +415,44 @@ class BinaryReaderIR : public BinaryReaderNop { CodeMetadataExprQueue code_metadata_queue_; std::string_view current_metadata_name_; + + // Queue instructions to patch + struct RelocQueue { + enum Type { + CODE, + DATA, + CUSTOM, + }; + + RelocQueue(Offset start, Type type) + : start(start), type(type), incoming_relocs(), entries(), data_segment_starts() {} + + template + using Entries = std::tuple...>; + + template + decltype(auto) get() { + return std::get>(entries); + } + template + void traverse(F f) { + std::apply([&f](auto&&... vs) { (f(vs), ...); }, entries); + } + + Offset start; + Type type; + std::vector incoming_relocs; + Entries entries; + std::map data_segment_starts; + }; + std::unordered_map reloc_queues; + decltype(reloc_queues)::iterator active_reloc_section = end(reloc_queues); + SymbolTable table; + std::multiset data_symbols; + + Index active_section = kInvalidIndex; + void MakeQueue(RelocQueue::Type); + RelocQueue* GetQueue(); }; BinaryReaderIR::BinaryReaderIR(Module* out_module, @@ -467,6 +522,13 @@ Result BinaryReaderIR::TopLabelExpr(LabelNode** label, Expr** expr) { } Result BinaryReaderIR::AppendExpr(std::unique_ptr expr) { + if (RelocQueue* queue = GetQueue()) + queue->traverse([&](auto&& map) { + using Value = std::remove_reference_t; + if (auto* ce = dynamic_cast(expr.get())) { + map.insert({state->offset - queue->start, ce}); + } + }); expr->loc = GetLocation(); LabelNode* label; CHECK_RESULT(TopLabel(&label)); @@ -1480,6 +1542,7 @@ Result BinaryReaderIR::OnDataSegmentData(Index index, Address size) { assert(index == module_->data_segments.size() - 1); DataSegment* segment = module_->data_segments[index]; + GetQueue()->data_segment_starts.emplace(state->offset - size, segment); segment->data.resize(size); if (size > 0) { memcpy(segment->data.data(), data, size); @@ -1750,6 +1813,20 @@ Result BinaryReaderIR::OnDataSymbol(Index index, Index segment, uint32_t offset, uint32_t size) { + bool undef = flags & WABT_SYMBOL_FLAG_UNDEFINED; + if (undef) + ++module_->num_data_imports; + std::string name2{name}; + SymbolCommon common = {flags, name2}; + DataSym sym = + undef ? DataSym{common, MakeDollarName(name), kInvalidIndex, + module_->num_data_imports, 0} + : DataSym{common, MakeDollarName(name), segment, offset, size}; + data_symbols.emplace(sym); + assert(index == table.symbols().size()); + table.AddSymbol( + {name2, flags, + Symbol::Data{sym.segment, static_cast(sym.offset), sym.size}}); if (name.empty()) { return Result::Ok; } @@ -1778,14 +1855,18 @@ Result BinaryReaderIR::OnFunctionSymbol(Index index, uint32_t flags, std::string_view name, Index func_index) { - if (name.empty()) { - return Result::Ok; - } + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Function{func_index}}; + table.AddSymbol(sym); if (func_index >= module_->funcs.size()) { PrintError("invalid function index: %" PRIindex, func_index); return Result::Error; } Func* func = module_->funcs[func_index]; + static_cast(*func) = sym; + if (name.empty()) { + return Result::Ok; + } if (!func->name.empty()) { // The name section has already named this function. return Result::Ok; @@ -1801,12 +1882,23 @@ Result BinaryReaderIR::OnGlobalSymbol(Index index, uint32_t flags, std::string_view name, Index global_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Global{global_index}}; + table.AddSymbol(sym); + if (global_index >= module_->globals.size()) { + PrintError("invalid global index: %" PRIindex, global_index); + return Result::Error; + } + Global* glob = module_->globals[global_index]; + static_cast(*glob) = sym; return SetGlobalName(global_index, name); } Result BinaryReaderIR::OnSectionSymbol(Index index, uint32_t flags, Index section_index) { + assert(index == table.symbols().size()); + table.AddSymbol({"", flags, Symbol::Section{section_index}}); return Result::Ok; } @@ -1814,14 +1906,18 @@ Result BinaryReaderIR::OnTagSymbol(Index index, uint32_t flags, std::string_view name, Index tag_index) { - if (name.empty()) { - return Result::Ok; - } + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Tag{tag_index}}; + table.AddSymbol(sym); if (tag_index >= module_->tags.size()) { PrintError("invalid tag index: %" PRIindex, tag_index); return Result::Error; } Tag* tag = module_->tags[tag_index]; + static_cast(*tag) = sym; + if (name.empty()) { + return Result::Ok; + } std::string dollar_name = GetUniqueName(&module_->tag_bindings, MakeDollarName(name)); tag->name = dollar_name; @@ -1833,9 +1929,99 @@ Result BinaryReaderIR::OnTableSymbol(Index index, uint32_t flags, std::string_view name, Index table_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Table{table_index}}; + table.AddSymbol(sym); + if (table_index >= module_->tables.size()) { + PrintError("invalid table index: %" PRIindex, table_index); + return Result::Error; + } + Table* table = module_->tables[table_index]; + static_cast(*table) = sym; return SetTableName(table_index, name); } +Result BinaryReaderIR::OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) { + GetQueue()->incoming_relocs.emplace_back(type, offset, index, addend); + return Result::Ok; +} +void BinaryReaderIR::MakeQueue(RelocQueue::Type t) { + assert(active_section != kInvalidIndex); + active_reloc_section = + reloc_queues.insert({active_section, RelocQueue{state->offset, t}}).first; +} +BinaryReaderIR::RelocQueue* BinaryReaderIR::GetQueue() { + if (active_reloc_section != end(reloc_queues)) + return &active_reloc_section->second; + return nullptr; +} + +Result BinaryReaderIR::BeginCodeSection(Offset size) { + MakeQueue(RelocQueue::CODE); + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSection(Offset size) { + MakeQueue(RelocQueue::DATA); + return Result::Ok; +} + +Result BinaryReaderIR::BeginGenericCustomSection(Offset size) { + MakeQueue(RelocQueue::CUSTOM); + return Result::Ok; +} + +Result BinaryReaderIR::BeginElemSection(Offset size) { + return Result::Ok; +} + +Result BinaryReaderIR::OnRelocCount(Index count, Index section_index) { + active_reloc_section = reloc_queues.find(section_index); + if (!GetQueue()) { + if (active_section < section_index) { + PrintError( + "Relocation section [%d] does not follow its target section [%d]", + active_section, section_index); + } else { + PrintError( + "The target section for the relocation section [%d] does not have a " + "valid index [%d]", + active_section, section_index); + } + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::EndRelocSection() { + active_reloc_section = end(reloc_queues); + return Result::Ok; +} + +Result BinaryReaderIR::BeginSection(Index section_index, + BinarySection section_type, + Offset size) { + active_section = section_index; + return Result::Ok; +} + +Result BinaryReaderIR::OnInitFunction(uint32_t prio, Index sym) { + if (sym >= table.symbols().size()) { + return Result::Ok; + // PrintError("invalid init function priority symbol index: %" PRIindex, + // sym); return Result::Error; + } + Index func = table.symbols()[sym].AsFunction().index; + if (func >= module_->funcs.size()) + // We already emitted an error for the invalid symbol + return Result::Ok; + module_->funcs[func]->priority = prio; + return Result::Ok; +} + Result BinaryReaderIR::OnGenericCustomSection(std::string_view name, const void* data, Offset size) { @@ -1848,6 +2034,138 @@ Result BinaryReaderIR::OnGenericCustomSection(std::string_view name, return Result::Ok; } +Result BinaryReaderIR::EndModule() { + size_t i = 0; + Index range_start = 0, data_segment = -1; + for (auto& datasym : data_symbols) { + if (datasym.segment >= module_->data_segments.size() && datasym.segment != kInvalidIndex) + // all further symbols are invalid + break; + if (datasym.segment != data_segment) { + if (data_segment != kInvalidIndex) { + module_->data_segments[data_segment]->symbol_range = {range_start, i}; + } + range_start = i; + data_segment = datasym.segment; + } + module_->data_symbols.push_back(datasym); + if (!datasym.name.empty()) { + module_->data_symbols[i].name = datasym.name; + module_->data_symbol_bindings.emplace(datasym.name, i); + } + ++i; + } + if (data_segment != kInvalidIndex) { + module_->data_segments[data_segment]->symbol_range = {range_start, i}; + } + + auto lookup_reloc = [this](Reloc r) { + auto maybe_name = [](auto& table, Index idx) { + if (idx >= table.size()) + return Var{kInvalidIndex, {}}; + auto sym = Overload{ + [](auto* x) { return x; }, + [](auto& x) { return &x; }, + }(table[idx]); + return sym->name.empty() ? Var{idx, {}} : Var{sym->name, {}}; + }; + + if (r.index >= size(table.symbols())) + return Var{kInvalidIndex, {}}; + + auto& sym = table.symbols()[r.index]; + switch (sym.type()) { + case SymbolType::Data: { + auto& data = sym.AsData(); + auto&& syms = module_->data_symbols; + auto res = + std::lower_bound(syms.begin(), syms.end(), + DataSym::MakeForSearch(data.index, data.offset)); + Index sym = res - syms.begin(); + return maybe_name(module_->data_symbols, sym); + } + // Sure would've been nice to have a feature that would allow one to write + // a piece of code and stamp it out multiple times, but with different + // types and stuff. Better yet, maybe use that to yield different data for + // different types. And call that feature templates, that'd be a great + // name for it! + case SymbolType::Section: { + auto idx = sym.AsSection().section; + return maybe_name(module_->customs, idx); + } + case SymbolType::Function: { + auto idx = sym.AsFunction().index; + return maybe_name(module_->funcs, idx); + } + case SymbolType::Global: { + auto idx = sym.AsGlobal().index; + return maybe_name(module_->globals, idx); + } + case SymbolType::Table: { + auto idx = sym.AsTable().index; + return maybe_name(module_->tables, idx); + } + case SymbolType::Tag: { + auto idx = sym.AsTag().index; + return maybe_name(module_->tags, idx); + } + default: + WABT_UNREACHABLE; + } + }; + + for (auto& [index, queue] : reloc_queues) { + for (auto reloc : queue.incoming_relocs) { + bool applied_relocation = false; + Var sym_id = lookup_reloc(reloc); + if (sym_id.is_index() && sym_id.index() == kInvalidIndex) + // this reloc points to an invalid symbol and is therefore unapplicable + continue; + auto reloc_size = + kRelocDataTypeSize[int(kRelocDataType[int(reloc.type)])]; + // We pray that the relocation is always the last operand, and that the + // operand is an overlong leb already + auto reloc_addr = reloc.offset + reloc_size; + if (queue.type == RelocQueue::CODE && kRelocDataType[int(reloc.type)] == RelocDataType::LEB) { + switch (kRelocSymbolType[int(reloc.type)]) { + case RelocKind::Global: + case RelocKind::Type: + case RelocKind::Table: + case RelocKind::Function: + // Assume all relocations of primary shape are valid, we have no way + // to check + continue; + default: + break; + } + } + queue.traverse([&](auto& insns) { + auto insn = insns.find(reloc_addr); + if (insn != end(insns)) { + insn->second->reloc = {reloc.type, sym_id, reloc.addend}; + assert(insn->second->reloc.type != RelocType::None); + applied_relocation = true; + } + }); + if (applied_relocation) + continue; + auto it = queue.data_segment_starts.lower_bound(reloc.offset); + if (it != end(queue.data_segment_starts)) { + auto end = it->first + it->second->data.size(); + auto abs_offset = reloc.offset + queue.start; + if (end >= abs_offset + reloc_size) { + it->second->relocs.push_back( + {abs_offset - it->first, {reloc.type, sym_id, reloc.addend}}); + applied_relocation = true; + } + } + assert(applied_relocation && "Unable to apply relocation"); + } + } + + return Result::Ok; +} + } // end anonymous namespace Result ReadBinaryIr(const char* filename, diff --git a/src/binary-reader.cc b/src/binary-reader.cc index cbdd3384f8..434e15bf9e 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -2341,6 +2341,9 @@ Result BinaryReader::ReadLinkingSection(Offset section_size) { CALLBACK(OnSectionSymbol, i, flags, index); break; } + default: + PrintError("Unknown symbol type: %d", static_cast(sym_type)); + return Result::Error; } } break; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 600154b941..09c9aa7ad6 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -117,252 +117,6 @@ struct RelocSection { std::vector relocations; }; -class Symbol { - public: - struct Function { - static const SymbolType type = SymbolType::Function; - Index index; - }; - struct Data { - static const SymbolType type = SymbolType::Data; - Index index; - Offset offset; - Address size; - }; - struct Global { - static const SymbolType type = SymbolType::Global; - Index index; - }; - struct Section { - static const SymbolType type = SymbolType::Section; - Index section; - }; - struct Tag { - static const SymbolType type = SymbolType::Tag; - Index index; - }; - struct Table { - static const SymbolType type = SymbolType::Table; - Index index; - }; - - private: - SymbolType type_; - std::string_view name_; - uint8_t flags_; - union { - Function function_; - Data data_; - Global global_; - Section section_; - Tag tag_; - Table table_; - }; - - public: - Symbol(const std::string_view& name, uint8_t flags, const Function& f) - : type_(Function::type), name_(name), flags_(flags), function_(f) {} - Symbol(const std::string_view& name, uint8_t flags, const Data& d) - : type_(Data::type), name_(name), flags_(flags), data_(d) {} - Symbol(const std::string_view& name, uint8_t flags, const Global& g) - : type_(Global::type), name_(name), flags_(flags), global_(g) {} - Symbol(const std::string_view& name, uint8_t flags, const Section& s) - : type_(Section::type), name_(name), flags_(flags), section_(s) {} - Symbol(const std::string_view& name, uint8_t flags, const Tag& e) - : type_(Tag::type), name_(name), flags_(flags), tag_(e) {} - Symbol(const std::string_view& name, uint8_t flags, const Table& t) - : type_(Table::type), name_(name), flags_(flags), table_(t) {} - - SymbolType type() const { return type_; } - const std::string_view& name() const { return name_; } - uint8_t flags() const { return flags_; } - - SymbolVisibility visibility() const { - return static_cast(flags() & WABT_SYMBOL_MASK_VISIBILITY); - } - SymbolBinding binding() const { - return static_cast(flags() & WABT_SYMBOL_MASK_BINDING); - } - bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; } - bool defined() const { return !undefined(); } - bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; } - bool explicit_name() const { - return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; - } - bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } - - bool IsFunction() const { return type() == Function::type; } - bool IsData() const { return type() == Data::type; } - bool IsGlobal() const { return type() == Global::type; } - bool IsSection() const { return type() == Section::type; } - bool IsTag() const { return type() == Tag::type; } - bool IsTable() const { return type() == Table::type; } - - const Function& AsFunction() const { - assert(IsFunction()); - return function_; - } - const Data& AsData() const { - assert(IsData()); - return data_; - } - const Global& AsGlobal() const { - assert(IsGlobal()); - return global_; - } - const Section& AsSection() const { - assert(IsSection()); - return section_; - } - const Tag& AsTag() const { - assert(IsTag()); - return tag_; - } - const Table& AsTable() const { - assert(IsTable()); - return table_; - } -}; - -class SymbolTable { - WABT_DISALLOW_COPY_AND_ASSIGN(SymbolTable); - - std::vector symbols_; - - std::vector functions_; - std::vector tables_; - std::vector globals_; - - std::set seen_names_; - - Result EnsureUnique(const std::string_view& name) { - if (seen_names_.count(name)) { - fprintf(stderr, - "error: duplicate symbol when writing relocatable " - "binary: %s\n", - &name[0]); - return Result::Error; - } - seen_names_.insert(name); - return Result::Ok; - }; - - template - Result AddSymbol(std::vector* map, - std::string_view name, - bool imported, - bool exported, - T&& sym) { - uint8_t flags = 0; - if (imported) { - flags |= WABT_SYMBOL_FLAG_UNDEFINED; - // Wabt currently has no way for a user to explicitly specify the name of - // an import, so never set the EXPLICIT_NAME flag, and ignore any display - // name fabricated by wabt. - name = std::string_view(); - } else { - if (name.empty()) { - // Definitions without a name are local. - flags |= uint8_t(SymbolBinding::Local); - flags |= uint8_t(SymbolVisibility::Hidden); - } else { - // Otherwise, strip the dollar off the name; a definition $foo is - // available for linking as "foo". - assert(name[0] == '$'); - name.remove_prefix(1); - } - - if (exported) { - CHECK_RESULT(EnsureUnique(name)); - flags |= uint8_t(SymbolVisibility::Hidden); - flags |= WABT_SYMBOL_FLAG_NO_STRIP; - } - } - if (exported) { - flags |= WABT_SYMBOL_FLAG_EXPORTED; - } - - map->push_back(symbols_.size()); - symbols_.emplace_back(name, flags, sym); - return Result::Ok; - }; - - Index SymbolIndex(const std::vector& table, Index index) const { - // For well-formed modules, an index into (e.g.) functions_ will always be - // within bounds; the out-of-bounds case here is just to allow --relocatable - // to write known-invalid modules. - return index < table.size() ? table[index] : kInvalidIndex; - } - - public: - SymbolTable() {} - - Result Populate(const Module* module) { - std::set exported_funcs; - std::set exported_globals; - std::set exported_tags; - std::set exported_tables; - - for (const Export* export_ : module->exports) { - switch (export_->kind) { - case ExternalKind::Func: - exported_funcs.insert(module->GetFuncIndex(export_->var)); - break; - case ExternalKind::Table: - exported_tables.insert(module->GetTableIndex(export_->var)); - break; - case ExternalKind::Memory: - break; - case ExternalKind::Global: - exported_globals.insert(module->GetGlobalIndex(export_->var)); - break; - case ExternalKind::Tag: - exported_tags.insert(module->GetTagIndex(export_->var)); - break; - } - } - - // We currently only create symbol table entries for function, table, and - // global symbols. - for (size_t i = 0; i < module->funcs.size(); ++i) { - const Func* func = module->funcs[i]; - bool imported = i < module->num_func_imports; - bool exported = exported_funcs.count(i); - CHECK_RESULT(AddSymbol(&functions_, func->name, imported, exported, - Symbol::Function{Index(i)})); - } - - for (size_t i = 0; i < module->tables.size(); ++i) { - const Table* table = module->tables[i]; - bool imported = i < module->num_table_imports; - bool exported = exported_tables.count(i); - CHECK_RESULT(AddSymbol(&tables_, table->name, imported, exported, - Symbol::Table{Index(i)})); - } - - for (size_t i = 0; i < module->globals.size(); ++i) { - const Global* global = module->globals[i]; - bool imported = i < module->num_global_imports; - bool exported = exported_globals.count(i); - CHECK_RESULT(AddSymbol(&globals_, global->name, imported, exported, - Symbol::Global{Index(i)})); - } - - return Result::Ok; - } - - const std::vector& symbols() const { return symbols_; } - Index FunctionSymbolIndex(Index index) const { - return SymbolIndex(functions_, index); - } - Index TableSymbolIndex(Index index) const { - return SymbolIndex(tables_, index); - } - Index GlobalSymbolIndex(Index index) const { - return SymbolIndex(globals_, index); - } -}; - struct CodeMetadata { Offset offset; std::vector data; @@ -407,6 +161,8 @@ class BinaryWriter { Index GetLocalIndex(const Func* func, const Var& var); Index GetSymbolIndex(RelocType reloc_type, Index index); void AddReloc(RelocType reloc_type, Index index); + void AddRelocAt(IrReloc, Offset); + void AddReloc(IrReloc); void WriteBlockDecl(const BlockDeclaration& decl); void WriteU32Leb128WithReloc(Index index, const char* desc, @@ -601,14 +357,20 @@ Index BinaryWriter::GetTagVarDepth(const Var* var) { } Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) { - switch (reloc_type) { - case RelocType::FuncIndexLEB: + switch (kRelocSymbolType[int(reloc_type)]) { + case RelocKind::FunctionTbl: + case RelocKind::Function: + case RelocKind::Text: return symtab_.FunctionSymbolIndex(index); - case RelocType::TableNumberLEB: + case RelocKind::Table: return symtab_.TableSymbolIndex(index); - case RelocType::GlobalIndexLEB: + case RelocKind::Global: return symtab_.GlobalSymbolIndex(index); - case RelocType::TypeIndexLEB: + case RelocKind::Data: + return symtab_.DataSymbolIndex(index); + case RelocKind::Tag: + return symtab_.TagSymbolIndex(index); + case RelocKind::Type: // Type indexes don't create entries in the symbol table; instead their // index is used directly. return index; @@ -619,7 +381,7 @@ Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) { } } -void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { +void BinaryWriter::AddRelocAt(IrReloc r, Offset offset) { // Add a new reloc section if needed if (!current_reloc_section_ || current_reloc_section_->section_index != section_count_) { @@ -629,16 +391,25 @@ void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { } // Add a new relocation to the curent reloc section - size_t offset = stream_->offset() - last_section_payload_offset_; - Index symbol_index = GetSymbolIndex(reloc_type, index); + Index symbol_index = GetSymbolIndex(r.type, r.symbol.index()); if (symbol_index == kInvalidIndex) { // The file is invalid, for example a reference to function 42 where only 10 // functions are defined. The user must have already passed --no-check, so // no extra warning here is needed. return; } - current_reloc_section_->relocations.emplace_back(reloc_type, offset, - symbol_index); + current_reloc_section_->relocations.emplace_back(r.type, offset, symbol_index, + r.addend); +} + +void BinaryWriter::AddReloc(IrReloc r) { + // Add a new relocation to the curent reloc section + size_t offset = stream_->offset() - last_section_payload_offset_; + return AddRelocAt(r, offset); +} + +void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { + return AddReloc({reloc_type, Var{index, {}}}); } void BinaryWriter::WriteU32Leb128WithReloc(Index index, @@ -701,7 +472,24 @@ void BinaryWriter::WriteLoadStoreExpr(const Func* func, } else { stream_->WriteU8(log2_u32(align), "alignment"); } - WriteU64Leb128(stream_, typed_expr->offset, desc); + if constexpr (std::is_same_v || std::is_same_v) { + if (options_.relocatable && typed_expr->reloc.type != RelocType::None) { + AddReloc(typed_expr->reloc); + switch (kRelocDataType[int(typed_expr->reloc.type)]) { + case RelocDataType::LEB64: + WriteFixedU64Leb128(stream_, typed_expr->offset, desc); + break; + case RelocDataType::LEB: + WriteFixedU32Leb128(stream_, typed_expr->offset, desc); + break; + default: + WABT_UNREACHABLE; + } + } else + WriteU64Leb128(stream_, typed_expr->offset, desc); + } else { + WriteU64Leb128(stream_, typed_expr->offset, desc); + } } template @@ -814,16 +602,31 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteOpcode(stream_, cast(expr)->opcode); break; case ExprType::Const: { - const Const& const_ = cast(expr)->const_; + const ConstExpr* const_expr = cast(expr); + const Const& const_ = const_expr->const_; switch (const_.type()) { case Type::I32: { WriteOpcode(stream_, Opcode::I32Const); - WriteS32Leb128(stream_, const_.u32(), "i32 literal"); + if (options_.relocatable && + const_expr->reloc.type != RelocType::None) { + assert(kRelocDataType[int(const_expr->reloc.type)] == + RelocDataType::SLEB); + AddReloc(const_expr->reloc); + WriteFixedS32Leb128(stream_, const_.u32(), "i32 literal"); + } else + WriteS32Leb128(stream_, const_.u32(), "i32 literal"); break; } case Type::I64: WriteOpcode(stream_, Opcode::I64Const); - WriteS64Leb128(stream_, const_.u64(), "i64 literal"); + if (options_.relocatable && + const_expr->reloc.type != RelocType::None) { + assert(kRelocDataType[int(const_expr->reloc.type)] == + RelocDataType::SLEB64); + AddReloc(const_expr->reloc); + WriteFixedS64Leb128(stream_, const_.u64(), "i64 literal"); + } else + WriteS64Leb128(stream_, const_.u64(), "i64 literal"); break; case Type::F32: WriteOpcode(stream_, Opcode::F32Const); @@ -1241,7 +1044,7 @@ void BinaryWriter::WriteRelocSection(const RelocSection* reloc_section) { case RelocType::SectionOffsetI32: case RelocType::MemoryAddressTLSSLEB: case RelocType::MemoryAddressTLSSLEB64: - WriteU32Leb128(stream_, reloc.addend, "reloc addend"); + WriteS32Leb128(stream_, reloc.addend, "reloc addend"); break; case RelocType::FuncIndexLEB: case RelocType::FuncIndexI32: @@ -1269,6 +1072,18 @@ void BinaryWriter::WriteLinkingSection() { BeginCustomSection(WABT_BINARY_SECTION_LINKING); WriteU32Leb128(stream_, 2, "metadata version"); const std::vector& symbols = symtab_.symbols(); + int has_init = 0; + + stream_->WriteU8Enum(LinkingEntryType::SegmentInfo, "segments table"); + BeginSubsection("segment table"); + WriteU32Leb128(stream_, module_->data_segments.size(), "segment count"); + for (auto &&seg : module_->data_segments) { + WriteStr(stream_, seg->sym.name, "segment name"); + WriteU32Leb128(stream_, seg->sym.align, "segment align"); + WriteU32Leb128(stream_, seg->sym.flags, "segment flags"); + } + EndSubsection(); + if (symbols.size()) { stream_->WriteU8Enum(LinkingEntryType::SymbolTable, "symbol table"); BeginSubsection("symbol table"); @@ -1283,6 +1098,9 @@ void BinaryWriter::WriteLinkingSection() { if (sym.defined() || sym.explicit_name()) { WriteStr(stream_, sym.name(), "function name", PrintChars::Yes); } + if (module_->funcs[sym.AsFunction().index]->priority) { + ++has_init; + } break; case SymbolType::Data: WriteStr(stream_, sym.name(), "data name", PrintChars::Yes); @@ -1316,6 +1134,24 @@ void BinaryWriter::WriteLinkingSection() { } } EndSubsection(); + + if (has_init) { + stream_->WriteU8Enum(LinkingEntryType::InitFunctions, "initializsers"); + BeginSubsection("initializsers"); + WriteU32Leb128(stream_, has_init, "initializser count"); + int i = 0; + for (const Symbol& sym : symbols) { + if (sym.IsFunction()) { + auto &prio = module_->funcs[sym.AsFunction().index]->priority; + if (prio) { + WriteU32Leb128(stream_, *prio, "priority"); + WriteU32Leb128(stream_, i, "func id"); + } + } + ++i; + } + EndSubsection(); + } } EndSection(); } @@ -1707,7 +1543,11 @@ Result BinaryWriter::WriteModule() { } WriteU32Leb128(stream_, segment->data.size(), "data segment size"); WriteHeader("data segment data", i); + size_t start_offset = stream_->offset() - last_section_payload_offset_; stream_->WriteData(segment->data, "data segment data"); + for (auto& [offset, reloc] : segment->relocs) { + AddRelocAt(reloc, offset + start_offset); + } } EndSection(); } diff --git a/src/ir.cc b/src/ir.cc index 47b5cb3187..053237ccc7 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -110,6 +110,72 @@ bool FuncSignature::operator==(const FuncSignature& rhs) const { return param_types == rhs.param_types && result_types == rhs.result_types; } +template <> +std::vector& SymbolTable::GetTable() { + return functions_; +} +template <> +std::vector& SymbolTable::GetTable() { + return tables_; +} +template <> +std::vector& SymbolTable::GetTable() { + return globals_; +} +template <> +std::vector& SymbolTable::GetTable() { + return tags_; +} +template <> +std::vector& SymbolTable::GetTable() { + return datas_; +} + +void EnlargeFor(std::vector& v, Index i) { + if (size(v) <= i) + v.resize(i + 1, kInvalidIndex); +} + +Result SymbolTable::AddSymbol(Symbol sym) { + sym.visit([this](auto type) { + if constexpr (!std::is_same_v && + !std::is_same_v) { + auto& table = this->GetTable(); + EnlargeFor(table, type.index); + // This is lossy since multiple symbols are genuinely possible, but apart + // from data symbols their semantics is not very clear + if (table[type.index] == kInvalidIndex) + table[type.index] = symbols_.size(); + } + }); + symbols_.push_back(sym); + return Result::Ok; +} +Result SymbolTable::Populate(const Module* module) { + auto add = [&](auto& table, auto make_sym) { + for (size_t i = 0; i < table.size(); ++i) { + auto sym = table[i]; + CHECK_RESULT(AddSymbol({sym->name_, sym->flags_, make_sym(i, sym)})); + } + return Result::Ok; + }; + add(module->funcs, [](Index i, auto&) { return Symbol::Function{i}; }); + add(module->tables, [](Index i, auto&) { return Symbol::Table{i}; }); + add(module->globals, [](Index i, auto&) { return Symbol::Global{i}; }); + add(module->tags, [](Index i, auto&) { return Symbol::Tag{i}; }); + for (size_t i = 0; i < module->data_symbols.size(); ++i) { + auto& sym = module->data_symbols[i]; + CHECK_RESULT( + AddSymbol({sym.name_, sym.flags_, + Symbol::Data{sym.segment, static_cast(sym.offset), + sym.size}})); + EnlargeFor(datas_, i); + datas_[i] = symbols().size() - 1; + } + + return Result::Ok; +} + const Export* Module::GetExport(std::string_view name) const { Index index = export_bindings.FindIndex(name); if (index >= exports.size()) { @@ -150,6 +216,10 @@ Index Module::GetElemSegmentIndex(const Var& var) const { return elem_segment_bindings.FindIndex(var); } +Index Module::GetDataSymIndex(const Var& var) const { + return data_symbol_bindings.FindIndex(var); +} + bool Module::IsImport(ExternalKind kind, const Var& var) const { switch (kind) { case ExternalKind::Func: @@ -312,6 +382,14 @@ ElemSegment* Module::GetElemSegment(const Var& var) { return elem_segments[index]; } +DataSym* Module::GetDataSym(const Var& var) { + Index index = data_symbol_bindings.FindIndex(var); + if (index >= elem_segments.size()) { + return nullptr; + } + return &data_symbols[index]; +} + const FuncType* Module::GetFuncType(const Var& var) const { return const_cast(this)->GetFuncType(var); } diff --git a/src/leb128.cc b/src/leb128.cc index 6c5a650fa9..ed2f2a26aa 100644 --- a/src/leb128.cc +++ b/src/leb128.cc @@ -141,6 +141,22 @@ void WriteU64Leb128(Stream* stream, uint64_t value, const char* desc) { stream->WriteData(data, length, desc); } +void WriteFixedU64Leb128(Stream* stream, uint64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(length == MAX_U64_LEB128_BYTES); + stream->WriteData(data, length, desc); +} +void WriteFixedS64Leb128(Stream* stream, int64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(length == MAX_U64_LEB128_BYTES); + stream->WriteData(data, length, desc); +} +void WriteFixedS64Leb128(Stream* stream, uint64_t value, const char* desc) { + WriteS64Leb128(stream, Bitcast(value), desc); +} + void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc) { WriteS64Leb128(stream, Bitcast(value), desc); } diff --git a/src/lexer-keywords.txt b/src/lexer-keywords.txt index 5923c7109c..d571d80bd3 100644 --- a/src/lexer-keywords.txt +++ b/src/lexer-keywords.txt @@ -19,6 +19,7 @@ struct TokenInfo { %% array, Type::Array, TokenType::Array after, TokenType::After +align, TokenType::Align assert_exception, TokenType::AssertException assert_exhaustion, TokenType::AssertExhaustion assert_invalid, TokenType::AssertInvalid @@ -190,6 +191,7 @@ get, TokenType::Get global.get, TokenType::GlobalGet, Opcode::GlobalGet global.set, TokenType::GlobalSet, Opcode::GlobalSet global, TokenType::Global +hidden, TokenType::Hidden i16x8.abs, TokenType::Unary, Opcode::I16X8Abs i16x8.add_sat_s, TokenType::Binary, Opcode::I16X8AddSatS i16x8.add_sat_u, TokenType::Binary, Opcode::I16X8AddSatU @@ -534,6 +536,7 @@ i8x16.sub, TokenType::Binary, Opcode::I8X16Sub i8x16, TokenType::I8X16 if, TokenType::If, Opcode::If import, TokenType::Import +init_prio, TokenType::InitPrio input, TokenType::Input invoke, TokenType::Invoke item, TokenType::Item @@ -555,6 +558,7 @@ module, TokenType::Module mut, TokenType::Mut nan:arithmetic, TokenType::NanArithmetic nan:canonical, TokenType::NanCanonical +name, TokenType::Name nop, TokenType::Nop, Opcode::Nop offset, TokenType::Offset output, TokenType::Output @@ -568,13 +572,16 @@ ref.is_null, TokenType::RefIsNull, Opcode::RefIsNull ref.null, TokenType::RefNull, Opcode::RefNull register, TokenType::Register result, TokenType::Result +retain, TokenType::Retain rethrow, TokenType::Rethrow, Opcode::Rethrow return_call_indirect, TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect return_call, TokenType::ReturnCall, Opcode::ReturnCall return, TokenType::Return, Opcode::Return select, TokenType::Select, Opcode::Select shared, TokenType::Shared +size, TokenType::Size start, TokenType::Start +strings, TokenType::Strings struct, Type::Struct, TokenType::Struct table.copy, TokenType::TableCopy, Opcode::TableCopy table.fill, TokenType::TableFill, Opcode::TableFill @@ -587,10 +594,12 @@ table, TokenType::Table then, TokenType::Then throw, TokenType::Throw, Opcode::Throw throw_ref, TokenType::ThrowRef, Opcode::ThrowRef +tls, TokenType::TLS try, TokenType::Try, Opcode::Try try_table, TokenType::TryTable, Opcode::TryTable type, TokenType::Type unreachable, TokenType::Unreachable, Opcode::Unreachable +weak, TokenType::Weak v128.andnot, TokenType::Binary, Opcode::V128Andnot v128.and, TokenType::Binary, Opcode::V128And v128.bitselect, TokenType::Ternary, Opcode::V128BitSelect diff --git a/src/prebuilt/lexer-keywords.cc b/src/prebuilt/lexer-keywords.cc index 89f14dbaca..0b18c5025c 100644 --- a/src/prebuilt/lexer-keywords.cc +++ b/src/prebuilt/lexer-keywords.cc @@ -1,4 +1,4 @@ -/* C++ code produced by gperf version 3.1 */ +/* C++ code produced by gperf version 3.3 */ /* Command-line: gperf -m 50 -L C++ -N InWordSet -E -t -c --output-file=src/prebuilt/lexer-keywords.cc src/lexer-keywords.txt */ /* Computed positions: -k'1,3,5-8,10,12,15,17-19,23,27,$' */ @@ -48,7 +48,7 @@ struct TokenInfo { Opcode opcode; }; }; -/* maximum key range = 2193, duplicates = 0 */ +/* maximum key range = 2332, duplicates = 0 */ class Perfect_Hash { @@ -63,32 +63,32 @@ Perfect_Hash::hash (const char *str, size_t len) { static unsigned short asso_values[] = { - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 13, 2230, 2230, 426, - 351, 14, 17, 13, 176, 531, 32, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 183, 13, 16, 811, 21, - 68, 16, 326, 13, 347, 223, 20, 13, 15, 140, - 80, 54, 559, 611, 14, 15, 24, 13, 556, 521, - 125, 416, 213, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230 + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2, 2341, 2341, 448, + 310, 2, 31, 1, 331, 255, 90, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 225, 1, 3, 723, 30, + 73, 1, 385, 6, 449, 332, 2, 1, 14, 136, + 65, 101, 439, 655, 8, 3, 3, 1, 482, 664, + 143, 231, 119, 3, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341 }; unsigned int hval = len; @@ -96,54 +96,119 @@ Perfect_Hash::hash (const char *str, size_t len) { default: hval += asso_values[static_cast(str[26])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 26: case 25: case 24: case 23: hval += asso_values[static_cast(str[22])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 22: case 21: case 20: case 19: hval += asso_values[static_cast(str[18])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 18: hval += asso_values[static_cast(str[17])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 17: hval += asso_values[static_cast(str[16])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 16: case 15: hval += asso_values[static_cast(str[14])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 14: case 13: case 12: hval += asso_values[static_cast(str[11])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 11: case 10: hval += asso_values[static_cast(str[9])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 9: case 8: hval += asso_values[static_cast(str[7])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 7: hval += asso_values[static_cast(str[6])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 6: hval += asso_values[static_cast(str[5])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 5: hval += asso_values[static_cast(str[4])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 4: case 3: hval += asso_values[static_cast(str[2]+1)]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 2: case 1: @@ -158,1499 +223,1581 @@ Perfect_Hash::InWordSet (const char *str, size_t len) { enum { - TOTAL_KEYWORDS = 601, + TOTAL_KEYWORDS = 610, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 35, - MIN_HASH_VALUE = 37, - MAX_HASH_VALUE = 2229 + MIN_HASH_VALUE = 9, + MAX_HASH_VALUE = 2340 }; +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif static struct TokenInfo wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 35 "src/lexer-keywords.txt" - {"br", TokenType::Br, Opcode::Br}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 152 "src/lexer-keywords.txt" - {"f64", Type::F64}, - {""}, {""}, -#line 45 "src/lexer-keywords.txt" +#line 46 "src/lexer-keywords.txt" {"data", TokenType::Data}, - {""}, {""}, {""}, -#line 464 "src/lexer-keywords.txt" - {"i64", Type::I64}, +#line 597 "src/lexer-keywords.txt" + {"tls", TokenType::TLS}, +#line 582 "src/lexer-keywords.txt" + {"size", TokenType::Size}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 122 "src/lexer-keywords.txt" - {"f32x4", TokenType::F32X4}, - {""}, {""}, {""}, {""}, -#line 586 "src/lexer-keywords.txt" - {"table", TokenType::Table}, -#line 48 "src/lexer-keywords.txt" - {"do", TokenType::Do}, -#line 364 "src/lexer-keywords.txt" - {"i32x4", TokenType::I32X4}, - {""}, {""}, {""}, -#line 135 "src/lexer-keywords.txt" +#line 136 "src/lexer-keywords.txt" {"f64.ge", TokenType::Compare, Opcode::F64Ge}, -#line 74 "src/lexer-keywords.txt" +#line 75 "src/lexer-keywords.txt" {"f32.ge", TokenType::Compare, Opcode::F32Ge}, + {""}, {""}, #line 137 "src/lexer-keywords.txt" - {"f64.le", TokenType::Compare, Opcode::F64Le}, -#line 76 "src/lexer-keywords.txt" - {"f32.le", TokenType::Compare, Opcode::F32Le}, - {""}, {""}, {""}, {""}, {""}, -#line 30 "src/lexer-keywords.txt" - {"before", TokenType::Before}, - {""}, {""}, {""}, {""}, {""}, -#line 187 "src/lexer-keywords.txt" - {"func", Type::FuncRef, TokenType::Func}, -#line 136 "src/lexer-keywords.txt" {"f64.gt", TokenType::Compare, Opcode::F64Gt}, -#line 75 "src/lexer-keywords.txt" +#line 76 "src/lexer-keywords.txt" {"f32.gt", TokenType::Compare, Opcode::F32Gt}, -#line 139 "src/lexer-keywords.txt" + {""}, {""}, +#line 138 "src/lexer-keywords.txt" + {"f64.le", TokenType::Compare, Opcode::F64Le}, +#line 77 "src/lexer-keywords.txt" + {"f32.le", TokenType::Compare, Opcode::F32Le}, + {""}, +#line 574 "src/lexer-keywords.txt" + {"result", TokenType::Result}, +#line 140 "src/lexer-keywords.txt" {"f64.lt", TokenType::Compare, Opcode::F64Lt}, -#line 78 "src/lexer-keywords.txt" +#line 79 "src/lexer-keywords.txt" {"f32.lt", TokenType::Compare, Opcode::F32Lt}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 43 "src/lexer-keywords.txt" - {"code", TokenType::Code}, - {""}, {""}, {""}, -#line 570 "src/lexer-keywords.txt" - {"result", TokenType::Result}, + {""}, {""}, +#line 466 "src/lexer-keywords.txt" + {"i64", Type::I64}, +#line 593 "src/lexer-keywords.txt" + {"table", TokenType::Table}, {""}, -#line 100 "src/lexer-keywords.txt" - {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge}, +#line 36 "src/lexer-keywords.txt" + {"br", TokenType::Br, Opcode::Br}, +#line 153 "src/lexer-keywords.txt" + {"f64", Type::F64}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 585 "src/lexer-keywords.txt" + {"struct", Type::Struct, TokenType::Struct}, {""}, -#line 102 "src/lexer-keywords.txt" - {"f32x4.le", TokenType::Compare, Opcode::F32X4Le}, +#line 591 "src/lexer-keywords.txt" + {"table.set", TokenType::TableSet, Opcode::TableSet}, {""}, -#line 578 "src/lexer-keywords.txt" - {"struct", Type::Struct, TokenType::Struct}, - {""}, {""}, {""}, {""}, {""}, -#line 555 "src/lexer-keywords.txt" - {"mut", TokenType::Mut}, -#line 441 "src/lexer-keywords.txt" - {"i64.or", TokenType::Binary, Opcode::I64Or}, -#line 298 "src/lexer-keywords.txt" - {"i32.or", TokenType::Binary, Opcode::I32Or}, - {""}, {""}, -#line 581 "src/lexer-keywords.txt" +#line 31 "src/lexer-keywords.txt" + {"before", TokenType::Before}, +#line 588 "src/lexer-keywords.txt" {"table.get", TokenType::TableGet, Opcode::TableGet}, -#line 101 "src/lexer-keywords.txt" - {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt}, -#line 584 "src/lexer-keywords.txt" - {"table.set", TokenType::TableSet, Opcode::TableSet}, -#line 103 "src/lexer-keywords.txt" - {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt}, -#line 330 "src/lexer-keywords.txt" + {""}, {""}, +#line 332 "src/lexer-keywords.txt" {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU}, - {""}, +#line 101 "src/lexer-keywords.txt" + {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge}, #line 334 "src/lexer-keywords.txt" - {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU}, + {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU}, {""}, -#line 329 "src/lexer-keywords.txt" +#line 331 "src/lexer-keywords.txt" {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS}, -#line 93 "src/lexer-keywords.txt" - {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil}, +#line 102 "src/lexer-keywords.txt" + {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt}, #line 333 "src/lexer-keywords.txt" - {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS}, - {""}, -#line 332 "src/lexer-keywords.txt" - {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU}, + {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS}, {""}, -#line 342 "src/lexer-keywords.txt" +#line 336 "src/lexer-keywords.txt" + {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU}, +#line 103 "src/lexer-keywords.txt" + {"f32x4.le", TokenType::Compare, Opcode::F32X4Le}, +#line 344 "src/lexer-keywords.txt" {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU}, {""}, -#line 331 "src/lexer-keywords.txt" - {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS}, - {""}, -#line 341 "src/lexer-keywords.txt" +#line 335 "src/lexer-keywords.txt" + {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS}, +#line 104 "src/lexer-keywords.txt" + {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt}, +#line 343 "src/lexer-keywords.txt" {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS}, -#line 145 "src/lexer-keywords.txt" +#line 366 "src/lexer-keywords.txt" + {"i32x4", TokenType::I32X4}, +#line 558 "src/lexer-keywords.txt" + {"mut", TokenType::Mut}, + {""}, {""}, +#line 123 "src/lexer-keywords.txt" + {"f32x4", TokenType::F32X4}, +#line 442 "src/lexer-keywords.txt" + {"i64.ne", TokenType::Compare, Opcode::I64Ne}, +#line 299 "src/lexer-keywords.txt" + {"i32.ne", TokenType::Compare, Opcode::I32Ne}, + {""}, +#line 44 "src/lexer-keywords.txt" + {"code", TokenType::Code}, +#line 146 "src/lexer-keywords.txt" {"f64.ne", TokenType::Compare, Opcode::F64Ne}, -#line 84 "src/lexer-keywords.txt" +#line 85 "src/lexer-keywords.txt" {"f32.ne", TokenType::Compare, Opcode::F32Ne}, - {""}, {""}, {""}, -#line 554 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, +#line 557 "src/lexer-keywords.txt" {"module", TokenType::Module}, {""}, -#line 440 "src/lexer-keywords.txt" - {"i64.ne", TokenType::Compare, Opcode::I64Ne}, -#line 297 "src/lexer-keywords.txt" - {"i32.ne", TokenType::Compare, Opcode::I32Ne}, -#line 46 "src/lexer-keywords.txt" - {"declare", TokenType::Declare}, +#line 584 "src/lexer-keywords.txt" + {"strings", TokenType::Strings}, {""}, -#line 144 "src/lexer-keywords.txt" +#line 145 "src/lexer-keywords.txt" {"f64.neg", TokenType::Unary, Opcode::F64Neg}, -#line 83 "src/lexer-keywords.txt" +#line 84 "src/lexer-keywords.txt" {"f32.neg", TokenType::Unary, Opcode::F32Neg}, +#line 47 "src/lexer-keywords.txt" + {"declare", TokenType::Declare}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 144 "src/lexer-keywords.txt" + {"f64.nearest", TokenType::Unary, Opcode::F64Nearest}, +#line 83 "src/lexer-keywords.txt" + {"f32.nearest", TokenType::Unary, Opcode::F32Nearest}, {""}, -#line 149 "src/lexer-keywords.txt" - {"f64.store", TokenType::Store, Opcode::F64Store}, -#line 87 "src/lexer-keywords.txt" - {"f32.store", TokenType::Store, Opcode::F32Store}, - {""}, -#line 447 "src/lexer-keywords.txt" - {"i64.rotr", TokenType::Binary, Opcode::I64Rotr}, -#line 304 "src/lexer-keywords.txt" - {"i32.rotr", TokenType::Binary, Opcode::I32Rotr}, -#line 446 "src/lexer-keywords.txt" - {"i64.rotl", TokenType::Binary, Opcode::I64Rotl}, -#line 303 "src/lexer-keywords.txt" - {"i32.rotl", TokenType::Binary, Opcode::I32Rotl}, -#line 454 "src/lexer-keywords.txt" - {"i64.store", TokenType::Store, Opcode::I64Store}, -#line 310 "src/lexer-keywords.txt" - {"i32.store", TokenType::Store, Opcode::I32Store}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 568 "src/lexer-keywords.txt" - {"ref.null", TokenType::RefNull, Opcode::RefNull}, -#line 108 "src/lexer-keywords.txt" - {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg}, +#line 49 "src/lexer-keywords.txt" + {"do", TokenType::Do}, + {""}, {""}, {""}, {""}, {""}, +#line 94 "src/lexer-keywords.txt" + {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil}, {""}, -#line 109 "src/lexer-keywords.txt" +#line 352 "src/lexer-keywords.txt" + {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne}, + {""}, {""}, {""}, +#line 110 "src/lexer-keywords.txt" {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne}, - {""}, {""}, {""}, {""}, -#line 349 "src/lexer-keywords.txt" - {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg}, {""}, -#line 350 "src/lexer-keywords.txt" - {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne}, - {""}, {""}, -#line 151 "src/lexer-keywords.txt" +#line 351 "src/lexer-keywords.txt" + {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg}, + {""}, {""}, {""}, +#line 109 "src/lexer-keywords.txt" + {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg}, +#line 152 "src/lexer-keywords.txt" {"f64.trunc", TokenType::Unary, Opcode::F64Trunc}, -#line 89 "src/lexer-keywords.txt" +#line 90 "src/lexer-keywords.txt" {"f32.trunc", TokenType::Unary, Opcode::F32Trunc}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 572 "src/lexer-keywords.txt" + {"ref.null", TokenType::RefNull, Opcode::RefNull}, +#line 443 "src/lexer-keywords.txt" + {"i64.or", TokenType::Binary, Opcode::I64Or}, +#line 300 "src/lexer-keywords.txt" + {"i32.or", TokenType::Binary, Opcode::I32Or}, +#line 456 "src/lexer-keywords.txt" + {"i64.store", TokenType::Store, Opcode::I64Store}, +#line 312 "src/lexer-keywords.txt" + {"i32.store", TokenType::Store, Opcode::I32Store}, + {""}, {""}, +#line 150 "src/lexer-keywords.txt" + {"f64.store", TokenType::Store, Opcode::F64Store}, +#line 88 "src/lexer-keywords.txt" + {"f32.store", TokenType::Store, Opcode::F32Store}, +#line 108 "src/lexer-keywords.txt" + {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest}, {""}, {""}, {""}, {""}, -#line 143 "src/lexer-keywords.txt" - {"f64.nearest", TokenType::Unary, Opcode::F64Nearest}, -#line 82 "src/lexer-keywords.txt" - {"f32.nearest", TokenType::Unary, Opcode::F32Nearest}, - {""}, {""}, {""}, -#line 120 "src/lexer-keywords.txt" - {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc}, -#line 574 "src/lexer-keywords.txt" +#line 449 "src/lexer-keywords.txt" + {"i64.rotr", TokenType::Binary, Opcode::I64Rotr}, +#line 306 "src/lexer-keywords.txt" + {"i32.rotr", TokenType::Binary, Opcode::I32Rotr}, +#line 188 "src/lexer-keywords.txt" + {"func", Type::FuncRef, TokenType::Func}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 579 "src/lexer-keywords.txt" {"return", TokenType::Return, Opcode::Return}, + {""}, {""}, +#line 448 "src/lexer-keywords.txt" + {"i64.rotl", TokenType::Binary, Opcode::I64Rotl}, +#line 305 "src/lexer-keywords.txt" + {"i32.rotl", TokenType::Binary, Opcode::I32Rotl}, {""}, {""}, {""}, {""}, {""}, -#line 453 "src/lexer-keywords.txt" - {"i64.store8", TokenType::Store, Opcode::I64Store8}, -#line 309 "src/lexer-keywords.txt" - {"i32.store8", TokenType::Store, Opcode::I32Store8}, -#line 142 "src/lexer-keywords.txt" - {"f64.mul", TokenType::Binary, Opcode::F64Mul}, -#line 81 "src/lexer-keywords.txt" - {"f32.mul", TokenType::Binary, Opcode::F32Mul}, -#line 92 "src/lexer-keywords.txt" - {"f32x4.add", TokenType::Binary, Opcode::F32X4Add}, -#line 107 "src/lexer-keywords.txt" - {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest}, +#line 121 "src/lexer-keywords.txt" + {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc}, +#line 48 "src/lexer-keywords.txt" + {"delegate", TokenType::Delegate}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 561 "src/lexer-keywords.txt" + {"name", TokenType::Name}, {""}, {""}, {""}, -#line 439 "src/lexer-keywords.txt" +#line 441 "src/lexer-keywords.txt" {"i64.mul", TokenType::Binary, Opcode::I64Mul}, -#line 296 "src/lexer-keywords.txt" +#line 298 "src/lexer-keywords.txt" {"i32.mul", TokenType::Binary, Opcode::I32Mul}, -#line 323 "src/lexer-keywords.txt" + {""}, {""}, +#line 143 "src/lexer-keywords.txt" + {"f64.mul", TokenType::Binary, Opcode::F64Mul}, +#line 82 "src/lexer-keywords.txt" + {"f32.mul", TokenType::Binary, Opcode::F32Mul}, +#line 580 "src/lexer-keywords.txt" + {"select", TokenType::Select, Opcode::Select}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 354 "src/lexer-keywords.txt" + {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane}, +#line 353 "src/lexer-keywords.txt" + {"i32x4.relaxed_laneselect", TokenType::Ternary, Opcode::I32X4RelaxedLaneSelect}, + {""}, {""}, +#line 117 "src/lexer-keywords.txt" + {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane}, + {""}, +#line 325 "src/lexer-keywords.txt" {"i32x4.add", TokenType::Binary, Opcode::I32X4Add}, {""}, -#line 38 "src/lexer-keywords.txt" - {"call", TokenType::Call, Opcode::Call}, +#line 350 "src/lexer-keywords.txt" + {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul}, {""}, -#line 126 "src/lexer-keywords.txt" - {"f64.const", TokenType::Const, Opcode::F64Const}, -#line 64 "src/lexer-keywords.txt" - {"f32.const", TokenType::Const, Opcode::F32Const}, - {""}, {""}, {""}, -#line 106 "src/lexer-keywords.txt" - {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul}, +#line 93 "src/lexer-keywords.txt" + {"f32x4.add", TokenType::Binary, Opcode::F32X4Add}, {""}, -#line 413 "src/lexer-keywords.txt" +#line 107 "src/lexer-keywords.txt" + {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 415 "src/lexer-keywords.txt" {"i64.const", TokenType::Const, Opcode::I64Const}, -#line 275 "src/lexer-keywords.txt" +#line 277 "src/lexer-keywords.txt" {"i32.const", TokenType::Const, Opcode::I32Const}, + {""}, {""}, +#line 127 "src/lexer-keywords.txt" + {"f64.const", TokenType::Const, Opcode::F64Const}, +#line 65 "src/lexer-keywords.txt" + {"f32.const", TokenType::Const, Opcode::F32Const}, + {""}, {""}, {""}, {""}, +#line 377 "src/lexer-keywords.txt" + {"i64.and", TokenType::Binary, Opcode::I64And}, +#line 248 "src/lexer-keywords.txt" + {"i32.and", TokenType::Binary, Opcode::I32And}, {""}, -#line 575 "src/lexer-keywords.txt" - {"select", TokenType::Select, Opcode::Select}, +#line 39 "src/lexer-keywords.txt" + {"call", TokenType::Call, Opcode::Call}, + {""}, {""}, {""}, {""}, +#line 376 "src/lexer-keywords.txt" + {"i64.add", TokenType::Binary, Opcode::I64Add}, +#line 247 "src/lexer-keywords.txt" + {"i32.add", TokenType::Binary, Opcode::I32Add}, + {""}, {""}, +#line 125 "src/lexer-keywords.txt" + {"f64.add", TokenType::Binary, Opcode::F64Add}, +#line 63 "src/lexer-keywords.txt" + {"f32.add", TokenType::Binary, Opcode::F32Add}, {""}, -#line 348 "src/lexer-keywords.txt" - {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul}, +#line 545 "src/lexer-keywords.txt" + {"local.tee", TokenType::LocalTee, Opcode::LocalTee}, {""}, -#line 543 "src/lexer-keywords.txt" +#line 544 "src/lexer-keywords.txt" + {"local.set", TokenType::LocalSet, Opcode::LocalSet}, +#line 546 "src/lexer-keywords.txt" {"local", TokenType::Local}, - {""}, {""}, {""}, -#line 496 "src/lexer-keywords.txt" - {"i64.xor", TokenType::Binary, Opcode::I64Xor}, -#line 373 "src/lexer-keywords.txt" - {"i32.xor", TokenType::Binary, Opcode::I32Xor}, -#line 47 "src/lexer-keywords.txt" - {"delegate", TokenType::Delegate}, - {""}, {""}, {""}, -#line 124 "src/lexer-keywords.txt" - {"f64.add", TokenType::Binary, Opcode::F64Add}, -#line 62 "src/lexer-keywords.txt" - {"f32.add", TokenType::Binary, Opcode::F32Add}, -#line 138 "src/lexer-keywords.txt" - {"f64.load", TokenType::Load, Opcode::F64Load}, -#line 77 "src/lexer-keywords.txt" - {"f32.load", TokenType::Load, Opcode::F32Load}, - {""}, {""}, {""}, -#line 374 "src/lexer-keywords.txt" - {"i64.add", TokenType::Binary, Opcode::I64Add}, -#line 245 "src/lexer-keywords.txt" - {"i32.add", TokenType::Binary, Opcode::I32Add}, -#line 436 "src/lexer-keywords.txt" - {"i64.load", TokenType::Load, Opcode::I64Load}, -#line 293 "src/lexer-keywords.txt" - {"i32.load", TokenType::Load, Opcode::I32Load}, - {""}, {""}, {""}, {""}, -#line 116 "src/lexer-keywords.txt" - {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane}, - {""}, {""}, {""}, -#line 375 "src/lexer-keywords.txt" - {"i64.and", TokenType::Binary, Opcode::I64And}, -#line 246 "src/lexer-keywords.txt" - {"i32.and", TokenType::Binary, Opcode::I32And}, {""}, -#line 352 "src/lexer-keywords.txt" - {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane}, - {""}, {""}, {""}, -#line 425 "src/lexer-keywords.txt" +#line 543 "src/lexer-keywords.txt" + {"local.get", TokenType::LocalGet, Opcode::LocalGet}, +#line 427 "src/lexer-keywords.txt" {"i64.ge_u", TokenType::Compare, Opcode::I64GeU}, -#line 284 "src/lexer-keywords.txt" +#line 286 "src/lexer-keywords.txt" {"i32.ge_u", TokenType::Compare, Opcode::I32GeU}, #line 429 "src/lexer-keywords.txt" - {"i64.le_u", TokenType::Compare, Opcode::I64LeU}, + {"i64.gt_u", TokenType::Compare, Opcode::I64GtU}, #line 288 "src/lexer-keywords.txt" - {"i32.le_u", TokenType::Compare, Opcode::I32LeU}, -#line 424 "src/lexer-keywords.txt" + {"i32.gt_u", TokenType::Compare, Opcode::I32GtU}, +#line 426 "src/lexer-keywords.txt" {"i64.ge_s", TokenType::Compare, Opcode::I64GeS}, -#line 283 "src/lexer-keywords.txt" +#line 285 "src/lexer-keywords.txt" {"i32.ge_s", TokenType::Compare, Opcode::I32GeS}, #line 428 "src/lexer-keywords.txt" - {"i64.le_s", TokenType::Compare, Opcode::I64LeS}, + {"i64.gt_s", TokenType::Compare, Opcode::I64GtS}, #line 287 "src/lexer-keywords.txt" - {"i32.le_s", TokenType::Compare, Opcode::I32LeS}, -#line 427 "src/lexer-keywords.txt" - {"i64.gt_u", TokenType::Compare, Opcode::I64GtU}, -#line 286 "src/lexer-keywords.txt" - {"i32.gt_u", TokenType::Compare, Opcode::I32GtU}, -#line 438 "src/lexer-keywords.txt" + {"i32.gt_s", TokenType::Compare, Opcode::I32GtS}, +#line 431 "src/lexer-keywords.txt" + {"i64.le_u", TokenType::Compare, Opcode::I64LeU}, +#line 290 "src/lexer-keywords.txt" + {"i32.le_u", TokenType::Compare, Opcode::I32LeU}, +#line 440 "src/lexer-keywords.txt" {"i64.lt_u", TokenType::Compare, Opcode::I64LtU}, -#line 295 "src/lexer-keywords.txt" +#line 297 "src/lexer-keywords.txt" {"i32.lt_u", TokenType::Compare, Opcode::I32LtU}, -#line 426 "src/lexer-keywords.txt" - {"i64.gt_s", TokenType::Compare, Opcode::I64GtS}, -#line 285 "src/lexer-keywords.txt" - {"i32.gt_s", TokenType::Compare, Opcode::I32GtS}, -#line 437 "src/lexer-keywords.txt" +#line 430 "src/lexer-keywords.txt" + {"i64.le_s", TokenType::Compare, Opcode::I64LeS}, +#line 289 "src/lexer-keywords.txt" + {"i32.le_s", TokenType::Compare, Opcode::I32LeS}, +#line 439 "src/lexer-keywords.txt" {"i64.lt_s", TokenType::Compare, Opcode::I64LtS}, -#line 294 "src/lexer-keywords.txt" +#line 296 "src/lexer-keywords.txt" {"i32.lt_s", TokenType::Compare, Opcode::I32LtS}, - {""}, {""}, {""}, -#line 540 "src/lexer-keywords.txt" - {"local.get", TokenType::LocalGet, Opcode::LocalGet}, - {""}, -#line 541 "src/lexer-keywords.txt" - {"local.set", TokenType::LocalSet, Opcode::LocalSet}, -#line 542 "src/lexer-keywords.txt" - {"local.tee", TokenType::LocalTee, Opcode::LocalTee}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 498 "src/lexer-keywords.txt" + {"i64.xor", TokenType::Binary, Opcode::I64Xor}, +#line 375 "src/lexer-keywords.txt" + {"i32.xor", TokenType::Binary, Opcode::I32Xor}, + {""}, {""}, {""}, +#line 438 "src/lexer-keywords.txt" + {"i64.load", TokenType::Load, Opcode::I64Load}, +#line 295 "src/lexer-keywords.txt" + {"i32.load", TokenType::Load, Opcode::I32Load}, + {""}, {""}, +#line 139 "src/lexer-keywords.txt" + {"f64.load", TokenType::Load, Opcode::F64Load}, +#line 78 "src/lexer-keywords.txt" + {"f32.load", TokenType::Load, Opcode::F32Load}, +#line 416 "src/lexer-keywords.txt" + {"i64.ctz", TokenType::Unary, Opcode::I64Ctz}, +#line 278 "src/lexer-keywords.txt" + {"i32.ctz", TokenType::Unary, Opcode::I32Ctz}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 351 "src/lexer-keywords.txt" - {"i32x4.relaxed_laneselect", TokenType::Ternary, Opcode::I32X4RelaxedLaneSelect}, -#line 324 "src/lexer-keywords.txt" +#line 414 "src/lexer-keywords.txt" + {"i64.clz", TokenType::Unary, Opcode::I64Clz}, +#line 276 "src/lexer-keywords.txt" + {"i32.clz", TokenType::Unary, Opcode::I32Clz}, + {""}, {""}, {""}, +#line 569 "src/lexer-keywords.txt" + {"ref.extern", TokenType::RefExtern}, + {""}, {""}, {""}, {""}, +#line 326 "src/lexer-keywords.txt" {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue}, {""}, -#line 125 "src/lexer-keywords.txt" - {"f64.ceil", TokenType::Unary, Opcode::F64Ceil}, -#line 63 "src/lexer-keywords.txt" - {"f32.ceil", TokenType::Unary, Opcode::F32Ceil}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 585 "src/lexer-keywords.txt" - {"table.size", TokenType::TableSize, Opcode::TableSize}, - {""}, {""}, {""}, -#line 104 "src/lexer-keywords.txt" - {"f32x4.max", TokenType::Binary, Opcode::F32X4Max}, -#line 535 "src/lexer-keywords.txt" - {"if", TokenType::If, Opcode::If}, -#line 411 "src/lexer-keywords.txt" +#line 413 "src/lexer-keywords.txt" {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore}, -#line 273 "src/lexer-keywords.txt" +#line 275 "src/lexer-keywords.txt" {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 563 "src/lexer-keywords.txt" - {"ref", TokenType::Ref}, {""}, {""}, -#line 404 "src/lexer-keywords.txt" - {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr}, -#line 267 "src/lexer-keywords.txt" - {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr}, - {""}, {""}, {""}, {""}, {""}, -#line 573 "src/lexer-keywords.txt" - {"return_call", TokenType::ReturnCall, Opcode::ReturnCall}, - {""}, {""}, -#line 53 "src/lexer-keywords.txt" - {"else", TokenType::Else, Opcode::Else}, - {""}, {""}, {""}, {""}, {""}, -#line 55 "src/lexer-keywords.txt" - {"tag", TokenType::Tag}, - {""}, -#line 98 "src/lexer-keywords.txt" - {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane}, -#line 565 "src/lexer-keywords.txt" - {"ref.extern", TokenType::RefExtern}, -#line 338 "src/lexer-keywords.txt" +#line 455 "src/lexer-keywords.txt" + {"i64.store8", TokenType::Store, Opcode::I64Store8}, +#line 311 "src/lexer-keywords.txt" + {"i32.store8", TokenType::Store, Opcode::I32Store8}, + {""}, {""}, {""}, {""}, +#line 340 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_u_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2UZero}, -#line 90 "src/lexer-keywords.txt" - {"f32", Type::F32}, -#line 337 "src/lexer-keywords.txt" +#line 393 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU}, +#line 339 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_s_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2SZero}, - {""}, {""}, -#line 328 "src/lexer-keywords.txt" - {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane}, - {""}, -#line 189 "src/lexer-keywords.txt" - {"get", TokenType::Get}, -#line 320 "src/lexer-keywords.txt" +#line 322 "src/lexer-keywords.txt" {"i32", Type::I32}, -#line 50 "src/lexer-keywords.txt" - {"either", TokenType::Either}, - {""}, {""}, -#line 391 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU}, -#line 435 "src/lexer-keywords.txt" - {"i64.load8_u", TokenType::Load, Opcode::I64Load8U}, -#line 292 "src/lexer-keywords.txt" - {"i32.load8_u", TokenType::Load, Opcode::I32Load8U}, -#line 434 "src/lexer-keywords.txt" - {"i64.load8_s", TokenType::Load, Opcode::I64Load8S}, -#line 291 "src/lexer-keywords.txt" - {"i32.load8_s", TokenType::Load, Opcode::I32Load8S}, +#line 330 "src/lexer-keywords.txt" + {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane}, +#line 406 "src/lexer-keywords.txt" + {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr}, +#line 269 "src/lexer-keywords.txt" + {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr}, +#line 91 "src/lexer-keywords.txt" + {"f32", Type::F32}, +#line 99 "src/lexer-keywords.txt" + {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane}, {""}, -#line 410 "src/lexer-keywords.txt" - {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8}, -#line 272 "src/lexer-keywords.txt" - {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8}, -#line 431 "src/lexer-keywords.txt" - {"i64.load16_u", TokenType::Load, Opcode::I64Load16U}, -#line 290 "src/lexer-keywords.txt" - {"i32.load16_u", TokenType::Load, Opcode::I32Load16U}, -#line 457 "src/lexer-keywords.txt" +#line 459 "src/lexer-keywords.txt" {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U}, -#line 313 "src/lexer-keywords.txt" +#line 315 "src/lexer-keywords.txt" {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U}, -#line 430 "src/lexer-keywords.txt" - {"i64.load16_s", TokenType::Load, Opcode::I64Load16S}, -#line 289 "src/lexer-keywords.txt" - {"i32.load16_s", TokenType::Load, Opcode::I32Load16S}, -#line 456 "src/lexer-keywords.txt" + {""}, {""}, +#line 458 "src/lexer-keywords.txt" {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S}, -#line 312 "src/lexer-keywords.txt" +#line 314 "src/lexer-keywords.txt" {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S}, -#line 445 "src/lexer-keywords.txt" + {""}, {""}, +#line 105 "src/lexer-keywords.txt" + {"f32x4.max", TokenType::Binary, Opcode::F32X4Max}, + {""}, {""}, +#line 161 "src/lexer-keywords.txt" + {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge}, + {""}, +#line 115 "src/lexer-keywords.txt" + {"f32x4.relaxed_min", TokenType::Binary, Opcode::F32X4RelaxedMin}, +#line 477 "src/lexer-keywords.txt" + {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS}, +#line 162 "src/lexer-keywords.txt" + {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt}, +#line 475 "src/lexer-keywords.txt" + {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS}, + {""}, {""}, +#line 163 "src/lexer-keywords.txt" + {"f64x2.le", TokenType::Compare, Opcode::F64X2Le}, + {""}, {""}, +#line 476 "src/lexer-keywords.txt" + {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS}, +#line 164 "src/lexer-keywords.txt" + {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt}, +#line 474 "src/lexer-keywords.txt" + {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS}, + {""}, {""}, {""}, {""}, {""}, +#line 598 "src/lexer-keywords.txt" + {"try", TokenType::Try, Opcode::Try}, + {""}, {""}, {""}, {""}, {""}, +#line 116 "src/lexer-keywords.txt" + {"f32x4.relaxed_nmadd", TokenType::Ternary, Opcode::F32X4RelaxedNmadd}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 207 "src/lexer-keywords.txt" + {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU}, + {""}, +#line 209 "src/lexer-keywords.txt" + {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU}, +#line 578 "src/lexer-keywords.txt" + {"return_call", TokenType::ReturnCall, Opcode::ReturnCall}, +#line 206 "src/lexer-keywords.txt" + {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS}, + {""}, +#line 208 "src/lexer-keywords.txt" + {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS}, + {""}, +#line 211 "src/lexer-keywords.txt" + {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU}, + {""}, +#line 215 "src/lexer-keywords.txt" + {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU}, +#line 390 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU}, +#line 210 "src/lexer-keywords.txt" + {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS}, +#line 592 "src/lexer-keywords.txt" + {"table.size", TokenType::TableSize, Opcode::TableSize}, +#line 214 "src/lexer-keywords.txt" + {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS}, +#line 447 "src/lexer-keywords.txt" {"i64.rem_u", TokenType::Binary, Opcode::I64RemU}, -#line 302 "src/lexer-keywords.txt" +#line 304 "src/lexer-keywords.txt" {"i32.rem_u", TokenType::Binary, Opcode::I32RemU}, -#line 444 "src/lexer-keywords.txt" +#line 446 "src/lexer-keywords.txt" {"i64.rem_s", TokenType::Binary, Opcode::I64RemS}, -#line 301 "src/lexer-keywords.txt" +#line 303 "src/lexer-keywords.txt" {"i32.rem_s", TokenType::Binary, Opcode::I32RemS}, - {""}, +#line 389 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU}, +#line 156 "src/lexer-keywords.txt" + {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil}, +#line 537 "src/lexer-keywords.txt" + {"if", TokenType::If, Opcode::If}, +#line 473 "src/lexer-keywords.txt" + {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne}, + {""}, {""}, #line 54 "src/lexer-keywords.txt" - {"end", TokenType::End, Opcode::End}, + {"else", TokenType::Else, Opcode::Else}, +#line 170 "src/lexer-keywords.txt" + {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne}, {""}, -#line 407 "src/lexer-keywords.txt" - {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor}, -#line 270 "src/lexer-keywords.txt" - {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 587 "src/lexer-keywords.txt" - {"then", TokenType::Then}, -#line 583 "src/lexer-keywords.txt" - {"table.init", TokenType::TableInit, Opcode::TableInit}, +#line 479 "src/lexer-keywords.txt" + {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg}, +#line 567 "src/lexer-keywords.txt" + {"ref", TokenType::Ref}, {""}, {""}, -#line 344 "src/lexer-keywords.txt" +#line 169 "src/lexer-keywords.txt" + {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg}, + {""}, {""}, {""}, {""}, {""}, +#line 126 "src/lexer-keywords.txt" + {"f64.ceil", TokenType::Unary, Opcode::F64Ceil}, +#line 64 "src/lexer-keywords.txt" + {"f32.ceil", TokenType::Unary, Opcode::F32Ceil}, + {""}, +#line 51 "src/lexer-keywords.txt" + {"either", TokenType::Either}, + {""}, {""}, +#line 168 "src/lexer-keywords.txt" + {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest}, +#line 346 "src/lexer-keywords.txt" {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU}, {""}, -#line 343 "src/lexer-keywords.txt" +#line 345 "src/lexer-keywords.txt" {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS}, - {""}, -#line 390 "src/lexer-keywords.txt" + {""}, {""}, {""}, +#line 392 "src/lexer-keywords.txt" {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU}, -#line 448 "src/lexer-keywords.txt" - {"i64.shl", TokenType::Binary, Opcode::I64Shl}, -#line 305 "src/lexer-keywords.txt" - {"i32.shl", TokenType::Binary, Opcode::I32Shl}, - {""}, {""}, -#line 114 "src/lexer-keywords.txt" - {"f32x4.relaxed_min", TokenType::Binary, Opcode::F32X4RelaxedMin}, {""}, -#line 115 "src/lexer-keywords.txt" - {"f32x4.relaxed_nmadd", TokenType::Ternary, Opcode::F32X4RelaxedNmadd}, -#line 140 "src/lexer-keywords.txt" - {"f64.max", TokenType::Binary, Opcode::F64Max}, -#line 79 "src/lexer-keywords.txt" - {"f32.max", TokenType::Binary, Opcode::F32Max}, - {""}, {""}, -#line 160 "src/lexer-keywords.txt" - {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge}, +#line 409 "src/lexer-keywords.txt" + {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor}, +#line 272 "src/lexer-keywords.txt" + {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor}, {""}, -#line 162 "src/lexer-keywords.txt" - {"f64x2.le", TokenType::Compare, Opcode::F64X2Le}, +#line 225 "src/lexer-keywords.txt" + {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne}, {""}, {""}, -#line 387 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU}, +#line 113 "src/lexer-keywords.txt" + {"f32x4.relaxed_madd", TokenType::Ternary, Opcode::F32X4RelaxedMadd}, + {""}, {""}, +#line 223 "src/lexer-keywords.txt" + {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg}, +#line 437 "src/lexer-keywords.txt" + {"i64.load8_u", TokenType::Load, Opcode::I64Load8U}, +#line 294 "src/lexer-keywords.txt" + {"i32.load8_u", TokenType::Load, Opcode::I32Load8U}, +#line 436 "src/lexer-keywords.txt" + {"i64.load8_s", TokenType::Load, Opcode::I64Load8S}, +#line 293 "src/lexer-keywords.txt" + {"i32.load8_s", TokenType::Load, Opcode::I32Load8S}, {""}, -#line 353 "src/lexer-keywords.txt" - {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl}, +#line 181 "src/lexer-keywords.txt" + {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc}, {""}, {""}, -#line 569 "src/lexer-keywords.txt" - {"register", TokenType::Register}, -#line 379 "src/lexer-keywords.txt" +#line 141 "src/lexer-keywords.txt" + {"f64.max", TokenType::Binary, Opcode::F64Max}, +#line 80 "src/lexer-keywords.txt" + {"f32.max", TokenType::Binary, Opcode::F32Max}, +#line 454 "src/lexer-keywords.txt" + {"i64.store32", TokenType::Store, Opcode::I64Store32}, +#line 242 "src/lexer-keywords.txt" + {"i16x8", TokenType::I16X8}, + {""}, {""}, {""}, {""}, +#line 590 "src/lexer-keywords.txt" + {"table.init", TokenType::TableInit, Opcode::TableInit}, + {""}, {""}, {""}, +#line 381 "src/lexer-keywords.txt" {"i64.atomic.load", TokenType::AtomicLoad, Opcode::I64AtomicLoad}, -#line 249 "src/lexer-keywords.txt" +#line 251 "src/lexer-keywords.txt" {"i32.atomic.load", TokenType::AtomicLoad, Opcode::I32AtomicLoad}, - {""}, {""}, {""}, -#line 161 "src/lexer-keywords.txt" - {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt}, -#line 388 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU}, -#line 163 "src/lexer-keywords.txt" - {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt}, - {""}, -#line 58 "src/lexer-keywords.txt" - {"exn", Type::ExnRef, TokenType::Exn}, - {""}, {""}, -#line 475 "src/lexer-keywords.txt" - {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS}, -#line 155 "src/lexer-keywords.txt" - {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil}, -#line 474 "src/lexer-keywords.txt" - {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS}, - {""}, {""}, {""}, {""}, {""}, -#line 473 "src/lexer-keywords.txt" - {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS}, +#line 564 "src/lexer-keywords.txt" + {"output", TokenType::Output}, +#line 568 "src/lexer-keywords.txt" + {"quote", TokenType::Quote}, +#line 594 "src/lexer-keywords.txt" + {"then", TokenType::Then}, +#line 190 "src/lexer-keywords.txt" + {"get", TokenType::Get}, {""}, -#line 472 "src/lexer-keywords.txt" - {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS}, -#line 99 "src/lexer-keywords.txt" - {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor}, +#line 563 "src/lexer-keywords.txt" + {"offset", TokenType::Offset}, +#line 56 "src/lexer-keywords.txt" + {"tag", TokenType::Tag}, {""}, {""}, -#line 185 "src/lexer-keywords.txt" - {"field", TokenType::Field}, -#line 112 "src/lexer-keywords.txt" - {"f32x4.relaxed_madd", TokenType::Ternary, Opcode::F32X4RelaxedMadd}, - {""}, {""}, {""}, {""}, {""}, -#line 419 "src/lexer-keywords.txt" - {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S}, -#line 281 "src/lexer-keywords.txt" - {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S}, - {""}, -#line 539 "src/lexer-keywords.txt" - {"item", TokenType::Item}, +#line 55 "src/lexer-keywords.txt" + {"end", TokenType::End, Opcode::End}, {""}, {""}, -#line 421 "src/lexer-keywords.txt" +#line 423 "src/lexer-keywords.txt" {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S}, -#line 282 "src/lexer-keywords.txt" +#line 284 "src/lexer-keywords.txt" {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S}, - {""}, {""}, -#line 566 "src/lexer-keywords.txt" - {"ref.func", TokenType::RefFunc, Opcode::RefFunc}, -#line 134 "src/lexer-keywords.txt" - {"f64.floor", TokenType::Unary, Opcode::F64Floor}, -#line 73 "src/lexer-keywords.txt" - {"f32.floor", TokenType::Unary, Opcode::F32Floor}, - {""}, {""}, -#line 412 "src/lexer-keywords.txt" - {"i64.clz", TokenType::Unary, Opcode::I64Clz}, -#line 274 "src/lexer-keywords.txt" - {"i32.clz", TokenType::Unary, Opcode::I32Clz}, - {""}, {""}, {""}, {""}, -#line 168 "src/lexer-keywords.txt" - {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg}, -#line 105 "src/lexer-keywords.txt" - {"f32x4.min", TokenType::Binary, Opcode::F32X4Min}, -#line 169 "src/lexer-keywords.txt" - {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne}, -#line 414 "src/lexer-keywords.txt" - {"i64.ctz", TokenType::Unary, Opcode::I64Ctz}, -#line 276 "src/lexer-keywords.txt" - {"i32.ctz", TokenType::Unary, Opcode::I32Ctz}, - {""}, {""}, -#line 477 "src/lexer-keywords.txt" - {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg}, -#line 452 "src/lexer-keywords.txt" - {"i64.store32", TokenType::Store, Opcode::I64Store32}, +#line 487 "src/lexer-keywords.txt" + {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane}, +#line 486 "src/lexer-keywords.txt" + {"i64x2.relaxed_laneselect", TokenType::Ternary, Opcode::I64X2RelaxedLaneSelect}, + {""}, +#line 194 "src/lexer-keywords.txt" + {"hidden", TokenType::Hidden}, +#line 177 "src/lexer-keywords.txt" + {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane}, +#line 575 "src/lexer-keywords.txt" + {"retain", TokenType::Retain}, +#line 467 "src/lexer-keywords.txt" + {"i64x2.add", TokenType::Binary, Opcode::I64X2Add}, + {""}, #line 471 "src/lexer-keywords.txt" - {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne}, + {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul}, +#line 33 "src/lexer-keywords.txt" + {"block", TokenType::Block, Opcode::Block}, +#line 155 "src/lexer-keywords.txt" + {"f64x2.add", TokenType::Binary, Opcode::F64X2Add}, {""}, -#line 56 "src/lexer-keywords.txt" - {"extern", Type::ExternRef, TokenType::Extern}, +#line 167 "src/lexer-keywords.txt" + {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul}, + {""}, {""}, {""}, +#line 573 "src/lexer-keywords.txt" + {"register", TokenType::Register}, +#line 412 "src/lexer-keywords.txt" + {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8}, +#line 274 "src/lexer-keywords.txt" + {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8}, #line 394 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU}, -#line 257 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU}, - {""}, {""}, -#line 392 "src/lexer-keywords.txt" {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU}, {""}, -#line 113 "src/lexer-keywords.txt" +#line 338 "src/lexer-keywords.txt" + {"i32x4.relaxed_trunc_f32x4_u", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4U}, + {""}, +#line 450 "src/lexer-keywords.txt" + {"i64.shl", TokenType::Binary, Opcode::I64Shl}, +#line 307 "src/lexer-keywords.txt" + {"i32.shl", TokenType::Binary, Opcode::I32Shl}, +#line 337 "src/lexer-keywords.txt" + {"i32x4.relaxed_trunc_f32x4_s", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4S}, +#line 114 "src/lexer-keywords.txt" {"f32x4.relaxed_max", TokenType::Binary, Opcode::F32X4RelaxedMax}, - {""}, {""}, {""}, {""}, {""}, -#line 395 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU}, -#line 258 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU}, {""}, {""}, -#line 188 "src/lexer-keywords.txt" - {"function", TokenType::Function}, -#line 401 "src/lexer-keywords.txt" - {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd}, -#line 264 "src/lexer-keywords.txt" - {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd}, - {""}, -#line 180 "src/lexer-keywords.txt" - {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc}, +#line 358 "src/lexer-keywords.txt" + {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat}, + {""}, {""}, {""}, +#line 118 "src/lexer-keywords.txt" + {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat}, +#line 228 "src/lexer-keywords.txt" + {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane}, +#line 226 "src/lexer-keywords.txt" + {"i16x8.relaxed_laneselect", TokenType::Ternary, Opcode::I16X8RelaxedLaneSelect}, {""}, {""}, -#line 393 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU}, +#line 555 "src/lexer-keywords.txt" + {"memory.size", TokenType::MemorySize, Opcode::MemorySize}, + {""}, +#line 198 "src/lexer-keywords.txt" + {"i16x8.add", TokenType::Binary, Opcode::I16X8Add}, + {""}, +#line 220 "src/lexer-keywords.txt" + {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul}, {""}, {""}, -#line 557 "src/lexer-keywords.txt" - {"nan:canonical", TokenType::NanCanonical}, +#line 355 "src/lexer-keywords.txt" + {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl}, {""}, {""}, -#line 402 "src/lexer-keywords.txt" +#line 404 "src/lexer-keywords.txt" {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd}, -#line 265 "src/lexer-keywords.txt" +#line 267 "src/lexer-keywords.txt" {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd}, -#line 154 "src/lexer-keywords.txt" - {"f64x2.add", TokenType::Binary, Opcode::F64X2Add}, -#line 167 "src/lexer-keywords.txt" - {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest}, - {""}, {""}, {""}, -#line 141 "src/lexer-keywords.txt" - {"f64.min", TokenType::Binary, Opcode::F64Min}, -#line 80 "src/lexer-keywords.txt" - {"f32.min", TokenType::Binary, Opcode::F32Min}, -#line 465 "src/lexer-keywords.txt" - {"i64x2.add", TokenType::Binary, Opcode::I64X2Add}, - {""}, {""}, -#line 400 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU}, -#line 263 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU}, - {""}, -#line 459 "src/lexer-keywords.txt" - {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U}, -#line 315 "src/lexer-keywords.txt" - {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U}, {""}, -#line 166 "src/lexer-keywords.txt" - {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul}, -#line 458 "src/lexer-keywords.txt" - {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S}, -#line 314 "src/lexer-keywords.txt" - {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S}, -#line 567 "src/lexer-keywords.txt" - {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull}, -#line 605 "src/lexer-keywords.txt" - {"v128", Type::V128}, - {""}, {""}, -#line 469 "src/lexer-keywords.txt" - {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul}, -#line 433 "src/lexer-keywords.txt" +#line 435 "src/lexer-keywords.txt" {"i64.load32_u", TokenType::Load, Opcode::I64Load32U}, {""}, {""}, {""}, -#line 432 "src/lexer-keywords.txt" +#line 434 "src/lexer-keywords.txt" {"i64.load32_s", TokenType::Load, Opcode::I64Load32S}, - {""}, {""}, {""}, {""}, -#line 556 "src/lexer-keywords.txt" - {"nan:arithmetic", TokenType::NanArithmetic}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 538 "src/lexer-keywords.txt" - {"invoke", TokenType::Invoke}, - {""}, {""}, {""}, {""}, {""}, -#line 378 "src/lexer-keywords.txt" - {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U}, -#line 248 "src/lexer-keywords.txt" - {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U}, +#line 403 "src/lexer-keywords.txt" + {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd}, +#line 266 "src/lexer-keywords.txt" + {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd}, + {""}, {""}, +#line 542 "src/lexer-keywords.txt" + {"item", TokenType::Item}, +#line 570 "src/lexer-keywords.txt" + {"ref.func", TokenType::RefFunc, Opcode::RefFunc}, {""}, -#line 176 "src/lexer-keywords.txt" - {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane}, +#line 57 "src/lexer-keywords.txt" + {"extern", Type::ExternRef, TokenType::Extern}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 485 "src/lexer-keywords.txt" - {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane}, - {""}, -#line 564 "src/lexer-keywords.txt" - {"quote", TokenType::Quote}, -#line 32 "src/lexer-keywords.txt" - {"block", TokenType::Block, Opcode::Block}, - {""}, {""}, -#line 450 "src/lexer-keywords.txt" - {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU}, -#line 307 "src/lexer-keywords.txt" - {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU}, -#line 449 "src/lexer-keywords.txt" - {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS}, -#line 306 "src/lexer-keywords.txt" - {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS}, #line 397 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU}, + {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU}, #line 260 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU}, -#line 240 "src/lexer-keywords.txt" - {"i16x8", TokenType::I16X8}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 355 "src/lexer-keywords.txt" - {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU}, -#line 346 "src/lexer-keywords.txt" - {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU}, -#line 354 "src/lexer-keywords.txt" - {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS}, -#line 345 "src/lexer-keywords.txt" - {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS}, -#line 600 "src/lexer-keywords.txt" - {"v128.or", TokenType::Binary, Opcode::V128Or}, + {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU}, +#line 433 "src/lexer-keywords.txt" + {"i64.load16_u", TokenType::Load, Opcode::I64Load16U}, +#line 292 "src/lexer-keywords.txt" + {"i32.load16_u", TokenType::Load, Opcode::I32Load16U}, {""}, -#line 560 "src/lexer-keywords.txt" - {"output", TokenType::Output}, +#line 186 "src/lexer-keywords.txt" + {"field", TokenType::Field}, +#line 432 "src/lexer-keywords.txt" + {"i64.load16_s", TokenType::Load, Opcode::I64Load16S}, +#line 291 "src/lexer-keywords.txt" + {"i32.load16_s", TokenType::Load, Opcode::I32Load16S}, +#line 396 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU}, +#line 259 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU}, + {""}, {""}, {""}, {""}, +#line 422 "src/lexer-keywords.txt" + {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S}, {""}, {""}, -#line 559 "src/lexer-keywords.txt" - {"offset", TokenType::Offset}, - {""}, -#line 592 "src/lexer-keywords.txt" - {"type", TokenType::Type}, -#line 590 "src/lexer-keywords.txt" - {"try", TokenType::Try, Opcode::Try}, +#line 59 "src/lexer-keywords.txt" + {"exn", Type::ExnRef, TokenType::Exn}, +#line 395 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU}, + {""}, {""}, {""}, {""}, +#line 100 "src/lexer-keywords.txt" + {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 421 "src/lexer-keywords.txt" + {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S}, +#line 283 "src/lexer-keywords.txt" + {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 580 "src/lexer-keywords.txt" - {"table.fill", TokenType::TableFill, Opcode::TableFill}, - {""}, -#line 484 "src/lexer-keywords.txt" - {"i64x2.relaxed_laneselect", TokenType::Ternary, Opcode::I64X2RelaxedLaneSelect}, -#line 478 "src/lexer-keywords.txt" +#line 480 "src/lexer-keywords.txt" {"i64x2.all_true", TokenType::Unary, Opcode::I64X2AllTrue}, - {""}, {""}, {""}, {""}, {""}, -#line 205 "src/lexer-keywords.txt" - {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU}, -#line 420 "src/lexer-keywords.txt" - {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S}, -#line 209 "src/lexer-keywords.txt" - {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU}, - {""}, -#line 204 "src/lexer-keywords.txt" - {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS}, -#line 40 "src/lexer-keywords.txt" - {"catch_all", TokenType::CatchAll, Opcode::CatchAll}, -#line 208 "src/lexer-keywords.txt" - {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS}, -#line 336 "src/lexer-keywords.txt" - {"i32x4.relaxed_trunc_f32x4_u", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4U}, -#line 207 "src/lexer-keywords.txt" - {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU}, - {""}, -#line 213 "src/lexer-keywords.txt" - {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU}, -#line 335 "src/lexer-keywords.txt" - {"i32x4.relaxed_trunc_f32x4_s", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4S}, -#line 206 "src/lexer-keywords.txt" - {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS}, - {""}, -#line 212 "src/lexer-keywords.txt" - {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS}, - {""}, {""}, -#line 70 "src/lexer-keywords.txt" - {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64}, - {""}, -#line 164 "src/lexer-keywords.txt" - {"f64x2.max", TokenType::Binary, Opcode::F64X2Max}, - {""}, -#line 117 "src/lexer-keywords.txt" - {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat}, -#line 604 "src/lexer-keywords.txt" - {"v128.store", TokenType::Store, Opcode::V128Store}, -#line 537 "src/lexer-keywords.txt" - {"input", TokenType::Input}, {""}, {""}, -#line 572 "src/lexer-keywords.txt" - {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect}, +#line 106 "src/lexer-keywords.txt" + {"f32x4.min", TokenType::Binary, Opcode::F32X4Min}, {""}, -#line 356 "src/lexer-keywords.txt" - {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat}, -#line 508 "src/lexer-keywords.txt" +#line 510 "src/lexer-keywords.txt" {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU}, -#line 33 "src/lexer-keywords.txt" - {"br_if", TokenType::BrIf, Opcode::BrIf}, + {""}, #line 512 "src/lexer-keywords.txt" - {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU}, + {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU}, {""}, -#line 507 "src/lexer-keywords.txt" +#line 509 "src/lexer-keywords.txt" {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS}, {""}, #line 511 "src/lexer-keywords.txt" - {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS}, + {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS}, {""}, -#line 510 "src/lexer-keywords.txt" - {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU}, -#line 536 "src/lexer-keywords.txt" - {"import", TokenType::Import}, #line 514 "src/lexer-keywords.txt" - {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU}, - {""}, -#line 509 "src/lexer-keywords.txt" - {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS}, + {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU}, {""}, +#line 516 "src/lexer-keywords.txt" + {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU}, +#line 468 "src/lexer-keywords.txt" + {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane}, #line 513 "src/lexer-keywords.txt" + {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS}, +#line 234 "src/lexer-keywords.txt" + {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU}, +#line 515 "src/lexer-keywords.txt" {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS}, - {""}, {""}, {""}, {""}, {""}, -#line 598 "src/lexer-keywords.txt" - {"v128.load", TokenType::Load, Opcode::V128Load}, -#line 158 "src/lexer-keywords.txt" +#line 159 "src/lexer-keywords.txt" {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane}, - {""}, {""}, -#line 221 "src/lexer-keywords.txt" - {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg}, - {""}, -#line 223 "src/lexer-keywords.txt" - {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne}, -#line 423 "src/lexer-keywords.txt" - {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U}, -#line 466 "src/lexer-keywords.txt" - {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane}, -#line 422 "src/lexer-keywords.txt" - {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S}, - {""}, {""}, -#line 148 "src/lexer-keywords.txt" - {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt}, -#line 86 "src/lexer-keywords.txt" - {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt}, -#line 211 "src/lexer-keywords.txt" - {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U}, {""}, -#line 210 "src/lexer-keywords.txt" - {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S}, -#line 611 "src/lexer-keywords.txt" - {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane}, -#line 406 "src/lexer-keywords.txt" - {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg}, -#line 269 "src/lexer-keywords.txt" - {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}, +#line 233 "src/lexer-keywords.txt" + {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS}, {""}, {""}, {""}, -#line 184 "src/lexer-keywords.txt" - {"f64x2", TokenType::F64X2}, - {""}, {""}, -#line 610 "src/lexer-keywords.txt" - {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat}, +#line 556 "src/lexer-keywords.txt" + {"memory", TokenType::Memory}, +#line 32 "src/lexer-keywords.txt" + {"binary", TokenType::Bin}, +#line 380 "src/lexer-keywords.txt" + {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U}, +#line 250 "src/lexer-keywords.txt" + {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U}, +#line 165 "src/lexer-keywords.txt" + {"f64x2.max", TokenType::Binary, Opcode::F64X2Max}, {""}, -#line 599 "src/lexer-keywords.txt" - {"v128.not", TokenType::Unary, Opcode::V128Not}, -#line 618 "src/lexer-keywords.txt" - {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane}, -#line 495 "src/lexer-keywords.txt" - {"i64x2", TokenType::I64X2}, -#line 118 "src/lexer-keywords.txt" - {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt}, +#line 142 "src/lexer-keywords.txt" + {"f64.min", TokenType::Binary, Opcode::F64Min}, +#line 81 "src/lexer-keywords.txt" + {"f32.min", TokenType::Binary, Opcode::F32Min}, +#line 199 "src/lexer-keywords.txt" + {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue}, +#line 175 "src/lexer-keywords.txt" + {"f64x2.relaxed_min", TokenType::Binary, Opcode::F64X2RelaxedMin}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 135 "src/lexer-keywords.txt" + {"f64.floor", TokenType::Unary, Opcode::F64Floor}, +#line 74 "src/lexer-keywords.txt" + {"f32.floor", TokenType::Unary, Opcode::F32Floor}, {""}, -#line 521 "src/lexer-keywords.txt" - {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg}, +#line 497 "src/lexer-keywords.txt" + {"i64x2", TokenType::I64X2}, + {""}, {""}, {""}, +#line 185 "src/lexer-keywords.txt" + {"f64x2", TokenType::F64X2}, {""}, -#line 523 "src/lexer-keywords.txt" - {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne}, -#line 44 "src/lexer-keywords.txt" +#line 45 "src/lexer-keywords.txt" {"data.drop", TokenType::DataDrop, Opcode::DataDrop}, + {""}, {""}, +#line 586 "src/lexer-keywords.txt" + {"table.copy", TokenType::TableCopy, Opcode::TableCopy}, +#line 176 "src/lexer-keywords.txt" + {"f64x2.relaxed_nmadd", TokenType::Ternary, Opcode::F64X2RelaxedNmadd}, + {""}, {""}, +#line 525 "src/lexer-keywords.txt" + {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne}, + {""}, {""}, {""}, {""}, {""}, +#line 523 "src/lexer-keywords.txt" + {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg}, +#line 402 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU}, +#line 265 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU}, + {""}, {""}, {""}, +#line 461 "src/lexer-keywords.txt" + {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U}, +#line 317 "src/lexer-keywords.txt" + {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U}, + {""}, {""}, +#line 460 "src/lexer-keywords.txt" + {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S}, +#line 316 "src/lexer-keywords.txt" + {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S}, + {""}, {""}, +#line 600 "src/lexer-keywords.txt" + {"type", TokenType::Type}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 451 "src/lexer-keywords.txt" - {"i64.store16", TokenType::Store, Opcode::I64Store16}, -#line 308 "src/lexer-keywords.txt" - {"i32.store16", TokenType::Store, Opcode::I32Store16}, +#line 540 "src/lexer-keywords.txt" + {"input", TokenType::Input}, {""}, -#line 186 "src/lexer-keywords.txt" - {"funcref", Type::FuncRef}, +#line 197 "src/lexer-keywords.txt" + {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU}, + {""}, {""}, +#line 571 "src/lexer-keywords.txt" + {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull}, #line 196 "src/lexer-keywords.txt" - {"i16x8.add", TokenType::Binary, Opcode::I16X8Add}, - {""}, {""}, {""}, -#line 597 "src/lexer-keywords.txt" - {"v128.const", TokenType::Const, Opcode::V128Const}, + {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS}, +#line 541 "src/lexer-keywords.txt" + {"invoke", TokenType::Invoke}, {""}, -#line 606 "src/lexer-keywords.txt" - {"v128.xor", TokenType::Binary, Opcode::V128Xor}, +#line 538 "src/lexer-keywords.txt" + {"import", TokenType::Import}, + {""}, {""}, {""}, +#line 189 "src/lexer-keywords.txt" + {"function", TokenType::Function}, {""}, {""}, {""}, {""}, {""}, -#line 174 "src/lexer-keywords.txt" - {"f64x2.relaxed_min", TokenType::Binary, Opcode::F64X2RelaxedMin}, - {""}, -#line 175 "src/lexer-keywords.txt" - {"f64x2.relaxed_nmadd", TokenType::Ternary, Opcode::F64X2RelaxedNmadd}, - {""}, -#line 218 "src/lexer-keywords.txt" - {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul}, - {""}, -#line 376 "src/lexer-keywords.txt" - {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U}, -#line 247 "src/lexer-keywords.txt" - {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U}, +#line 149 "src/lexer-keywords.txt" + {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt}, +#line 87 "src/lexer-keywords.txt" + {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 452 "src/lexer-keywords.txt" + {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU}, +#line 309 "src/lexer-keywords.txt" + {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU}, +#line 451 "src/lexer-keywords.txt" + {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS}, +#line 308 "src/lexer-keywords.txt" + {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS}, {""}, {""}, {""}, -#line 39 "src/lexer-keywords.txt" - {"catch", TokenType::Catch, Opcode::Catch}, - {""}, {""}, -#line 486 "src/lexer-keywords.txt" - {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl}, +#line 173 "src/lexer-keywords.txt" + {"f64x2.relaxed_madd", TokenType::Ternary, Opcode::F64X2RelaxedMadd}, +#line 577 "src/lexer-keywords.txt" + {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 119 "src/lexer-keywords.txt" + {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt}, {""}, {""}, -#line 500 "src/lexer-keywords.txt" +#line 528 "src/lexer-keywords.txt" + {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane}, +#line 527 "src/lexer-keywords.txt" + {"i8x16.relaxed_laneselect", TokenType::Ternary, Opcode::I8X16RelaxedLaneSelect}, + {""}, {""}, {""}, {""}, +#line 502 "src/lexer-keywords.txt" {"i8x16.add", TokenType::Binary, Opcode::I8X16Add}, - {""}, -#line 595 "src/lexer-keywords.txt" - {"v128.and", TokenType::Binary, Opcode::V128And}, +#line 217 "src/lexer-keywords.txt" + {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU}, +#line 357 "src/lexer-keywords.txt" + {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU}, +#line 216 "src/lexer-keywords.txt" + {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS}, +#line 356 "src/lexer-keywords.txt" + {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS}, +#line 399 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU}, +#line 262 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU}, +#line 559 "src/lexer-keywords.txt" + {"nan:arithmetic", TokenType::NanArithmetic}, + {""}, {""}, {""}, {""}, {""}, +#line 583 "src/lexer-keywords.txt" + {"start", TokenType::Start}, {""}, {""}, {""}, {""}, -#line 534 "src/lexer-keywords.txt" - {"i8x16", TokenType::I8X16}, - {""}, {""}, -#line 52 "src/lexer-keywords.txt" - {"elem", TokenType::Elem}, +#line 348 "src/lexer-keywords.txt" + {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU}, {""}, -#line 57 "src/lexer-keywords.txt" - {"externref", Type::ExternRef}, - {""}, {""}, -#line 594 "src/lexer-keywords.txt" - {"v128.andnot", TokenType::Binary, Opcode::V128Andnot}, +#line 347 "src/lexer-keywords.txt" + {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS}, +#line 21 "src/lexer-keywords.txt" + {"after", TokenType::After}, +#line 124 "src/lexer-keywords.txt" + {"f64.abs", TokenType::Unary, Opcode::F64Abs}, +#line 62 "src/lexer-keywords.txt" + {"f32.abs", TokenType::Unary, Opcode::F32Abs}, {""}, {""}, -#line 384 "src/lexer-keywords.txt" +#line 71 "src/lexer-keywords.txt" + {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64}, + {""}, {""}, {""}, {""}, {""}, +#line 112 "src/lexer-keywords.txt" + {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin}, + {""}, {""}, {""}, +#line 614 "src/lexer-keywords.txt" + {"v128", Type::V128}, +#line 386 "src/lexer-keywords.txt" {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU}, -#line 254 "src/lexer-keywords.txt" +#line 256 "src/lexer-keywords.txt" {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU}, - {""}, -#line 226 "src/lexer-keywords.txt" - {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane}, - {""}, {""}, -#line 159 "src/lexer-keywords.txt" - {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor}, - {""}, {""}, -#line 468 "src/lexer-keywords.txt" - {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U}, -#line 172 "src/lexer-keywords.txt" - {"f64x2.relaxed_madd", TokenType::Ternary, Opcode::F64X2RelaxedMadd}, - {""}, {""}, -#line 467 "src/lexer-keywords.txt" - {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 560 "src/lexer-keywords.txt" + {"nan:canonical", TokenType::NanCanonical}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 36 "src/lexer-keywords.txt" - {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect}, +#line 174 "src/lexer-keywords.txt" + {"f64x2.relaxed_max", TokenType::Binary, Opcode::F64X2RelaxedMax}, {""}, -#line 526 "src/lexer-keywords.txt" - {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane}, +#line 359 "src/lexer-keywords.txt" + {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub}, +#line 491 "src/lexer-keywords.txt" + {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat}, +#line 324 "src/lexer-keywords.txt" + {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs}, + {""}, +#line 120 "src/lexer-keywords.txt" + {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub}, +#line 178 "src/lexer-keywords.txt" + {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat}, +#line 92 "src/lexer-keywords.txt" + {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs}, + {""}, +#line 35 "src/lexer-keywords.txt" + {"br_table", TokenType::BrTable, Opcode::BrTable}, {""}, {""}, {""}, {""}, {""}, -#line 165 "src/lexer-keywords.txt" - {"f64x2.min", TokenType::Binary, Opcode::F64X2Min}, -#line 383 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU}, -#line 253 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 224 "src/lexer-keywords.txt" - {"i16x8.relaxed_laneselect", TokenType::Ternary, Opcode::I16X8RelaxedLaneSelect}, -#line 197 "src/lexer-keywords.txt" - {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue}, +#line 613 "src/lexer-keywords.txt" + {"v128.store", TokenType::Store, Opcode::V128Store}, +#line 41 "src/lexer-keywords.txt" + {"catch_all", TokenType::CatchAll, Opcode::CatchAll}, +#line 587 "src/lexer-keywords.txt" + {"table.fill", TokenType::TableFill, Opcode::TableFill}, +#line 488 "src/lexer-keywords.txt" + {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl}, + {""}, +#line 609 "src/lexer-keywords.txt" + {"v128.or", TokenType::Binary, Opcode::V128Or}, {""}, {""}, -#line 21 "src/lexer-keywords.txt" - {"after", TokenType::After}, #line 552 "src/lexer-keywords.txt" - {"memory.size", TokenType::MemorySize, Opcode::MemorySize}, -#line 173 "src/lexer-keywords.txt" - {"f64x2.relaxed_max", TokenType::Binary, Opcode::F64X2RelaxedMax}, -#line 380 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU}, -#line 250 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU}, -#line 399 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU}, -#line 262 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU}, -#line 232 "src/lexer-keywords.txt" - {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU}, - {""}, {""}, {""}, -#line 231 "src/lexer-keywords.txt" - {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS}, - {""}, {""}, {""}, -#line 381 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU}, -#line 251 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU}, -#line 347 "src/lexer-keywords.txt" - {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S}, + {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill}, +#line 408 "src/lexer-keywords.txt" + {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg}, +#line 271 "src/lexer-keywords.txt" + {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}, +#line 425 "src/lexer-keywords.txt" + {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U}, {""}, -#line 389 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU}, +#line 424 "src/lexer-keywords.txt" + {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S}, {""}, {""}, {""}, {""}, {""}, -#line 525 "src/lexer-keywords.txt" - {"i8x16.relaxed_laneselect", TokenType::Ternary, Opcode::I8X16RelaxedLaneSelect}, -#line 501 "src/lexer-keywords.txt" - {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue}, - {""}, {""}, {""}, {""}, -#line 577 "src/lexer-keywords.txt" - {"start", TokenType::Start}, - {""}, -#line 123 "src/lexer-keywords.txt" - {"f64.abs", TokenType::Unary, Opcode::F64Abs}, -#line 61 "src/lexer-keywords.txt" - {"f32.abs", TokenType::Unary, Opcode::F32Abs}, +#line 34 "src/lexer-keywords.txt" + {"br_if", TokenType::BrIf, Opcode::BrIf}, {""}, -#line 532 "src/lexer-keywords.txt" +#line 232 "src/lexer-keywords.txt" + {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 534 "src/lexer-keywords.txt" {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU}, {""}, {""}, {""}, -#line 531 "src/lexer-keywords.txt" +#line 533 "src/lexer-keywords.txt" {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS}, -#line 616 "src/lexer-keywords.txt" - {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 119 "src/lexer-keywords.txt" - {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub}, + {""}, {""}, {""}, {""}, +#line 229 "src/lexer-keywords.txt" + {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl}, +#line 383 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU}, +#line 253 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU}, {""}, {""}, -#line 91 "src/lexer-keywords.txt" - {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs}, +#line 627 "src/lexer-keywords.txt" + {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane}, {""}, -#line 608 "src/lexer-keywords.txt" - {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat}, -#line 562 "src/lexer-keywords.txt" - {"param", TokenType::Param}, -#line 357 "src/lexer-keywords.txt" - {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub}, -#line 96 "src/lexer-keywords.txt" - {"f32x4.div", TokenType::Binary, Opcode::F32X4Div}, -#line 602 "src/lexer-keywords.txt" - {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero}, -#line 322 "src/lexer-keywords.txt" - {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs}, -#line 34 "src/lexer-keywords.txt" - {"br_table", TokenType::BrTable, Opcode::BrTable}, - {""}, {""}, {""}, -#line 195 "src/lexer-keywords.txt" - {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU}, - {""}, {""}, {""}, -#line 194 "src/lexer-keywords.txt" - {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS}, +#line 503 "src/lexer-keywords.txt" + {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue}, {""}, -#line 111 "src/lexer-keywords.txt" - {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin}, -#line 31 "src/lexer-keywords.txt" - {"binary", TokenType::Bin}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 463 "src/lexer-keywords.txt" - {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U}, -#line 319 "src/lexer-keywords.txt" - {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U}, +#line 382 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU}, +#line 252 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU}, + {""}, {""}, {""}, +#line 160 "src/lexer-keywords.txt" + {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 608 "src/lexer-keywords.txt" + {"v128.not", TokenType::Unary, Opcode::V128Not}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 200 "src/lexer-keywords.txt" + {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU}, +#line 205 "src/lexer-keywords.txt" + {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU}, + {""}, +#line 204 "src/lexer-keywords.txt" + {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS}, +#line 22 "src/lexer-keywords.txt" + {"align", TokenType::Align}, +#line 166 "src/lexer-keywords.txt" + {"f64x2.min", TokenType::Binary, Opcode::F64X2Min}, +#line 58 "src/lexer-keywords.txt" + {"externref", Type::ExternRef}, + {""}, {""}, #line 385 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU}, + {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU}, #line 255 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU}, -#line 462 "src/lexer-keywords.txt" - {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S}, -#line 318 "src/lexer-keywords.txt" - {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S}, + {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU}, + {""}, +#line 607 "src/lexer-keywords.txt" + {"v128.load", TokenType::Load, Opcode::V128Load}, {""}, {""}, -#line 613 "src/lexer-keywords.txt" - {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 499 "src/lexer-keywords.txt" - {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU}, -#line 377 "src/lexer-keywords.txt" - {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U}, +#line 602 "src/lexer-keywords.txt" + {"weak", TokenType::Weak}, {""}, -#line 615 "src/lexer-keywords.txt" - {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane}, -#line 498 "src/lexer-keywords.txt" +#line 599 "src/lexer-keywords.txt" + {"try_table", TokenType::TryTable, Opcode::TryTable}, + {""}, {""}, {""}, {""}, {""}, +#line 581 "src/lexer-keywords.txt" + {"shared", TokenType::Shared}, +#line 606 "src/lexer-keywords.txt" + {"v128.const", TokenType::Const, Opcode::V128Const}, + {""}, {""}, +#line 50 "src/lexer-keywords.txt" + {"drop", TokenType::Drop, Opcode::Drop}, + {""}, {""}, {""}, +#line 501 "src/lexer-keywords.txt" + {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU}, + {""}, {""}, +#line 604 "src/lexer-keywords.txt" + {"v128.and", TokenType::Binary, Opcode::V128And}, +#line 500 "src/lexer-keywords.txt" {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS}, {""}, -#line 386 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU}, -#line 256 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU}, +#line 187 "src/lexer-keywords.txt" + {"funcref", Type::FuncRef}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 536 "src/lexer-keywords.txt" + {"i8x16", TokenType::I8X16}, +#line 619 "src/lexer-keywords.txt" + {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat}, + {""}, {""}, +#line 420 "src/lexer-keywords.txt" + {"i64.eqz", TokenType::Convert, Opcode::I64Eqz}, +#line 282 "src/lexer-keywords.txt" + {"i32.eqz", TokenType::Convert, Opcode::I32Eqz}, {""}, -#line 192 "src/lexer-keywords.txt" - {"global", TokenType::Global}, -#line 215 "src/lexer-keywords.txt" - {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU}, +#line 620 "src/lexer-keywords.txt" + {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane}, +#line 453 "src/lexer-keywords.txt" + {"i64.store16", TokenType::Store, Opcode::I64Store16}, +#line 310 "src/lexer-keywords.txt" + {"i32.store16", TokenType::Store, Opcode::I32Store16}, +#line 53 "src/lexer-keywords.txt" + {"elem", TokenType::Elem}, {""}, -#line 214 "src/lexer-keywords.txt" - {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS}, +#line 111 "src/lexer-keywords.txt" + {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 379 "src/lexer-keywords.txt" + {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U}, {""}, {""}, {""}, {""}, -#line 488 "src/lexer-keywords.txt" - {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU}, +#line 603 "src/lexer-keywords.txt" + {"v128.andnot", TokenType::Binary, Opcode::V128Andnot}, +#line 193 "src/lexer-keywords.txt" + {"global", TokenType::Global}, +#line 192 "src/lexer-keywords.txt" + {"global.set", TokenType::GlobalSet, Opcode::GlobalSet}, +#line 411 "src/lexer-keywords.txt" + {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32}, {""}, -#line 487 "src/lexer-keywords.txt" - {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS}, +#line 191 "src/lexer-keywords.txt" + {"global.get", TokenType::GlobalGet, Opcode::GlobalGet}, +#line 391 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU}, {""}, -#line 549 "src/lexer-keywords.txt" - {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill}, - {""}, {""}, {""}, {""}, -#line 326 "src/lexer-keywords.txt" - {"i32x4.relaxed_dot_i8x16_i7x16_add_s", TokenType::Ternary, Opcode::I32X4DotI8X16I7X16AddS}, -#line 41 "src/lexer-keywords.txt" - {"catch_ref", TokenType::CatchRef}, - {""}, {""}, {""}, -#line 579 "src/lexer-keywords.txt" - {"table.copy", TokenType::TableCopy, Opcode::TableCopy}, +#line 387 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU}, +#line 257 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU}, {""}, -#line 227 "src/lexer-keywords.txt" - {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl}, - {""}, {""}, {""}, {""}, {""}, -#line 516 "src/lexer-keywords.txt" +#line 566 "src/lexer-keywords.txt" + {"param", TokenType::Param}, +#line 615 "src/lexer-keywords.txt" + {"v128.xor", TokenType::Binary, Opcode::V128Xor}, +#line 97 "src/lexer-keywords.txt" + {"f32x4.div", TokenType::Binary, Opcode::F32X4Div}, + {""}, {""}, +#line 378 "src/lexer-keywords.txt" + {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U}, +#line 249 "src/lexer-keywords.txt" + {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U}, +#line 518 "src/lexer-keywords.txt" {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU}, {""}, -#line 515 "src/lexer-keywords.txt" +#line 517 "src/lexer-keywords.txt" {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS}, - {""}, {""}, -#line 576 "src/lexer-keywords.txt" - {"shared", TokenType::Shared}, -#line 130 "src/lexer-keywords.txt" + {""}, {""}, {""}, +#line 470 "src/lexer-keywords.txt" + {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U}, + {""}, {""}, {""}, +#line 469 "src/lexer-keywords.txt" + {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S}, + {""}, {""}, {""}, {""}, {""}, +#line 37 "src/lexer-keywords.txt" + {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 131 "src/lexer-keywords.txt" {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U}, -#line 68 "src/lexer-keywords.txt" +#line 69 "src/lexer-keywords.txt" {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U}, - {""}, {""}, -#line 129 "src/lexer-keywords.txt" +#line 465 "src/lexer-keywords.txt" + {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U}, +#line 321 "src/lexer-keywords.txt" + {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U}, +#line 130 "src/lexer-keywords.txt" {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S}, -#line 67 "src/lexer-keywords.txt" +#line 68 "src/lexer-keywords.txt" {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S}, - {""}, {""}, {""}, {""}, {""}, -#line 60 "src/lexer-keywords.txt" - {"export", TokenType::Export}, - {""}, {""}, {""}, {""}, {""}, -#line 527 "src/lexer-keywords.txt" - {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl}, -#line 553 "src/lexer-keywords.txt" - {"memory", TokenType::Memory}, -#line 593 "src/lexer-keywords.txt" - {"unreachable", TokenType::Unreachable, Opcode::Unreachable}, +#line 464 "src/lexer-keywords.txt" + {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S}, +#line 320 "src/lexer-keywords.txt" + {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S}, {""}, -#line 177 "src/lexer-keywords.txt" - {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat}, -#line 110 "src/lexer-keywords.txt" - {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax}, -#line 372 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero}, +#line 40 "src/lexer-keywords.txt" + {"catch", TokenType::Catch, Opcode::Catch}, + {""}, {""}, {""}, +#line 213 "src/lexer-keywords.txt" + {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U}, {""}, -#line 371 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero}, +#line 212 "src/lexer-keywords.txt" + {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S}, {""}, -#line 190 "src/lexer-keywords.txt" - {"global.get", TokenType::GlobalGet, Opcode::GlobalGet}, -#line 489 "src/lexer-keywords.txt" - {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat}, -#line 191 "src/lexer-keywords.txt" - {"global.set", TokenType::GlobalSet, Opcode::GlobalSet}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 409 "src/lexer-keywords.txt" - {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32}, - {""}, {""}, -#line 59 "src/lexer-keywords.txt" - {"exnref", Type::ExnRef}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 609 "src/lexer-keywords.txt" - {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat}, -#line 617 "src/lexer-keywords.txt" - {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane}, -#line 178 "src/lexer-keywords.txt" +#line 610 "src/lexer-keywords.txt" + {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 179 "src/lexer-keywords.txt" {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt}, -#line 588 "src/lexer-keywords.txt" - {"throw", TokenType::Throw, Opcode::Throw}, -#line 603 "src/lexer-keywords.txt" - {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero}, - {""}, {""}, {""}, {""}, -#line 37 "src/lexer-keywords.txt" - {"call_ref", TokenType::CallRef, Opcode::CallRef}, - {""}, {""}, -#line 551 "src/lexer-keywords.txt" - {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit}, -#line 416 "src/lexer-keywords.txt" - {"i64.div_u", TokenType::Binary, Opcode::I64DivU}, -#line 278 "src/lexer-keywords.txt" - {"i32.div_u", TokenType::Binary, Opcode::I32DivU}, -#line 415 "src/lexer-keywords.txt" - {"i64.div_s", TokenType::Binary, Opcode::I64DivS}, -#line 277 "src/lexer-keywords.txt" - {"i32.div_s", TokenType::Binary, Opcode::I32DivS}, - {""}, {""}, {""}, {""}, -#line 418 "src/lexer-keywords.txt" - {"i64.eqz", TokenType::Convert, Opcode::I64Eqz}, -#line 280 "src/lexer-keywords.txt" - {"i32.eqz", TokenType::Convert, Opcode::I32Eqz}, {""}, {""}, -#line 589 "src/lexer-keywords.txt" - {"throw_ref", TokenType::ThrowRef, Opcode::ThrowRef}, - {""}, -#line 203 "src/lexer-keywords.txt" - {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU}, +#line 601 "src/lexer-keywords.txt" + {"unreachable", TokenType::Unreachable, Opcode::Unreachable}, +#line 349 "src/lexer-keywords.txt" + {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S}, + {""}, {""}, {""}, +#line 388 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU}, +#line 258 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU}, {""}, -#line 202 "src/lexer-keywords.txt" - {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS}, - {""}, {""}, -#line 614 "src/lexer-keywords.txt" - {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane}, -#line 396 "src/lexer-keywords.txt" +#line 490 "src/lexer-keywords.txt" + {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU}, + {""}, +#line 489 "src/lexer-keywords.txt" + {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS}, + {""}, {""}, {""}, {""}, +#line 398 "src/lexer-keywords.txt" {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU}, -#line 259 "src/lexer-keywords.txt" +#line 261 "src/lexer-keywords.txt" {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 408 "src/lexer-keywords.txt" - {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16}, -#line 271 "src/lexer-keywords.txt" - {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16}, + {""}, {""}, {""}, {""}, {""}, +#line 547 "src/lexer-keywords.txt" + {"loop", TokenType::Loop, Opcode::Loop}, +#line 401 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU}, +#line 264 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU}, + {""}, {""}, {""}, {""}, +#line 532 "src/lexer-keywords.txt" + {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat}, {""}, {""}, -#line 591 "src/lexer-keywords.txt" - {"try_table", TokenType::TryTable, Opcode::TryTable}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 601 "src/lexer-keywords.txt" - {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue}, - {""}, -#line 506 "src/lexer-keywords.txt" - {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU}, -#line 366 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U}, -#line 505 "src/lexer-keywords.txt" - {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS}, +#line 444 "src/lexer-keywords.txt" + {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt}, +#line 301 "src/lexer-keywords.txt" + {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt}, {""}, {""}, -#line 365 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S}, - {""}, {""}, {""}, {""}, -#line 49 "src/lexer-keywords.txt" - {"drop", TokenType::Drop, Opcode::Drop}, +#line 405 "src/lexer-keywords.txt" + {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg}, +#line 268 "src/lexer-keywords.txt" + {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg}, +#line 172 "src/lexer-keywords.txt" + {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin}, {""}, {""}, {""}, -#line 582 "src/lexer-keywords.txt" - {"table.grow", TokenType::TableGrow, Opcode::TableGrow}, - {""}, {""}, -#line 571 "src/lexer-keywords.txt" - {"rethrow", TokenType::Rethrow, Opcode::Rethrow}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 229 "src/lexer-keywords.txt" +#line 231 "src/lexer-keywords.txt" {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU}, -#line 217 "src/lexer-keywords.txt" - {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU}, -#line 228 "src/lexer-keywords.txt" + {""}, +#line 230 "src/lexer-keywords.txt" {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS}, -#line 216 "src/lexer-keywords.txt" +#line 529 "src/lexer-keywords.txt" + {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 554 "src/lexer-keywords.txt" + {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit}, +#line 617 "src/lexer-keywords.txt" + {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat}, +#line 492 "src/lexer-keywords.txt" + {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub}, + {""}, +#line 478 "src/lexer-keywords.txt" + {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs}, +#line 219 "src/lexer-keywords.txt" + {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU}, +#line 180 "src/lexer-keywords.txt" + {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub}, +#line 218 "src/lexer-keywords.txt" {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS}, - {""}, {""}, {""}, {""}, {""}, -#line 403 "src/lexer-keywords.txt" - {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg}, -#line 266 "src/lexer-keywords.txt" - {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg}, +#line 154 "src/lexer-keywords.txt" + {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs}, {""}, -#line 121 "src/lexer-keywords.txt" - {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero}, +#line 27 "src/lexer-keywords.txt" + {"assert_return", TokenType::AssertReturn}, +#line 61 "src/lexer-keywords.txt" + {"export", TokenType::Export}, {""}, {""}, -#line 42 "src/lexer-keywords.txt" - {"catch_all_ref", TokenType::CatchAllRef}, +#line 368 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U}, + {""}, {""}, {""}, +#line 367 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S}, + {""}, {""}, {""}, {""}, {""}, +#line 504 "src/lexer-keywords.txt" + {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU}, +#line 508 "src/lexer-keywords.txt" + {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU}, + {""}, +#line 507 "src/lexer-keywords.txt" + {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS}, + {""}, {""}, {""}, {""}, {""}, +#line 551 "src/lexer-keywords.txt" + {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy}, +#line 624 "src/lexer-keywords.txt" + {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane}, + {""}, +#line 235 "src/lexer-keywords.txt" + {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub}, + {""}, +#line 195 "src/lexer-keywords.txt" + {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 622 "src/lexer-keywords.txt" + {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 529 "src/lexer-keywords.txt" - {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU}, -#line 518 "src/lexer-keywords.txt" - {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU}, -#line 528 "src/lexer-keywords.txt" - {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS}, -#line 517 "src/lexer-keywords.txt" - {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS}, {""}, {""}, {""}, -#line 26 "src/lexer-keywords.txt" - {"assert_return", TokenType::AssertReturn}, -#line 550 "src/lexer-keywords.txt" - {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow}, +#line 626 "src/lexer-keywords.txt" + {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 539 "src/lexer-keywords.txt" + {"init_prio", TokenType::InitPrio}, {""}, {""}, {""}, {""}, -#line 398 "src/lexer-keywords.txt" +#line 400 "src/lexer-keywords.txt" {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU}, -#line 261 "src/lexer-keywords.txt" +#line 263 "src/lexer-keywords.txt" {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU}, +#line 418 "src/lexer-keywords.txt" + {"i64.div_u", TokenType::Binary, Opcode::I64DivU}, +#line 280 "src/lexer-keywords.txt" + {"i32.div_u", TokenType::Binary, Opcode::I32DivU}, +#line 417 "src/lexer-keywords.txt" + {"i64.div_s", TokenType::Binary, Opcode::I64DivS}, +#line 279 "src/lexer-keywords.txt" + {"i32.div_s", TokenType::Binary, Opcode::I32DivS}, +#line 625 "src/lexer-keywords.txt" + {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 611 "src/lexer-keywords.txt" + {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 198 "src/lexer-keywords.txt" - {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU}, -#line 230 "src/lexer-keywords.txt" - {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat}, {""}, {""}, {""}, -#line 340 "src/lexer-keywords.txt" - {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U}, +#line 42 "src/lexer-keywords.txt" + {"catch_ref", TokenType::CatchRef}, {""}, -#line 558 "src/lexer-keywords.txt" - {"nop", TokenType::Nop, Opcode::Nop}, +#line 553 "src/lexer-keywords.txt" + {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow}, +#line 524 "src/lexer-keywords.txt" + {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 339 "src/lexer-keywords.txt" - {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 179 "src/lexer-keywords.txt" - {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub}, +#line 526 "src/lexer-keywords.txt" + {"i8x16.relaxed_swizzle", TokenType::Binary, Opcode::I8X16RelaxedSwizzle}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 227 "src/lexer-keywords.txt" + {"i16x8.relaxed_q15mulr_s", TokenType::Binary, Opcode::I16X8RelaxedQ15mulrS}, + {""}, {""}, {""}, {""}, {""}, +#line 171 "src/lexer-keywords.txt" + {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax}, {""}, {""}, -#line 153 "src/lexer-keywords.txt" - {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs}, - {""}, {""}, {""}, -#line 490 "src/lexer-keywords.txt" - {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub}, -#line 156 "src/lexer-keywords.txt" - {"f64x2.div", TokenType::Binary, Opcode::F64X2Div}, +#line 20 "src/lexer-keywords.txt" + {"array", Type::Array, TokenType::Array}, {""}, -#line 476 "src/lexer-keywords.txt" - {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs}, -#line 502 "src/lexer-keywords.txt" - {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU}, -#line 530 "src/lexer-keywords.txt" - {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 171 "src/lexer-keywords.txt" - {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin}, +#line 328 "src/lexer-keywords.txt" + {"i32x4.relaxed_dot_i8x16_i7x16_add_s", TokenType::Ternary, Opcode::I32X4DotI8X16I7X16AddS}, {""}, {""}, -#line 544 "src/lexer-keywords.txt" - {"loop", TokenType::Loop, Opcode::Loop}, +#line 562 "src/lexer-keywords.txt" + {"nop", TokenType::Nop, Opcode::Nop}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 157 "src/lexer-keywords.txt" + {"f64x2.div", TokenType::Binary, Opcode::F64X2Div}, {""}, {""}, {""}, {""}, {""}, -#line 461 "src/lexer-keywords.txt" +#line 38 "src/lexer-keywords.txt" + {"call_ref", TokenType::CallRef, Opcode::CallRef}, + {""}, {""}, {""}, {""}, +#line 374 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero}, + {""}, +#line 373 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 327 "src/lexer-keywords.txt" + {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask}, + {""}, +#line 129 "src/lexer-keywords.txt" + {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U}, +#line 67 "src/lexer-keywords.txt" + {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U}, +#line 463 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U}, -#line 317 "src/lexer-keywords.txt" +#line 319 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U}, -#line 133 "src/lexer-keywords.txt" - {"f64.eq", TokenType::Compare, Opcode::F64Eq}, -#line 72 "src/lexer-keywords.txt" - {"f32.eq", TokenType::Compare, Opcode::F32Eq}, -#line 460 "src/lexer-keywords.txt" +#line 128 "src/lexer-keywords.txt" + {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S}, +#line 66 "src/lexer-keywords.txt" + {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S}, +#line 462 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S}, -#line 316 "src/lexer-keywords.txt" +#line 318 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S}, +#line 531 "src/lexer-keywords.txt" + {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU}, + {""}, +#line 530 "src/lexer-keywords.txt" + {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS}, + {""}, {""}, {""}, {""}, {""}, +#line 60 "src/lexer-keywords.txt" + {"exnref", Type::ExnRef}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 520 "src/lexer-keywords.txt" + {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU}, + {""}, +#line 519 "src/lexer-keywords.txt" + {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 132 "src/lexer-keywords.txt" + {"f64.copysign", TokenType::Binary, Opcode::F64Copysign}, +#line 70 "src/lexer-keywords.txt" + {"f32.copysign", TokenType::Binary, Opcode::F32Copysign}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 417 "src/lexer-keywords.txt" +#line 596 "src/lexer-keywords.txt" + {"throw_ref", TokenType::ThrowRef, Opcode::ThrowRef}, + {""}, {""}, {""}, {""}, {""}, +#line 535 "src/lexer-keywords.txt" + {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub}, +#line 26 "src/lexer-keywords.txt" + {"assert_malformed", TokenType::AssertMalformed}, +#line 499 "src/lexer-keywords.txt" + {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 419 "src/lexer-keywords.txt" {"i64.eq", TokenType::Compare, Opcode::I64Eq}, -#line 279 "src/lexer-keywords.txt" +#line 281 "src/lexer-keywords.txt" {"i32.eq", TokenType::Compare, Opcode::I32Eq}, -#line 325 "src/lexer-keywords.txt" - {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask}, - {""}, {""}, {""}, {""}, -#line 442 "src/lexer-keywords.txt" - {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt}, -#line 299 "src/lexer-keywords.txt" - {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt}, {""}, {""}, -#line 382 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU}, -#line 252 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU}, +#line 134 "src/lexer-keywords.txt" + {"f64.eq", TokenType::Compare, Opcode::F64Eq}, +#line 73 "src/lexer-keywords.txt" + {"f32.eq", TokenType::Compare, Opcode::F32Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 97 "src/lexer-keywords.txt" + {""}, {""}, +#line 595 "src/lexer-keywords.txt" + {"throw", TokenType::Throw, Opcode::Throw}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 329 "src/lexer-keywords.txt" + {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq}, + {""}, {""}, {""}, +#line 98 "src/lexer-keywords.txt" {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 327 "src/lexer-keywords.txt" - {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq}, +#line 384 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU}, +#line 254 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU}, + {""}, +#line 618 "src/lexer-keywords.txt" + {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat}, +#line 629 "src/lexer-keywords.txt" + {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle}, + {""}, {""}, +#line 133 "src/lexer-keywords.txt" + {"f64.div", TokenType::Binary, Opcode::F64Div}, +#line 72 "src/lexer-keywords.txt" + {"f32.div", TokenType::Binary, Opcode::F32Div}, + {""}, +#line 589 "src/lexer-keywords.txt" + {"table.grow", TokenType::TableGrow, Opcode::TableGrow}, + {""}, {""}, +#line 43 "src/lexer-keywords.txt" + {"catch_all_ref", TokenType::CatchAllRef}, + {""}, {""}, {""}, {""}, +#line 342 "src/lexer-keywords.txt" + {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U}, + {""}, {""}, {""}, +#line 341 "src/lexer-keywords.txt" + {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S}, + {""}, {""}, {""}, +#line 52 "src/lexer-keywords.txt" + {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 410 "src/lexer-keywords.txt" + {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16}, +#line 273 "src/lexer-keywords.txt" + {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16}, + {""}, +#line 28 "src/lexer-keywords.txt" + {"assert_trap", TokenType::AssertTrap}, {""}, {""}, {""}, {""}, {""}, -#line 482 "src/lexer-keywords.txt" +#line 623 "src/lexer-keywords.txt" + {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 628 "src/lexer-keywords.txt" + {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 484 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendLowI32X4U}, {""}, -#line 480 "src/lexer-keywords.txt" +#line 482 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendLowI32X4S}, -#line 522 "src/lexer-keywords.txt" - {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt}, {""}, {""}, -#line 607 "src/lexer-keywords.txt" +#line 576 "src/lexer-keywords.txt" + {"rethrow", TokenType::Rethrow, Opcode::Rethrow}, + {""}, {""}, +#line 122 "src/lexer-keywords.txt" + {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 457 "src/lexer-keywords.txt" + {"i64.sub", TokenType::Binary, Opcode::I64Sub}, +#line 313 "src/lexer-keywords.txt" + {"i32.sub", TokenType::Binary, Opcode::I32Sub}, + {""}, {""}, +#line 151 "src/lexer-keywords.txt" + {"f64.sub", TokenType::Binary, Opcode::F64Sub}, +#line 89 "src/lexer-keywords.txt" + {"f32.sub", TokenType::Binary, Opcode::F32Sub}, + {""}, +#line 612 "src/lexer-keywords.txt" + {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 616 "src/lexer-keywords.txt" {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat}, + {""}, {""}, {""}, +#line 96 "src/lexer-keywords.txt" + {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U}, + {""}, +#line 95 "src/lexer-keywords.txt" + {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S}, +#line 202 "src/lexer-keywords.txt" + {"i16x8.relaxed_dot_i8x16_i7x16_s", TokenType::Binary, Opcode::I16X8DotI8X16I7X16S}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 222 "src/lexer-keywords.txt" + {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U}, + {""}, +#line 221 "src/lexer-keywords.txt" + {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S}, {""}, {""}, {""}, {""}, {""}, -#line 128 "src/lexer-keywords.txt" - {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U}, -#line 66 "src/lexer-keywords.txt" - {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U}, - {""}, {""}, -#line 127 "src/lexer-keywords.txt" - {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S}, -#line 65 "src/lexer-keywords.txt" - {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S}, +#line 495 "src/lexer-keywords.txt" + {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U}, {""}, -#line 368 "src/lexer-keywords.txt" - {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U}, +#line 493 "src/lexer-keywords.txt" + {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S}, {""}, -#line 367 "src/lexer-keywords.txt" - {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S}, +#line 481 "src/lexer-keywords.txt" + {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask}, +#line 323 "src/lexer-keywords.txt" + {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 170 "src/lexer-keywords.txt" - {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax}, - {""}, {""}, {""}, {""}, -#line 612 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 621 "src/lexer-keywords.txt" {"v128.load16_lane", TokenType::SimdLoadLane, Opcode::V128Load16Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 147 "src/lexer-keywords.txt" + {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32}, {""}, {""}, -#line 619 "src/lexer-keywords.txt" - {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle}, - {""}, {""}, -#line 359 "src/lexer-keywords.txt" - {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U}, +#line 201 "src/lexer-keywords.txt" + {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 246 "src/lexer-keywords.txt" + {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U}, {""}, -#line 358 "src/lexer-keywords.txt" - {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S}, - {""}, {""}, -#line 25 "src/lexer-keywords.txt" - {"assert_malformed", TokenType::AssertMalformed}, - {""}, {""}, {""}, -#line 51 "src/lexer-keywords.txt" - {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop}, +#line 245 "src/lexer-keywords.txt" + {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S}, +#line 565 "src/lexer-keywords.txt" + {"pagesize", TokenType::PageSize}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 493 "src/lexer-keywords.txt" - {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U}, -#line 524 "src/lexer-keywords.txt" - {"i8x16.relaxed_swizzle", TokenType::Binary, Opcode::I8X16RelaxedSwizzle}, -#line 491 "src/lexer-keywords.txt" - {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S}, - {""}, {""}, {""}, {""}, {""}, -#line 370 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, +#line 148 "src/lexer-keywords.txt" + {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 372 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendLowI16X8U}, {""}, -#line 369 "src/lexer-keywords.txt" +#line 371 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendLowI16X8S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 363 "src/lexer-keywords.txt" - {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U}, - {""}, -#line 361 "src/lexer-keywords.txt" - {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S}, - {""}, -#line 147 "src/lexer-keywords.txt" - {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64}, - {""}, {""}, -#line 321 "src/lexer-keywords.txt" - {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64}, - {""}, {""}, {""}, {""}, -#line 620 "src/lexer-keywords.txt" - {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle}, +#line 23 "src/lexer-keywords.txt" + {"assert_exception", TokenType::AssertException}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 132 "src/lexer-keywords.txt" - {"f64.div", TokenType::Binary, Opcode::F64Div}, -#line 71 "src/lexer-keywords.txt" - {"f32.div", TokenType::Binary, Opcode::F32Div}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 233 "src/lexer-keywords.txt" - {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub}, - {""}, {""}, -#line 193 "src/lexer-keywords.txt" - {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs}, {""}, -#line 561 "src/lexer-keywords.txt" - {"pagesize", TokenType::PageSize}, +#line 472 "src/lexer-keywords.txt" + {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq}, + {""}, {""}, {""}, +#line 158 "src/lexer-keywords.txt" + {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq}, {""}, {""}, -#line 95 "src/lexer-keywords.txt" - {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U}, +#line 240 "src/lexer-keywords.txt" + {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U}, {""}, -#line 94 "src/lexer-keywords.txt" - {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S}, +#line 238 "src/lexer-keywords.txt" + {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S}, + {""}, {""}, {""}, {""}, {""}, +#line 445 "src/lexer-keywords.txt" + {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 362 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 203 "src/lexer-keywords.txt" + {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 364 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U}, {""}, -#line 360 "src/lexer-keywords.txt" +#line 362 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S}, - {""}, {""}, -#line 131 "src/lexer-keywords.txt" - {"f64.copysign", TokenType::Binary, Opcode::F64Copysign}, -#line 69 "src/lexer-keywords.txt" - {"f32.copysign", TokenType::Binary, Opcode::F32Copysign}, -#line 533 "src/lexer-keywords.txt" - {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub}, - {""}, {""}, -#line 497 "src/lexer-keywords.txt" - {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 225 "src/lexer-keywords.txt" - {"i16x8.relaxed_q15mulr_s", TokenType::Binary, Opcode::I16X8RelaxedQ15mulrS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 370 "src/lexer-keywords.txt" + {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U}, + {""}, +#line 369 "src/lexer-keywords.txt" + {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S}, + {""}, {""}, {""}, {""}, +#line 361 "src/lexer-keywords.txt" + {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U}, + {""}, +#line 360 "src/lexer-keywords.txt" + {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 605 "src/lexer-keywords.txt" + {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect}, {""}, {""}, {""}, {""}, {""}, -#line 200 "src/lexer-keywords.txt" - {"i16x8.relaxed_dot_i8x16_i7x16_s", TokenType::Binary, Opcode::I16X8DotI8X16I7X16S}, +#line 407 "src/lexer-keywords.txt" + {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub}, +#line 270 "src/lexer-keywords.txt" + {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 443 "src/lexer-keywords.txt" - {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 244 "src/lexer-keywords.txt" - {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U}, - {""}, -#line 243 "src/lexer-keywords.txt" - {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 505 "src/lexer-keywords.txt" + {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 29 "src/lexer-keywords.txt" + {"assert_unlinkable", TokenType::AssertUnlinkable}, +#line 365 "src/lexer-keywords.txt" + {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U}, + {""}, +#line 363 "src/lexer-keywords.txt" + {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 86 "src/lexer-keywords.txt" + {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 220 "src/lexer-keywords.txt" - {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U}, - {""}, -#line 219 "src/lexer-keywords.txt" - {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S}, - {""}, {""}, -#line 238 "src/lexer-keywords.txt" - {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U}, - {""}, -#line 236 "src/lexer-keywords.txt" - {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S}, {""}, {""}, {""}, #line 548 "src/lexer-keywords.txt" - {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy}, - {""}, -#line 479 "src/lexer-keywords.txt" - {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask}, + {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, +#line 224 "src/lexer-keywords.txt" + {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 25 "src/lexer-keywords.txt" + {"assert_invalid", TokenType::AssertInvalid}, + {""}, +#line 302 "src/lexer-keywords.txt" + {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32}, {""}, {""}, {""}, {""}, {""}, -#line 157 "src/lexer-keywords.txt" - {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq}, +#line 506 "src/lexer-keywords.txt" + {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 470 "src/lexer-keywords.txt" - {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq}, +#line 24 "src/lexer-keywords.txt" + {"assert_exhaustion", TokenType::AssertExhaustion}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 483 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 485 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendHighI32X4U}, {""}, -#line 481 "src/lexer-keywords.txt" +#line 483 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendHighI32X4S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 20 "src/lexer-keywords.txt" - {"array", Type::Array, TokenType::Array}, - {""}, {""}, -#line 27 "src/lexer-keywords.txt" - {"assert_trap", TokenType::AssertTrap}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 596 "src/lexer-keywords.txt" - {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 150 "src/lexer-keywords.txt" - {"f64.sub", TokenType::Binary, Opcode::F64Sub}, -#line 88 "src/lexer-keywords.txt" - {"f32.sub", TokenType::Binary, Opcode::F32Sub}, - {""}, {""}, {""}, {""}, {""}, -#line 455 "src/lexer-keywords.txt" - {"i64.sub", TokenType::Binary, Opcode::I64Sub}, -#line 311 "src/lexer-keywords.txt" - {"i32.sub", TokenType::Binary, Opcode::I32Sub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 146 "src/lexer-keywords.txt" - {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 494 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, +#line 30 "src/lexer-keywords.txt" + {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, +#line 496 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U}, {""}, -#line 492 "src/lexer-keywords.txt" +#line 494 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1660,124 +1807,69 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 22 "src/lexer-keywords.txt" - {"assert_exception", TokenType::AssertException}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 199 "src/lexer-keywords.txt" - {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 23 "src/lexer-keywords.txt" - {"assert_exhaustion", TokenType::AssertExhaustion}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 503 "src/lexer-keywords.txt" - {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask}, - {""}, -#line 201 "src/lexer-keywords.txt" - {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 504 "src/lexer-keywords.txt" - {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 547 "src/lexer-keywords.txt" - {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64}, +#line 549 "src/lexer-keywords.txt" + {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 85 "src/lexer-keywords.txt" - {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, -#line 24 "src/lexer-keywords.txt" - {"assert_invalid", TokenType::AssertInvalid}, + {""}, {""}, {""}, {""}, +#line 550 "src/lexer-keywords.txt" + {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 405 "src/lexer-keywords.txt" - {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub}, -#line 268 "src/lexer-keywords.txt" - {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 545 "src/lexer-keywords.txt" - {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 183 "src/lexer-keywords.txt" + {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U}, +#line 522 "src/lexer-keywords.txt" + {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}, +#line 182 "src/lexer-keywords.txt" + {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S}, +#line 521 "src/lexer-keywords.txt" + {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 242 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 244 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendHighI8X16U}, {""}, -#line 241 "src/lexer-keywords.txt" +#line 243 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendHighI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 28 "src/lexer-keywords.txt" - {"assert_unlinkable", TokenType::AssertUnlinkable}, - {""}, {""}, -#line 300 "src/lexer-keywords.txt" - {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32}, {""}, {""}, {""}, {""}, -#line 182 "src/lexer-keywords.txt" - {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U}, - {""}, -#line 181 "src/lexer-keywords.txt" - {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S}, - {""}, -#line 235 "src/lexer-keywords.txt" +#line 237 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_u", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16U}, {""}, -#line 234 "src/lexer-keywords.txt" +#line 236 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_s", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 546 "src/lexer-keywords.txt" - {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32}, - {""}, {""}, {""}, {""}, {""}, -#line 520 "src/lexer-keywords.txt" - {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}, - {""}, -#line 519 "src/lexer-keywords.txt" - {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S}, - {""}, -#line 222 "src/lexer-keywords.txt" - {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 29 "src/lexer-keywords.txt" - {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence}, - {""}, {""}, {""}, {""}, -#line 239 "src/lexer-keywords.txt" - {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U}, - {""}, -#line 237 "src/lexer-keywords.txt" - {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 184 "src/lexer-keywords.txt" + {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 183 "src/lexer-keywords.txt" - {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4} + {""}, {""}, {""}, {""}, {""}, +#line 241 "src/lexer-keywords.txt" + {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U}, + {""}, +#line 239 "src/lexer-keywords.txt" + {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S} }; +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3) +#pragma GCC diagnostic pop +#endif if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { @@ -1791,5 +1883,5 @@ Perfect_Hash::InWordSet (const char *str, size_t len) return &wordlist[key]; } } - return 0; + return static_cast (0); } diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 67fc44e923..5ac824b4ce 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -81,6 +81,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnRethrowExpr(RethrowExpr*) override; Result OnSimdLoadLaneExpr(SimdLoadLaneExpr*) override; Result OnSimdStoreLaneExpr(SimdStoreLaneExpr*) override; + Result OnConstExpr(ConstExpr*) override; private: void PrintError(const Location* loc, const char* fmt, ...); @@ -100,7 +101,9 @@ class NameResolver : public ExprVisitor::DelegateNop { void ResolveTagVar(Var* var); void ResolveDataSegmentVar(Var* var); void ResolveElemSegmentVar(Var* var); + void ResolveDataVar(Var* var); void ResolveLocalVar(Var* var); + void ResolveReloc(IrReloc* reloc); void ResolveBlockDeclarationVar(BlockDeclaration* decl); void VisitFunc(Func* func); void VisitExport(Export* export_); @@ -219,6 +222,9 @@ void NameResolver::ResolveDataSegmentVar(Var* var) { void NameResolver::ResolveElemSegmentVar(Var* var) { ResolveVar(¤t_module_->elem_segment_bindings, var, "elem segment"); } +void NameResolver::ResolveDataVar(Var* var) { + ResolveVar(¤t_module_->data_symbol_bindings, var, "data symbol"); +} void NameResolver::ResolveLocalVar(Var* var) { if (var->is_name()) { @@ -236,6 +242,35 @@ void NameResolver::ResolveLocalVar(Var* var) { var->set_index(index); } } +void NameResolver::ResolveReloc(IrReloc* reloc) { + if (reloc->type == RelocType::None) + return; + switch (kRelocSymbolType[int(reloc->type)]) { + case RelocKind::Text: + case RelocKind::Function: + case RelocKind::FunctionTbl: + ResolveFuncVar(&reloc->symbol); + break; + case RelocKind::Data: + ResolveDataVar(&reloc->symbol); + break; + case RelocKind::Type: + ResolveFuncTypeVar(&reloc->symbol); + break; + case RelocKind::Table: + ResolveTableVar(&reloc->symbol); + break; + case RelocKind::Global: + ResolveGlobalVar(&reloc->symbol); + break; + case RelocKind::Tag: + ResolveTagVar(&reloc->symbol); + break; + case RelocKind::Section: + // Do nothing for now + break; + } +} void NameResolver::ResolveBlockDeclarationVar(BlockDeclaration* decl) { if (decl->has_func_type) { @@ -331,6 +366,7 @@ Result NameResolver::EndIfExpr(IfExpr* expr) { Result NameResolver::OnLoadExpr(LoadExpr* expr) { ResolveMemoryVar(&expr->memidx); + ResolveReloc(&expr->reloc); return Result::Ok; } @@ -430,6 +466,7 @@ Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) { Result NameResolver::OnStoreExpr(StoreExpr* expr) { ResolveMemoryVar(&expr->memidx); + ResolveReloc(&expr->reloc); return Result::Ok; } @@ -500,6 +537,10 @@ Result NameResolver::OnSimdStoreLaneExpr(SimdStoreLaneExpr* expr) { ResolveMemoryVar(&expr->memidx); return Result::Ok; } +Result NameResolver::OnConstExpr(ConstExpr* expr) { + ResolveReloc(&expr->reloc); + return Result::Ok; +} void NameResolver::VisitFunc(Func* func) { current_func_ = func; @@ -566,6 +607,8 @@ void NameResolver::VisitElemSegment(ElemSegment* segment) { void NameResolver::VisitDataSegment(DataSegment* segment) { ResolveMemoryVar(&segment->memory_var); visitor_.VisitExprList(segment->offset); + for (auto& [offset, reloc] : segment->relocs) + ResolveReloc(&reloc); } Result NameResolver::VisitModule(Module* module) { diff --git a/src/tools/wasm2wat.cc b/src/tools/wasm2wat.cc index 25e1c743c6..015865fff5 100644 --- a/src/tools/wasm2wat.cc +++ b/src/tools/wasm2wat.cc @@ -46,6 +46,7 @@ static bool s_read_debug_names = true; static bool s_fail_on_custom_section_error = true; static std::unique_ptr s_log_stream; static bool s_validate = true; +static bool s_relocatable = false; static const char s_description[] = R"( Read a file in the WebAssembly binary format, and convert it to @@ -96,6 +97,8 @@ static void ParseOptions(int argc, char** argv) { s_infile = argument; ConvertBackslashToSlash(&s_infile); }); + parser.AddOption('r', "relocatable", "Generate relocation annotations", + []() { s_relocatable = true; }); parser.Parse(argc, argv); } @@ -138,6 +141,7 @@ int ProgramMain(int argc, char** argv) { wat_options.fold_exprs = s_fold_exprs; wat_options.inline_import = s_inline_import; wat_options.inline_export = s_inline_export; + wat_options.relocatable = s_relocatable; FileStream stream(!s_outfile.empty() ? FileStream(s_outfile) : FileStream(stdout)); result = WriteWat(&stream, &module, wat_options); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index b452697bfa..ef157b0289 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -587,7 +587,8 @@ TokenType WastParser::Peek(size_t n) { } if ((options_->features.code_metadata_enabled() && cur.text().find("metadata.code.") == 0) || - cur.text() == "custom") { + cur.text() == "custom" || cur.text() == "reloc" || + cur.text() == "sym.import.data" || cur.text() == "sym") { tokens_.push_back(cur); continue; } @@ -657,6 +658,26 @@ bool WastParser::MatchLpar(TokenType type) { return false; } +bool WastParser::MatchText(TokenType type, std::string_view text) { + auto tok = GetToken(); + if (tok.token_type() == type && tok.text() == text) { + Consume(); + return true; + } + return false; +} +std::optional WastParser::MatchTextPrefix( + TokenType type, + std::string_view prefix) { + auto tok = GetToken(); + if (tok.token_type() == type) + if (auto rest = TryTrimPfx(tok.text(), prefix)) { + Consume(); + return rest; + } + return std::nullopt; +} + Result WastParser::Expect(TokenType type) { if (!Match(type)) { Token token = Consume(); @@ -693,6 +714,14 @@ Result WastParser::Synchronize(SynchronizeFunc func) { return Result::Error; } +std::optional WastParser::TryTrimPfx( + std::string_view string, + std::string_view prefix) { + if (string.substr(0, prefix.size()) == prefix) + return string.substr(prefix.size()); + return std::nullopt; +} + void WastParser::ErrorUnlessOpcodeEnabled(const Token& token) { Opcode opcode = token.opcode(); if (!opcode.IsEnabled(options_->features)) { @@ -1297,6 +1326,207 @@ bool WastParser::PeekIsCustom() { return options_->features.annotations_enabled() && IsLparAnn(PeekPair()) && tokens_.front().text() == "custom"; } +bool WastParser::PeekIsDataImport() { + // If IsLparAnn succeeds, tokens_.front() must have text, as it is an LparAnn + // token. + return options_->features.annotations_enabled() && IsLparAnn(PeekPair()) && + tokens_.front().text() == "sym.import.data"; +} + +std::optional WastParser::ParseSymAttrString(TokenType tag) { + if (!MatchLpar(tag)) + return {}; + std::optional ret(std::in_place); + if (ParseQuotedText(&*ret)) { + if (Failed(Expect(TokenType::Rpar))) + ParseUnwindReloc(1); + return ret; + } + ErrorExpected({"A quoted string"}, "\"foo\""); + ParseUnwindReloc(1); + ret.reset(); + return ret; +} + +std::optional WastParser::ParseSymAttrNumber(TokenType tag) { + if (!MatchLpar(tag)) + return {}; + std::optional ret(std::in_place); + if (ParseNat(&*ret, true)) { + if (Failed(Expect(TokenType::Rpar))) + ParseUnwindReloc(1); + return ret; + } + ErrorExpected({"A number"}, "32"); + ParseUnwindReloc(1); + ret.reset(); + return ret; +} + +Result WastParser::ParseSymOpt(SymbolCommon* sym, + bool in_import, + SymAux aux) { + using OnceProperty = std::pair>; + Location last_tok_loc; + + OnceProperty visibility{"visibility", {}}; + OnceProperty binding{"linkage", {}}; + OnceProperty retain{"retain", {}}; + OnceProperty name{"name", {}}; + OnceProperty size{"size", {}}; + OnceProperty priority{"priority", {}}; + + auto check_once = [this, &last_tok_loc](OnceProperty& var) { + if (!var.second) + var.second = last_tok_loc; + else { + Error(last_tok_loc, "Symbol's " PRIstringview " already specified", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + Error(*var.second, "See previous definition"); + } + }; + auto check_seen = [this, &last_tok_loc](OnceProperty& var) { + if (!var.second) + Error(last_tok_loc, "Must specify " PRIstringview " for this symbol", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + }; + auto check_unseen = [this](OnceProperty& var) { + if (var.second) + Error(*var.second, "Cannot specify " PRIstringview " for this symbol", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + }; + + auto validate = [&] { + if (in_import && (sym->flags_ & uint32_t(SymbolBinding::Local))) { + Error(*binding.second, "static symbol cannot be an import"); + } + if (std::get_if(&aux)) { + if (!in_import) + check_seen(size); + check_seen(name); + } else { + check_unseen(size); + } + if (!std::get_if(&aux)) + check_unseen(priority); + }; + + sym->flags_ |= in_import ? WABT_SYMBOL_FLAG_UNDEFINED : 0; + if (!IsLparAnn(PeekPair())) + return Result::Ok; + Token tok = GetToken(); + bool is_data = std::get_if(&aux); + if (tok.text() != (is_data && in_import ? "sym.import.data" : "sym")) + return Result::Ok; + Consume(); + + if (auto *data = std::get_if(&aux)) { + ParseVarOpt(&(*data)->name, (*data)->name); + } + for (;;) { + last_tok_loc = GetLocation(); + if (Match(TokenType::Rpar)) { + validate(); + return Result::Ok; + } + if (auto sym_name = ParseSymAttrString(TokenType::Name)) { + check_once(name); + sym->name_ = *sym_name; + sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } else if (auto sym_size = ParseSymAttrNumber(TokenType::Size)) { + check_once(size); + if (auto *data = std::get_if(&aux)) + (*data)->size = *sym_size; + } else if (auto sym_prio = ParseSymAttrNumber(TokenType::InitPrio)) { + check_once(priority); + if (auto *data = std::get_if(&aux)) + (*data)->priority = *sym_prio; + } else if (Match(TokenType::Local)) { + check_once(binding); + sym->flags_ |= uint32_t(SymbolBinding::Local); + } else if (Match(TokenType::Weak)) { + check_once(binding); + sym->flags_ |= uint32_t(SymbolBinding::Weak); + } else if (Match(TokenType::Retain)) { + check_once(retain); + sym->flags_ |= WABT_SYMBOL_FLAG_NO_STRIP; + } else if (Match(TokenType::Hidden)) { + check_once(visibility); + sym->flags_ |= uint32_t(SymbolVisibility::Hidden); + } else { + bool do_unwind = PeekMatch(TokenType::Lpar); + ErrorExpected({"symbol attribute", "')'"}, "(name \"foo\")"); + if (do_unwind) + ParseUnwindReloc(1); + } + } +} +Result WastParser::ParseSymSegment(DataSegment::SymInfo* info) { + if (!IsLparAnn(PeekPair())) + return Result::Ok; + Token tok = GetToken(); + if (tok.text() != "sym") + return Result::Ok; + Consume(); + Location last_tok_loc = GetLocation(); + for (;;) { + last_tok_loc = GetLocation(); + using Flags = DataSegment::SymInfo::Flags; + + if (Match(TokenType::Rpar)) break; + if (auto name = ParseSymAttrString(TokenType::Name)) + info->name = *std::move(name); + else if (auto align = ParseSymAttrNumber(TokenType::Align)) { + for (int i = 0;; ++i) { + uint64_t num = 1 << i; + if (num < *align) + continue; + if (num == *align) + info->align = i; + else + Error(last_tok_loc, "Alignment is not a power of 2"); + break; + } + } + else if (Match(TokenType::Retain)) + info->flags = Flags(info->flags | Flags::WASM_SEG_FLAG_RETAIN); + else if (Match(TokenType::TLS)) + info->flags = Flags(info->flags | Flags::WASM_SEGMENT_FLAG_TLS); + else if (Match(TokenType::Strings)) + info->flags = Flags(info->flags | Flags::WASM_SEGMENT_FLAG_STRINGS); + else { + ErrorExpected({"segment attribute"}, "(name \"foo\")"); + ParseUnwindReloc(1); + return Result::Error; + } + } + return Result::Ok; +} + +Result WastParser::ParseDataImport(Module* module) { + DataSym sym{}; + DatasymAux aux; + sym.flags_ = WABT_SYMBOL_FLAG_UNDEFINED; + CHECK_RESULT(ParseSymOpt(&sym, true, &aux)); + + if (!module->data_symbols.empty()) { + if (module->data_symbols.back().segment != kInvalidIndex) { + Error(GetLocation(), "data imports must occur before definitions"); + return Result::Error; + } + } + ++module->num_data_imports; + sym.segment = kInvalidIndex; + sym.offset = module->num_data_imports; + Index sym_idx = module->data_symbols.size(); + if (aux.name.is_name()) { + module->data_symbol_bindings.insert( + {aux.name.name(), {aux.name.loc, sym_idx}}); + sym.name = aux.name.name(); + } + module->data_symbols.push_back(sym); + return Result::Ok; +} Result WastParser::ResolveRefTypes(const Module& module, TypeVector* types, @@ -1358,11 +1588,15 @@ Result WastParser::ParseModuleFieldList(Module* module) { resolve_types_.clear(); resolve_funcs_.clear(); - while (IsModuleField(PeekPair()) || PeekIsCustom()) { + while (IsModuleField(PeekPair()) || PeekIsCustom() || PeekIsDataImport()) { if (PeekIsCustom()) { CHECK_RESULT(ParseCustomSectionAnnotation(module)); continue; } + if (PeekIsDataImport()) { + CHECK_RESULT(ParseDataImport(module)); + continue; + } if (Failed(ParseModuleField(module))) { CHECK_RESULT(Synchronize(IsModuleField)); } @@ -1383,6 +1617,51 @@ Result WastParser::ParseModuleFieldList(Module* module) { CHECK_RESULT(result); CHECK_RESULT(ResolveFuncTypes(module, errors_)); CHECK_RESULT(ResolveNamesModule(module, errors_)); + for (auto exp : module->exports) { + auto patch = [&](auto& fields, const BindingHash& bindings) { + Index i = bindings.FindIndex(exp->var); + if (i >= fields.size()) + return; + SymbolCommon& sym = *fields[i]; + sym.flags_ |= WABT_SYMBOL_FLAG_EXPORTED | WABT_SYMBOL_FLAG_NO_STRIP; + if (sym.name_.empty() && sym.defined()) { + sym.name_ = exp->name; + sym.flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } + }; + switch (exp->kind) { + case ExternalKind::Func: + patch(module->funcs, module->func_bindings); + break; + case ExternalKind::Table: + patch(module->tables, module->table_bindings); + break; + case ExternalKind::Global: + patch(module->globals, module->global_bindings); + break; + case ExternalKind::Tag: + patch(module->tags, module->tag_bindings); + break; + case ExternalKind::Memory: + // Memories are not relocatable + break; + } + } + auto validize_flags = [](SymbolCommon* sym) { + if (!sym->undefined() && !sym->exported() && sym->name().empty()) { + sym->flags_ |= uint32_t(SymbolVisibility::Hidden); + sym->flags_ &= ~WABT_SYMBOL_MASK_BINDING; + sym->flags_ |= uint32_t(SymbolBinding::Local); + } + }; + for (auto sym : module->funcs) + validize_flags(sym); + for (auto sym : module->globals) + validize_flags(sym); + for (auto sym : module->tables) + validize_flags(sym); + for (auto sym : module->tags) + validize_flags(sym); return Result::Ok; } @@ -1416,6 +1695,8 @@ Result WastParser::ParseDataModuleField(Module* module) { ParseBindVarOpt(&name); auto field = std::make_unique(loc, name); + ParseSymSegment(&field->data_segment.sym); + if (PeekMatchLpar(TokenType::Memory)) { EXPECT(Lpar); EXPECT(Memory); @@ -1433,7 +1714,50 @@ Result WastParser::ParseDataModuleField(Module* module) { field->data_segment.kind = SegmentKind::Passive; } - ParseTextListOpt(&field->data_segment.data); + field->data_segment.symbol_range.first = module->data_symbols.size(); + + for (;;) { + Token tok = GetToken(); + if (tok.token_type() == TokenType::Rpar) + break; + if (tok.token_type() == TokenType::LparAnn) { + size_t offset = field->data_segment.data.size(); + if (tok.text() == "reloc") { + IrReloc r; + ParseReloc(true, &r); + size_t reloc_size = + kRelocDataTypeSize[int(kRelocDataType[int(r.type)])]; + field->data_segment.relocs.push_back({offset - reloc_size, r}); + continue; + } + if (tok.text() == "sym") { + DataSym sym{}; + Index sym_idx = module->data_symbols.size(); + DatasymAux aux = {Var{sym_idx, GetLocation()}, 0}; + ParseSymOpt(&sym, false, &aux); + sym.segment = module->data_segments.size(); + sym.offset = offset; + sym.size = aux.size; + if (aux.name.is_name()) { + module->data_symbol_bindings.insert( + {aux.name.name(), {aux.name.loc, sym_idx}}); + sym.name = aux.name.name(); + } + module->data_symbols.push_back(sym); + continue; + } + } + if (PeekMatch(TokenType::Text)) { + RemoveEscapes(Consume().text(), + std::back_inserter(field->data_segment.data)); + continue; + } + Expect(TokenType::Rpar); + return Result::Error; + } + + field->data_segment.symbol_range.second = module->data_symbols.size(); + EXPECT(Rpar); module->AppendField(std::move(field)); return Result::Ok; @@ -1534,6 +1858,10 @@ Result WastParser::ParseTagModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); + Tag& tag = field->tag; + CHECK_RESULT(ParseSymOpt(&tag, false)); + if (!name.empty() && !tag.explicit_name()) + tag.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig)); module->AppendField(std::move(field)); @@ -1572,6 +1900,9 @@ Result WastParser::ParseFuncModuleField(Module* module) { CheckImportOrdering(module); auto import = std::make_unique(name); Func& func = import->func; + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&func, true, &aux)); + func.priority = aux.priority; CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1583,6 +1914,11 @@ Result WastParser::ParseFuncModuleField(Module* module) { auto field = std::make_unique(loc, name); Func& func = field->func; func.loc = GetLocation(); + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&func, false, &aux)); + func.priority = aux.priority; + if (!name.empty() && !func.explicit_name()) + func.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1712,6 +2048,10 @@ Result WastParser::ParseGlobalModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); + Global& global = field->global; + CHECK_RESULT(ParseSymOpt(&global, false)); + if (!name.empty() && !global.explicit_name()) + global.name_ = name.substr(1); CHECK_RESULT(ParseGlobalType(&field->global)); CHECK_RESULT(ParseTerminatingInstrList(&field->global.init_expr)); module->AppendField(std::move(field)); @@ -1735,6 +2075,11 @@ Result WastParser::ParseImportModuleField(Module* module) { CHECK_RESULT(ParseQuotedText(&field_name)); EXPECT(Lpar); + auto inject_name = [&](SymbolCommon& sym) { + if (!sym.explicit_name()) + sym.name_ = field_name; + }; + std::unique_ptr field; std::string name; @@ -1743,11 +2088,15 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&import->func, true, &aux)); + import->func.priority = aux.priority; CHECK_RESULT(ParseTypeUseOpt(&import->func.decl)); CHECK_RESULT( ParseFuncSignature(&import->func.decl.sig, &import->func.bindings)); CHECK_RESULT(ErrorIfLpar({"param", "result"})); EXPECT(Rpar); + inject_name(import->func); field = std::make_unique(std::move(import), loc); break; } @@ -1756,10 +2105,12 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->table, true)); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); CHECK_RESULT(ParseRefType(&import->table.elem_type)); EXPECT(Rpar); + inject_name(import->table); field = std::make_unique(std::move(import), loc); break; } @@ -1781,8 +2132,10 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->global, true)); CHECK_RESULT(ParseGlobalType(&import->global)); EXPECT(Rpar); + inject_name(import->global); field = std::make_unique(std::move(import), loc); break; } @@ -1791,9 +2144,11 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->tag, true)); CHECK_RESULT(ParseTypeUseOpt(&import->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&import->tag.decl.sig)); EXPECT(Rpar); + inject_name(import->tag); field = std::make_unique(std::move(import), loc); break; } @@ -1905,6 +2260,7 @@ Result WastParser::ParseTableModuleField(Module* module) { if (PeekMatchLpar(TokenType::Import)) { CheckImportOrdering(module); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->table, true)); CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); @@ -1915,6 +2271,9 @@ Result WastParser::ParseTableModuleField(Module* module) { } else { auto field = std::make_unique(loc, name); auto& table = field->table; + CHECK_RESULT(ParseSymOpt(&table, false)); + if (!name.empty() && !table.explicit_name()) + table.name_ = name.substr(1); CHECK_RESULT(ParseLimitsIndex(&table.elem_limits)); if (PeekMatch(TokenType::ValueType)) { Type elem_type; @@ -2124,9 +2483,17 @@ Result WastParser::ParseInstrList(ExprList* exprs) { CHECK_RESULT(Synchronize(IsInstr)); } } else if (IsLparAnn(pair)) { - if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { - exprs->splice(exprs->end(), new_exprs); + Token tk = GetToken(); + constexpr std::string_view pfx = "metadata.code."; + std::string_view name = tk.text(); + if (name.substr(0, size(pfx)) == pfx) { + if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { + exprs->splice(exprs->end(), new_exprs); + } else { + CHECK_RESULT(Synchronize(IsLparAnn)); + } } else { + ErrorExpected({"an annotation", "an instruction"}); CHECK_RESULT(Synchronize(IsLparAnn)); } } else { @@ -2166,11 +2533,225 @@ Result WastParser::ParseInstr(ExprList* exprs) { } } +Result WastParser::ParseRejectReloc() { + Token tok = GetToken(); + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { + Error(GetLocation(), "Operand is not relocatable"); + Consume(); + return ParseUnwindReloc(1); + } + return Result::Ok; +} +Result WastParser::ParseUnwindReloc(int curr_indent) { + while (curr_indent) { + if (PeekMatch(TokenType::Lpar) || PeekMatch(TokenType::LparAnn)) + ++curr_indent; + if (PeekMatch(TokenType::Rpar)) + --curr_indent; + Consume(); + } + return Result::Ok; +} + +Result WastParser::ParseRelocAddend(uint32_t* addend, + Var* name) { + if (PeekMatch(TokenType::Rpar)) { + if (addend) + *addend = 0; + return Result::Ok; + } + if (!addend) + return Result::Error; + Token curr = GetToken(); + if (name && Match(TokenType::Var)) { + *name = Var{curr.text(), curr.loc}; + return Result::Ok; + } + if (!Expect(TokenType::Int)) { + return Result::Error; + } + auto sv = curr.literal().text; + if (!ParseInt32(sv, addend, ParseIntType::SignedAndUnsigned)) + ErrorExpected({"integer with sign"}, "+123"); + if (sv.find_first_of("+-") != 0) + return ErrorExpected({"integer with sign"}, + ("+" + std::string(sv)).c_str()); + return Result::Ok; +} + +Result WastParser::ParseRelocModifiers(RelocModifiers* mod) { + *mod = RelocModifiers::None; + Token tok = GetToken(); + if (tok.token_type() == TokenType::Reserved) { + if (tok.text() == "tls") + *mod = RelocModifiers::TLS; + else if (tok.text() == "pic") + *mod = RelocModifiers::PIC; + } + if (*mod != RelocModifiers::None) + Consume(); + return Result::Ok; +} + +Result WastParser::ParseRelocKind(RelocKind* kind) { + bool did_reloc = false; + Token tok = GetToken(); + TokenType tt = tok.token_type(); + if (tt == TokenType::Global) { + *kind = RelocKind::Global; + did_reloc = true; + } + if (tt == TokenType::Function) { + *kind = RelocKind::Function; + did_reloc = true; + } + if (tt == TokenType::Table) { + *kind = RelocKind::Table; + did_reloc = true; + } + if (tt == TokenType::Tag) { + *kind = RelocKind::Tag; + did_reloc = true; + } + if (tt == TokenType::Data) { + *kind = RelocKind::Data; + did_reloc = true; + } + if (tt == TokenType::Type) { + *kind = RelocKind::Type; + did_reloc = true; + } + if (tt == TokenType::Reserved) { + if (tok.text() == "text") { + *kind = RelocKind::Text; + did_reloc = true; + } + if (tok.text() == "functable") { + *kind = RelocKind::FunctionTbl; + did_reloc = true; + } + if (tok.text() == "custom") { + *kind = RelocKind::Section; + did_reloc = true; + } + } + if (did_reloc) { + Consume(); + return Result::Ok; + } else + return Result::Error; +} +Result WastParser::ParseRelocDataType(RelocDataType* type) { + bool did_reloc = false; + Token tok = GetToken(); + TokenType tt = tok.token_type(); + if (tt == TokenType::ValueType) { + if (tok.type() == Type::I32) { + *type = RelocDataType::I32; + did_reloc = true; + } + if (tok.type() == Type::I64) { + *type = RelocDataType::I64; + did_reloc = true; + } + } + if (tt == TokenType::Reserved) { + if (tok.text() == "leb") { + *type = RelocDataType::LEB; + did_reloc = true; + } + if (tok.text() == "sleb") { + *type = RelocDataType::SLEB; + did_reloc = true; + } + if (tok.text() == "leb64") { + *type = RelocDataType::LEB64; + did_reloc = true; + } + if (tok.text() == "sleb64") { + *type = RelocDataType::SLEB64; + did_reloc = true; + } + } + if (did_reloc) { + Consume(); + return Result::Ok; + } else + return Result::Error; +} + +Result WastParser::ParseReloc(bool opt, + IrReloc* reloc, + RelocDataType data, + RelocKind kind, + Var* name, + bool data_default, + bool kind_default, + bool name_default) { + Token tok = GetToken(); + Result res = Result::Ok; + RelocModifiers mod = RelocModifiers::None; + Var sym_name; + Var addend_name; + uint32_t addend_num; + + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { + Consume(); + if (data == RelocDataType::None) + res |= ParseRelocDataType(&data); + else if (data_default) + ParseRelocDataType(&data); + + if (kind == RelocKind::None) + res |= ParseRelocKind(&kind); + else if (kind_default) + ParseRelocKind(&kind); + + ParseRelocModifiers(&mod); + + if (!name) + res |= ParseVar(&sym_name); + else if (name_default) + ParseVar(&sym_name); + else + sym_name = *name; + + bool text_addend_allowed = + kind == RelocKind::Text || kind == RelocKind::Section; + bool addend_allowed = kind == RelocKind::Data || text_addend_allowed; + ParseRelocAddend(addend_allowed ? &addend_num : nullptr, + text_addend_allowed ? &addend_name : nullptr); + if (!Expect(TokenType::Rpar)) { + res = Result::Error; + ParseUnwindReloc(1); + } + } else if (!name || kind == RelocKind::None || data == RelocDataType::None) { + if (opt) + return Result::Ok; + return ErrorExpected({"relocation annotation"}, "(@reloc $foo)"); + } + + RelocType reloc_type = RecognizeReloc(kind, data, mod); + if (reloc_type == RelocType::None) + res = Result::Error; + CHECK_RESULT(res); + + reloc->type = reloc_type; + reloc->addend = addend_num; + reloc->symbol = sym_name; + + return Result::Ok; +} + Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { WABT_TRACE(ParseCodeMetadataAnnotation); Token tk = Consume(); + constexpr std::string_view pfx = "metadata.code."; std::string_view name = tk.text(); - name.remove_prefix(sizeof("metadata.code.") - 1); + assert(name.substr(0, size(pfx)) == pfx && + "ParseCodeMetadataAnnotation should only be called with appropriate " + "annotation"); + name.remove_prefix(size(pfx)); std::string data_text; CHECK_RESULT(ParseQuotedText(&data_text, false)); std::vector data(data_text.begin(), data_text.end()); @@ -2220,14 +2801,24 @@ template Result WastParser::ParseLoadStoreInstr(Location loc, Token token, std::unique_ptr* out_expr) { + constexpr bool relocatable = + std::is_same_v || std::is_same_v; Opcode opcode = token.opcode(); Var memidx; Address offset; Address align; + IrReloc reloc; CHECK_RESULT(ParseMemidx(loc, &memidx)); ParseOffsetOpt(&offset); + if constexpr (relocatable) + CHECK_RESULT(ParseReloc(true, &reloc, RelocDataType::LEB, RelocKind::Data, + nullptr, false, true)); ParseAlignOpt(&align); - out_expr->reset(new T(opcode, memidx, align, offset, loc)); + T* expr = new T(opcode, memidx, align, offset, loc); + if constexpr (relocatable) + expr->reloc = reloc; + + out_expr->reset(expr); return Result::Ok; } @@ -2447,7 +3038,14 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { case TokenType::Const: { Const const_; CHECK_RESULT(ParseConst(&const_, ConstType::Normal)); - out_expr->reset(new ConstExpr(const_, loc)); + auto expr = new ConstExpr(const_, loc); + out_expr->reset(expr); + if (const_.type() == Type::I64) + CHECK_RESULT(ParseReloc(true, &expr->reloc, RelocDataType::SLEB64)); + else if (const_.type() == Type::I32) + CHECK_RESULT(ParseReloc(true, &expr->reloc, RelocDataType::SLEB)); + else + CHECK_RESULT(ParseRejectReloc()); break; } @@ -3813,7 +4411,7 @@ Result WastParser::ParseScriptModule( auto tsm = std::make_unique(); tsm->module.name = name; tsm->module.loc = loc; - if (IsModuleField(PeekPair()) || PeekIsCustom()) { + if (IsModuleField(PeekPair()) || PeekIsCustom() || PeekIsDataImport()) { CHECK_RESULT(ParseModuleFieldList(&tsm->module)); } else if (!PeekMatch(TokenType::Rpar)) { ConsumeIfLpar(); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index f19e3c3c86..424d5e3463 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -136,7 +137,7 @@ class WatWriter : ModuleContext { const Block& block, const char* text); void WriteEndBlock(); - void WriteConst(const Const& const_); + void WriteConst(const ConstExpr& const_); void WriteExpr(const Expr* expr); template void WriteLoadStoreExpr(const Expr* expr); @@ -149,6 +150,9 @@ class WatWriter : ModuleContext { const T& types, const std::vector& index_to_name, Index binding_index_offset = 0); + void WriteRelocAttrs(const SymbolCommon& sym); + void WriteReloc(const IrReloc& reloc, bool require_type = false); + void WriteDataImports(); void WriteBeginFunc(const Func& func); void WriteFunc(const Func& func); void WriteBeginGlobal(const Global& global); @@ -469,17 +473,20 @@ void WatWriter::WriteEndBlock() { WritePutsNewline(Opcode::End_Opcode.GetName()); } -void WatWriter::WriteConst(const Const& const_) { +void WatWriter::WriteConst(const ConstExpr& expr) { + const Const& const_ = expr.const_; switch (const_.type()) { case Type::I32: WritePutsSpace(Opcode::I32Const_Opcode.GetName()); Writef("%d", static_cast(const_.u32())); + WriteReloc(expr.reloc); WriteNewline(NO_FORCE_NEWLINE); break; case Type::I64: WritePutsSpace(Opcode::I64Const_Opcode.GetName()); Writef("%" PRId64, static_cast(const_.u64())); + WriteReloc(expr.reloc); WriteNewline(NO_FORCE_NEWLINE); break; @@ -516,6 +523,7 @@ void WatWriter::WriteConst(const Const& const_) { assert(0); break; } + WriteReloc(expr.reloc, false); } template @@ -539,6 +547,7 @@ void WatWriter::WriteMemoryLoadStoreExpr(const Expr* expr) { if (typed_expr->offset) { Writef("offset=%" PRIaddress, typed_expr->offset); } + WriteReloc(typed_expr->reloc); if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) { Writef("align=%" PRIaddress, typed_expr->align); } @@ -705,7 +714,7 @@ Result WatWriter::ExprVisitorDelegate::OnCompareExpr(CompareExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnConstExpr(ConstExpr* expr) { - writer_->WriteConst(expr->const_); + writer_->WriteConst(*expr); return Result::Ok; } @@ -1435,9 +1444,115 @@ void WatWriter::WriteTypeBindings(const char* prefix, } } +void WatWriter::WriteRelocAttrs(const SymbolCommon& sym) { + if (sym.binding() == SymbolBinding::Weak) + WritePutsSpace("weak"); + if (sym.binding() == SymbolBinding::Local) + WritePutsSpace("static"); + else { + if (sym.visibility() == SymbolVisibility::Hidden) + WritePutsSpace("hidden"); + } + if (sym.no_strip()) + WritePutsSpace("retain"); + if (sym.exported()) + WritePutsSpace("export"); + if (!sym.name().empty()) { + WritePuts("name=", NextChar::None); + WriteQuotedString(sym.name(), NextChar::Space); + } +} + +void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { + if (reloc.type == RelocType::None || !options_.relocatable) + return; + WriteOpenSpace("@reloc"); + if (require_type) + switch (kRelocDataType[int(reloc.type)]) { + case RelocDataType::I32: + WritePutsSpace("i32"); + break; + case RelocDataType::I64: + WritePutsSpace("i64"); + break; + case RelocDataType::LEB: + WritePutsSpace("leb"); + break; + case RelocDataType::SLEB: + WritePutsSpace("sleb"); + break; + case RelocDataType::LEB64: + WritePutsSpace("leb64"); + break; + case RelocDataType::SLEB64: + WritePutsSpace("sleb64"); + break; + } + switch (kRelocSymbolType[int(reloc.type)]) { + case RelocKind::Function: + WritePutsSpace("func"); + break; + case RelocKind::Data: + WritePutsSpace("data"); + break; + case RelocKind::Global: + WritePutsSpace("global"); + break; + case RelocKind::FunctionTbl: + WritePutsSpace("functable"); + break; + case RelocKind::Table: + WritePutsSpace("table"); + break; + case RelocKind::Tag: + WritePutsSpace("tag"); + break; + case RelocKind::Type: + WritePutsSpace("type"); + break; + case RelocKind::Text: + WritePutsSpace("text"); + break; + case RelocKind::Section: + WritePutsSpace("section"); + break; + default: + WABT_UNREACHABLE; + } + + if (bool(kRelocModifiers[int(reloc.type)] & RelocModifiers::TLS)) + WritePutsSpace("tls"); + if (bool(kRelocModifiers[int(reloc.type)] & RelocModifiers::PIC)) + WritePutsSpace("pic"); + + WriteVar(reloc.symbol, NextChar::None); + if (reloc.addend) + Writef("+%u", reloc.addend); + WriteCloseSpace(); +} +void WatWriter::WriteDataImports() { + for (Index i = 0; i != module.num_data_imports; ++i) { + const DataSym& sym = module.data_symbols[i]; + WriteOpenSpace("@sym.import.data"); + if (!sym.name.empty()) + WriteName(sym.name, NextChar::Space); + WriteRelocAttrs(sym); + WriteCloseNewline(); + } +} + void WatWriter::WriteBeginFunc(const Func& func) { + bool import = module.IsImport(ExternalKind::Func, Var(func_index_, {})); WriteOpenSpace("func"); WriteNameOrIndex(func.name, func_index_, NextChar::Space); + + if ((func.non_default(import) || func.priority) && options_.relocatable) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(func); + if (func.priority.has_value()) + Writef("init=%u", *func.priority); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Func, func_index_); WriteInlineImport(ExternalKind::Func, func_index_); if (func.decl.has_func_type) { @@ -1446,7 +1561,7 @@ void WatWriter::WriteBeginFunc(const Func& func) { WriteCloseSpace(); } - if (module.IsImport(ExternalKind::Func, Var(func_index_, Location()))) { + if (import) { // Imported functions can be written a few ways: // // 1. (import "module" "field" (func (type 0))) @@ -1489,8 +1604,14 @@ void WatWriter::WriteFunc(const Func& func) { } void WatWriter::WriteBeginGlobal(const Global& global) { + bool import = module.IsImport(ExternalKind::Global, Var(func_index_, {})); WriteOpenSpace("global"); WriteNameOrIndex(global.name, global_index_, NextChar::Space); + if (global.non_default(import) && options_.relocatable) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(global); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Global, global_index_); WriteInlineImport(ExternalKind::Global, global_index_); if (global.mutable_) { @@ -1510,8 +1631,14 @@ void WatWriter::WriteGlobal(const Global& global) { } void WatWriter::WriteTag(const Tag& tag) { + bool import = module.IsImport(ExternalKind::Tag, Var(func_index_, {})); WriteOpenSpace("tag"); WriteNameOrIndex(tag.name, tag_index_, NextChar::Space); + if (tag.non_default(import) && options_.relocatable) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(tag); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Tag, tag_index_); WriteInlineImport(ExternalKind::Tag, tag_index_); if (tag.decl.has_func_type) { @@ -1538,8 +1665,14 @@ void WatWriter::WriteLimits(const Limits& limits) { } void WatWriter::WriteTable(const Table& table) { + bool import = module.IsImport(ExternalKind::Table, Var(func_index_, {})); WriteOpenSpace("table"); WriteNameOrIndex(table.name, table_index_, NextChar::Space); + if (table.non_default(import) && options_.relocatable) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(table); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Table, table_index_); WriteInlineImport(ExternalKind::Table, table_index_); WriteLimits(table.elem_limits); @@ -1622,7 +1755,43 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { } WriteInitExpr(segment.offset); } - WriteQuotedData(segment.data.data(), segment.data.size()); + Offset offset = 0, next_sym = 0, next_reloc = 0; + constexpr auto end_offset = std::numeric_limits::max(); + Index curr_sym = segment.symbol_range.first; + auto curr_reloc = begin(segment.relocs); + bool written_some_data = false; + for (;;) { + next_reloc = curr_reloc != end(segment.relocs) && options_.relocatable + ? curr_reloc->first + + kRelocDataTypeSize[int( + kRelocDataType[int(curr_reloc->second.type)])] + : end_offset; + next_sym = curr_sym != segment.symbol_range.second && options_.relocatable + ? module.data_symbols[curr_sym].offset + : end_offset; + if (offset == next_reloc) { + WriteReloc(curr_reloc->second, true); + ++curr_reloc; + continue; + } + if (offset == next_sym) { + WriteOpenSpace("@sym"); + WriteName(module.data_symbols[curr_sym].name, NextChar::Space); + Writef("size=%" PRIaddress, module.data_symbols[curr_sym].size); + WriteRelocAttrs(module.data_symbols[curr_sym]); + WriteCloseSpace(); + ++curr_sym; + continue; + } + if (offset == segment.data.size() && written_some_data) + // if we have no relocs/syms left, and there's also no data, leave + break; + Offset write_to = + std::min(segment.data.size(), std::min(next_reloc, next_sym)); + WriteQuotedData(segment.data.data() + offset, write_to - offset); + offset = write_to; + written_some_data = true; + } WriteCloseNewline(); data_segment_index_++; } @@ -1745,6 +1914,7 @@ Result WatWriter::WriteModule() { } else { WriteName(module.name, NextChar::Newline); } + WriteDataImports(); for (const ModuleField& field : module.fields) { switch (field.type()) { case ModuleFieldType::Func: @@ -1784,6 +1954,10 @@ Result WatWriter::WriteModule() { } if (options_.features.annotations_enabled()) { for (const Custom& custom : module.customs) { + if (custom.name == "linking") + continue; + if (std::string_view{custom.name}.substr(0, 6) == "reloc." && options_.relocatable) + continue; WriteCustom(custom); } } diff --git a/test/dump/relocations-all-features.txt b/test/dump/relocations-all-features.txt index 0b22b64184..b6d6dc48fd 100644 --- a/test/dump/relocations-all-features.txt +++ b/test/dump/relocations-all-features.txt @@ -59,7 +59,7 @@ Custom: - symbol table [count=5] - 0: F <__extern.foo> func=0 [ undefined binding=global vis=default ] - 1: F <__extern.bar> func=1 [ undefined binding=global vis=default ] - - 2: F func=2 [ exported no_strip binding=global vis=hidden ] + - 2: F func=2 [ exported no_strip binding=global vis=default ] - 3: T <> table=0 [ binding=local vis=hidden ] - 4: G global=0 [ binding=global vis=default ] Custom: diff --git a/test/dump/relocations-block-types.txt b/test/dump/relocations-block-types.txt index 5192b77488..9089b5b462 100644 --- a/test/dump/relocations-block-types.txt +++ b/test/dump/relocations-block-types.txt @@ -30,7 +30,7 @@ Code[1]: Custom: - name: "linking" - symbol table [count=1] - - 0: F func=0 [ exported no_strip binding=global vis=hidden ] + - 0: F func=0 [ exported no_strip binding=global vis=default ] Custom: - name: "reloc.Code" - relocations for section: 3 (Code) [1] diff --git a/test/dump/relocations-section-target.txt b/test/dump/relocations-section-target.txt index 112b655315..075bb9d235 100644 --- a/test/dump/relocations-section-target.txt +++ b/test/dump/relocations-section-target.txt @@ -27,7 +27,7 @@ Custom: - name: "linking" - symbol table [count=2] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] Custom: - name: "reloc.Code" - relocations for section: 4 (Code) [1] diff --git a/test/dump/relocations.txt b/test/dump/relocations.txt index 9114e3562f..ead46a0a43 100644 --- a/test/dump/relocations.txt +++ b/test/dump/relocations.txt @@ -59,7 +59,7 @@ Custom: - symbol table [count=5] - 0: F <__extern.foo> func=0 [ undefined binding=global vis=default ] - 1: F <__extern.bar> func=1 [ undefined binding=global vis=default ] - - 2: F func=2 [ exported no_strip binding=global vis=hidden ] + - 2: F func=2 [ exported no_strip binding=global vis=default ] - 3: T <> table=0 [ binding=local vis=hidden ] - 4: G global=0 [ binding=global vis=default ] Custom: diff --git a/test/dump/symbol-tables-all-features.txt b/test/dump/symbol-tables-all-features.txt index 5aaa07bfeb..a87c8cdda5 100644 --- a/test/dump/symbol-tables-all-features.txt +++ b/test/dump/symbol-tables-all-features.txt @@ -39,7 +39,7 @@ Custom: - name: "linking" - symbol table [count=5] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] - 2: F <> func=2 [ binding=local vis=hidden ] - 3: F func=3 [ binding=global vis=default ] - 4: T table=0 [ binding=global vis=default ] diff --git a/test/dump/symbol-tables.txt b/test/dump/symbol-tables.txt index 04a2085d97..8f716bafa0 100644 --- a/test/dump/symbol-tables.txt +++ b/test/dump/symbol-tables.txt @@ -41,7 +41,7 @@ Custom: - name: "linking" - symbol table [count=6] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] - 2: F <> func=2 [ binding=local vis=hidden ] - 3: F func=3 [ binding=global vis=default ] - 4: T table=0 [ undefined binding=global vis=default ] diff --git a/test/help/wasm2wat.txt b/test/help/wasm2wat.txt index f2b2f5c88f..93fa020485 100644 --- a/test/help/wasm2wat.txt +++ b/test/help/wasm2wat.txt @@ -45,4 +45,5 @@ options: --ignore-custom-section-errors Ignore errors in custom sections --generate-names Give auto-generated names to non-named functions, types, etc. --no-check Don't check for invalid modules + -r, --relocatable Generate relocation annotations ;;; STDOUT ;;)