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

Reply via email to