re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / ira-costs.c
index dbefaced65773749e439f2b160ce8339ebcc1380..0d39215b0479f086a813299ed4b173a5dc26f8d8 100644 (file)
@@ -1,5 +1,5 @@
 /* IRA hard register and memory cost calculation for allocnos or pseudos.
-   Copyright (C) 2006-2014 Free Software Foundation, Inc.
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -22,25 +22,29 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "hash-table.h"
 #include "hard-reg-set.h"
 #include "rtl.h"
+#include "symtab.h"
+#include "function.h"
+#include "flags.h"
+#include "alias.h"
+#include "tree.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "tm_p.h"
-#include "flags.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "input.h"
-#include "function.h"
 #include "dominance.h"
 #include "cfg.h"
 #include "basic-block.h"
 #include "regs.h"
 #include "addresses.h"
-#include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
 #include "diagnostic-core.h"
@@ -143,25 +147,23 @@ static cost_classes_t *regno_cost_classes;
 
 /* Helper for cost_classes hashing.  */
 
-struct cost_classes_hasher
+struct cost_classes_hasher : pointer_hash <cost_classes>
 {
-  typedef cost_classes value_type;
-  typedef cost_classes compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
-  static inline void remove (value_type *);
+  static inline hashval_t hash (const cost_classes *);
+  static inline bool equal (const cost_classes *, const cost_classes *);
+  static inline void remove (cost_classes *);
 };
 
 /* Returns hash value for cost classes info HV.  */
 inline hashval_t
-cost_classes_hasher::hash (const value_type *hv)
+cost_classes_hasher::hash (const cost_classes *hv)
 {
   return iterative_hash (&hv->classes, sizeof (enum reg_class) * hv->num, 0);
 }
 
 /* Compares cost classes info HV1 and HV2.  */
 inline bool
-cost_classes_hasher::equal (const value_type *hv1, const compare_type *hv2)
+cost_classes_hasher::equal (const cost_classes *hv1, const cost_classes *hv2)
 {
   return (hv1->num == hv2->num
          && memcmp (hv1->classes, hv2->classes,
@@ -170,7 +172,7 @@ cost_classes_hasher::equal (const value_type *hv1, const compare_type *hv2)
 
 /* Delete cost classes info V from the hash table.  */
 inline void
-cost_classes_hasher::remove (value_type *v)
+cost_classes_hasher::remove (cost_classes *v)
 {
   ira_free (v);
 }
@@ -251,7 +253,7 @@ setup_cost_classes (cost_classes_t from)
    valid for mode MODE.  Both FULL and the returned class are globally
    allocated.  */
 static cost_classes_t
-restrict_cost_classes (cost_classes_t full, enum machine_mode mode,
+restrict_cost_classes (cost_classes_t full, machine_mode mode,
                       const HARD_REG_SET &regs)
 {
   static struct cost_classes narrow;
@@ -387,12 +389,18 @@ setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
       classes_ptr = cost_classes_aclass_cache[aclass] = (cost_classes_t) *slot;
     }
   if (regno_reg_rtx[regno] != NULL_RTX)
-    /* Restrict the classes to those that are valid for REGNO's mode
-       (which might for example exclude singleton classes if the mode requires
-       two registers).  */
-    classes_ptr = restrict_cost_classes (classes_ptr,
-                                        PSEUDO_REGNO_MODE (regno),
-                                        reg_class_contents[ALL_REGS]);
+    {
+      /* Restrict the classes to those that are valid for REGNO's mode
+        (which might for example exclude singleton classes if the mode
+        requires two registers).  Also restrict the classes to those that
+        are valid for subregs of REGNO.  */
+      const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno);
+      if (!valid_regs)
+       valid_regs = &reg_class_contents[ALL_REGS];
+      classes_ptr = restrict_cost_classes (classes_ptr,
+                                          PSEUDO_REGNO_MODE (regno),
+                                          *valid_regs);
+    }
   regno_cost_classes[regno] = classes_ptr;
 }
 
@@ -403,13 +411,19 @@ setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
    calculation for such important classes is only wasting CPU
    time.  */
 static void
-setup_regno_cost_classes_by_mode (int regno, enum machine_mode mode)
+setup_regno_cost_classes_by_mode (int regno, machine_mode mode)
 {
-  if (cost_classes_mode_cache[mode] == NULL)
-    cost_classes_mode_cache[mode]
-      = restrict_cost_classes (&all_cost_classes, mode,
-                              reg_class_contents[ALL_REGS]);
-  regno_cost_classes[regno] = cost_classes_mode_cache[mode];
+  if (const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno))
+    regno_cost_classes[regno] = restrict_cost_classes (&all_cost_classes,
+                                                      mode, *valid_regs);
+  else
+    {
+      if (cost_classes_mode_cache[mode] == NULL)
+       cost_classes_mode_cache[mode]
+         = restrict_cost_classes (&all_cost_classes, mode,
+                                  reg_class_contents[ALL_REGS]);
+      regno_cost_classes[regno] = cost_classes_mode_cache[mode];
+    }
 }
 
 /* Finalize info about the cost classes for each pseudo.  */
@@ -427,7 +441,7 @@ finish_regno_cost_classes (void)
    TO_P is FALSE) a register of class RCLASS in mode MODE.  X must not
    be a pseudo register.  */
 static int
