diff options
author | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-30 14:27:25 +0000 |
---|---|---|
committer | vmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-10-30 14:27:25 +0000 |
commit | 284f069678f0b28c57e62b5da9b6dfed77d4d700 (patch) | |
tree | 27225af1bc13234694bb062d327dd794b7bbb8cc /gcc/ira.c | |
parent | f484312fbab6135dc4ac30fbc504ae02848794e3 (diff) | |
download | gcc-284f069678f0b28c57e62b5da9b6dfed77d4d700.tar.gz |
2013-10-30 Vladimir Makarov <vmakarov@redhat.com>
* regmove.c: Remove.
* tree-pass.h (make_pass_regmove): Remove.
* timevar.def (TV_REGMOVE): Remove.
* passes.def (pass_regmove): Remove.
* opts.c (default_options_table): Remove entry for regmove.
* doc/passes.texi: Remove regmove pass description.
* doc/invoke.texi (-foptimize-register-move, -fregmove): Remove
options.
(-fdump-rtl-regmove): Ditto.
* common.opt (foptimize-register-move, fregmove): Ignore.
* Makefile.in (OBJS): Remove regmove.o.
* regmove.c: Remove.
* ira-int.h (struct ira_allocno_pref, ira_pref_t): New structure
and type.
(struct ira_allocno) New member allocno_prefs.
(ALLOCNO_PREFS): New macro.
(ira_prefs, ira_prefs_num): New external vars.
(ira_setup_alts, ira_get_dup_out_num, ira_debug_pref): New
prototypes.
(ira_debug_prefs, ira_debug_allocno_prefs, ira_create_pref):
Ditto.
(ira_add_allocno_pref, ira_remove_pref, ira_remove_allocno_prefs):
Ditto.
(ira_add_allocno_copy_to_list): Remove prototype.
(ira_swap_allocno_copy_ends_if_necessary): Ditto.
(ira_pref_iterator): New type.
(ira_pref_iter_init, ira_pref_iter_cond): New functions.
(FOR_EACH_PREF): New macro.
* ira.c (commutative_constraint_p): Move from ira-conflicts.c.
(ira_get_dup_out_num): Ditto. Rename from get_dup_num. Modify the
code.
(ira_setup_alts): New function.
(decrease_live_ranges_number): New function.
(ira): Call the above function.
* ira-build.c (ira_prefs, ira_prefs_num): New global vars.
(ira_create_allocno): Initialize allocno prefs.
(pref_pool, pref_vec): New static vars.
(initiate_prefs, find_allocno_pref, ira_create_pref): New
functions.
(add_allocno_pref_to_list, ira_add_allocno_pref, print_pref): Ditto.
(ira_debug_pref, print_prefs, ira_debug_prefs): Ditto.
(print_allocno_prefs, ira_debug_allocno_prefs, finish_pref): Ditto.
(ira_remove_pref, ira_remove_allocno_prefs, finish_prefs): Ditto.
(ira_add_allocno_copy_to_list): Make static. Rename to
add_allocno_copy_to_list.
(ira_swap_allocno_copy_ends_if_necessary): Make static. Rename to
swap_allocno_copy_ends_if_necessary.
(remove_unnecessary_allocnos, remove_low_level_allocnos): Call
ira_remove_allocno_prefs.
(ira_flattening): Ditto.
(ira_build): Call initiate_prefs, print_prefs.
(ira_destroy): Call finish_prefs.
* ira-color.c (struct update_cost_record): New.
(struct allocno_color_data): Add new member update_cost_records.
(update_cost_record_pool): New static var.
(init_update_cost_records, get_update_cost_record): New functions.
(free_update_cost_record_list, finish_update_cost_records): Ditto.
(struct update_cost_queue_elem): Add member from.
(initiate_cost_update): Call init_update_cost_records.
(finish_cost_update): Call finish_update_cost_records.
(queue_update_cost, get_next_update_cost): Add new param from.
(Update_allocno_cost, update_costs_from_allocno): New functions.
(update_costs_from_prefs): Ditto.
(update_copy_costs): Rename to update_costs_from_copies.
(restore_costs_from_copies): New function.
(update_conflict_hard_regno_costs): Don't go back.
(assign_hard_reg): Call restore_costs_from_copies. Add printing
more debug info.
(pop_allocnos): Add priniting more debug info.
(color_allocnos): Remove prefs for conflicting hard regs.
Call update_costs_from_prefs.
* ira-conflicts.c (commutative_constraint_p): Move to ira.c
(get_dup_num): Rename, modify, and move to ira.c
(process_regs_for_copy): Add prefs.
(add_insn_allocno_copies): Put src as first arg of
process_regs_for_copy. Remove dead code. Call ira_setup_alts.
* ira-costs.c (record_reg_classes): Modify and move code into
record_operands_costs.
(find_costs_and_classes): Create prefs for the hard reg of small
reg class.
(process_bb_node_for_hard_reg_moves): Add prefs.
2013-10-30 Vladimir Makarov <vmakarov@redhat.com>
* gcc.target/i386/fma_double_3.c: Use pattern for
scan-assembler-times instead of just one insn name.
* gcc.target/i386/fma_double_5.c: Ditto.
* gcc.target/i386/fma_float_3.c: Ditto.
* gcc.target/i386/fma_float_5.c: Ditto.
* gcc.target/i386/l_fma_double_1.c: Ditto.
* gcc.target/i386/l_fma_double_2.c: Ditto.
* gcc.target/i386/l_fma_double_3.c: Ditto.
* gcc.target/i386/l_fma_double_4.c: Ditto.
* gcc.target/i386/l_fma_double_5.c: Ditto.
* gcc.target/i386/l_fma_double_6.c: Ditto.
* gcc.target/i386/l_fma_float_1.c: Ditto.
* gcc.target/i386/l_fma_float_2.c: Ditto.
* gcc.target/i386/l_fma_float_3.c: Ditto.
* gcc.target/i386/l_fma_float_4.c: Ditto.
* gcc.target/i386/l_fma_float_5.c: Ditto.
* gcc.target/i386/l_fma_float_6.c: Ditto.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204212 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ira.c')
-rw-r--r-- | gcc/ira.c | 524 |
1 files changed, 523 insertions, 1 deletions
diff --git a/gcc/ira.c b/gcc/ira.c index 113413515f4..830ead1d89c 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -1761,6 +1761,527 @@ setup_prohibited_mode_move_regs (void) +/* Return TRUE if the operand constraint STR is commutative. */ +static bool +commutative_constraint_p (const char *str) +{ + int curr_alt, c; + bool ignore_p; + + for (ignore_p = false, curr_alt = 0;;) + { + c = *str; + if (c == '\0') + break; + str += CONSTRAINT_LEN (c, str); + if (c == '#' || !recog_data.alternative_enabled_p[curr_alt]) + ignore_p = true; + else if (c == ',') + { + curr_alt++; + ignore_p = false; + } + else if (! ignore_p) + { + /* Usually `%' is the first constraint character but the + documentation does not require this. */ + if (c == '%') + return true; + } + } + return false; +} + +/* Setup possible alternatives in ALTS for INSN. */ +void +ira_setup_alts (rtx insn, HARD_REG_SET &alts) +{ + /* MAP nalt * nop -> start of constraints for given operand and + alternative */ + static vec<const char *> insn_constraints; + int nop, nalt; + bool curr_swapped; + const char *p; + rtx op; + int commutative = -1; + + extract_insn (insn); + CLEAR_HARD_REG_SET (alts); + insn_constraints.release (); + insn_constraints.safe_grow_cleared (recog_data.n_operands + * recog_data.n_alternatives + 1); + /* Check that the hard reg set is enough for holding all + alternatives. It is hard to imagine the situation when the + assertion is wrong. */ + ira_assert (recog_data.n_alternatives + <= (int) MAX (sizeof (HARD_REG_ELT_TYPE) * CHAR_BIT, + FIRST_PSEUDO_REGISTER)); + for (curr_swapped = false;; curr_swapped = true) + { + /* Calculate some data common for all alternatives to speed up the + function. */ + for (nop = 0; nop < recog_data.n_operands; nop++) + { + for (nalt = 0, p = recog_data.constraints[nop]; + nalt < recog_data.n_alternatives; + nalt++) + { + insn_constraints[nop * recog_data.n_alternatives + nalt] = p; + while (*p && *p != ',') + p++; + if (*p) + p++; + } + } + for (nalt = 0; nalt < recog_data.n_alternatives; nalt++) + { + if (! recog_data.alternative_enabled_p[nalt] || TEST_HARD_REG_BIT (alts, nalt)) + continue; + + for (nop = 0; nop < recog_data.n_operands; nop++) + { + int c, len; + + op = recog_data.operand[nop]; + p = insn_constraints[nop * recog_data.n_alternatives + nalt]; + if (*p == 0 || *p == ',') + continue; + + do + switch (c = *p, len = CONSTRAINT_LEN (c, p), c) + { + case '#': + case ',': + c = '\0'; + case '\0': + len = 0; + break; + + case '?': case '!': case '*': case '=': case '+': + break; + + case '%': + /* We only support one commutative marker, the + first one. We already set commutative + above. */ + if (commutative < 0) + commutative = nop; + break; + + case '&': + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + goto op_success; + break; + + case 'p': + case 'g': + case 'X': + case TARGET_MEM_CONSTRAINT: + goto op_success; + break; + + case '<': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == POST_DEC)) + goto op_success; + break; + + case '>': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == POST_INC)) + goto op_success; + break; + + case 'E': + case 'F': + if (CONST_DOUBLE_AS_FLOAT_P (op) + || (GET_CODE (op) == CONST_VECTOR + && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)) + goto op_success; + break; + + case 'G': + case 'H': + if (CONST_DOUBLE_AS_FLOAT_P (op) + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) + goto op_success; + break; + + case 's': + if (CONST_SCALAR_INT_P (op)) + break; + case 'i': + if (CONSTANT_P (op)) + goto op_success; + break; + + case 'n': + if (CONST_SCALAR_INT_P (op)) + goto op_success; + break; + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (CONST_INT_P (op) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) + goto op_success; + break; + + case 'V': + if (MEM_P (op) && ! offsettable_memref_p (op)) + goto op_success; + break; + + case 'o': + goto op_success; + break; + + default: + { + enum reg_class cl; + + cl = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p)); + if (cl != NO_REGS) + goto op_success; +#ifdef EXTRA_CONSTRAINT_STR + else if (EXTRA_CONSTRAINT_STR (op, c, p)) + goto op_success; + else if (EXTRA_MEMORY_CONSTRAINT (c, p)) + goto op_success; + else if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + goto op_success; +#endif + break; + } + } + while (p += len, c); + break; + op_success: + ; + } + if (nop >= recog_data.n_operands) + SET_HARD_REG_BIT (alts, nalt); + } + if (commutative < 0) + break; + if (curr_swapped) + break; + op = recog_data.operand[commutative]; + recog_data.operand[commutative] = recog_data.operand[commutative + 1]; + recog_data.operand[commutative + 1] = op; + + } +} + +/* Return the number of the output non-early clobber operand which + should be the same in any case as operand with number OP_NUM (or + negative value if there is no such operand). The function takes + only really possible alternatives into consideration. */ +int +ira_get_dup_out_num (int op_num, HARD_REG_SET &alts) +{ + int curr_alt, c, original, dup; + bool ignore_p, use_commut_op_p; + const char *str; +#ifdef EXTRA_CONSTRAINT_STR + rtx op; +#endif + + if (op_num < 0 || recog_data.n_alternatives == 0) + return -1; + use_commut_op_p = false; + str = recog_data.constraints[op_num]; + for (;;) + { +#ifdef EXTRA_CONSTRAINT_STR + op = recog_data.operand[op_num]; +#endif + + for (ignore_p = false, original = -1, curr_alt = 0;;) + { + c = *str; + if (c == '\0') + break; + if (c == '#' || !TEST_HARD_REG_BIT (alts, curr_alt)) + ignore_p = true; + else if (c == ',') + { + curr_alt++; + ignore_p = false; + } + else if (! ignore_p) + switch (c) + { + /* We should find duplications only for input operands. */ + case '=': + case '+': + goto fail; + case 'X': + case 'p': + case 'g': + goto fail; + case 'r': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'h': case 'j': case 'k': case 'l': + case 'q': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': + case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'W': case 'Y': case 'Z': + { + enum reg_class cl; + + cl = (c == 'r' + ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, str)); + if (cl != NO_REGS) + { + if (! targetm.class_likely_spilled_p (cl)) + goto fail; + } +#ifdef EXTRA_CONSTRAINT_STR + else if (EXTRA_CONSTRAINT_STR (op, c, str)) + goto fail; +#endif + break; + } + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (original != -1 && original != c) + goto fail; + original = c; + break; + } + str += CONSTRAINT_LEN (c, str); + } + if (original == -1) + goto fail; + dup = -1; + for (ignore_p = false, str = recog_data.constraints[original - '0']; + *str != 0; + str++) + if (ignore_p) + { + if (*str == ',') + ignore_p = false; + } + else if (*str == '#') + ignore_p = true; + else if (! ignore_p) + { + if (*str == '=') + dup = original - '0'; + /* It is better ignore an alternative with early clobber. */ + else if (*str == '&') + goto fail; + } + if (dup >= 0) + return dup; + fail: + if (use_commut_op_p) + break; + use_commut_op_p = true; + if (commutative_constraint_p (recog_data.constraints[op_num])) + str = recog_data.constraints[op_num + 1]; + else if (op_num > 0 && commutative_constraint_p (recog_data.constraints + [op_num - 1])) + str = recog_data.constraints[op_num - 1]; + else + break; + } + return -1; +} + + + +/* Search forward to see if the source register of a copy insn dies + before either it or the destination register is modified, but don't + scan past the end of the basic block. If so, we can replace the + source with the destination and let the source die in the copy + insn. + + This will reduce the number of registers live in that range and may + enable the destination and the source coalescing, thus often saving + one register in addition to a register-register copy. */ + +static void +decrease_live_ranges_number (void) +{ + basic_block bb; + rtx insn, set, src, dest, dest_death, p, q, note; + int sregno, dregno; + + if (! flag_expensive_optimizations) + return; + + if (ira_dump_file) + fprintf (ira_dump_file, "Starting decreasing number of live ranges...\n"); + + FOR_EACH_BB (bb) + FOR_BB_INSNS (bb, insn) + { + set = single_set (insn); + if (! set) + continue; + src = SET_SRC (set); + dest = SET_DEST (set); + if (! REG_P (src) || ! REG_P (dest) + || find_reg_note (insn, REG_DEAD, src)) + continue; + sregno = REGNO (src); + dregno = REGNO (dest); + + /* We don't want to mess with hard regs if register classes + are small. */ + if (sregno == dregno + || (targetm.small_register_classes_for_mode_p (GET_MODE (src)) + && (sregno < FIRST_PSEUDO_REGISTER + || dregno < FIRST_PSEUDO_REGISTER)) + /* We don't see all updates to SP if they are in an + auto-inc memory reference, so we must disallow this + optimization on them. */ + || sregno == STACK_POINTER_REGNUM + || dregno == STACK_POINTER_REGNUM) + continue; + + dest_death = NULL_RTX; + + for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p)) + { + if (! INSN_P (p)) + continue; + if (BLOCK_FOR_INSN (p) != bb) + break; + + if (reg_set_p (src, p) || reg_set_p (dest, p) + /* If SRC is an asm-declared register, it must not be + replaced in any asm. Unfortunately, the REG_EXPR + tree for the asm variable may be absent in the SRC + rtx, so we can't check the actual register + declaration easily (the asm operand will have it, + though). To avoid complicating the test for a rare + case, we just don't perform register replacement + for a hard reg mentioned in an asm. */ + || (sregno < FIRST_PSEUDO_REGISTER + && asm_noperands (PATTERN (p)) >= 0 + && reg_overlap_mentioned_p (src, PATTERN (p))) + /* Don't change hard registers used by a call. */ + || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER + && find_reg_fusage (p, USE, src)) + /* Don't change a USE of a register. */ + || (GET_CODE (PATTERN (p)) == USE + && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0)))) + break; + + /* See if all of SRC dies in P. This test is slightly + more conservative than it needs to be. */ + if ((note = find_regno_note (p, REG_DEAD, sregno)) + && GET_MODE (XEXP (note, 0)) == GET_MODE (src)) + { + int failed = 0; + + /* We can do the optimization. Scan forward from INSN + again, replacing regs as we go. Set FAILED if a + replacement can't be done. In that case, we can't + move the death note for SRC. This should be + rare. */ + + /* Set to stop at next insn. */ + for (q = next_real_insn (insn); + q != next_real_insn (p); + q = next_real_insn (q)) + { + if (reg_overlap_mentioned_p (src, PATTERN (q))) + { + /* If SRC is a hard register, we might miss + some overlapping registers with + validate_replace_rtx, so we would have to + undo it. We can't if DEST is present in + the insn, so fail in that combination of + cases. */ + if (sregno < FIRST_PSEUDO_REGISTER + && reg_mentioned_p (dest, PATTERN (q))) + failed = 1; + + /* Attempt to replace all uses. */ + else if (!validate_replace_rtx (src, dest, q)) + failed = 1; + + /* If this succeeded, but some part of the + register is still present, undo the + replacement. */ + else if (sregno < FIRST_PSEUDO_REGISTER + && reg_overlap_mentioned_p (src, PATTERN (q))) + { + validate_replace_rtx (dest, src, q); + failed = 1; + } + } + + /* If DEST dies here, remove the death note and + save it for later. Make sure ALL of DEST dies + here; again, this is overly conservative. */ + if (! dest_death + && (dest_death = find_regno_note (q, REG_DEAD, dregno))) + { + if (GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest)) + remove_note (q, dest_death); + else + { + failed = 1; + dest_death = 0; + } + } + } + + if (! failed) + { + /* Move death note of SRC from P to INSN. */ + remove_note (p, note); + XEXP (note, 1) = REG_NOTES (insn); + REG_NOTES (insn) = note; + } + + /* DEST is also dead if INSN has a REG_UNUSED note for + DEST. */ + if (! dest_death + && (dest_death + = find_regno_note (insn, REG_UNUSED, dregno))) + { + PUT_REG_NOTE_KIND (dest_death, REG_DEAD); + remove_note (insn, dest_death); + } + + /* Put death note of DEST on P if we saw it die. */ + if (dest_death) + { + XEXP (dest_death, 1) = REG_NOTES (p); + REG_NOTES (p) = dest_death; + } + break; + } + + /* If SRC is a hard register which is set or killed in + some other way, we can't do this optimization. */ + else if (sregno < FIRST_PSEUDO_REGISTER && dead_or_set_p (p, src)) + break; + } + } +} + + + /* Return nonzero if REGNO is a particularly bad choice for reloading X. */ static bool ira_bad_reload_regno_1 (int regno, rtx x) @@ -4655,7 +5176,7 @@ ira (FILE *f) } setup_prohibited_mode_move_regs (); - + decrease_live_ranges_number (); df_note_add_problem (); /* DF_LIVE can't be used in the register allocator, too many other @@ -4671,6 +5192,7 @@ ira (FILE *f) df->changeable_flags |= DF_VERIFY_SCHEDULED; #endif df_analyze (); + df_clear_flags (DF_NO_INSN_RESCAN); regstat_init_n_sets_and_refs (); regstat_compute_ri (); |