Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cranelift-isle: Add "partial" flag for constructors #5392

Merged
merged 9 commits into from
Dec 8, 2022

Conversation

jameysharp
Copy link
Contributor

I speculate that this PR may have a performance impact, which I want to measure before merging, but I'd appreciate review on the implementation. Also I wanted to get the CI run going overnight.

Instead of tying fallibility of constructors to whether they're either internal or pure, this commit assumes all constructors are infallible unless tagged otherwise with a "partial" flag.

Internal constructors without the "partial" flag are not allowed to use constructors which have the "partial" flag on the right-hand side of any rules, because they have no way to report last-minute match failures.

Multi-constructors should never be "partial"; they report match failures with an empty iterator instead. In turn this means you can't use partial constructors on the right-hand side of internal multi-constructor rules. However, you can use the same constructors on the left-hand side with if or if-let instead.

In many cases, ISLE can already trivially prove that an internal constructor always returns Some. With this commit, those cases are laregly unchanged, except for removing all the Options and Somes from the generated code for those terms.

However, for internal non-partial constructors where ISLE could not prove that, it now emits an unreachable! panic as the last-resort, instead of returning None like it used to do. Among the existing backends, here's how many constructors have these panic cases:

  • x64: 14% (53/374)
  • aarch64: 15% (41/277)
  • riscv64: 23% (26/114)
  • s390x: 47% (268/567)

It's often possible to rewrite rules so that ISLE can tell the panic can never be hit. Just ensure that there's a lowest-priority rule which has no constraints on the left-hand side.

But in many of these constructors, it's difficult to statically prove the unhandled cases are unreachable because that's only down to knowledge about how they're called or other preconditions.

So this commit does not try to enforce that all terms have a last-resort fallback rule.

Instead of tying fallibility of constructors to whether they're either
internal or pure, this commit assumes all constructors are infallible
unless tagged otherwise with a "partial" flag.

Internal constructors without the "partial" flag are not allowed to use
constructors which have the "partial" flag on the right-hand side of any
rules, because they have no way to report last-minute match failures.

Multi-constructors should never be "partial"; they report match failures
with an empty iterator instead. In turn this means you can't use partial
constructors on the right-hand side of internal multi-constructor rules.
However, you can use the same constructors on the left-hand side with
`if` or `if-let` instead.

In many cases, ISLE can already trivially prove that an internal
constructor always returns `Some`. With this commit, those cases are
laregly unchanged, except for removing all the `Option`s and `Some`s
from the generated code for those terms.

However, for internal non-partial constructors where ISLE could not
prove that, it now emits an `unreachable!` panic as the last-resort,
instead of returning `None` like it used to do. Among the existing
backends, here's how many constructors have these panic cases:

- x64: 14% (53/374)
- aarch64: 15% (41/277)
- riscv64: 23% (26/114)
- s390x: 47% (268/567)

It's often possible to rewrite rules so that ISLE can tell the panic can
never be hit. Just ensure that there's a lowest-priority rule which has
no constraints on the left-hand side.

But in many of these constructors, it's difficult to statically prove
the unhandled cases are unreachable because that's only down to
knowledge about how they're called or other preconditions.

So this commit does not try to enforce that all terms have a last-resort
fallback rule.
@jameysharp jameysharp requested a review from cfallin December 7, 2022 06:53
@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator cranelift:area:aarch64 Issues related to AArch64 backend. cranelift:area:x64 Issues related to x64 codegen isle Related to the ISLE domain-specific language labels Dec 7, 2022
@github-actions
Copy link

github-actions bot commented Dec 7, 2022

Subscribe to Label Action

cc @cfallin, @fitzgen

This issue or pull request has been labeled: "cranelift", "cranelift:area:aarch64", "cranelift:area:x64", "isle"

Thus the following users have been cc'd because of the following labels:

  • cfallin: isle
  • fitzgen: isle

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Instead of doing it in a separate pass afterward.

This involved threading all the term flags (pure, multi, partial)
through the recursive `translate_expr` calls, so I extracted the flags
to a new struct so they can all be passed together.
Now that I've threaded the flags through `translate_expr`, it's easy to
check this case too, so let's just do it.
There are only three legal states for the combination of `multi` and
`infallible`, so replace those fields of `ExternalSig` with a
three-state enum.
If we'd had any external multi-constructors this would correct their
signatures as well.
I believe the only reason these weren't marked `pure` before was because
that would have implied that they're also partial. Now that those two
states are specified separately we apply this flag more places.
@jameysharp jameysharp marked this pull request as ready for review December 7, 2022 23:06
Copy link
Member

@cfallin cfallin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks! Just pair-reviewed this with Jamey; nothing too surprising going on, and it's a nice generalization of the sorts of constructors we support today.

@jameysharp
Copy link
Contributor Author

On a suggestion from Chris, I ran wasmtime compile on the Spidermonkey benchmark from Sightglass, both with and without this PR, and compared the compiled .cwasm files. They were byte-for-byte identical. In conjunction with the fact that none of the precise-output filetests failed on any backend, I have pretty good confidence that this didn't change the results of instruction selection.

I had thought this PR might marginally improve performance in the instruction selection phase of compiling, due to fewer checks for whether constructors returned Option::Some.

When measuring time spent in wasmtime compile on Spidermonkey with DHAT, this PR reduces instructions retired by 0.06%, at the cost of 0.0007% more bytes read and 0.0001% more bytes written. Somehow this PR increased total heap allocations by 8 bytes.

Sightglass/perf agrees with DHAT that instructions retired during compilation are improved by a statistically significant amount but with such a small effect size that it reports this PR is "1.00x faster" on the bz2, pulldown-cmark, and spidermonkey benchmarks.

Sightglass' cpu-cycles measure and Hyperfine's wall-clock time both report that this PR is slightly slower when compiling Spidermonkey: the baseline version is "1.00x to 1.01x faster" according to Sightglass and "1.00 ± 0.02 times faster" according to Hyperfine. On the smaller benchmarks (bz2 and pulldown-cmark), Sightglass found no significant difference in cpu-cycles.

In short, this PR has almost no effect on performance by any measure.

@jameysharp jameysharp merged commit 8726eee into bytecodealliance:main Dec 8, 2022
@jameysharp jameysharp deleted the isle-partial-flag branch December 8, 2022 01:16
avanhatt added a commit to avanhatt/wasmtime that referenced this pull request Mar 21, 2023
Noticed this was missing, tried to add based on the comments in bytecodealliance#5392 (CC @jameysharp)
cfallin pushed a commit that referenced this pull request Mar 21, 2023
Noticed this was missing, tried to add based on the comments in #5392 (CC @jameysharp)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:area:aarch64 Issues related to AArch64 backend. cranelift:area:x64 Issues related to x64 codegen cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants