ConstraintAnalysis: Optimize local.get - #9136
Conversation
| auto oldType = (*currp)->type; | ||
| if (!Type::isSubType(rep->type, oldType)) { | ||
| // The value we know must exist here is impossible, which means it was | ||
| // cast in a way that traps at runtime. This code is unreachable. | ||
| rep = Builder(*getModule()).makeUnreachable(); | ||
| refinalize = true; | ||
| } else if (rep->type != oldType) { | ||
| // We are refining. | ||
| refinalize = true; | ||
| } |
There was a problem hiding this comment.
Should we move this logic into optimizeLocalGet so this loop can be responsible for nothing but performing the replacements? That will keep all the optimization logic together in one place.
There was a problem hiding this comment.
Good idea, done. This does mean passing around refinalize but it does seem nicer overall.
There was a problem hiding this comment.
Does ctor-eval run optimizations by default? Is that why there is a change here?
There was a problem hiding this comment.
Yes, after we eval code in a function, we run default opts immediately as a followup. (To save the user needing to do the obvious wasm-opt call)
| ;; CHECK-NEXT: (local.get $0) | ||
| ;; CHECK-NEXT: (local.get $0) | ||
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: (i32.const 84) |
There was a problem hiding this comment.
Are we optimizing tuple-typed locals? If so, is that intentional?
There was a problem hiding this comment.
We don't optimize them directly (no parsing support for tuples), but if TupleOptimization broke such a local into normal ones, we can handle those.
| ;; The condition here ends up comparing $x to itself. That is normally 1, | ||
| ;; but not with a nan. We do not optimize floats for this reason (without | ||
| ;; --fast-math, see constraint-analysis-float.wast). |
There was a problem hiding this comment.
I guess we could still optimize in cases where we know the relevant values cannot be NaNs. Like if we had an f64.const 1 below, we would know that the LHS and RHS of the f64.eq cannot be NaN, so we could still optimize according to the normal math rules.
There was a problem hiding this comment.
Yes, there is definitely more we can do for floats here. I have some TODOs that I hope to get to.
| ;; A non-null value, like an internalized string, is not optimized (we could | ||
| ;; emit an any.convert_extern of a strong.const, but it increases size, so | ||
| ;; we leave this for passes like Precompute and GUFA). | ||
| ;; TODO: should we optimize this? |
There was a problem hiding this comment.
Probably; all the strings constants should be deduplicated during string lowering anyway.
There was a problem hiding this comment.
Hmm, good point. Anyhow, let's consider this later?
| Expression* optimizeLocalGet(Expression** currp, | ||
| const BasicBlockConstraintMap& constraints) { | ||
| const BasicBlockConstraintMap& constraints, | ||
| bool& refinalize) { |
There was a problem hiding this comment.
This is a function-parallel pass, so we should be able to just track refinalize as a member of the pass class rather than passing it around.
|
Will only land this after landing some speedups first, to avoid a big slowdown in the middle. |
…nt-locals-detection scheme - all we do is operate on all locals, except ones of the wrong types - we don't need to carefully check if we detected the right locals as relevant.
|
Speedups landed. With them + this PR, things are faster than before! |
E.g.
This removes the "markRelevant" logic that tried to only track locals
that have interesting operations on them that we can optimize,
because now anything with a
local.getmight get optimized - whichis pretty much anything.
This does make the pass significantly slower, unfortunately, around
30% or so, and this was one of our slower passes. I'm looking into
speedups to land after this to mitigate that, but this does look useful
enough: this increases the amount of things we optimize by a
substantial amount. On one large Dart testcase I saw a total binary
size reduction of 0.3%. Overall this seems like the right tradeoff
for a pass that only runs in
-Os/-O3+.Some existing tests needed adjustment, as constants are now
propagated in cases that can be confusing.