From 36d2792f22664bab9d29254b8a5b55e14c3bdec4 Mon Sep 17 00:00:00 2001 From: vmakarov Date: Fri, 26 Sep 2008 00:43:11 +0000 Subject: [PATCH] 2008-09-25 Vladimir Makarov PR middle-end/37535 * ira-lives.c (mark_reg_live, mark_reg_dead): New functions. (mark_ref_live, mark_ref_dead): Use them. (def_conflicts_with_inputs_p): Remove. (mark_early_clobbers): New function. (process_bb_node_lives): Call preprocess_constraints and mark_early_clobbers. * doc/rtx.texi (clobber): Change how RA deals with clobbers. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@140679 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 ++++++ gcc/doc/rtl.texi | 13 +++--- gcc/ira-lives.c | 125 ++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 107 insertions(+), 44 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fa2f0ccd52b..86d2c46d6a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2008-09-25 Vladimir Makarov + PR middle-end/37535 + + * ira-lives.c (mark_reg_live, mark_reg_dead): New functions. + (mark_ref_live, mark_ref_dead): Use them. + (def_conflicts_with_inputs_p): Remove. + (mark_early_clobbers): New function. + (process_bb_node_lives): Call preprocess_constraints and + mark_early_clobbers. + + * doc/rtl.texi (clobber): Change how RA deals with clobbers. + +2008-09-25 Vladimir Makarov + PR middle-end/37448 * ira-int.h (IRA_ALLOCNO_TEMP): Rename to ALLOCNO_TEMP. diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 148e19ddc9a..984ee432641 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -2930,12 +2930,13 @@ 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. However, the reload phase may allocate a register used for one of -the inputs unless the @samp{&} constraint is specified for the selected -alternative (@pxref{Modifiers}). 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. +insn if 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 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. For instructions that require a temporary register, you should use @code{scratch} instead of a pseudo-register because this will allow the diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index 609708e9069..e49860fa927 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -209,20 +209,15 @@ clear_allocno_live (ira_allocno_t a) sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a)); } -/* Mark the register referenced by use or def REF as live - Store a 1 in hard_regs_live or allocnos_live for this register or - the corresponding allocno, record how many consecutive hardware - registers it actually needs. */ - +/* Mark the register REG as live. Store a 1 in hard_regs_live or + allocnos_live for this register or the corresponding allocno, + record how many consecutive hardware registers it actually + needs. */ static void -mark_ref_live (struct df_ref *ref) +mark_reg_live (rtx reg) { - rtx reg; int regno; - reg = DF_REF_REG (ref); - if (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); gcc_assert (REG_P (reg)); regno = REGNO (reg); @@ -269,32 +264,25 @@ mark_ref_live (struct df_ref *ref) } } -/* Return true if the definition described by DEF conflicts with the - instruction's inputs. */ -static bool -def_conflicts_with_inputs_p (struct df_ref *def) +/* Mark the register referenced by use or def REF as live. */ +static void +mark_ref_live (struct df_ref *ref) { - /* Conservatively assume that the condition is true for all clobbers. */ - return DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER); + rtx reg; + + reg = DF_REF_REG (ref); + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + mark_reg_live (reg); } -/* Mark the register referenced by definition DEF as dead, if the - definition is a total one. Store a 0 in hard_regs_live or +/* Mark the register REG as dead. Store a 0 in hard_regs_live or allocnos_live for the register. */ static void -mark_ref_dead (struct df_ref *def) +mark_reg_dead (rtx reg) { - unsigned int i; - rtx reg; int regno; - if (DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL) - || DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)) - return; - - reg = DF_REF_REG (def); - if (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); gcc_assert (REG_P (reg)); regno = REGNO (reg); @@ -312,6 +300,7 @@ mark_ref_dead (struct df_ref *def) } else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno)) { + unsigned int i; int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; enum reg_class cover_class; @@ -343,6 +332,71 @@ mark_ref_dead (struct df_ref *def) } } +/* Mark the register referenced by definition DEF as dead, if the + definition is a total one. */ +static void +mark_ref_dead (struct df_ref *def) +{ + rtx reg; + + if (DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL) + || DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)) + return; + + reg = DF_REF_REG (def); + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + 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. */ +static bool +mark_early_clobbers (rtx insn, bool live_p) +{ + int alt; + int def; + struct df_ref **def_rec; + bool set_p = false; + bool asm_p = asm_noperands (PATTERN (insn)) >= 0; + + if (asm_p) + for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) + if (DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MUST_CLOBBER)) + { + if (live_p) + mark_ref_live (*def_rec); + else + mark_ref_dead (*def_rec); + set_p = true; + } + + 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; + + 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 (alt >= recog_data.n_alternatives) + continue; + + if (live_p) + mark_reg_live (dreg); + else + mark_reg_dead (dreg); + set_p = true; + } + return set_p; +} + /* Checks that CONSTRAINTS permits to use only one hard register. If it is so, the function returns the class of the hard register. Otherwise it returns NO_REGS. */ @@ -580,6 +634,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) bitmap_iterator bi; bitmap reg_live_out; unsigned int px; + bool set_p; bb = loop_tree_node->bb; if (bb != NULL) @@ -698,6 +753,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) } extract_insn (insn); + preprocess_constraints (); process_single_reg_class_operands (false, freq); /* See which defined values die here. */ @@ -733,19 +789,12 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) mark_ref_live (*use_rec); - /* If any defined values conflict with the inputs, mark those - defined values as live. */ - for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) - if (def_conflicts_with_inputs_p (*def_rec)) - mark_ref_live (*def_rec); + set_p = mark_early_clobbers (insn, true); process_single_reg_class_operands (true, freq); - /* See which of the defined values we marked as live are dead - before the instruction. */ - for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) - if (def_conflicts_with_inputs_p (*def_rec)) - mark_ref_dead (*def_rec); + if (set_p) + mark_early_clobbers (insn, false); curr_point++; } -- 2.11.4.GIT