diff options
author | Vladimir Makarov <vmakarov@redhat.com> | 2012-10-23 15:51:41 +0000 |
---|---|---|
committer | Vladimir Makarov <vmakarov@gcc.gnu.org> | 2012-10-23 15:51:41 +0000 |
commit | 55a2c3226a3e90a6d65f19710bab1ac377054234 (patch) | |
tree | 915ce489d01a05653371ff4f7770258ffacab1b4 /gcc/lra-lives.c | |
parent | 6acf25e4b380e5ad738ffe2830a71635bc5230d1 (diff) | |
download | gcc-55a2c3226a3e90a6d65f19710bab1ac377054234.zip gcc-55a2c3226a3e90a6d65f19710bab1ac377054234.tar.gz gcc-55a2c3226a3e90a6d65f19710bab1ac377054234.tar.bz2 |
dbxout.c (dbxout_symbol_location): Pass new argument to alter_subreg.
2012-10-23 Vladimir Makarov <vmakarov@redhat.com>
* dbxout.c (dbxout_symbol_location): Pass new argument to
alter_subreg.
* dwarf2out.c: Include ira.h and lra.h.
(based_loc_descr, compute_frame_pointer_to_fb_displacement): Use
lra_eliminate_regs for LRA instead of eliminate_regs.
* expr.c (emit_move_insn_1): Pass an additional argument to
emit_move_via_integer. Use emit_move_via_integer for LRA only if
the insn is recognized.
* emit-rtl.c (gen_rtx_REG): Add lra_in_progress.
(validate_subreg): Don't check offset for LRA and floating point
modes.
* final.c (final_scan_insn, cleanup_subreg_operands): Pass new
argument to alter_subreg.
(walk_alter_subreg, output_operand): Ditto.
(alter_subreg): Add new argument.
* gcse.c (calculate_bb_reg_pressure): Add parameter to
ira_setup_eliminable_regset call.
* ira.c: Include lra.h.
(ira_init_once, ira_init, ira_finish_once): Call lra_start_once,
lra_init, lra_finish_once in anyway.
(ira_setup_eliminable_regset): Add parameter. Remove need_fp.
Call lra_init_elimination and mark HARD_FRAME_POINTER_REGNUM as
living forever if frame_pointer_needed.
(setup_reg_class_relations): Set up ira_reg_class_subset.
(ira_reg_equiv_invariant_p, ira_reg_equiv_const): Remove.
(find_reg_equiv_invariant_const): Ditto.
(setup_reg_renumber): Use ira_equiv_no_lvalue_p instead of
ira_reg_equiv_invariant_p. Skip caps for LRA.
(setup_reg_equiv_init, ira_update_equiv_info_by_shuffle_insn): New
functions.
(ira_reg_equiv_len, ira_reg_equiv): New externals.
(ira_reg_equiv): New.
(ira_expand_reg_equiv, init_reg_equiv, finish_reg_equiv): New
functions.
(no_equiv, update_equiv_regs): Use ira_reg_equiv instead of
reg_equiv_init.
(setup_reg_equiv): New function.
(ira_use_lra_p): New global.
(ira): Set up lra_simple_p and ira_conflicts_p. Set up and
restore flag_caller_saves and flag_ira_region. Move
initialization of ira_obstack and ira_bitmap_obstack upper. Call
init_reg_equiv, setup_reg_equiv, and setup_reg_equiv_init instead
of initialization of ira_reg_equiv_len, ira_reg_equiv_invariant_p,
and ira_reg_equiv_const. Call ira_setup_eliminable_regset with a
new argument. Don't flatten IRA IRA for LRA. Don't reassign
conflict allocnos for LRA. Call finish_reg_equiv.
(do_reload): Prepare code for LRA call. Call LRA.
* ira.h (ira_use_lra_p): New external.
(struct target_ira): Add members x_ira_class_subset_p
x_ira_reg_class_subset, and x_ira_reg_classes_intersect_p.
(ira_class_subset_p, ira_reg_class_subset): New macros.
(ira_reg_classes_intersect_p): New macro.
(struct ira_reg_equiv): New.
(ira_setup_eliminable_regset): Add an argument.
(ira_expand_reg_equiv, ira_update_equiv_info_by_shuffle_insn): New
prototypes.
* ira-color.c (color_pass, move_spill_restore, coalesce_allocnos):
Use ira_equiv_no_lvalue_p.
(coalesce_spill_slots, ira_sort_regnos_for_alter_reg): Ditto.
* ira-emit.c (ira_create_new_reg): Call ira_expand_reg_equiv.
(generate_edge_moves, change_loop) Use ira_equiv_no_lvalue_p.
(emit_move_list): Simplify code. Call
ira_update_equiv_info_by_shuffle_insn. Use ira_reg_equiv instead
of ira_reg_equiv_invariant_p and ira_reg_equiv_const. Change
assert.
* ira-int.h (struct target_ira_int): Remove x_ira_class_subset_p
and x_ira_reg_classes_intersect_p.
(ira_class_subset_p, ira_reg_classes_intersect_p): Remove.
(ira_reg_equiv_len, ira_reg_equiv_invariant_p): Ditto.
(ira_reg_equiv_const): Ditto.
(ira_equiv_no_lvalue_p): New function.
* jump.c (true_regnum): Always use hard_regno for subreg_get_info
when lra is in progress.
* haifa-sched.c (sched_init): Pass new argument to
ira_setup_eliminable_regset.
* loop-invariant.c (calculate_loop_reg_pressure): Pass new
argument to ira_setup_eliminable_regset.
* lra.h: New.
* lra-int.h: Ditto.
* lra.c: Ditto.
* lra-assigns.c: Ditto.
* lra-constraints.c: Ditto.
* lra-coalesce.c: Ditto.
* lra-eliminations.c: Ditto.
* lra-lives.c: Ditto.
* lra-spills.c: Ditto.
* Makefile.in (LRA_INT_H): New.
(OBJS): Add lra.o, lra-assigns.o, lra-coalesce.o,
lra-constraints.o, lra-eliminations.o, lra-lives.o, and
lra-spills.o.
(dwarf2out.o): Add dependence on ira.h and lra.h.
(ira.o): Add dependence on lra.h.
(lra.o, lra-assigns.o, lra-coalesce.o, lra-constraints.o): New
entries.
(lra-eliminations.o, lra-lives.o, lra-spills.o): Ditto.
* output.h (alter_subreg): Add new argument.
* rtlanal.c (simplify_subreg_regno): Permit mode changes for LRA.
Permit ARG_POINTER_REGNUM and STACK_POINTER_REGNUM for LRA.
* recog.c (general_operand, register_operand): Accept paradoxical
FLOAT_MODE subregs for LRA.
(scratch_operand): Accept pseudos for LRA.
* rtl.h (lra_in_progress): New external.
(debug_bb_n_slim, debug_bb_slim, print_value_slim): New
prototypes.
(debug_rtl_slim, debug_insn_slim): Ditto.
* sdbout.c (sdbout_symbol): Pass new argument to alter_subreg.
* sched-vis.c (print_value_slim): New.
* target.def (lra_p): New hook.
(register_priority): Ditto.
(different_addr_displacement_p): Ditto.
(spill_class): Ditto.
* target-globals.h (this_target_lra_int): New external.
(target_globals): New member lra_int.
(restore_target_globals): Restore this_target_lra_int.
* target-globals.c: Include lra-int.h.
(default_target_globals): Add &default_target_lra_int.
* targhooks.c (default_lra_p): New function.
(default_register_priority): Ditto.
(default_different_addr_displacement_p): Ditto.
* targhooks.h (default_lra_p): Declare.
(default_register_priority): Ditto.
(default_different_addr_displacement_p): Ditto.
* timevar.def (TV_LRA, TV_LRA_ELIMINATE, TV_LRA_INHERITANCE): New.
(TV_LRA_CREATE_LIVE_RANGES, TV_LRA_ASSIGN, TV_LRA_COALESCE): New.
* config/arm/arm.c (load_multiple_sequence): Pass new argument toOB
alter_subreg.
(store_multiple_sequence): Ditto.
* config/i386/i386.h (enum ix86_tune_indices): Add
X86_TUNE_GENERAL_REGS_SSE_SPILL.
(TARGET_GENERAL_REGS_SSE_SPILL): New macro.
* config/i386/i386.c (initial_ix86_tune_features): Set up
X86_TUNE_GENERAL_REGS_SSE_SPILL for m_COREI7 and m_CORE2I7.
(ix86_lra_p, ix86_register_priority): New functions.
(ix86_secondary_reload): Add NON_Q_REGS, SIREG, DIREG.
(inline_secondary_memory_needed): Change assert.
(ix86_spill_class): New function.
(TARGET_LRA_P, TARGET_REGISTER_BANK, TARGET_SPILL_CLASS): New
macros.
* config/m68k/m68k.c (emit_move_sequence): Pass new argument to
alter_subreg.
* config/m32r/m32r.c (gen_split_move_double): Ditto.
* config/pa/pa.c (pa_emit_move_sequence): Ditto.
* config/sh/sh.md: Ditto.
* config/v850/v850.c (v850_reorg): Ditto.
* config/xtensa/xtensa.c (fixup_subreg_mem): Ditto.
* doc/md.texi: Add new interpretation of hint * for LRA.
* doc/passes.texi: Describe LRA pass.
* doc/tm.texi.in: Add TARGET_LRA_P, TARGET_REGISTER_PRIORITY,
TARGET_DIFFERENT_ADDR_DISPLACEMENT_P, and TARGET_SPILL_CLASS.
* doc/tm.texi: Update.
From-SVN: r192719
Diffstat (limited to 'gcc/lra-lives.c')
-rw-r--r-- | gcc/lra-lives.c | 1010 |
1 files changed, 1010 insertions, 0 deletions
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c new file mode 100644 index 0000000..6e00250 --- /dev/null +++ b/gcc/lra-lives.c @@ -0,0 +1,1010 @@ +/* Build live ranges for pseudos. + Copyright (C) 2010, 2011, 2012 + Free Software Foundation, Inc. + Contributed by Vladimir Makarov <vmakarov@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +/* This file contains code to build pseudo live-ranges (analogous + structures used in IRA, so read comments about the live-ranges + there) and other info necessary for other passes to assign + hard-registers to pseudos, coalesce the spilled pseudos, and assign + stack memory slots to spilled pseudos. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hard-reg-set.h" +#include "rtl.h" +#include "tm_p.h" +#include "insn-config.h" +#include "recog.h" +#include "output.h" +#include "regs.h" +#include "function.h" +#include "expr.h" +#include "basic-block.h" +#include "except.h" +#include "df.h" +#include "ira.h" +#include "sparseset.h" +#include "lra-int.h" + +/* Program points are enumerated by numbers from range + 0..LRA_LIVE_MAX_POINT-1. There are approximately two times more + program points than insns. Program points are places in the + program where liveness info can be changed. In most general case + (there are more complicated cases too) some program points + correspond to places where input operand dies and other ones + correspond to places where output operands are born. */ +int lra_live_max_point; + +/* Accumulated execution frequency of all references for each hard + register. */ +int lra_hard_reg_usage[FIRST_PSEUDO_REGISTER]; + +/* A global flag whose true value says to build live ranges for all + pseudos, otherwise the live ranges only for pseudos got memory is + build. True value means also building copies and setting up hard + register preferences. The complete info is necessary only for the + assignment pass. The complete info is not needed for the + coalescing and spill passes. */ +static bool complete_info_p; + +/* Pseudos live at current point in the RTL scan. */ +static sparseset pseudos_live; + +/* Pseudos probably living through calls and setjumps. As setjump is + a call too, if a bit in PSEUDOS_LIVE_THROUGH_SETJUMPS is set up + then the corresponding bit in PSEUDOS_LIVE_THROUGH_CALLS is set up + too. These data are necessary for cases when only one subreg of a + multi-reg pseudo is set up after a call. So we decide it is + probably live when traversing bb backward. We are sure about + living when we see its usage or definition of the pseudo. */ +static sparseset pseudos_live_through_calls; +static sparseset pseudos_live_through_setjumps; + +/* Set of hard regs (except eliminable ones) currently live. */ +static HARD_REG_SET hard_regs_live; + +/* Set of pseudos and hard registers start living/dying in the current + insn. These sets are used to update REG_DEAD and REG_UNUSED notes + in the insn. */ +static sparseset start_living, start_dying; + +/* Set of pseudos and hard regs dead and unused in the current + insn. */ +static sparseset unused_set, dead_set; + +/* Pool for pseudo live ranges. */ +static alloc_pool live_range_pool; + +/* Free live range LR. */ +static void +free_live_range (lra_live_range_t lr) +{ + pool_free (live_range_pool, lr); +} + +/* Free live range list LR. */ +static void +free_live_range_list (lra_live_range_t lr) +{ + lra_live_range_t next; + + while (lr != NULL) + { + next = lr->next; + free_live_range (lr); + lr = next; + } +} + +/* Create and return pseudo live range with given attributes. */ +static lra_live_range_t +create_live_range (int regno, int start, int finish, lra_live_range_t next) +{ + lra_live_range_t p; + + p = (lra_live_range_t) pool_alloc (live_range_pool); + p->regno = regno; + p->start = start; + p->finish = finish; + p->next = next; + return p; +} + +/* Copy live range R and return the result. */ +static lra_live_range_t +copy_live_range (lra_live_range_t r) +{ + lra_live_range_t p; + + p = (lra_live_range_t) pool_alloc (live_range_pool); + *p = *r; + return p; +} + +/* Copy live range list given by its head R and return the result. */ +lra_live_range_t +lra_copy_live_range_list (lra_live_range_t r) +{ + lra_live_range_t p, first, *chain; + + first = NULL; + for (chain = &first; r != NULL; r = r->next) + { + p = copy_live_range (r); + *chain = p; + chain = &p->next; + } + return first; +} + +/* Merge *non-intersected* ranges R1 and R2 and returns the result. + The function maintains the order of ranges and tries to minimize + size of the result range list. Ranges R1 and R2 may not be used + after the call. */ +lra_live_range_t +lra_merge_live_ranges (lra_live_range_t r1, lra_live_range_t r2) +{ + lra_live_range_t first, last, temp; + + if (r1 == NULL) + return r2; + if (r2 == NULL) + return r1; + for (first = last = NULL; r1 != NULL && r2 != NULL;) + { + if (r1->start < r2->start) + { + temp = r1; + r1 = r2; + r2 = temp; + } + if (r1->start == r2->finish + 1) + { + /* Joint ranges: merge r1 and r2 into r1. */ + r1->start = r2->start; + temp = r2; + r2 = r2->next; + pool_free (live_range_pool, temp); + } + else + { + gcc_assert (r2->finish + 1 < r1->start); + /* Add r1 to the result. */ + if (first == NULL) + first = last = r1; + else + { + last->next = r1; + last = r1; + } + r1 = r1->next; + } + } + if (r1 != NULL) + { + if (first == NULL) + first = r1; + else + last->next = r1; + } + else + { + lra_assert (r2 != NULL); + if (first == NULL) + first = r2; + else + last->next = r2; + } + return first; +} + +/* Return TRUE if live ranges R1 and R2 intersect. */ +bool +lra_intersected_live_ranges_p (lra_live_range_t r1, lra_live_range_t r2) +{ + /* Remember the live ranges are always kept ordered. */ + while (r1 != NULL && r2 != NULL) + { + if (r1->start > r2->finish) + r1 = r1->next; + else if (r2->start > r1->finish) + r2 = r2->next; + else + return true; + } + return false; +} + +/* The function processing birth of hard register REGNO. It updates + living hard regs, conflict hard regs for living pseudos, and + START_LIVING. */ +static void +make_hard_regno_born (int regno) +{ + unsigned int i; + + lra_assert (regno < FIRST_PSEUDO_REGISTER); + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) + || TEST_HARD_REG_BIT (hard_regs_live, regno)) + return; + SET_HARD_REG_BIT (hard_regs_live, regno); + sparseset_set_bit (start_living, regno); + EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) + SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno); +} + +/* Process the death of hard register REGNO. This updates + hard_regs_live and START_DYING. */ +static void +make_hard_regno_dead (int regno) +{ + lra_assert (regno < FIRST_PSEUDO_REGISTER); + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, regno) + || ! TEST_HARD_REG_BIT (hard_regs_live, regno)) + return; + sparseset_set_bit (start_dying, regno); + CLEAR_HARD_REG_BIT (hard_regs_live, regno); +} + +/* Mark pseudo REGNO as living at program point POINT, update conflicting + hard registers of the pseudo and START_LIVING, and start a new live + range for the pseudo corresponding to REGNO if it is necessary. */ +static void +mark_pseudo_live (int regno, int point) +{ + lra_live_range_t p; + + lra_assert (regno >= FIRST_PSEUDO_REGISTER); + lra_assert (! sparseset_bit_p (pseudos_live, regno)); + sparseset_set_bit (pseudos_live, regno); + IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live); + + if ((complete_info_p || lra_get_regno_hard_regno (regno) < 0) + && ((p = lra_reg_info[regno].live_ranges) == NULL + || (p->finish != point && p->finish + 1 != point))) + lra_reg_info[regno].live_ranges + = create_live_range (regno, point, -1, p); + sparseset_set_bit (start_living, regno); +} + +/* Mark pseudo REGNO as not living at program point POINT and update + START_DYING. + This finishes the current live range for the pseudo corresponding + to REGNO. */ +static void +mark_pseudo_dead (int regno, int point) +{ + lra_live_range_t p; + + lra_assert (regno >= FIRST_PSEUDO_REGISTER); + lra_assert (sparseset_bit_p (pseudos_live, regno)); + sparseset_clear_bit (pseudos_live, regno); + sparseset_set_bit (start_dying, regno); + if (complete_info_p || lra_get_regno_hard_regno (regno) < 0) + { + p = lra_reg_info[regno].live_ranges; + lra_assert (p != NULL); + p->finish = point; + } +} + +/* Mark register REGNO (pseudo or hard register) in MODE as live + at program point POINT. + Return TRUE if the liveness tracking sets were modified, + or FALSE if nothing changed. */ +static bool +mark_regno_live (int regno, enum machine_mode mode, int point) +{ + int last; + bool changed = false; + + if (regno < FIRST_PSEUDO_REGISTER) + { + for (last = regno + hard_regno_nregs[regno][mode]; + regno < last; + regno++) + make_hard_regno_born (regno); + } + else if (! sparseset_bit_p (pseudos_live, regno)) + { + mark_pseudo_live (regno, point); + changed = true; + } + return changed; +} + + +/* Mark register REGNO in MODE as dead at program point POINT. + Return TRUE if the liveness tracking sets were modified, + or FALSE if nothing changed. */ +static bool +mark_regno_dead (int regno, enum machine_mode mode, int point) +{ + int last; + bool changed = false; + + if (regno < FIRST_PSEUDO_REGISTER) + { + for (last = regno + hard_regno_nregs[regno][mode]; + regno < last; + regno++) + make_hard_regno_dead (regno); + } + else if (sparseset_bit_p (pseudos_live, regno)) + { + mark_pseudo_dead (regno, point); + changed = true; + } + return changed; +} + +/* Insn currently scanned. */ +static rtx curr_insn; +/* The insn data. */ +static lra_insn_recog_data_t curr_id; +/* The insn static data. */ +static struct lra_static_insn_data *curr_static_id; + +/* Return true when one of the predecessor edges of BB is marked with + EDGE_ABNORMAL_CALL or EDGE_EH. */ +static bool +bb_has_abnormal_call_pred (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)) + return true; + } + return false; +} + +/* Vec containing execution frequencies of program points. */ +static VEC(int,heap) *point_freq_vec; + +/* The start of the above vector elements. */ +int *lra_point_freq; + +/* Increment the current program point POINT to the next point which has + execution frequency FREQ. */ +static void +next_program_point (int &point, int freq) +{ + VEC_safe_push (int, heap, point_freq_vec, freq); + lra_point_freq = VEC_address (int, point_freq_vec); + point++; +} + +/* Update the preference of HARD_REGNO for pseudo REGNO by PROFIT. */ +void +lra_setup_reload_pseudo_preferenced_hard_reg (int regno, + int hard_regno, int profit) +{ + lra_assert (regno >= lra_constraint_new_regno_start); + if (lra_reg_info[regno].preferred_hard_regno1 == hard_regno) + lra_reg_info[regno].preferred_hard_regno_profit1 += profit; + else if (lra_reg_info[regno].preferred_hard_regno2 == hard_regno) + lra_reg_info[regno].preferred_hard_regno_profit2 += profit; + else if (lra_reg_info[regno].preferred_hard_regno1 < 0) + { + lra_reg_info[regno].preferred_hard_regno1 = hard_regno; + lra_reg_info[regno].preferred_hard_regno_profit1 = profit; + } + else if (lra_reg_info[regno].preferred_hard_regno2 < 0 + || profit > lra_reg_info[regno].preferred_hard_regno_profit2) + { + lra_reg_info[regno].preferred_hard_regno2 = hard_regno; + lra_reg_info[regno].preferred_hard_regno_profit2 = profit; + } + else + return; + /* Keep the 1st hard regno as more profitable. */ + if (lra_reg_info[regno].preferred_hard_regno1 >= 0 + && lra_reg_info[regno].preferred_hard_regno2 >= 0 + && (lra_reg_info[regno].preferred_hard_regno_profit2 + > lra_reg_info[regno].preferred_hard_regno_profit1)) + { + int temp; + + temp = lra_reg_info[regno].preferred_hard_regno1; + lra_reg_info[regno].preferred_hard_regno1 + = lra_reg_info[regno].preferred_hard_regno2; + lra_reg_info[regno].preferred_hard_regno2 = temp; + temp = lra_reg_info[regno].preferred_hard_regno_profit1; + lra_reg_info[regno].preferred_hard_regno_profit1 + = lra_reg_info[regno].preferred_hard_regno_profit2; + lra_reg_info[regno].preferred_hard_regno_profit2 = temp; + } + if (lra_dump_file != NULL) + { + if ((hard_regno = lra_reg_info[regno].preferred_hard_regno1) >= 0) + fprintf (lra_dump_file, + " Hard reg %d is preferable by r%d with profit %d\n", + hard_regno, regno, + lra_reg_info[regno].preferred_hard_regno_profit1); + if ((hard_regno = lra_reg_info[regno].preferred_hard_regno2) >= 0) + fprintf (lra_dump_file, + " Hard reg %d is preferable by r%d with profit %d\n", + hard_regno, regno, + lra_reg_info[regno].preferred_hard_regno_profit2); + } +} + +/* Check that REGNO living through calls and setjumps, set up conflict + regs, and clear corresponding bits in PSEUDOS_LIVE_THROUGH_CALLS and + PSEUDOS_LIVE_THROUGH_SETJUMPS. */ +static inline void +check_pseudos_live_through_calls (int regno) +{ + if (! sparseset_bit_p (pseudos_live_through_calls, regno)) + return; + sparseset_clear_bit (pseudos_live_through_calls, regno); + IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, + call_used_reg_set); +#ifdef ENABLE_CHECKING + lra_reg_info[regno].call_p = true; +#endif + if (! sparseset_bit_p (pseudos_live_through_setjumps, regno)) + return; + sparseset_clear_bit (pseudos_live_through_setjumps, regno); + /* Don't allocate pseudos that cross setjmps or any call, if this + function receives a nonlocal goto. */ + SET_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs); +} + +/* Process insns of the basic block BB to update pseudo live ranges, + pseudo hard register conflicts, and insn notes. We do it on + backward scan of BB insns. CURR_POINT is the program point where + BB ends. The function updates this counter and returns in + CURR_POINT the program point where BB starts. */ +static void +process_bb_lives (basic_block bb, int &curr_point) +{ + int i, regno, freq; + unsigned int j; + bitmap_iterator bi; + bitmap reg_live_out; + unsigned int px; + rtx link, *link_loc; + bool need_curr_point_incr; + + reg_live_out = df_get_live_out (bb); + sparseset_clear (pseudos_live); + sparseset_clear (pseudos_live_through_calls); + sparseset_clear (pseudos_live_through_setjumps); + REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out); + AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset); + AND_COMPL_HARD_REG_SET (hard_regs_live, lra_no_alloc_regs); + EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) + mark_pseudo_live (j, curr_point); + + freq = REG_FREQ_FROM_BB (bb); + + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " BB %d\n", bb->index); + + /* Scan the code of this basic block, noting which pseudos and hard + regs are born or die. + + Note that this loop treats uninitialized values as live until the + beginning of the block. For example, if an instruction uses + (reg:DI foo), and only (subreg:SI (reg:DI foo) 0) is ever set, + FOO will remain live until the beginning of the block. Likewise + if FOO is not set at all. This is unnecessarily pessimistic, but + it probably doesn't matter much in practice. */ + FOR_BB_INSNS_REVERSE (bb, curr_insn) + { + bool call_p; + int dst_regno, src_regno; + rtx set; + struct lra_insn_reg *reg; + + if (!NONDEBUG_INSN_P (curr_insn)) + continue; + + curr_id = lra_get_insn_recog_data (curr_insn); + curr_static_id = curr_id->insn_static_data; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Insn %u: point = %d\n", + INSN_UID (curr_insn), curr_point); + + /* Update max ref width and hard reg usage. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->regno >= FIRST_PSEUDO_REGISTER + && (GET_MODE_SIZE (reg->biggest_mode) + > GET_MODE_SIZE (lra_reg_info[reg->regno].biggest_mode))) + lra_reg_info[reg->regno].biggest_mode = reg->biggest_mode; + else if (reg->regno < FIRST_PSEUDO_REGISTER) + lra_hard_reg_usage[reg->regno] += freq; + + call_p = CALL_P (curr_insn); + if (complete_info_p + && (set = single_set (curr_insn)) != NULL_RTX + && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set)) + /* Check that source regno does not conflict with + destination regno to exclude most impossible + preferences. */ + && ((((src_regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER + && ! sparseset_bit_p (pseudos_live, src_regno)) + || (src_regno < FIRST_PSEUDO_REGISTER + && ! TEST_HARD_REG_BIT (hard_regs_live, src_regno))) + /* It might be 'inheritance pseudo <- reload pseudo'. */ + || (src_regno >= lra_constraint_new_regno_start + && ((int) REGNO (SET_DEST (set)) + >= lra_constraint_new_regno_start)))) + { + int hard_regno = -1, regno = -1; + + dst_regno = REGNO (SET_DEST (set)); + if (dst_regno >= lra_constraint_new_regno_start + && src_regno >= lra_constraint_new_regno_start) + lra_create_copy (dst_regno, src_regno, freq); + else if (dst_regno >= lra_constraint_new_regno_start) + { + if ((hard_regno = src_regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = reg_renumber[src_regno]; + regno = dst_regno; + } + else if (src_regno >= lra_constraint_new_regno_start) + { + if ((hard_regno = dst_regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = reg_renumber[dst_regno]; + regno = src_regno; + } + if (regno >= 0 && hard_regno >= 0) + lra_setup_reload_pseudo_preferenced_hard_reg + (regno, hard_regno, freq); + } + + sparseset_clear (start_living); + + /* Try to avoid unnecessary program point increments, this saves + a lot of time in remove_some_program_points_and_update_live_ranges. + We only need an increment if something becomes live or dies at this + program point. */ + need_curr_point_incr = false; + + /* Mark each defined value as live. We need to do this for + unused values because they still conflict with quantities + that are live at the time of the definition. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type != OP_IN) + { + need_curr_point_incr |= mark_regno_live (reg->regno, + reg->biggest_mode, + curr_point); + check_pseudos_live_through_calls (reg->regno); + } + + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type != OP_IN) + make_hard_regno_born (reg->regno); + + sparseset_copy (unused_set, start_living); + + sparseset_clear (start_dying); + + /* See which defined values die here. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p) + need_curr_point_incr |= mark_regno_dead (reg->regno, + reg->biggest_mode, + curr_point); + + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p) + make_hard_regno_dead (reg->regno); + + if (call_p) + { + sparseset_ior (pseudos_live_through_calls, + pseudos_live_through_calls, pseudos_live); + if (cfun->has_nonlocal_label + || find_reg_note (curr_insn, REG_SETJMP, + NULL_RTX) != NULL_RTX) + sparseset_ior (pseudos_live_through_setjumps, + pseudos_live_through_setjumps, pseudos_live); + } + + /* Increment the current program point if we must. */ + if (need_curr_point_incr) + next_program_point (curr_point, freq); + + sparseset_clear (start_living); + + need_curr_point_incr = false; + + /* Mark each used value as live. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_IN) + { + need_curr_point_incr |= mark_regno_live (reg->regno, + reg->biggest_mode, + curr_point); + check_pseudos_live_through_calls (reg->regno); + } + + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type == OP_IN) + make_hard_regno_born (reg->regno); + + if (curr_id->arg_hard_regs != NULL) + /* Make argument hard registers live. */ + for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++) + make_hard_regno_born (regno); + + sparseset_and_compl (dead_set, start_living, start_dying); + + /* Mark early clobber outputs dead. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p) + need_curr_point_incr = mark_regno_dead (reg->regno, + reg->biggest_mode, + curr_point); + + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p) + make_hard_regno_dead (reg->regno); + + if (need_curr_point_incr) + next_program_point (curr_point, freq); + + /* Update notes. */ + for (link_loc = ®_NOTES (curr_insn); (link = *link_loc) != NULL_RTX;) + { + if (REG_NOTE_KIND (link) != REG_DEAD + && REG_NOTE_KIND (link) != REG_UNUSED) + ; + else if (REG_P (XEXP (link, 0))) + { + regno = REGNO (XEXP (link, 0)); + if ((REG_NOTE_KIND (link) == REG_DEAD + && ! sparseset_bit_p (dead_set, regno)) + || (REG_NOTE_KIND (link) == REG_UNUSED + && ! sparseset_bit_p (unused_set, regno))) + { + *link_loc = XEXP (link, 1); + continue; + } + if (REG_NOTE_KIND (link) == REG_DEAD) + sparseset_clear_bit (dead_set, regno); + else if (REG_NOTE_KIND (link) == REG_UNUSED) + sparseset_clear_bit (unused_set, regno); + } + link_loc = &XEXP (link, 1); + } + EXECUTE_IF_SET_IN_SPARSESET (dead_set, j) + add_reg_note (curr_insn, REG_DEAD, regno_reg_rtx[j]); + EXECUTE_IF_SET_IN_SPARSESET (unused_set, j) + add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]); + } + +#ifdef EH_RETURN_DATA_REGNO + if (bb_has_eh_pred (bb)) + for (j = 0; ; ++j) + { + unsigned int regno = EH_RETURN_DATA_REGNO (j); + + if (regno == INVALID_REGNUM) + break; + make_hard_regno_born (regno); + } +#endif + + /* Pseudos can't go in stack regs at the start of a basic block that + is reached by an abnormal edge. Likewise for call clobbered regs, + because caller-save, fixup_abnormal_edges and possibly the table + driven EH machinery are not quite ready to handle such pseudos + live across such edges. */ + if (bb_has_abnormal_pred (bb)) + { +#ifdef STACK_REGS + EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, px) + lra_reg_info[px].no_stack_p = true; + for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++) + make_hard_regno_born (px); +#endif + /* No need to record conflicts for call clobbered regs if we + have nonlocal labels around, as we don't ever try to + allocate such regs in this case. */ + if (!cfun->has_nonlocal_label && bb_has_abnormal_call_pred (bb)) + for (px = 0; px < FIRST_PSEUDO_REGISTER; px++) + if (call_used_regs[px]) + make_hard_regno_born (px); + } + + /* See if we'll need an increment at the end of this basic block. + An increment is needed if the PSEUDOS_LIVE set is not empty, + to make sure the finish points are set up correctly. */ + need_curr_point_incr = (sparseset_cardinality (pseudos_live) > 0); + + EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) + mark_pseudo_dead (i, curr_point); + + EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb), FIRST_PSEUDO_REGISTER, j, bi) + { + if (sparseset_cardinality (pseudos_live_through_calls) == 0) + break; + if (sparseset_bit_p (pseudos_live_through_calls, j)) + check_pseudos_live_through_calls (j); + } + + if (need_curr_point_incr) + next_program_point (curr_point, freq); +} + +/* Compress pseudo live ranges by removing program points where + nothing happens. Complexity of many algorithms in LRA is linear + function of program points number. To speed up the code we try to + minimize the number of the program points here. */ +static void +remove_some_program_points_and_update_live_ranges (void) +{ + unsigned i; + int n, max_regno; + int *map; + lra_live_range_t r, prev_r, next_r; + sbitmap born_or_dead, born, dead; + sbitmap_iterator sbi; + bool born_p, dead_p, prev_born_p, prev_dead_p; + + born = sbitmap_alloc (lra_live_max_point); + dead = sbitmap_alloc (lra_live_max_point); + sbitmap_zero (born); + sbitmap_zero (dead); + max_regno = max_reg_num (); + for (i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++) + { + for (r = lra_reg_info[i].live_ranges; r != NULL; r = r->next) + { + lra_assert (r->start <= r->finish); + SET_BIT (born, r->start); + SET_BIT (dead, r->finish); + } + } + born_or_dead = sbitmap_alloc (lra_live_max_point); + sbitmap_a_or_b (born_or_dead, born, dead); + map = XCNEWVEC (int, lra_live_max_point); + n = -1; + prev_born_p = prev_dead_p = false; + EXECUTE_IF_SET_IN_SBITMAP (born_or_dead, 0, i, sbi) + { + born_p = TEST_BIT (born, i); + dead_p = TEST_BIT (dead, i); + if ((prev_born_p && ! prev_dead_p && born_p && ! dead_p) + || (prev_dead_p && ! prev_born_p && dead_p && ! born_p)) + { + map[i] = n; + lra_point_freq[n] = MAX (lra_point_freq[n], lra_point_freq[i]); + } + else + { + map[i] = ++n; + lra_point_freq[n] = lra_point_freq[i]; + } + prev_born_p = born_p; + prev_dead_p = dead_p; + } + sbitmap_free (born_or_dead); + sbitmap_free (born); + sbitmap_free (dead); + n++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "Compressing live ranges: from %d to %d - %d%%\n", + lra_live_max_point, n, 100 * n / lra_live_max_point); + if (n < lra_live_max_point) + { + lra_live_max_point = n; + for (i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++) + { + for (prev_r = NULL, r = lra_reg_info[i].live_ranges; + r != NULL; + r = next_r) + { + next_r = r->next; + r->start = map[r->start]; + r->finish = map[r->finish]; + if (prev_r == NULL || prev_r->start > r->finish + 1) + { + prev_r = r; + continue; + } + prev_r->start = r->start; + prev_r->next = next_r; + free_live_range (r); + } + } + } + free (map); +} + +/* Print live ranges R to file F. */ +void +lra_print_live_range_list (FILE *f, lra_live_range_t r) +{ + for (; r != NULL; r = r->next) + fprintf (f, " [%d..%d]", r->start, r->finish); + fprintf (f, "\n"); +} + +/* Print live ranges R to stderr. */ +void +lra_debug_live_range_list (lra_live_range_t r) +{ + lra_print_live_range_list (stderr, r); +} + +/* Print live ranges of pseudo REGNO to file F. */ +static void +print_pseudo_live_ranges (FILE *f, int regno) +{ + if (lra_reg_info[regno].live_ranges == NULL) + return; + fprintf (f, " r%d:", regno); + lra_print_live_range_list (f, lra_reg_info[regno].live_ranges); +} + +/* Print live ranges of pseudo REGNO to stderr. */ +void +lra_debug_pseudo_live_ranges (int regno) +{ + print_pseudo_live_ranges (stderr, regno); +} + +/* Print live ranges of all pseudos to file F. */ +static void +print_live_ranges (FILE *f) +{ + int i, max_regno; + + max_regno = max_reg_num (); + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + print_pseudo_live_ranges (f, i); +} + +/* Print live ranges of all pseudos to stderr. */ +void +lra_debug_live_ranges (void) +{ + print_live_ranges (stderr); +} + +/* Compress pseudo live ranges. */ +static void +compress_live_ranges (void) +{ + remove_some_program_points_and_update_live_ranges (); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, "Ranges after the compression:\n"); + print_live_ranges (lra_dump_file); + } +} + +/* The number of the current live range pass. */ +int lra_live_range_iter; + +/* The main entry function creates live ranges only for memory pseudos + (or for all ones if ALL_P), set up CONFLICT_HARD_REGS for + the pseudos. */ +void +lra_create_live_ranges (bool all_p) +{ + basic_block bb; + int i, hard_regno, max_regno = max_reg_num (); + int curr_point; + + timevar_push (TV_LRA_CREATE_LIVE_RANGES); + + complete_info_p = all_p; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + "\n********** Pseudo live ranges #%d: **********\n\n", + ++lra_live_range_iter); + memset (lra_hard_reg_usage, 0, sizeof (lra_hard_reg_usage)); + for (i = 0; i < max_regno; i++) + { + lra_reg_info[i].live_ranges = NULL; + CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs); + lra_reg_info[i].preferred_hard_regno1 = -1; + lra_reg_info[i].preferred_hard_regno2 = -1; + lra_reg_info[i].preferred_hard_regno_profit1 = 0; + lra_reg_info[i].preferred_hard_regno_profit2 = 0; +#ifdef STACK_REGS + lra_reg_info[i].no_stack_p = false; +#endif + if (regno_reg_rtx[i] != NULL_RTX) + lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]); + else + lra_reg_info[i].biggest_mode = VOIDmode; +#ifdef ENABLE_CHECKING + lra_reg_info[i].call_p = false; +#endif + if (i >= FIRST_PSEUDO_REGISTER + && lra_reg_info[i].nrefs != 0 && (hard_regno = reg_renumber[i]) >= 0) + lra_hard_reg_usage[hard_regno] += lra_reg_info[i].freq; + } + lra_free_copies (); + pseudos_live = sparseset_alloc (max_regno); + pseudos_live_through_calls = sparseset_alloc (max_regno); + pseudos_live_through_setjumps = sparseset_alloc (max_regno); + start_living = sparseset_alloc (max_regno); + start_dying = sparseset_alloc (max_regno); + dead_set = sparseset_alloc (max_regno); + unused_set = sparseset_alloc (max_regno); + curr_point = 0; + point_freq_vec = VEC_alloc (int, heap, get_max_uid () * 2); + lra_point_freq = VEC_address (int, point_freq_vec); + int *post_order_rev_cfg = XNEWVEC (int, last_basic_block); + int n_blocks_inverted = inverted_post_order_compute (post_order_rev_cfg); + lra_assert (n_blocks_inverted == n_basic_blocks); + for (i = n_blocks_inverted - 1; i >= 0; --i) + { + bb = BASIC_BLOCK (post_order_rev_cfg[i]); + if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR) + continue; + process_bb_lives (bb, curr_point); + } + free (post_order_rev_cfg); + lra_live_max_point = curr_point; + if (lra_dump_file != NULL) + print_live_ranges (lra_dump_file); + /* Clean up. */ + sparseset_free (unused_set); + sparseset_free (dead_set); + sparseset_free (start_dying); + sparseset_free (start_living); + sparseset_free (pseudos_live_through_calls); + sparseset_free (pseudos_live_through_setjumps); + sparseset_free (pseudos_live); + compress_live_ranges (); + timevar_pop (TV_LRA_CREATE_LIVE_RANGES); +} + +/* Finish all live ranges. */ +void +lra_clear_live_ranges (void) +{ + int i; + + for (i = 0; i < max_reg_num (); i++) + free_live_range_list (lra_reg_info[i].live_ranges); + VEC_free (int, heap, point_freq_vec); +} + +/* Initialize live ranges data once per function. */ +void +lra_live_ranges_init (void) +{ + live_range_pool = create_alloc_pool ("live ranges", + sizeof (struct lra_live_range), 100); +} + +/* Finish live ranges data once per function. */ +void +lra_live_ranges_finish (void) +{ + free_alloc_pool (live_range_pool); +} |