From 7173d4d00091dd0096cce8ab7dd8d6c0e4018a45 Mon Sep 17 00:00:00 2001 From: vmakarov Date: Thu, 16 Oct 2008 00:51:34 +0000 Subject: [PATCH] 2008-10-15 Vladimir Makarov PR middle-end/37535 * ira-lives.c (mark_early_clobbers): Remove. (make_pseudo_conflict, check_and_make_def_use_conflicts, check_and_make_def_conflicts, make_early_clobber_and_input_conflicts, mark_hard_reg_early_clobbers): New functions. (process_bb_node_lives): Call make_early_clobber_and_input_conflicts and mark_hard_reg_early_clobbers. Make hard register inputs live again. * doc/rtl.texi (clobber): Change descriotion of RA behaviour for early clobbers of pseudo-registers. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@141160 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 16 +++++ gcc/doc/rtl.texi | 11 +-- gcc/ira-lives.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 193 insertions(+), 35 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0cf0decee8a..68ae6eca9d6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,21 @@ 2008-10-15 Vladimir Makarov + PR middle-end/37535 + * ira-lives.c (mark_early_clobbers): Remove. + (make_pseudo_conflict, check_and_make_def_use_conflicts, + check_and_make_def_conflicts, + make_early_clobber_and_input_conflicts, + mark_hard_reg_early_clobbers): New functions. + (process_bb_node_lives): Call + make_early_clobber_and_input_conflicts and + mark_hard_reg_early_clobbers. Make hard register inputs live + again. + + * doc/rtl.texi (clobber): Change descriotion of RA behaviour for + early clobbers of pseudo-registers. + +2008-10-15 Vladimir Makarov + PR middle-end/37674 * ira-build.c (ira_flattening): Recalculate ALLOCNO_TOTAL_NO_STACK_REG_P and ALLOCNO_TOTAL_CONFLICT_HARD_REGS diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 701e490ccef..1411f24e5d9 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -2917,11 +2917,12 @@ constituent instructions might not. When a @code{clobber} expression for a register appears inside a @code{parallel} with other side effects, the register allocator guarantees that the register is unoccupied both before and after that -insn if it is a hard register clobber or the @samp{&} constraint -is specified for at least one alternative (@pxref{Modifiers}) of the -clobber. However, the reload phase may allocate a register used for -one of the inputs unless the @samp{&} constraint is specified for the -selected alternative. You can clobber either a specific hard +insn if it is a hard register clobber. For pseudo-register clobber, +the register allocator and the reload pass do not assign the same hard +register to the clobber and the input operands if there is an insn +alternative containing the @samp{&} constraint (@pxref{Modifiers}) for +the clobber and the hard register is in register classes of the +clobber in the alternative. You can clobber either a specific hard register, a pseudo register, or a @code{scratch} expression; in the latter two cases, GCC will allocate a hard register that is available there for use as a temporary. diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index 89343fe30f3..f4b2d6de42b 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -349,39 +349,169 @@ mark_ref_dead (df_ref def) mark_reg_dead (reg); } -/* Mark early clobber registers of the current INSN as live (if - LIVE_P) or dead. Return true if there are such registers. */ +/* Make pseudo REG conflicting with pseudo DREG, if the 1st pseudo + class is intersected with class CL. Advance the current program + point before making the conflict if ADVANCE_P. Return TRUE if we + will need to advance the current program point. */ static bool -mark_early_clobbers (rtx insn, bool live_p) +make_pseudo_conflict (rtx reg, enum reg_class cl, rtx dreg, bool advance_p) { - int alt; - int def; - df_ref *def_rec; - bool set_p = false; + ira_allocno_t a; - for (def = 0; def < recog_data.n_operands; def++) - { - rtx dreg = recog_data.operand[def]; - - if (GET_CODE (dreg) == SUBREG) - dreg = SUBREG_REG (dreg); - if (! REG_P (dreg)) - continue; + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + + if (! REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER) + return advance_p; + + a = ira_curr_regno_allocno_map[REGNO (reg)]; + if (! reg_classes_intersect_p (cl, ALLOCNO_COVER_CLASS (a))) + return advance_p; - for (alt = 0; alt < recog_data.n_alternatives; alt++) - if ((recog_op_alt[def][alt].earlyclobber) - && (recog_op_alt[def][alt].cl != NO_REGS)) - break; + if (advance_p) + curr_point++; - if (alt >= recog_data.n_alternatives) - continue; + mark_reg_live (reg); + mark_reg_live (dreg); + mark_reg_dead (reg); + mark_reg_dead (dreg); + + return false; +} - if (live_p) - mark_reg_live (dreg); +/* Check and make if necessary conflicts for pseudo DREG of class + DEF_CL of the current insn with input operand USE of class USE_CL. + Advance the current program point before making the conflict if + ADVANCE_P. Return TRUE if we will need to advance the current + program point. */ +static bool +check_and_make_def_use_conflict (rtx dreg, enum reg_class def_cl, + int use, enum reg_class use_cl, + bool advance_p) +{ + if (! reg_classes_intersect_p (def_cl, use_cl)) + return advance_p; + + advance_p = make_pseudo_conflict (recog_data.operand[use], + use_cl, dreg, advance_p); + /* Reload may end up swapping commutative operands, so you + have to take both orderings into account. The + constraints for the two operands can be completely + different. (Indeed, if the constraints for the two + operands are the same for all alternatives, there's no + point marking them as commutative.) */ + if (use < recog_data.n_operands + 1 + && recog_data.constraints[use][0] == '%') + advance_p + = make_pseudo_conflict (recog_data.operand[use + 1], + use_cl, dreg, advance_p); + if (use >= 1 + && recog_data.constraints[use - 1][0] == '%') + advance_p + = make_pseudo_conflict (recog_data.operand[use - 1], + use_cl, dreg, advance_p); + return advance_p; +} + +/* Check and make if necessary conflicts for definition DEF of class + DEF_CL of the current insn with input operands. Process only + constraints of alternative ALT. */ +static void +check_and_make_def_conflict (int alt, int def, enum reg_class def_cl) +{ + int use, use_match; + ira_allocno_t a; + enum reg_class use_cl, acl; + bool advance_p; + rtx dreg = recog_data.operand[def]; + + if (def_cl == NO_REGS) + return; + + if (GET_CODE (dreg) == SUBREG) + dreg = SUBREG_REG (dreg); + + if (! REG_P (dreg) || REGNO (dreg) < FIRST_PSEUDO_REGISTER) + return; + + a = ira_curr_regno_allocno_map[REGNO (dreg)]; + acl = ALLOCNO_COVER_CLASS (a); + if (! reg_classes_intersect_p (acl, def_cl)) + return; + + advance_p = true; + + for (use = 0; use < recog_data.n_operands; use++) + { + if (use == def || recog_data.operand_type[use] == OP_OUT) + return; + + if (recog_op_alt[use][alt].anything_ok) + use_cl = ALL_REGS; else - mark_reg_dead (dreg); - set_p = true; + use_cl = recog_op_alt[use][alt].cl; + + advance_p = check_and_make_def_use_conflict (dreg, def_cl, use, + use_cl, advance_p); + + if ((use_match = recog_op_alt[use][alt].matches) >= 0) + { + if (use_match == def) + return; + + if (recog_op_alt[use_match][alt].anything_ok) + use_cl = ALL_REGS; + else + use_cl = recog_op_alt[use_match][alt].cl; + advance_p = check_and_make_def_use_conflict (dreg, def_cl, use, + use_cl, advance_p); + } } +} + +/* Make conflicts of early clobber pseudo registers of the current + insn with its inputs. Avoid introducing unnecessary conflicts by + checking classes of the constraints and pseudos because otherwise + significant code degradation is possible for some targets. */ +static void +make_early_clobber_and_input_conflicts (void) +{ + int alt; + int def, def_match; + enum reg_class def_cl; + + for (alt = 0; alt < recog_data.n_alternatives; alt++) + for (def = 0; def < recog_data.n_operands; def++) + { + def_cl = NO_REGS; + if (recog_op_alt[def][alt].earlyclobber) + { + if (recog_op_alt[def][alt].anything_ok) + def_cl = ALL_REGS; + else + def_cl = recog_op_alt[def][alt].cl; + check_and_make_def_conflict (alt, def, def_cl); + } + if ((def_match = recog_op_alt[def][alt].matches) >= 0 + && (recog_op_alt[def_match][alt].earlyclobber + || recog_op_alt[def][alt].earlyclobber)) + { + if (recog_op_alt[def_match][alt].anything_ok) + def_cl = ALL_REGS; + else + def_cl = recog_op_alt[def_match][alt].cl; + check_and_make_def_conflict (alt, def, def_cl); + } + } +} + +/* Mark early clobber hard registers of the current INSN as live (if + LIVE_P) or dead. Return true if there are such registers. */ +static bool +mark_hard_reg_early_clobbers (rtx insn, bool live_p) +{ + df_ref *def_rec; + bool set_p = false; for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) if (DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MUST_CLOBBER)) @@ -792,25 +922,36 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) } } + make_early_clobber_and_input_conflicts (); + curr_point++; /* Mark each used value as live. */ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) mark_ref_live (*use_rec); - set_p = mark_early_clobbers (insn, true); - process_single_reg_class_operands (true, freq); + set_p = mark_hard_reg_early_clobbers (insn, true); + if (set_p) { - mark_early_clobbers (insn, false); + mark_hard_reg_early_clobbers (insn, false); - /* Mark each used value as live again. For example, a + /* Mark each hard reg as live again. For example, a hard register can be in clobber and in an insn input. */ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) - mark_ref_live (*use_rec); + { + rtx ureg = DF_REF_REG (*use_rec); + + if (GET_CODE (ureg) == SUBREG) + ureg = SUBREG_REG (ureg); + if (! REG_P (ureg) || REGNO (ureg) >= FIRST_PSEUDO_REGISTER) + continue; + + mark_ref_live (*use_rec); + } } curr_point++; -- 2.11.4.GIT