reload.c (find_valid_class_1): New static function.
authorBernd Schmidt <bernds@codesourcery.com>
Thu, 9 Aug 2012 13:18:05 +0000 (13:18 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Thu, 9 Aug 2012 13:18:05 +0000 (13:18 +0000)
* reload.c (find_valid_class_1): New static function.
(push_reload): Use it when reloading a SYMBOL_REG as the inner
of a subreg.  Keep better track of needed classes for the
secondary memory case.
* config/i386/i386.h (LIMIT_RELOAD_CLASS): Limit INT_SSE_REGS to
GENERAL_REGS.
* reload1.c (replaced_subreg): New static function.
(gen_reload): Use it when deciding whether to use secondary
memory.

* gcc.c-torture/compile/20120727-1.c: New test.

From-SVN: r190252

gcc/ChangeLog
gcc/config/i386/i386.h
gcc/reload.c
gcc/reload1.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20120727-1.c [new file with mode: 0644]

index 36302bffbcbcc547e10cf6e039c584a27a718647..2a00c31eb00dc56abd2bd9929cad86c5052cadb9 100644 (file)
@@ -1,3 +1,15 @@
+2012-08-09  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * reload.c (find_valid_class_1): New static function.
+       (push_reload): Use it when reloading a SYMBOL_REG as the inner
+       of a subreg.  Keep better track of needed classes for the
+       secondary memory case.
+       * config/i386/i386.h (LIMIT_RELOAD_CLASS): Limit INT_SSE_REGS to
+       GENERAL_REGS.
+       * reload1.c (replaced_subreg): New static function.
+       (gen_reload): Use it when deciding whether to use secondary
+       memory.
+
 2012-08-09  Richard Guenther  <rguenther@suse.de>
 
        * tree.h (SSA_VAR_P): Simplify.
index c2b44607585c401c7019ac44cdf98ef3c5a99fa9..de7b82a57e7b78560cea009b3b2b9c427b18178f 100644 (file)
@@ -1384,7 +1384,8 @@ enum reg_class
   ((MODE) == QImode && !TARGET_64BIT                           \
    && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS          \
        || (CLASS) == LEGACY_REGS || (CLASS) == INDEX_REGS)     \
-   ? Q_REGS : (CLASS))
+   ? Q_REGS                                                    \
+   : (CLASS) == INT_SSE_REGS ? GENERAL_REGS : (CLASS))
 
 /* If we are copying between general and FP registers, we need a memory
    location. The same is true for SSE and MMX registers.  */
index 39178d857d1c76e155e8a1ac3a0d267d7c81bf0c..201f4759ad5f5868c83579526ac7041661f9d447 100644 (file)
@@ -707,6 +707,55 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
 
   return best_class;
 }
+
+/* We are trying to reload a subreg of something that is not a register.
+   Find the largest class which has at least one register valid in
+   mode MODE.  OUTER is the mode of the subreg, DEST_CLASS the class in
+   which we would eventually like to obtain the object.  */
+
+static enum reg_class
+find_valid_class_1 (enum machine_mode outer ATTRIBUTE_UNUSED,
+                   enum machine_mode mode ATTRIBUTE_UNUSED,
+                   enum reg_class dest_class ATTRIBUTE_UNUSED)
+{
+  int best_cost = -1;
+  int rclass;
+  int regno;
+  enum reg_class best_class = NO_REGS;
+  unsigned int best_size = 0;
+  int cost;
+
+  for (rclass = 1; rclass < N_REG_CLASSES; rclass++)
+    {
+      int bad = 0;
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++)
+       if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno)
+           && !HARD_REGNO_MODE_OK (regno, mode))
+         bad = 1;
+
+      if (bad)
+       continue;
+
+      cost = register_move_cost (outer, (enum reg_class) rclass, dest_class);
+
+      if ((reg_class_size[rclass] > best_size
+          && (best_cost < 0 || best_cost >= cost))
+         || best_cost > cost)
+       {
+         best_class = (enum reg_class) rclass;
+         best_size = reg_class_size[rclass];
+         best_cost = register_move_cost (outer, (enum reg_class) rclass,
+                                         dest_class);
+       }
+    }
+
+  gcc_assert (best_size != 0);
+
+#ifdef LIMIT_RELOAD_CLASS
+  best_class = LIMIT_RELOAD_CLASS (mode, best_class);
+#endif
+  return best_class;
+}
 \f
 /* Return the number of a previously made reload that can be combined with
    a new one, or n_reloads if none of the existing reloads can be used.
@@ -925,6 +974,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
   int secondary_in_reload = -1, secondary_out_reload = -1;
   enum insn_code secondary_in_icode = CODE_FOR_nothing;
   enum insn_code secondary_out_icode = CODE_FOR_nothing;
+  enum reg_class subreg_in_class ATTRIBUTE_UNUSED;
+  subreg_in_class = NO_REGS;
 
   /* INMODE and/or OUTMODE could be VOIDmode if no mode
      has been specified for the operand.  In that case,
@@ -1091,16 +1142,18 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
   if (in != 0 && reload_inner_reg_of_subreg (in, inmode, false))
     {
-      enum reg_class in_class = rclass;
-
       if (REG_P (SUBREG_REG (in)))
-       in_class
+       subreg_in_class
          = find_valid_class (inmode, GET_MODE (SUBREG_REG (in)),
                              subreg_regno_offset (REGNO (SUBREG_REG (in)),
                                                   GET_MODE (SUBREG_REG (in)),
                                                   SUBREG_BYTE (in),
                                                   GET_MODE (in)),
                              REGNO (SUBREG_REG (in)));
+      else if (GET_CODE (SUBREG_REG (in)) == SYMBOL_REF)
+       subreg_in_class = find_valid_class_1 (inmode,
+                                             GET_MODE (SUBREG_REG (in)),
+                                             rclass);
 
       /* This relies on the fact that emit_reload_insns outputs the
         instructions for input reloads of type RELOAD_OTHER in the same
@@ -1108,7 +1161,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
         RELOAD_OTHER, we are guaranteed that this inner reload will be
         output before the outer reload.  */
       push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0,
