common.opt (flag_ira_hoist_pressure): New.
authorBin Cheng <bin.cheng@arm.com>
Fri, 19 Oct 2012 05:42:24 +0000 (05:42 +0000)
committerBin Cheng <amker@gcc.gnu.org>
Fri, 19 Oct 2012 05:42:24 +0000 (05:42 +0000)
gcc/ChangeLog
* common.opt (flag_ira_hoist_pressure): New.
* doc/invoke.texi (-fira-hoist-pressure): Describe.
* ira-costs.c (ira_set_pseudo_classes): New parameter.
* ira.h: Update copyright dates.
(ira_set_pseudo_classes): Update prototype.
* haifa-sched.c (sched_init): Update call.
* ira.c (ira): Update call.
* regmove.c: Update copyright dates.
(regmove_optimize): Update call.
* loop-invariant.c: Update copyright dates.
(move_loop_invariants): Update call.
* gcse.c: (struct bb_data): New structure.
(BB_DATA): New macro.
(curr_bb, curr_reg_pressure): New static variables.
(should_hoist_expr_to_dom): Rename from hoist_expr_reaches_here_p.
Change parameter expr_index to expr.
New parameters pressure_class, nregs and hoisted_bbs.
Use reg pressure to determine the distance expr can be hoisted.
(hoist_code): Use reg pressure to direct the hoist process.
(get_regno_pressure_class, get_pressure_class_and_nregs)
(change_pressure, calculate_bb_reg_pressure): New.
(one_code_hoisting_pass): Calculate register pressure. Allocate
and free data.

gcc/testsuite/ChangeLog
* testsuite/gcc.dg/hoist-register-pressure.c: New test.

From-SVN: r192604

12 files changed:
gcc/ChangeLog
gcc/common.opt
gcc/doc/invoke.texi
gcc/gcse.c
gcc/haifa-sched.c
gcc/ira-costs.c
gcc/ira.c
gcc/ira.h
gcc/loop-invariant.c
gcc/regmove.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/hoist-register-pressure.c [new file with mode: 0644]

index 93cc988186923b83c9c6a91a1eb131f53e152fa1..9b09aaa638afdb807234b3613c4d4d1f7f40c240 100644 (file)
@@ -1,3 +1,29 @@
+2012-10-19  Bin Cheng  <bin.cheng@arm.com>
+
+       * common.opt (flag_ira_hoist_pressure): New.
+       * doc/invoke.texi (-fira-hoist-pressure): Describe.
+       * ira-costs.c (ira_set_pseudo_classes): New parameter.
+       * ira.h: Update copyright dates.
+       (ira_set_pseudo_classes): Update prototype.
+       * haifa-sched.c (sched_init): Update call.
+       * ira.c (ira): Update call.
+       * regmove.c: Update copyright dates.
+       (regmove_optimize): Update call.
+       * loop-invariant.c: Update copyright dates.
+       (move_loop_invariants): Update call.
+       * gcse.c: (struct bb_data): New structure.
+       (BB_DATA): New macro.
+       (curr_bb, curr_reg_pressure): New static variables.
+       (should_hoist_expr_to_dom): Rename from hoist_expr_reaches_here_p.
+       Change parameter expr_index to expr.
+       New parameters pressure_class, nregs and hoisted_bbs.
+       Use reg pressure to determine the distance expr can be hoisted.
+       (hoist_code): Use reg pressure to direct the hoist process.
+       (get_regno_pressure_class, get_pressure_class_and_nregs)
+       (change_pressure, calculate_bb_reg_pressure): New.
+       (one_code_hoisting_pass): Calculate register pressure. Allocate
+       and free data.
+
 2012-10-19  Bin Cheng  <bin.cheng@arm.com>
 
        * gcse.c: Update copyright dates.
index e21fb71bbd4dae511630a749552d54c9d7456bb9..5b69aff2febbd29ec3904dd2280257c5a5be6298 100644 (file)
@@ -1392,6 +1392,11 @@ Enum(ira_region) String(all) Value(IRA_REGION_ALL)
 EnumValue
 Enum(ira_region) String(mixed) Value(IRA_REGION_MIXED)
 
