summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-02-23 09:56:28 -0800
committerGitHub <noreply@github.com>2023-02-23 09:56:28 -0800
commite929b9c23cced499d08630c25a2991391cabdabb (patch)
treed27feeac37443d8bc1ae8feaac1f8e011675a226
parenta6ae22ca0c5c0f4d5e681d749adc0a2d1bea8861 (diff)
downloadbinaryen-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.cpp74
-rw-r--r--test/lit/ctor-eval/multivalue-local.wast65
-rw-r--r--test/lit/help/wasm-ctor-eval.test3
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: -------------