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:
parent
3fcac00fec
commit
83d48fad1f
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
129
gcc/ira-lives.c
129
gcc/ira-lives.c
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue