[to-be-committed][RISC-V] Generate nearby constant, then adjust to our final desired constant

Next step in constant synthesis work.

For some cases it can be advantageous to generate a constant near our target,
then do a final addi to fully synthesize C.

The idea is that while our target C may require N instructions to synthesize,
C' may only require N-2 (or fewer) instructions.  Thus there's budget to adjust
C' into C ending up with a better sequence than if we tried to generate C
directly.

So as an example:

> unsigned long foo_0xfffff7fe7ffff7ff(void) { return 0xfffff7fe7ffff7ffUL; }

This is currently 5 instructions on the trunk:

>         li      a0,-4096
>         addi    a0,a0,2047
>         bclri   a0,a0,31
>         bclri   a0,a0,32
>         bclri   a0,a0,43

But we can do better by first synthesizing 0xfffff7fe7ffff800 which is just 3
instructions.  Then we can subtract 1 from the result.  That gives us this
sequence:

>         li      a0,-16789504
>         slli    a0,a0,19
>         addi    a0,a0,-2048
>         addi    a0,a0,-1

These cases are relatively easy to find once you know what you're looking for.
I kept the full set found by the testing code yesterday, mostly because some of
them show different patterns for generating C', thus showing generality in the
overall synthesis implementation.  While all these tests have 0x7ff in their
low bits.  That's just an artifact to the test script.  The methodology will
work for a variety of other cases.

gcc/
	* config/riscv/riscv.cc (riscv_build_integer_1): Try generating
	a nearby simpler constant, then using a final addi to set low
	bits properly.

gcc/testsuite

	* gcc.target/riscv/synthesis-7.c: New test.
This commit is contained in:
Jeff Law 2024-05-26 10:54:18 -06:00
parent 87463737b9
commit 95660223c4
2 changed files with 1551 additions and 0 deletions

View file

@ -963,6 +963,26 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS],
}
}
/* We might be able to generate a constant close to our target
then a final ADDI to get the desired constant. */
if (cost > 2
&& (value & 0xfff) != 0
&& (value & 0x1800) == 0x1000)
{
HOST_WIDE_INT adjustment = -(0x800 - (value & 0xfff));
alt_cost = 1 + riscv_build_integer_1 (alt_codes,
value - adjustment, mode);
if (alt_cost < cost)
{
alt_codes[alt_cost - 1].code = PLUS;
alt_codes[alt_cost - 1].value = adjustment;
alt_codes[alt_cost - 1].use_uw = false;
memcpy (codes, alt_codes, sizeof (alt_codes));
cost = alt_cost;
}
}
/* Final cases, particularly focused on bseti. */
if (cost > 2 && TARGET_ZBS)
{

File diff suppressed because it is too large Load diff