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