dse.c (find_shift_sequence): Allow word as well as subword shifts.
authorRichard Sandiford <rsandifo@nildram.co.uk>
Sun, 16 Sep 2007 21:02:54 +0000 (21:02 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 16 Sep 2007 21:02:54 +0000 (21:02 +0000)
gcc/
* dse.c (find_shift_sequence): Allow word as well as subword shifts.
Do the tentative shift expansion with the DF_NO_INSN_RESCAN flag set.
Fix the call to insn_rtx_cost.  Skip access sizes that require a
real truncation of the store register.  Use convert_move instead
of gen_lowpart when narrowing the result.
(replace_read): Use convert_move instead of gen_lowpart when
narrowing the store rhs.

gcc/testsuite/
* gcc.target/mips/dse-1.c: New test.

From-SVN: r128530

gcc/ChangeLog
gcc/dse.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/dse-1.c [new file with mode: 0644]

index db1ef1ca73fbafbd349ddddae4257b1cf4ad80fb..60bd52db87f2f9021f4c32d7f6a5334b119bea98 100644 (file)
@@ -1,3 +1,13 @@
+2007-09-16  Richard Sandiford  <rsandifo@nildram.co.uk>
+
+       * dse.c (find_shift_sequence): Allow word as well as subword shifts.
+       Do the tentative shift expansion with the DF_NO_INSN_RESCAN flag set.
+       Fix the call to insn_rtx_cost.  Skip access sizes that require a
+       real truncation of the store register.  Use convert_move instead
+       of gen_lowpart when narrowing the result.
+       (replace_read): Use convert_move instead of gen_lowpart when
+       narrowing the store rhs.
+
 2007-09-16  Richard Sandiford  <rsandifo@nildram.co.uk>
 
        * config/mips/mips.md (SHORT): Fix long line.
index e04e7e820ad93af759c1f2edb0a30f308493cab6..1aa1598e6b49b7cc524efcce80becfe9f96c7c6e 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -1407,21 +1407,31 @@ find_shift_sequence (rtx read_reg,
      justify the value we want to read but is available in one insn on
      the machine.  */
 
-  while (access_size < UNITS_PER_WORD)
+  for (; access_size <= UNITS_PER_WORD; access_size *= 2)
     {
-      rtx target;
-      enum machine_mode new_mode
-       = smallest_mode_for_size (access_size * BITS_PER_UNIT,
-                                 GET_MODE_CLASS (read_mode));
-      rtx new_reg = gen_reg_rtx (new_mode);
+      rtx target, new_reg;
+      enum machine_mode new_mode;
+
+      /* Try a wider mode if truncating the store mode to ACCESS_SIZE
+        bytes requires a real instruction.  */
+      if (access_size < GET_MODE_SIZE (store_mode)
+         && !TRULY_NOOP_TRUNCATION (access_size * BITS_PER_UNIT,
+                                    GET_MODE_BITSIZE (store_mode)))
+       continue;
+
+      new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT,
+                                        GET_MODE_CLASS (read_mode));
+      new_reg = gen_reg_rtx (new_mode);
 
       start_sequence ();
 
       /* In theory we could also check for an ashr.  Ian Taylor knows
         of one dsp where the cost of these two was not the same.  But
         this really is a rare case anyway.  */
+      df_set_flags (DF_NO_INSN_RESCAN);
       target = expand_binop (new_mode, lshr_optab, new_reg,
                             GEN_INT (shift), new_reg, 1, OPTAB_DIRECT);
+      df_clear_flags (DF_NO_INSN_RESCAN);
 
       if (target == new_reg)
        {
@@ -1436,7 +1446,8 @@ find_shift_sequence (rtx read_reg,
              rtx insn;
 
              for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
-               cost += insn_rtx_cost (insn);
+               if (INSN_P (insn))
+                 cost += insn_rtx_cost (PATTERN (insn));
 
              /* The computation up to here is essentially independent
                 of the arguments and could be precomputed.  It may
@@ -1455,7 +1466,7 @@ find_shift_sequence (rtx read_reg,
                  start_sequence ();
                  emit_move_insn (new_reg, gen_lowpart (new_mode, store_info->rhs));
                  emit_insn (shift_seq);
-                 emit_move_insn (read_reg,  gen_lowpart (read_mode, new_reg));
+                 convert_move (read_reg, new_reg, 1);
                  
                  if (dump_file)
                    {
@@ -1480,8 +1491,6 @@ find_shift_sequence (rtx read_reg,
       else
        /* End the sequence.  */
        end_sequence ();
-
-      access_size = access_size * 2;
     }
 
   return NULL;
@@ -1595,7 +1604,7 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
             place, we need to extract the value in the right from the
             rhs of the store.  */
          start_sequence ();
-         emit_move_insn (read_reg, gen_lowpart (read_mode, store_info->rhs));
+         convert_move (read_reg, store_info->rhs, 1);
          
          if (dump_file)
            fprintf (dump_file, " -- adding extract insn r%d:%s = r%d:%s\n",
index d99cdad19416c098f14444226c4a2bfd50631f64..1fea6a1daafd5db6660315a2a2c299d5235f3a2a 100644 (file)
@@ -1,3 +1,7 @@
+2007-09-16  Richard Sandiford  <rsandifo@nildram.co.uk>
+
+       * gcc.target/mips/dse-1.c: New test.
+
 2007-09-16  Nathan Sidwell  <nathan@codesourcery.com>
 
        PR c++/32756
diff --git a/gcc/testsuite/gcc.target/mips/dse-1.c b/gcc/testsuite/gcc.target/mips/dse-1.c
new file mode 100644 (file)
index 0000000..a2b8445
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-mips-options "-mgp64 -O" } */
+
+#define TEST(ID, TYPE1, TYPE2)                                 \
+  union {                                                      \
+    TYPE1 m1[sizeof (TYPE2) / sizeof (TYPE1)];                 \
+    TYPE2 m2;                                                  \
+  } u##ID;                                                     \
+                                                               \
+  /* The MIPS16 versions of the shifts we need are too         \
+     expensive.  */                                            \
+  TYPE1 __attribute__((nomips16))                              \
+  f##ID (TYPE2 x)                                              \
+  {                                                            \
+    u##ID.m2 = x;                                              \
+    return (u##ID.m1[0]                                                \
+           + u##ID.m1[sizeof (TYPE2) / sizeof (TYPE1) - 1]);   \
+  }
+
+TEST (1, unsigned int, unsigned long long);
+TEST (2, int, long long);
+TEST (3, unsigned short, unsigned long long);
+TEST (4, short, long long);
+TEST (5, unsigned char, unsigned long long);
+TEST (6, signed char, long long);
+
+TEST (7, unsigned short, unsigned int);
+TEST (8, short, int);
+TEST (9, unsigned char, unsigned int);
+TEST (10, signed char, int);
+
+/* DSE isn't yet read to consider stores of subregs, so the corresponding
+   (char, short) tests won't pass.  */
+
+/* { dg-final { scan-assembler-not "\tlh\t" } } */
+/* { dg-final { scan-assembler-not "\tlw\t" } } */
+/* { dg-final { scan-assembler-not "\tlb\t" } } */