summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/DeadArgumentElimination.cpp40
-rw-r--r--src/passes/param-utils.cpp62
-rw-r--r--src/passes/param-utils.h16
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