The attached change fixes an old bug.  In debugging the segmentation fault of 
cc76narrowing1 in the
ppl-1.1 test suite, I found that we incorrectly handle register indexed memory 
operands in double word
loads on 32-bit targets.  In particular, when there is an overlap between the 
source registers and the
destination registers, we get wrong assembly code.  For example, with
(insn:TI 220 543 544 (set (reg:DF 28 %r28 [orig:133 D.246652 ] [133])        
(mem:DF (plus:SI (reg/f:SI 29 %r29 [orig:167 _49->D.173044.impl ] [167])
                (reg:SI 28 %r28 [163])) [142 MEM[(const double &)_53]+0 S8 A64])
) 72 {*pa.md:3858}

we generated the following assembly code:

        ldo 4(%r29),%r29
        ldw %r29(%r28),%r29
        ldo -4(%r29),%r29
        ldw %r29(%r28),%r28

The first ldw instruction clobbers %r29.

Tested on hppa-unknown-linux-gnu and hppa2.0w-hp-hpux11.11.  Committed to 
trunk, and 4.9 and 4.8 branches.

Dave
--
John David Anglin       dave.ang...@bell.net


2015-04-02  John David Anglin  <dang...@gcc.gnu.org>

        * config/pa/pa.c (pa_output_move_double): Directly handle register
        indexed memory operand.  Simplify handling of scaled register indexed
        memory operands.

Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c      (revision 221781)
+++ config/pa/pa.c      (working copy)
@@ -2595,29 +2595,30 @@
               && GET_CODE (XEXP (addr, 0)) == MULT)
        {
          rtx xoperands[4];
-         rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
 
-         if (!reg_overlap_mentioned_p (high_reg, addr))
-           {
-             xoperands[0] = high_reg;
-             xoperands[1] = XEXP (addr, 1);
-             xoperands[2] = XEXP (XEXP (addr, 0), 0);
-             xoperands[3] = XEXP (XEXP (addr, 0), 1);
-             output_asm_insn ("{sh%O3addl %2,%1,%0|shladd,l %2,%O3,%1,%0}",
-                              xoperands);
-             return "ldw 4(%0),%R0\n\tldw 0(%0),%0";
-           }
-         else
-           {
-             xoperands[0] = high_reg;
-             xoperands[1] = XEXP (addr, 1);
-             xoperands[2] = XEXP (XEXP (addr, 0), 0);
-             xoperands[3] = XEXP (XEXP (addr, 0), 1);
-             output_asm_insn ("{sh%O3addl %2,%1,%R0|shladd,l %2,%O3,%1,%R0}",
-                              xoperands);
-             return "ldw 0(%R0),%0\n\tldw 4(%R0),%R0";
-           }
+         /* Load address into left half of destination register.  */
+         xoperands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
+         xoperands[1] = XEXP (addr, 1);
+         xoperands[2] = XEXP (XEXP (addr, 0), 0);
+         xoperands[3] = XEXP (XEXP (addr, 0), 1);
+         output_asm_insn ("{sh%O3addl %2,%1,%0|shladd,l %2,%O3,%1,%0}",
+                          xoperands);
+         return "ldw 4(%0),%R0\n\tldw 0(%0),%0";
        }
+      else if (GET_CODE (addr) == PLUS
+              && REG_P (XEXP (addr, 0))
+              && REG_P (XEXP (addr, 1)))
+       {
+         rtx xoperands[3];
+
+         /* Load address into left half of destination register.  */
+         xoperands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
+         xoperands[1] = XEXP (addr, 0);
+         xoperands[2] = XEXP (addr, 1);
+         output_asm_insn ("{addl|add,l} %1,%2,%0",
+                          xoperands);
+         return "ldw 4(%0),%R0\n\tldw 0(%0),%0";
+       }
     }
 
   /* If an operand is an unoffsettable memory ref, find a register

Reply via email to