aarch64: lower ishl + ushr/sshr pairs to a single ubfm/sbfm instruction - #14187
aarch64: lower ishl + ushr/sshr pairs to a single ubfm/sbfm instruction#14187Rafferty97 wants to merge 8 commits into
ishl + ushr/sshr pairs to a single ubfm/sbfm instruction#14187Conversation
eligible `ishl`/`sshr` pairs into one `sbfm` instruction.
methods `sbfm_immr`/`sbfm_imms`; added additional test cases
Subscribe to Label ActionDetailsThis issue or pull request has been labeled: "cranelift", "cranelift:area:aarch64", "isle"Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
cfallin
left a comment
There was a problem hiding this comment.
Thanks! This looks generally good. Just a few comments below.
Also: would you be interested in seeing if you can use the verification framework (cranelift/isle/veri) that is in-tree, but not yet in enforcing mode, to verify these new lowerings? (I will soon turn it on but this would be a good test-case for usability in the meantime.) It might just work if the instruction specs for ubfm/sbfm are already generated; I'm not sure. Let us know if any issues with this!
| let w = ty.lane_bits() as u8; | ||
| let a = (a as u8) & (w - 1); | ||
| let b = (b as u8) & (w - 1); | ||
| UImm6::maybe_from_u8(if a <= b { b - a } else { w - (a - b) }).unwrap() |
There was a problem hiding this comment.
Comment here that the unwrap should always succeed because w is at most 64? Probably also debug_assert!(w <= 64) above.
There was a problem hiding this comment.
Sure, good suggestions. I usually prefer expect over unwrap with a comment as it surfaces the reasoning in panic messages too. Will update.
| (to_bits u8)) | ||
|
|
||
| ;; A bitfield move instruction, which encompasses | ||
| ;; the BFM, UBFM and SBFM instructions. |
There was a problem hiding this comment.
Add "Overwrites whole rd (the bits outside the specified bitfield are zeroed)." here for clarity, per above.
There was a problem hiding this comment.
As mentioned above, the situation's a bit more nuanced. How does this read?
;; A bitfield move instruction, which encompasses
;; the BFM, UBFM and SBFM instructions.
;;
;; The net effect of these instructions is to move a
;; contiguous subset of bits in `rn` into `rd`, possibly
;; at an offset, then:
;; * For BFM: the other bits in `rd` are preserved
;; * For UBFM/SBFM: the other bits are cleared/sign-extended
76d7197 to
572335f
Compare
572335f to
882b994
Compare
@cfallin Ah, I forgot to reply to this one. Sure, I'd be interested in adding some tests in the new verification framework. Is it alright if this comes via a seperate PR? |
Yes, that's fine -- it was an opportunistic request, we don't have it on in fully gating mode yet, so it's not yet an expectation :-) |
|
@cfallin Thanks again for reviewing this so quickly. It looks like the verifier check has failed, due to these errors: These are the two helper functions that calculate |
|
Ah, yes, we don't have full verification on but we do check that specs are present. All helpers that bottom out in Rust (and that are reachable) need specs -- hopefully you'll be able to follow the examples on the existing helpers, but feel free to ping if not and we can help. |
UBFM; add spec clauses to both helpers
Thanks. I've added the I'm curious why this PR passed CI before approval, but failed in the merge queue? |
|
The I checked locally that this should pass the current CI. Sorry for the churn as we work through the kinks of the new verifier integration/instructions! |
|
Also re: the merge queue, it runs a superset of tests; you can run all for a commit by including |
|
@avanhatt Thanks for the helpful answers - I'll update my PR now as per your suggestion |
|
I was also wondering - would there be interest in a follow up PR that removes |
|
Hi @cfallin, @avanhatt - I've hit another wall. I'm now seeing this output from the "ISLE verifier basic check": I've looked at |
I've attempted to do this - with a lot of help from Claude - and the solution it came up with seems to make the CI test pass now. However, I'm not confident that it's the best solution, or even needed at all right now, and the fact that it generates a 50k ISLE file seems a bit off. The code is in this commit, if you wouldn't mind having a quick glance to see if it's going in the right direction: Rafferty97@dc043ad |
|
@Rafferty97 sorry, I should have caught this! For this to not block this PR, you can just mark this as a TODO via: I'm happy to help with adding a real spec for |
|
I can also take over doing that PR in its entirely if you're not interested in it, since this may be more than you bargained for! Thanks again for your patience with this new process. |
I'd appreciate that, actually :) I'm not sure if the LLM-assisted code in the commit I mentioned is helpful at all, but the reason it generates so much ISLE is that it has to enumerate all 64x64 combination of I've just pushed a commit with the added |
|
One other minor thing: While working through that latest CI issue, I tried running the CI command locally, i.e.: But in order to get it working, I had to make a small fix to I'm not sure if this is just an issue with my setup, though, and I'd guess it is. |
Motivation
AArch64 can express a left-shift followed by a right-shift as a single bitfield-move instruction, either
ubfmorsbfm, which are commonly aliased tosbfx/sbfiz/ubfx/ubfiz. The aarch64 backend currently emits two instructions, since no rule inspects a sshr/ushr's operand for a producing ishl. The appropriate encoder already exists inemit.rsas the functionenc_bfm, but only servesMInst::Extend, which only covers fixed-width sign extension.There has been previous discussion around adding support for this kind of lowering here: #1067
Changes
I've added
MInst::BitfieldMoveto express the bitfield move family of AArch64 instructions (bfm, ubfm, sbfm) more generally than the pre-existingMInst::Extend. I then added lowering rules to recognise a sequence ofishl+ushrorishl+sshroperations that could be lowered toubfmorsbfmrespectively. This necessitated two helper functions (sbfm_immrandsbfm_imms) to calculate the appropriate values for theimmrandimmsimmediates.I have taken care to support both 32-bit and 64-bit instructions, and to mask off the shift amounts as required by CLIF's semantics. I've added tests to
shift-rotate.clifthat cover all these cases.I've also lightly modified the
enc_bfmfunction signature to take aBfmOprather than raw bits, for better separation of concerns.Future work
Now that
MInstcan represent the full suite of bitfield-move instructions precisely, there's an argument for removing theExtendvariant and instead lowering zero- and sign-extension operations toBitfieldMovedirectly. To bound the scope of this PR, though, I've left it in place.