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.
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;
 }
 

Reply via email to