Commit a141f2d8 by Peter Bergner Committed by Peter Bergner

re PR rtl-optimization/86939 (IRA incorrectly creates an interference between a…

re PR rtl-optimization/86939 (IRA incorrectly creates an interference between a pseudo register and a hard register)

gcc/
	PR rtl-optimization/86939
	PR rtl-optimization/87479
	* ira.h (non_conflicting_reg_copy_p): New prototype.
	* ira-lives.c (ignore_reg_for_conflicts): New static variable.
	(make_hard_regno_dead): Don't add conflicts for register
	ignore_reg_for_conflicts.
	(make_object_dead): Likewise.
	(non_conflicting_reg_copy_p): New function.
	(process_bb_node_lives): Set ignore_reg_for_conflicts for copies.
	Remove special conflict handling of REAL_PIC_OFFSET_TABLE_REGNUM.
	* lra-lives.c (ignore_reg_for_conflicts): New static variable.
	(make_hard_regno_dead): Don't add conflicts for register
	ignore_reg_for_conflicts.  Remove special conflict handling of
	REAL_PIC_OFFSET_TABLE_REGNUM.  Remove now unused argument
	check_pic_pseudo_p and update callers.
	(mark_pseudo_dead): Don't add conflicts for register
	ignore_reg_for_conflicts.
	(process_bb_lives): Set ignore_reg_for_conflicts for copies.

gcc/testsuite/
	PR rtl-optimization/86939
	PR rtl-optimization/87479
	* gcc.target/powerpc/pr86939.c: New test.
	* gcc/testsuite/gcc.target/i386/pr49095.c: Fix expected results.

From-SVN: r264897
parent fb6f9bbc
2018-10-05 Peter Bergner <bergner@linux.ibm.com>
PR rtl-optimization/86939
PR rtl-optimization/87479
* ira.h (non_conflicting_reg_copy_p): New prototype.
* ira-lives.c (ignore_reg_for_conflicts): New static variable.
(make_hard_regno_dead): Don't add conflicts for register
ignore_reg_for_conflicts.
(make_object_dead): Likewise.
(non_conflicting_reg_copy_p): New function.
(process_bb_node_lives): Set ignore_reg_for_conflicts for copies.
Remove special conflict handling of REAL_PIC_OFFSET_TABLE_REGNUM.
* lra-lives.c (ignore_reg_for_conflicts): New static variable.
(make_hard_regno_dead): Don't add conflicts for register
ignore_reg_for_conflicts. Remove special conflict handling of
REAL_PIC_OFFSET_TABLE_REGNUM. Remove now unused argument
check_pic_pseudo_p and update callers.
(mark_pseudo_dead): Don't add conflicts for register
ignore_reg_for_conflicts.
(process_bb_lives): Set ignore_reg_for_conflicts for copies.
2018-10-05 Andrew Waterman <andrew@sifive.com>
Jim Wilson <jimw@sifive.com>
......@@ -84,6 +84,10 @@ static int *allocno_saved_at_call;
supplemental to recog_data. */
static alternative_mask preferred_alternatives;
/* If non-NULL, the source operand of a register to register copy for which
we should not add a conflict with the copy's destination operand. */
static rtx ignore_reg_for_conflicts;
/* Record hard register REGNO as now being live. */
static void
make_hard_regno_live (int regno)
......@@ -101,6 +105,11 @@ make_hard_regno_dead (int regno)
{
ira_object_t obj = ira_object_id_map[i];
if (ignore_reg_for_conflicts != NULL_RTX
&& REGNO (ignore_reg_for_conflicts)
== (unsigned int) ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)))
continue;
SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
}
......@@ -154,12 +163,38 @@ static void
make_object_dead (ira_object_t obj)
{
live_range_t lr;
int ignore_regno = -1;
int end_regno = -1;
sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj));
/* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts
with OBJ. */
if (ignore_reg_for_conflicts != NULL_RTX
&& REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER)
{
end_regno = END_REGNO (ignore_reg_for_conflicts);
int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts);
while (src_regno < end_regno)
{
if (TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), src_regno))
{
ignore_regno = end_regno = -1;
break;
}
src_regno++;
}
}
IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), hard_regs_live);
IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), hard_regs_live);
/* If IGNORE_REG_FOR_CONFLICTS did not already conflict with OBJ, make
sure it still doesn't. */
for (; ignore_regno < end_regno; ignore_regno++)
CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), ignore_regno);
lr = OBJECT_LIVE_RANGES (obj);
ira_assert (lr != NULL);
lr->finish = curr_point;
......@@ -1022,6 +1057,38 @@ find_call_crossed_cheap_reg (rtx_insn *insn)
return cheap_reg;
}
/* Determine whether INSN is a register to register copy of the type where
we do not need to make the source and destiniation registers conflict.
If this is a copy instruction, then return the source reg. Otherwise,
return NULL_RTX. */
rtx
non_conflicting_reg_copy_p (rtx_insn *insn)
{
rtx set = single_set (insn);
/* Disallow anything other than a simple register to register copy
that has no side effects. */
if (set == NULL_RTX
|| !REG_P (SET_DEST (set))
|| !REG_P (SET_SRC (set))
|| side_effects_p (set))
return NULL_RTX;
int dst_regno = REGNO (SET_DEST (set));
int src_regno = REGNO (SET_SRC (set));
machine_mode mode = GET_MODE (SET_DEST (set));
/* Computing conflicts for register pairs is difficult to get right, so
for now, disallow it. */
if ((dst_regno < FIRST_PSEUDO_REGISTER
&& hard_regno_nregs (dst_regno, mode) != 1)
|| (src_regno < FIRST_PSEUDO_REGISTER
&& hard_regno_nregs (src_regno, mode) != 1))
return NULL_RTX;
return SET_SRC (set);
}
/* Process insns of the basic block given by its LOOP_TREE_NODE to
update allocno live ranges, allocno hard register conflicts,
intersected calls, and register pressure info for allocnos for the
......@@ -1107,22 +1174,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
curr_point);
call_p = CALL_P (insn);
#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
int regno;
bool clear_pic_use_conflict_p = false;
/* Processing insn usage in call insn can create conflict
with pic pseudo and pic hard reg and that is wrong.
Check this situation and fix it at the end of the insn
processing. */
if (call_p && pic_offset_table_rtx != NULL_RTX
&& (regno = REGNO (pic_offset_table_rtx)) >= FIRST_PSEUDO_REGISTER
&& (a = ira_curr_regno_allocno_map[regno]) != NULL)
clear_pic_use_conflict_p
= (find_regno_fusage (insn, USE, REAL_PIC_OFFSET_TABLE_REGNUM)
&& ! TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS
(ALLOCNO_OBJECT (a, 0)),
REAL_PIC_OFFSET_TABLE_REGNUM));
#endif
ignore_reg_for_conflicts = non_conflicting_reg_copy_p (insn);
/* Mark each defined value as live. We need to do this for
unused values because they still conflict with quantities
......@@ -1276,20 +1328,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
}
}
#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
if (clear_pic_use_conflict_p)
{
regno = REGNO (pic_offset_table_rtx);
a = ira_curr_regno_allocno_map[regno];
CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (ALLOCNO_OBJECT (a, 0)),
REAL_PIC_OFFSET_TABLE_REGNUM);
CLEAR_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS
(ALLOCNO_OBJECT (a, 0)),
REAL_PIC_OFFSET_TABLE_REGNUM);
}
#endif
curr_point++;
}
ignore_reg_for_conflicts = NULL_RTX;
if (bb_has_eh_pred (bb))
for (j = 0; ; ++j)
......
......@@ -210,6 +210,9 @@ extern void ira_adjust_equiv_reg_cost (unsigned, int);
/* ira-costs.c */
extern void ira_costs_c_finalize (void);
/* ira-lives.c */
extern rtx non_conflicting_reg_copy_p (rtx_insn *);
/* Spilling static chain pseudo may result in generation of wrong
non-local goto code using frame-pointer to address saved stack
pointer value after restoring old frame pointer value. The
......
......@@ -96,6 +96,10 @@ static bitmap_head temp_bitmap;
/* Pool for pseudo live ranges. */
static object_allocator<lra_live_range> lra_live_range_pool ("live ranges");
/* If non-NULL, the source operand of a register to register copy for which
we should not add a conflict with the copy's destination operand. */
static rtx ignore_reg_for_conflicts;
/* Free live range list LR. */
static void
free_live_range_list (lra_live_range_t lr)
......@@ -239,11 +243,9 @@ make_hard_regno_live (int regno)
/* Process the definition of hard register REGNO. This updates
hard_regs_live, START_DYING and conflict hard regs for living
pseudos. Conflict hard regs for the pic pseudo is not updated if
REGNO is REAL_PIC_OFFSET_TABLE_REGNUM and CHECK_PIC_PSEUDO_P is
true. */
pseudos. */
static void
make_hard_regno_dead (int regno, bool check_pic_pseudo_p ATTRIBUTE_UNUSED)
make_hard_regno_dead (int regno)
{
lra_assert (regno < FIRST_PSEUDO_REGISTER);
if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
......@@ -251,13 +253,12 @@ make_hard_regno_dead (int regno, bool check_pic_pseudo_p ATTRIBUTE_UNUSED)
sparseset_set_bit (start_dying, regno);
unsigned int i;
EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
if (! check_pic_pseudo_p
|| regno != REAL_PIC_OFFSET_TABLE_REGNUM
|| pic_offset_table_rtx == NULL
|| i != REGNO (pic_offset_table_rtx))
#endif
{
if (ignore_reg_for_conflicts != NULL_RTX
&& REGNO (ignore_reg_for_conflicts) == i)
continue;
SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
}
CLEAR_HARD_REG_BIT (hard_regs_live, regno);
if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno))
{
......@@ -294,14 +295,41 @@ static void
mark_pseudo_dead (int regno, int point)
{
lra_live_range_t p;
int ignore_regno = -1;
int end_regno = -1;
lra_assert (regno >= FIRST_PSEUDO_REGISTER);
lra_assert (sparseset_bit_p (pseudos_live, regno));
sparseset_clear_bit (pseudos_live, regno);
sparseset_set_bit (start_dying, regno);
/* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts
with REGNO. */
if (ignore_reg_for_conflicts != NULL_RTX
&& REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER)
{
end_regno = END_REGNO (ignore_reg_for_conflicts);
int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts);
while (src_regno < end_regno)
{
if (TEST_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs,
src_regno))
{
ignore_regno = end_regno = -1;
break;
}
src_regno++;
}
}
IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
/* If IGNORE_REG_FOR_CONFLICTS did not already conflict with REGNO, make
sure it still doesn't. */
for (; ignore_regno < end_regno; ignore_regno++)
CLEAR_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, ignore_regno);
if (complete_info_p || lra_get_regno_hard_regno (regno) < 0)
{
p = lra_reg_info[regno].live_ranges;
......@@ -350,7 +378,7 @@ mark_regno_dead (int regno, machine_mode mode, int point)
if (regno < FIRST_PSEUDO_REGISTER)
{
for (last = end_hard_regno (mode, regno); regno < last; regno++)
make_hard_regno_dead (regno, false);
make_hard_regno_dead (regno);
}
else
{
......@@ -747,6 +775,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
}
call_p = CALL_P (curr_insn);
ignore_reg_for_conflicts = non_conflicting_reg_copy_p (curr_insn);
src_regno = (set != NULL_RTX && REG_P (SET_SRC (set))
? REGNO (SET_SRC (set)) : -1);
dst_regno = (set != NULL_RTX && REG_P (SET_DEST (set))
......@@ -858,14 +887,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
if (reg->type == OP_OUT
&& ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
make_hard_regno_dead (reg->regno, false);
make_hard_regno_dead (reg->regno);
if (curr_id->arg_hard_regs != NULL)
for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
if (regno >= FIRST_PSEUDO_REGISTER)
/* It is a clobber. Don't create conflict of used
REAL_PIC_OFFSET_TABLE_REGNUM and the pic pseudo. */
make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER, true);
/* It is a clobber. */
make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER);
if (call_p)
{
......@@ -926,8 +954,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
make_hard_regno_live (reg->regno);
if (curr_id->arg_hard_regs != NULL)
/* Make argument hard registers live. Don't create conflict
of used REAL_PIC_OFFSET_TABLE_REGNUM and the pic pseudo. */
/* Make argument hard registers live. */
for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
if (regno < FIRST_PSEUDO_REGISTER)
make_hard_regno_live (regno);
......@@ -955,7 +982,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
if (reg2->type != OP_OUT && reg2->regno == reg->regno)
break;
if (reg2 == NULL)
make_hard_regno_dead (reg->regno, false);
make_hard_regno_dead (reg->regno);
}
if (need_curr_point_incr)
......@@ -990,6 +1017,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
EXECUTE_IF_SET_IN_SPARSESET (unused_set, j)
add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]);
}
ignore_reg_for_conflicts = NULL_RTX;
if (bb_has_eh_pred (bb))
for (j = 0; ; ++j)
......
2018-10-05 Peter Bergner <bergner@linux.ibm.com>
PR rtl-optimization/86939
PR rtl-optimization/87479
* gcc.target/powerpc/pr86939.c: New test.
* gcc/testsuite/gcc.target/i386/pr49095.c: Fix expected results.
2018-10-05 Bernd Edlinger <bernd.edlinger@hotmail.de>
* gnat.dg/string_merge1.adb: Fix test expectations.
......
......@@ -73,4 +73,5 @@ G (long)
/* { dg-final { scan-assembler-not "test\[lq\]" } } */
/* The {f,h}{char,short,int,long}xor functions aren't optimized into
a RMW instruction, so need load, modify and store. FIXME eventually. */
/* { dg-final { scan-assembler-times "\\), %" 8 } } */
/* { dg-final { scan-assembler-times "\\), %" 57 { target { ia32 } } } } */
/* { dg-final { scan-assembler-times "\\), %" 45 { target { ! ia32 } } } } */
/* { dg-do compile { target { powerpc*-*-* } } } */
/* { dg-options "-O2" } */
typedef long (*fptr_t) (void);
long
func (fptr_t *p)
{
if (p)
return (*p) ();
return 0;
}
/* { dg-final { scan-assembler-not {mr %?r?12,} } } */
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