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.
R.
> arm_overalign_2.patch
>
>
> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
> index
> 164ac13a26289bf755c89e78a8a5f751883c6039..c6718282d2555f8cf9a4e9111b1393e1f7704983
> 100644
> --- a/gcc/config/arm/arm.md
> +++ b/gcc/config/arm/arm.md
> @@ -5415,6 +5415,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 LDRD's into 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;
> + }
> "
> )
>
>