From: Vladimir Makarov Date: Tue, 6 Jan 2009 03:50:07 +0000 (+0000) Subject: re PR rtl-optimization/38583 (huge test case makes register allocator run out of... X-Git-Tag: releases/gcc-4.4.0~1013 X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=311aab0649dded5e7f9bb84dd78040871d6812d9;p=gcc.git re PR rtl-optimization/38583 (huge test case makes register allocator run out of memory while constructing the conflict graph) 2009-01-05 Vladimir Makarov PR rtl-optimization/38583 * params.h (IRA_MAX_CONFLICT_TABLE_SIZE): New macro. * params.def (ira-max-conflict-table-size): New. * doc/invoke.texi (ira-max-conflict-table-size): Decribe. * ira.h (ira_conflicts_p): New external definition. * ira-conflicts.c (build_conflict_bit_table): Do not build too big table. Report this. Return result of building. (ira_build_conflicts): Use ira_conflicts_p. Check result of building conflict table. * ira-color.c (fast_allocation): Use num instead of ira_allocnos_num. (ira_color): Use ira_conflicts_p. * global.c: Include ira.h. (pseudo_for_reload_consideration_p, build_insn_chain): Use ira_conflicts_p. * Makefile.in (global.o): Add ira.h. * ira-build.c (mark_all_loops_for_removal, propagate_some_info_from_allocno): New. (remove_unnecessary_allocnos): Call propagate_some_info_from_allocno. (remove_low_level_allocnos): New. (remove_unnecessary_regions): Add parameter. Call mark_all_loops_for_removal and remove_low_level_allocnos. Pass parameter to remove_unnecessary_regions. (ira_build): Remove all regions but root if the conflict table was not built. Update conflict hard regs for allocnos crossing calls. * ira.c (ira_conflicts_p): New global. (ira): Define and use ira_conflicts_p. * reload1.c (compute_use_by_pseudos, reload, count_pseudo, count_spilled_pseudo, find_reg, alter_reg, finish_spills, emit_input_reload_insns, delete_output_reload): Use ira_conflicts_p. From-SVN: r143112 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5853ca870c9a..0fda2b414dc6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,48 @@ +2009-01-05 Vladimir Makarov + + PR rtl-optimization/38583 + * params.h (IRA_MAX_CONFLICT_TABLE_SIZE): New macro. + + * params.def (ira-max-conflict-table-size): New. + + * doc/invoke.texi (ira-max-conflict-table-size): Decribe. + + * ira.h (ira_conflicts_p): New external definition. + + * ira-conflicts.c (build_conflict_bit_table): Do not build too big + table. Report this. Return result of building. + (ira_build_conflicts): Use ira_conflicts_p. Check result of + building conflict table. + + * ira-color.c (fast_allocation): Use num instead of + ira_allocnos_num. + (ira_color): Use ira_conflicts_p. + + * global.c: Include ira.h. + (pseudo_for_reload_consideration_p, build_insn_chain): Use + ira_conflicts_p. + + * Makefile.in (global.o): Add ira.h. + + * ira-build.c (mark_all_loops_for_removal, + propagate_some_info_from_allocno): New. + (remove_unnecessary_allocnos): Call + propagate_some_info_from_allocno. + (remove_low_level_allocnos): New. + (remove_unnecessary_regions): Add parameter. Call + mark_all_loops_for_removal and remove_low_level_allocnos. Pass + parameter to remove_unnecessary_regions. + (ira_build): Remove all regions but root if the conflict table was + not built. Update conflict hard regs for allocnos crossing calls. + + * ira.c (ira_conflicts_p): New global. + (ira): Define and use ira_conflicts_p. + + * reload1.c (compute_use_by_pseudos, reload, count_pseudo, + count_spilled_pseudo, find_reg, alter_reg, finish_spills, + emit_input_reload_insns, delete_output_reload): Use + ira_conflicts_p. + 2009-01-06 Ben Elliston * gengtype-lex.l (YY_NO_INPUT): Define. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 1b89c0d8e638..83c503621ae1 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2860,7 +2860,7 @@ bitmap.o : bitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(FLAGS_H) reload.h $(FUNCTION_H) $(RECOG_H) $(REGS_H) hard-reg-set.h \ insn-config.h output.h $(TOPLEV_H) $(TM_P_H) $(MACHMODE_H) tree-pass.h \ - $(TIMEVAR_H) vecprim.h $(DF_H) $(DBGCNT_H) $(RA_H) + $(TIMEVAR_H) vecprim.h $(DF_H) $(DBGCNT_H) $(RA_H) ira.h ra-conflict.o : ra-conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(FLAGS_H) reload.h $(FUNCTION_H) $(RECOG_H) $(REGS_H) hard-reg-set.h \ insn-config.h output.h $(TOPLEV_H) $(TM_P_H) $(MACHMODE_H) tree-pass.h \ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 12a3cabaf318..47e718b1a20f 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -7617,6 +7617,15 @@ given number of the most frequently executed loops will form regions for the regional register allocation. The default value of the parameter is 100. +@item ira-max-conflict-table-size +Although IRA uses a sophisticated algorithm of compression conflict +table, the table can be still big for huge functions. If the conflict +table for a function could be more than size in MB given by the +parameter, the conflict table is not built and faster, simpler, and +lower quality register allocation algorithm will be used. The +algorithm do not use pseudo-register conflicts. The default value of +the parameter is 2000. + @end table @end table diff --git a/gcc/global.c b/gcc/global.c index 824fcf0f702f..abf070d91c27 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "vecprim.h" #include "dbgcnt.h" #include "ra.h" +#include "ira.h" /* This pass of the compiler performs global register allocation. It assigns hard register numbers to all the pseudo registers @@ -1394,7 +1395,7 @@ pseudo_for_reload_consideration_p (int regno) /* Consider spilled pseudos too for IRA because they still have a chance to get hard-registers in the reload when IRA is used. */ return (reg_renumber[regno] >= 0 - || (flag_ira && optimize && flag_ira_share_spill_slots)); + || (flag_ira && ira_conflicts_p && flag_ira_share_spill_slots)); } /* Walk the insns of the current function and build reload_insn_chain, @@ -1483,7 +1484,7 @@ build_insn_chain (void) if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0 - || (flag_ira && optimize)) + || (flag_ira && ira_conflicts_p)) && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL))) { rtx reg = DF_REF_REG (def); diff --git a/gcc/ira-build.c b/gcc/ira-build.c index 9e47333d46e5..00df69c6d2e6 100644 --- a/gcc/ira-build.c +++ b/gcc/ira-build.c @@ -1751,6 +1751,33 @@ mark_loops_for_removal (void) ira_free (sorted_loops); } +/* Mark all loops but root for removing. */ +static void +mark_all_loops_for_removal (void) +{ + int i; + loop_p loop; + + for (i = 0; VEC_iterate (loop_p, ira_loops.larray, i, loop); i++) + if (ira_loop_nodes[i].regno_allocno_map != NULL) + { + if (ira_loop_nodes[i].parent == NULL) + { + /* Don't remove the root. */ + ira_loop_nodes[i].to_remove_p = false; + continue; + } + ira_loop_nodes[i].to_remove_p = true; + if (internal_flag_ira_verbose > 1 && ira_dump_file != NULL) + fprintf + (ira_dump_file, + " Mark loop %d (header %d, freq %d, depth %d) for removal\n", + ira_loop_nodes[i].loop->num, + ira_loop_nodes[i].loop->header->index, + ira_loop_nodes[i].loop->header->frequency, + loop_depth (ira_loop_nodes[i].loop)); + } +} /* Definition of vector of loop tree nodes. */ DEF_VEC_P(ira_loop_tree_node_t); @@ -1856,6 +1883,43 @@ ira_rebuild_regno_allocno_list (int regno) fprintf (ira_dump_file, " Rebuilding regno allocno list for %d\n", regno); } +/* Propagate info from allocno FROM_A to allocno A. */ +static void +propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a) +{ + enum reg_class cover_class; + + IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), + ALLOCNO_CONFLICT_HARD_REGS (from_a)); +#ifdef STACK_REGS + if (ALLOCNO_NO_STACK_REG_P (from_a)) + ALLOCNO_NO_STACK_REG_P (a) = true; +#endif + ALLOCNO_NREFS (a) += ALLOCNO_NREFS (from_a); + ALLOCNO_FREQ (a) += ALLOCNO_FREQ (from_a); + ALLOCNO_CALL_FREQ (a) += ALLOCNO_CALL_FREQ (from_a); + IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), + ALLOCNO_TOTAL_CONFLICT_HARD_REGS (from_a)); + ALLOCNO_CALLS_CROSSED_NUM (a) += ALLOCNO_CALLS_CROSSED_NUM (from_a); + ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) + += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a); + if (! ALLOCNO_BAD_SPILL_P (from_a)) + ALLOCNO_BAD_SPILL_P (a) = false; +#ifdef STACK_REGS + if (ALLOCNO_TOTAL_NO_STACK_REG_P (from_a)) + ALLOCNO_TOTAL_NO_STACK_REG_P (a) = true; +#endif + cover_class = ALLOCNO_COVER_CLASS (from_a); + ira_assert (cover_class == ALLOCNO_COVER_CLASS (a)); + ira_allocate_and_accumulate_costs (&ALLOCNO_HARD_REG_COSTS (a), cover_class, + ALLOCNO_HARD_REG_COSTS (from_a)); + ira_allocate_and_accumulate_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), + cover_class, + ALLOCNO_CONFLICT_HARD_REG_COSTS (from_a)); + ALLOCNO_COVER_CLASS_COST (a) += ALLOCNO_COVER_CLASS_COST (from_a); + ALLOCNO_MEMORY_COST (a) += ALLOCNO_MEMORY_COST (from_a); +} + /* Remove allocnos from loops removed from the allocation consideration. */ static void @@ -1863,7 +1927,6 @@ remove_unnecessary_allocnos (void) { int regno; bool merged_p, rebuild_p; - enum reg_class cover_class; ira_allocno_t a, prev_a, next_a, parent_a; ira_loop_tree_node_t a_node, parent; allocno_live_range_t r; @@ -1890,9 +1953,9 @@ remove_unnecessary_allocnos (void) ; if (parent_a == NULL) { - /* There are no allocnos with the same regno in upper - region -- just move the allocno to the upper - region. */ + /* There are no allocnos with the same regno in + upper region -- just move the allocno to the + upper region. */ prev_a = a; ALLOCNO_LOOP_TREE_NODE (a) = parent; parent->regno_allocno_map[regno] = a; @@ -1911,43 +1974,10 @@ remove_unnecessary_allocnos (void) change_allocno_in_range_list (r, parent_a); ALLOCNO_LIVE_RANGES (parent_a) = ira_merge_allocno_live_ranges - (r, ALLOCNO_LIVE_RANGES (parent_a)); + (r, ALLOCNO_LIVE_RANGES (parent_a)); merged_p = true; ALLOCNO_LIVE_RANGES (a) = NULL; - IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (parent_a), - ALLOCNO_CONFLICT_HARD_REGS (a)); -#ifdef STACK_REGS - if (ALLOCNO_NO_STACK_REG_P (a)) - ALLOCNO_NO_STACK_REG_P (parent_a) = true; -#endif - ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a); - ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a); - ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a); - IOR_HARD_REG_SET - (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (parent_a), - ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a)); - ALLOCNO_CALLS_CROSSED_NUM (parent_a) - += ALLOCNO_CALLS_CROSSED_NUM (a); - ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a) - += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a); - if (! ALLOCNO_BAD_SPILL_P (a)) - ALLOCNO_BAD_SPILL_P (parent_a) = false; -#ifdef STACK_REGS - if (ALLOCNO_TOTAL_NO_STACK_REG_P (a)) - ALLOCNO_TOTAL_NO_STACK_REG_P (parent_a) = true; -#endif - cover_class = ALLOCNO_COVER_CLASS (a); - ira_assert (cover_class == ALLOCNO_COVER_CLASS (parent_a)); - ira_allocate_and_accumulate_costs - (&ALLOCNO_HARD_REG_COSTS (parent_a), cover_class, - ALLOCNO_HARD_REG_COSTS (a)); - ira_allocate_and_accumulate_costs - (&ALLOCNO_CONFLICT_HARD_REG_COSTS (parent_a), - cover_class, - ALLOCNO_CONFLICT_HARD_REG_COSTS (a)); - ALLOCNO_COVER_CLASS_COST (parent_a) - += ALLOCNO_COVER_CLASS_COST (a); - ALLOCNO_MEMORY_COST (parent_a) += ALLOCNO_MEMORY_COST (a); + propagate_some_info_from_allocno (parent_a, a); finish_allocno (a); } } @@ -1968,15 +1998,88 @@ remove_unnecessary_allocnos (void) ira_free (regno_allocnos); } -/* Remove loops from consideration. We remove loops for which a - separate allocation will not improve the result. We have to do - this after allocno creation and their costs and cover class - evaluation because only after that the register pressure can be - known and is calculated. */ +/* Remove allocnos from all loops but the root. */ static void -remove_unnecessary_regions (void) +remove_low_level_allocnos (void) { - mark_loops_for_removal (); + int regno; + bool merged_p, propagate_p; + ira_allocno_t a, top_a; + ira_loop_tree_node_t a_node, parent; + allocno_live_range_t r; + ira_allocno_iterator ai; + + merged_p = false; + FOR_EACH_ALLOCNO (a, ai) + { + a_node = ALLOCNO_LOOP_TREE_NODE (a); + if (a_node == ira_loop_tree_root || ALLOCNO_CAP_MEMBER (a) != NULL) + continue; + regno = ALLOCNO_REGNO (a); + if ((top_a = ira_loop_tree_root->regno_allocno_map[regno]) == NULL) + { + ALLOCNO_LOOP_TREE_NODE (a) = ira_loop_tree_root; + ira_loop_tree_root->regno_allocno_map[regno] = a; + continue; + } + propagate_p = a_node->parent->regno_allocno_map[regno] == NULL; + /* Remove the allocno and update info of allocno in the upper + region. */ + r = ALLOCNO_LIVE_RANGES (a); + change_allocno_in_range_list (r, top_a); + ALLOCNO_LIVE_RANGES (top_a) + = ira_merge_allocno_live_ranges (r, ALLOCNO_LIVE_RANGES (top_a)); + merged_p = true; + ALLOCNO_LIVE_RANGES (a) = NULL; + if (propagate_p) + propagate_some_info_from_allocno (top_a, a); + } + FOR_EACH_ALLOCNO (a, ai) + { + a_node = ALLOCNO_LOOP_TREE_NODE (a); + if (a_node == ira_loop_tree_root) + continue; + parent = a_node->parent; + regno = ALLOCNO_REGNO (a); + if (ALLOCNO_CAP_MEMBER (a) != NULL) + ira_assert (ALLOCNO_CAP (a) != NULL); + else if (ALLOCNO_CAP (a) == NULL) + ira_assert (parent->regno_allocno_map[regno] != NULL); + } + FOR_EACH_ALLOCNO (a, ai) + { + regno = ALLOCNO_REGNO (a); + if (ira_loop_tree_root->regno_allocno_map[regno] == a) + { + ira_regno_allocno_map[regno] = a; + ALLOCNO_NEXT_REGNO_ALLOCNO (a) = NULL; + ALLOCNO_CAP_MEMBER (a) = NULL; + COPY_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), + ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a)); +#ifdef STACK_REGS + if (ALLOCNO_TOTAL_NO_STACK_REG_P (a)) + ALLOCNO_NO_STACK_REG_P (a) = true; +#endif + } + else + finish_allocno (a); + } + if (merged_p) + ira_rebuild_start_finish_chains (); +} + +/* Remove loops from consideration. We remove all loops except for + root if ALL_P or loops for which a separate allocation will not + improve the result. We have to do this after allocno creation and + their costs and cover class evaluation because only after that the + register pressure can be known and is calculated. */ +static void +remove_unnecessary_regions (bool all_p) +{ + if (all_p) + mark_all_loops_for_removal (); + else + mark_loops_for_removal (); children_vec = VEC_alloc (ira_loop_tree_node_t, heap, last_basic_block + VEC_length (loop_p, ira_loops.larray)); @@ -1985,7 +2088,10 @@ remove_unnecessary_regions (void) last_basic_block + VEC_length (loop_p, ira_loops.larray)); remove_uneccesary_loop_nodes_from_loop_tree (ira_loop_tree_root) ; VEC_free (ira_loop_tree_node_t, heap, children_vec); - remove_unnecessary_allocnos (); + if (all_p) + remove_low_level_allocnos (); + else + remove_unnecessary_allocnos (); while (VEC_length (ira_loop_tree_node_t, removed_loop_vec) > 0) finish_loop_tree_node (VEC_pop (ira_loop_tree_node_t, removed_loop_vec)); VEC_free (ira_loop_tree_node_t, heap, removed_loop_vec); @@ -2668,7 +2774,7 @@ ira_build (bool loops_p) create_allocnos (); ira_costs (); ira_create_allocno_live_ranges (); - remove_unnecessary_regions (); + remove_unnecessary_regions (false); ira_compress_allocno_live_ranges (); update_bad_spill_attribute (); loops_p = more_one_region_p (); @@ -2685,6 +2791,29 @@ ira_build (bool loops_p) sort_conflict_id_allocno_map (); setup_min_max_conflict_allocno_ids (); ira_build_conflicts (); + if (! ira_conflicts_p) + { + ira_allocno_t a; + ira_allocno_iterator ai; + + /* Remove all regions but root one. */ + if (loops_p) + { + remove_unnecessary_regions (true); + loops_p = false; + } + /* We don't save hard registers around calls for fast allocation + -- add caller clobbered registers as conflicting ones to + allocno crossing calls. */ + FOR_EACH_ALLOCNO (a, ai) + if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) + { + IOR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), + call_used_reg_set); + IOR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (a), + call_used_reg_set); + } + } if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) print_copies (ira_dump_file); if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL) diff --git a/gcc/ira-color.c b/gcc/ira-color.c index c9cb1845fe47..c7c600bc41c5 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -3267,7 +3267,7 @@ fast_allocation (void) * ira_max_point); for (i = 0; i < ira_max_point; i++) CLEAR_HARD_REG_SET (used_hard_regs[i]); - qsort (sorted_allocnos, ira_allocnos_num, sizeof (ira_allocno_t), + qsort (sorted_allocnos, num, sizeof (ira_allocno_t), allocno_priority_compare_func); for (i = 0; i < num; i++) { @@ -3329,7 +3329,7 @@ ira_color (void) ALLOCNO_UPDATED_MEMORY_COST (a) = ALLOCNO_MEMORY_COST (a); ALLOCNO_UPDATED_COVER_CLASS_COST (a) = ALLOCNO_COVER_CLASS_COST (a); } - if (optimize) + if (ira_conflicts_p) color (); else fast_allocation (); diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c index ff116b5da8a1..244d3bc9b3ef 100644 --- a/gcc/ira-conflicts.c +++ b/gcc/ira-conflicts.c @@ -60,8 +60,10 @@ static IRA_INT_TYPE **conflicts; -/* Build allocno conflict table by processing allocno live ranges. */ -static void +/* Build allocno conflict table by processing allocno live ranges. + Return true if the table was built. The table is not built if it + is too big. */ +static bool build_conflict_bit_table (void) { int i, num, id, allocated_words_num, conflict_bit_vec_words_num; @@ -74,6 +76,26 @@ build_conflict_bit_table (void) int allocno_set_words; allocno_set_words = (ira_allocnos_num + IRA_INT_BITS - 1) / IRA_INT_BITS; + allocated_words_num = 0; + FOR_EACH_ALLOCNO (allocno, ai) + { + if (ALLOCNO_MAX (allocno) < ALLOCNO_MIN (allocno)) + continue; + conflict_bit_vec_words_num + = ((ALLOCNO_MAX (allocno) - ALLOCNO_MIN (allocno) + IRA_INT_BITS) + / IRA_INT_BITS); + allocated_words_num += conflict_bit_vec_words_num; + if ((unsigned long long) allocated_words_num * sizeof (IRA_INT_TYPE) + > (unsigned long long) IRA_MAX_CONFLICT_TABLE_SIZE * 1024 * 1024) + { + if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL) + fprintf + (ira_dump_file, + "+++Conflict table will be too big(>%dMB) -- don't use it\n", + IRA_MAX_CONFLICT_TABLE_SIZE); + return false; + } + } allocnos_live = sparseset_alloc (ira_allocnos_num); conflicts = (IRA_INT_TYPE **) ira_allocate (sizeof (IRA_INT_TYPE *) * ira_allocnos_num); @@ -134,6 +156,7 @@ build_conflict_bit_table (void) sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (r->allocno)); } sparseset_free (allocnos_live); + return true; } @@ -743,29 +766,34 @@ ira_build_conflicts (void) ira_allocno_iterator ai; HARD_REG_SET temp_hard_reg_set; - if (optimize) + if (ira_conflicts_p) { - build_conflict_bit_table (); - build_conflicts (); - ira_traverse_loop_tree (true, ira_loop_tree_root, NULL, add_copies); - /* We need finished conflict table for the subsequent call. */ - if (flag_ira_region == IRA_REGION_ALL - || flag_ira_region == IRA_REGION_MIXED) - propagate_copies (); - /* Now we can free memory for the conflict table (see function - build_allocno_conflicts for details). */ - FOR_EACH_ALLOCNO (a, ai) + ira_conflicts_p = build_conflict_bit_table (); + if (ira_conflicts_p) { - if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != conflicts[ALLOCNO_NUM (a)]) - ira_free (conflicts[ALLOCNO_NUM (a)]); + build_conflicts (); + ira_traverse_loop_tree (true, ira_loop_tree_root, NULL, add_copies); + /* We need finished conflict table for the subsequent call. */ + if (flag_ira_region == IRA_REGION_ALL + || flag_ira_region == IRA_REGION_MIXED) + propagate_copies (); + /* Now we can free memory for the conflict table (see function + build_allocno_conflicts for details). */ + FOR_EACH_ALLOCNO (a, ai) + { + if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) + != conflicts[ALLOCNO_NUM (a)]) + ira_free (conflicts[ALLOCNO_NUM (a)]); + } + ira_free (conflicts); } - ira_free (conflicts); } if (! CLASS_LIKELY_SPILLED_P (BASE_REG_CLASS)) CLEAR_HARD_REG_SET (temp_hard_reg_set); else { - COPY_HARD_REG_SET (temp_hard_reg_set, reg_class_contents[BASE_REG_CLASS]); + COPY_HARD_REG_SET (temp_hard_reg_set, + reg_class_contents[BASE_REG_CLASS]); AND_COMPL_HARD_REG_SET (temp_hard_reg_set, ira_no_alloc_regs); AND_HARD_REG_SET (temp_hard_reg_set, call_used_reg_set); } @@ -796,6 +824,7 @@ ira_build_conflicts (void) } } } - if (optimize && internal_flag_ira_verbose > 2 && ira_dump_file != NULL) + if (optimize && ira_conflicts_p + && internal_flag_ira_verbose > 2 && ira_dump_file != NULL) print_conflicts (ira_dump_file, false); } diff --git a/gcc/ira.c b/gcc/ira.c index 44f7032bf319..2273512ec23d 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -1827,6 +1827,10 @@ too_high_register_pressure_p (void) /* All natural loops. */ struct loops ira_loops; +/* True if we have allocno conflicts. It is false for non-optimized + mode or when the conflict table is too big. */ +bool ira_conflicts_p; + /* This is the main entry of IRA. */ static void ira (FILE *f) @@ -1851,6 +1855,7 @@ ira (FILE *f) ira_dump_file = stderr; } + ira_conflicts_p = optimize > 0; setup_prohibited_mode_move_regs (); df_note_add_problem (); @@ -1916,6 +1921,8 @@ ira (FILE *f) loops_p = ira_build (optimize && (flag_ira_region == IRA_REGION_ALL || flag_ira_region == IRA_REGION_MIXED)); + + ira_assert (ira_conflicts_p || !loops_p); saved_flag_ira_share_spill_slots = flag_ira_share_spill_slots; if (too_high_register_pressure_p ()) @@ -1929,7 +1936,7 @@ ira (FILE *f) ira_emit (loops_p); - if (optimize) + if (ira_conflicts_p) { max_regno = max_reg_num (); @@ -1963,7 +1970,7 @@ ira (FILE *f) calculate_allocation_cost (); #ifdef ENABLE_IRA_CHECKING - if (optimize) + if (ira_conflicts_p) check_allocation (); #endif @@ -1992,7 +1999,7 @@ ira (FILE *f) allocate_initial_values (reg_equiv_memory_loc); overall_cost_before = ira_overall_cost; - if (optimize) + if (ira_conflicts_p) { fix_reg_equiv_init (); @@ -2015,13 +2022,13 @@ ira (FILE *f) df_set_flags (DF_NO_INSN_RESCAN); build_insn_chain (); - reload_completed = !reload (get_insns (), optimize > 0); + reload_completed = !reload (get_insns (), ira_conflicts_p); timevar_pop (TV_RELOAD); timevar_push (TV_IRA); - if (optimize) + if (ira_conflicts_p) { ira_free (ira_spilled_reg_stack_slots); diff --git a/gcc/ira.h b/gcc/ira.h index 5f964c47a42c..165274d95f70 100644 --- a/gcc/ira.h +++ b/gcc/ira.h @@ -20,6 +20,10 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ +/* True if we have allocno conflicts. It is false for non-optimized + mode or when the conflict table is too big. */ +extern bool ira_conflicts_p; + extern void ira_init_once (void); extern void ira_init (void); extern void ira_finish_once (void); diff --git a/gcc/params.def b/gcc/params.def index ea3015b3640a..d09a8581e330 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -750,6 +750,11 @@ DEFPARAM (PARAM_IRA_MAX_LOOPS_NUM, "max loops number for regional RA", 100, 0, 0) +DEFPARAM (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE, + "ira-max-conflict-table-size", + "max size of conflict table in MB", + 2000, 0, 0) + /* Switch initialization conversion will refuse to create arrays that are bigger than this parameter times the number of switch branches. */ diff --git a/gcc/params.h b/gcc/params.h index 8147b6098484..501259c78e14 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -169,6 +169,8 @@ typedef enum compiler_param PARAM_VALUE (PARAM_USE_CANONICAL_TYPES) #define IRA_MAX_LOOPS_NUM \ PARAM_VALUE (PARAM_IRA_MAX_LOOPS_NUM) +#define IRA_MAX_CONFLICT_TABLE_SIZE \ + PARAM_VALUE (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE) #define SWITCH_CONVERSION_BRANCH_RATIO \ PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO) #endif /* ! GCC_PARAMS_H */ diff --git a/gcc/reload1.c b/gcc/reload1.c index ffde2bf94d82..bbffad0b98dc 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -557,7 +557,7 @@ compute_use_by_pseudos (HARD_REG_SET *to, regset from) which might still contain registers that have not actually been allocated since they have an equivalence. */ - gcc_assert ((flag_ira && optimize) || reload_completed); + gcc_assert ((flag_ira && ira_conflicts_p) || reload_completed); } else add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r); @@ -901,7 +901,7 @@ reload (rtx first, int global) for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) temp_pseudo_reg_arr[n++] = i; - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) /* Ask IRA to order pseudo-registers for better stack slot sharing. */ ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width); @@ -1055,7 +1055,7 @@ reload (rtx first, int global) calculate_needs_all_insns (global); - if (! flag_ira || ! optimize) + if (! flag_ira || ! ira_conflicts_p) /* Don't do it for IRA. We need this info because we don't change live_throughout and dead_or_set for chains when IRA is used. */ @@ -1614,7 +1614,7 @@ calculate_needs_all_insns (int global) reg_equiv_memory_loc [REGNO (SET_DEST (set))])))) { - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) /* Inform IRA about the insn deletion. */ ira_mark_memory_move_deletion (REGNO (SET_DEST (set)), REGNO (SET_SRC (set))); @@ -1723,7 +1723,7 @@ count_pseudo (int reg) || REGNO_REG_SET_P (&spilled_pseudos, reg) /* Ignore spilled pseudo-registers which can be here only if IRA is used. */ - || (flag_ira && optimize && r < 0)) + || (flag_ira && ira_conflicts_p && r < 0)) return; SET_REGNO_REG_SET (&pseudos_counted, reg); @@ -1804,7 +1804,7 @@ count_spilled_pseudo (int spilled, int spilled_nregs, int reg) /* Ignore spilled pseudo-registers which can be here only if IRA is used. */ - if ((flag_ira && optimize && r < 0) + if ((flag_ira && ira_conflicts_p && r < 0) || REGNO_REG_SET_P (&spilled_pseudos, reg) || spilled + spilled_nregs <= r || r + nregs <= spilled) return; @@ -1876,7 +1876,7 @@ find_reg (struct insn_chain *chain, int order) if (! ok) continue; - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) { /* Ask IRA to find a better pseudo-register for spilling. */ @@ -2158,7 +2158,7 @@ alter_reg (int i, int from_reg, bool dont_share_p) unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT; int adjust = 0; - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) { /* Mark the spill for IRA. */ SET_REGNO_REG_SET (&spilled_pseudos, i); @@ -2177,7 +2177,8 @@ alter_reg (int i, int from_reg, bool dont_share_p) enough inherent space and enough total space. Otherwise, we allocate a new slot, making sure that it has no less inherent space, and no less total space, then the previous slot. */ - else if (from_reg == -1 || (!dont_share_p && flag_ira && optimize)) + else if (from_reg == -1 + || (!dont_share_p && flag_ira && ira_conflicts_p)) { rtx stack_slot; @@ -2202,7 +2203,7 @@ alter_reg (int i, int from_reg, bool dont_share_p) adjust); } - if (! dont_share_p && flag_ira && optimize) + if (! dont_share_p && flag_ira && ira_conflicts_p) /* Inform IRA about allocation a new stack slot. */ ira_mark_new_stack_slot (stack_slot, i, total_size); } @@ -3904,7 +3905,7 @@ finish_spills (int global) spill_reg_order[i] = -1; EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi) - if (! flag_ira || ! optimize || reg_renumber[i] >= 0) + if (! flag_ira || ! ira_conflicts_p || reg_renumber[i] >= 0) { /* Record the current hard register the pseudo is allocated to in pseudo_previous_regs so we avoid reallocating it to the @@ -3914,7 +3915,7 @@ finish_spills (int global) SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]); /* Mark it as no longer having a hard register home. */ reg_renumber[i] = -1; - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) /* Inform IRA about the change. */ ira_mark_allocation_change (i); /* We will need to scan everything again. */ @@ -3944,7 +3945,7 @@ finish_spills (int global) } } - if (! flag_ira || ! optimize) + if (! flag_ira || ! ira_conflicts_p) { /* Retry allocating the spilled pseudos. For each reg, merge the various reg sets that indicate which hard regs @@ -3996,7 +3997,7 @@ finish_spills (int global) HARD_REG_SET used_by_pseudos; HARD_REG_SET used_by_pseudos2; - if (! flag_ira || ! optimize) + if (! flag_ira || ! ira_conflicts_p) { /* Don't do it for IRA because IRA and the reload still can assign hard registers to the spilled pseudos on next @@ -6999,7 +7000,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl, && REG_N_SETS (REGNO (old)) == 1) { reg_renumber[REGNO (old)] = REGNO (reloadreg); - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) /* Inform IRA about the change. */ ira_mark_allocation_change (REGNO (old)); alter_reg (REGNO (old), -1, false); @@ -8540,7 +8541,7 @@ delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg) /* For the debugging info, say the pseudo lives in this reload reg. */ reg_renumber[REGNO (reg)] = REGNO (new_reload_reg); - if (flag_ira && optimize) + if (flag_ira && ira_conflicts_p) /* Inform IRA about the change. */ ira_mark_allocation_change (REGNO (reg)); alter_reg (REGNO (reg), -1, false);