This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA: one more patch to solve PR37535
- From: Vladimir Makarov <vmakarov at redhat dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Cc: Jeffrey Law <law at redhat dot com>
- Date: Mon, 29 Sep 2008 18:27:38 -0400
- Subject: RFA: one more patch to solve PR37535
Jeff, This is one more patch to fix PR37355. The changes in comparison
with previous version are in mark_early_clobber and
process_bb_node_lives. The problem was in wrong processing early
clobber of hard registers which are not operands and therefore have no
constraints. One example of such insn from rs6000.md is
(define_insn ""
[(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b"))
(mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b")))
(use (match_operand:SI 2 "immediate_operand" "i"))
(use (match_operand:SI 3 "immediate_operand" "i"))
(clobber (match_operand:SI 4 "gpc_reg_operand" "=&r"))
(clobber (reg:SI 6))
(clobber (reg:SI 7))
(clobber (reg:SI 8))
(clobber (reg:SI 9))
(clobber (reg:SI 10))
(clobber (reg:SI 11))
(clobber (reg:SI 12))
(clobber (match_scratch:SI 5 "=q"))]
Now all clobbers of hard registers are treated as early clobbers.
Last 3 days I tested the patch on 4 platforms for all reported problems
on bootstraps (as crashes and code differences) and testsuite
regressions using stage3 compiler. Al the problems are reported for ppc
with specific config options.
The patch was successfully tested on bootstrap x86, i686, itanium,
ppc64, ppc64 with --with-cpu=default32, ppc64 with --with-cpu=default32
--with-tune=cell. The patch was also sucessfully tested on gcc testuite
on x86, x86_64, itanium, ppc64, and ppc64 with --with-cpu=default32
--with-tune=cell on the bootstrapped version.
Ok to commit?
Sorry, for any inconvinience with the previous version of the patch. I
tested it thorougly but it was not enough to find the problem.
2008-09-24 Vladimir Makarov <vmakarov@redhat.com>
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. Process inputs again if necessary.
* doc/rtx.texi (clobber): Change how RA deals with clobbers.
Index: ira-lives.c
===================================================================
--- ira-lives.c (revision 140721)
+++ ira-lives.c (working copy)
@@ -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,80 @@ 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;
+
+ 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;
+ }
+
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+ if (DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MUST_CLOBBER))
+ {
+ rtx dreg = DF_REF_REG (*def_rec);
+
+ if (GET_CODE (dreg) == SUBREG)
+ dreg = SUBREG_REG (dreg);
+ if (! REG_P (dreg) || REGNO (dreg) >= FIRST_PSEUDO_REGISTER)
+ continue;
+
+ /* Hard register clobbers are believed to be early clobber
+ because there is no way to say that non-operand hard
+ register clobbers are not early ones. */
+ if (live_p)
+ mark_ref_live (*def_rec);
+ else
+ mark_ref_dead (*def_rec);
+ 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 +643,7 @@ process_bb_node_lives (ira_loop_tree_nod
bitmap_iterator bi;
bitmap reg_live_out;
unsigned int px;
+ bool set_p;
bb = loop_tree_node->bb;
if (bb != NULL)
@@ -698,6 +762,7 @@ process_bb_node_lives (ira_loop_tree_nod
}
extract_insn (insn);
+ preprocess_constraints ();
process_single_reg_class_operands (false, freq);
/* See which defined values die here. */
@@ -733,19 +798,20 @@ process_bb_node_lives (ira_loop_tree_nod
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);
+
+ /* Mark each used value 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);
+ }
curr_point++;
}
Index: doc/rtl.texi
===================================================================
--- doc/rtl.texi (revision 140723)
+++ doc/rtl.texi (working copy)
@@ -2930,9 +2930,11 @@ 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
+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
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.