+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>
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)
{
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);
}
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;
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
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
}
}
-#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)
/* 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
/* 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)
/* 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))
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))
{
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;
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
{
}
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))
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)
{
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);
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)
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.
/* { 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 } } } } */
--- /dev/null
+/* { 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,} } } */