diff options
author | Alon Zakai <azakai@google.com> | 2022-01-12 09:08:07 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-12 09:08:07 -0800 |
commit | b48c24f2f967b23ff65f23d7c3cccda4872b5926 (patch) | |
tree | 529aa29b6506f4cc71bfe208e8cc0fcec568330d /src/tools/wasm-ctor-eval.cpp | |
parent | b63fea1feefce42be49fa28fd85d01d4a52603a2 (diff) | |
download | binaryen-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.cpp | 73 |
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; } } |