diff mbox

PR80357: Negative register pressure

Message ID 87shlb5l73.fsf@e105548-lin.cambridge.arm.com
State New
Headers show

Commit Message

Richard Sandiford April 14, 2017, 10:37 a.m. UTC
In the PR testcase, there were two instructions that had
a large number of insn_reg_use records for the same register.
model_recompute was instead expecting the records to be unique
and so decremented the register pressure for each one.  We then
ended up with a negative pressure.

I think the records *should* be unique here, and that this is
really a bug in the generic -fsched-pressure code.  Making them
unique could be too invasive for GCC 7 though.  There are at
least two problems:

(1) sched-deps.c uses rtx_insn_lists instead of bitmaps to record
    the set of instructions that use a live register.
    sched-rgn.c then propagates this information between blocks
    in a region using list concatenation:

      succ_rl->uses = concat_INSN_LIST (pred_rl->uses, succ_rl->uses);

    So dependencies for common predecessors will appear multiple
    times in the list.

    In this case (and for the PR), it might be enough to make
    setup_insn_reg_uses detect duplicate entries.  However...

(2) setup_insn_reg_uses adds entries for all queued uses of a register
    at the point that the register is expected to die.  It looks like
    this doesn't work reliably for REG_INC registers: if a register R
    is auto-incremented in I1 and then used for the last time in I2,
    setup_insn_reg_uses will first treat the original R as dying
    in I1 (rightly IMO).  But that use of R in I1 is still in the
    reg_last->uses list when processing I2, so setup_insn_reg_uses
    adds it a second time.

There might be more reasons for multiple records: I stopped looking
at this point.

I think for GCC 7 it'd be more pragmatic to live with the duplicate
entries and keep the fix specific to SCHED_PRESSURE_MODEL.

Tested on aarch64-linux-gnu (which uses SCHED_PRESSURE_MODEL by default)
and on x86_64-linux-gnu.  OK to install?

Thanks,
Richard


gcc/
	PR rtl-optimization/80357
	* haifa-sched.c (tmp_bitmap): New variable.
	(model_recompute): Handle duplicate use records.
	(alloc_global_sched_pressure_data): Initialize tmp_bitmap.
	(free_global_sched_pressure_data): Free it.

gcc/testsuite/
	PR rtl-optimization/80357
	* gcc.c-torture/compile/pr80357.c: New test.

Comments

Jeff Law April 18, 2017, 6:46 p.m. UTC | #1
On 04/14/2017 04:37 AM, Richard Sandiford wrote:
> In the PR testcase, there were two instructions that had
> a large number of insn_reg_use records for the same register.
> model_recompute was instead expecting the records to be unique
> and so decremented the register pressure for each one.  We then
> ended up with a negative pressure.
> 
> I think the records *should* be unique here, and that this is
> really a bug in the generic -fsched-pressure code.  Making them
> unique could be too invasive for GCC 7 though.  There are at
> least two problems:
> 
> (1) sched-deps.c uses rtx_insn_lists instead of bitmaps to record
>      the set of instructions that use a live register.
>      sched-rgn.c then propagates this information between blocks
>      in a region using list concatenation:
> 
>        succ_rl->uses = concat_INSN_LIST (pred_rl->uses, succ_rl->uses);
> 
>      So dependencies for common predecessors will appear multiple
>      times in the list.
> 
>      In this case (and for the PR), it might be enough to make
>      setup_insn_reg_uses detect duplicate entries.  However...
> 
> (2) setup_insn_reg_uses adds entries for all queued uses of a register
>      at the point that the register is expected to die.  It looks like
>      this doesn't work reliably for REG_INC registers: if a register R
>      is auto-incremented in I1 and then used for the last time in I2,
>      setup_insn_reg_uses will first treat the original R as dying
>      in I1 (rightly IMO).  But that use of R in I1 is still in the
>      reg_last->uses list when processing I2, so setup_insn_reg_uses
>      adds it a second time.
> 
> There might be more reasons for multiple records: I stopped looking
> at this point.
> 
> I think for GCC 7 it'd be more pragmatic to live with the duplicate
> entries and keep the fix specific to SCHED_PRESSURE_MODEL.
> 
> Tested on aarch64-linux-gnu (which uses SCHED_PRESSURE_MODEL by default)
> and on x86_64-linux-gnu.  OK to install?
> 
> Thanks,
> Richard
> 
> 
> gcc/
> 	PR rtl-optimization/80357
> 	* haifa-sched.c (tmp_bitmap): New variable.
> 	(model_recompute): Handle duplicate use records.
> 	(alloc_global_sched_pressure_data): Initialize tmp_bitmap.
> 	(free_global_sched_pressure_data): Free it.
> 
> gcc/testsuite/
> 	PR rtl-optimization/80357
> 	* gcc.c-torture/compile/pr80357.c: New test.
OK.

I'm going to go ahead and commit.

Jeff
diff mbox

Patch

diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 07de1bb..0ebf110 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -930,6 +930,9 @@  static bitmap saved_reg_live;
 /* Registers mentioned in the current region.  */
 static bitmap region_ref_regs;
 
+/* Temporary bitmap used for SCHED_PRESSURE_MODEL.  */
+static bitmap tmp_bitmap;
+
 /* Effective number of available registers of a given class (see comment
    in sched_pressure_start_bb).  */
 static int sched_class_regs_num[N_REG_CLASSES];
@@ -2135,10 +2138,11 @@  model_recompute (rtx_insn *insn)
      registers that will be born in the range [model_curr_point, POINT).  */
   num_uses = 0;
   num_pending_births = 0;
+  bitmap_clear (tmp_bitmap);
   for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
     {
       new_last = model_last_use_except (use);
-      if (new_last < point)
+      if (new_last < point && bitmap_set_bit (tmp_bitmap, use->regno))
 	{
 	  gcc_assert (num_uses < ARRAY_SIZE (uses));
 	  uses[num_uses].last_use = new_last;
@@ -7241,6 +7245,8 @@  alloc_global_sched_pressure_data (void)
 	  saved_reg_live = BITMAP_ALLOC (NULL);
 	  region_ref_regs = BITMAP_ALLOC (NULL);
 	}
+      if (sched_pressure == SCHED_PRESSURE_MODEL)
+	tmp_bitmap = BITMAP_ALLOC (NULL);
 
       /* Calculate number of CALL_SAVED_REGS and FIXED_REGS in register classes
 	 that we calculate register pressure for.  */
@@ -7274,6 +7280,8 @@  free_global_sched_pressure_data (void)
 	  BITMAP_FREE (region_ref_regs);
 	  BITMAP_FREE (saved_reg_live);
 	}
+      if (sched_pressure == SCHED_PRESSURE_MODEL)
+	BITMAP_FREE (tmp_bitmap);
       BITMAP_FREE (curr_reg_live);
       free (sched_regno_pressure_class);
     }
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr80357.c b/gcc/testsuite/gcc.c-torture/compile/pr80357.c
new file mode 100644
index 0000000..a3c6ab0
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr80357.c
@@ -0,0 +1,18 @@ 
+typedef char a;
+a b, c;
+int d, e;
+void f(void *g) { *(volatile int *)g; }
+void j() {
+  a h, i;
+  for (; b; b += 2) {
+    d = b;
+    i = i >> b;
+    if (i)
+      continue;
+    f(&c + (b >> 2));
+    h = 0;
+    for (; h < 8 / 2; h++)
+      if (i << h)
+        e = 0;
+  }
+}