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