diff options
Diffstat (limited to 'gcc/ira.c')
-rw-r--r-- | gcc/ira.c | 584 |
1 files changed, 429 insertions, 155 deletions
diff --git a/gcc/ira.c b/gcc/ira.c index 78b3f92db00..e91d37ddaa5 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -382,6 +382,7 @@ along with GCC; see the file COPYING3. If not see #include "function.h" #include "ggc.h" #include "ira-int.h" +#include "lra.h" #include "dce.h" #include "dbgcnt.h" @@ -1201,6 +1202,7 @@ setup_reg_class_relations (void) { ira_reg_classes_intersect_p[cl1][cl2] = false; ira_reg_class_intersect[cl1][cl2] = NO_REGS; + ira_reg_class_subset[cl1][cl2] = NO_REGS; COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl1]); AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); COPY_HARD_REG_SET (temp_set2, reg_class_contents[cl2]); @@ -1248,9 +1250,8 @@ setup_reg_class_relations (void) COPY_HARD_REG_SET (union_set, reg_class_contents[cl1]); IOR_HARD_REG_SET (union_set, reg_class_contents[cl2]); AND_COMPL_HARD_REG_SET (union_set, no_unit_alloc_regs); - for (i = 0; i < ira_important_classes_num; i++) + for (cl3 = 0; cl3 < N_REG_CLASSES; cl3++) { - cl3 = ira_important_classes[i]; COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl3]); AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs); if (hard_reg_set_subset_p (temp_hard_regset, intersection_set)) @@ -1258,25 +1259,45 @@ setup_reg_class_relations (void) /* CL3 allocatable hard register set is inside of intersection of allocatable hard register sets of CL1 and CL2. */ + if (important_class_p[cl3]) + { + COPY_HARD_REG_SET + (temp_set2, + reg_class_contents + [(int) ira_reg_class_intersect[cl1][cl2]]); + AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs); + if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2) + /* If the allocatable hard register sets are + the same, prefer GENERAL_REGS or the + smallest class for debugging + purposes. */ + || (hard_reg_set_equal_p (temp_hard_regset, temp_set2) + && (cl3 == GENERAL_REGS + || ((ira_reg_class_intersect[cl1][cl2] + != GENERAL_REGS) + && hard_reg_set_subset_p + (reg_class_contents[cl3], + reg_class_contents + [(int) + ira_reg_class_intersect[cl1][cl2]]))))) + ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3; + } COPY_HARD_REG_SET (temp_set2, - reg_class_contents[(int) - ira_reg_class_intersect[cl1][cl2]]); + reg_class_contents[(int) ira_reg_class_subset[cl1][cl2]]); AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs); - if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2) - /* If the allocatable hard register sets are the - same, prefer GENERAL_REGS or the smallest - class for debugging purposes. */ + if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2) + /* Ignore unavailable hard registers and prefer + smallest class for debugging purposes. */ || (hard_reg_set_equal_p (temp_hard_regset, temp_set2) - && (cl3 == GENERAL_REGS - || (ira_reg_class_intersect[cl1][cl2] != GENERAL_REGS - && hard_reg_set_subset_p - (reg_class_contents[cl3], - reg_class_contents - [(int) ira_reg_class_intersect[cl1][cl2]]))))) - ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3; + && hard_reg_set_subset_p + (reg_class_contents[cl3], + reg_class_contents + [(int) ira_reg_class_subset[cl1][cl2]]))) + ira_reg_class_subset[cl1][cl2] = (enum reg_class) cl3; } - if (hard_reg_set_subset_p (temp_hard_regset, union_set)) + if (important_class_p[cl3] + && hard_reg_set_subset_p (temp_hard_regset, union_set)) { /* CL3 allocatbale hard register set is inside of union of allocatable hard register sets of CL1 @@ -1632,6 +1653,7 @@ void ira_init_once (void) { ira_init_costs_once (); + lra_init_once (); } /* Free ira_max_register_move_cost, ira_may_move_in_cost and @@ -1679,6 +1701,7 @@ ira_init (void) clarify_prohibited_class_mode_regs (); setup_hard_regno_aclass (); ira_init_costs (); + lra_init (); } /* Function called once at the end of compiler work. */ @@ -1687,6 +1710,7 @@ ira_finish_once (void) { ira_finish_costs_once (); free_register_move_costs (); + lra_finish_once (); } @@ -1823,9 +1847,11 @@ compute_regs_asm_clobbered (void) } -/* Set up ELIMINABLE_REGSET, IRA_NO_ALLOC_REGS, and REGS_EVER_LIVE. */ +/* Set up ELIMINABLE_REGSET, IRA_NO_ALLOC_REGS, and REGS_EVER_LIVE. + If the function is called from IRA (not from the insn scheduler or + RTL loop invariant motion), FROM_IRA_P is true. */ void -ira_setup_eliminable_regset (void) +ira_setup_eliminable_regset (bool from_ira_p) { #ifdef ELIMINABLE_REGS int i; @@ -1835,7 +1861,7 @@ ira_setup_eliminable_regset (void) sp for alloca. So we can't eliminate the frame pointer in that case. At some point, we should improve this by emitting the sp-adjusting insns for this case. */ - int need_fp + frame_pointer_needed = (! flag_omit_frame_pointer || (cfun->calls_alloca && EXIT_IGNORE_STACK) /* We need the frame pointer to catch stack overflow exceptions @@ -1845,8 +1871,14 @@ ira_setup_eliminable_regset (void) || crtl->stack_realign_needed || targetm.frame_pointer_required ()); - frame_pointer_needed = need_fp; + if (from_ira_p && ira_use_lra_p) + /* It can change FRAME_POINTER_NEEDED. We call it only from IRA + because it is expensive. */ + lra_init_elimination (); + if (frame_pointer_needed) + df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true); + COPY_HARD_REG_SET (ira_no_alloc_regs, no_unit_alloc_regs); CLEAR_HARD_REG_SET (eliminable_regset); @@ -1859,7 +1891,7 @@ ira_setup_eliminable_regset (void) { bool cannot_elim = (! targetm.can_eliminate (eliminables[i].from, eliminables[i].to) - || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp)); + || (eliminables[i].to == STACK_POINTER_REGNUM && frame_pointer_needed)); if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, eliminables[i].from)) { @@ -1878,10 +1910,10 @@ ira_setup_eliminable_regset (void) if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM)) { SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM); - if (need_fp) + if (frame_pointer_needed) SET_HARD_REG_BIT (ira_no_alloc_regs, HARD_FRAME_POINTER_REGNUM); } - else if (need_fp) + else if (frame_pointer_needed) error ("%s cannot be used in asm here", reg_names[HARD_FRAME_POINTER_REGNUM]); else @@ -1892,10 +1924,10 @@ ira_setup_eliminable_regset (void) if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM)) { SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM); - if (need_fp) + if (frame_pointer_needed) SET_HARD_REG_BIT (ira_no_alloc_regs, FRAME_POINTER_REGNUM); } - else if (need_fp) + else if (frame_pointer_needed) error ("%s cannot be used in asm here", reg_names[FRAME_POINTER_REGNUM]); else df_set_regs_ever_live (FRAME_POINTER_REGNUM, true); @@ -1904,66 +1936,6 @@ ira_setup_eliminable_regset (void) -/* The length of the following two arrays. */ -int ira_reg_equiv_len; - -/* The element value is TRUE if the corresponding regno value is - invariant. */ -bool *ira_reg_equiv_invariant_p; - -/* The element value is equiv constant of given pseudo-register or - NULL_RTX. */ -rtx *ira_reg_equiv_const; - -/* Set up the two arrays declared above. */ -static void -find_reg_equiv_invariant_const (void) -{ - unsigned int i; - bool invariant_p; - rtx list, insn, note, constant, x; - - for (i = FIRST_PSEUDO_REGISTER; i < VEC_length (reg_equivs_t, reg_equivs); i++) - { - constant = NULL_RTX; - invariant_p = false; - for (list = reg_equiv_init (i); list != NULL_RTX; list = XEXP (list, 1)) - { - insn = XEXP (list, 0); - note = find_reg_note (insn, REG_EQUIV, NULL_RTX); - - if (note == NULL_RTX) - continue; - - x = XEXP (note, 0); - - if (! CONSTANT_P (x) - || ! flag_pic || LEGITIMATE_PIC_OPERAND_P (x)) - { - /* It can happen that a REG_EQUIV note contains a MEM - that is not a legitimate memory operand. As later - stages of the reload assume that all addresses found - in the reg_equiv_* arrays were originally legitimate, - we ignore such REG_EQUIV notes. */ - if (memory_operand (x, VOIDmode)) - invariant_p = MEM_READONLY_P (x); - else if (function_invariant_p (x)) - { - if (GET_CODE (x) == PLUS - || x == frame_pointer_rtx || x == arg_pointer_rtx) - invariant_p = true; - else - constant = x; - } - } - } - ira_reg_equiv_invariant_p[i] = invariant_p; - ira_reg_equiv_const[i] = constant; - } -} - - - /* Vector of substitutions of register numbers, used to map pseudo regs into hardware regs. This is set up as a result of register allocation. @@ -1984,6 +1956,8 @@ setup_reg_renumber (void) caller_save_needed = 0; FOR_EACH_ALLOCNO (a, ai) { + if (ira_use_lra_p && ALLOCNO_CAP_MEMBER (a) != NULL) + continue; /* There are no caps at this point. */ ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL); if (! ALLOCNO_ASSIGNED_P (a)) @@ -2015,9 +1989,7 @@ setup_reg_renumber (void) ira_assert (!optimize || flag_caller_saves || (ALLOCNO_CALLS_CROSSED_NUM (a) == ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)) - || regno >= ira_reg_equiv_len - || ira_reg_equiv_const[regno] - || ira_reg_equiv_invariant_p[regno]); + || ira_equiv_no_lvalue_p (regno)); caller_save_needed = 1; } } @@ -2184,6 +2156,109 @@ check_allocation (void) } #endif +/* Allocate REG_EQUIV_INIT. Set up it from IRA_REG_EQUIV which should + be already calculated. */ +static void +setup_reg_equiv_init (void) +{ + int i; + int max_regno = max_reg_num (); + + for (i = 0; i < max_regno; i++) + reg_equiv_init (i) = ira_reg_equiv[i].init_insns; +} + +/* Update equiv regno from movement of FROM_REGNO to TO_REGNO. INSNS + are insns which were generated for such movement. It is assumed + that FROM_REGNO and TO_REGNO always have the same value at the + point of any move containing such registers. This function is used + to update equiv info for register shuffles on the region borders + and for caller save/restore insns. */ +void +ira_update_equiv_info_by_shuffle_insn (int to_regno, int from_regno, rtx insns) +{ + rtx insn, x, note; + + if (! ira_reg_equiv[from_regno].defined_p + && (! ira_reg_equiv[to_regno].defined_p + || ((x = ira_reg_equiv[to_regno].memory) != NULL_RTX + && ! MEM_READONLY_P (x)))) + return; + insn = insns; + if (NEXT_INSN (insn) != NULL_RTX) + { + if (! ira_reg_equiv[to_regno].defined_p) + { + ira_assert (ira_reg_equiv[to_regno].init_insns == NULL_RTX); + return; + } + ira_reg_equiv[to_regno].defined_p = false; + ira_reg_equiv[to_regno].memory + = ira_reg_equiv[to_regno].constant + = ira_reg_equiv[to_regno].invariant + = ira_reg_equiv[to_regno].init_insns = NULL_RTX; + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + fprintf (ira_dump_file, + " Invalidating equiv info for reg %d\n", to_regno); + return; + } + /* It is possible that FROM_REGNO still has no equivalence because + in shuffles to_regno<-from_regno and from_regno<-to_regno the 2nd + insn was not processed yet. */ + if (ira_reg_equiv[from_regno].defined_p) + { + ira_reg_equiv[to_regno].defined_p = true; + if ((x = ira_reg_equiv[from_regno].memory) != NULL_RTX) + { + ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX + && ira_reg_equiv[from_regno].constant == NULL_RTX); + ira_assert (ira_reg_equiv[to_regno].memory == NULL_RTX + || rtx_equal_p (ira_reg_equiv[to_regno].memory, x)); + ira_reg_equiv[to_regno].memory = x; + if (! MEM_READONLY_P (x)) + /* We don't add the insn to insn init list because memory + equivalence is just to say what memory is better to use + when the pseudo is spilled. */ + return; + } + else if ((x = ira_reg_equiv[from_regno].constant) != NULL_RTX) + { + ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX); + ira_assert (ira_reg_equiv[to_regno].constant == NULL_RTX + || rtx_equal_p (ira_reg_equiv[to_regno].constant, x)); + ira_reg_equiv[to_regno].constant = x; + } + else + { + x = ira_reg_equiv[from_regno].invariant; + ira_assert (x != NULL_RTX); + ira_assert (ira_reg_equiv[to_regno].invariant == NULL_RTX + || rtx_equal_p (ira_reg_equiv[to_regno].invariant, x)); + ira_reg_equiv[to_regno].invariant = x; + } + if (find_reg_note (insn, REG_EQUIV, x) == NULL_RTX) + { + note = set_unique_reg_note (insn, REG_EQUIV, x); + gcc_assert (note != NULL_RTX); + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + { + fprintf (ira_dump_file, + " Adding equiv note to insn %u for reg %d ", + INSN_UID (insn), to_regno); + print_value_slim (ira_dump_file, x, 1); + fprintf (ira_dump_file, "\n"); + } + } + } + ira_reg_equiv[to_regno].init_insns + = gen_rtx_INSN_LIST (VOIDmode, insn, + ira_reg_equiv[to_regno].init_insns); + if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL) + fprintf (ira_dump_file, + " Adding equiv init move insn %u to reg %d\n", + INSN_UID (insn), to_regno); +} + /* Fix values of array REG_EQUIV_INIT after live range splitting done by IRA. */ static void @@ -2221,6 +2296,7 @@ fix_reg_equiv_init (void) prev = x; else { + /* Remove the wrong list element. */ if (prev == NULL_RTX) reg_equiv_init (i) = next; else @@ -2360,6 +2436,46 @@ mark_elimination (int from, int to) +/* The length of the following array. */ +int ira_reg_equiv_len; + +/* Info about equiv. info for each register. */ +struct ira_reg_equiv *ira_reg_equiv; + +/* Expand ira_reg_equiv if necessary. */ +void +ira_expand_reg_equiv (void) +{ + int old = ira_reg_equiv_len; + + if (ira_reg_equiv_len > max_reg_num ()) + return; + ira_reg_equiv_len = max_reg_num () * 3 / 2 + 1; + ira_reg_equiv + = (struct ira_reg_equiv *) xrealloc (ira_reg_equiv, + ira_reg_equiv_len + * sizeof (struct ira_reg_equiv)); + gcc_assert (old < ira_reg_equiv_len); + memset (ira_reg_equiv + old, 0, + sizeof (struct ira_reg_equiv) * (ira_reg_equiv_len - old)); +} + +static void +init_reg_equiv (void) +{ + ira_reg_equiv_len = 0; + ira_reg_equiv = NULL; + ira_expand_reg_equiv (); +} + +static void +finish_reg_equiv (void) +{ + free (ira_reg_equiv); +} + + + struct equivalence { /* Set when a REG_EQUIV note is found or created. Use to @@ -2733,7 +2849,8 @@ no_equiv (rtx reg, const_rtx store ATTRIBUTE_UNUSED, should keep their initialization insns. */ if (reg_equiv[regno].is_arg_equivalence) return; - reg_equiv_init (regno) = NULL_RTX; + ira_reg_equiv[regno].defined_p = false; + ira_reg_equiv[regno].init_insns = NULL_RTX; for (; list; list = XEXP (list, 1)) { rtx insn = XEXP (list, 0); @@ -2769,7 +2886,7 @@ static int recorded_label_ref; value into the using insn. If it succeeds, we can eliminate the register completely. - Initialize the REG_EQUIV_INIT array of initializing insns. + Initialize init_insns in ira_reg_equiv array. Return non-zero if jump label rebuilding should be done. */ static int @@ -2844,14 +2961,16 @@ update_equiv_regs (void) gcc_assert (REG_P (dest)); regno = REGNO (dest); - /* Note that we don't want to clear reg_equiv_init even if there - are multiple sets of this register. */ + /* Note that we don't want to clear init_insns in + ira_reg_equiv even if there are multiple sets of this + register. */ reg_equiv[regno].is_arg_equivalence = 1; /* Record for reload that this is an equivalencing insn. */ if (rtx_equal_p (src, XEXP (note, 0))) - reg_equiv_init (regno) - = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno)); + ira_reg_equiv[regno].init_insns + = gen_rtx_INSN_LIST (VOIDmode, insn, + ira_reg_equiv[regno].init_insns); /* Continue normally in case this is a candidate for replacements. */ @@ -2951,8 +3070,9 @@ update_equiv_regs (void) /* If we haven't done so, record for reload that this is an equivalencing insn. */ if (!reg_equiv[regno].is_arg_equivalence) - reg_equiv_init (regno) - = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno)); + ira_reg_equiv[regno].init_insns + = gen_rtx_INSN_LIST (VOIDmode, insn, + ira_reg_equiv[regno].init_insns); /* Record whether or not we created a REG_EQUIV note for a LABEL_REF. We might end up substituting the LABEL_REF for uses of the @@ -3052,7 +3172,7 @@ update_equiv_regs (void) { /* This insn makes the equivalence, not the one initializing the register. */ - reg_equiv_init (regno) + ira_reg_equiv[regno].init_insns = gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX); df_notes_rescan (init_insn); } @@ -3106,9 +3226,10 @@ update_equiv_regs (void) /* reg_equiv[REGNO].replace gets set only when REG_N_REFS[REGNO] is 2, i.e. the register is set - once and used once. (If it were only set, but not used, - flow would have deleted the setting insns.) Hence - there can only be one insn in reg_equiv[REGNO].init_insns. */ + once and used once. (If it were only set, but + not used, flow would have deleted the setting + insns.) Hence there can only be one insn in + reg_equiv[REGNO].init_insns. */ gcc_assert (reg_equiv[regno].init_insns && !XEXP (reg_equiv[regno].init_insns, 1)); equiv_insn = XEXP (reg_equiv[regno].init_insns, 0); @@ -3155,7 +3276,7 @@ update_equiv_regs (void) reg_equiv[regno].init_insns = XEXP (reg_equiv[regno].init_insns, 1); - reg_equiv_init (regno) = NULL_RTX; + ira_reg_equiv[regno].init_insns = NULL_RTX; bitmap_set_bit (cleared_regs, regno); } /* Move the initialization of the register to just before @@ -3188,7 +3309,7 @@ update_equiv_regs (void) if (insn == BB_HEAD (bb)) BB_HEAD (bb) = PREV_INSN (insn); - reg_equiv_init (regno) + ira_reg_equiv[regno].init_insns = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX); bitmap_set_bit (cleared_regs, regno); } @@ -3236,6 +3357,88 @@ update_equiv_regs (void) +/* Set up fields memory, constant, and invariant from init_insns in + the structures of array ira_reg_equiv. */ +static void +setup_reg_equiv (void) +{ + int i; + rtx elem, insn, set, x; + + for (i = FIRST_PSEUDO_REGISTER; i < ira_reg_equiv_len; i++) + for (elem = ira_reg_equiv[i].init_insns; elem; elem = XEXP (elem, 1)) + { + insn = XEXP (elem, 0); + set = single_set (insn); + + /* Init insns can set up equivalence when the reg is a destination or + a source (in this case the destination is memory). */ + if (set != 0 && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set)))) + { + if ((x = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL) + x = XEXP (x, 0); + else if (REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) == (unsigned int) i) + x = SET_SRC (set); + else + { + gcc_assert (REG_P (SET_SRC (set)) + && REGNO (SET_SRC (set)) == (unsigned int) i); + x = SET_DEST (set); + } + if (! function_invariant_p (x) + || ! flag_pic + /* A function invariant is often CONSTANT_P but may + include a register. We promise to only pass + CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */ + || (CONSTANT_P (x) && LEGITIMATE_PIC_OPERAND_P (x))) + { + /* It can happen that a REG_EQUIV note contains a MEM + that is not a legitimate memory operand. As later + stages of reload assume that all addresses found in + the lra_regno_equiv_* arrays were originally + legitimate, we ignore such REG_EQUIV notes. */ + if (memory_operand (x, VOIDmode)) + { + ira_reg_equiv[i].defined_p = true; + ira_reg_equiv[i].memory = x; + continue; + } + else if (function_invariant_p (x)) + { + enum machine_mode mode; + + mode = GET_MODE (SET_DEST (set)); + if (GET_CODE (x) == PLUS + || x == frame_pointer_rtx || x == arg_pointer_rtx) + /* This is PLUS of frame pointer and a constant, + or fp, or argp. */ + ira_reg_equiv[i].invariant = x; + else if (targetm.legitimate_constant_p (mode, x)) + ira_reg_equiv[i].constant = x; + else + { + ira_reg_equiv[i].memory = force_const_mem (mode, x); + if (ira_reg_equiv[i].memory == NULL_RTX) + { + ira_reg_equiv[i].defined_p = false; + ira_reg_equiv[i].init_insns = NULL_RTX; + break; + } + } + ira_reg_equiv[i].defined_p = true; + continue; + } + } + } + ira_reg_equiv[i].defined_p = false; + ira_reg_equiv[i].init_insns = NULL_RTX; + break; + } +} + + + /* Print chain C to FILE. */ static void print_insn_chain (FILE *file, struct insn_chain *c) @@ -4130,6 +4333,11 @@ allocate_initial_values (void) } } + +/* True when we use LRA instead of reload pass for the current + function. */ +bool ira_use_lra_p; + /* All natural loops. */ struct loops ira_loops; @@ -4147,6 +4355,31 @@ ira (FILE *f) bool loops_p; int max_regno_before_ira, ira_max_point_before_emit; int rebuild_p; + bool saved_flag_caller_saves = flag_caller_saves; + enum ira_region saved_flag_ira_region = flag_ira_region; + + ira_conflicts_p = optimize > 0; + + ira_use_lra_p = targetm.lra_p (); + /* If there are too many pseudos and/or basic blocks (e.g. 10K + pseudos and 10K blocks or 100K pseudos and 1K blocks), we will + use simplified and faster algorithms in LRA. */ + lra_simple_p + = (ira_use_lra_p && max_reg_num () >= (1 << 26) / last_basic_block); + if (lra_simple_p) + { + /* It permits to skip live range splitting in LRA. */ + flag_caller_saves = false; + /* There is no sense to do regional allocation when we use + simplified LRA. */ + flag_ira_region = IRA_REGION_ONE; + ira_conflicts_p = false; + } + +#ifndef IRA_NO_OBSTACK + gcc_obstack_init (&ira_obstack); +#endif + bitmap_obstack_initialize (&ira_bitmap_obstack); if (flag_caller_saves) init_caller_save (); @@ -4162,7 +4395,6 @@ ira (FILE *f) ira_dump_file = stderr; } - ira_conflicts_p = optimize > 0; setup_prohibited_mode_move_regs (); df_note_add_problem (); @@ -4188,30 +4420,18 @@ ira (FILE *f) if (resize_reg_info () && flag_ira_loop_pressure) ira_set_pseudo_classes (true, ira_dump_file); + init_reg_equiv (); rebuild_p = update_equiv_regs (); + setup_reg_equiv (); + setup_reg_equiv_init (); -#ifndef IRA_NO_OBSTACK - gcc_obstack_init (&ira_obstack); -#endif - bitmap_obstack_initialize (&ira_bitmap_obstack); - if (optimize) + if (optimize && rebuild_p) { - max_regno = max_reg_num (); - ira_reg_equiv_len = max_regno; - ira_reg_equiv_invariant_p - = (bool *) ira_allocate (max_regno * sizeof (bool)); - memset (ira_reg_equiv_invariant_p, 0, max_regno * sizeof (bool)); - ira_reg_equiv_const = (rtx *) ira_allocate (max_regno * sizeof (rtx)); - memset (ira_reg_equiv_const, 0, max_regno * sizeof (rtx)); - find_reg_equiv_invariant_const (); - if (rebuild_p) - { - timevar_push (TV_JUMP); - rebuild_jump_labels (get_insns ()); - if (purge_all_dead_edges ()) - delete_unreachable_blocks (); - timevar_pop (TV_JUMP); - } + timevar_push (TV_JUMP); + rebuild_jump_labels (get_insns ()); + if (purge_all_dead_edges ()) + delete_unreachable_blocks (); + timevar_pop (TV_JUMP); } allocated_reg_info_size = max_reg_num (); @@ -4226,7 +4446,7 @@ ira (FILE *f) find_moveable_pseudos (); max_regno_before_ira = max_reg_num (); - ira_setup_eliminable_regset (); + ira_setup_eliminable_regset (true); ira_overall_cost = ira_reg_cost = ira_mem_cost = 0; ira_load_cost = ira_store_cost = ira_shuffle_cost = 0; @@ -4263,19 +4483,32 @@ ira (FILE *f) ira_emit (loops_p); + max_regno = max_reg_num (); if (ira_conflicts_p) { - max_regno = max_reg_num (); - if (! loops_p) - ira_initiate_assign (); + { + if (! ira_use_lra_p) + ira_initiate_assign (); + } else { expand_reg_info (); - if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL) - fprintf (ira_dump_file, "Flattening IR\n"); - ira_flattening (max_regno_before_ira, ira_max_point_before_emit); + if (ira_use_lra_p) + { + ira_allocno_t a; + ira_allocno_iterator ai; + + FOR_EACH_ALLOCNO (a, ai) + ALLOCNO_REGNO (a) = REGNO (ALLOCNO_EMIT_DATA (a)->reg); + } + else + { + if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL) + fprintf (ira_dump_file, "Flattening IR\n"); + ira_flattening (max_regno_before_ira, ira_max_point_before_emit); + } /* New insns were generated: add notes and recalculate live info. */ df_analyze (); @@ -4289,9 +4522,12 @@ ira (FILE *f) current_loops = &ira_loops; record_loop_exits (); - setup_allocno_assignment_flags (); - ira_initiate_assign (); - ira_reassign_conflict_allocnos (max_regno); + if (! ira_use_lra_p) + { + setup_allocno_assignment_flags (); + ira_initiate_assign (); + ira_reassign_conflict_allocnos (max_regno); + } } } @@ -4338,6 +4574,13 @@ ira (FILE *f) /* See comment for find_moveable_pseudos call. */ if (ira_conflicts_p) move_unallocated_pseudos (); + + /* Restore original values. */ + if (lra_simple_p) + { + flag_caller_saves = saved_flag_caller_saves; + flag_ira_region = saved_flag_ira_region; + } } static void @@ -4349,46 +4592,77 @@ do_reload (void) if (flag_ira_verbose < 10) ira_dump_file = dump_file; - df_set_flags (DF_NO_INSN_RESCAN); - build_insn_chain (); + timevar_push (TV_RELOAD); + if (ira_use_lra_p) + { + if (current_loops != NULL) + { + release_recorded_exits (); + flow_loops_free (&ira_loops); + free_dominance_info (CDI_DOMINATORS); + } + FOR_ALL_BB (bb) + bb->loop_father = NULL; + current_loops = NULL; + + if (ira_conflicts_p) + ira_free (ira_spilled_reg_stack_slots); + + ira_destroy (); - need_dce = reload (get_insns (), ira_conflicts_p); + lra (ira_dump_file); + /* ???!!! Move it before lra () when we use ira_reg_equiv in + LRA. */ + VEC_free (reg_equivs_t, gc, reg_equivs); + reg_equivs = NULL; + need_dce = false; + } + else + { + df_set_flags (DF_NO_INSN_RESCAN); + build_insn_chain (); + + need_dce = reload (get_insns (), ira_conflicts_p); + + } + + timevar_pop (TV_RELOAD); timevar_push (TV_IRA); - if (ira_conflicts_p) + if (ira_conflicts_p && ! ira_use_lra_p) { ira_free (ira_spilled_reg_stack_slots); - ira_finish_assign (); } + if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL && overall_cost_before != ira_overall_cost) fprintf (ira_dump_file, "+++Overall after reload %d\n", ira_overall_cost); - ira_destroy (); flag_ira_share_spill_slots = saved_flag_ira_share_spill_slots; - if (current_loops != NULL) + if (! ira_use_lra_p) { - release_recorded_exits (); - flow_loops_free (&ira_loops); - free_dominance_info (CDI_DOMINATORS); + ira_destroy (); + if (current_loops != NULL) + { + release_recorded_exits (); + flow_loops_free (&ira_loops); + free_dominance_info (CDI_DOMINATORS); + } + FOR_ALL_BB (bb) + bb->loop_father = NULL; + current_loops = NULL; + + regstat_free_ri (); + regstat_free_n_sets_and_refs (); } - FOR_ALL_BB (bb) - bb->loop_father = NULL; - current_loops = NULL; - - regstat_free_ri (); - regstat_free_n_sets_and_refs (); if (optimize) - { - cleanup_cfg (CLEANUP_EXPENSIVE); + cleanup_cfg (CLEANUP_EXPENSIVE); - ira_free (ira_reg_equiv_invariant_p); - ira_free (ira_reg_equiv_const); - } + finish_reg_equiv (); bitmap_obstack_release (&ira_bitmap_obstack); #ifndef IRA_NO_OBSTACK |