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

2008-10-06  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: r140906
This commit is contained in:
Vladimir Makarov 2008-10-06 15:34:26 +00:00 committed by Vladimir Makarov
parent e84319a3ff
commit 3517d3a087
3 changed files with 124 additions and 43 deletions

View File

@ -1,3 +1,16 @@
2008-10-06 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.
2008-10-06 Danny Smith <dannysmith@users.sourceforge.net>
* config/i386/mingw32.h (REAL_LIBGCC_SPEC): Add thread cleanup

View File

@ -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.

View File

@ -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)
{
/* 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. */
/* Mark the register referenced by use or def REF as live. */
static void
mark_ref_dead (struct df_ref *def)
mark_ref_live (struct df_ref *ref)
{
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);
reg = DF_REF_REG (ref);
if (GET_CODE (reg) == SUBREG)
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));
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_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 +762,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 +798,20 @@ 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);
/* 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++;
}