[RFC] RISC-V: elide sign extend when expanding cmp_and_jump
Vineet Gupta
vineetg@rivosinc.com
Wed Oct 25 23:28:43 GMT 2023
On 10/24/23 22:01, Vineet Gupta wrote:
> RV64 comapre and branch instructions only support 64-bit operands.
> The backend unconditionally generates zero/sign extend at Expand time
> for compare and branch operands even if they are already as such
> e.g. function args which ABI guarantees to be sign-extended (at callsite).
>
> And subsequently REE fails to eliminate them as
> "missing defintion(s)"
> specially for function args since they show up as missing explicit
> definition.
>
> So elide the sign extensions at Expand time for a subreg promoted var
> with inner word sized value whcih doesn't need explicit sign extending
> (fairly good represntative of an incoming function arg).
>
> There are patches floating to enhance REE and/or new passes to elimiate
> extensions, but it is always better to not generate them if possible,
> given Expand is so early, the elimiated extend would help improve outcomes
> of later passes such as combine if they have fewer operations/combinations
> to deal with.
>
> The test used was existing gcc.c-torture/execute/20020506-1.c -O2 zbb
> It elimiates the SEXT.W and an additional branch
>
> before after
> ------- ------
> test2: test2:
> sext.b a0,a0
> blt a0,zero,.L15
> bne a1,zero,.L17 bne a1,zero,.L17
>
> This is marked RFC as I only ran a spot check with a directed test and
> want to use Patrick's pre-commit CI to do the A/B testing for me.
>
> gcc/ChangeLog:
> * config/riscv/riscv.cc (riscv_extend_comparands): Don't
> sign-extend operand if subreg promoted with inner word size.
>
> Signed-off-by: Vineet Gupta <vineetg@rivosinc.com>
> ---
> gcc/config/riscv/riscv.cc | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index f2dcb0db6fbd..a8d12717e43d 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -3707,7 +3707,16 @@ riscv_extend_comparands (rtx_code code, rtx *op0, rtx *op1)
> }
> else
> {
> - *op0 = gen_rtx_SIGN_EXTEND (word_mode, *op0);
> + /* A subreg promoted SI of DI could be peeled to expose DI, eliding
> + an unnecessary sign extension. */
> + if (GET_CODE (*op0) == SUBREG
> + && SUBREG_PROMOTED_VAR_P (*op0)
> + && GET_MODE_SIZE (GET_MODE (XEXP (*op0, 0))).to_constant ()
> + == GET_MODE_SIZE (word_mode))
> + *op0 = XEXP (*op0, 0);
> + else
> + *op0 = gen_rtx_SIGN_EXTEND (word_mode, *op0);
> +
> if (*op1 != const0_rtx)
> *op1 = gen_rtx_SIGN_EXTEND (word_mode, *op1);
> }
Just a quick update that testing revealed additional failures and
unpacking which took me a while and in hindsight embarrassing. I was
misunderstanding what ABI guarantees and what ISA actually does :-)
The ABI guarantees sign extension this for 32-bit things in 64-bit reg
(so in rv64, int), but *not* 8-bit things in a reg. i.e. not for char
arguments.
e.g.
uint8_t abs8(uint8_t x)
{
if (x & 0x80) // SEXT.b a4, a0
...
}
main()
{
if (abs8(128) != 127) // LI a0, 128 => ADDI a0, x0, 128
__builtin_abort();
}
So my patch was optimizing away the SEXT.B (despite claiming that subreg
prom of SI....) which is wrong.
Sure ADDI in main () sign-extends, but it does that for 12-bit imm
0x080, which comes out to 0x80, but sign-extending for char scope 0x80
would yield 0xFFFF....0x80. Hence the issue.
I'll spin a v2 after more testing.
This is slightly disappointing as it reduces the scope of optimization,
but correctness in this trade is non-negotiable :-)
-Vineet
More information about the Gcc-patches
mailing list