-copy_cost (rtx x, enum machine_mode mode, reg_class_t rclass, bool to_p,
+copy_cost (rtx x, machine_mode mode, reg_class_t rclass, bool to_p,
           secondary_reload_info *prev_sri)
 {
   secondary_reload_info sri;
@@ -500,7 +514,7 @@ copy_cost (rtx x, enum machine_mode mode, reg_class_t rclass, bool to_p,
    the alternatives.  */
 static void
 record_reg_classes (int n_alts, int n_ops, rtx *ops,
-                   enum machine_mode *modes, const char **constraints,
+                   machine_mode *modes, const char **constraints,
                    rtx_insn *insn, enum reg_class *pref)
 {
   int alt;
@@ -536,7 +550,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          unsigned char c;
          const char *p = constraints[i];
          rtx op = ops[i];
-         enum machine_mode mode = modes[i];
+         machine_mode mode = modes[i];
          int allows_addr = 0;
          int win = 0;
 
@@ -561,7 +575,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
            p++;
 
-         if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
+         if (p[0] >= '0' && p[0] <= '0' + i)
            {
              /* Copy class and whether memory is allowed from the
                 matching alternative.  Then perform any needed cost
@@ -726,14 +740,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                      && ! find_reg_note (insn, REG_DEAD, op))
                    alt_cost += 2;
 
-                 /* This is in place of ordinary cost computation for
-                    this operand, so skip to the end of the
-                    alternative (should be just one character).  */
-                 while (*p && *p++ != ',')
-                   ;
-
-                 constraints[i] = p;
-                 continue;
+                 p++;
                }
            }
 
@@ -750,6 +757,10 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                  c = *++p;
                  break;
 
+               case '^':
+                 alt_cost += 2;
+                 break;
+
                case '?':
                  alt_cost += 2;
                  break;
@@ -1052,7 +1063,7 @@ ok_for_index_p_nonstrict (rtx reg)
    pseudo-registers should count as OK.  Arguments as for
    regno_ok_for_base_p.  */
 static inline bool
-ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
+ok_for_base_p_nonstrict (rtx reg, machine_mode mode, addr_space_t as,
                         enum rtx_code outer_code, enum rtx_code index_code)
 {
   unsigned regno = REGNO (reg);
@@ -1075,7 +1086,7 @@ ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
    SCALE is twice the amount to multiply the cost by (it is twice so
    we can represent half-cost adjustments).  */
 static void
-record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
+record_address_regs (machine_mode mode, addr_space_t as, rtx x,
                     int context, enum rtx_code outer_code,
                     enum rtx_code index_code, int scale)
 {
@@ -1270,7 +1281,7 @@ static void
 record_operand_costs (rtx_insn *insn, enum reg_class *pref)
 {
   const char *constraints[MAX_RECOG_OPERANDS];
-  enum machine_mode modes[MAX_RECOG_OPERANDS];
+  machine_mode modes[MAX_RECOG_OPERANDS];
   rtx ops[MAX_RECOG_OPERANDS];
   rtx set;
   int i;
@@ -1355,8 +1366,6 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
 
-      dest = SET_DEST (set);
-      src = SET_SRC (set);
       if (GET_CODE (dest) == SUBREG
          && (GET_MODE_SIZE (GET_MODE (dest))
              == GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))))
@@ -1372,7 +1381,7 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
              || ((regno = REGNO (dest)) >= FIRST_PSEUDO_REGISTER
                  && (other_regno = REGNO (src)) < FIRST_PSEUDO_REGISTER)))
        {
-         enum machine_mode mode = GET_MODE (src);
+         machine_mode mode = GET_MODE (src);
          cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
          enum reg_class *cost_classes = cost_classes_ptr->classes;
          reg_class_t rclass;
@@ -1536,14 +1545,11 @@ print_allocno_costs (FILE *f)
       for (k = 0; k < cost_classes_ptr->num; k++)
        {
          rclass = cost_classes[k];
-         if (! invalid_mode_change_p (regno, (enum reg_class) rclass))
-           {
-             fprintf (f, " %s:%d", reg_class_names[rclass],
-                      COSTS (costs, i)->cost[k]);
-             if (flag_ira_region == IRA_REGION_ALL
-                 || flag_ira_region == IRA_REGION_MIXED)
-               fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
-           }
+         fprintf (f, " %s:%d", reg_class_names[rclass],
+                  COSTS (costs, i)->cost[k]);
+         if (flag_ira_region == IRA_REGION_ALL
+             || flag_ira_region == IRA_REGION_MIXED)
+           fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
        }
       fprintf (f, " MEM:%i", COSTS (costs, i)->mem_cost);
       if (flag_ira_region == IRA_REGION_ALL
@@ -1574,9 +1580,8 @@ print_pseudo_costs (FILE *f)
       for (k = 0; k < cost_classes_ptr->num; k++)
        {
          rclass = cost_classes[k];
-         if (! invalid_mode_change_p (regno, (enum reg_class) rclass))
-           fprintf (f, " %s:%d", reg_class_names[rclass],
-                    COSTS (costs, regno)->cost[k]);
+         fprintf (f, " %s:%d", reg_class_names[rclass],
+                  COSTS (costs, regno)->cost[k]);
        }
       fprintf (f, " MEM:%i\n", COSTS (costs, regno)->mem_cost);
     }
@@ -1617,7 +1622,7 @@ find_costs_and_classes (FILE *dump_file)
   int i, k, start, max_cost_classes_num;
   int pass;
   basic_block bb;
-  enum reg_class *regno_best_class;
+  enum reg_class *regno_best_class, new_class;
 
   init_recog ();
   regno_best_class
@@ -1813,10 +1818,6 @@ find_costs_and_classes (FILE *dump_file)
          for (k = 0; k < cost_classes_ptr->num; k++)
            {
              rclass = cost_classes[k];
-             /* Ignore classes that are too small or invalid for this
-                operand.  */
-             if (invalid_mode_change_p (i, (enum reg_class) rclass))
-               continue;
              if (i_costs[k] < best_cost)
                {
                  best_cost = i_costs[k];
@@ -1863,6 +1864,18 @@ find_costs_and_classes (FILE *dump_file)
              ira_assert (regno_aclass[i] != NO_REGS
                          && ira_reg_allocno_class_p[regno_aclass[i]]);
            }
+         if ((new_class
+              = (reg_class) (targetm.ira_change_pseudo_allocno_class
+                             (i, regno_aclass[i]))) != regno_aclass[i])
+           {
+             regno_aclass[i] = new_class;
+             if (hard_reg_set_subset_p (reg_class_contents[new_class],
+                                        reg_class_contents[best]))
+               best = new_class;
+             if (hard_reg_set_subset_p (reg_class_contents[new_class],
+                                        reg_class_contents[alt_class]))
+               alt_class = new_class;
+           }
          if (pass == flag_expensive_optimizations)
            {
              if (best_cost > i_mem_cost)
@@ -1906,11 +1919,7 @@ find_costs_and_classes (FILE *dump_file)
                      rclass = cost_classes[k];
                      if (! ira_class_subset_p[rclass][aclass])
                        continue;
-                     /* Ignore classes that are too small or invalid
-                        for this operand.  */
-                     if (invalid_mode_change_p (i, (enum reg_class) rclass))
-                       ;
-                     else if (total_a_costs[k] < best_cost)
+                     if (total_a_costs[k] < best_cost)
                        {
                          best_cost = total_a_costs[k];
                          allocno_cost = a_costs[k];
@@ -2039,7 +2048,7 @@ process_bb_node_for_hard_reg_moves (ira_loop_tree_node_t loop_tree_node)
       {
        int cost;
        enum reg_class hard_reg_class;
-       enum machine_mode mode;
+       machine_mode mode;
        
        mode = ALLOCNO_MODE (a);
        hard_reg_class = REGNO_REG_CLASS (hard_regno);
@@ -2249,7 +2258,7 @@ ira_tune_allocno_costs (void)
   int j, n, regno;
   int cost, min_cost, *reg_costs;
   enum reg_class aclass, rclass;
-  enum machine_mode mode;
+  machine_mode mode;
   ira_allocno_t a;
   ira_allocno_iterator ai;
   ira_allocno_object_iterator oi;
@@ -2356,3 +2365,9 @@ ira_adjust_equiv_reg_cost (unsigned regno, int cost)
   else
     regno_equiv_gains[regno] += cost;
 }
+
+void
+ira_costs_c_finalize (void)
+{
+  this_target_ira_int->free_ira_costs ();
+}