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