On Tue, 2016-10-04 at 12:53 +0000, Wilco Dijkstra wrote:
> GCC currently doesn't canonicalize address expressions. As a result
> inefficient code is generated even for trivial index address
> expressions,
> blocking CSE and other optimizations:
>
> int f(int *p, int i) { return p[i+2] + p[i+1]; }
>
> sxtw x1, w1
> add x1, x1, 2
> add x2, x0, x1, lsl 2
> ldr w0, [x0, x1, lsl 2]
> ldr w1, [x2, -4]
> add w0, w1, w0
> ret
>
> After this patch:
>
> add x1, x0, x1, sxtw 2
> ldp w0, w2, [x1, 4]
> add w0, w2, w0
> ret
>
> The reason for this is that array index expressions are preferably
> kept in the *(p + (i + C0) * C1) form eventhough it is best on most
> targets to make use of an offset in memory accesses - ie. *(p + i *
> C1 + (C0*C1)).
>
> This patch disables the folding in fold_plusminus_mult_expr that
> changes the latter form into the former. Unfortunately it isn't
> possible to know it is an address expression, and neither is there a
> way to decide when C0*C1 is too complex.
>
> So is there a better way/place to do this, or do we need an address
> canonicalization phase in the tree that ensures we expand addresses
> in an efficient manner, taking into account target offsets?
There's been an effort to implement address mode selection (AMS)
optimization in GCC as part of the GSoC program. However, it hasn't
been mainlined yet and it's for SH only, but I'd like to move that
forward and make it available to other backends, too.
It's an RTL pass and works by analyzing memory accesses inside basic
blocks, figuring out the effective address expressions, querying the
backend for address mode alternatives for each memory access and the
associated costs. With that information it tries to find a minimal
solution (minimizing address register calculations and minimizing
address mode alternative costs), which is currently implemented with
backtracking.
For SH, the AMS pass can convert your example above from this
_f:
mov r5,r0
add #2,r0
shll2 r0
mov r4,r1
add r0,r1
mov.l @(r0,r4),r0
add #-4,r1
mov.l @r1,r2
rts
add r2,r0
into this:
_f:
shll2 r5
add r5,r4
mov.l @(4,r4),r0
mov.l @(8,r4),r1
rts
add r1,r0
.. which is minimal on SH.
It also fixes several missed auto-inc opportunities and was meant to
allow further address mode related optimizations like displacement
range fitting or access reordering.
Although not yet ready for mainline, the current code can be found on
github:
https://github.com/erikvarga/gcc/commits/master
https://github.com/erikvarga/gcc/blob/master/gcc/ams.h
https://github.com/erikvarga/gcc/blob/master/gcc/ams.cc
The way AMS gets address mode information from the backend is different
to GCC's current approach:
https://github.com/erikvarga/gcc/blob/master/gcc/config/sh/sh.c#L11946
Since the SH ISA is a bit irregular, there are a bunch of exceptions
and special cases in the cost calculations which take surrounding insns
and mem accesses into account. I guess a more regular or less
restrictive ISA wouldn't need too many special cases.
Cheers,
Oleg