Commit 22c02455 by Vladimir Makarov Committed by Vladimir Makarov

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
parent 0ca9fa56
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
* ira-build.c (ira_flattening): Recalculate
ALLOCNO_TOTAL_NO_STACK_REG_P and ALLOCNO_TOTAL_CONFLICT_HARD_REGS
......
......@@ -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.
......
......@@ -349,39 +349,169 @@ 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)
{
int alt;
int def;
df_ref *def_rec;
bool set_p = false;
ira_allocno_t a;
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;
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;
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 (advance_p)
curr_point++;
if (alt >= recog_data.n_alternatives)
continue;
mark_reg_live (reg);
mark_reg_live (dreg);
mark_reg_dead (reg);
mark_reg_dead (dreg);
return false;
}
if (live_p)
mark_reg_live (dreg);
/* 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
mark_reg_dead (dreg);
set_p = true;
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, 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_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++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment