Hi!
Note, in other cases combine is sucessful. E.g. consider:
struct S { int a, b, c, d; };
struct T { struct S e[16]; struct S f[1024]; } t;
int
foo (unsigned long x)
{
return t.f[x + 5].a;
}
int
bar (struct T *x, unsigned long y)
{
return x->f[y + 5].b;
}
On x86_64-linux with -O2, we have before combine in both cases
(idx + 21) << 4 and in foo combine says:
Trying 7, 8 -> 10:
7: {r87:DI=r91:DI+0x15;clobber flags:CC;}
REG_DEAD r91:DI
REG_UNUSED flags:CC
8: {r88:DI=r87:DI<<0x4;clobber flags:CC;}
REG_DEAD r87:DI
REG_UNUSED flags:CC
10: r90:SI=[r88:DI+`t']
REG_DEAD r88:DI
Failed to match this instruction:
(set (reg:SI 90 [ t.f[_1].a ])
(mem:SI (plus:DI (mult:DI (reg:DI 91)
(const_int 16 [0x10]))
(const:DI (plus:DI (symbol_ref:DI ("t") [flags 0x2] <var_decl
0x7f837b94cab0 t>)
(const_int 336 [0x150])))) [1 t.f[_1].a+0 S4 A32]))
Successfully matched this instruction:
(set (reg:DI 88)
(ashift:DI (reg:DI 91)
(const_int 4 [0x4])))
Successfully matched this instruction:
(set (reg:SI 90 [ t.f[_1].a ])
(mem:SI (plus:DI (reg:DI 88)
(const:DI (plus:DI (symbol_ref:DI ("t") [flags 0x2] <var_decl
0x7f837b94cab0 t>)
(const_int 336 [0x150])))) [1 t.f[_1].a+0 S4 A32]))
and it is merged the way we want:
salq $4, %rdi
movl t+336(%rdi), %eax
while in bar:
Failed to match this instruction:
(set (reg:SI 91 [ x_4(D)->f[_1].b ])
(mem:SI (plus:DI (plus:DI (mult:DI (reg:DI 93)
(const_int 16 [0x10]))
(reg:DI 92))
(const_int 340 [0x154])) [1 x_4(D)->f[_1].b+0 S4 A32]))
Failed to match this instruction:
(set (reg:DI 88)
(plus:DI (ashift:DI (reg:DI 93)
(const_int 4 [0x4]))
(reg:DI 92)))
and it is not merged:
addq $21, %rsi
salq $4, %rsi
movl 4(%rsi,%rdi), %eax
when it could be:
salq $4, %rsi
movl 340(%rsi,%rdi), %eax
It isn't x86 specific though, e.g. on powerpc64-linux we end up with:
addi 4,4,21
sldi 4,4,4
add 4,3,4
lwa 3,4(4)
for bar, where I guess:
sldi 4,4,4
add 4,3,4
lwa 3,340(4)
would work too.
Jakub