diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/DeadArgumentElimination.cpp | 40 | ||||
-rw-r--r-- | src/passes/param-utils.cpp | 62 | ||||
-rw-r--r-- | src/passes/param-utils.h | 16 |
3 files changed, 80 insertions, 38 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index ce4d17c74..784aec31a 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -225,7 +225,6 @@ struct DAE : public Pass { continue; } auto* func = module->getFunction(name); - auto numParams = func->getNumParams(); // Refine argument types before doing anything else. This does not // affect whether an argument is used or not, it just refines the type // where possible. @@ -234,39 +233,12 @@ struct DAE : public Pass { if (refineReturnTypes(func, calls, module)) { refinedReturnTypes = true; } - // Check if all calls pass the same constant for a particular argument. - for (Index i = 0; i < numParams; i++) { - Literal value; - for (auto* call : calls) { - assert(call->target == name); - assert(call->operands.size() == numParams); - auto* operand = call->operands[i]; - // TODO: refnull etc. - if (auto* c = operand->dynCast<Const>()) { - if (value.type == Type::none) { - // This is the first value seen. - value = c->value; - } else if (value != c->value) { - // Not identical, give up - value = Literal(Type::none); - break; - } - } else { - // Not a constant, give up - value = Literal(Type::none); - break; - } - } - if (value.type != Type::none) { - // Success! We can just apply the constant in the function, which - // makes the parameter value unused, which lets us remove it later. - Builder builder(*module); - func->body = builder.makeSequence( - builder.makeLocalSet(i, builder.makeConst(value)), func->body); - // Mark it as unused, which we know it now is (no point to - // re-scan just for that). - infoMap[name].unusedParams.insert(i); - } + auto optimizedIndexes = + ParamUtils::applyConstantValues({func}, calls, {}, module); + for (auto i : optimizedIndexes) { + // Mark it as unused, which we know it now is (no point to re-scan just + // for that). + infoMap[name].unusedParams.insert(i); } } if (refinedReturnTypes) { diff --git a/src/passes/param-utils.cpp b/src/passes/param-utils.cpp index 019df6d7f..ded96a826 100644 --- a/src/passes/param-utils.cpp +++ b/src/passes/param-utils.cpp @@ -16,6 +16,7 @@ #include "ir/function-utils.h" #include "ir/local-graph.h" +#include "ir/possible-constant.h" #include "ir/type-updating.h" #include "support/sorted_vector.h" #include "wasm.h" @@ -44,7 +45,7 @@ std::unordered_set<Index> getUsedParams(Function* func) { return usedParams; } -bool removeParameter(const std::vector<Function*> funcs, +bool removeParameter(const std::vector<Function*>& funcs, Index index, const std::vector<Call*>& calls, const std::vector<CallRef*>& callRefs, @@ -137,7 +138,7 @@ bool removeParameter(const std::vector<Function*> funcs, return true; } -SortedVector removeParameters(const std::vector<Function*> funcs, +SortedVector removeParameters(const std::vector<Function*>& funcs, SortedVector indexes, const std::vector<Call*>& calls, const std::vector<CallRef*>& callRefs, @@ -174,4 +175,61 @@ SortedVector removeParameters(const std::vector<Function*> funcs, return removed; } +SortedVector applyConstantValues(const std::vector<Function*>& funcs, + const std::vector<Call*>& calls, + const std::vector<CallRef*>& callRefs, + Module* module) { + assert(funcs.size() > 0); + auto* first = funcs[0]; +#ifndef NDEBUG + for (auto* func : funcs) { + assert(func->type == first->type); + } +#endif + + SortedVector optimized; + auto numParams = first->getNumParams(); + for (Index i = 0; i < numParams; i++) { + PossibleConstantValues value; + + // Processes one operand. + auto processOperand = [&](Expression* operand) { + if (auto* c = operand->dynCast<Const>()) { + value.note(c->value); + return; + } + // TODO: refnull, immutable globals, etc. + // Not a constant, give up + value.noteUnknown(); + }; + for (auto* call : calls) { + processOperand(call->operands[i]); + if (!value.isConstant()) { + break; + } + } + for (auto* call : callRefs) { + processOperand(call->operands[i]); + if (!value.isConstant()) { + break; + } + } + if (!value.isConstant()) { + continue; + } + + // Optimize: write the constant value in the function bodies, making them + // ignore the parameter's value. + Builder builder(*module); + for (auto* func : funcs) { + func->body = builder.makeSequence( + builder.makeLocalSet(i, builder.makeConst(value.getConstantLiteral())), + func->body); + } + optimized.insert(i); + } + + return optimized; +} + } // namespace wasm::ParamUtils diff --git a/src/passes/param-utils.h b/src/passes/param-utils.h index 9bfbf1aec..10645b230 100644 --- a/src/passes/param-utils.h +++ b/src/passes/param-utils.h @@ -58,7 +58,7 @@ std::unordered_set<Index> getUsedParams(Function* func); // use cases are either to send a single function, or to send a set of functions // that all have the same heap type (and so if they all do not use some // parameter, it can be removed from them all). -bool removeParameter(const std::vector<Function*> funcs, +bool removeParameter(const std::vector<Function*>& funcs, Index index, const std::vector<Call*>& calls, const std::vector<CallRef*>& callRefs, @@ -67,13 +67,25 @@ bool removeParameter(const std::vector<Function*> funcs, // The same as removeParameter, but gets a sorted list of indexes. It tries to // remove them all, and returns which we removed. -SortedVector removeParameters(const std::vector<Function*> funcs, +SortedVector removeParameters(const std::vector<Function*>& funcs, SortedVector indexes, const std::vector<Call*>& calls, const std::vector<CallRef*>& callRefs, Module* module, PassRunner* runner); +// Given a set of functions and the calls and call_refs that reach them, find +// which parameters are passed the same constant value in all the calls. For +// each such parameter, apply it inside the function, that is, do a local.set of +// that value in the function. The parameter's incoming value is then ignored, +// which allows other optimizations to remove it. +// +// Returns the indexes that were optimized. +SortedVector applyConstantValues(const std::vector<Function*>& funcs, + const std::vector<Call*>& calls, + const std::vector<CallRef*>& callRefs, + Module* module); + } // namespace wasm::ParamUtils #endif // wasm_ir_function_h |