Patchwork [aarch64] PR target/59780 Fix aarch64_split_128bit_move

login
register
mail settings
Submitter Richard Earnshaw
Date Jan. 16, 2014, 5:44 p.m.
Message ID <52D81A94.2070103@arm.com>
Download mbox | patch
Permalink /patch/311804/
State New
Headers show

Comments

Richard Earnshaw - Jan. 16, 2014, 5:44 p.m.
Looking at this PR I noticed that there were other potential issues with
the implementation of this function, so I've essentially rewritten it.
We now far more consistently use gen_(high/low)part, and avoid
dereferencing REGNO when we don't have a register src.

R.

2014-01-16  Richard Earnshaw  <rearnsha@arm.com>

	PR target/59780
	* aarch64.c (aarch64_split_128bit_move): Don't lookup REGNO on
	non-register objects.  Use gen_(high/low)part more consistently.
	Fix assertions.

Patch

--- aarch64.c	(revision 206647)
+++ aarch64.c	(local)
@@ -680,90 +680,82 @@  aarch64_emit_move (rtx dest, rtx src)
 	  : emit_move_insn_1 (dest, src));
 }
 
+/* Split a 128-bit move operation into two 64-bit move operations,
+   taking care to handle partial overlap of register to register
+   copies.  Special cases are needed when moving between GP regs and
+   FP regs.  SRC can be a register, constant or memory; DST a register
+   or memory.  If either operand is memory it must not have any side
+   effects.  */
 void
 aarch64_split_128bit_move (rtx dst, rtx src)
 {
-  rtx low_dst;
+  rtx dst_lo, dst_hi;
+  rtx src_lo, src_hi;
 
-  enum machine_mode src_mode = GET_MODE (src);
-  enum machine_mode dst_mode = GET_MODE (dst);
-  int src_regno = REGNO (src);
-  int dst_regno = REGNO (dst);
+  enum machine_mode mode = GET_MODE (dst);
 
-  gcc_assert (dst_mode == TImode || dst_mode == TFmode);
+  gcc_assert (mode == TImode || mode == TFmode);
+  gcc_assert (!(side_effects_p (src) || side_effects_p (dst)));
+  gcc_assert (mode == GET_MODE (src) || GET_MODE (src) == VOIDmode);
 
   if (REG_P (dst) && REG_P (src))
     {
-      gcc_assert (src_mode == TImode || src_mode == TFmode);
+      int src_regno = REGNO (src);
+      int dst_regno = REGNO (dst);
 
-      /* Handle r -> w, w -> r.  */
+      /* Handle FP <-> GP regs.  */
       if (FP_REGNUM_P (dst_regno) && GP_REGNUM_P (src_regno))
 	{
-	  switch (src_mode) {
-	  case TImode:
-	    emit_insn
-	      (gen_aarch64_movtilow_di (dst, gen_lowpart (word_mode, src)));
-	    emit_insn
-	      (gen_aarch64_movtihigh_di (dst, gen_highpart (word_mode, src)));
-	    return;
-	  case TFmode:
-	    emit_insn
-	      (gen_aarch64_movtflow_di (dst, gen_lowpart (word_mode, src)));
-	    emit_insn
-	      (gen_aarch64_movtfhigh_di (dst, gen_highpart (word_mode, src)));
-	    return;
-	  default:
-	    gcc_unreachable ();
-	  }
+	  src_lo = gen_lowpart (word_mode, src);
+	  src_hi = gen_highpart (word_mode, src);
+
+	  if (mode == TImode)
+	    {
+	      emit_insn (gen_aarch64_movtilow_di (dst, src_lo));
+	      emit_insn (gen_aarch64_movtihigh_di (dst, src_hi));
+	    }
+	  else
+	    {
+	      emit_insn (gen_aarch64_movtflow_di (dst, src_lo));
+	      emit_insn (gen_aarch64_movtfhigh_di (dst, src_hi));
+	    }
+	  return;
 	}
       else if (GP_REGNUM_P (dst_regno) && FP_REGNUM_P (src_regno))
 	{
-	  switch (src_mode) {
-	  case TImode:
-	    emit_insn
-	      (gen_aarch64_movdi_tilow (gen_lowpart (word_mode, dst), src));
-	    emit_insn
-	      (gen_aarch64_movdi_tihigh (gen_highpart (word_mode, dst), src));
-	    return;
-	  case TFmode:
-	    emit_insn
-	      (gen_aarch64_movdi_tflow (gen_lowpart (word_mode, dst), src));
-	    emit_insn
-	      (gen_aarch64_movdi_tfhigh (gen_highpart (word_mode, dst), src));
-	    return;
-	  default:
-	    gcc_unreachable ();
-	  }
+	  dst_lo = gen_lowpart (word_mode, dst);
+	  dst_hi = gen_highpart (word_mode, dst);
+
+	  if (mode == TImode)
+	    {
+	      emit_insn (gen_aarch64_movdi_tilow (dst_lo, src));
+	      emit_insn (gen_aarch64_movdi_tihigh (dst_hi, src));
+	    }
+	  else
+	    {
+	      emit_insn (gen_aarch64_movdi_tflow (dst_lo, src));
+	      emit_insn (gen_aarch64_movdi_tfhigh (dst_hi, src));
+	    }
+	  return;
 	}
-      /* Fall through to r -> r cases.  */
     }
 
-  switch (dst_mode) {
-  case TImode:
-    low_dst = gen_lowpart (word_mode, dst);
-    if (REG_P (low_dst)
-	&& reg_overlap_mentioned_p (low_dst, src))
-      {
-	aarch64_emit_move (gen_highpart (word_mode, dst),
-			   gen_highpart_mode (word_mode, TImode, src));
-	aarch64_emit_move (low_dst, gen_lowpart (word_mode, src));
-      }
-    else
-      {
-	aarch64_emit_move (low_dst, gen_lowpart (word_mode, src));
-	aarch64_emit_move (gen_highpart (word_mode, dst),
-			   gen_highpart_mode (word_mode, TImode, src));
-      }
-    return;
-  case TFmode:
-    emit_move_insn (gen_rtx_REG (DFmode, dst_regno),
-		    gen_rtx_REG (DFmode, src_regno));
-    emit_move_insn (gen_rtx_REG (DFmode, dst_regno + 1),
-		    gen_rtx_REG (DFmode, src_regno + 1));
-    return;
-  default:
-    gcc_unreachable ();
-  }
+  dst_lo = gen_lowpart (word_mode, dst);
+  dst_hi = gen_highpart (word_mode, dst);
+  src_lo = gen_lowpart (word_mode, src);
+  src_hi = gen_highpart_mode (word_mode, mode, src);
+
+  /* At most one pairing may overlap.  */
+  if (reg_overlap_mentioned_p (dst_lo, src_hi))
+    {
+      aarch64_emit_move (dst_hi, src_hi);
+      aarch64_emit_move (dst_lo, src_lo);
+    }
+  else
+    {
+      aarch64_emit_move (dst_lo, src_lo);
+      aarch64_emit_move (dst_hi, src_hi);
+    }
 }
 
 bool