This is the first of either 2 (possibly 3) patches to address the
fix-r4000-10 regression in BZ87761.

There's a bit of winding path to get to the code quality regression and
some things we can and should do for gcc-10 (smarter splitters, avoid
stupid code from init-regs).

Even if those issues earlier in the pipeline were fixed we actually
wouldn't get any code improvement for fix-r1000-10.  We actually need to
dig into regcprop.

As we enter regcprop we have the following horrific RTL:

>> (insn 33 5 6 2 (set (reg:DI 6 $6 [207])
>>         (reg:DI 5 $5 [ y ])) "j.c":8:40 313 {*movdi_64bit}
>>      (nil))
>> (note 6 33 7 2 NOTE_INSN_DELETED)
>> (note 7 6 35 2 NOTE_INSN_FUNCTION_BEG)
>> (insn 35 7 36 2 (set (reg:DI 2 $2 [orig:200 x ] [200])
>>         (const_int 0 [0])) "j.c":8:49 313 {*movdi_64bit}
>>      (nil))
>> (insn 36 35 10 2 (set (reg:DI 3 $3 [ x+8 ])
>>         (const_int 0 [0])) "j.c":8:49 313 {*movdi_64bit}
>>      (nil))
>> (insn 10 36 11 2 (set (reg:DI 2 $2 [orig:200 x ] [200])
>>         (reg:DI 4 $4 [206])) "j.c":8:49 313 {*movdi_64bit}
>>      (nil))
>> (insn 11 10 37 2 (set (reg:DI 3 $3 [ x+8 ])
>>         (const_int 0 [0])) "j.c":8:49 313 {*movdi_64bit}
>>      (nil))
>> (insn 37 11 38 2 (set (reg:DI 4 $4 [orig:201 y ] [201])
>>         (const_int 0 [0])) "j.c":8:63 313 {*movdi_64bit}
>>      (nil))
>> (insn 38 37 12 2 (set (reg:DI 5 $5 [ y+8 ])
>>         (const_int 0 [0])) "j.c":8:63 313 {*movdi_64bit}
>>      (nil))
>> (insn 12 38 13 2 (set (reg:DI 4 $4 [orig:201 y ] [201])
>>         (reg:DI 6 $6 [207])) "j.c":8:63 313 {*movdi_64bit}
>>      (nil))
>> (insn 13 12 17 2 (set (reg:DI 5 $5 [ y+8 ])
>>         (const_int 0 [0])) "j.c":8:63 313 {*movdi_64bit}
>>      (nil))
>> (insn 17 13 26 2 (parallel [
>>             (set (reg:TI 2 $2 [199])
>>                 (mult:TI (zero_extend:TI (reg:DI 2 $2 [orig:200 x ] [200]))
>>                     (zero_extend:TI (reg:DI 4 $4 [orig:201 y ] [201]))))
>>             (clobber (reg:TI 64 lo [208]))
>>         ]) "j.c":8:63 80 {umulditi3_r4000}
>>      (nil))


You'll note there's a fair amount of obviously dead code.  The dead code
really hampers regcprop's ability to propagate values.  Ultimately what
we want to be able to do is cprop reg4 and reg5 (incoming argument
registers) into insn 17.  The fact that we shuffle through reg4 and have
unused sets of reg4 and reg5 get in the way.

This patch addresses one particular subissue -- namely the sets of
unused registers.  insns 35, 36, 11, 37, 38 & 13.  By identifying &
removing them as regcprop processes the current block (triggering on
REG_UNUSED which will be set up by regcprop) we essentially present the
core of regcprop with:

>> (insn 33 5 6 2 (set (reg:DI 6 $6 [207])
>>         (reg:DI 5 $5 [ y ])) "j.c":8:40 312 {*movdi_64bit}
>>      (nil))
>> 
>> (note 6 33 7 2 NOTE_INSN_DELETED)
>> 
>> (note 7 6 10 2 NOTE_INSN_FUNCTION_BEG)
>> 
>> (insn 10 7 12 2 (set (reg:DI 2 $2 [orig:200 x ] [200])
>>         (reg:DI 4 $4 [206])) "j.c":8:49 312 {*movdi_64bit}
>>      (nil))
>> 
>> (insn 12 10 17 2 (set (reg:DI 4 $4 [orig:201 y ] [201])
>>         (reg:DI 6 $6 [207])) "j.c":8:63 312 {*movdi_64bit}
>>      (nil))
>> 
>> (insn 17 12 26 2 (parallel [
>>             (set (reg:TI 2 $2 [199])
>>                 (mult:TI (zero_extend:TI (reg:DI 2 $2 [orig:200 x ] [200]))
>>                     (zero_extend:TI (reg:DI 4 $4 [orig:201 y ] [201]))))
>>             (clobber (reg:TI 64 lo [208]))
>>         ]) "j.c":8:63 80 {umulditi3_r4000}
>>      (nil))


