summaryrefslogtreecommitdiff
path: root/gcc/loop-invariant.c
diff options
context:
space:
mode:
authorvmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-14 16:24:11 +0000
committervmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-14 16:24:11 +0000
commite8eed2f8760fe42abb9f6228677dacd7a90271a8 (patch)
tree793540b6a00bb42653fb0e372d22502ee7bdf535 /gcc/loop-invariant.c
parentbc0ed27cfa8d09e9ea1060918377d3d2b205478e (diff)
downloadgcc-e8eed2f8760fe42abb9f6228677dacd7a90271a8.tar.gz
2009-09-26 Vladimir Makarov <vmakarov@redhat.com>
* params.def (PARAM_IRA_LOOP_RESERVED_REGS): New. * params.h (IRA_LOOP_RESERVED_REGS): New * tree-pass.h (pass_subregs_of_mode_init, pass_subregs_of_mode_finish): Remove. * passes.c (pass_subregs_of_mode_init, pass_subregs_of_mode_finish): Remove. (pass_reginfo_init): Move before loop optimizations. * config/i386/i386.h (STACK_REG_COVER_CLASS): Define. * common.opt (fira-loop-pressure): New. * toplev.h (flag_ira_loop_pressure): New. * rtl.h (init_subregs_of_mode, finish_subregs_of_mode): New externals. * reginfo.c (init_subregs_of_mode, finish_subregs_of_mode): Make external and void type functions. (gate_subregs_of_mode_init, pass_subregs_of_mode_init, pass_subregs_of_mode_finish): Remove. * ira-costs.c (init_costs): Call init_subregs_of_mode. * regmove.c: Include ira.h. (regmove_optimize): Call ira_set_pseudo_classes after IRA based register pressure calculation in loops. * loop-invariant.c: Include REGS_H and ira.h. (struct loop_data): New members max_reg_pressure, regs_ref, and regs_live. (struct invariant): New member orig_regno. (curr_loop): New variable. (find_exits): Initialize regs_ref and regs_live. (create_new_invariant): Initialize orig_regno. (get_cover_class_and_nregs): New. (get_inv_cost): Make aregs_needed an array. Use regs_needed as an array. Add code for flag_ira_loop_pressure. (gain_for_invariant): Make new_regs an array. Add code for flag_ira_loop_pressure. (best_gain_for_invariant): Ditto. (set_move_mark): New parameter gain. Use it for debugging output. (find_invariants_to_move): Make regs_needed and new_regs an array. Add code for flag_ira_loop_pressure. (move_invariant_reg): Set up orig_regno. (move_invariants): Set up reg classes for pseudos for flag_ira_loop_pressure. (free_loop_data): Clear regs_ref and regs_live. (curr_regs_live, curr_reg_pressure, regs_set, n_regs_set, get_regno_cover_class, change_pressure, mark_regno_live, mark_regno_death, mark_reg_store, mark_reg_clobber, mark_reg_death, mark_ref_regs, calculate_loop_reg_pressure): New. (move_loop_invariants): Calculate pressure. Initialize curr_loop. * ira.c (ira): Call ira_set_pseudo_classes after IRA based register pressure calculation in loops if new regs were added. Call finish_subregs_of_mode. * opts.c (decode_options): Set up flag_ira_loop_pressure. * Makefile.in (loop-invariant.o): Add ira.h. (regmove.o): Ditto. * doc/invoke.texi (-fira-loop-pressure, ira-loop-reserved-regs): Describe. * doc/tm.texi (STACK_REG_COVER_CLASS): Describe. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152770 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/loop-invariant.c')
-rw-r--r--gcc/loop-invariant.c610
1 files changed, 569 insertions, 41 deletions
diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c
index 11a8310f33e..7fb6cf05fd4 100644
--- a/gcc/loop-invariant.c
+++ b/gcc/loop-invariant.c
@@ -39,9 +39,9 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "obstack.h"
#include "basic-block.h"
#include "cfgloop.h"
@@ -54,6 +54,8 @@ along with GCC; see the file COPYING3. If not see
#include "hashtab.h"
#include "except.h"
#include "params.h"
+#include "regs.h"
+#include "ira.h"
/* The data stored for the loop. */
@@ -61,6 +63,12 @@ struct loop_data
{
struct loop *outermost_exit; /* The outermost exit of the loop. */
bool has_call; /* True if the loop contains a call. */
+ /* Maximal register pressure inside loop for given register class
+ (defined only for the cover classes). */
+ int max_reg_pressure[N_REG_CLASSES];
+ /* Loop regs referenced and live pseudo-registers. */
+ bitmap_head regs_ref;
+ bitmap_head regs_live;
};
#define LOOP_DATA(LOOP) ((struct loop_data *) (LOOP)->aux)
@@ -100,6 +108,10 @@ struct invariant
value. */
rtx reg;
+ /* If we moved the invariant out of the loop, the original regno
+ that contained its value. */
+ int orig_regno;
+
/* The definition of the invariant. */
struct def *def;
@@ -126,6 +138,9 @@ struct invariant
unsigned stamp;
};
+/* Currently processed loop. */
+static struct loop *curr_loop;
+
/* Table of invariants indexed by the df_ref uid field. */
static unsigned int invariant_table_size = 0;
@@ -615,7 +630,12 @@ find_exits (struct loop *loop, basic_block *body,
}
}
- loop->aux = xcalloc (1, sizeof (struct loop_data));
+ if (loop->aux == NULL)
+ {
+ loop->aux = xcalloc (1, sizeof (struct loop_data));
+ bitmap_initialize (&LOOP_DATA (loop)->regs_ref, &reg_obstack);
+ bitmap_initialize (&LOOP_DATA (loop)->regs_live, &reg_obstack);
+ }
LOOP_DATA (loop)->outermost_exit = outermost_exit;
LOOP_DATA (loop)->has_call = has_call;
}
@@ -696,6 +716,7 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
inv->move = false;
inv->reg = NULL_RTX;
+ inv->orig_regno = -1;
inv->stamp = 0;
inv->insn = insn;
@@ -982,14 +1003,46 @@ free_use_list (struct use *use)
}
}
+/* Return cover class and number of hard registers (through *NREGS)
+ for destination of INSN. */
+static enum reg_class
+get_cover_class_and_nregs (rtx insn, int *nregs)
+{
+ rtx reg;
+ enum reg_class cover_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;
+ cover_class = NO_REGS;
+ }
+ else
+ {
+ if (! REG_P (reg))
+ reg = NULL_RTX;
+ if (reg == NULL_RTX)
+ cover_class = GENERAL_REGS;
+ else
+ cover_class = reg_cover_class (REGNO (reg));
+ *nregs = ira_reg_class_nregs[cover_class][GET_MODE (SET_SRC (set))];
+ }
+ return cover_class;
+}
+
/* Calculates cost and number of registers needed for moving invariant INV
out of the loop and stores them to *COST and *REGS_NEEDED. */
static void
get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
{
- int acomp_cost;
- unsigned aregs_needed;
+ int i, acomp_cost;
+ unsigned aregs_needed[N_REG_CLASSES];
unsigned depno;
struct invariant *dep;
bitmap_iterator bi;
@@ -998,13 +1051,30 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
inv = VEC_index (invariant_p, invariants, inv->eqto);
*comp_cost = 0;
- *regs_needed = 0;
+ if (! flag_ira_loop_pressure)
+ regs_needed[0] = 0;
+ else
+ {
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ regs_needed[ira_reg_class_cover[i]] = 0;
+ }
+
if (inv->move
|| inv->stamp == actual_stamp)
return;
inv->stamp = actual_stamp;
- (*regs_needed)++;
+ if (! flag_ira_loop_pressure)
+ regs_needed[0]++;
+ else
+ {
+ int nregs;
+ enum reg_class cover_class;
+
+ cover_class = get_cover_class_and_nregs (inv->insn, &nregs);
+ regs_needed[cover_class] += nregs;
+ }
+
if (!inv->cheap_address
|| inv->def->n_addr_uses < inv->def->n_uses)
(*comp_cost) += inv->cost;
@@ -1029,19 +1099,35 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
on floating point constants is unlikely to ever occur. */
rtx set = single_set (inv->insn);
if (set
- && IS_STACK_MODE (GET_MODE (SET_SRC (set)))
- && constant_pool_constant_p (SET_SRC (set)))
- (*regs_needed) += 2;
+ && IS_STACK_MODE (GET_MODE (SET_SRC (set)))
+ && constant_pool_constant_p (SET_SRC (set)))
+ {
+ if (flag_ira_loop_pressure)
+ regs_needed[STACK_REG_COVER_CLASS] += 2;
+ else
+ regs_needed[0] += 2;
+ }
}
#endif
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi)
{
+ bool check_p;
+
dep = VEC_index (invariant_p, invariants, depno);
- get_inv_cost (dep, &acomp_cost, &aregs_needed);
+ get_inv_cost (dep, &acomp_cost, aregs_needed);
- if (aregs_needed
+ if (! flag_ira_loop_pressure)
+ check_p = aregs_needed[0] != 0;
+ else
+ {
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ if (aregs_needed[ira_reg_class_cover[i]] != 0)
+ break;
+ check_p = i < ira_reg_class_cover_size;
+ }
+ if (check_p
/* We need to check always_executed, since if the original value of
the invariant may be preserved, we may need to keep it in a
separate register. TODO check whether the register has an
@@ -1051,10 +1137,26 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
{
/* If this is a single use, after moving the dependency we will not
need a new register. */
- aregs_needed--;
+ if (! flag_ira_loop_pressure)
+ aregs_needed[0]--;
+ else
+ {
+ int nregs;
+ enum reg_class cover_class;
+
+ cover_class = get_cover_class_and_nregs (inv->insn, &nregs);
+ aregs_needed[cover_class] -= nregs;
+ }
}
- (*regs_needed) += aregs_needed;
+ if (! flag_ira_loop_pressure)
+ regs_needed[0] += aregs_needed[0];
+ else
+ {
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ regs_needed[ira_reg_class_cover[i]]
+ += aregs_needed[ira_reg_class_cover[i]];
+ }
(*comp_cost) += acomp_cost;
}
}
@@ -1066,15 +1168,62 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
static int
gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
- unsigned new_regs, unsigned regs_used, bool speed)
+ unsigned *new_regs, unsigned regs_used, bool speed)
{
int comp_cost, size_cost;
- get_inv_cost (inv, &comp_cost, regs_needed);
actual_stamp++;
- size_cost = (estimate_reg_pressure_cost (new_regs + *regs_needed, regs_used, speed)
- - estimate_reg_pressure_cost (new_regs, regs_used, speed));
+ get_inv_cost (inv, &comp_cost, regs_needed);
+
+ if (! flag_ira_loop_pressure)
+ {
+ size_cost = (estimate_reg_pressure_cost (new_regs[0] + regs_needed[0],
+ regs_used, speed)
+ - estimate_reg_pressure_cost (new_regs[0],
+ regs_used, speed));
+ }
+ else
+ {
+ int i;
+ enum reg_class cover_class;
+
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ {
+ cover_class = ira_reg_class_cover[i];
+ if ((int) new_regs[cover_class]
+ + (int) regs_needed[cover_class]
+ + LOOP_DATA (curr_loop)->max_reg_pressure[cover_class]
+ + IRA_LOOP_RESERVED_REGS
+ > ira_available_class_regs[cover_class])
+ break;
+ }
+ if (i < ira_reg_class_cover_size)
+ /* There will be register pressure excess and we want not to
+ make this loop invariant motion. All loop invariants with
+ non-positive gains will be rejected in function
+ find_invariants_to_move. Therefore we return the negative
+ number here.
+
+ One could think that this rejects also expensive loop
+ invariant motions and this will hurt code performance.
+ However numerous experiments with different heuristics
+ taking invariant cost into account did not confirm this
+ assumption. There are possible explanations for this
+ result:
+ o probably all expensive invariants were already moved out
+ of the loop by PRE and gimple invariant motion pass.
+ o expensive invariant execution will be hidden by insn
+ scheduling or OOO processor hardware because usually such
+ invariants have a lot of freedom to be executed
+ out-of-order.
+ Another reason for ignoring invariant cost vs spilling cost
+ heuristics is also in difficulties to evaluate accurately
+ spill cost at this stage. */
+ return -1;
+ else
+ size_cost = 0;
+ }
return comp_cost - size_cost;
}
@@ -1087,11 +1236,11 @@ gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
static int
best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
- unsigned new_regs, unsigned regs_used, bool speed)
+ unsigned *new_regs, unsigned regs_used, bool speed)
{
struct invariant *inv;
- int gain = 0, again;
- unsigned aregs_needed, invno;
+ int i, gain = 0, again;
+ unsigned aregs_needed[N_REG_CLASSES], invno;
for (invno = 0; VEC_iterate (invariant_p, invariants, invno, inv); invno++)
{
@@ -1102,13 +1251,20 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
if (inv->eqto != inv->invno)
continue;
- again = gain_for_invariant (inv, &aregs_needed, new_regs, regs_used,
+ again = gain_for_invariant (inv, aregs_needed, new_regs, regs_used,
speed);
if (again > gain)
{
gain = again;
*best = inv;
- *regs_needed = aregs_needed;
+ if (! flag_ira_loop_pressure)
+ regs_needed[0] = aregs_needed[0];
+ else
+ {
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ regs_needed[ira_reg_class_cover[i]]
+ = aregs_needed[ira_reg_class_cover[i]];
+ }
}
}
@@ -1118,7 +1274,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
/* Marks invariant INVNO and all its dependencies for moving. */
static void
-set_move_mark (unsigned invno)
+set_move_mark (unsigned invno, int gain)
{
struct invariant *inv = VEC_index (invariant_p, invariants, invno);
bitmap_iterator bi;
@@ -1131,11 +1287,18 @@ set_move_mark (unsigned invno)
inv->move = true;
if (dump_file)
- fprintf (dump_file, "Decided to move invariant %d\n", invno);
+ {
+ if (gain >= 0)
+ fprintf (dump_file, "Decided to move invariant %d -- gain %d\n",
+ invno, gain);
+ else
+ fprintf (dump_file, "Decided to move dependent invariant %d\n",
+ invno);
+ };
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, invno, bi)
{
- set_move_mark (invno);
+ set_move_mark (invno, -1);
}
}
@@ -1144,32 +1307,54 @@ set_move_mark (unsigned invno)
static void
find_invariants_to_move (bool speed)
{
- unsigned i, regs_used, regs_needed = 0, new_regs;
+ int gain;
+ unsigned i, regs_used, regs_needed[N_REG_CLASSES], new_regs[N_REG_CLASSES];
struct invariant *inv = NULL;
- unsigned int n_regs = DF_REG_SIZE (df);
if (!VEC_length (invariant_p, invariants))
return;
- /* We do not really do a good job in estimating number of registers used;
- we put some initial bound here to stand for induction variables etc.
- that we do not detect. */
- regs_used = 2;
-
- for (i = 0; i < n_regs; i++)
+ if (flag_ira_loop_pressure)
+ /* REGS_USED is actually never used when the flag is on. */
+ regs_used = 0;
+ else
+ /* We do not really do a good job in estimating number of
+ registers used; we put some initial bound here to stand for
+ induction variables etc. that we do not detect. */
{
- if (!DF_REGNO_FIRST_DEF (i) && DF_REGNO_LAST_USE (i))
+ unsigned int n_regs = DF_REG_SIZE (df);
+
+ regs_used = 2;
+
+ for (i = 0; i < n_regs; i++)
{
- /* This is a value that is used but not changed inside loop. */
- regs_used++;
+ if (!DF_REGNO_FIRST_DEF (i) && DF_REGNO_LAST_USE (i))
+ {
+ /* This is a value that is used but not changed inside loop. */
+ regs_used++;
+ }
}
}
- new_regs = 0;
- while (best_gain_for_invariant (&inv, &regs_needed, new_regs, regs_used, speed) > 0)
+ if (! flag_ira_loop_pressure)
+ new_regs[0] = regs_needed[0] = 0;
+ else
{
- set_move_mark (inv->invno);
- new_regs += regs_needed;
+ for (i = 0; (int) i < ira_reg_class_cover_size; i++)
+ new_regs[ira_reg_class_cover[i]] = 0;
+ }
+ while ((gain = best_gain_for_invariant (&inv, regs_needed,
+ new_regs, regs_used, speed)) > 0)
+ {
+ set_move_mark (inv->invno, gain);
+ if (! flag_ira_loop_pressure)
+ new_regs[0] += regs_needed[0];
+ else
+ {
+ for (i = 0; (int) i < ira_reg_class_cover_size; i++)
+ new_regs[ira_reg_class_cover[i]]
+ += regs_needed[ira_reg_class_cover[i]];
+ }
}
}
@@ -1186,11 +1371,13 @@ move_invariant_reg (struct loop *loop, unsigned invno)
rtx reg, set, dest, note;
struct use *use;
bitmap_iterator bi;
+ int regno;
if (inv->reg)
return true;
if (!repr->move)
return false;
+ regno = -1;
/* If this is a representative of the class of equivalent invariants,
really move the invariant. Otherwise just replace its use with
the register used for the representative. */
@@ -1211,7 +1398,12 @@ move_invariant_reg (struct loop *loop, unsigned invno)
would not be dominated by it, we may just move it (TODO). Otherwise we
need to create a temporary register. */
set = single_set (inv->insn);
- dest = SET_DEST (set);
+ reg = dest = SET_DEST (set);
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+ if (REG_P (reg))
+ regno = REGNO (reg);
+
reg = gen_reg_rtx_and_attrs (dest);
/* Try replacing the destination by a new pseudoregister. */
@@ -1237,6 +1429,7 @@ move_invariant_reg (struct loop *loop, unsigned invno)
if (!move_invariant_reg (loop, repr->invno))
goto fail;
reg = repr->reg;
+ regno = repr->orig_regno;
set = single_set (inv->insn);
emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
delete_insn (inv->insn);
@@ -1244,6 +1437,7 @@ move_invariant_reg (struct loop *loop, unsigned invno)
inv->reg = reg;
+ inv->orig_regno = regno;
/* Replace the uses we know to be dominated. It saves work for copy
propagation, and also it is necessary so that dependent invariants
@@ -1266,6 +1460,7 @@ fail:
fprintf (dump_file, "Failed to move invariant %d\n", invno);
inv->move = false;
inv->reg = NULL_RTX;
+ inv->orig_regno = -1;
return false;
}
@@ -1281,6 +1476,21 @@ move_invariants (struct loop *loop)
for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
move_invariant_reg (loop, i);
+ if (flag_ira_loop_pressure && resize_reg_info ())
+ {
+ for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
+ if (inv->reg != NULL_RTX)
+ {
+ if (inv->orig_regno >= 0)
+ setup_reg_classes (REGNO (inv->reg),
+ reg_preferred_class (inv->orig_regno),
+ reg_alternate_class (inv->orig_regno),
+ reg_cover_class (inv->orig_regno));
+ else
+ setup_reg_classes (REGNO (inv->reg),
+ GENERAL_REGS, NO_REGS, GENERAL_REGS);
+ }
+ }
}
/* Initializes invariant motion data. */
@@ -1346,10 +1556,317 @@ free_loop_data (struct loop *loop)
{
struct loop_data *data = LOOP_DATA (loop);
+ bitmap_clear (&LOOP_DATA (loop)->regs_ref);
+ bitmap_clear (&LOOP_DATA (loop)->regs_live);
free (data);
loop->aux = NULL;
}
+
+
+/* Registers currently living. */
+static bitmap_head curr_regs_live;
+
+/* Current reg pressure for each cover class. */
+static int curr_reg_pressure[N_REG_CLASSES];
+
+/* Record all regs that are set in any one insn. Communication from
+ mark_reg_{store,clobber} and global_conflicts. Asm can refer to
+ all hard-registers. */
+static rtx regs_set[(FIRST_PSEUDO_REGISTER > MAX_RECOG_OPERANDS
+ ? FIRST_PSEUDO_REGISTER : MAX_RECOG_OPERANDS) * 2];
+/* Number of regs stored in the previous array. */
+static int n_regs_set;
+
+/* Return cover class and number of needed hard registers (through
+ *NREGS) of register REGNO. */
+static enum reg_class
+get_regno_cover_class (int regno, int *nregs)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ enum reg_class cover_class = reg_cover_class (regno);
+
+ *nregs = ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)];
+ return cover_class;
+ }
+ else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)
+ && ! TEST_HARD_REG_BIT (eliminable_regset, regno))
+ {
+ *nregs = 1;
+ return ira_class_translate[REGNO_REG_CLASS (regno)];
+ }
+ else
+ {
+ *nregs = 0;
+ return NO_REGS;
+ }
+}
+
+/* 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 cover_class;
+
+ cover_class = get_regno_cover_class (regno, &nregs);
+ if (! incr_p)
+ curr_reg_pressure[cover_class] -= nregs;
+ else
+ {
+ curr_reg_pressure[cover_class] += nregs;
+ if (LOOP_DATA (curr_loop)->max_reg_pressure[cover_class]
+ < curr_reg_pressure[cover_class])
+ LOOP_DATA (curr_loop)->max_reg_pressure[cover_class]
+ = curr_reg_pressure[cover_class];
+ }
+}
+
+/* Mark REGNO birth. */
+static void
+mark_regno_live (int regno)
+{
+ struct loop *loop;
+
+ for (loop = curr_loop;
+ loop != current_loops->tree_root;
+ loop = loop_outer (loop))
+ bitmap_set_bit (&LOOP_DATA (loop)->regs_live, regno);
+ if (bitmap_bit_p (&curr_regs_live, regno))
+ return;
+ bitmap_set_bit (&curr_regs_live, regno);
+ change_pressure (regno, true);
+}
+
+/* Mark REGNO death. */
+static void
+mark_regno_death (int regno)
+{
+ if (! bitmap_bit_p (&curr_regs_live, regno))
+ return;
+ bitmap_clear_bit (&curr_regs_live, regno);
+ change_pressure (regno, false);
+}
+
+/* Mark setting register REG. */
+static void
+mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ int regno;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+
+ if (! REG_P (reg))
+ return;
+
+ regs_set[n_regs_set++] = reg;
+
+ regno = REGNO (reg);
+
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ mark_regno_live (regno);
+ else
+ {
+ int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
+
+ while (regno < last)
+ {
+ mark_regno_live (regno);
+ regno++;
+ }
+ }
+}
+
+/* Mark clobbering register REG. */
+static void
+mark_reg_clobber (rtx reg, const_rtx setter, void *data)
+{
+ if (GET_CODE (setter) == CLOBBER)
+ mark_reg_store (reg, setter, data);
+}
+
+/* Mark register REG death. */
+static void
+mark_reg_death (rtx reg)
+{
+ int regno = REGNO (reg);
+
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ mark_regno_death (regno);
+ else
+ {
+ int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
+
+ while (regno < last)
+ {
+ mark_regno_death (regno);
+ regno++;
+ }
+ }
+}
+
+/* Mark occurrence of registers in X for the current loop. */
+static void
+mark_ref_regs (rtx x)
+{
+ RTX_CODE code;
+ int i;
+ const char *fmt;
+
+ if (!x)
+ return;
+
+ code = GET_CODE (x);
+ if (code == REG)
+ {
+ struct loop *loop;
+
+ for (loop = curr_loop;
+ loop != current_loops->tree_root;
+ loop = loop_outer (loop))
+ bitmap_set_bit (&LOOP_DATA (loop)->regs_ref, REGNO (x));
+ return;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ mark_ref_regs (XEXP (x, i));
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = 0; j < XVECLEN (x, i); j++)
+ mark_ref_regs (XVECEXP (x, i, j));
+ }
+}
+
+/* Calculate register pressure in the loops. */
+static void
+calculate_loop_reg_pressure (void)
+{
+ int i;
+ unsigned int j;
+ bitmap_iterator bi;
+ basic_block bb;
+ rtx insn, link;
+ struct loop *loop, *parent;
+ loop_iterator li;
+
+ FOR_EACH_LOOP (li, loop, 0)
+ if (loop->aux == NULL)
+ {
+ loop->aux = xcalloc (1, sizeof (struct loop_data));
+ bitmap_initialize (&LOOP_DATA (loop)->regs_ref, &reg_obstack);
+ bitmap_initialize (&LOOP_DATA (loop)->regs_live, &reg_obstack);
+ }
+ ira_setup_eliminable_regset ();
+ bitmap_initialize (&curr_regs_live, &reg_obstack);
+ FOR_EACH_BB (bb)
+ {
+ curr_loop = bb->loop_father;
+ if (curr_loop == current_loops->tree_root)
+ continue;
+
+ for (loop = curr_loop;
+ loop != current_loops->tree_root;
+ loop = loop_outer (loop))
+ bitmap_ior_into (&LOOP_DATA (loop)->regs_live, DF_LR_IN (bb));
+
+ bitmap_copy (&curr_regs_live, DF_LR_IN (bb));
+ for (i = 0; i < ira_reg_class_cover_size; i++)
+ curr_reg_pressure[ira_reg_class_cover[i]] = 0;
+ EXECUTE_IF_SET_IN_BITMAP (&curr_regs_live, 0, j, bi)
+ change_pressure (j, true);
+
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (! INSN_P (insn))
+ continue;
+
+ mark_ref_regs (PATTERN (insn));
+ n_regs_set = 0;
+ note_stores (PATTERN (insn), mark_reg_clobber, NULL);
+
+ /* Mark any registers dead after INSN as dead now. */
+
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_DEAD)
+ mark_reg_death (XEXP (link, 0));
+
+ /* Mark any registers set in INSN as live,
+ and mark them as conflicting with all other live regs.
+ Clobbers are processed again, so they conflict with
+ the registers that are set. */
+
+ note_stores (PATTERN (insn), mark_reg_store, NULL);
+
+#ifdef AUTO_INC_DEC
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_INC)
+ mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
+#endif
+ while (n_regs_set-- > 0)
+ {
+ rtx note = find_regno_note (insn, REG_UNUSED,
+ REGNO (regs_set[n_regs_set]));
+ if (! note)
+ continue;
+
+ mark_reg_death (XEXP (note, 0));
+ }
+ }
+ }
+ bitmap_clear (&curr_regs_live);
+ if (flag_ira_region == IRA_REGION_MIXED
+ || flag_ira_region == IRA_REGION_ALL)
+ FOR_EACH_LOOP (li, loop, 0)
+ {
+ EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi)
+ if (! bitmap_bit_p (&LOOP_DATA (loop)->regs_ref, j))
+ {
+ enum reg_class cover_class;
+ int nregs;
+
+ cover_class = get_regno_cover_class (j, &nregs);
+ LOOP_DATA (loop)->max_reg_pressure[cover_class] -= nregs;
+ }
+ }
+ if (dump_file == NULL)
+ return;
+ FOR_EACH_LOOP (li, loop, 0)
+ {
+ parent = loop_outer (loop);
+ fprintf (dump_file, "\n Loop %d (parent %d, header bb%d, depth %d)\n",
+ loop->num, (parent == NULL ? -1 : parent->num),
+ loop->header->index, loop_depth (loop));
+ fprintf (dump_file, "\n ref. regnos:");
+ EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_ref, 0, j, bi)
+ fprintf (dump_file, " %d", j);
+ fprintf (dump_file, "\n live regnos:");
+ EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi)
+ fprintf (dump_file, " %d", j);
+ fprintf (dump_file, "\n Pressure:");
+ for (i = 0; (int) i < ira_reg_class_cover_size; i++)
+ {
+ enum reg_class cover_class;
+
+ cover_class = ira_reg_class_cover[i];
+ if (LOOP_DATA (loop)->max_reg_pressure[cover_class] == 0)
+ continue;
+ fprintf (dump_file, " %s=%d", reg_class_names[cover_class],
+ LOOP_DATA (loop)->max_reg_pressure[cover_class]);
+ }
+ fprintf (dump_file, "\n");
+ }
+}
+
+
+
/* Move the invariants out of the loops. */
void
@@ -1358,10 +1875,17 @@ move_loop_invariants (void)
struct loop *loop;
loop_iterator li;
+ if (flag_ira_loop_pressure)
+ {
+ df_analyze ();
+ ira_set_pseudo_classes (dump_file);
+ calculate_loop_reg_pressure ();
+ }
df_set_flags (DF_EQ_NOTES + DF_DEFER_INSN_RESCAN);
/* Process the loops, innermost first. */
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
+ curr_loop = loop;
/* move_single_loop_invariants for very large loops
is time consuming and might need a lot of memory. */
if (loop->num_nodes <= (unsigned) LOOP_INVARIANT_MAX_BBS_IN_LOOP)
@@ -1373,6 +1897,10 @@ move_loop_invariants (void)
free_loop_data (loop);
}
+ if (flag_ira_loop_pressure)
+ /* There is no sense to keep this info because it was most
+ probably outdated by subsequent passes. */
+ free_reg_info ();
free (invariant_table);
invariant_table = NULL;
invariant_table_size = 0;