lra: Stop registers being incorrectly marked live [PR92989]
diff mbox series

Message ID mpty2u2wa8f.fsf@arm.com
State New
Headers show
Series
  • lra: Stop registers being incorrectly marked live [PR92989]
Related show

Commit Message

Richard Sandiford Jan. 20, 2020, 1:03 p.m. UTC
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.

Tested on aarch64-linux-gnu and x86_64-linux-gnu, and that the
preprocessed libstdc++ code now compiles for mipsisa64-elf.
OK to install?

Richard


2020-01-20  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.
---
 gcc/lra-lives.c | 96 ++++++++++++++++++++++++++-----------------------
 1 file changed, 51 insertions(+), 45 deletions(-)

Comments

Jeff Law Jan. 26, 2020, 4:43 p.m. UTC | #1
On Mon, 2020-01-20 at 13:03 +0000, Richard Sandiford wrote:
> 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.
> 
> Tested on aarch64-linux-gnu and x86_64-linux-gnu, and that the
> preprocessed libstdc++ code now compiles for mipsisa64-elf.
> OK to install?
> 
> Richard
> 
> 
> 2020-01-20  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.
OK
jeff
>

Patch
diff mbox series

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);