[ARM] fix movdi expander to avoid illegal ldrd/strd
authorAlan Lawrence <alan.lawrence@arm.com>
Mon, 6 Jul 2015 16:21:55 +0000 (16:21 +0000)
committerAlan Lawrence <alalaw01@gcc.gnu.org>
Mon, 6 Jul 2015 16:21:55 +0000 (16:21 +0000)
        * config/arm/arm.md (movdi): Avoid odd-number ldrd/strd in ARM state.

From-SVN: r225461

gcc/ChangeLog
gcc/config/arm/arm.md

index d3929fa..8275549 100644 (file)
@@ -1,3 +1,7 @@
+2015-07-06  Alan Lawrence  <alan.lawrence@arm.com>
+
+       * config/arm/arm.md (movdi): Avoid odd-number ldrd/strd in ARM state.
+
 2015-07-06  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/66772
index 1ac8af0..be51c77 100644 (file)
       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;
+    }
   "
 )