diff options
author | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-10-14 16:24:11 +0000 |
---|---|---|
committer | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-10-14 16:24:11 +0000 |
commit | e8eed2f8760fe42abb9f6228677dacd7a90271a8 (patch) | |
tree | 793540b6a00bb42653fb0e372d22502ee7bdf535 /gcc/loop-invariant.c | |
parent | bc0ed27cfa8d09e9ea1060918377d3d2b205478e (diff) | |
download | gcc-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.c | 610 |
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, ®_obstack); + bitmap_initialize (&LOOP_DATA (loop)->regs_live, ®_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, ®s_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, ®_obstack); + bitmap_initialize (&LOOP_DATA (loop)->regs_live, ®_obstack); + } + ira_setup_eliminable_regset (); + bitmap_initialize (&curr_regs_live, ®_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; |