summaryrefslogtreecommitdiff
path: root/gcc/lra-lives.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2020-01-18 12:41:48 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2020-01-27 10:53:35 +0000
commite648e57efca6ce6d751ef8c2038608817b514fb4 (patch)
treeff7b9ee6a3e7cf26d5e69879b49944a56cc9c99f /gcc/lra-lives.c
parent150760dd6dd1899705790183d646fa5fc004554e (diff)
lra: Stop registers being incorrectly marked live [PR92989]
lra_assign has an assert to make sure that no pseudo is allocated to a conflicting hard register. It used to be restricted to !flag_ipa_ra, but in g:a1e6ee38e708ef2bdef4 I'd enabled it for flag_ipa_ra too. It then tripped while building libstdc++ for mips-mti-linux. The failure was due to code at the end of process_bb_lives. For an abnormal/EH edge, we need to make sure that all pseudos that are live on entry to the destination conflict with all hard registers that are clobbered by an abnormal call return. The usual way to do this would be to simulate a clobber of the hard registers, by making them live and them making them dead again. Making the registers live creates the conflict; making them dead again restores the correct live set for whatever follows. However, process_bb_lives skips the second step (making the registers dead again) at the start of a BB, presumably on the basis that there's no further code that needs a correct live set. The problem for the PR is that that wasn't quite true in practice. There was code further down process_bb_lives that updated the live-in set of the BB for some registers, and this live set was "contaminated" by registers that weren't live but that created conflicts. This information then got propagated to other blocks, so that registers that were made live purely to create a conflict at the start of the EH receiver then became needlessly live throughout preceding blocks. This in turn created a fake conflict with pseudos in those blocks, invalidating the choices made by IRA. The easiest fix seems to be to update the live-in set *before* adding the fake live registers. An alternative would be to simulate the full clobber, but that seems a bit wasteful. 2020-01-27 Richard Sandiford <richard.sandiford@arm.com> gcc/ PR rtl-optimization/92989 * lra-lives.c (process_bb_lives): Update the live-in set before processing additional clobbers.
Diffstat (limited to 'gcc/lra-lives.c')
-rw-r--r--gcc/lra-lives.c96
1 files changed, 51 insertions, 45 deletions
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index 0adac6b5a42..f439e899395 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -1023,6 +1023,57 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
make_hard_regno_live (regno);
}
+ bool live_change_p = false;
+ /* Check if bb border live info was changed. */
+ unsigned int live_pseudos_num = 0;
+ EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb),
+ FIRST_PSEUDO_REGISTER, j, bi)
+ {
+ live_pseudos_num++;
+ if (! sparseset_bit_p (pseudos_live, j))
+ {
+ live_change_p = true;
+ if (lra_dump_file != NULL)
+ fprintf (lra_dump_file,
+ " r%d is removed as live at bb%d start\n", j, bb->index);
+ break;
+ }
+ }
+ if (! live_change_p
+ && sparseset_cardinality (pseudos_live) != live_pseudos_num)
+ {
+ live_change_p = true;
+ if (lra_dump_file != NULL)
+ EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
+ if (! bitmap_bit_p (df_get_live_in (bb), j))
+ fprintf (lra_dump_file,
+ " r%d is added to live at bb%d start\n", j, bb->index);
+ }
+
+ /* The order of this code and the code below is important. At this
+ point hard_regs_live does genuinely contain only live registers.
+ Below we pretend other hard registers are live in order to create
+ conflicts with pseudos, but this fake live set shouldn't leak out
+ into the df info. */
+ for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
+ {
+ if (!TEST_HARD_REG_BIT (hard_regs_live, i))
+ continue;
+
+ if (!TEST_HARD_REG_BIT (hard_regs_spilled_into, i))
+ continue;
+
+ if (bitmap_bit_p (df_get_live_in (bb), i))
+ continue;
+
+ live_change_p = true;
+ if (lra_dump_file)
+ fprintf (lra_dump_file,
+ " hard reg r%d is added to live at bb%d start\n", i,
+ bb->index);
+ bitmap_set_bit (df_get_live_in (bb), i);
+ }
+
/* Pseudos can't go in stack regs at the start of a basic block that
is reached by an abnormal edge. Likewise for registers that are at
least partly call clobbered, because caller-save, fixup_abnormal_edges
@@ -1057,32 +1108,6 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
make_hard_regno_live (px);
}
- bool live_change_p = false;
- /* Check if bb border live info was changed. */
- unsigned int live_pseudos_num = 0;
- EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb),
- FIRST_PSEUDO_REGISTER, j, bi)
- {
- live_pseudos_num++;
- if (! sparseset_bit_p (pseudos_live, j))
- {
- live_change_p = true;
- if (lra_dump_file != NULL)
- fprintf (lra_dump_file,
- " r%d is removed as live at bb%d start\n", j, bb->index);
- break;
- }
- }
- if (! live_change_p
- && sparseset_cardinality (pseudos_live) != live_pseudos_num)
- {
- live_change_p = true;
- if (lra_dump_file != NULL)
- EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
- if (! bitmap_bit_p (df_get_live_in (bb), j))
- fprintf (lra_dump_file,
- " r%d is added to live at bb%d start\n", j, bb->index);
- }
/* See if we'll need an increment at the end of this basic block.
An increment is needed if the PSEUDOS_LIVE set is not empty,
to make sure the finish points are set up correctly. */
@@ -1102,25 +1127,6 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
check_pseudos_live_through_calls (j, last_call_abi);
}
- for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
- {
- if (!TEST_HARD_REG_BIT (hard_regs_live, i))
- continue;
-
- if (!TEST_HARD_REG_BIT (hard_regs_spilled_into, i))
- continue;
-
- if (bitmap_bit_p (df_get_live_in (bb), i))
- continue;
-
- live_change_p = true;
- if (lra_dump_file)
- fprintf (lra_dump_file,
- " hard reg r%d is added to live at bb%d start\n", i,
- bb->index);
- bitmap_set_bit (df_get_live_in (bb), i);
- }
-
if (need_curr_point_incr)
next_program_point (curr_point, freq);