summaryrefslogtreecommitdiff
path: root/src/tools/wasm-ctor-eval.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-01-12 09:08:07 -0800
committerGitHub <noreply@github.com>2022-01-12 09:08:07 -0800
commitb48c24f2f967b23ff65f23d7c3cccda4872b5926 (patch)
tree529aa29b6506f4cc71bfe208e8cc0fcec568330d /src/tools/wasm-ctor-eval.cpp
parentb63fea1feefce42be49fa28fd85d01d4a52603a2 (diff)
downloadbinaryen-b48c24f2f967b23ff65f23d7c3cccda4872b5926.tar.gz
binaryen-b48c24f2f967b23ff65f23d7c3cccda4872b5926.tar.bz2
binaryen-b48c24f2f967b23ff65f23d7c3cccda4872b5926.zip
[ctor-eval] Eval functions with a return value (#4443)
This is necessary for e.g. main() which returns an i32.
Diffstat (limited to 'src/tools/wasm-ctor-eval.cpp')
-rw-r--r--src/tools/wasm-ctor-eval.cpp73
1 files changed, 49 insertions, 24 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 3923d137c..a117474a5 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -489,13 +489,28 @@ private:
}
};
+struct EvalCtorOutcome {
+ // Whether we completely evalled the function (that is, we did not fail, and
+ // we did not only partially eval it).
+ bool evalledCompletely;
+
+ // If the function was evalled completely, and it returns something, that
+ // value is given here.
+ Literals results;
+
+ static EvalCtorOutcome incomplete() { return {false, Literals()}; }
+
+ static EvalCtorOutcome complete(Literals results) { return {true, results}; }
+};
+
// Eval a single ctor function. Returns whether we succeeded to completely
-// evaluate the ctor, which means that the caller can proceed to try to eval
-// further ctors if there are any.
-bool evalCtor(EvallingModuleInstance& instance,
- CtorEvalExternalInterface& interface,
- Name funcName,
- Name exportName) {
+// evaluate the ctor (which means that the caller can proceed to try to eval
+// further ctors if there are any), and if we did, the results if the function
+// returns any.
+EvalCtorOutcome evalCtor(EvallingModuleInstance& instance,
+ CtorEvalExternalInterface& interface,
+ Name funcName,
+ Name exportName) {
auto& wasm = instance.wasm;
auto* func = wasm.getFunction(funcName);
@@ -503,13 +518,7 @@ bool evalCtor(EvallingModuleInstance& instance,
// TODO: Maybe use ignoreExternalInput?
if (func->getNumParams() > 0) {
std::cout << " ...stopping due to params\n";
- return false;
- }
-
- // TODO: Handle a return value by emitting a proper constant.
- if (func->getResults() != Type::none) {
- std::cout << " ...stopping due to results\n";
- return false;
+ return EvalCtorOutcome::incomplete();
}
// We want to handle the form of the global constructor function in LLVM. That
@@ -523,10 +532,10 @@ bool evalCtor(EvallingModuleInstance& instance,
//
// Some of those ctors may be inlined, however, which would mean that the
// function could have locals, control flow, etc. However, we assume for now
- // that it does not have parameters at least (whose values we can't tell),
- // or results. And for now we look for a toplevel block and process its
- // children one at a time. This allows us to eval some of the $ctor.*
- // functions (or their inlined contents) even if not all.
+ // that it does not have parameters at least (whose values we can't tell).
+ // And for now we look for a toplevel block and process its children one at a
+ // time. This allows us to eval some of the $ctor.* functions (or their
+ // inlined contents) even if not all.
//
// TODO: Support complete partial evalling, that is, evaluate parts of an
// arbitrary function, and not just a sequence in a single toplevel
@@ -546,6 +555,7 @@ bool evalCtor(EvallingModuleInstance& instance,
// an item in the block that we only partially evalled.
EvallingModuleInstance::FunctionScope appliedScope(func, LiteralList());
+ Literals results;
Index successes = 0;
for (auto* curr : block->list) {
Flow flow;
@@ -568,6 +578,10 @@ bool evalCtor(EvallingModuleInstance& instance,
appliedScope = scope;
successes++;
+ // Note the values here, if any. If we are exiting the function now then
+ // these will be returned.
+ results = flow.values;
+
if (flow.breaking()) {
// 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
@@ -627,22 +641,27 @@ bool evalCtor(EvallingModuleInstance& instance,
// Return true if we evalled the entire block. Otherwise, even if we evalled
// some of it, the caller must stop trying to eval further things.
- return successes == block->list.size();
+ if (successes == block->list.size()) {
+ return EvalCtorOutcome::complete(results);
+ } else {
+ return EvalCtorOutcome::incomplete();
+ }
}
// Otherwise, we don't recognize a pattern that allows us to do partial
// evalling. So simply call the entire function at once and see if we can
// optimize that.
+ Literals results;
try {
- instance.callFunction(funcName, LiteralList());
+ results = instance.callFunction(funcName, LiteralList());
} catch (FailToEvalException& fail) {
std::cout << " ...stopping since could not eval: " << fail.why << "\n";
- return false;
+ return EvalCtorOutcome::incomplete();
}
// Success! Apply the results.
interface.applyToModule();
- return true;
+ return EvalCtorOutcome::complete(results);
}
// Eval all ctors in a module.
@@ -677,12 +696,13 @@ void evalCtors(Module& wasm,
Fatal() << "export not found: " << ctor;
}
auto funcName = ex->value;
- if (!evalCtor(instance, interface, funcName, ctor)) {
+ auto outcome = evalCtor(instance, interface, funcName, ctor);
+ if (!outcome.evalledCompletely) {
std::cout << " ...stopping\n";
return;
}
- // Success! Remove the export, and continue.
+ // Success! And we can continue to try more.
std::cout << " ...success on " << ctor << ".\n";
// Remove the export if we should.
@@ -695,7 +715,12 @@ void evalCtors(Module& wasm,
auto* func = wasm.getFunction(exp->value);
auto copyName = Names::getValidFunctionName(wasm, func->name);
auto* copyFunc = ModuleUtils::copyFunction(func, wasm, copyName);
- copyFunc->body = Builder(wasm).makeNop();
+ if (func->getResults() == Type::none) {
+ copyFunc->body = Builder(wasm).makeNop();
+ } else {
+ copyFunc->body =
+ Builder(wasm).makeConstantExpression(outcome.results);
+ }
wasm.getExport(exp->name)->value = copyName;
}
}