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