+fira-hoist-pressure
+Common Report Var(flag_ira_hoist_pressure) Init(1) Optimization
+Use IRA based register pressure calculation
+in RTL hoist optimizations.
+
 fira-loop-pressure
 Common Report Var(flag_ira_loop_pressure)
 Use IRA based register pressure calculation
index f8c92306c1aa2b78d34cb7f955c4a310cbae5cdf..a66dff1353fd8f540ff20cd2ad47a16263efbaf9 100644 (file)
@@ -372,7 +372,7 @@ Objective-C and Objective-C++ Dialects}.
 -finline-small-functions -fipa-cp -fipa-cp-clone @gol
 -fipa-pta -fipa-profile -fipa-pure-const -fipa-reference @gol
 -fira-algorithm=@var{algorithm} @gol
--fira-region=@var{region} @gol
+-fira-region=@var{region} -fira-hoist-pressure @gol
 -fira-loop-pressure -fno-ira-share-save-slots @gol
 -fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
 -fivopts -fkeep-inline-functions -fkeep-static-consts @gol
@@ -6996,6 +6996,14 @@ This typically results in the smallest code size, and is enabled by default for
 
 @end table
 
+@item -fira-hoist-pressure
+@opindex fira-hoist-pressure
+Use IRA to evaluate register pressure in the code hoisting pass for
+decisions to hoist expressions.  This option usually results in smaller
+code, but it can slow the compiler down.
+
+This option is enabled at level @option{-Os} for all targets.
+
 @item -fira-loop-pressure
 @opindex fira-loop-pressure
 Use IRA to evaluate register pressure in loops for decisions to move
index 94f4beb6982a42d1c0f88090f155533a9948e971..99e7685cdbab91bbb8cb97fa8a9a8b64bc70548b 100644 (file)
@@ -20,9 +20,11 @@ along with GCC; see the file COPYING3.  If not see
 
 /* TODO
    - reordering of memory allocation and freeing to be more space efficient
-   - do rough calc of how many regs are needed in each block, and a rough
-     calc of how many regs are available in each class and use that to
-     throttle back the code in cases where RTX_COST is minimal.
+   - simulate register pressure change of each basic block accurately during
+     hoist process.  But I doubt the benefit since most expressions hoisted
+     are constant or address, which usually won't reduce register pressure.
+   - calc rough register pressure information and use the info to drive all
+     kinds of code motion (including code hoisting) in a unified way.
 */
 
 /* References searched while implementing this.
@@ -141,11 +143,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "toplev.h"
 
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "tree.h"
 #include "tm_p.h"
 #include "regs.h"
-#include "hard-reg-set.h"
+#include "ira.h"
 #include "flags.h"
 #include "insn-config.h"
 #include "recog.h"
@@ -412,6 +415,22 @@ static bool doing_code_hoisting_p = false;
 /* For available exprs */
 static sbitmap *ae_kill;
 \f
+/* Data stored for each basic block.  */
+struct bb_data
+{
+  /* Maximal register pressure inside basic block for given register class
+     (defined only for the pressure classes).  */
+  int max_reg_pressure[N_REG_CLASSES];
+};
+
+#define BB_DATA(bb) ((struct bb_data *) (bb)->aux)
+
+static basic_block curr_bb;
+
+/* Current register pressure for each pressure class.  */
+static int curr_reg_pressure[N_REG_CLASSES];
+\f
+
 static void compute_can_copy (void);
 static void *gmalloc (size_t) ATTRIBUTE_MALLOC;
 static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC;
@@ -460,9 +479,11 @@ static void alloc_code_hoist_mem (int, int);
 static void free_code_hoist_mem (void);
 static void compute_code_hoist_vbeinout (void);
 static void compute_code_hoist_data (void);
