diff mbox

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

Message ID 559ABD76.2050508@arm.com
State New
Headers show

Commit Message

Alan Lawrence July 6, 2015, 5:40 p.m. UTC
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
diff mbox

Patch

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