GCC is producing wrong code for the following C code on my port:
int f(short *p){
int sum, i;
sum = 0;
for(i = 0; i < 256; i++){
sum += *p++ & 0xFF;
}
return sum;
}
The problem boils down to this RTL
(zero_extend:SI (subreg:QI (mem:HI (post_inc:SI (reg/v/f:SI 61 [ p ])) [2 S2
A16]) 0))
being replaced by this RTL
(zero_extend:SI (mem:QI (post_inc:SI (reg/v/f:SI 0 r0 [orig:61 p ] [61])) [2 S1
A16]))
which changes the post-increment amount from 2 to 1. I tracked down the
problem. Reload calls cleanup_subreg_operands for each insn. This leads to
the following sequence of nested calls:
reload1.c: reload
final.c: cleanup_subreg_operands
final.c: alter_subreg
emit-rtl.c: adjust_address_1
emit-rtl.c: change_address_1
None of these check mode_dependent_address_p.
At some point, the post_inc should be replaced with a post_modify if available
or a separate add insn. Theoretically, a machine could have neither
post_modify nor add with immediate and the separate add could need reloading.
I believe the question is "Who's responsibility is it to ensure the correct
code?" Combine creates the subreg. Perhaps combine should instead create the
post_modify or separate add. Perhaps this job should be tossed onto the pile
that is reload. Perhaps some other pass in between should ensure that any such
subregs have been transformed.
I believe this is one of those bugs that has been there forever but is only
exposed when more optimization is done in tree land.
--
Summary: mode_dependent_address_p not checked when simplifying
subreg
Product: gcc
Version: 4.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: middle-end
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: TabonyEE at austin dot rr dot com
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30798