Richard Earnshaw wrote:
On 03/07/15 16:27, Alan Lawrence wrote:
The previous patch caused a regression in
gcc.c-torture/execute/20040709-1.c at -O0 (only), and the new
align_rec2.c test fails, both outputting an illegal assembler
instruction (ldrd on an odd-numbered reg) from output_move_double in
arm.c. Most routes have checks against such an illegal instruction, but
expanding a function call can directly name such impossible register
(pairs), bypassing the normal checks.
gcc/ChangeLog:
* config/arm/arm.md (movdi): Avoid odd-number ldrd/strd in ARM state.
OK.
Both patches, plus Jakub's test, pushed onto trunk (r221461/5/6), and
gcc-5-branch (r225467/9/70), with an obvious comment fix to the movdi patch
(LDRD's into, STRD's from), as below.
Cheers, Alan
Index: gcc/config/arm/arm.md
===================================================================
--- gcc/config/arm/arm.md (revision 225457)
+++ gcc/config/arm/arm.md (working copy)
@@ -5481,6 +5481,42 @@
if (!REG_P (operands[0]))
operands[1] = force_reg (DImode, operands[1]);
}
+ if (REG_P (operands[0]) && REGNO (operands[0]) < FIRST_VIRTUAL_REGISTER
+ && !HARD_REGNO_MODE_OK (REGNO (operands[0]), DImode))
+ {
+ /* Avoid LDRD's into an odd-numbered register pair in ARM state
+ when expanding function calls. */
+ gcc_assert (can_create_pseudo_p ());
+ if (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1]))
+ {
+ /* Perform load into legal reg pair first, then move. */
+ rtx reg = gen_reg_rtx (DImode);
+ emit_insn (gen_movdi (reg, operands[1]));
+ operands[1] = reg;
+ }
+ emit_move_insn (gen_lowpart (SImode, operands[0]),
+ gen_lowpart (SImode, operands[1]));
+ emit_move_insn (gen_highpart (SImode, operands[0]),
+ gen_highpart (SImode, operands[1]));
+ DONE;
+ }
+ else if (REG_P (operands[1]) && REGNO (operands[1]) < FIRST_VIRTUAL_REGISTER
+ && !HARD_REGNO_MODE_OK (REGNO (operands[1]), DImode))
+ {
+ /* Avoid STRD's from an odd-numbered register pair in ARM state
+ when expanding function prologue. */
+ gcc_assert (can_create_pseudo_p ());
+ rtx split_dest = (MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0]))
+ ? gen_reg_rtx (DImode)
+ : operands[0];
+ emit_move_insn (gen_lowpart (SImode, split_dest),
+ gen_lowpart (SImode, operands[1]));
+ emit_move_insn (gen_highpart (SImode, split_dest),
+ gen_highpart (SImode, operands[1]));
+ if (split_dest != operands[0])
+ emit_insn (gen_movdi (operands[0], split_dest));
+ DONE;
+ }
"
)