aboutsummaryrefslogtreecommitdiff
path: root/gcc/lra-lives.c
diff options
context:
space:
mode:
authorVladimir Makarov <vmakarov@redhat.com>2012-10-23 15:51:41 +0000
committerVladimir Makarov <vmakarov@gcc.gnu.org>2012-10-23 15:51:41 +0000
commit55a2c3226a3e90a6d65f19710bab1ac377054234 (patch)
tree915ce489d01a05653371ff4f7770258ffacab1b4 /gcc/lra-lives.c
parent6acf25e4b380e5ad738ffe2830a71635bc5230d1 (diff)
downloadgcc-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.c1010
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 = &REG_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);
+}