Patchwork [PR42575,approved] Shorten pseudos live ranges when expanding doubleword mult

login
register
mail settings
Submitter Maxim Kuvyrkov
Date Aug. 18, 2010, 10:28 a.m.
Message ID <4C6BB5E0.5040006@codesourcery.com>
Download mbox | patch
Permalink /patch/62025/
State New
Headers show

Comments

Maxim Kuvyrkov - Aug. 18, 2010, 10:28 a.m.
This patch gets rid of the extraneous move when generating doubleword 
multiplication.  The patch was approved off-list by Bernd.

One of the problems in PR42575 when compiled for ARMv7-A is an extra 
move that, ideally, should not be there (-O2 -march=armv7-a):

longfunc:
     @ args = 0, pretend = 0, frame = 0
     @ frame_needed = 0, uses_anonymous_args = 0
     @ link register save eliminated.
     mul    r3, r0, r3
     mla    r3, r2, r1, r3
     umull    r0, r1, r0, r2
     add    r3, r3, r1
     mov    r1, r3 // Extra move
     bx    lr

The problem is in expand.  Expand unnecessarily lengthens live range of 
the pseudo that gets allocated to r3.  IRA cannot allocate that pseudo 
to r1 as part of its live range crosses with previous value of r1.

The problem is fixed by making expand not reuse the pseudo (adjust 
variable in the patch).  With the patch GCC generates :
longfunc:
     @ args = 0, pretend = 0, frame = 0
     @ frame_needed = 0, uses_anonymous_args = 0
     @ link register save eliminated.
     mul    r3, r0, r3
     mla    r3, r2, r1, r3
     umull    r0, r1, r0, r2
     add    r1, r3, r1
     bx    lr
     .size    longfunc, .-longfunc

Bootstrapped and regtested on i686-pc-linux-gnu{-m32/-m64}.  Bernd also 
verified that the patch doesn't cause any negative change in the 
generated code on this collection of examples.

Will check in shortly.

Thanks,

Patch

diff --git a/gcc/optabs.c b/gcc/optabs.c
index b9db02f..1fcbedc 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -1257,7 +1257,7 @@  expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   /* OP1_HIGH should now be dead.  */
 
   adjust = expand_binop (word_mode, add_optab, adjust, temp,
-			 adjust, 0, OPTAB_DIRECT);
+			 NULL_RTX, 0, OPTAB_DIRECT);
 
   if (target && !REG_P (target))
     target = NULL_RTX;
@@ -1274,8 +1274,7 @@  expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 
   product_high = operand_subword (product, high, 1, mode);
   adjust = expand_binop (word_mode, add_optab, product_high, adjust,
-			 REG_P (product_high) ? product_high : adjust,
-			 0, OPTAB_DIRECT);
+			 NULL_RTX, 0, OPTAB_DIRECT);
   emit_move_insn (product_high, adjust);
   return product;
 }
diff --git a/gcc/testsuite/gcc.target/arm/pr42575.c b/gcc/testsuite/gcc.target/arm/pr42575.c
new file mode 100644
index 0000000..474bf6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr42575.c
@@ -0,0 +1,9 @@ 
+/* { dg-options "-O2 -march=armv7-a" }  */
+/* Make sure RA does good job allocating registers and avoids
+   unnecessary moves.  */
+/* { dg-final { scan-assembler-not "mov" } } */
+
+long long longfunc(long long x, long long y)
+{
+      return x * y;
+}