On 7/11/2026 7:31 AM, Jin Ma wrote:
> The early-clobber scratch in *<any_extract>3 is unnecessary: slli
> reads its source before writing, so the destination register can
> safely hold the intermediate value.  This reduces register pressure
> and makes the split output simpler.
>
> gcc/ChangeLog:
>
>       * config/riscv/riscv.md (*<any_extract:optab><GPR:mode>3):
>       Remove (clobber (match_scratch)) and use operand 0 as the
>       intermediate destination for the shift-left half of the split.
>
> gcc/testsuite/ChangeLog:
>
>       * gcc.target/riscv/extract-zero-no-scratch.c: New test.
>       * gcc.target/riscv/extract-sign-no-scratch.c: New test.
The riscv.md part is fine.  The tests aren't.

> diff --git a/gcc/testsuite/gcc.target/riscv/extract-sign-no-scratch.c 
> b/gcc/testsuite/gcc.target/riscv/extract-sign-no-scratch.c
> new file mode 100644
> index 00000000000..e908737fb5b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/extract-sign-no-scratch.c
> @@ -0,0 +1,18 @@
> +/* Verify *sign_extract splitter uses the same dest for slli and srai.  */
> +/* { dg-do compile { target { ! riscv_abi_e } } } */
> +/* { dg-require-effective-target rv64 } */
> +/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */
> +/* { dg-skip-if "" { *-*-* } { "-Os" "-Oz" "-Og" "-flto" } } */
> +
> +long sign_ext_11_5  (long x) { return ((x << 48) >> 53); }
> +long sign_ext_16_8  (long x) { return ((x << 40) >> 48); }
> +long sign_ext_10_20 (long x) { return ((x << 34) >> 54); }
> +
> +/* { dg-final { scan-assembler-times "slli\t" 3 } } */
> +/* { dg-final { scan-assembler-times "srai\t" 3 } } */
> +/* { dg-final { scan-assembler "slli\ta0,a0,48" } } */
> +/* { dg-final { scan-assembler "srai\ta0,a0,53" } } */
> +/* { dg-final { scan-assembler "slli\ta0,a0,40" } } */
> +/* { dg-final { scan-assembler "srai\ta0,a0,48" } } */
> +/* { dg-final { scan-assembler "slli\ta0,a0,34" } } */
> +/* { dg-final { scan-assembler "srai\ta0,a0,54" } } */
The problem with tests of this style is you're going to be incredibly 
sensitive to register allocation because you're scanning for specific 
registers in the output.

GIven the nature of the patch, testing final downstream effect may be 
tough precisely because you'd have to look at the registers used.  
Scanning the RTL to verify there aren't any clobbers might be a 
possibility -- but you run the possibility that there are other clobbers 
in the IL that make scanning hard.

You could perhaps use the check-function-bodies framework with 
generalized register names.  *If* the current code without your patch 
has an extra move or something like that, then the check-function-bodies 
approach might be helpful to verify we're eliminating those extra moves, 
without completely tying us down to using precise registers.

You could also generalize the registers in this scan.  It's a bit weaker 
than scan-function-bodies, but perhaps good enough here. The downside is 
you won't catch cases where we get an extra move or similar kinds of 
regressions.

Or you could just avoid the test in this case.  I'm a big proponent of 
aggressively adding tests to the testsuite, but in this case I could 
make the argument that the cost/benefit analysis on a test for this 
problem isn't great and that our time is better spent elsewhere.

So again, the riscv.md part looks good.  We just need to figure out what 
the testing strategy ought to be, which perhaps might include the 
possibility of no test in this case.

Jeff

Reply via email to