re PR middle-end/37535 (gcc/libgcc2.c:404: internal compiler error: Floating point exception)

2008-09-25  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.

	* doc/rtx.texi (clobber): Change how RA deals with clobbers.

From-SVN: r140679
This commit is contained in:
Vladimir Makarov 2008-09-26 00:43:11 +00:00 committed by Vladimir Makarov
parent 3fcac00fec
commit 83d48fad1f
3 changed files with 109 additions and 46 deletions

View File

@ -1,3 +1,16 @@
2008-09-25 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.
* doc/rtl.texi (clobber): Change how RA deals with clobbers.
2008-09-25 Vladimir Makarov <vmakarov@redhat.com> 2008-09-25 Vladimir Makarov <vmakarov@redhat.com>
PR middle-end/37448 PR middle-end/37448

View File

@ -2930,12 +2930,13 @@ constituent instructions might not.
When a @code{clobber} expression for a register appears inside a When a @code{clobber} expression for a register appears inside a
@code{parallel} with other side effects, the register allocator @code{parallel} with other side effects, the register allocator
guarantees that the register is unoccupied both before and after that guarantees that the register is unoccupied both before and after that
insn. However, the reload phase may allocate a register used for one of insn if the @samp{&} constraint is specified for at least one
the inputs unless the @samp{&} constraint is specified for the selected alternative (@pxref{Modifiers}) of the clobber. However, the reload
alternative (@pxref{Modifiers}). You can clobber either a specific hard phase may allocate a register used for one of the inputs unless the
register, a pseudo register, or a @code{scratch} expression; in the @samp{&} constraint is specified for the selected alternative. You
latter two cases, GCC will allocate a hard register that is available can clobber either a specific hard register, a pseudo register, or a
there for use as a temporary. @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 For instructions that require a temporary register, you should use
@code{scratch} instead of a pseudo-register because this will allow the @code{scratch} instead of a pseudo-register because this will allow the

View File

@ -209,20 +209,15 @@ clear_allocno_live (ira_allocno_t a)
sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a)); sparseset_clear_bit (allocnos_live, ALLOCNO_NUM (a));
} }
/* Mark the register referenced by use or def REF as live /* Mark the register REG as live. Store a 1 in hard_regs_live or
Store a 1 in hard_regs_live or allocnos_live for this register or allocnos_live for this register or the corresponding allocno,
the corresponding allocno, record how many consecutive hardware record how many consecutive hardware registers it actually
registers it actually needs. */ needs. */
static void static void
mark_ref_live (struct df_ref *ref) mark_reg_live (rtx reg)
{ {
rtx reg;
int regno; int regno;
reg = DF_REF_REG (ref);
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
gcc_assert (REG_P (reg)); gcc_assert (REG_P (reg));
regno = REGNO (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 /* Mark the register referenced by use or def REF as live. */
instruction's inputs. */
static bool
def_conflicts_with_inputs_p (struct df_ref *def)
{
/* Conservatively assume that the condition is true for all clobbers. */
return DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER);
}
/* Mark the register referenced by definition DEF as dead, if the
definition is a total one. Store a 0 in hard_regs_live or
allocnos_live for the register. */
static void static void
mark_ref_dead (struct df_ref *def) mark_ref_live (struct df_ref *ref)
{ {
unsigned int i;
rtx reg; rtx reg;
int regno;
if (DF_REF_FLAGS_IS_SET (def, DF_REF_PARTIAL) reg = DF_REF_REG (ref);
|| DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL))
return;
reg = DF_REF_REG (def);
if (GET_CODE (reg) == SUBREG) if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg); reg = SUBREG_REG (reg);
mark_reg_live (reg);
}
/* Mark the register REG as dead. Store a 0 in hard_regs_live or
allocnos_live for the register. */
static void
mark_reg_dead (rtx reg)
{
int regno;
gcc_assert (REG_P (reg)); gcc_assert (REG_P (reg));
regno = REGNO (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)) else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
{ {
unsigned int i;
int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
enum reg_class cover_class; 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 /* Checks that CONSTRAINTS permits to use only one hard register. If
it is so, the function returns the class of the hard register. it is so, the function returns the class of the hard register.
Otherwise it returns NO_REGS. */ 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_iterator bi;
bitmap reg_live_out; bitmap reg_live_out;
unsigned int px; unsigned int px;
bool set_p;
bb = loop_tree_node->bb; bb = loop_tree_node->bb;
if (bb != NULL) if (bb != NULL)
@ -698,6 +753,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
} }
extract_insn (insn); extract_insn (insn);
preprocess_constraints ();
process_single_reg_class_operands (false, freq); process_single_reg_class_operands (false, freq);
/* See which defined values die here. */ /* 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++) for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
mark_ref_live (*use_rec); mark_ref_live (*use_rec);
/* If any defined values conflict with the inputs, mark those set_p = mark_early_clobbers (insn, true);
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);
process_single_reg_class_operands (true, freq); process_single_reg_class_operands (true, freq);
/* See which of the defined values we marked as live are dead if (set_p)
before the instruction. */ mark_early_clobbers (insn, false);
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
if (def_conflicts_with_inputs_p (*def_rec))
mark_ref_dead (*def_rec);
curr_point++; curr_point++;
} }