summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog57
-rw-r--r--gcc/Makefile.in8
-rw-r--r--gcc/common.opt5
-rw-r--r--gcc/config/i386/i386.h3
-rw-r--r--gcc/doc/invoke.texi22
-rw-r--r--gcc/doc/tm.texi5
-rw-r--r--gcc/ira-costs.c1
-rw-r--r--gcc/ira.c6
-rw-r--r--gcc/loop-invariant.c610
-rw-r--r--gcc/opts.c1
-rw-r--r--gcc/params.def5
-rw-r--r--gcc/params.h2
-rw-r--r--gcc/passes.c4
-rw-r--r--gcc/reginfo.c69
-rw-r--r--gcc/regmove.c6
-rw-r--r--gcc/rtl.h2
-rw-r--r--gcc/toplev.h1
-rw-r--r--gcc/tree-pass.h2
18 files changed, 695 insertions, 114 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index db71cc76214..79906edfcc3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,60 @@
+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.
+
2009-10-14 Richard Guenther <rguenther@suse.de>
* lto-symtab.c (lto_symtab_compatible): Fold in ...
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 34cba739a25..3d24ac35ca3 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3076,9 +3076,9 @@ loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
output.h intl.h $(TOPLEV_H) $(DF_H) $(HASHTAB_H)
loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
- $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) $(RECOG_H) coretypes.h \
- $(TM_H) $(TM_P_H) $(FUNCTION_H) $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h \
- $(HASHTAB_H) $(EXCEPT_H) $(PARAMS_H)
+ $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) $(RECOG_H) \
+ coretypes.h $(TM_H) $(TM_P_H) $(FUNCTION_H) $(FLAGS_H) $(DF_H) \
+ $(OBSTACK_H) output.h $(HASHTAB_H) $(EXCEPT_H) $(PARAMS_H) $(REGS_H) ira.h
cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) output.h \
coretypes.h $(TM_H) cfghooks.h $(OBSTACK_H) $(TREE_FLOW_H)
@@ -3192,7 +3192,7 @@ ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H)\
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
- $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(EXCEPT_H) reload.h
+ $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(EXCEPT_H) ira.h reload.h
combine-stack-adj.o : combine-stack-adj.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(RTL_H) insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) \
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
diff --git a/gcc/common.opt b/gcc/common.opt
index dd2d8155c5e..b57234a92ab 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -717,6 +717,11 @@ fira-coalesce
Common Report Var(flag_ira_coalesce) Init(0)
Do optimistic coalescing.
+fira-loop-pressure
+Common Report Var(flag_ira_loop_pressure)
+Use IRA based register pressure calculation
+in RTL loop optimizations.
+
fira-share-save-slots
Common Report Var(flag_ira_share_save_slots) Init(1)
Share slots for saving different hard registers.
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 8d525727eec..33a50771471 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -873,6 +873,9 @@ enum target_cpu_default
|| ((MODE) == DFmode && (!TARGET_SSE2 || !TARGET_SSE_MATH)) \
|| (MODE) == XFmode)
+/* Cover class containing the stack registers. */
+#define STACK_REG_COVER_CLASS FLOAT_REGS
+
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
from 0 to just below FIRST_PSEUDO_REGISTER.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3f131fd02b4..ddcde711c20 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -346,7 +346,8 @@ Objective-C and Objective-C++ Dialects}.
-finline-small-functions -fipa-cp -fipa-cp-clone -fipa-matrix-reorg -fipa-pta @gol
-fipa-pure-const -fipa-reference -fipa-struct-reorg @gol
-fipa-type-escape -fira-algorithm=@var{algorithm} @gol
--fira-region=@var{region} -fira-coalesce -fno-ira-share-save-slots @gol
+-fira-region=@var{region} -fira-coalesce @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
-floop-block -floop-interchange -floop-strip-mine -fgraphite-identity @gol
@@ -5719,7 +5720,8 @@ invoking @option{-O2} on programs that use computed gotos.
Optimize yet more. @option{-O3} turns on all optimizations specified
by @option{-O2} and also turns on the @option{-finline-functions},
@option{-funswitch-loops}, @option{-fpredictive-commoning},
-@option{-fgcse-after-reload} and @option{-ftree-vectorize} options.
+@option{-fgcse-after-reload}, @option{-ftree-vectorize} and
+@option{-fira-loop-pressure} options.
@item -O0
@opindex O0
@@ -6216,6 +6218,14 @@ give the best results in most cases and for most architectures.
Do optimistic register coalescing. This option might be profitable for
architectures with big regular register files.
+@item -fira-loop-pressure
+@opindex fira-loop-pressure
+Use IRA to evaluate register pressure in loops for decision to move
+loop invariants. Usage of this option usually results in generation
+of faster and smaller code but can slow compiler down.
+
+This option is enabled at level @option{-O3}.
+
@item -fno-ira-share-save-slots
@opindex fno-ira-share-save-slots
Switch off sharing stack slots used for saving call used hard
@@ -8387,6 +8397,14 @@ lower quality register allocation algorithm will be used. The
algorithm do not use pseudo-register conflicts. The default value of
the parameter is 2000.
+@item ira-loop-reserved-regs
+IRA can be used to evaluate more accurate register pressure in loops
+for decision to move loop invariants (see @option{-O3}). The number
+of available registers reserved for some other purposes is described
+by this parameter. The default value of the parameter is 2 which is
+minimal number of registers needed for execution of typical
+instruction. This value is the best found from numerous experiments.
+
@item loop-invariant-max-bbs-in-loop
Loop invariant motion can be very expensive, both in compile time and
in amount of needed compile time memory, with very large loops. Loops
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 8588852bec9..57e2b76fa50 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2349,6 +2349,11 @@ with it, as well as defining these macros.
Define this if the machine has any stack-like registers.
@end defmac
+@defmac STACK_REG_COVER_CLASS
+This is a cover class containing the stack registers. Define this if
+the machine has any stack-like registers.
+@end defmac
+
@defmac FIRST_STACK_REG
The number of the first stack-like register. This one is the top
of the stack.
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index fd756f6de73..4b9d29f1db1 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -1665,6 +1665,7 @@ ira_finish_costs_once (void)
static void
init_costs (void)
{
+ init_subregs_of_mode ();
costs = (struct costs *) ira_allocate (max_struct_costs_size
* cost_elements_num);
pref_buffer
diff --git a/gcc/ira.c b/gcc/ira.c
index b960f769534..962d0994c36 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3132,6 +3132,9 @@ ira (FILE *f)
epilogue thus changing register elimination offsets. */
current_function_is_leaf = leaf_function_p ();
+ if (resize_reg_info () && flag_ira_loop_pressure)
+ ira_set_pseudo_classes (ira_dump_file);
+
rebuild_p = update_equiv_regs ();
#ifndef IRA_NO_OBSTACK
@@ -3158,7 +3161,6 @@ ira (FILE *f)
}
max_regno_before_ira = allocated_reg_info_size = max_reg_num ();
- resize_reg_info ();
ira_setup_eliminable_regset ();
ira_overall_cost = ira_reg_cost = ira_mem_cost = 0;
@@ -3272,6 +3274,8 @@ ira (FILE *f)
reload_completed = !reload (get_insns (), ira_conflicts_p);
+ finish_subregs_of_mode ();
+
timevar_pop (TV_RELOAD);
timevar_push (TV_IRA);
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;
diff --git a/gcc/opts.c b/gcc/opts.c
index 51a0cb95419..c69a399768f 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -917,6 +917,7 @@ decode_options (unsigned int argc, const char **argv)
flag_ipa_cp_clone = opt3;
if (flag_ipa_cp_clone)
flag_ipa_cp = 1;
+ flag_ira_loop_pressure = opt3;
/* Just -O1/-O0 optimizations. */
opt1_max = (optimize <= 1);
diff --git a/gcc/params.def b/gcc/params.def
index 051398573e6..21cfbdc7fec 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -719,6 +719,11 @@ DEFPARAM (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE,
"max size of conflict table in MB",
1000, 0, 0)
+DEFPARAM (PARAM_IRA_LOOP_RESERVED_REGS,
+ "ira-loop-reserved-regs",
+ "The number of registers in each class kept unused by loop invariant motion",
+ 2, 0, 0)
+
/* Switch initialization conversion will refuse to create arrays that are
bigger than this parameter times the number of switch branches. */
diff --git a/gcc/params.h b/gcc/params.h
index 67a7a05c3de..56db145e1f6 100644
--- a/gcc/params.h
+++ b/gcc/params.h
@@ -160,6 +160,8 @@ typedef enum compiler_param
PARAM_VALUE (PARAM_IRA_MAX_LOOPS_NUM)
#define IRA_MAX_CONFLICT_TABLE_SIZE \
PARAM_VALUE (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE)
+#define IRA_LOOP_RESERVED_REGS \
+ PARAM_VALUE (PARAM_IRA_LOOP_RESERVED_REGS)
#define SWITCH_CONVERSION_BRANCH_RATIO \
PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO)
#define LOOP_INVARIANT_MAX_BBS_IN_LOOP \
diff --git a/gcc/passes.c b/gcc/passes.c
index 5a472156aa2..2d11c1f6987 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -943,6 +943,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_rtl_store_motion);
NEXT_PASS (pass_cse_after_global_opts);
NEXT_PASS (pass_rtl_ifcvt);
+ NEXT_PASS (pass_reginfo_init);
/* Perform loop optimizations. It might be better to do them a bit
sooner, but we want the profile feedback to work more
efficiently. */
@@ -962,7 +963,6 @@ init_optimization_passes (void)
NEXT_PASS (pass_cse2);
NEXT_PASS (pass_rtl_dse1);
NEXT_PASS (pass_rtl_fwprop_addr);
- NEXT_PASS (pass_reginfo_init);
NEXT_PASS (pass_inc_dec);
NEXT_PASS (pass_initialize_regs);
NEXT_PASS (pass_ud_rtl_dce);
@@ -978,10 +978,8 @@ init_optimization_passes (void)
NEXT_PASS (pass_mode_switching);
NEXT_PASS (pass_match_asm_constraints);
NEXT_PASS (pass_sms);
- NEXT_PASS (pass_subregs_of_mode_init);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_ira);
- NEXT_PASS (pass_subregs_of_mode_finish);
NEXT_PASS (pass_postreload);
{
struct opt_pass **p = &pass_postreload.pass.sub;
diff --git a/gcc/reginfo.c b/gcc/reginfo.c
index 0f11c91a3de..96e9bd9437a 100644
--- a/gcc/reginfo.c
+++ b/gcc/reginfo.c
@@ -904,6 +904,9 @@ struct reg_pref
run. */
static struct reg_pref *reg_pref;
+/* Current size of reg_info. */
+static int reg_info_size;
+
/* Return the reg_class in which pseudo reg number REGNO is best allocated.
This function is sometimes called before the info has been computed.
When that happens, just return GENERAL_REGS, which is innocuous. */
@@ -937,9 +940,6 @@ reg_cover_class (int regno)
-/* Current size of reg_info. */
-static int reg_info_size;
-
/* Allocate space for reg info. */
static void
allocate_reg_info (void)
@@ -1040,6 +1040,7 @@ setup_reg_classes (int regno,
{
if (reg_pref == NULL)
return;
+ gcc_assert (reg_info_size == max_reg_num ());
reg_pref[regno].prefclass = prefclass;
reg_pref[regno].altclass = altclass;
reg_pref[regno].coverclass = coverclass;
@@ -1321,7 +1322,7 @@ find_subregs_of_mode (rtx x)
}
}
-static unsigned int
+void
init_subregs_of_mode (void)
{
basic_block bb;
@@ -1336,8 +1337,6 @@ init_subregs_of_mode (void)
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
find_subregs_of_mode (PATTERN (insn));
-
- return 0;
}
/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
@@ -1367,74 +1366,22 @@ invalid_mode_change_p (unsigned int regno,
return false;
}
-static unsigned int
+void
finish_subregs_of_mode (void)
{
htab_delete (subregs_of_mode);
subregs_of_mode = 0;
- return 0;
}
#else
-static unsigned int
+void
init_subregs_of_mode (void)
{
- return 0;
}
-static unsigned int
+void
finish_subregs_of_mode (void)
{
- return 0;
}
#endif /* CANNOT_CHANGE_MODE_CLASS */
-static bool
-gate_subregs_of_mode_init (void)
-{
-#ifdef CANNOT_CHANGE_MODE_CLASS
- return true;
-#else
- return false;
-#endif
-}
-
-struct rtl_opt_pass pass_subregs_of_mode_init =
-{
- {
- RTL_PASS,
- "subregs_of_mode_init", /* name */
- gate_subregs_of_mode_init, /* gate */
- init_subregs_of_mode, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
-
-struct rtl_opt_pass pass_subregs_of_mode_finish =
-{
- {
- RTL_PASS,
- "subregs_of_mode_finish", /* name */
- gate_subregs_of_mode_init, /* gate */
- finish_subregs_of_mode, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
-
-
#include "gt-reginfo.h"
diff --git a/gcc/regmove.c b/gcc/regmove.c
index a411183c550..4d45d5d1beb 100644
--- a/gcc/regmove.c
+++ b/gcc/regmove.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "tree-pass.h"
#include "df.h"
+#include "ira.h"
static int optimize_reg_copy_1 (rtx, rtx, rtx);
static void optimize_reg_copy_2 (rtx, rtx, rtx);
@@ -1226,6 +1227,9 @@ regmove_optimize (void)
df_note_add_problem ();
df_analyze ();
+ if (flag_ira_loop_pressure)
+ ira_set_pseudo_classes (dump_file);
+
regstat_init_n_sets_and_refs ();
regstat_compute_ri ();
@@ -1248,6 +1252,8 @@ regmove_optimize (void)
}
regstat_free_n_sets_and_refs ();
regstat_free_ri ();
+ if (flag_ira_loop_pressure)
+ free_reg_info ();
return 0;
}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index d5dbd1eb5f1..68cd4665c5f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1930,6 +1930,8 @@ extern void init_move_cost (enum machine_mode);
extern bool resize_reg_info (void);
/* Free up register info memory. */
extern void free_reg_info (void);
+extern void init_subregs_of_mode (void);
+extern void finish_subregs_of_mode (void);
/* recog.c */
extern rtx extract_asm_operands (rtx);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index cca68675f87..88ab7e8ecf0 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -142,6 +142,7 @@ extern int flag_unroll_all_loops;
extern int flag_unswitch_loops;
extern int flag_cprop_registers;
extern int time_report;
+extern int flag_ira_loop_pressure;
extern int flag_ira_coalesce;
extern int flag_ira_move_spills;
extern int flag_ira_share_save_slots;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index b829cee08b3..8b8b3c4816f 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -497,8 +497,6 @@ extern struct rtl_opt_pass pass_cse2;
extern struct rtl_opt_pass pass_df_initialize_opt;
extern struct rtl_opt_pass pass_df_initialize_no_opt;
extern struct rtl_opt_pass pass_reginfo_init;
-extern struct rtl_opt_pass pass_subregs_of_mode_init;
-extern struct rtl_opt_pass pass_subregs_of_mode_finish;
extern struct rtl_opt_pass pass_inc_dec;
extern struct rtl_opt_pass pass_stack_ptr_mod;
extern struct rtl_opt_pass pass_initialize_regs;