commit 75e7d1600f47859df40b2ac0feff5a71e0dbb040
Author: Vladimir N. Makarov <vmakarov@redhat.com>
Date: Fri Dec 6 16:16:28 2024 -0500
[PR117248][LRA]: Rewriting reg notes update and fix calculation of conflict hard regs of pseudo.
LRA updates conflict hard regs of pseudo when some hard reg dies. A
complicated PA div/mod insns reference for clobbered explicit hard regs and
hard reg as operands. It prevents some hard reg dying although they
still conflict with pseudos living through. Although on such insns LRA
updates wrongly reg notes (REG_DEAD, REG_UNUSED) which are used later in
rematerialization subpass. The patch fixes the problems.
gcc/ChangeLog:
PR rtl-optimization/117248
* lra-lives.cc (start_living, start_dying): Remove.
(insn_regnos, out_insn_regnos, insn_regnos_live_after): New.
(sparseset_contains_pseudos_p): Remove.
(make_hard_regno_live, make_hard_regno_dead): Return true if
something in liveness is changed.
(mark_pseudo_live, mark_pseudo_dead): Ditto.
(mark_regno_live, mark_regno_dead): Ditto.
(clear_sparseset_regnos, regnos_in_sparseset_p): Use set instead
of dead_set.
(process_bb_lives): Rewrite dealing with reg notes. Update
conflict hard regs even when clobber hard reg is not marked as
dead.
(lra_create_live_ranges_1): Add initialization/finalization of
insn_regnos, out_insn_regnos, insn_regnos_live_after.
@@ -83,10 +83,10 @@ static sparseset pseudos_live_through_setjumps;
/* Set of hard regs (except eliminable ones) currently live. */
static HARD_REG_SET hard_regs_live;
-/* Set of pseudos and hard registers start living/dying in the current
- insn. These sets are used to update REG_DEAD and REG_UNUSED notes
- in the insn. */
-static sparseset start_living, start_dying;
+/* Set of pseudos and hard registers in the current insn, only out/inout ones,
+ and the current insn pseudos and hard registers living right after the
+ insn. */
+static sparseset insn_regnos, out_insn_regnos, insn_regnos_live_after;
/* Set of pseudos and hard regs dead and unused in the current
insn. */
@@ -227,17 +227,6 @@ enum point_type {
USE_POINT
};
-/* Return TRUE if set A contains a pseudo register, otherwise, return FALSE. */
-static bool
-sparseset_contains_pseudos_p (sparseset a)
-{
- int regno;
- EXECUTE_IF_SET_IN_SPARSESET (a, regno)
- if (!HARD_REGISTER_NUM_P (regno))
- return true;
- return false;
-}
-
/* Mark pseudo REGNO as living or dying at program point POINT, depending on
whether TYPE is a definition or a use. If this is the first reference to
REGNO that we've encountered, then create a new live range for it. */
@@ -276,29 +265,29 @@ update_pseudo_point (int regno, int point, enum point_type type)
/* The corresponding bitmaps of BB currently being processed. */
static bitmap bb_killed_pseudos, bb_gen_pseudos;
-/* Record hard register REGNO as now being live. It updates
- living hard regs and START_LIVING. */
-static void
+/* Record hard register REGNO as now being live. Return true if REGNO liveness
+ changes. */
+static bool
make_hard_regno_live (int regno)
{
lra_assert (HARD_REGISTER_NUM_P (regno));
if (TEST_HARD_REG_BIT (hard_regs_live, regno)
|| TEST_HARD_REG_BIT (eliminable_regset, regno))
- return;
+ return false;
SET_HARD_REG_BIT (hard_regs_live, regno);
- sparseset_set_bit (start_living, regno);
if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno))
bitmap_set_bit (bb_gen_pseudos, regno);
+ return true;
}
-/* Process the definition of hard register REGNO. This updates
- hard_regs_live, START_DYING and conflict hard regs for living
- pseudos. */
-static void
+/* Process the definition of hard register REGNO. This updates hard_regs_live
+ and conflict hard regs for living pseudos. Return true if REGNO liveness
+ changes. */
+static bool
make_hard_regno_dead (int regno)
{
if (TEST_HARD_REG_BIT (eliminable_regset, regno))
- return;
+ return false;
lra_assert (HARD_REGISTER_NUM_P (regno));
unsigned int i;
@@ -306,79 +295,89 @@ make_hard_regno_dead (int regno)
SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
- return;
+ return false;
CLEAR_HARD_REG_BIT (hard_regs_live, regno);
- sparseset_set_bit (start_dying, regno);
if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno))
{
bitmap_clear_bit (bb_gen_pseudos, regno);
bitmap_set_bit (bb_killed_pseudos, regno);
}
+ return true;
}
-/* Mark pseudo REGNO as now being live and update START_LIVING. */
-static void
+/* Mark pseudo REGNO as now being live. Return true if REGNO liveness
+ changes. */
+static bool
mark_pseudo_live (int regno)
{
lra_assert (!HARD_REGISTER_NUM_P (regno));
if (sparseset_bit_p (pseudos_live, regno))
- return;
-
+ return false;
sparseset_set_bit (pseudos_live, regno);
- sparseset_set_bit (start_living, regno);
+ return true;
}
-/* Mark pseudo REGNO as now being dead and update START_DYING. */
-static void
+/* Mark pseudo REGNO as now being dead. Return true if REGNO liveness
+ changes. */
+static bool
mark_pseudo_dead (int regno)
{
lra_assert (!HARD_REGISTER_NUM_P (regno));
lra_reg_info[regno].conflict_hard_regs |= hard_regs_live;
if (!sparseset_bit_p (pseudos_live, regno))
- return;
+ return false;
sparseset_clear_bit (pseudos_live, regno);
- sparseset_set_bit (start_dying, regno);
+ return true;
}
-/* Mark register REGNO (pseudo or hard register) in MODE as being live
- and update BB_GEN_PSEUDOS. */
-static void
+/* Mark register REGNO (pseudo or hard register) in MODE as being live and
+ update BB_GEN_PSEUDOS. Return true if REGNO liveness changes. */
+static bool
mark_regno_live (int regno, machine_mode mode)
{
int last;
+ bool change_p = false;
if (HARD_REGISTER_NUM_P (regno))
{
for (last = end_hard_regno (mode, regno); regno < last; regno++)
- make_hard_regno_live (regno);
+ if (make_hard_regno_live (regno))
+ change_p = true;
}
else
{
- mark_pseudo_live (regno);
+ if (mark_pseudo_live (regno))
+ change_p = true;
bitmap_set_bit (bb_gen_pseudos, regno);
}
+ return change_p;
}
-/* Mark register REGNO (pseudo or hard register) in MODE as being dead
- and update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS. */
-static void
+/* Mark register REGNO (pseudo or hard register) in MODE as being dead and
+ update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS. Return true if REGNO liveness
+ changes. */
+static bool
mark_regno_dead (int regno, machine_mode mode)
{
int last;
+ bool change_p = false;
if (HARD_REGISTER_NUM_P (regno))
{
for (last = end_hard_regno (mode, regno); regno < last; regno++)
- make_hard_regno_dead (regno);
+ if (make_hard_regno_dead (regno))
+ change_p = true;
}
else
{
- mark_pseudo_dead (regno);
+ if (mark_pseudo_dead (regno))
+ change_p = true;
bitmap_clear_bit (bb_gen_pseudos, regno);
bitmap_set_bit (bb_killed_pseudos, regno);
}
+ return change_p;
}
@@ -622,7 +621,7 @@ clear_sparseset_regnos (sparseset set, int regno, enum machine_mode mode)
{
if (regno >= FIRST_PSEUDO_REGISTER)
{
- sparseset_clear_bit (dead_set, regno);
+ sparseset_clear_bit (set, regno);
return;
}
for (int last = end_hard_regno (mode, regno); regno < last; regno++)
@@ -635,7 +634,7 @@ static bool
regnos_in_sparseset_p (sparseset set, int regno, enum machine_mode mode)
{
if (regno >= FIRST_PSEUDO_REGISTER)
- return sparseset_bit_p (dead_set, regno);
+ return sparseset_bit_p (set, regno);
for (int last = end_hard_regno (mode, regno); regno < last; regno++)
if (!sparseset_bit_p (set, regno))
return false;
@@ -852,8 +851,46 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
(regno, hard_regno, freq);
}
- sparseset_clear (start_living);
+ sparseset_clear (insn_regnos_live_after);
+ sparseset_clear (insn_regnos);
+ sparseset_clear (out_insn_regnos);
+
+ for (reg = curr_id->regs; reg != NULL; reg = reg->next)
+ {
+ if (!HARD_REGISTER_NUM_P (reg->regno))
+ {
+ sparseset_set_bit (insn_regnos, reg->regno);
+ if (reg->type != OP_IN)
+ sparseset_set_bit (out_insn_regnos, reg->regno);
+ if (sparseset_bit_p (pseudos_live, reg->regno))
+ sparseset_set_bit (insn_regnos_live_after, reg->regno);
+ }
+ else
+ {
+ for (int regno = reg->regno,
+ last = end_hard_regno (reg->biggest_mode, regno);
+ regno < last;
+ regno++)
+ {
+ sparseset_set_bit (insn_regnos, regno);
+ if (reg->type != OP_IN)
+ sparseset_set_bit (out_insn_regnos, regno);
+ if (TEST_HARD_REG_BIT (hard_regs_live, regno))
+ sparseset_set_bit (insn_regnos_live_after, regno);
+ }
+ }
+ }
+
+ for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
+ {
+ sparseset_set_bit (insn_regnos, reg->regno);
+ if (reg->type != OP_IN)
+ sparseset_set_bit (out_insn_regnos, reg->regno);
+ if (TEST_HARD_REG_BIT (hard_regs_live, reg->regno))
+ sparseset_set_bit (insn_regnos_live_after, reg->regno);
+ }
+ bool next_point_p = false;
/* Mark each defined value as live. We need to do this for
unused values because they still conflict with quantities
that are live at the time of the definition. */
@@ -861,24 +898,21 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
if (reg->type != OP_IN)
{
update_pseudo_point (reg->regno, curr_point, USE_POINT);
- mark_regno_live (reg->regno, reg->biggest_mode);
+ if (mark_regno_live (reg->regno, reg->biggest_mode))
+ next_point_p = true;
/* ??? Should be a no-op for unused registers. */
check_pseudos_live_through_calls (reg->regno, last_call_abi);
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_IN)
- make_hard_regno_live (reg->regno);
+ if (reg->type != OP_IN && make_hard_regno_live (reg->regno))
+ next_point_p = true;
if (curr_id->arg_hard_regs != NULL)
for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (!HARD_REGISTER_NUM_P (regno))
- /* It is a clobber. */
- make_hard_regno_live (regno - FIRST_PSEUDO_REGISTER);
-
- sparseset_copy (unused_set, start_living);
-
- sparseset_clear (start_dying);
+ if (!HARD_REGISTER_NUM_P (regno) /* It is a clobber. */
+ && make_hard_regno_live (regno - FIRST_PSEUDO_REGISTER))
+ next_point_p = true;
/* See which defined values die here. */
for (reg = curr_id->regs; reg != NULL; reg = reg->next)
@@ -887,19 +921,21 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
{
if (reg->type == OP_OUT)
update_pseudo_point (reg->regno, curr_point, DEF_POINT);
- mark_regno_dead (reg->regno, reg->biggest_mode);
+ if (mark_regno_dead (reg->regno, reg->biggest_mode))
+ next_point_p = true;
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
if (reg->type != OP_IN
- && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
- make_hard_regno_dead (reg->regno);
+ && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p
+ && make_hard_regno_dead (reg->regno))
+ next_point_p = true;
if (curr_id->arg_hard_regs != NULL)
for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (!HARD_REGISTER_NUM_P (regno))
- /* It is a clobber. */
- make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER);
+ if (!HARD_REGISTER_NUM_P (regno) /* It is a clobber. */
+ && make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER))
+ next_point_p = true;
if (call_p)
{
@@ -922,13 +958,11 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
}
/* Increment the current program point if we must. */
- if (sparseset_contains_pseudos_p (unused_set)
- || sparseset_contains_pseudos_p (start_dying))
+ if (next_point_p)
next_program_point (curr_point, freq);
/* If we removed the source reg from a simple register copy from the
- live set above, then add it back now so we don't accidentally add
- it to the start_living set below. */
+ live set above, then add it back now. */
if (ignore_reg != NULL_RTX)
{
int ignore_regno = REGNO (ignore_reg);
@@ -938,31 +972,27 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
sparseset_set_bit (pseudos_live, ignore_regno);
}
- sparseset_clear (start_living);
-
+ next_point_p = false;
/* Mark each used value as live. */
for (reg = curr_id->regs; reg != NULL; reg = reg->next)
if (reg->type != OP_OUT)
{
if (reg->type == OP_IN)
update_pseudo_point (reg->regno, curr_point, USE_POINT);
- mark_regno_live (reg->regno, reg->biggest_mode);
+ if (mark_regno_live (reg->regno, reg->biggest_mode))
+ next_point_p = true;
check_pseudos_live_through_calls (reg->regno, last_call_abi);
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type != OP_OUT)
- make_hard_regno_live (reg->regno);
+ if (reg->type != OP_OUT && make_hard_regno_live (reg->regno))
+ next_point_p = true;
if (curr_id->arg_hard_regs != NULL)
/* Make argument hard registers live. */
for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
- if (HARD_REGISTER_NUM_P (regno))
- make_hard_regno_live (regno);
-
- sparseset_and_compl (dead_set, start_living, start_dying);
-
- sparseset_clear (start_dying);
+ if (HARD_REGISTER_NUM_P (regno) && make_hard_regno_live (regno))
+ next_point_p = true;
/* Mark early clobber outputs dead. */
for (reg = curr_id->regs; reg != NULL; reg = reg->next)
@@ -971,12 +1001,14 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
{
if (reg->type == OP_OUT)
update_pseudo_point (reg->regno, curr_point, DEF_POINT);
- mark_regno_dead (reg->regno, reg->biggest_mode);
+ if (mark_regno_dead (reg->regno, reg->biggest_mode))
+ next_point_p = true;
/* We're done processing inputs, so make sure early clobber
operands that are both inputs and outputs are still live. */
- if (reg->type == OP_INOUT)
- mark_regno_live (reg->regno, reg->biggest_mode);
+ if (reg->type == OP_INOUT
+ && mark_regno_live (reg->regno, reg->biggest_mode))
+ next_point_p = true;
}
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
@@ -988,29 +1020,59 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
/* We can have early clobbered non-operand hard reg and
the same hard reg as an insn input. Don't make hard
reg dead before the insns. */
- for (reg2 = curr_static_id->hard_regs; reg2 != NULL; reg2 = reg2->next)
+ for (reg2 = curr_static_id->hard_regs;
+ reg2 != NULL;
+ reg2 = reg2->next)
if (reg2->type != OP_OUT && reg2->regno == reg->regno)
break;
- if (reg2 != NULL)
- continue;
-
- HARD_REG_SET clobbered_regset;
- CLEAR_HARD_REG_SET (clobbered_regset);
- SET_HARD_REG_BIT (clobbered_regset, reg->regno);
-
- for (reg2 = curr_id->regs; reg2 != NULL; reg2 = reg2->next)
- if (reg2->type != OP_OUT && reg2->regno < FIRST_PSEUDO_REGISTER
- && ira_hard_reg_set_intersection_p (reg2->regno,
- reg2->biggest_mode,
- clobbered_regset))
- break;
if (reg2 == NULL)
- make_hard_regno_dead (reg->regno);
+ {
+ HARD_REG_SET clobbered_regset;
+ CLEAR_HARD_REG_SET (clobbered_regset);
+ SET_HARD_REG_BIT (clobbered_regset, reg->regno);
+
+ for (reg2 = curr_id->regs; reg2 != NULL; reg2 = reg2->next)
+ if (reg2->type != OP_OUT && HARD_REGISTER_NUM_P (reg2->regno)
+ && ira_hard_reg_set_intersection_p (reg2->regno,
+ reg2->biggest_mode,
+ clobbered_regset))
+ break;
+ if (reg2 == NULL)
+ {
+ if (make_hard_regno_dead (reg->regno))
+ next_point_p = true;
+ }
+ else
+ {
+ EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
+ SET_HARD_REG_BIT (lra_reg_info[j].conflict_hard_regs,
+ reg->regno);
+ }
+ }
}
+ sparseset_clear (dead_set);
+ sparseset_clear (unused_set);
+ EXECUTE_IF_SET_IN_SPARSESET (insn_regnos, j)
+ {
+ if (sparseset_bit_p (insn_regnos_live_after, j))
+ continue;
+ if (!HARD_REGISTER_NUM_P (j))
+ {
+ if (sparseset_bit_p (pseudos_live, j))
+ sparseset_set_bit (dead_set, j);
+ }
+ else
+ {
+ if (TEST_HARD_REG_BIT (hard_regs_live, j))
+ sparseset_set_bit (dead_set, j);
+ }
+ if (sparseset_bit_p (out_insn_regnos, j))
+ sparseset_set_bit (unused_set, j);
+ }
+
/* Increment the current program point if we must. */
- if (sparseset_contains_pseudos_p (dead_set)
- || sparseset_contains_pseudos_p (start_dying))
+ if (next_point_p)
next_program_point (curr_point, freq);
/* Update notes. */
@@ -1043,10 +1105,16 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
}
link_loc = &XEXP (link, 1);
}
- EXECUTE_IF_SET_IN_SPARSESET (dead_set, j)
- add_reg_note (curr_insn, REG_DEAD, regno_reg_rtx[j]);
EXECUTE_IF_SET_IN_SPARSESET (unused_set, j)
- add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]);
+ {
+ gcc_assert (find_regno_note (curr_insn, REG_UNUSED, j) == NULL_RTX);
+ add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]);
+ }
+ EXECUTE_IF_SET_IN_SPARSESET (dead_set, j)
+ {
+ gcc_assert (find_regno_note (curr_insn, REG_DEAD, j) == NULL_RTX);
+ add_reg_note (curr_insn, REG_DEAD, regno_reg_rtx[j]);
+ }
}
if (bb_has_eh_pred (bb))
@@ -1408,8 +1476,9 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
pseudos_live = sparseset_alloc (max_regno);
pseudos_live_through_calls = sparseset_alloc (max_regno);
pseudos_live_through_setjumps = sparseset_alloc (max_regno);
- start_living = sparseset_alloc (max_regno);
- start_dying = sparseset_alloc (max_regno);
+ insn_regnos = sparseset_alloc (max_regno);
+ out_insn_regnos = sparseset_alloc (max_regno);
+ insn_regnos_live_after = sparseset_alloc (max_regno);
dead_set = sparseset_alloc (max_regno);
unused_set = sparseset_alloc (max_regno);
curr_point = 0;
@@ -1480,8 +1549,9 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
/* Clean up. */
sparseset_free (unused_set);
sparseset_free (dead_set);
- sparseset_free (start_dying);
- sparseset_free (start_living);
+ sparseset_free (insn_regnos);
+ sparseset_free (out_insn_regnos);
+ sparseset_free (insn_regnos_live_after);
sparseset_free (pseudos_live_through_calls);
sparseset_free (pseudos_live_through_setjumps);
sparseset_free (pseudos_live);