From f0a46d8300adc51c430add3e640b289a8222c1b7 Mon Sep 17 00:00:00 2001 From: vmakarov Date: Wed, 3 Sep 2008 20:12:27 +0000 Subject: [PATCH] 2008-09-03 Vladimir Makarov PR rtl-opt/37243 * ira-conflicts.c (REG_SUBREG_P, go_through_subreg): New. (process_regs_for_copy): Process subregs. Refine check when cost is taken into account in ira-costs.c. (process_reg_shuffles): Use REG_SUBREG_P. (add_insn_allocno_copies): Ditto. Ignore modes. * ira-color.c (conflict_allocno_vec): New. (COST_HOP_DIVISOR): New macro. (update_copy_costs_1): Use it. (update_conflict_hard_regno_costs): New function. (assign_hard_reg): Use it. (ira_color): Allocate and free conflict_allocno_vec. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@139949 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 17 +++++++ gcc/ira-color.c | 136 ++++++++++++++++++++++++++++++++++++++++------------ gcc/ira-conflicts.c | 64 +++++++++++++++++++------ 3 files changed, 172 insertions(+), 45 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d6241816a7f..87e5fcc2d49 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,22 @@ 2008-09-03 Vladimir Makarov + PR rtl-opt/37243 + + * ira-conflicts.c (REG_SUBREG_P, go_through_subreg): New. + (process_regs_for_copy): Process subregs. Refine check when cost + is taken into account in ira-costs.c. + (process_reg_shuffles): Use REG_SUBREG_P. + (add_insn_allocno_copies): Ditto. Ignore modes. + + * ira-color.c (conflict_allocno_vec): New. + (COST_HOP_DIVISOR): New macro. + (update_copy_costs_1): Use it. + (update_conflict_hard_regno_costs): New function. + (assign_hard_reg): Use it. + (ira_color): Allocate and free conflict_allocno_vec. + +2008-09-03 Vladimir Makarov + PR rtl-opt/37296 * ira-int.h (ira_sort_insn_chain): Remove. diff --git a/gcc/ira-color.c b/gcc/ira-color.c index a9a64b96ac6..71e3f68aca0 100644 --- a/gcc/ira-color.c +++ b/gcc/ira-color.c @@ -68,6 +68,9 @@ static ira_allocno_t *sorted_allocnos; /* Vec representing the stack of allocnos used during coloring. */ static VEC(ira_allocno_t,heap) *allocno_stack_vec; +/* Vec representing conflict allocnos used during assigning. */ +static VEC(ira_allocno_t,heap) *conflict_allocno_vec; + /* Array used to choose an allocno for spilling. */ static ira_allocno_t *allocnos_for_spilling; @@ -116,6 +119,11 @@ finish_cost_update (void) ira_free (allocno_update_cost_check); } +/* When we traverse allocnos to update hard register costs, the cost + divisor will be multiplied by the following macro value for each + hop from given allocno to directly connected allocnos. */ +#define COST_HOP_DIVISOR 4 + /* This recursive function updates costs (decrease if DECR_P) of the unassigned allocnos connected by copies with ALLOCNO. This update increases chances to remove some copies. Copy cost is proportional @@ -180,7 +188,7 @@ update_copy_costs_1 (ira_allocno_t allocno, int hard_regno, += update_cost; if (update_cost != 0) update_copy_costs_1 (another_allocno, hard_regno, - decr_p, divisor * 4); + decr_p, divisor * COST_HOP_DIVISOR); } } @@ -193,6 +201,84 @@ update_copy_costs (ira_allocno_t allocno, bool decr_p) update_copy_costs_1 (allocno, ALLOCNO_HARD_REGNO (allocno), decr_p, 1); } +/* This recursive function updates COSTS (decrease if DECR_P) by + conflict costs of the unassigned allocnos connected by copies with + ALLOCNO. This update increases chances to remove some copies. + Copy cost is proportional to the copy frequency divided by + DIVISOR. */ +static void +update_conflict_hard_regno_costs (int *costs, ira_allocno_t allocno, + int divisor, bool decr_p) +{ + int i, cost, class_size, mult, div; + int *conflict_costs; + bool cont_p; + enum machine_mode mode; + enum reg_class cover_class; + ira_allocno_t another_allocno; + ira_copy_t cp, next_cp; + + cover_class = ALLOCNO_COVER_CLASS (allocno); + /* Probably 5 hops will be enough. */ + if (divisor > (COST_HOP_DIVISOR * COST_HOP_DIVISOR + * COST_HOP_DIVISOR * COST_HOP_DIVISOR * COST_HOP_DIVISOR)) + return; + if (cover_class == NO_REGS) + return; + /* Check that it was already visited. */ + if (allocno_update_cost_check[ALLOCNO_NUM (allocno)] == update_cost_check) + return; + allocno_update_cost_check[ALLOCNO_NUM (allocno)] = update_cost_check; + mode = ALLOCNO_MODE (allocno); + class_size = ira_class_hard_regs_num[cover_class]; + for (cp = ALLOCNO_COPIES (allocno); cp != NULL; cp = next_cp) + { + if (cp->first == allocno) + { + next_cp = cp->next_first_allocno_copy; + another_allocno = cp->second; + } + else if (cp->second == allocno) + { + next_cp = cp->next_second_allocno_copy; + another_allocno = cp->first; + } + else + gcc_unreachable (); + if (cover_class != ALLOCNO_COVER_CLASS (another_allocno) + || ALLOCNO_ASSIGNED_P (another_allocno) + || ALLOCNO_MAY_BE_SPILLED_P (another_allocno)) + continue; + ira_allocate_and_copy_costs + (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno), + cover_class, ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); + conflict_costs + = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno); + if (conflict_costs == NULL) + cont_p = true; + else + { + ira_assert (ALLOCNO_FREQ (another_allocno) != 0); + mult = cp->freq; + div = ALLOCNO_FREQ (another_allocno) * divisor; + cont_p = false; + for (i = class_size - 1; i >= 0; i--) + { + cost = conflict_costs [i] * mult / div; + if (cost == 0) + continue; + cont_p = true; + if (decr_p) + cost = -cost; + costs[i] += cost; + } + } + if (cont_p) + update_conflict_hard_regno_costs (costs, another_allocno, + divisor * COST_HOP_DIVISOR, decr_p); + } +} + /* Sort allocnos according to the profit of usage of a hard register instead of memory for them. */ static int @@ -246,9 +332,7 @@ assign_hard_reg (ira_allocno_t allocno, bool retry_p) enum reg_class cover_class, rclass; enum machine_mode mode; ira_allocno_t a, conflict_allocno; - ira_allocno_t another_allocno; ira_allocno_conflict_iterator aci; - ira_copy_t cp, next_cp; static int costs[FIRST_PSEUDO_REGISTER], full_costs[FIRST_PSEUDO_REGISTER]; #ifdef STACK_REGS bool no_stack_reg_p; @@ -333,42 +417,30 @@ assign_hard_reg (ira_allocno_t allocno, bool retry_p) if (conflict_costs != NULL) for (j = class_size - 1; j >= 0; j--) full_costs[j] -= conflict_costs[j]; + VEC_safe_push (ira_allocno_t, heap, conflict_allocno_vec, + conflict_allocno); } } if (a == allocno) break; } - /* Take copies into account. */ + /* Take into account preferences of allocnos connected by copies to + the conflict allocnos. */ + update_cost_check++; + while (VEC_length (ira_allocno_t, conflict_allocno_vec) != 0) + { + conflict_allocno = VEC_pop (ira_allocno_t, conflict_allocno_vec); + update_conflict_hard_regno_costs (full_costs, conflict_allocno, + COST_HOP_DIVISOR, true); + } + update_cost_check++; + /* Take preferences of allocnos connected by copies into + account. */ for (a = ALLOCNO_NEXT_COALESCED_ALLOCNO (allocno);; a = ALLOCNO_NEXT_COALESCED_ALLOCNO (a)) { - for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp) - { - if (cp->first == a) - { - next_cp = cp->next_first_allocno_copy; - another_allocno = cp->second; - } - else if (cp->second == a) - { - next_cp = cp->next_second_allocno_copy; - another_allocno = cp->first; - } - else - gcc_unreachable (); - if (cover_class != ALLOCNO_COVER_CLASS (another_allocno) - || ALLOCNO_ASSIGNED_P (another_allocno)) - continue; - ira_allocate_and_copy_costs - (&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno), - cover_class, ALLOCNO_CONFLICT_HARD_REG_COSTS (another_allocno)); - conflict_costs - = ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (another_allocno); - if (conflict_costs != NULL - && ! ALLOCNO_MAY_BE_SPILLED_P (another_allocno)) - for (j = class_size - 1; j >= 0; j--) - full_costs[j] += conflict_costs[j]; - } + update_conflict_hard_regno_costs (full_costs, a, + COST_HOP_DIVISOR, false); if (a == allocno) break; } @@ -2853,6 +2925,7 @@ void ira_color (void) { allocno_stack_vec = VEC_alloc (ira_allocno_t, heap, ira_allocnos_num); + conflict_allocno_vec = VEC_alloc (ira_allocno_t, heap, ira_allocnos_num); removed_splay_allocno_vec = VEC_alloc (ira_allocno_t, heap, ira_allocnos_num); memset (allocated_hardreg_p, 0, sizeof (allocated_hardreg_p)); @@ -2860,6 +2933,7 @@ ira_color (void) do_coloring (); ira_finish_assign (); VEC_free (ira_allocno_t, heap, removed_splay_allocno_vec); + VEC_free (ira_allocno_t, heap, conflict_allocno_vec); VEC_free (ira_allocno_t, heap, allocno_stack_vec); move_spill_restore (); } diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c index 04d3e42d64d..97da7c563df 100644 --- a/gcc/ira-conflicts.c +++ b/gcc/ira-conflicts.c @@ -181,7 +181,6 @@ get_dup_num (int op_num, bool use_commut_op_p) if (op_num < 0 || recog_data.n_alternatives == 0) return -1; op = recog_data.operand[op_num]; - ira_assert (REG_P (op)); commut_op_used_p = true; if (use_commut_op_p) { @@ -295,6 +294,32 @@ get_dup (int op_num, bool use_commut_op_p) return recog_data.operand[n]; } +/* Check that X is REG or SUBREG of REG. */ +#define REG_SUBREG_P(x) \ + (REG_P (x) || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))) + +/* Return X if X is a REG, otherwise it should be SUBREG of REG and + the function returns the reg in this case. *OFFSET will be set to + 0 in the first case or the regno offset in the first case. */ +static rtx +go_through_subreg (rtx x, int *offset) +{ + rtx reg; + + *offset = 0; + if (REG_P (x)) + return x; + ira_assert (GET_CODE (x) == SUBREG); + reg = SUBREG_REG (x); + ira_assert (REG_P (reg)); + if (REGNO (reg) < FIRST_PSEUDO_REGISTER) + *offset = subreg_regno_offset (REGNO (reg), GET_MODE (reg), + SUBREG_BYTE (x), GET_MODE (x)); + else + *offset = (SUBREG_BYTE (x) / REGMODE_NATURAL_SIZE (GET_MODE (x))); + return reg; +} + /* Process registers REG1 and REG2 in move INSN with execution frequency FREQ. The function also processes the registers in a potential move insn (INSN == NULL in this case) with frequency @@ -306,27 +331,32 @@ get_dup (int op_num, bool use_commut_op_p) static bool process_regs_for_copy (rtx reg1, rtx reg2, rtx insn, int freq) { - int hard_regno, cost, index; + int hard_regno, cost, index, offset1, offset2; + bool only_regs_p; ira_allocno_t a; enum reg_class rclass, cover_class; enum machine_mode mode; ira_copy_t cp; - gcc_assert (REG_P (reg1) && REG_P (reg2)); + gcc_assert (REG_SUBREG_P (reg1) && REG_SUBREG_P (reg2)); + only_regs_p = REG_P (reg1) && REG_P (reg2); + reg1 = go_through_subreg (reg1, &offset1); + reg2 = go_through_subreg (reg2, &offset2); if (HARD_REGISTER_P (reg1)) { if (HARD_REGISTER_P (reg2)) return false; - hard_regno = REGNO (reg1); + hard_regno = REGNO (reg1) + offset1 - offset2; a = ira_curr_regno_allocno_map[REGNO (reg2)]; } else if (HARD_REGISTER_P (reg2)) { - hard_regno = REGNO (reg2); + hard_regno = REGNO (reg2) + offset2 - offset1; a = ira_curr_regno_allocno_map[REGNO (reg1)]; } else if (!CONFLICT_ALLOCNO_P (ira_curr_regno_allocno_map[REGNO (reg1)], - ira_curr_regno_allocno_map[REGNO (reg2)])) + ira_curr_regno_allocno_map[REGNO (reg2)]) + && offset1 == offset2) { cp = ira_add_allocno_copy (ira_curr_regno_allocno_map[REGNO (reg1)], ira_curr_regno_allocno_map[REGNO (reg2)], @@ -341,7 +371,8 @@ process_regs_for_copy (rtx reg1, rtx reg2, rtx insn, int freq) cover_class = ALLOCNO_COVER_CLASS (a); if (! ira_class_subset_p[rclass][cover_class]) return false; - if (reg_class_size[rclass] <= (unsigned) CLASS_MAX_NREGS (rclass, mode)) + if (reg_class_size[rclass] <= (unsigned) CLASS_MAX_NREGS (rclass, mode) + && only_regs_p) /* It is already taken into account in ira-costs.c. */ return false; index = ira_class_hard_reg_index[cover_class][hard_regno]; @@ -371,12 +402,12 @@ process_reg_shuffles (rtx reg, int op_num, int freq) int i; rtx another_reg; - gcc_assert (REG_P (reg)); + gcc_assert (REG_SUBREG_P (reg)); for (i = 0; i < recog_data.n_operands; i++) { another_reg = recog_data.operand[i]; - if (!REG_P (another_reg) || op_num == i + if (!REG_SUBREG_P (another_reg) || op_num == i || recog_data.operand_type[i] != OP_OUT) continue; @@ -399,9 +430,12 @@ add_insn_allocno_copies (rtx insn) if (freq == 0) freq = 1; if ((set = single_set (insn)) != NULL_RTX - && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set)) + && REG_SUBREG_P (SET_DEST (set)) && REG_SUBREG_P (SET_SRC (set)) && ! side_effects_p (set) - && find_reg_note (insn, REG_DEAD, SET_SRC (set)) != NULL_RTX) + && find_reg_note (insn, REG_DEAD, + REG_P (SET_SRC (set)) + ? SET_SRC (set) + : SUBREG_REG (SET_SRC (set))) != NULL_RTX) process_regs_for_copy (SET_DEST (set), SET_SRC (set), insn, freq); else { @@ -409,8 +443,10 @@ add_insn_allocno_copies (rtx insn) for (i = 0; i < recog_data.n_operands; i++) { operand = recog_data.operand[i]; - if (REG_P (operand) - && find_reg_note (insn, REG_DEAD, operand) != NULL_RTX) + if (REG_SUBREG_P (operand) + && find_reg_note (insn, REG_DEAD, + REG_P (operand) + ? operand : SUBREG_REG (operand)) != NULL_RTX) { str = recog_data.constraints[i]; while (*str == ' ' && *str == '\t') @@ -418,7 +454,7 @@ add_insn_allocno_copies (rtx insn) bound_p = false; for (j = 0, commut_p = false; j < 2; j++, commut_p = true) if ((dup = get_dup (i, commut_p)) != NULL_RTX - && REG_P (dup) && GET_MODE (operand) == GET_MODE (dup) + && REG_SUBREG_P (dup) && process_regs_for_copy (operand, dup, NULL_RTX, freq)) bound_p = true; if (bound_p) -- 2.11.4.GIT