-static int hoist_expr_reaches_here_p (basic_block, int, basic_block, sbitmap,
-                                     int, int *);
+static int should_hoist_expr_to_dom (basic_block, struct expr *, basic_block,
+                                    sbitmap, int, int *, enum reg_class,
+                                    int *, bitmap);
 static int hoist_code (void);
+static enum reg_class get_pressure_class_and_nregs (rtx insn, int *nregs);
 static int one_code_hoisting_pass (void);
 static rtx process_insert_insn (struct expr *);
 static int pre_edge_insert (struct edge_list *, struct expr **);
@@ -1858,7 +1879,7 @@ prune_expressions (bool pre_p)
         a basic block we should account for any side-effects of a subsequent
         jump instructions that could clobber the expression.  It would
         be best to implement this check along the lines of
-        hoist_expr_reaches_here_p where the target block is already known
+        should_hoist_expr_to_dom where the target block is already known
         and, hence, there's no need to conservatively prune expressions on
         "intermediate" set-and-jump instructions.  */
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -2826,10 +2847,21 @@ compute_code_hoist_data (void)
     fprintf (dump_file, "\n");
 }
 
-/* Determine if the expression identified by EXPR_INDEX would
-   reach BB unimpared if it was placed at the end of EXPR_BB.
-   Stop the search if the expression would need to be moved more
-   than DISTANCE instructions.
+/* Determine if the expression EXPR should be hoisted to EXPR_BB up in
+   flow graph, if it can reach BB unimpared.  Stop the search if the
+   expression would need to be moved more than DISTANCE instructions.
+
+   DISTANCE is the number of instructions through which EXPR can be
+   hoisted up in flow graph.
+
+   BB_SIZE points to an array which contains the number of instructions
+   for each basic block.
+
+   PRESSURE_CLASS and NREGS are register class and number of hard registers
+   for storing EXPR.
+
+   HOISTED_BBS points to a bitmap indicating basic blocks through which
+   EXPR is hoisted.
 
    It's unclear exactly what Muchnick meant by "unimpared".  It seems
    to me that the expression must either be computed or transparent in
@@ -2842,18 +2874,32 @@ compute_code_hoist_data (void)
    paths.  */
 
 static int
-hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb,
-                          sbitmap visited, int distance, int *bb_size)
+should_hoist_expr_to_dom (basic_block expr_bb, struct expr *expr,
+                         basic_block bb, sbitmap visited, int distance,
+                         int *bb_size, enum reg_class pressure_class,
+                         int *nregs, bitmap hoisted_bbs)
 {
+  unsigned int i;
   edge pred;
   edge_iterator ei;
+  sbitmap_iterator sbi;
   int visited_allocated_locally = 0;
 
   /* Terminate the search if distance, for which EXPR is allowed to move,
      is exhausted.  */
   if (distance > 0)
     {
-      distance -= bb_size[bb->index];
+      /* Let EXPR be hoisted through basic block at no cost if the block
+        has low register pressure.  An exception is constant expression,
+        because hoisting constant expr aggressively results in worse code.
+        The exception is made by the observation of CSiBE on ARM target,
+        while it has no obvious effect on other targets like x86, x86_64,
+        mips and powerpc.  */
+      if (!flag_ira_hoist_pressure
+         || (BB_DATA (bb)->max_reg_pressure[pressure_class]
+               >= ira_class_hard_regs_num[pressure_class]
+             || CONST_INT_P (expr->expr)))
+       distance -= bb_size[bb->index];
 
       if (distance <= 0)
        return 0;
@@ -2878,21 +2924,35 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb,
        continue;
       else if (TEST_BIT (visited, pred_bb->index))
        continue;
-
-      else if (! TEST_BIT (transp[pred_bb->index], expr_index))
+      else if (! TEST_BIT (transp[pred_bb->index], expr->bitmap_index))
        break;
-
       /* Not killed.  */
       else
        {
          SET_BIT (visited, pred_bb->index);
-         if (! hoist_expr_reaches_here_p (expr_bb, expr_index, pred_bb,
-                                          visited, distance, bb_size))
+         if (! should_hoist_expr_to_dom (expr_bb, expr, pred_bb,
+                                         visited, distance, bb_size,
+                                         pressure_class, nregs, hoisted_bbs))
            break;
        }
     }
   if (visited_allocated_locally)
-    sbitmap_free (visited);
+    {
+      /* If EXPR can be hoisted to expr_bb, record basic blocks through
+        which EXPR is hoisted in hoisted_bbs.  Also update register
+        pressure for basic blocks newly added in hoisted_bbs.  */
+      if (flag_ira_hoist_pressure && !pred)
+       {
+         EXECUTE_IF_SET_IN_SBITMAP (visited, 0, i, sbi)
+           if (!bitmap_bit_p (hoisted_bbs, i))
+             {
+               bitmap_set_bit (hoisted_bbs, i);
+               BB_DATA (BASIC_BLOCK (i))->max_reg_pressure[pressure_class]
+                   += *nregs;
+             }
+       }
+      sbitmap_free (visited);
+    }
 
   return (pred == NULL);
 }
