On 9/27/26 1:28 PM, Dominic P wrote:
When combine forms an invalid MEM address (plus X C), find_split_point
splits out X, or gives up if X is a register; neither helps when C is
not a valid offset either. Split out C instead in that case, so that
I3 can keep X, for example a scaled index, in the address. A valid
offset stays where it is, since splitting it out needs one more
register. I2DEST receives the constant, so try_combine now checks that
it has the mode of the address.
On arm, ((volatile unsigned int *) 0x20a04000)[i] = v becomes a constant
load and str v, [rC, ri, lsl #2] instead of lsl, add, add and str; on
aarch64 a register plus a mov/movk constant is no longer added first.
A Raspberry Pi firmware (arm1176, -O2 -flto) shrinks by 96 bytes.
Bootstrapped and regression tested on x86_64-pc-linux-gnu, and regression
tested on arm-none-eabi and aarch64-linux-gnu.
Assisted-by: Claude Opus 5 (Anthropic)
gcc/ChangeLog:
* combine.cc (address_constant_mode_mismatch_p): New function.
(try_combine): Do not split out an address constant into an I2DEST
of another mode.
(find_split_point): Split out a MEM address constant that is not a
valid offset.
gcc/testsuite/ChangeLog:
* gcc.dg/rtl/aarch64/split-const-offset-1.c: New test.
* gcc.dg/torture/split-const-offset-1.c: New test.
* gcc.target/aarch64/split-const-offset-1.c: New test.
* gcc.target/arm/split-const-offset-1.c: New test.
* gcc.target/arm/split-const-offset-2.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
OK for trunk?
Why do you have the !address_constant_mode_mismatch test? It would seem
that for x+C that the C is never going to match the mode of X because C
is always VOIDmode.
@@ -5026,6 +5043,16 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
XEXP (XEXP (XEXP (x, 0), 0), 1) = tem;
}
+ /* If the constant is not a valid offset, compute it separately.
+ Test with a pseudo: a virtual REG may accept any offset. */
+ machine_mode address_mode = GET_MODE (XEXP (x, 0));
+ rtx base = alloca_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1);
+ rtx addr = alloca_rtx_fmt_ee (PLUS, address_mode, base,
+ XEXP (XEXP (x, 0), 1));
+ if (!memory_address_addr_space_p (GET_MODE (x), addr,
+ MEM_ADDR_SPACE (x)))
+ return &XEXP (XEXP (x, 0), 1);
Not sure what the alloca_raw_REG stuff you're doing here is. It seems
like you just need a random reg to test validity of a reg+d style
address? Why not just use the expression as-is rather than creating a
new one? Feels like I'm missing something here.
Jeff