-                  in_class, VOIDmode, VOIDmode, 0, 0, opnum, type);
+                  subreg_in_class, VOIDmode, VOIDmode, 0, 0, opnum, type);
       dont_remove_subreg = 1;
     }
 
@@ -1327,13 +1380,15 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
         So add an additional reload.  */
 
 #ifdef SECONDARY_MEMORY_NEEDED
-      /* If a memory location is needed for the copy, make one.  */
-      if (in != 0
+      if (subreg_in_class == NO_REGS
+         && in != 0
          && (REG_P (in)
              || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in))))
-         && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
-         && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
-                                     rclass, inmode))
+         && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER)
+       subreg_in_class = REGNO_REG_CLASS (reg_or_subregno (in));
+      /* If a memory location is needed for the copy, make one.  */
+      if (subreg_in_class != NO_REGS
+         && SECONDARY_MEMORY_NEEDED (subreg_in_class, rclass, inmode))
        get_secondary_mem (in, inmode, opnum, type);
 #endif
 
index e6d3a7132edd970e4fb6ae2ad02234266db4f2cb..bf5d3d3bb083e3f42f0e2af21103f92fbf3bf6b4 100644 (file)
@@ -8469,6 +8469,18 @@ emit_insn_if_valid_for_reload (rtx insn)
   return NULL;
 }
 
+/* If X is not a subreg, return it unmodified.  If it is a subreg,
+   look up whether we made a replacement for the SUBREG_REG.  Return
+   either the replacement or the SUBREG_REG.  */
+
+static rtx
+replaced_subreg (rtx x)
+{
+  if (GET_CODE (x) == SUBREG)
+    return find_replacement (&SUBREG_REG (x));
+  return x;
+}
+
 /* Emit code to perform a reload from IN (which may be a reload register) to
    OUT (which may also be a reload register).  IN or OUT is from operand
    OPNUM with reload type TYPE.
@@ -8479,7 +8491,7 @@ static rtx
 gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
 {
   rtx last = get_last_insn ();
-  rtx tem;
+  rtx tem, tem1, tem2;
 
   /* If IN is a paradoxical SUBREG, remove it and try to put the
      opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
@@ -8616,14 +8628,12 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
 
 #ifdef SECONDARY_MEMORY_NEEDED
   /* If we need a memory location to do the move, do it that way.  */
-  else if ((REG_P (in)
-            || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in))))
-          && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
-          && (REG_P (out)
-              || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out))))
-          && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
-          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
-                                      REGNO_REG_CLASS (reg_or_subregno (out)),
+  else if ((tem1 = replaced_subreg (in), tem2 = replaced_subreg (out),
+           (REG_P (tem1) && REG_P (tem2)))
+          && REGNO (tem1) < FIRST_PSEUDO_REGISTER
+          && REGNO (tem2) < FIRST_PSEUDO_REGISTER
+          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (tem1)),
+                                      REGNO_REG_CLASS (REGNO (tem2)),
                                       GET_MODE (out)))
     {
       /* Get the memory to use and rewrite both registers to its mode.  */
index 47066a3f3a9593d73bbd502af40b625d7f1faefa..7dcf7d760edc0954aa62012057d2db38c6c15411 100644 (file)
@@ -1,3 +1,7 @@
+2012-08-09  Bernd Schmidt  <bernds@codesourcery.com>
+
+       * gcc.c-torture/compile/20120727-1.c: New test.
+
 2012-08-09  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/54199
diff --git a/gcc/testsuite/gcc.c-torture/compile/20120727-1.c b/gcc/testsuite/gcc.c-torture/compile/20120727-1.c
new file mode 100644 (file)
index 0000000..d43472f
--- /dev/null
@@ -0,0 +1,11 @@
+union {
+  char *p;
+  float f;
+} u;
+
+void
+f (void)
+{
+  u.p = "";
+  u.f += 1.1;
+}