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

2008-10-15  Vladimir Makarov  <vmakarov@redhat.com>

	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.

From-SVN: r141160
This commit is contained in:
Vladimir Makarov 2008-10-16 00:51:34 +00:00 committed by Vladimir Makarov
parent 0ca9fa56e9
commit 22c02455bf
3 changed files with 196 additions and 38 deletions

View File

@ -1,3 +1,19 @@
2008-10-15 Vladimir Makarov <vmakarov@redhat.com>
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 <vmakarov@redhat.com>
PR middle-end/37674

View File

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

View File

@ -349,40 +349,170 @@ 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)
{
ira_allocno_t a;
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;
if (advance_p)
curr_point++;
mark_reg_live (reg);
mark_reg_live (dreg);
mark_reg_dead (reg);
mark_reg_dead (dreg);
return false;
}
/* 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
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;
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 = 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))
{
@ -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++;