summaryrefslogtreecommitdiff
path: root/src/passes
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes')
-rw-r--r--src/passes/RemoveUnusedBrs.cpp62
1 files changed, 44 insertions, 18 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index fca5b7db4..576f2fe91 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -80,38 +80,64 @@ static bool canTurnIfIntoBrIf(Expression* ifCondition,
return !EffectAnalyzer(options, wasm, ifCondition).invalidates(value);
}
-// This leads to similar choices as LLVM does.
-// See https://github.com/WebAssembly/binaryen/pull/4228
-// It can be tuned more later.
-const Index TooCostlyToRunUnconditionally = 9;
+// This leads to similar choices as LLVM does in some cases, by balancing the
+// extra work of code that is run unconditionally with the speedup from not
+// branching to decide whether to run it or not.
+// See:
+// * https://github.com/WebAssembly/binaryen/pull/4228
+// * https://github.com/WebAssembly/binaryen/issues/5983
+const Index TooCostlyToRunUnconditionally = 8;
static_assert(TooCostlyToRunUnconditionally < CostAnalyzer::Unacceptable,
"We never run code unconditionally if it has unacceptable cost");
-// Check if it is not worth it to run code unconditionally. This
-// assumes we are trying to run two expressions where previously
-// only one of the two might have executed. We assume here that
-// executing both is good for code size.
static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
- Expression* one,
- Expression* two) {
- // If we care mostly about code size, just do it for that reason.
- if (passOptions.shrinkLevel) {
- return false;
+ Index cost) {
+ if (passOptions.shrinkLevel == 0) {
+ // We are focused on speed. Any extra cost is risky, but allow a small
+ // amount.
+ return cost > TooCostlyToRunUnconditionally / 2;
+ } else if (passOptions.shrinkLevel == 1) {
+ // We are optimizing for size in a balanced manner. Allow some extra
+ // overhead here.
+ return cost >= TooCostlyToRunUnconditionally;
+ } else {
+ // We should have already decided what to do if shrink_level=2 and not
+ // gotten here, and other values are invalid.
+ WASM_UNREACHABLE("bad shrink level");
}
- // Consider the cost of executing all the code unconditionally.
- auto total = CostAnalyzer(one).cost + CostAnalyzer(two).cost;
- return total >= TooCostlyToRunUnconditionally;
}
// As above, but a single expression that we are considering moving to a place
// where it executes unconditionally.
static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
Expression* curr) {
- if (passOptions.shrinkLevel) {
+ // If we care entirely about code size, just do it for that reason (early
+ // exit to avoid work).
+ if (passOptions.shrinkLevel >= 2) {
+ return false;
+ }
+ auto cost = CostAnalyzer(curr).cost;
+ return tooCostlyToRunUnconditionally(passOptions, cost);
+}
+
+// Check if it is not worth it to run code unconditionally. This
+// assumes we are trying to run two expressions where previously
+// only one of the two might have executed. We assume here that
+// executing both is good for code size.
+static bool tooCostlyToRunUnconditionally(const PassOptions& passOptions,
+ Expression* one,
+ Expression* two) {
+ // If we care entirely about code size, just do it for that reason (early
+ // exit to avoid work).
+ if (passOptions.shrinkLevel >= 2) {
return false;
}
- return CostAnalyzer(curr).cost >= TooCostlyToRunUnconditionally;
+
+ // Consider the cost of executing all the code unconditionally, which adds
+ // either the cost of running one or two, so the maximum is the worst case.
+ auto max = std::max(CostAnalyzer(one).cost, CostAnalyzer(two).cost);
+ return tooCostlyToRunUnconditionally(passOptions, max);
}
struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {