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: Add newtype wrappers for x64 register classes #3752

Merged

Conversation

fitzgen
Copy link
Member

@fitzgen fitzgen commented Feb 1, 2022

This primary motivation of this large commit (apologies for its size!) is to
introduce Gpr and Xmm newtypes over Reg. This should help catch
difficult-to-diagnose register class mixup bugs in x64 lowerings.

But having a newtype for Gpr and Xmm themselves isn't enough to catch all of
our operand-with-wrong-register-class bugs, because about 50% of operands on x64
aren't just a register, but a register or memory address or even an
immediate! So we have {Gpr,Xmm}Mem[Imm] newtypes as well.

Unfortunately, GprMem et al can't be enums and are therefore a little bit
noisier to work with from ISLE. They need to maintain the invariant that their
registers really are of the claimed register class, so they need to encapsulate
the inner data. If they exposed the underlying enum variants, then anyone
could just change register classes or construct a GprMem that holds an XMM
register, defeating the whole point of these newtypes. So when working with
these newtypes from ISLE, we rely on external constructors like (gpr_to_gpr_mem my_gpr) instead of (GprMem.Gpr my_gpr).

A bit of extra lines of code are included to add support for register mapping
for all of these newtypes as well. Ultimately this is all a bit wordier than I'd
hoped it would be when I first started authoring this commit, but I think it is
all worth it nonetheless!

In the process of adding these newtypes, I didn't want to have to update both
the ISLE extern type definition of MInst and the Rust definition, so I move
the definition fully into ISLE, similar as aarch64.

Finally, this process isn't complete. I've introduced the newtypes here, and
I've made most XMM-using instructions switch from Reg to Xmm, as well as
register class-converting instructions, but I haven't moved all of the GPR-using
instructions over to the newtypes yet. I figured this commit was big enough as
it was, and I can continue the adoption of these newtypes in follow up commits.

Part of #3685.

@fitzgen fitzgen requested a review from cfallin February 1, 2022 19:25
@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator cranelift:area:machinst Issues related to instruction selection and the new MachInst backend. 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 Feb 1, 2022
@github-actions
Copy link

github-actions bot commented Feb 1, 2022

Subscribe to Label Action

cc @cfallin, @fitzgen

This issue or pull request has been labeled: "cranelift", "cranelift:area:aarch64", "cranelift:area:machinst", "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.

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.

Thanks for doing all of this -- it's really quite tedious!

I admit to harboring a little doubt as I look at the number of conversions (to_writable_reg, from_writable_reg, etc) and type-tetris this code adds, though this has to be traded off against the correctness benefits. The Writable<T> technique has likely saved us a few times (judged by the several regalloc metadata sort of bugs we've had) and this will probably have similar yields.

I guess a good answer to that is that implicit conversions (#3753) should make almost all of these go away; we should probably prioritize that work (I can take a look at it soon-ish probably, once I'm back from Wasmtime-land).

;; Construct a new `XmmMem` from the given `RegMem`.
;;
;; Asserts that the `RegMem`'s register, if any, is an XMM register.
(decl xmm_mem_new (RegMem) XmmMem)
Copy link
Member

Choose a reason for hiding this comment

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

Would these constructors be clearer without the _new suffix, I wonder? I'm mostly thinking in terms of symmetry with e.g. instruction constructors and the other utility types -- we have (value_regs ...), not (value_regs_new ...). (Or maybe there's a name conflict from elsewhere I'm missing?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I can do reg_mem_to_xmm_mem which is more similar to the other constructors. Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

That seems reasonable to me! I guess as a general principle the x_to_y explicitness is good and is a sort of direct indication that we can register all such constructors as implicit conversions later.

@fitzgen
Copy link
Member Author

fitzgen commented Feb 3, 2022

I guess a good answer to that is that implicit conversions (#3753) should make almost all of these go away; we should probably prioritize that work (I can take a look at it soon-ish probably, once I'm back from Wasmtime-land).

Yes, I think this the type conversions mechanism will make all of this much better.

@fitzgen fitzgen force-pushed the newtypes-for-register-classes branch 2 times, most recently from 94e2beb to 61cfd3c Compare February 3, 2022 20:33
I need this to move the x64 `Inst` definition into ISLE without losing its
custom `Debug` implementation that prints the assembly for the `Inst`.
This primary motivation of this large commit (apologies for its size!) is to
introduce `Gpr` and `Xmm` newtypes over `Reg`. This should help catch
difficult-to-diagnose register class mixup bugs in x64 lowerings.

But having a newtype for `Gpr` and `Xmm` themselves isn't enough to catch all of
our operand-with-wrong-register-class bugs, because about 50% of operands on x64
aren't just a register, but a register or memory address or even an
immediate! So we have `{Gpr,Xmm}Mem[Imm]` newtypes as well.

Unfortunately, `GprMem` et al can't be `enum`s and are therefore a little bit
noisier to work with from ISLE. They need to maintain the invariant that their
registers really are of the claimed register class, so they need to encapsulate
the inner data. If they exposed the underlying `enum` variants, then anyone
could just change register classes or construct a `GprMem` that holds an XMM
register, defeating the whole point of these newtypes. So when working with
these newtypes from ISLE, we rely on external constructors like `(gpr_to_gpr_mem
my_gpr)` instead of `(GprMem.Gpr my_gpr)`.

A bit of extra lines of code are included to add support for register mapping
for all of these newtypes as well. Ultimately this is all a bit wordier than I'd
hoped it would be when I first started authoring this commit, but I think it is
all worth it nonetheless!

In the process of adding these newtypes, I didn't want to have to update both
the ISLE `extern` type definition of `MInst` and the Rust definition, so I move
the definition fully into ISLE, similar as aarch64.

Finally, this process isn't complete. I've introduced the newtypes here, and
I've made most XMM-using instructions switch from `Reg` to `Xmm`, as well as
register class-converting instructions, but I haven't moved all of the GPR-using
instructions over to the newtypes yet. I figured this commit was big enough as
it was, and I can continue the adoption of these newtypes in follow up commits.

Part of bytecodealliance#3685.
@fitzgen fitzgen force-pushed the newtypes-for-register-classes branch from 61cfd3c to 2c77cf8 Compare February 3, 2022 22:08
@fitzgen fitzgen merged commit a519e5a into bytecodealliance:main Feb 3, 2022
@fitzgen fitzgen deleted the newtypes-for-register-classes branch February 3, 2022 22:57
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:machinst Issues related to instruction selection and the new MachInst 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