GCC currently doesn't canonicalize address expressions. As a result
inefficient code is generated even for trivial index address expressions,
blocking CSE and other optimizations:

int f(int *p, int i) { return p[i+2] + p[i+1]; }

        sxtw    x1, w1
        add     x1, x1, 2
        add     x2, x0, x1, lsl 2
        ldr     w0, [x0, x1, lsl 2]
        ldr     w1, [x2, -4]
        add     w0, w1, w0
        ret

After this patch:

        add     x1, x0, x1, sxtw 2
        ldp     w0, w2, [x1, 4]
        add     w0, w2, w0
        ret

The reason for this is that array index expressions are preferably kept in 
the *(p + (i + C0) * C1) form eventhough it is best on most targets to make
use of an offset in memory accesses - ie. *(p + i * C1 + (C0*C1)).

This patch disables the folding in fold_plusminus_mult_expr that changes
the latter form into the former.  Unfortunately it isn't possible to know
it is an address expression, and neither is there a way to decide when
C0*C1 is too complex. 

So is there a better way/place to do this, or do we need an address
canonicalization phase in the tree that ensures we expand addresses in an
efficient manner, taking into account target offsets?


ChangeLog:
2016-10-04  Wilco Dijkstra  <wdijk...@arm.com>

    gcc/
        * fold-const.c (fold_plusminus_mult_expr): Block folding of immediates
        into multiply.
--

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 
e71ce5e0f23adbb1d4a73506769f7243900cfd2d..bc9fb1e8ff3e33c94e66a2d1282235b71fac2730
 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -6912,7 +6912,9 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code 
code, tree type,
      (A * C) +- A -> A * (C+-1).
      We are most concerned about the case where C is a constant,
      but other combinations show up during loop reduction.  Since
-     it is not difficult, try all four possibilities.  */
+     it is not difficult, try all four possibilities.
+     However avoid moving integer constants into the multiply:
+     (A * C0) +- C1 is better than (A +- (C1/C0)) * C0.  */
 
   if (TREE_CODE (arg0) == MULT_EXPR)
     {
@@ -6920,10 +6922,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code 
code, tree type,
       arg01 = TREE_OPERAND (arg0, 1);
     }
   else if (TREE_CODE (arg0) == INTEGER_CST)
-    {
-      arg00 = build_one_cst (type);
-      arg01 = arg0;
-    }
+    return NULL_TREE;
   else
     {
       /* We cannot generate constant 1 for fract.  */
@@ -6938,20 +6937,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code 
code, tree type,
       arg11 = TREE_OPERAND (arg1, 1);
     }
   else if (TREE_CODE (arg1) == INTEGER_CST)
-    {
-      arg10 = build_one_cst (type);
-      /* As we canonicalize A - 2 to A + -2 get rid of that sign for
-        the purpose of this canonicalization.  */
-      if (wi::neg_p (arg1, TYPE_SIGN (TREE_TYPE (arg1)))
-         && negate_expr_p (arg1)
-         && code == PLUS_EXPR)
-       {
-         arg11 = negate_expr (arg1);
-         code = MINUS_EXPR;
-       }
-      else
-       arg11 = arg1;
-    }
+    return NULL_TREE;
   else
     {
       /* We cannot generate constant 1 for fract.  */

Reply via email to