diff mbox

[2/2,ARM] fix movdi expander to avoid illegal ldrd/strd

Message ID 5596A9C7.3040109@arm.com
State New
Headers show

Commit Message

Alan Lawrence July 3, 2015, 3:27 p.m. UTC
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.

Comments

Richard Earnshaw July 3, 2015, 4:16 p.m. UTC | #1
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;
> +    }
>    "
>  )
>  
>
diff mbox

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;
+    }
   "
 )