[RFA] Minor improvement to compare elimination

Message ID b8fe6b25-2506-34f0-6989-24373da6b3be@gmail.com
State New
Headers show
Series
  • [RFA] Minor improvement to compare elimination
Related show

Commit Message

H.J. Lu via Gcc-patches June 14, 2021, 12:30 a.m.
I was reviewing the generated code in libgcc for the H8 to see if there 
were any obvious redundant test/compares.  Sure enough I found one in 
the first file I looked at ;-)

So after IRA we have something like this:

(insn 43 112 44 4 (set (subreg:SI (reg:DI 40) 0)
         (and:SI (subreg:SI (reg:DI 38) 0)
             (subreg:SI (reg:DI 39) 0))) 
"/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 246 {*logicalsi3}
      (nil))
(insn 44 43 47 4 (set (subreg:SI (reg:DI 40) 4)
         (and:SI (subreg:SI (reg:DI 38) 4)
             (subreg:SI (reg:DI 39) 4))) 
"/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 246 {*logicalsi3}
      (expr_list:REG_DEAD (reg:DI 39)
         (expr_list:REG_DEAD (reg:DI 38)
             (nil))))
(jump_insn 47 44 83 4 (set (pc)
         (if_then_else (ge (subreg:SI (reg:DI 40) 0)
                 (const_int 0 [0]))
             (label_ref 55)
             (pc))) "/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 281 
{*branch}
      (expr_list:REG_DEAD (reg:DI 40)
         (int_list:REG_BR_PROB 1073204964 (nil)))

Which is just a DImode AND and a conditional branch based on the state 
of the most significant bit.  On the H8 we don't expose the condition 
codes until split2.  After splitting we have:

(insn 228 227 229 4 (parallel [
             (set (reg:SI 0 r0)
                 (and:SI (reg:SI 0 r0)
                     (reg:SI 2 r2)))
             (clobber (reg:CC 12 cc))
         ]) "/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 263 {*andsi3}
      (nil))
(insn 229 228 230 4 (parallel [
             (set (reg:SI 1 r1)
                 (mem/c:SI (plus:SI (reg/f:SI 7 sp)
                         (const_int 12 [0xc])) [1 %sfp+-12 S4 A32]))
             (clobber (reg:CC 12 cc))
         ]) "/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 20 
{*movsi_clobber_flags}
      (nil))
(insn 230 229 231 4 (parallel [
             (set (reg:SI 1 r1)
                 (and:SI (reg:SI 1 r1)
                     (reg:SI 3 r3 [orig:39+4 ] [39])))
             (clobber (reg:CC 12 cc))
         ]) "/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 263 {*andsi3}
      (nil))
(insn 231 230 232 4 (set (reg:CC 12 cc)
         (compare:CC (reg:SI 0 r0)
             (const_int 0 [0]))) 
"/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 131 {cmpsi}
      (nil))
(jump_insn 232 231 83 4 (set (pc)
         (if_then_else (ge (reg:CC 12 cc)
                 (const_int 0 [0]))
             (label_ref 55)
             (pc))) "/home/jlaw/test/gcc/libgcc/libgcc2.c":247:7 283 
{*branch_1}

So far so good.  An astute observer would probably note at this time 
that insn 228 is a good candidate to eliminate the compare at insn 231, 
except that insns 229 and 230 clobber the condition codes.

Things stay effectively like this through compare elimination which 
fails to trigger because the condition codes are clobbered between insn 
228 and insn 231.

*But* it turns out that insn 229 and insn 230 are both dead. They'll be 
detected as such during peephole2, but that's too late to help compare 
elimination (and in case you're wondering the DImode use in insn 47 
keeps insn 44 from being deleted as dead before reload).

Naturally once peep2 has deleted the dead code it becomes obvious 
there's a redundant test/compare.

The fix here is trivial -- just ask the DF machinery to do a fast DCE 
from compare-elimination.  That kills the two problematical insns and 
then allows compare-elimination to detect that the compare is not 
necessary.  This shows up numerous times throughout libgcc and newlib.  
Each time we're able to eliminate a compare like this we save 6 bytes of 
instruction space and 3 cycles.

*** orig.s      2021-06-13 20:21:55.014435803 -0400
--- new.s       2021-06-13 20:21:34.329494744 -0400
*************** ___absvdi2:
*** 43,50 ****
         not.l   er2
         mov.l   @(8,er7),er0
         and.l   er2,er0
!       cmp.l   #0,er0
!       bge     .L2
         sub.l   er0,er0
         mov.l   er0,@(16,er7)
         sub.l   er1,er1
--- 43,49 ----
         not.l   er2
         mov.l   @(8,er7),er0
         and.l   er2,er0
!       bpl     .L2
         sub.l   er0,er0
         mov.l   er0,@(16,er7)
         sub.l   er1,er1


I've bootstrapped and regression tested this on x86_64, though I doubt 
it makes any difference there.  BUt I'd bet it would help other targets 
that don't expose double-word operations and have a condition code that 
is clobbered by most instructions.


OK for the trunk?

Jeff
Minor improvement to compare elimination

gcc/
	* compare-elim.c (try_eliminate_compare): Run DCE to clean things
	before eliminating comparisons.

Comments

Eric Botcazou June 15, 2021, 11:46 a.m. | #1
> I've bootstrapped and regression tested this on x86_64, though I doubt

> it makes any difference there.  BUt I'd bet it would help other targets

> that don't expose double-word operations and have a condition code that

> is clobbered by most instructions.

> 

> OK for the trunk?


Sure, thanks.

-- 
Eric Botcazou

Patch

diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
index 85085cd6973..607eadc3d96 100644
--- a/gcc/compare-elim.c
+++ b/gcc/compare-elim.c
@@ -906,6 +906,7 @@  try_eliminate_compare (struct comparison *cmp)
 static unsigned int
 execute_compare_elim_after_reload (void)
 {
+  df_set_flags (DF_LR_RUN_DCE);
   df_analyze ();
 
   gcc_checking_assert (!all_compares.exists ());