diff mbox

[MIPS] Improve unaligned 32bits load on MIPS64

Message ID E3980B5A0D7C9243AC3486B369A6143018758BE1@BY2PRD0710MB377.namprd07.prod.outlook.com
State New
Headers show

Commit Message

Andrew Pinski July 20, 2012, 7:34 p.m. UTC
Hi,
  Currently doing a 32bit unaligned load on MIPS64, produces 4 byte loads, this can be improved to using lwl/lwr instead.  The problem is the code in mips_expand_ext_as_unaligned_load that handles this case does handle the case where the register is DImode but the width is 32.

This patch fixes the problem by creating a new temp register of SImode and then using that as the destination and then extending (zero or sign depending on the if it is extv or extzv) into the original destination.

OK?  Bootstrapped and tested on mips64-linux-gnu with no regressions.

Thanks,
Andrew Pinski

ChangeLog:
* config/mips/mips-protos.h (mips_expand_ext_as_unaligned_load): Add a bool argument.
* config/mips/mips.c (mips_block_move_straight): Update call to mips_expand_ext_as_unaligned_load.
(mips_expand_ext_as_unaligned_load): Add unsigned_p argument.
Accept DImode dest when the width is that of SImode.

Comments

Richard Sandiford July 21, 2012, 7:35 a.m. UTC | #1
"Pinski, Andrew" <Andrew.Pinski@caviumnetworks.com> writes:
> +  /* If TARGET_64BIT, the destination of a 32-bit "extz" or "extzv" will
> +     be a DImode, create a new temp and emit a zero extend at the end.  */

"emit an extend", since it can be signed or unsigned.  OK with that change.

Nice optimisation, thanks.

Richard
diff mbox

Patch

Index: testsuite/gcc.target/mips/unaligned-1.c
===================================================================
--- testsuite/gcc.target/mips/unaligned-1.c	(revision 0)
+++ testsuite/gcc.target/mips/unaligned-1.c	(revision 0)
@@ -0,0 +1,44 @@ 
+/* { dg-options "-O2 -mgp64" } */
+/* { dg-final { scan-assembler-times "sdl\t" 1 } } */
+/* { dg-final { scan-assembler-times "sdr\t" 1 } } */
+/* { dg-final { scan-assembler-times "ldl\t" 1 } } */
+/* { dg-final { scan-assembler-times "ldr\t" 1 } } */
+/* { dg-final { scan-assembler-times "swl\t" 1 } } */
+/* { dg-final { scan-assembler-times "swr\t" 1 } } */
+/* { dg-final { scan-assembler-times "lwl\t" 1 } } */
+/* { dg-final { scan-assembler-times "lwr\t" 1 } } */
+/* { dg-final { scan-assembler-not "nop" } } */
+
+/* Test to make sure we produce the unaligned load/store for
+   both 64bit and 32bits sized accesses.  */
+
+struct s
+{
+  char c;
+  int i;
+  long long l;
+} __attribute__ ((packed)) s __attribute__((aligned(1) ));
+
+void
+sd (long long l)
+{
+  s.l = l;
+}
+
+long long
+ld ()
+{
+  return s.l;
+}
+
+void
+sw (int i)
+{
+  s.i = i;
+}
+
+int
+lw ()
+{
+  return s.i;
+}
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 189724)
+++ config/mips/mips.md	(working copy)
@@ -3653,7 +3653,8 @@  (define_expand "extv"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
 					 INTVAL (operands[2]),
-					 INTVAL (operands[3])))
+					 INTVAL (operands[3]),
+					 /*unsigned=*/ false))
     DONE;
   else if (register_operand (operands[1], GET_MODE (operands[0]))
 	   && ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32)
@@ -3690,7 +3691,8 @@  (define_expand "extzv"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
 					 INTVAL (operands[2]),
-					 INTVAL (operands[3])))
+					 INTVAL (operands[3]),
+					 /*unsigned=*/true))
     DONE;
   else if (mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
 			       INTVAL (operands[3])))
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 189724)
+++ config/mips/mips-protos.h	(working copy)
@@ -241,7 +241,7 @@  extern bool mips_pad_arg_upward (enum ma
 extern bool mips_pad_reg_upward (enum machine_mode, tree);
 
 extern bool mips_expand_ext_as_unaligned_load (rtx, rtx, HOST_WIDE_INT,
-					       HOST_WIDE_INT);
+					       HOST_WIDE_INT, bool);
 extern bool mips_expand_ins_as_unaligned_store (rtx, rtx, HOST_WIDE_INT,
 						HOST_WIDE_INT);
 extern bool mips_mem_fits_mode_p (enum machine_mode mode, rtx x);
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 189724)
+++ config/mips/mips.c	(working copy)
@@ -6916,7 +6916,7 @@  mips_block_move_straight (rtx dest, rtx 
       else
 	{
 	  rtx part = adjust_address (src, BLKmode, offset);
-	  if (!mips_expand_ext_as_unaligned_load (regs[i], part, bits, 0))
+	  if (!mips_expand_ext_as_unaligned_load (regs[i], part, bits, 0, 0))
 	    gcc_unreachable ();
 	}
     }
@@ -7248,9 +7248,10 @@  mips_get_unaligned_mem (rtx *op, HOST_WI
 
 bool
 mips_expand_ext_as_unaligned_load (rtx dest, rtx src, HOST_WIDE_INT width,
-				   HOST_WIDE_INT bitpos)
+				   HOST_WIDE_INT bitpos, bool unsigned_p)
 {
   rtx left, right, temp;
+  rtx dest1 = NULL_RTX;
 
   /* If TARGET_64BIT, the destination of a 32-bit "extz" or "extzv" will
      be a paradoxical word_mode subreg.  This is the only case in which
@@ -7260,6 +7261,16 @@  mips_expand_ext_as_unaligned_load (rtx d
       && GET_MODE (SUBREG_REG (dest)) == SImode)
     dest = SUBREG_REG (dest);
 
+  /* If TARGET_64BIT, the destination of a 32-bit "extz" or "extzv" will
+     be a DImode, create a new temp and emit a zero extend at the end.  */
+  if (GET_MODE (dest) == DImode
+      && REG_P (dest)
+      && GET_MODE_BITSIZE (SImode) == width)
+    {
+      dest1 = dest;
+      dest = gen_reg_rtx (SImode);
+    }
+
   /* After the above adjustment, the destination must be the same
      width as the source.  */
   if (GET_MODE_BITSIZE (GET_MODE (dest)) != width)
@@ -7279,6 +7290,16 @@  mips_expand_ext_as_unaligned_load (rtx d
       emit_insn (gen_mov_lwl (temp, src, left));
       emit_insn (gen_mov_lwr (dest, copy_rtx (src), right, temp));
     }
+
+  /* If we were loading 32bits and the original register was DI then
+     sign/zero extend into the orignal dest.  */
+  if (dest1)
+    {
+      if (unsigned_p)
+        emit_insn (gen_zero_extendsidi2 (dest1, dest));
+      else
+        emit_insn (gen_extendsidi2 (dest1, dest));
+    }
   return true;
 }