diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2020-04-02 10:36:19 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-02 10:36:19 -0700 |
commit | 80c5164e1f50ed26e6fab373a563fd7a84135429 (patch) | |
tree | ac944407ac6bf1b26e524d31a3db8c410e4599e7 | |
parent | 702b99508487bc5f56c409d890644b3b9212ae81 (diff) | |
download | binaryen-80c5164e1f50ed26e6fab373a563fd7a84135429.tar.gz binaryen-80c5164e1f50ed26e6fab373a563fd7a84135429.tar.bz2 binaryen-80c5164e1f50ed26e6fab373a563fd7a84135429.zip |
Tuple globals (#2718)
Since it wasn't easy to support tuples in Asyncify's call support
using temporary functions, we decided to allow tuple-typed globals
after all. This PR adds support for parsing, printing, lowering, and
interpreting tuple globals and also adds validation ensuring that
imported and exported globals do not have tuple types.
-rw-r--r-- | src/ir/global-utils.h | 9 | ||||
-rw-r--r-- | src/ir/module-utils.h | 23 | ||||
-rw-r--r-- | src/passes/Print.cpp | 12 | ||||
-rw-r--r-- | src/passes/SimplifyGlobals.cpp | 8 | ||||
-rw-r--r-- | src/shell-interface.h | 12 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 20 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 10 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 21 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 28 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 21 | ||||
-rw-r--r-- | test/multivalue.wast | 16 | ||||
-rw-r--r-- | test/multivalue.wast.from-wast | 37 | ||||
-rw-r--r-- | test/multivalue.wast.fromBinary | 42 | ||||
-rw-r--r-- | test/multivalue.wast.fromBinary.noDebugInfo | 42 | ||||
-rw-r--r-- | test/spec/multivalue.wast | 15 |
17 files changed, 240 insertions, 93 deletions
diff --git a/src/ir/global-utils.h b/src/ir/global-utils.h index e096aec8c..b575d6952 100644 --- a/src/ir/global-utils.h +++ b/src/ir/global-utils.h @@ -54,6 +54,15 @@ getGlobalInitializedToImport(Module& wasm, Name module, Name base) { } inline bool canInitializeGlobal(const Expression* curr) { + if (auto* tuple = curr->dynCast<TupleMake>()) { + for (auto* op : tuple->operands) { + if (!op->is<Const>() && !op->is<RefNull>() && + !op->is<RefFunc>() & !op->is<GlobalGet>()) { + return false; + } + } + return true; + } return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>() || curr->is<GlobalGet>(); } diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index be924f742..485bc4833 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -35,8 +35,8 @@ namespace ModuleUtils { // just use them directly). struct BinaryIndexes { std::unordered_map<Name, Index> functionIndexes; - std::unordered_map<Name, Index> globalIndexes; std::unordered_map<Name, Index> eventIndexes; + std::unordered_map<Name, Index> globalIndexes; BinaryIndexes(Module& wasm) { auto addIndexes = [&](auto& source, auto& indexes) { @@ -56,8 +56,27 @@ struct BinaryIndexes { } }; addIndexes(wasm.functions, functionIndexes); - addIndexes(wasm.globals, globalIndexes); addIndexes(wasm.events, eventIndexes); + + // Globals may have tuple types in the IR, in which case they lower to + // multiple globals, one for each tuple element, in the binary. Tuple + // globals therefore occupy multiple binary indices, and we have to take + // that into account when calculating indices. + Index globalCount = 0; + auto addGlobal = [&](auto* curr) { + globalIndexes[curr->name] = globalCount; + globalCount += curr->type.size(); + }; + for (auto& curr : wasm.globals) { + if (curr->imported()) { + addGlobal(curr.get()); + } + } + for (auto& curr : wasm.globals) { + if (!curr->imported()) { + addGlobal(curr.get()); + } + } } }; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index d6dbb3300..18f2beb43 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -59,12 +59,12 @@ static std::ostream& printLocal(Index index, Function* func, std::ostream& o) { // Unlike the default format, tuple types in s-expressions should not have // commas. -struct LocalType { +struct SExprType { Type type; - LocalType(Type type) : type(type){}; + SExprType(Type type) : type(type){}; }; -static std::ostream& operator<<(std::ostream& o, const LocalType& localType) { +static std::ostream& operator<<(std::ostream& o, const SExprType& localType) { Type type = localType.type; if (type.isMulti()) { const std::vector<Type>& types = type.expand(); @@ -2072,9 +2072,9 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { } void emitGlobalType(Global* curr) { if (curr->mutable_) { - o << "(mut " << curr->type << ')'; + o << "(mut " << SExprType(curr->type) << ')'; } else { - o << curr->type; + o << SExprType(curr->type); } } void visitImportedGlobal(Global* curr) { @@ -2155,7 +2155,7 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { o << '('; printMinor(o, "local "); printLocal(i, currFunction, o) - << ' ' << LocalType(curr->getLocalType(i)) << ')'; + << ' ' << SExprType(curr->getLocalType(i)) << ')'; o << maybeNewLine; } // Print the body. diff --git a/src/passes/SimplifyGlobals.cpp b/src/passes/SimplifyGlobals.cpp index 55c16910a..5fa1686fc 100644 --- a/src/passes/SimplifyGlobals.cpp +++ b/src/passes/SimplifyGlobals.cpp @@ -109,7 +109,7 @@ struct ConstantGlobalApplier if (auto* set = curr->dynCast<GlobalSet>()) { if (Properties::isConstantExpression(set->value)) { currConstantGlobals[set->name] = - getSingleLiteralFromConstExpression(set->value); + getLiteralsFromConstExpression(set->value); } else { currConstantGlobals.erase(set->name); } @@ -160,7 +160,7 @@ private: bool replaced = false; // The globals currently constant in the linear trace. - std::map<Name, Literal> currConstantGlobals; + std::map<Name, Literals> currConstantGlobals; }; } // anonymous namespace @@ -248,12 +248,12 @@ struct SimplifyGlobals : public Pass { void propagateConstantsToGlobals() { // Go over the list of globals in order, which is the order of // initialization as well, tracking their constant values. - std::map<Name, Literal> constantGlobals; + std::map<Name, Literals> constantGlobals; for (auto& global : module->globals) { if (!global->imported()) { if (Properties::isConstantExpression(global->init)) { constantGlobals[global->name] = - getSingleLiteralFromConstExpression(global->init); + getLiteralsFromConstExpression(global->init); } else if (auto* get = global->init->dynCast<GlobalGet>()) { auto iter = constantGlobals.find(get->name); if (iter != constantGlobals.end()) { diff --git a/src/shell-interface.h b/src/shell-interface.h index de4fe357a..94ecd61c3 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -95,22 +95,22 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { table.resize(wasm.table.initial); } - void importGlobals(std::map<Name, Literal>& globals, Module& wasm) override { + void importGlobals(std::map<Name, Literals>& globals, Module& wasm) override { // add spectest globals ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) { if (import->module == SPECTEST && import->base.startsWith(GLOBAL)) { switch (import->type.getSingle()) { case Type::i32: - globals[import->name] = Literal(int32_t(666)); + globals[import->name] = {Literal(int32_t(666))}; break; case Type::i64: - globals[import->name] = Literal(int64_t(666)); + globals[import->name] = {Literal(int64_t(666))}; break; case Type::f32: - globals[import->name] = Literal(float(666.6)); + globals[import->name] = {Literal(float(666.6))}; break; case Type::f64: - globals[import->name] = Literal(double(666.6)); + globals[import->name] = {Literal(double(666.6))}; break; case Type::v128: assert(false && "v128 not implemented yet"); @@ -118,7 +118,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { case Type::anyref: case Type::nullref: case Type::exnref: - globals[import->name] = Literal::makeNullref(); + globals[import->name] = {Literal::makeNullref()}; break; case Type::none: case Type::unreachable: diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 512c47396..ca0dafd8e 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -48,7 +48,7 @@ struct FailToEvalException { // We do not have access to imported globals class EvallingGlobalManager { // values of globals - std::map<Name, Literal> globals; + std::map<Name, Literals> globals; // globals that are dangerous to modify in the module std::set<Name> dangerousGlobals; @@ -70,7 +70,7 @@ public: return !(*this == other); } - Literal& operator[](Name name) { + Literals& operator[](Name name) { if (dangerousGlobals.count(name) > 0) { std::string extra; if (name == "___dso_handle") { @@ -87,11 +87,11 @@ public: struct Iterator { Name first; - Literal second; + Literals second; bool found; Iterator() : found(false) {} - Iterator(Name name, Literal value) + Iterator(Name name, Literals value) : first(name), second(value), found(true) {} bool operator==(const Iterator& other) { @@ -177,28 +177,28 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { // fill usable values for stack imports, and globals initialized to them ImportInfo imports(wasm_); if (auto* stackTop = imports.getImportedGlobal(ENV, STACKTOP)) { - globals[stackTop->name] = Literal(int32_t(STACK_START)); + globals[stackTop->name] = {Literal(int32_t(STACK_START))}; if (auto* stackTop = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) { - globals[stackTop->name] = Literal(int32_t(STACK_START)); + globals[stackTop->name] = {Literal(int32_t(STACK_START))}; } } if (auto* stackMax = imports.getImportedGlobal(ENV, STACK_MAX)) { - globals[stackMax->name] = Literal(int32_t(STACK_START)); + globals[stackMax->name] = {Literal(int32_t(STACK_START))}; if (auto* stackMax = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) { - globals[stackMax->name] = Literal(int32_t(STACK_START)); + globals[stackMax->name] = {Literal(int32_t(STACK_START))}; } } // fill in fake values for everything else, which is dangerous to use ModuleUtils::iterDefinedGlobals(wasm_, [&](Global* defined) { if (globals.find(defined->name) == globals.end()) { - globals[defined->name] = Literal::makeSingleZero(defined->type); + globals[defined->name] = Literal::makeZero(defined->type); } }); ModuleUtils::iterImportedGlobals(wasm_, [&](Global* import) { if (globals.find(import->name) == globals.end()) { - globals[import->name] = Literal::makeSingleZero(import->type); + globals[import->name] = Literal::makeZero(import->type); } }); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 4765efa0e..ca8041d5a 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1432,7 +1432,7 @@ public: globals[global->name] = ConstantExpressionRunner<GlobalManager>(globals, maxDepth) .visit(global->init) - .getSingleValue(); + .values; }); // initialize the rest of the external interface @@ -1457,10 +1457,10 @@ public: return callFunction(export_->value, arguments); } - Literal callExport(Name name) { return callExport(name, LiteralList()); } + Literals callExport(Name name) { return callExport(name, LiteralList()); } // get an exported global - Literal getExport(Name name) { + Literals getExport(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_) { externalInterface->trap("getExport external not found"); @@ -1677,7 +1677,7 @@ private: } NOTE_EVAL1(name); NOTE_EVAL1(flow.getSingleValue()); - instance.globals[name] = flow.getSingleValue(); + instance.globals[name] = flow.values; return Flow(); } @@ -2232,7 +2232,7 @@ protected: }; // The default ModuleInstance uses a trivial global manager -using TrivialGlobalManager = std::map<Name, Literal>; +using TrivialGlobalManager = std::map<Name, Literals>; class ModuleInstance : public ModuleInstanceBase<TrivialGlobalManager, ModuleInstance> { public: diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 420692808..24cb7914a 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -160,6 +160,7 @@ private: } Type stringToType(const char* str, bool allowError = false, bool prefix = false); + Type elementToType(Element& s); Type stringToLaneType(const char* str); bool isType(cashew::IString str) { return stringToType(str, true) != Type::none; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index c36789828..3b8649d29 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -376,14 +376,25 @@ void WasmBinaryWriter::writeGlobals() { } BYN_TRACE("== writeglobals\n"); auto start = startSection(BinaryConsts::Section::Global); - auto num = importInfo->getNumDefinedGlobals(); + // Count and emit the total number of globals after tuple globals have been + // expanded into their constituent parts. + Index num = 0; + ModuleUtils::iterDefinedGlobals( + *wasm, [&num](Global* global) { num += global->type.size(); }); o << U32LEB(num); ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) { BYN_TRACE("write one\n"); - o << binaryType(global->type); - o << U32LEB(global->mutable_); - writeExpression(global->init); - o << int8_t(BinaryConsts::End); + const auto& types = global->type.expand(); + for (size_t i = 0; i < types.size(); ++i) { + o << binaryType(types[i]); + o << U32LEB(global->mutable_); + if (types.size() == 1) { + writeExpression(global->init); + } else { + writeExpression(global->init->cast<TupleMake>()->operands[i]); + } + o << int8_t(BinaryConsts::End); + } }); finishSection(start); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 4354b747a..a39e52b6d 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -546,12 +546,7 @@ SExpressionWasmBuilder::parseParamOrLocal(Element& s, size_t& localIndex) { throw ParseException( "params may not have tuple types", s[i]->line, s[i]->col); } - auto& tuple = s[i]->list(); - std::vector<Type> types; - for (size_t j = 0; j < s[i]->size(); ++j) { - types.push_back(stringToType(tuple[j]->str())); - } - type = Type(types); + type = elementToType(*s[i]); } namedParams.emplace_back(name, type); } @@ -886,6 +881,18 @@ Type SExpressionWasmBuilder::stringToType(const char* str, throw ParseException(std::string("invalid wasm type: ") + str); } +Type SExpressionWasmBuilder::elementToType(Element& s) { + if (s.isStr()) { + return stringToType(s.str(), false, false); + } + auto& tuple = s.list(); + std::vector<Type> types; + for (size_t i = 0; i < s.size(); ++i) { + types.push_back(stringToType(tuple[i]->str())); + } + return Type(types); +} + Type SExpressionWasmBuilder::stringToLaneType(const char* str) { if (strcmp(str, "i8x16") == 0) { return Type::i32; @@ -2278,7 +2285,7 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { bool exported = false; Name importModule, importBase; while (i < s.size() && s[i]->isList()) { - auto& inner = *s[i]; + auto& inner = *s[i++]; if (elementStartsWith(inner, EXPORT)) { auto ex = make_unique<Export>(); ex->name = inner[1]->str(); @@ -2289,16 +2296,15 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { } wasm.addExport(ex.release()); exported = true; - i++; } else if (elementStartsWith(inner, IMPORT)) { importModule = inner[1]->str(); importBase = inner[2]->str(); - i++; } else if (elementStartsWith(inner, MUT)) { mutable_ = true; - type = stringToType(inner[1]->str()); - i++; + type = elementToType(*inner[1]); + break; } else { + type = elementToType(inner); break; } } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 9b5dc3f22..48fe79fa1 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -114,13 +114,21 @@ void BinaryInstWriter::visitLocalSet(LocalSet* curr) { } void BinaryInstWriter::visitGlobalGet(GlobalGet* curr) { - o << int8_t(BinaryConsts::GlobalGet) - << U32LEB(parent.getGlobalIndex(curr->name)); + // Emit a global.get for each element if this is a tuple global + Index index = parent.getGlobalIndex(curr->name); + size_t numValues = curr->type.size(); + for (Index i = 0; i < numValues; ++i) { + o << int8_t(BinaryConsts::GlobalGet) << U32LEB(index + i); + } } void BinaryInstWriter::visitGlobalSet(GlobalSet* curr) { - o << int8_t(BinaryConsts::GlobalSet) - << U32LEB(parent.getGlobalIndex(curr->name)); + // Emit a global.set for each element if this is a tuple global + Index index = parent.getGlobalIndex(curr->name); + size_t numValues = parent.getModule()->getGlobal(curr->name)->type.size(); + for (int i = numValues - 1; i >= 0; --i) { + o << int8_t(BinaryConsts::GlobalSet) << U32LEB(index + i); + } } void BinaryInstWriter::visitLoad(Load* curr) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 368c01bdc..c152e4b98 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2137,12 +2137,14 @@ static void validateImports(Module& module, ValidationInfo& info) { } } }); - if (!module.features.hasMutableGlobals()) { - ModuleUtils::iterImportedGlobals(module, [&](Global* curr) { + ModuleUtils::iterImportedGlobals(module, [&](Global* curr) { + if (!module.features.hasMutableGlobals()) { info.shouldBeFalse( curr->mutable_, curr->name, "Imported global cannot be mutable"); - }); - } + } + info.shouldBeTrue( + curr->type.isSingle(), curr->name, "Imported global cannot be tuple"); + }); } static void validateExports(Module& module, ValidationInfo& info) { @@ -2164,11 +2166,14 @@ static void validateExports(Module& module, ValidationInfo& info) { "Exported function must not have i64 results"); } } - } else if (curr->kind == ExternalKind::Global && - !module.features.hasMutableGlobals()) { + } else if (curr->kind == ExternalKind::Global) { if (Global* g = module.getGlobalOrNull(curr->value)) { - info.shouldBeFalse( - g->mutable_, g->name, "Exported global cannot be mutable"); + if (!module.features.hasMutableGlobals()) { + info.shouldBeFalse( + g->mutable_, g->name, "Exported global cannot be mutable"); + } + info.shouldBeTrue( + g->type.isSingle(), g->name, "Exported global cannot be tuple"); } } } diff --git a/test/multivalue.wast b/test/multivalue.wast index 08e23f62a..d740d384f 100644 --- a/test/multivalue.wast +++ b/test/multivalue.wast @@ -1,7 +1,8 @@ (module (import "env" "pair" (func $pair (result i32 i64))) - - ;; Test basic lowering of tuple.make, tuple.extract, and tuple locals + (global $g1 (mut (i32 i64)) (tuple.make (i32.const 0) (i64.const 0))) + (global $g2 (i32 i64) (tuple.make (i32.const 0) (i64.const 0))) + ;; Test basic lowering of tuple.make, tuple.extract, and tuple variables (func $triple (result i32 i64 f32) (tuple.make (i32.const 42) @@ -51,6 +52,17 @@ ) ) + ;; Test multivalue globals + (func $global (result i32 i64) + (global.set $g1 + (tuple.make + (i32.const 42) + (i64.const 7) + ) + ) + (global.get $g2) + ) + ;; Test lowering of multivalue drops (func $drop-call (drop diff --git a/test/multivalue.wast.from-wast b/test/multivalue.wast.from-wast index a918979f5..d23198e94 100644 --- a/test/multivalue.wast.from-wast +++ b/test/multivalue.wast.from-wast @@ -9,6 +9,14 @@ (type $none_=>_i32_i64_nullref (func (result i32 i64 nullref))) (type $none_=>_f32 (func (result f32))) (import "env" "pair" (func $pair (result i32 i64))) + (global $g1 (mut (i32 i64)) (tuple.make + (i32.const 0) + (i64.const 0) + )) + (global $g2 (i32 i64) (tuple.make + (i32.const 0) + (i64.const 0) + )) (func $triple (; 1 ;) (result i32 i64 f32) (tuple.make (i32.const 42) @@ -57,12 +65,21 @@ ) ) ) - (func $drop-call (; 7 ;) + (func $global (; 7 ;) (result i32 i64) + (global.set $g1 + (tuple.make + (i32.const 42) + (i64.const 7) + ) + ) + (global.get $g2) + ) + (func $drop-call (; 8 ;) (drop (call $pair) ) ) - (func $drop-tuple-make (; 8 ;) + (func $drop-tuple-make (; 9 ;) (drop (tuple.make (i32.const 42) @@ -70,7 +87,7 @@ ) ) ) - (func $drop-block (; 9 ;) + (func $drop-block (; 10 ;) (drop (block $block (result i32 i64) (tuple.make @@ -80,7 +97,7 @@ ) ) ) - (func $mv-return (; 10 ;) (result i32 i64) + (func $mv-return (; 11 ;) (result i32 i64) (return (tuple.make (i32.const 42) @@ -88,7 +105,7 @@ ) ) ) - (func $mv-return-in-block (; 11 ;) (result i32 i64) + (func $mv-return-in-block (; 12 ;) (result i32 i64) (block $block (result i32 i64) (return (tuple.make @@ -98,7 +115,7 @@ ) ) ) - (func $mv-block-break (; 12 ;) (result i32 i64) + (func $mv-block-break (; 13 ;) (result i32 i64) (block $l (result i32 i64) (br $l (tuple.make @@ -108,7 +125,7 @@ ) ) ) - (func $mv-block-br-if (; 13 ;) (result i32 i64) + (func $mv-block-br-if (; 14 ;) (result i32 i64) (block $l (result i32 i64) (br_if $l (tuple.make @@ -119,7 +136,7 @@ ) ) ) - (func $mv-if (; 14 ;) (result i32 i64 anyref) + (func $mv-if (; 15 ;) (result i32 i64 anyref) (if (result i32 i64 nullref) (i32.const 1) (tuple.make @@ -134,7 +151,7 @@ ) ) ) - (func $mv-loop (; 15 ;) (result i32 i64) + (func $mv-loop (; 16 ;) (result i32 i64) (loop $loop-in (result i32 i64) (tuple.make (i32.const 42) @@ -142,7 +159,7 @@ ) ) ) - (func $mv-switch (; 16 ;) (result i32 i64) + (func $mv-switch (; 17 ;) (result i32 i64) (block $a (result i32 i64) (block $b (result i32 i64) (br_table $a $b diff --git a/test/multivalue.wast.fromBinary b/test/multivalue.wast.fromBinary index 32f744c46..2a1bd095e 100644 --- a/test/multivalue.wast.fromBinary +++ b/test/multivalue.wast.fromBinary @@ -9,6 +9,10 @@ (type $none_=>_i32_i64_nullref (func (result i32 i64 nullref))) (type $none_=>_f32 (func (result f32))) (import "env" "pair" (func $pair (result i32 i64))) + (global $global$0 (mut i32) (i32.const 0)) + (global $global$1 (mut i64) (i64.const 0)) + (global $global$2 i32 (i32.const 0)) + (global $global$3 i64 (i64.const 0)) (func $triple (; 1 ;) (result i32 i64 f32) (tuple.make (i32.const 42) @@ -235,7 +239,25 @@ ) (unreachable) ) - (func $drop-call (; 7 ;) + (func $global (; 7 ;) (result i32 i64) + (local $0 i32) + (global.set $global$0 + (block (result i32) + (local.set $0 + (i32.const 42) + ) + (global.set $global$1 + (i64.const 7) + ) + (local.get $0) + ) + ) + (tuple.make + (global.get $global$2) + (global.get $global$3) + ) + ) + (func $drop-call (; 8 ;) (local $0 (i32 i64)) (local $1 i32) (local.set $0 @@ -257,7 +279,7 @@ ) ) ) - (func $drop-tuple-make (; 8 ;) + (func $drop-tuple-make (; 9 ;) (local $0 i32) (drop (block (result i32) @@ -271,7 +293,7 @@ ) ) ) - (func $drop-block (; 9 ;) + (func $drop-block (; 10 ;) (local $0 (i32 i64)) (local $1 i32) (local.set $0 @@ -298,7 +320,7 @@ ) ) ) - (func $mv-return (; 10 ;) (result i32 i64) + (func $mv-return (; 11 ;) (result i32 i64) (return (tuple.make (i32.const 42) @@ -306,7 +328,7 @@ ) ) ) - (func $mv-return-in-block (; 11 ;) (result i32 i64) + (func $mv-return-in-block (; 12 ;) (result i32 i64) (return (tuple.make (i32.const 42) @@ -314,7 +336,7 @@ ) ) ) - (func $mv-block-break (; 12 ;) (result i32 i64) + (func $mv-block-break (; 13 ;) (result i32 i64) (local $0 (i32 i64)) (local.set $0 (block $label$1 (result i32 i64) @@ -335,7 +357,7 @@ ) ) ) - (func $mv-block-br-if (; 13 ;) (result i32 i64) + (func $mv-block-br-if (; 14 ;) (result i32 i64) (local $0 (i32 i64)) (local $1 (i32 i64)) (local.set $1 @@ -368,7 +390,7 @@ ) ) ) - (func $mv-if (; 14 ;) (result i32 i64 anyref) + (func $mv-if (; 15 ;) (result i32 i64 anyref) (local $0 (i32 i64 nullref)) (local.set $0 (if (result i32 i64 nullref) @@ -397,7 +419,7 @@ ) ) ) - (func $mv-loop (; 15 ;) (result i32 i64) + (func $mv-loop (; 16 ;) (result i32 i64) (local $0 (i32 i64)) (local.set $0 (loop $label$1 (result i32 i64) @@ -416,7 +438,7 @@ ) ) ) - (func $mv-switch (; 16 ;) (result i32 i64) + (func $mv-switch (; 17 ;) (result i32 i64) (local $0 (i32 i64)) (local $1 (i32 i64)) (local.set $1 diff --git a/test/multivalue.wast.fromBinary.noDebugInfo b/test/multivalue.wast.fromBinary.noDebugInfo index c105df989..1682e3144 100644 --- a/test/multivalue.wast.fromBinary.noDebugInfo +++ b/test/multivalue.wast.fromBinary.noDebugInfo @@ -9,6 +9,10 @@ (type $none_=>_i32_i64_nullref (func (result i32 i64 nullref))) (type $none_=>_f32 (func (result f32))) (import "env" "pair" (func $fimport$0 (result i32 i64))) + (global $global$0 (mut i32) (i32.const 0)) + (global $global$1 (mut i64) (i64.const 0)) + (global $global$2 i32 (i32.const 0)) + (global $global$3 i64 (i64.const 0)) (func $0 (; 1 ;) (result i32 i64 f32) (tuple.make (i32.const 42) @@ -235,7 +239,25 @@ ) (unreachable) ) - (func $6 (; 7 ;) + (func $6 (; 7 ;) (result i32 i64) + (local $0 i32) + (global.set $global$0 + (block (result i32) + (local.set $0 + (i32.const 42) + ) + (global.set $global$1 + (i64.const 7) + ) + (local.get $0) + ) + ) + (tuple.make + (global.get $global$2) + (global.get $global$3) + ) + ) + (func $7 (; 8 ;) (local $0 (i32 i64)) (local $1 i32) (local.set $0 @@ -257,7 +279,7 @@ ) ) ) - (func $7 (; 8 ;) + (func $8 (; 9 ;) (local $0 i32) (drop (block (result i32) @@ -271,7 +293,7 @@ ) ) ) - (func $8 (; 9 ;) + (func $9 (; 10 ;) (local $0 (i32 i64)) (local $1 i32) (local.set $0 @@ -298,7 +320,7 @@ ) ) ) - (func $9 (; 10 ;) (result i32 i64) + (func $10 (; 11 ;) (result i32 i64) (return (tuple.make (i32.const 42) @@ -306,7 +328,7 @@ ) ) ) - (func $10 (; 11 ;) (result i32 i64) + (func $11 (; 12 ;) (result i32 i64) (return (tuple.make (i32.const 42) @@ -314,7 +336,7 @@ ) ) ) - (func $11 (; 12 ;) (result i32 i64) + (func $12 (; 13 ;) (result i32 i64) (local $0 (i32 i64)) (local.set $0 (block $label$1 (result i32 i64) @@ -335,7 +357,7 @@ ) ) ) - (func $12 (; 13 ;) (result i32 i64) + (func $13 (; 14 ;) (result i32 i64) (local $0 (i32 i64)) (local $1 (i32 i64)) (local.set $1 @@ -368,7 +390,7 @@ ) ) ) - (func $13 (; 14 ;) (result i32 i64 anyref) + (func $14 (; 15 ;) (result i32 i64 anyref) (local $0 (i32 i64 nullref)) (local.set $0 (if (result i32 i64 nullref) @@ -397,7 +419,7 @@ ) ) ) - (func $14 (; 15 ;) (result i32 i64) + (func $15 (; 16 ;) (result i32 i64) (local $0 (i32 i64)) (local.set $0 (loop $label$1 (result i32 i64) @@ -416,7 +438,7 @@ ) ) ) - (func $15 (; 16 ;) (result i32 i64) + (func $16 (; 17 ;) (result i32 i64) (local $0 (i32 i64)) (local $1 (i32 i64)) (local.set $1 diff --git a/test/spec/multivalue.wast b/test/spec/multivalue.wast index d6089721d..3891d6983 100644 --- a/test/spec/multivalue.wast +++ b/test/spec/multivalue.wast @@ -1,4 +1,5 @@ (module + (global $global_pair (mut (i32 i64)) (tuple.make (i32.const 0) (i64.const 0))) (func $pair (export "pair") (result i32 i64) (tuple.make (i32.const 42) @@ -9,6 +10,17 @@ (local $x (i32 i64)) (local.get $x) ) + (func (export "tuple-global-get") (result i32 i64) + (global.get $global_pair) + ) + (func (export "tuple-global-set") + (global.set $global_pair + (tuple.make + (i32.const 42) + (i64.const 7) + ) + ) + ) (func (export "tail-call") (result i32 i64) (return_call $pair) (unreachable) @@ -17,4 +29,7 @@ (assert_return (invoke "pair") (tuple.make (i32.const 42) (i64.const 7))) (assert_return (invoke "tuple-local") (tuple.make (i32.const 0) (i64.const 0))) +(assert_return (invoke "tuple-global-get") (tuple.make (i32.const 0) (i64.const 0))) +(assert_return (invoke "tuple-global-set")) +(assert_return (invoke "tuple-global-get") (tuple.make (i32.const 42) (i64.const 7))) (assert_return (invoke "tail-call") (tuple.make (i32.const 42) (i64.const 7))) |