diff options
-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))) |