X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fsel-sched.c;h=6b44893c8914ba18317650a94d10b764151d99af;hb=6956abd25f4834e2c451819a57af52874dd0aace;hp=be56ded153bdae59a0737fd7bdba76a8a9b411f2;hpb=851d929653778531dd174c25c55d6c6558b5510f;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index be56ded153b..6b44893c891 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "rtlhooks-def.h" #include "output.h" #include "emit-rtl.h" +#include "ira.h" #ifdef INSN_SCHEDULING #include "sel-sched-ir.h" @@ -794,8 +795,8 @@ substitute_reg_in_expr (expr_t expr, insn_t insn, bool undo) /* Do not allow clobbering the address register of speculative insns. */ if ((EXPR_SPEC_DONE_DS (expr) & SPECULATIVE) - && bitmap_bit_p (VINSN_REG_USES (EXPR_VINSN (expr)), - expr_dest_regno (expr))) + && register_unavailable_p (VINSN_REG_USES (EXPR_VINSN (expr)), + expr_dest_reg (expr))) EXPR_TARGET_AVAILABLE (expr) = false; return true; @@ -813,18 +814,12 @@ count_occurrences_1 (rtx *cur_rtx, void *arg) { rtx_search_arg_p p = (rtx_search_arg_p) arg; - /* The last param FOR_GCSE is true, because otherwise it performs excessive - substitutions like - r8 = r33 - r16 = r33 - for the last insn it presumes r33 equivalent to r8, so it changes it to - r33. Actually, there's no change, but it spoils debugging. */ - if (exp_equiv_p (*cur_rtx, p->x, 0, true)) - { - /* Bail out if we occupy more than one register. */ - if (REG_P (*cur_rtx) - && HARD_REGISTER_P (*cur_rtx) - && hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1) + if (REG_P (*cur_rtx) && REGNO (*cur_rtx) == REGNO (p->x)) + { + /* Bail out if mode is different or more than one register is used. */ + if (GET_MODE (*cur_rtx) != GET_MODE (p->x) + || (HARD_REGISTER_P (*cur_rtx) + && hard_regno_nregs[REGNO(*cur_rtx)][GET_MODE (*cur_rtx)] > 1)) { p->n = 0; return 1; @@ -837,7 +832,6 @@ count_occurrences_1 (rtx *cur_rtx, void *arg) } if (GET_CODE (*cur_rtx) == SUBREG - && REG_P (p->x) && (!REG_P (SUBREG_REG (*cur_rtx)) || REGNO (SUBREG_REG (*cur_rtx)) == REGNO (p->x))) { @@ -859,6 +853,7 @@ count_occurrences_equiv (rtx what, rtx where) { struct rtx_search_arg arg; + gcc_assert (REG_P (what)); arg.x = what; arg.n = 0; @@ -1581,7 +1576,7 @@ verify_target_availability (expr_t expr, regset used_regs, regno = expr_dest_regno (expr); mode = GET_MODE (EXPR_LHS (expr)); target_available = EXPR_TARGET_AVAILABLE (expr) == 1; - n = reload_completed ? hard_regno_nregs[regno][mode] : 1; + n = HARD_REGISTER_NUM_P (regno) ? hard_regno_nregs[regno][mode] : 1; live_available = hard_available = true; for (i = 0; i < n; i++) @@ -2119,6 +2114,61 @@ moving_insn_creates_bookkeeping_block_p (insn_t insn, return TRUE; } +/* Return true when the conflict with newly created implicit clobbers + between EXPR and THROUGH_INSN is found because of renaming. */ +static bool +implicit_clobber_conflict_p (insn_t through_insn, expr_t expr) +{ + HARD_REG_SET temp; + rtx insn, reg, rhs, pat; + hard_reg_set_iterator hrsi; + unsigned regno; + bool valid; + + /* Make a new pseudo register. */ + reg = gen_reg_rtx (GET_MODE (EXPR_LHS (expr))); + max_regno = max_reg_num (); + maybe_extend_reg_info_p (); + + /* Validate a change and bail out early. */ + insn = EXPR_INSN_RTX (expr); + validate_change (insn, &SET_DEST (PATTERN (insn)), reg, true); + valid = verify_changes (0); + cancel_changes (0); + if (!valid) + { + if (sched_verbose >= 6) + sel_print ("implicit clobbers failed validation, "); + return true; + } + + /* Make a new insn with it. */ + rhs = copy_rtx (VINSN_RHS (EXPR_VINSN (expr))); + pat = gen_rtx_SET (VOIDmode, reg, rhs); + start_sequence (); + insn = emit_insn (pat); + end_sequence (); + + /* Calculate implicit clobbers. */ + extract_insn (insn); + preprocess_constraints (); + ira_implicitly_set_insn_hard_regs (&temp); + AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs); + + /* If any implicit clobber registers intersect with regular ones in + through_insn, we have a dependency and thus bail out. */ + EXECUTE_IF_SET_IN_HARD_REG_SET (temp, 0, regno, hrsi) + { + vinsn_t vi = INSN_VINSN (through_insn); + if (bitmap_bit_p (VINSN_REG_SETS (vi), regno) + || bitmap_bit_p (VINSN_REG_CLOBBERS (vi), regno) + || bitmap_bit_p (VINSN_REG_USES (vi), regno)) + return true; + } + + return false; +} + /* Modifies EXPR so it can be moved through the THROUGH_INSN, performing necessary transformations. Record the type of transformation made in PTRANS_TYPE, when it is not NULL. When INSIDE_INSN_GROUP, @@ -2251,6 +2301,17 @@ moveup_expr (expr_t expr, insn_t through_insn, bool inside_insn_group, if (!enable_schedule_as_rhs_p || !EXPR_SEPARABLE_P (expr)) return MOVEUP_EXPR_NULL; + /* When renaming a hard register to a pseudo before reload, extra + dependencies can occur from the implicit clobbers of the insn. + Filter out such cases here. */ + if (!reload_completed && REG_P (EXPR_LHS (expr)) + && HARD_REGISTER_P (EXPR_LHS (expr)) + && implicit_clobber_conflict_p (through_insn, expr)) + { + if (sched_verbose >= 6) + sel_print ("implicit clobbers conflict detected, "); + return MOVEUP_EXPR_NULL; + } EXPR_TARGET_AVAILABLE (expr) = false; was_target_conflict = true; as_rhs = true; @@ -3573,29 +3634,41 @@ process_use_exprs (av_set_t *av_ptr) return NULL; } -/* Lookup EXPR in VINSN_VEC and return TRUE if found. */ +/* Lookup EXPR in VINSN_VEC and return TRUE if found. Also check patterns from + EXPR's history of changes. */ static bool vinsn_vec_has_expr_p (vinsn_vec_t vinsn_vec, expr_t expr) { - vinsn_t vinsn; + vinsn_t vinsn, expr_vinsn; int n; + unsigned i; - FOR_EACH_VEC_ELT (vinsn_t, vinsn_vec, n, vinsn) - if (VINSN_SEPARABLE_P (vinsn)) - { - if (vinsn_equal_p (vinsn, EXPR_VINSN (expr))) - return true; - } - else - { - /* For non-separable instructions, the blocking insn can have - another pattern due to substitution, and we can't choose - different register as in the above case. Check all registers - being written instead. */ - if (bitmap_intersect_p (VINSN_REG_SETS (vinsn), - VINSN_REG_SETS (EXPR_VINSN (expr)))) - return true; - } + /* Start with checking expr itself and then proceed with all the old forms + of expr taken from its history vector. */ + for (i = 0, expr_vinsn = EXPR_VINSN (expr); + expr_vinsn; + expr_vinsn = (i < VEC_length (expr_history_def, + EXPR_HISTORY_OF_CHANGES (expr)) + ? VEC_index (expr_history_def, + EXPR_HISTORY_OF_CHANGES (expr), + i++)->old_expr_vinsn + : NULL)) + FOR_EACH_VEC_ELT (vinsn_t, vinsn_vec, n, vinsn) + if (VINSN_SEPARABLE_P (vinsn)) + { + if (vinsn_equal_p (vinsn, expr_vinsn)) + return true; + } + else + { + /* For non-separable instructions, the blocking insn can have + another pattern due to substitution, and we can't choose + different register as in the above case. Check all registers + being written instead. */ + if (bitmap_intersect_p (VINSN_REG_SETS (vinsn), + VINSN_REG_SETS (expr_vinsn))) + return true; + } return false; } @@ -3631,12 +3704,12 @@ av_set_could_be_blocked_by_bookkeeping_p (av_set_t orig_ops, void *static_params renaming. Check with the right register instead. */ if (sparams->dest && REG_P (sparams->dest)) { - unsigned regno = REGNO (sparams->dest); + rtx reg = sparams->dest; vinsn_t failed_vinsn = INSN_VINSN (sparams->failed_insn); - if (bitmap_bit_p (VINSN_REG_SETS (failed_vinsn), regno) - || bitmap_bit_p (VINSN_REG_USES (failed_vinsn), regno) - || bitmap_bit_p (VINSN_REG_CLOBBERS (failed_vinsn), regno)) + if (register_unavailable_p (VINSN_REG_SETS (failed_vinsn), reg) + || register_unavailable_p (VINSN_REG_USES (failed_vinsn), reg) + || register_unavailable_p (VINSN_REG_CLOBBERS (failed_vinsn), reg)) return true; } @@ -4663,9 +4736,10 @@ create_block_for_bookkeeping (edge e1, edge e2) } /* Return insn after which we must insert bookkeeping code for path(s) incoming - into E2->dest, except from E1->src. */ + into E2->dest, except from E1->src. If the returned insn immediately + precedes a fence, assign that fence to *FENCE_TO_REWIND. */ static insn_t -find_place_for_bookkeeping (edge e1, edge e2) +find_place_for_bookkeeping (edge e1, edge e2, fence_t *fence_to_rewind) { insn_t place_to_insert; /* Find a basic block that can hold bookkeeping. If it can be found, do not @@ -4707,9 +4781,14 @@ find_place_for_bookkeeping (edge e1, edge e2) sel_print ("Pre-existing bookkeeping block is %i\n", book_block->index); } - /* If basic block ends with a jump, insert bookkeeping code right before it. */ + *fence_to_rewind = NULL; + /* If basic block ends with a jump, insert bookkeeping code right before it. + Notice if we are crossing a fence when taking PREV_INSN. */ if (INSN_P (place_to_insert) && control_flow_insn_p (place_to_insert)) - place_to_insert = PREV_INSN (place_to_insert); + { + *fence_to_rewind = flist_lookup (fences, place_to_insert); + place_to_insert = PREV_INSN (place_to_insert); + } return place_to_insert; } @@ -4784,21 +4863,23 @@ generate_bookkeeping_insn (expr_t c_expr, edge e1, edge e2) insn_t join_point, place_to_insert, new_insn; int new_seqno; bool need_to_exchange_data_sets; + fence_t fence_to_rewind; if (sched_verbose >= 4) sel_print ("Generating bookkeeping insn (%d->%d)\n", e1->src->index, e2->dest->index); join_point = sel_bb_head (e2->dest); - place_to_insert = find_place_for_bookkeeping (e1, e2); - if (!place_to_insert) - return NULL; + place_to_insert = find_place_for_bookkeeping (e1, e2, &fence_to_rewind); new_seqno = find_seqno_for_bookkeeping (place_to_insert, join_point); need_to_exchange_data_sets = sel_bb_empty_p (BLOCK_FOR_INSN (place_to_insert)); new_insn = emit_bookkeeping_insn (place_to_insert, c_expr, new_seqno); + if (fence_to_rewind) + FENCE_INSN (fence_to_rewind) = new_insn; + /* When inserting bookkeeping insn in new block, av sets should be following: old basic block (that now holds bookkeeping) data sets are the same as was before generation of bookkeeping, and new basic block @@ -5517,7 +5598,7 @@ fill_insns (fence_t fence, int seqno, ilist_t **scheduled_insns_tailpp) { blist_t *bnds_tailp1, *bndsp; expr_t expr_vliw; - int need_stall; + int need_stall = false; int was_stall = 0, scheduled_insns = 0; int max_insns = pipelining_p ? issue_rate : 2 * issue_rate; int max_stall = pipelining_p ? 1 : 3; @@ -5695,8 +5776,8 @@ update_and_record_unavailable_insns (basic_block book_block) || EXPR_TARGET_AVAILABLE (new_expr) != EXPR_TARGET_AVAILABLE (cur_expr)) /* Unfortunately, the below code could be also fired up on - separable insns. - FIXME: add an example of how this could happen. */ + separable insns, e.g. when moving insns through the new + speculation check as in PR 53701. */ vinsn_vec_add (&vec_bookkeeping_blocked_vinsns, cur_expr); } @@ -6675,7 +6756,7 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw, { struct moveop_static_params sparams; struct cmpd_local_params lparams; - bool res; + int res; /* Init params for code_motion_path_driver. */ sparams.dest = dest; @@ -6694,6 +6775,8 @@ move_op (insn_t insn, av_set_t orig_ops, expr_t expr_vliw, code_motion_path_driver_info = &move_op_hooks; res = code_motion_path_driver (insn, orig_ops, NULL, &lparams, &sparams); + gcc_assert (res != -1); + if (sparams.was_renamed) EXPR_WAS_RENAMED (expr_vliw) = true; @@ -6868,7 +6951,7 @@ sel_region_init (int rgn) for (i = 0; i < current_nr_blocks; i++) VEC_quick_push (basic_block, bbs, BASIC_BLOCK (BB_TO_BLOCK (i))); - sel_init_bbs (bbs, NULL); + sel_init_bbs (bbs); if (flag_sel_sched_pipelining) setup_current_loop_nest (rgn, &bbs); @@ -6877,13 +6960,13 @@ sel_region_init (int rgn) /* Initialize luids and dependence analysis which both sel-sched and haifa need. */ - sched_init_luids (bbs, NULL, NULL, NULL); + sched_init_luids (bbs); sched_deps_init (false); /* Initialize haifa data. */ rgn_setup_sched_infos (); sel_set_sched_flags (); - haifa_init_h_i_d (bbs, NULL, NULL, NULL); + haifa_init_h_i_d (bbs); sel_compute_priorities (rgn); init_deps_global (); @@ -7215,7 +7298,7 @@ sel_region_target_finish (bool reset_sched_cycles_p) /* Extend luids so that insns generated by the target will get zero luid. */ - sched_init_luids (NULL, NULL, NULL, NULL); + sched_extend_luids (); } } @@ -7269,6 +7352,7 @@ sel_region_finish (bool reset_sched_cycles_p) finish_deps_global (); sched_finish_luids (); + VEC_free (haifa_deps_insn_data_def, heap, h_d_i_d); sel_finish_bbs (); BITMAP_FREE (blocks_to_reschedule);