summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/global-utils.h9
-rw-r--r--src/ir/module-utils.h23
-rw-r--r--src/passes/Print.cpp12
-rw-r--r--src/passes/SimplifyGlobals.cpp8
-rw-r--r--src/shell-interface.h12
-rw-r--r--src/tools/wasm-ctor-eval.cpp20
-rw-r--r--src/wasm-interpreter.h10
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm/wasm-binary.cpp21
-rw-r--r--src/wasm/wasm-s-parser.cpp28
-rw-r--r--src/wasm/wasm-stack.cpp16
-rw-r--r--src/wasm/wasm-validator.cpp21
-rw-r--r--test/multivalue.wast16
-rw-r--r--test/multivalue.wast.from-wast37
-rw-r--r--test/multivalue.wast.fromBinary42
-rw-r--r--test/multivalue.wast.fromBinary.noDebugInfo42
-rw-r--r--test/spec/multivalue.wast15
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)))