------- Comment #5 from rguenth at gcc dot gnu dot org 2007-07-09 15:00 ------- Note that we don't hoist the i*4 or the addition to p to help addressing mode selection which likes to see the "whole" address.
Of course it shouldn't matter in which form we see the addresses and the same code should be generated for all, still canonicalization to the same form makes a difference. In fact, canonicalizing to unsigned int D.1656; <bb 2>: D.1656 = i * 4; return (*(p + (D.1656 + 8)) + *(p + (D.1656 + 4))) + *(p + (D.1656 + 12)); as you suggest creates worse assembly (look at the extra shift) foo: pushl %ebp movl %esp, %ebp movl 12(%ebp), %ecx movl 8(%ebp), %edx popl %ebp sall $2, %ecx movl 8(%ecx,%edx), %eax addl 4(%ecx,%edx), %eax addl 12(%ecx,%edx), %eax ret in fact the above shows that the proper fix would be in the backend (if there is anything to fix) and making sure we consistently canonicalize is good enough. Consider the related testcase int foo(int *p, short *q, char *r, unsigned int i) { return p[i + 1] + q[i + 1] + r[i + 1]; } which in one case is canonicalized to unsigned int D.1658; <bb 2>: D.1658 = i + 1; return ((int) *(r + D.1658) + *(p + D.1658 * 4)) + (int) *(q + D.1658 * 2); in the other to return ((int) *(r + (i + 1)) + *(p + (i * 4 + 4))) + (int) *(q + (i * 2 + 2)); so there is no form that is clearly better to canonicalize to. But the correct "form" depends on the context (whether it is profitable to either CSE i * 4 or i + 1). -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32698