@@ -2909,7 +2969,44 @@ find_occr_in_bb (struct occr *occr, basic_block bb)
   return occr;
 }
 
-/* Actually perform code hoisting.  */
+/* Actually perform code hoisting.
+
+   The code hoisting pass can hoist multiple computations of the same
+   expression along dominated path to a dominating basic block, like
+   from b2/b3 to b1 as depicted below:
+
+          b1      ------
+          /\         |
+         /  \        |
+        bx   by   distance
+       /      \      |
+      /        \     |
+     b2        b3 ------
+
+   Unfortunately code hoisting generally extends the live range of an
+   output pseudo register, which increases register pressure and hurts
+   register allocation.  To address this issue, an attribute MAX_DISTANCE
+   is computed and attached to each expression.  The attribute is computed
+   from rtx cost of the corresponding expression and it's used to control
+   how long the expression can be hoisted up in flow graph.  As the
+   expression is hoisted up in flow graph, GCC decreases its DISTANCE
+   and stops the hoist if DISTANCE reaches 0.
+
+   Option "-fira-hoist-pressure" implements register pressure directed
+   hoist based on upper method.  The rationale is:
+     1. Calculate register pressure for each basic block by reusing IRA
+       facility.
+     2. When expression is hoisted through one basic block, GCC checks
+       register pressure of the basic block and decrease DISTANCE only
+       when the register pressure is high.  In other words, expression
+       will be hoisted through basic block with low register pressure
+       at no cost.
+     3. Update register pressure information for basic blocks through
+       which expression is hoisted.
+       TODO: It is possible to have register pressure decreased because
+       of shrinked live ranges of input pseudo registers when hoisting
+       an expression.  For now, this effect is not simulated and we just
+       increase register pressure for hoisted expressions.  */
 
 static int
 hoist_code (void)
@@ -2918,12 +3015,18 @@ hoist_code (void)
   VEC (basic_block, heap) *dom_tree_walk;
   unsigned int dom_tree_walk_index;
   VEC (basic_block, heap) *domby;
-  unsigned int i,j;
+  unsigned int i, j, k;
   struct expr **index_map;
   struct expr *expr;
   int *to_bb_head;
   int *bb_size;
   int changed = 0;
+  struct bb_data *data;
+  /* Basic blocks that have occurrences reachable from BB.  */
+  bitmap from_bbs;
+  /* Basic blocks through which expr is hoisted.  */
+  bitmap hoisted_bbs = NULL;
+  bitmap_iterator bi;
 
   /* Compute a mapping from expression number (`bitmap_index') to
      hash table entry.  */
@@ -2961,6 +3064,10 @@ hoist_code (void)
              && (EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
                  == ENTRY_BLOCK_PTR->next_bb));
 
+  from_bbs = BITMAP_ALLOC (NULL);
+  if (flag_ira_hoist_pressure)
+    hoisted_bbs = BITMAP_ALLOC (NULL);
+
   dom_tree_walk = get_all_dominated_blocks (CDI_DOMINATORS,
                                            ENTRY_BLOCK_PTR->next_bb);
 
