-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
riscv64: Introduce Compressed Instructions #6989
Conversation
Subscribe to Label Action
This issue or pull request has been labeled: "cranelift", "cranelift:area:riscv64", "cranelift:meta", "isle"
Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks great to me, and thanks as always for the detail explanations!
Would it be possible to add detection of these features to cranelift/native
?
They should already be detected. The rest of them ( |
The C extension has been split a little bit since its introduction let's support the finer grained instructions. This also disables compressed instruction support by default.
Conditionally enable compressed instruction disassembly.
This commit reorganizes our emit function to first try a special case for compressed instruction, before falling back to uncompressed instructions. Currently the compressed case does nothing.
We can only emit compressed instructions if they have a specific physical register. For example `c.mv` does not support using the `x0` register. Thus, move the allocation function that converts from virtual registers to physical registers into a separate step before trying to emit the instruction. This allows us to know the real register when emitting compressed instructions.
`br_table` computes physical offsets from a certain instruction. Thus we need to force these instructions to be uncompressed in order to not jump into the wrong target.
This reverts commit 212dec4. It looks like the version of QEMU that CI uses does not yet support Zcb.
* riscv64: Add compressed extension instructions The C extension has been split a little bit since its introduction let's support the finer grained instructions. This also disables compressed instruction support by default. * ci: Enable zcb extension on RISC-V QEMU * riscv64: Enable RVC mode in capstone Conditionally enable compressed instruction disassembly. * riscv64: Prepare to emit compressed instructions This commit reorganizes our emit function to first try a special case for compressed instruction, before falling back to uncompressed instructions. Currently the compressed case does nothing. * riscv64: Move emit register allocation to separate function We can only emit compressed instructions if they have a specific physical register. For example `c.mv` does not support using the `x0` register. Thus, move the allocation function that converts from virtual registers to physical registers into a separate step before trying to emit the instruction. This allows us to know the real register when emitting compressed instructions. * riscv64: Emit BrTable as uncompressed `br_table` computes physical offsets from a certain instruction. Thus we need to force these instructions to be uncompressed in order to not jump into the wrong target. * riscv64: Mark DWARF CIE code alignment as 2 bytes * riscv64: Make minimum function alignment 2 bytes * riscv64: Emit `c.add` * riscv64: Add `c.mv` * riscv64: Add c runtests * Revert "ci: Enable zcb extension on RISC-V QEMU" This reverts commit 212dec4. It looks like the version of QEMU that CI uses does not yet support Zcb.
👋 Hey,
This PR makes introduces compressed instructions to the RISC-V backend as part of the C extension.
C extension introduction
The C Extension adds encodings for 16 bit instructions. These are allowed to be freely interleaved with uncompressed instructions (i.e. we don't need a mode switch like Thumb2).
Some C instruction formats cannot encode all registers, so they may only be emitted if they get assigned a certain physical register. Additionally C instructions (almost) always have an equivalent uncompressed instruction.
Implementation
I've implemented this as an encoding only change. So our VCode instructions remain the same, but if we happen to get the correct registers and all the stars line up we emit a compressed instruction instead of a full sized instruction.
Inst::emit
is now split into 3 stages:Inst::allocate
which just transforms aInst
with virtual registers, into aInst
with physical registersThis PR only enables 2 instructions
c.add
andc.mv
. Both of these use the CR format which allows the full range of registers. However they are enough to get us into trouble.c.mv
is emitted quite often, and is enough to "unalign" most of the rest of the code.Issues with capstone
Capstone supports decoding C instructions with a separate "Extra Mode".
Capstone currently cannot decode a number of instructions that we emit (i.e
Zca
,Zcb
,Zcs
or Vector Instructions). This is normally ok since it emits a.byte ...
directive and we can still read the V-Code to figure out what is going on.If I enable this "Extra Mode" by default it tries to decode these unknown instructions as C instructions and makes the whole thing unreadable.
My solution for this was to make C a non default extension, and only enable the Extra Mode when C is enabled. This lets us keep the normal disassembly for all current test cases. Mixing C instructions and Vector instructions still makes the whole thing unreadable, but at least its not the common case.
Runtests
I've made pretty much all runtests run with C as well as without. Even if the runtest will never directly emits a C instruction, it can emit for example a
c.mv
and emit the rest of the instructions "unaligned" which is also a configuration worth testing.This is built on top of #6988 so it's worth waiting for that to be merged before looking into this. Additionally, it's probably a good idea to review this commit by commit instead of all at once.