diff options
author | Alon Zakai <azakai@google.com> | 2023-02-23 09:56:28 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-23 09:56:28 -0800 |
commit | e929b9c23cced499d08630c25a2991391cabdabb (patch) | |
tree | d27feeac37443d8bc1ae8feaac1f8e011675a226 | |
parent | a6ae22ca0c5c0f4d5e681d749adc0a2d1bea8861 (diff) | |
download | binaryen-e929b9c23cced499d08630c25a2991391cabdabb.tar.gz binaryen-e929b9c23cced499d08630c25a2991391cabdabb.tar.bz2 binaryen-e929b9c23cced499d08630c25a2991391cabdabb.zip |
[wasm-ctor-eval] Add support for multivalue serialization and a quiet mode (#5510)
Simply loop over the values and use tuple.make.
This also adds a lit test for ctor-eval. I found that the problem blocking us
before was the logging, which confuses the update script. As this test at
least does not require that logging, this PR adds a --quiet flag that
disables the logging, and then a lit test just works.
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 74 | ||||
-rw-r--r-- | test/lit/ctor-eval/multivalue-local.wast | 65 | ||||
-rw-r--r-- | test/lit/help/wasm-ctor-eval.test | 3 |
3 files changed, 124 insertions, 18 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 40abe2f76..1002c9914 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -613,11 +613,23 @@ public: Expression* getSerialization(const Literals& values, Name possibleDefiningGlobal = Name()) { + if (values.size() > 1) { + // We do not support multivalues in defining globals, which store GC refs. + assert(possibleDefiningGlobal.isNull()); + std::vector<Expression*> children; + for (const auto& value : values) { + children.push_back(getSerialization(value)); + } + return Builder(*wasm).makeTupleMake(children); + } assert(values.size() == 1); return getSerialization(values[0], possibleDefiningGlobal); } }; +// Whether to emit informative logging to stdout about the eval process. +static bool quiet = false; + // The outcome of evalling a ctor is one of three states: // // 1. We failed to eval it completely (but perhaps we succeeded partially). In @@ -642,8 +654,10 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, // We don't know the values of parameters, so give up if there are any, unless // we are ignoring them. if (func->getNumParams() > 0 && !ignoreExternalInput) { - std::cout << " ...stopping due to params\n"; - std::cout << RECOMMENDATION "consider --ignore-external-input"; + if (!quiet) { + std::cout << " ...stopping due to params\n"; + std::cout << RECOMMENDATION "consider --ignore-external-input"; + } return EvalCtorOutcome(); } @@ -657,7 +671,9 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, for (Index i = 0; i < func->getNumParams(); i++) { auto type = func->getLocalType(i); if (!LiteralUtils::canMakeZero(type)) { - std::cout << " ...stopping due to non-zeroable param\n"; + if (!quiet) { + std::cout << " ...stopping due to non-zeroable param\n"; + } return EvalCtorOutcome(); } params.push_back(Literal::makeZero(type)); @@ -701,13 +717,15 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, try { flow = instance.visit(curr); } catch (FailToEvalException& fail) { - if (successes == 0) { - std::cout << " ...stopping (in block) since could not eval: " - << fail.why << "\n"; - } else { - std::cout << " ...partial evalling successful, but stopping since " - "could not eval: " - << fail.why << "\n"; + if (!quiet) { + if (successes == 0) { + std::cout << " ...stopping (in block) since could not eval: " + << fail.why << "\n"; + } else { + std::cout << " ...partial evalling successful, but stopping since " + "could not eval: " + << fail.why << "\n"; + } } break; } @@ -725,7 +743,9 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, // We are returning out of the function (either via a return, or via a // break to |block|, which has the same outcome. That means we don't // need to execute any more lines, and can consider them to be executed. - std::cout << " ...stopping in block due to break\n"; + if (!quiet) { + std::cout << " ...stopping in block due to break\n"; + } // Mark us as having succeeded on the entire block, since we have: we // are skipping the rest, which means there is no problem there. We must @@ -795,7 +815,9 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, try { results = instance.callFunction(funcName, params); } catch (FailToEvalException& fail) { - std::cout << " ...stopping since could not eval: " << fail.why << "\n"; + if (!quiet) { + std::cout << " ...stopping since could not eval: " << fail.why << "\n"; + } return EvalCtorOutcome(); } @@ -827,7 +849,9 @@ void evalCtors(Module& wasm, // go one by one, in order, until we fail // TODO: if we knew priorities, we could reorder? for (auto& ctor : ctors) { - std::cout << "trying to eval " << ctor << '\n'; + if (!quiet) { + std::cout << "trying to eval " << ctor << '\n'; + } Export* ex = wasm.getExportOrNull(ctor); if (!ex) { Fatal() << "export not found: " << ctor; @@ -835,12 +859,16 @@ void evalCtors(Module& wasm, auto funcName = ex->value; auto outcome = evalCtor(instance, interface, funcName, ctor); if (!outcome) { - std::cout << " ...stopping\n"; + if (!quiet) { + std::cout << " ...stopping\n"; + } return; } // Success! And we can continue to try more. - std::cout << " ...success on " << ctor << ".\n"; + if (!quiet) { + std::cout << " ...success on " << ctor << ".\n"; + } // Remove the export if we should. auto* exp = wasm.getExport(ctor); @@ -862,8 +890,10 @@ void evalCtors(Module& wasm, } } catch (FailToEvalException& fail) { // that's it, we failed to even create the instance - std::cout << " ...stopping since could not create module instance: " - << fail.why << "\n"; + if (!quiet) { + std::cout << " ...stopping since could not create module instance: " + << fail.why << "\n"; + } return; } } @@ -872,7 +902,9 @@ static bool canEval(Module& wasm) { // Check if we can flatten memory. We need to do so currently because of how // we assume memory is simple and flat. TODO if (!MemoryUtils::flatten(wasm)) { - std::cout << " ...stopping since could not flatten memory\n"; + if (!quiet) { + std::cout << " ...stopping since could not flatten memory\n"; + } return false; } return true; @@ -943,6 +975,12 @@ int main(int argc, const char* argv[]) { [&](Options* o, const std::string& argument) { ignoreExternalInput = true; }) + .add("--quiet", + "-q", + "Do not emit verbose logging about the eval process", + WasmCtorEvalOption, + Options::Arguments::Zero, + [&](Options* o, const std::string& argument) { quiet = true; }) .add_positional("INFILE", Options::Arguments::One, [](Options* o, const std::string& argument) { diff --git a/test/lit/ctor-eval/multivalue-local.wast b/test/lit/ctor-eval/multivalue-local.wast new file mode 100644 index 000000000..56dccd624 --- /dev/null +++ b/test/lit/ctor-eval/multivalue-local.wast @@ -0,0 +1,65 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; RUN: wasm-ctor-eval %s --ctors=multivalue-local --quiet -all -S -o - | filecheck %s + +(module + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (import "a" "b" (func $import)) + (import "a" "b" (func $import)) + + (func $multivalue-local (export "multivalue-local") (result i32) + (local $0 i32) + (local $1 (i32 i32)) + + ;; We can eval this line. But we will stop evalling at the line after it, the + ;; import call. As a result we'll only have a partial evalling of this + ;; function, as a result of which it will begin with sets of the values in the + ;; locals, followed by the import call and the rest. + (local.set $0 + (i32.add ;; This add will be evalled into 42. + (i32.const 41) + (i32.const 1) + ) + ) + (local.set $1 + (tuple.make + (local.get $0) ;; This will turn into 42. + (i32.const 1000) + ) + ) + + (call $import) + + ;; Use the locals so they are not trivally removed. + (i32.add + (local.get $0) + (tuple.extract 0 + (local.get $1) + ) + ) + ) +) +;; CHECK: (export "multivalue-local" (func $multivalue-local_0)) + +;; CHECK: (func $multivalue-local_0 (type $none_=>_i32) (result i32) +;; CHECK-NEXT: (local $0 i32) +;; CHECK-NEXT: (local $1 (i32 i32)) +;; CHECK-NEXT: (local.set $0 +;; CHECK-NEXT: (i32.const 42) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (local.set $1 +;; CHECK-NEXT: (tuple.make +;; CHECK-NEXT: (i32.const 42) +;; CHECK-NEXT: (i32.const 1000) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: (call $import) +;; CHECK-NEXT: (i32.add +;; CHECK-NEXT: (local.get $0) +;; CHECK-NEXT: (tuple.extract 0 +;; CHECK-NEXT: (local.get $1) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) +;; CHECK-NEXT: ) diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index 718249295..34281ea42 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -26,6 +26,9 @@ ;; CHECK-NEXT: --ignore-external-input,-ipi Assumes no env vars are to be read, stdin ;; CHECK-NEXT: is empty, etc. ;; CHECK-NEXT: +;; CHECK-NEXT: --quiet,-q Do not emit verbose logging about the +;; CHECK-NEXT: eval process +;; CHECK-NEXT: ;; CHECK-NEXT: ;; CHECK-NEXT: Tool options: ;; CHECK-NEXT: ------------- |