Conversation
When we catches "Output must be deterministic" we can't see any details. This PR fix
this and now we can see diff of b1.wasm and b2.wasm files.
Example output:
Output must be deterministic.
Diff:
--- expected
+++ actual
@@ -2072,9 +2072,7 @@
)
(drop
(block $label$16 (result funcref)
- (local.set $10
- (ref.null func)
- )
+ (nop)
(drop
(call $22
(f64.const 0.296)
tlively
left a comment
There was a problem hiding this comment.
I haven't read the tests yet, but here are my comments so far.
| // (like limitations on which functions can be inlined into in each iteration, | ||
| // the number of iterations, etc.). Therefore this function will only find out | ||
| // if we *can* split, but not actually do any splitting. | ||
| bool canSplit(Function* func, const FunctionInfo& info) { |
There was a problem hiding this comment.
It looks like info is not used in this function.
| // If the body is a block, and we have breaks to that block, then we cannot | ||
| // outline any code - we can't outline a break without the break's target. |
There was a problem hiding this comment.
Do we separately need to check for returns for the same reason?
There was a problem hiding this comment.
Not necessarily - one of the patterns below allows returns. The other will check for them.
| // | ||
| // TODO: support a return value | ||
| if (!iff->ifFalse && func->getResults() == Type::none && | ||
| iff->ifTrue->is<Return>() && body->is<Block>()) { |
There was a problem hiding this comment.
Why do we need to check body->is<Block>() here?
There was a problem hiding this comment.
Good point, we don't need to. In fact lower down we assert on that. I'll move the assert up here and remove the if.
| split.inlineable = copyFunction(func, "inlineable-A"); | ||
| auto* outlined = copyFunction(func, "outlined-A"); |
There was a problem hiding this comment.
Why the -A in the names?
Also, it seems wasteful to create a full copy of the function for inlineable, which will end up being very small. Could we avoid copying entirely and have the two new functions refer to the original IR nodes directly?
There was a problem hiding this comment.
-A is for "pattern A" as opposed to pattern B that appears below.
Yeah, there is a TODO in the copy function itself for avoiding the extra copying work. It's more work though, and potentially error-prone, so I'm not sure it's worth it. The overhead is wasteful but not that bad.
| // Checks if an expression is very simple - something simple enough that we | ||
| // are willing to inline it in this optimization. This should basically take | ||
| // almost no cost at all to compute. | ||
| bool isSimple(Expression* curr) { |
There was a problem hiding this comment.
Should the comparison instructions be simple as well?
There was a problem hiding this comment.
Do you mean the if conditions? This is called on them.
Or what do you mean here?
There was a problem hiding this comment.
I mean things like i32.lt_u, i32.ge_s, etc.
There was a problem hiding this comment.
Oh, yes, we may want those as well. For now I just added a tiny set of things, but it already handles the main things that j2cl needs. The rest is a TODO (on line 765).
Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com>
Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com>
| ;; CHECK-NEXT: (local $24 i32) | ||
| ;; CHECK-NEXT: (local $25 f64) |
There was a problem hiding this comment.
It would be good to replace this dump of real-world code with something more focused at some point. The diff here is not too useful for determining whether the code is working correctly.
There was a problem hiding this comment.
Yeah, sorry about that - for a change like this, inlining more things, the diff on this existing file is quite large.
(Ideally we could somehow make this particular file ignore this change, but otherwise I guess ignoring it in review is second best.)
| @@ -31060,3 +31021,87 @@ | |||
| ) | |||
| ) | |||
| ) | |||
| ;; CHECK: (func $byn-split-outlined-B$_fmt_u (param $0 i32) (param $1 i32) (param $2 i32) | |||
There was a problem hiding this comment.
Neat to see this work on real-world code, though!
| ;; CHECK-NEXT: ) | ||
| ;; CHECK-NEXT: ) | ||
| (func $call-reachable-if-body | ||
| ;; Note that the above contains |
There was a problem hiding this comment.
Would it be worth putting a loop in to make the test output less surprising?
There was a problem hiding this comment.
Hmm, I think it's nice to show this actually. It is a useful result - if we regress this, we want to know.
| (if | ||
| (i32.const 1) |
There was a problem hiding this comment.
It's not important that there's an if here, right?
There was a problem hiding this comment.
Yes, we don't actually even scan this inner if - we just look for returns inside it.
Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com>
(This is the last "big" optimization on my plate atm for wasm GC.)
This PR helps with functions like this:
If "lots of work" is large enough, then we won't inline such a
function. However, we may end up calling into the function
only to get a false on that if and immediately exit. So it is useful
to partially inline this function, basically by creating a split
of it into a condition part that is inlineable
and an outlined part that is not inlineable:
We can then inline the inlineable part. That means that a call
like
turns into
In other words, we end up replacing a call and then a check with
a check and then a call. Any time that the condition is false, this
will be a speedup.
The cost here is increased size, as we duplicate the condition
into the callsites. For that reason, only do this when heavily
optimizing for size.
This is a 10% speedup on j2cl. This helps two types of functions
there: Java class inits, which often look like "have I been
initialized before? if not, do all this work", and also assertion
methods which look like "if the input is null, throw an
exception".