mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-09 20:31:36 +08:00
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
This commit is contained in:
parent
fb6f9bbc75
commit
a141f2d862
@ -1,3 +1,24 @@
|
||||
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)
|
||||
|
@ -1,3 +1,10 @@
|
||||
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 } } } } */
|
||||
|
12
gcc/testsuite/gcc.target/powerpc/pr86939.c
Normal file
12
gcc/testsuite/gcc.target/powerpc/pr86939.c
Normal file
@ -0,0 +1,12 @@
|
||||
/* { 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,} } } */
|
Loading…
x
Reference in New Issue
Block a user