On Tue, 08 Nov 2022 19:26:01 PST (-0800), gcc-patches@gcc.gnu.org wrote:
loading constant 0x739290001LL in rv32 can be done with three instructions output: li a1, 7 lui a1, 234128 addi a1, a1, 1
Probably more useful to load the constant into two different registers? The point is the same, though, so just a commit message issue.
Similarly, loading 0x839290001LL in rv32 can be done within three instructions expected output: li a1, 8 lui a1, 234128 addi a1, a1, 1 However, riscv_build_integer does not handle this case well and makes a wrong prediction about the number of instructions needed and then the constant is forced to put in the memory via riscv_const_insns and emit_move_insn. real output: lui a4,%hi(.LC0) lw a2,%lo(.LC0)(a4) lw a3,%lo(.LC0+4)(a4) .LC0: .word958988289 .word8
That's still 3 instructions, but having loads and a constant is worse so that's just another commit message issue.
comparison with clang: https://godbolt.org/z/v5nxTbKe9 <https://godbolt.org/z/v5nxTbKe9 >
IIUC the rules are generally no compiler explorer links (so we can preserve history) and no attachment patches (ie, inline them like git-send-email does). There's some documenation on sending patches at <https://gcc.gnu.org/contribute.html>.
Given those usually show up for first-time contributors there's also some copyright/DCO procedures to bo followed. I see some other linux.alibaba.com emails called out explicitly, but then also a generic "GCC Alibaba Group Holding Limited". I think that means we're OK for copyright assignment here? There's still the "you wrote the code" bits that are worth reading, though.
Looking at the attached patch:
+ if ((value > INT32_MAX || value < INT32_MIN) && !TARGET_64BIT) + { + unsigned HOST_WIDE_INT loval = sext_hwi (value, 32); + unsigned HOST_WIDE_INT hival = sext_hwi ((value - loval) >> 32, 32); + struct riscv_integer_op alt_codes[RISCV_MAX_INTEGER_OPS], + hicode[RISCV_MAX_INTEGER_OPS]; + int hi_cost, lo_cost; + + hi_cost = riscv_build_integer_1 (hicode, hival, mode); + if (hi_cost < cost) + { + lo_cost = riscv_build_integer_1 (alt_codes, loval, mode); + if (lo_cost + hi_cost < cost) + { + memcpy (codes, alt_codes, + lo_cost * sizeof (struct riscv_integer_op)); + memcpy (codes + lo_cost, hicode, + hi_cost * sizeof (struct riscv_integer_op)); + cost = lo_cost + hi_cost; + } + } + }
This kind of stuff always seems like it should be possible to handle with generic middle-end optimizations: it's essentially just splitting the 64-bit constant into two 32-bit constants, which is free because it's going into two registers anyway. That's not a RISC-V specific problem, it's just the case any time a constant is going to be split between two registers -- it'd even apply for 128-bit constants on rv64, though those are probably rare enough they don't matter all that much.
I'm not opposed to doing this in the backend, but maybe it's a sign we've just screwed something else up and can avoid adding the code?
+++ b/gcc/testsuite/gcc.target/riscv/rv32-load-64bit-constant.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc -mabi=ilp32 -Os" } */
This has the same library/abi problems we've had before, but in this case I think it's fine to just leave the -march/-mabi out: the test cases won't be that exciting on rv64 (unless we add the 128-bit splits too?), but they should still stay away from the constant pool.
IIUC this should work on more than Os, at least O2/above? Not that exciting for the test case, though.
+/* { dg-final { scan-assembler-not "\.LC\[0-9\]" } } */
That's a bit fragile, maybe just match on load-word?