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