On 6/30/23 16:50, Andrew Waterman wrote:
I don't believe this is correct; the subtraction is needed to account
for the fact that the low part might be negative, resulting in a
borrow from the high part. See the output for your test case below:
$ cat test.c
#include <stdio.h>
int main()
{
unsigned long result, tmp;
asm (
"li %1,-252645376\n"
"addi %1,%1,240\n"
"slli %0,%1,32\n"
"add %0,%0,%1"
: "=r" (result), "=r" (tmp));
printf("%lx\n", result);
return 0;
}
$ riscv64-unknown-elf-gcc -O2 test.c
$ spike pk a.out
bbl loader
f0f0f0eff0f0f0f0
$
Thx for the quick feedback Andew. I'm clearly lacking in signed math :-(
So is it possible to have a better code seq for the testcase at all ?
-Vineet
On Fri, Jun 30, 2023 at 4:42 PM Vineet Gupta <vine...@rivosinc.com> wrote:
On 6/30/23 16:33, Vineet Gupta wrote:
Ran into a minor snafu in const splitting code when playing with test
case from an old PR/23813.
long long f(void) { return 0xF0F0F0F0F0F0F0F0ull; }
This currently generates
li a5,-252645376
addi a5,a5,241
li a0,-252645376
slli a5,a5,32
addi a0,a0,240
add a0,a5,a0
ret
The signed math in hival extraction introduces an additional bit,
causing loval == hival check to fail.
| riscv_split_integer (val=-1085102592571150096, mode=E_DImode) at
../gcc/config/riscv/riscv.cc:702
| 702 unsigned HOST_WIDE_INT loval = sext_hwi (val, 32);
| (gdb)n
| 703 unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32);
| (gdb)
FWIW (and I missed adding this observation to the changelog) I pondered
about using unsigned loval/hival with zext_hwi() but that in certain
cases can cause additional insns
e.g. constant 0x8000_0000 is codegen to LI 1 +SLLI 31 vs, LI
0xFFFFFFFF_80000000
| 704 rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode);
| (gdb) p/x val
| $2 = 0xf0f0f0f0f0f0f0f0
| (gdb) p/x loval
| $3 = 0xfffffffff0f0f0f0
| (gdb) p/x hival
| $4 = 0xfffffffff0f0f0f1
^^^
Fix that by eliding the subtraction in shift.
With patch:
li a5,-252645376
addi a5,a5,240
slli a0,a5,32
add a0,a0,a5
ret
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_split_integer): hival computation
do elide subtraction of loval.
* (riscv_split_integer_cost): Ditto.
* (riscv_build_integer): Ditto
Signed-off-by: Vineet Gupta <vine...@rivosinc.com>
---
I wasn't planning to do any more work on large const stuff, but just ran into
it this
on a random BZ entry when trying search for redundant constant stuff.
The test seemed too good to pass :-)
---
gcc/config/riscv/riscv.cc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 5ac187c1b1b4..377d3aac794b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -643,7 +643,7 @@ riscv_build_integer (struct riscv_integer_op *codes,
HOST_WIDE_INT value,
&& (value > INT32_MAX || value < INT32_MIN))
{
unsigned HOST_WIDE_INT loval = sext_hwi (value, 32);
- unsigned HOST_WIDE_INT hival = sext_hwi ((value - loval) >> 32, 32);
+ unsigned HOST_WIDE_INT hival = sext_hwi (value >> 32, 32);
struct riscv_integer_op alt_codes[RISCV_MAX_INTEGER_OPS];
struct riscv_integer_op hicode[RISCV_MAX_INTEGER_OPS];
int hi_cost, lo_cost;
@@ -674,7 +674,7 @@ riscv_split_integer_cost (HOST_WIDE_INT val)
{
int cost;
unsigned HOST_WIDE_INT loval = sext_hwi (val, 32);
- unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32);
+ unsigned HOST_WIDE_INT hival = sext_hwi (val >> 32, 32);
struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS];
cost = 2 + riscv_build_integer (codes, loval, VOIDmode);
@@ -700,7 +700,7 @@ static rtx
riscv_split_integer (HOST_WIDE_INT val, machine_mode mode)
{
unsigned HOST_WIDE_INT loval = sext_hwi (val, 32);
- unsigned HOST_WIDE_INT hival = sext_hwi ((val - loval) >> 32, 32);
+ unsigned HOST_WIDE_INT hival = sext_hwi (val >> 32, 32);
rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode);
riscv_move_integer (lo, lo, loval, mode);