@@ -2979,12 +3086,12 @@ hoist_code (void)
        {
          if (TEST_BIT (hoist_vbeout[bb->index], i))
            {
+             int nregs = 0;
+             enum reg_class pressure_class = NO_REGS;
              /* Current expression.  */
              struct expr *expr = index_map[i];
              /* Number of occurrences of EXPR that can be hoisted to BB.  */
              int hoistable = 0;
-             /* Basic blocks that have occurrences reachable from BB.  */
-             bitmap_head _from_bbs, *from_bbs = &_from_bbs;
              /* Occurrences reachable from BB.  */
              VEC (occr_t, heap) *occrs_to_hoist = NULL;
              /* We want to insert the expression into BB only once, so
@@ -2992,8 +3099,6 @@ hoist_code (void)
              int insn_inserted_p;
              occr_t occr;
 
-             bitmap_initialize (from_bbs, 0);
-
              /* If an expression is computed in BB and is available at end of
                 BB, hoist all occurrences dominated by BB to BB.  */
              if (TEST_BIT (comp[bb->index], i))
@@ -3047,13 +3152,18 @@ hoist_code (void)
                    max_distance += (bb_size[dominated->index]
                                     - to_bb_head[INSN_UID (occr->insn)]);
 
-                 /* Note if the expression would reach the dominated block
-                    unimpared if it was placed at the end of BB.
+                 pressure_class = get_pressure_class_and_nregs (occr->insn,
+                                                                &nregs);
+
+                 /* Note if the expression should be hoisted from the dominated
+                    block to BB if it can reach DOMINATED unimpared.
 
                     Keep track of how many times this expression is hoistable
                     from a dominated block into BB.  */
-                 if (hoist_expr_reaches_here_p (bb, i, dominated, NULL,
-                                                max_distance, bb_size))
+                 if (should_hoist_expr_to_dom (bb, expr, dominated, NULL,
+                                               max_distance, bb_size,
+                                               pressure_class, &nregs,
+                                               hoisted_bbs))
                    {
                      hoistable++;
                      VEC_safe_push (occr_t, heap,
@@ -3094,6 +3204,28 @@ hoist_code (void)
                /* Punt, no point hoisting a single occurence.  */
                VEC_free (occr_t, heap, occrs_to_hoist);
 
+             if (flag_ira_hoist_pressure
+                 && !VEC_empty (occr_t, occrs_to_hoist))
+               {
+                 /* Update register pressure for basic block to which expr
+                    is hoisted.  */
+                 data = BB_DATA (bb);
+                 data->max_reg_pressure[pressure_class] += nregs;
+               }
+             else if (flag_ira_hoist_pressure)
+               {
+                 /* Restore register pressure of basic block recorded in
+                    hoisted_bbs when expr will not be hoisted.  */
+                 EXECUTE_IF_SET_IN_BITMAP (hoisted_bbs, 0, k, bi)
+                   {
+                     data = BB_DATA (BASIC_BLOCK (k));
+                     data->max_reg_pressure[pressure_class] -= nregs;
+                   }
+               }
+
+             if (flag_ira_hoist_pressure)
+               bitmap_clear (hoisted_bbs);
+
              insn_inserted_p = 0;
 
              /* Walk through occurrences of I'th expressions we want
@@ -3142,6 +3274,10 @@ hoist_code (void)
     }
 
   VEC_free (basic_block, heap, dom_tree_walk);
+  BITMAP_FREE (from_bbs);
+  if (flag_ira_hoist_pressure)
+    BITMAP_FREE (hoisted_bbs);
+
   free (bb_size);
   free (to_bb_head);
   free (index_map);
@@ -3149,6 +3285,165 @@ hoist_code (void)
   return changed;
 }
 
+/* Return pressure class and number of needed hard registers (through
+   *NREGS) of register REGNO.  */
+static enum reg_class
+get_regno_pressure_class (int regno, int *nregs)
+{
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      enum reg_class pressure_class;
+
+      pressure_class = reg_allocno_class (regno);
+      pressure_class = ira_pressure_class_translate[pressure_class];
+      *nregs
+       = ira_reg_class_max_nregs[pressure_class][PSEUDO_REGNO_MODE (regno)];
+      return pressure_class;
+    }
+  else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)
+          && ! TEST_HARD_REG_BIT (eliminable_regset, regno))
+    {
+      *nregs = 1;
+      return ira_pressure_class_translate[REGNO_REG_CLASS (regno)];
+    }
+  else
+    {
+      *nregs = 0;
+      return NO_REGS;
+    }
+}
+
+/* Return pressure class and number of hard registers (through *NREGS)
+   for destination of INSN. */
+static enum reg_class
+get_pressure_class_and_nregs (rtx insn, int *nregs)
+{
+  rtx reg;
+  enum reg_class pressure_class;
+  rtx set = single_set (insn);
+
+  /* Considered invariant insns have only one set.  */
+  gcc_assert (set != NULL_RTX);
+  reg = SET_DEST (set);
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+  if (MEM_P (reg))
+    {
+      *nregs = 0;
+      pressure_class = NO_REGS;
+    }
+  else
+    {
+      gcc_assert (REG_P (reg));
+      pressure_class = reg_allocno_class (REGNO (reg));
+      pressure_class = ira_pressure_class_translate[pressure_class];
+      *nregs
+       = ira_reg_class_max_nregs[pressure_class][GET_MODE (SET_SRC (set))];
+    }
+  return pressure_class;
+}
+
+/* Increase (if INCR_P) or decrease current register pressure for
+   register REGNO.  */
+static void
+change_pressure (int regno, bool incr_p)
+{
+  int nregs;
+  enum reg_class pressure_class;
+
+  pressure_class = get_regno_pressure_class (regno, &nregs);
+  if (! incr_p)
+    curr_reg_pressure[pressure_class] -= nregs;
+  else
+    {
+      curr_reg_pressure[pressure_class] += nregs;
+      if (BB_DATA (curr_bb)->max_reg_pressure[pressure_class]
+         < curr_reg_pressure[pressure_class])
+       BB_DATA (curr_bb)->max_reg_pressure[pressure_class]
+         = curr_reg_pressure[pressure_class];
+    }
+}
+
+/* Calculate register pressure for each basic block by walking insns
+   from last to first.  */
+static void
+calculate_bb_reg_pressure (void)
+{
+  int i;
+  unsigned int j;
+  rtx insn;
+  basic_block bb;
+  bitmap curr_regs_live;
+  bitmap_iterator bi;
+
+
+  ira_setup_eliminable_regset ();
+  curr_regs_live = BITMAP_ALLOC (&reg_obstack);
+  FOR_EACH_BB (bb)
+    {
+      curr_bb = bb;
+      bitmap_copy (curr_regs_live, DF_LR_OUT (bb));
+      for (i = 0; i < ira_pressure_classes_num; i++)
+       curr_reg_pressure[ira_pressure_classes[i]] = 0;
+      EXECUTE_IF_SET_IN_BITMAP (curr_regs_live, 0, j, bi)
+       change_pressure (j, true);
+
+      FOR_BB_INSNS_REVERSE (bb, insn)
+       {
+         rtx dreg;
+         int regno;
+         df_ref *def_rec, *use_rec;
+
+         if (! NONDEBUG_INSN_P (insn))
+           continue;
+
+         for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+           {
+             dreg = DF_REF_REAL_REG (*def_rec);
+             gcc_assert (REG_P (dreg));
+             regno = REGNO (dreg);
+             if (!(DF_REF_FLAGS (*def_rec) 
+                   & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+               {
+                 if (bitmap_clear_bit (curr_regs_live, regno))
+                   change_pressure (regno, false);
+               }
+           }
+
+         for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+           {
+             dreg = DF_REF_REAL_REG (*use_rec);
+             gcc_assert (REG_P (dreg));
+             regno = REGNO (dreg);
+             if (bitmap_set_bit (curr_regs_live, regno))
+               change_pressure (regno, true);
+           }
+       }
+    }
+  BITMAP_FREE (curr_regs_live);
+
+  if (dump_file == NULL)
+    return;
+
+  fprintf (dump_file, "\nRegister Pressure: \n");
+  FOR_EACH_BB (bb)
+    {
+      fprintf (dump_file, "  Basic block %d: \n", bb->index);
+      for (i = 0; (int) i < ira_pressure_classes_num; i++)
+       {
+         enum reg_class pressure_class;
+
+         pressure_class = ira_pressure_classes[i];
+         if (BB_DATA (bb)->max_reg_pressure[pressure_class] == 0)
+           continue;
+
+         fprintf (dump_file, "    %s=%d\n", reg_class_names[pressure_class],
+                  BB_DATA (bb)->max_reg_pressure[pressure_class]);
+       }
+    }
+  fprintf (dump_file, "\n");
+}
+
 /* Top level routine to perform one code hoisting (aka unification) pass
 
    Return nonzero if a change was made.  */
@@ -3168,6 +3463,16 @@ one_code_hoisting_pass (void)
 
   doing_code_hoisting_p = true;
 
+  /* Calculate register pressure for each basic block.  */
+  if (flag_ira_hoist_pressure)
+    {
+      regstat_init_n_sets_and_refs ();
+      ira_set_pseudo_classes (false, dump_file);
+      alloc_aux_for_blocks (sizeof (struct bb_data));
+      calculate_bb_reg_pressure ();
+      regstat_free_n_sets_and_refs ();
+    }
+
   /* We need alias.  */
   init_alias_analysis ();
 
@@ -3188,6 +3493,11 @@ one_code_hoisting_pass (void)
       free_code_hoist_mem ();
     }
 
+  if (flag_ira_hoist_pressure)
+    {
+      free_aux_for_blocks ();
+      free_reg_info ();
+    }
   free_hash_table (&expr_hash_table);
   free_gcse_mem ();
   obstack_free (&gcse_obstack, NULL);
index f45caf48771c514388e3c7ac340ad299de2b133c..838d3a5161d8c45f84e6cd6c8d46aad5d9866db0 100644 (file)
@@ -6633,7 +6633,7 @@ sched_init (void)
        /* We need info about pseudos for rtl dumps about pseudo
           classes and costs.  */
        regstat_init_n_sets_and_refs ();
-      ira_set_pseudo_classes (sched_verbose ? sched_dump : NULL);
+      ira_set_pseudo_classes (true, sched_verbose ? sched_dump : NULL);
       sched_regno_pressure_class
        = (enum reg_class *) xmalloc (max_regno * sizeof (enum reg_class));
       for (i = 0; i < max_regno; i++)
index 0c59b03ded225cc878ffa79ce615684303e88408..034eff831ed8b613089fec83a32fa0fce5c69fc1 100644 (file)
@@ -2048,9 +2048,10 @@ ira_costs (void)
   ira_free (total_allocno_costs);
 }
 
-/* Entry function which defines classes for pseudos.  */
+/* Entry function which defines classes for pseudos.
+   Set pseudo_classes_defined_p only if DEFINE_PSEUDO_CLASSES is true.  */
 void
-ira_set_pseudo_classes (FILE *dump_file)
+ira_set_pseudo_classes (bool define_pseudo_classes, FILE *dump_file)
 {
   allocno_p = false;
   internal_flag_ira_verbose = flag_ira_verbose;
@@ -2059,7 +2060,9 @@ ira_set_pseudo_classes (FILE *dump_file)
   initiate_regno_cost_classes ();
   find_costs_and_classes (dump_file);
   finish_regno_cost_classes ();
-  pseudo_classes_defined_p = true;
+  if (define_pseudo_classes)
+    pseudo_classes_defined_p = true;
+
   finish_costs ();
 }
 
index a79a0dcdff3d52dac1ccd675553e27405ead3482..78b3f92db00fb4173ce14649b0fcd6e65ecf7244 100644 (file)
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -4186,7 +4186,7 @@ ira (FILE *f)
   crtl->is_leaf = leaf_function_p ();
 
   if (resize_reg_info () && flag_ira_loop_pressure)
-    ira_set_pseudo_classes (ira_dump_file);
+    ira_set_pseudo_classes (true, ira_dump_file);
 
   rebuild_p = update_equiv_regs ();
 
index 6870c4bf3039e570065f77137d689511825b94f2..0cafdf4a94cccd999bd04ff3ea71c735585dc11a 100644 (file)
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -1,6 +1,6 @@
 /* Communication between the Integrated Register Allocator (IRA) and
    the rest of the compiler.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012
    Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
@@ -131,7 +131,7 @@ extern void ira_init (void);
 extern void ira_finish_once (void);
 extern void ira_setup_eliminable_regset (void);
 extern rtx ira_eliminate_regs (rtx, enum machine_mode);
-extern void ira_set_pseudo_classes (FILE *);
+extern void ira_set_pseudo_classes (bool, FILE *);
 extern void ira_implicitly_set_insn_hard_regs (HARD_REG_SET *);
 
 extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
index 854b41c2ed6297ea4196091a7c9cd29e294e8c33..996e6e3a645442cdb9bb0ab20be33a28a3f101a1 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL-level loop invariant motion.
-   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -1939,7 +1939,7 @@ move_loop_invariants (void)
     {
       df_analyze ();
       regstat_init_n_sets_and_refs ();
-      ira_set_pseudo_classes (dump_file);
+      ira_set_pseudo_classes (true, dump_file);
       calculate_loop_reg_pressure ();
       regstat_free_n_sets_and_refs ();
     }
index 6ff8ef6191c5d0f4ccf456e383b1b004196524e8..408366d9d2b4e13f8e694c5063be43c194d9c926 100644 (file)
@@ -1,6 +1,7 @@
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -1237,7 +1238,7 @@ regmove_optimize (void)
   regstat_compute_ri ();
 
   if (flag_ira_loop_pressure)
-    ira_set_pseudo_classes (dump_file);
+    ira_set_pseudo_classes (true, dump_file);
 
   regno_src_regno = XNEWVEC (int, nregs);
   for (i = nregs; --i >= 0; )
index 31f487ed130623eee9f2c48485689cd6df5916c6..57d4383f1746f4da765de51566c1d55ba19b5210 100644 (file)
@@ -1,3 +1,7 @@
+2012-10-19  Bin Cheng  <bin.cheng@arm.com>
+
+       * testsuite/gcc.dg/hoist-register-pressure.c: New test.
+
 2012-10-18  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/54501
diff --git a/gcc/testsuite/gcc.dg/hoist-register-pressure.c b/gcc/testsuite/gcc.dg/hoist-register-pressure.c
new file mode 100644 (file)
index 0000000..6077f1e
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-options "-Os -fdump-rtl-hoist" }  */
+/* { dg-final { scan-rtl-dump "PRE/HOIST: end of bb .* copying expression" "hoist" } } */
+
+#define BUF 100
+int a[BUF];
+
+void com (int);
+void bar (int);
+
+int foo (int x, int y, int z)
+{
+  /* "x+y" won't be hoisted if "-fira-hoist-pressure" is disabled,
+     because its rtx_cost is too small.  */
+  if (z)
+    {
+      a[1] = a[0] + a[2];
+      a[2] = a[1] + a[3];
+      a[3] = a[2] + a[4];
+      a[4] = a[3] + a[5];
+      a[5] = a[4] + a[6];
+      a[6] = a[5] + a[7];
+      a[7] = a[6] + a[8];
+      com (x+y);
+    }
+  else
+    {
+      bar (x+y);
+    }
+
+  return 0;
+}