diff options
Diffstat (limited to 'src')
-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 |
12 files changed, 120 insertions, 61 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"); } } } |