regcprop will be able to cprop reg5 for the use of reg6 in insn 12 and
again for the use of reg4 in insn 17 resulting in something like this:

>> (insn 33 5 6 2 (set (reg:DI 6 $6 [207])
>>         (reg:DI 5 $5 [ y ])) "j.c":8:40 312 {*movdi_64bit}
>>      (expr_list:REG_DEAD (reg:DI 5 $5 [ y ])
>>         (nil)))
>> (note 6 33 7 2 NOTE_INSN_DELETED)
>> (note 7 6 10 2 NOTE_INSN_FUNCTION_BEG)
>> (insn 10 7 12 2 (set (reg:DI 2 $2 [orig:200 x ] [200])
>>         (reg:DI 4 $4 [206])) "j.c":8:49 312 {*movdi_64bit}
>>      (expr_list:REG_DEAD (reg:DI 4 $4 [206])
>>         (nil)))
>> (insn 12 10 17 2 (set (reg:DI 4 $4 [orig:201 y ] [201])
>>         (reg:DI 5 $5 [207])) "j.c":8:63 312 {*movdi_64bit}
>>      (expr_list:REG_DEAD (reg:DI 6 $6 [207])
>>         (nil)))
>> (insn 17 12 26 2 (parallel [
>>             (set (reg:TI 2 $2 [199])
>>                 (mult:TI (zero_extend:TI (reg:DI 2 $2 [orig:200 x ] [200]))
>>                     (zero_extend:TI (reg:DI 5 $5 [orig:201 y ] [201]))))
>>             (clobber (reg:TI 64 lo [208]))
>>         ]) "j.c":8:63 80 {umulditi3_r4000}
>>      (expr_list:REG_DEAD (reg:DI 4 $4 [orig:201 y ] [201])
>>         (expr_list:REG_UNUSED (reg:TI 64 lo [208])
>>             (nil))))

Which is halfway to our goal (we've cprop'd the incoming reg5 into insn
17).  DCE will later delete insns 33 and insn 12.


This triggers often on x86 and other targets as well.  I suspect most of
the time it's not enabling regcprop to do a better job, but instead just
cleans up stuff that the RTL DCE pass after regcprop would have caught
and eliminated anyway.

I also did some testing to verify that the insns we're removing weren't
things we wanted to keep (by exporting deletable_insn_p from DCE and
checking that).  I didn't include that in this patch, but could be
convinced that (or something similar) is the right thing to do.

Bootstrapped and regression tested on x86_64-linux-gnu, ppc64le, s390x
and aarch64.  Bootstrapped on arm, m68k, mips, riscv, alpha and sh4.
Also lightly tested on various *-elf targets.

Installing on the trunk momentarily.

jeff



diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c4260affdf7..92a90bcfa69 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-26  Jeff Law  <l...@redhat.com>
+
+       PR rtl-optimization/87761
+       * regcprop.c (copyprop_hardreg_forward_1): Use REG_UNUSED notes to
+       detect obviously dead insns and delete them.
+
 2019-02-26  Richard Biener  <rguent...@suse.de>
 
        PR tree-optimization/89505
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index e6bdeb07d8f..926df40f954 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -798,6 +798,22 @@ copyprop_hardreg_forward_1 (basic_block bb, struct 
value_data *vd)
            }
        }
 
+      /* Detect obviously dead sets (via REG_UNUSED notes) and remove them.  */
+      if (set
+         && INSN_P (insn)
+         && !may_trap_p (insn)
+         && find_reg_note (insn, REG_UNUSED, SET_DEST (set))
+         && !side_effects_p (SET_SRC (set))
+         && !side_effects_p (SET_DEST (set)))
+       {
+         bool last = insn == BB_END (bb);
+         delete_insn (insn);
+         if (last)
+           break;
+         continue;
+       }
+        
+
       extract_constrain_insn (insn);
       preprocess_constraints (insn);
       const operand_alternative *op_alt = which_op_alt ();

Reply via email to