Choosing registers for assembly snippets

Ludovic Henry ludovic at rivosinc.com
Wed Oct 5 09:09:43 UTC 2022


Hi,

My understanding is it's quite a mixed-bag. There are some places where it
is assumed which register is used (ex: StubGenerator::generate_zero_blocks
assumes x28 and x29 are used in MacroAssembler::zero_words) while other
places pass the registers to be used. It's surprising that the TLAB
allocation passes the registers to be used (tmp1 and tmp2) but there are
cases where tmp1 is noreg (like templateTable_riscv.cpp [1]).

In that specific case of TLAB allocation, it seems to me the right approach
is to make sure `tmp1` is always valid (AFAIU, the only required change is
to pass `t0` in [1]), and use `tmp1` in place of `t0`
in BarrierSetAssembler::tlab_allocate. It would also require asserting that
both tmp1 and tmp2 are not noreg.

Finally, on always using t0 and t1 as temporary registers, it's the case
most of the time, but there are cases where you can't
(StubGenerator::generate_zero_blocks and MacroAssembler::zero_words for
example).

So IMHO the best practice is to pass the registers you can use. The
exception is when you can't (like the StubGenerator which generates the
code at startup); then it's a tradeoff between passing the parameters as
normal arguments (c_rarg0, c_rarg1, etc.) or make an assumption or where
the value is currently stored (x28. x29 in MacroAssembler::zero_words case
for example).

Cheers,
Ludovic

[1]
https://github.com/openjdk/jdk/blob/953ce8da2c7ddd60b09a18c7875616a2477e5ba5/src/hotspot/cpu/riscv/templateTable_riscv.cpp#L3406

On Tue, Oct 4, 2022 at 1:01 PM Zixian Cai <zixian.cai at anu.edu.au> wrote:

> Hi all,
>
>
>
> I’m just wondering what the best practices are in terms of choosing
> registers.
>
>
>
> I was looking at the assembly code for tlab allocation (
> https://github.com/openjdk/jdk/blob/5a9cd33632862aa2249794902d4168a7fe143054/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp#L131)
> and noticed the following.
>
>    1. tmp1 register is invalid.
>    2. tmp2 register is valid but sometimes clashes with
>    var_size_in_bytes, which requires the workaround here
>    https://github.com/openjdk/jdk/blob/5a9cd33632862aa2249794902d4168a7fe143054/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp#L155
>    3. t0 is used as a temporary register despite not passed into the
>    method as a temporary register
>    https://github.com/openjdk/jdk/blob/5a9cd33632862aa2249794902d4168a7fe143054/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp#L149
>
>
>
> I’d really appreciate if someone could shed insight on how these decisions
> are made so that I can avoid common pitfalls when writing assembly code.
> The only resource I found at the moment is the architecture description file
>
> https://github.com/openjdk/jdk/blob/5a9cd33632862aa2249794902d4168a7fe143054/src/hotspot/cpu/riscv/riscv.ad#L73
>  which suggests x5(t0)-x6(t1) can always be used as temporary registers.
>
>
>
> Sincerely,
>
> Zixian
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/riscv-port-dev/attachments/20221005/2435bb61/attachment.htm>


More information about the riscv-port-dev mailing list