A general TARGET_MEM_REF is:

    BASE + STEP * INDEX + INDEX2 + OFFSET

After classifying the address in this way, the code that builds
TARGET_MEM_REFs tries to simplify the address until it's valid
for the current target and for the mode of memory being addressed.
It does this in a fixed order:

(1) add SYMBOL to BASE
(2) add INDEX * STEP to the base, if STEP != 1
(3) add OFFSET to INDEX or BASE (reverted if unsuccessful)
(4) add INDEX to BASE
(5) add OFFSET to BASE

So suppose we had an address:

    &symbol + offset + index * 8   (e.g. "a[i + 1]" for a global "a")

on a target that only allows an index or an offset, not both.  Following
the steps above, we'd first create:

    tmp = symbol
    tmp2 = tmp + index * 8

Then if the given offset value was valid for the mode being addressed,
we'd create:

    MEM[base:tmp2, offset:offset]

while if it was invalid we'd create:

    tmp3 = tmp2 + offset
    MEM[base:tmp3, offset:0]

The problem is that this could happen if ivopts had decided to use
a scaled index for an address that happens to have a constant base.
The old procedure failed to give an indexed TARGET_MEM_REF in that case,
and adding the offset last prevented later passes from being able to
fold the index back in.

The patch avoids this by skipping (2) if BASE + INDEX * STEP
is a legitimate address and if OFFSET is stopping the address
being valid.

Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64-linux-gnu.
OK to install?

Richard


2017-10-31  Richard Sandiford  <richard.sandif...@linaro.org>
            Alan Hayward  <alan.hayw...@arm.com>
            David Sherwood  <david.sherw...@arm.com>

gcc/
        * tree-ssa-address.c (keep_index_p): New function.
        (create_mem_ref): Use it.  Only split out the INDEX * STEP
        component if that is invalid even with the symbol and offset
        removed.

Index: gcc/tree-ssa-address.c
===================================================================
--- gcc/tree-ssa-address.c      2017-11-03 12:15:44.097060121 +0000
+++ gcc/tree-ssa-address.c      2017-11-03 12:21:18.060359821 +0000
@@ -746,6 +746,20 @@ gimplify_mem_ref_parts (gimple_stmt_iter
                                             true, GSI_SAME_STMT);
 }
 
+/* Return true if the STEP in PARTS gives a valid BASE + INDEX * STEP
+   address for type TYPE and if the offset is making it appear invalid.  */
+
+static bool
+keep_index_p (tree type, mem_address parts)
+{
+  if (!parts.base)
+    return false;
+
+  gcc_assert (!parts.symbol);
+  parts.offset = NULL_TREE;
+  return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
+}
+
 /* Creates and returns a TARGET_MEM_REF for address ADDR.  If necessary
    computations are emitted in front of GSI.  TYPE is the mode
    of created memory reference. IV_CAND is the selected iv candidate in ADDR,
@@ -809,7 +823,8 @@ create_mem_ref (gimple_stmt_iterator *gs
      into:
        index' = index << step;
        [... + index' + ,,,].  */
-  if (parts.step && !integer_onep (parts.step))
+  bool scaled_p = (parts.step && !integer_onep (parts.step));
+  if (scaled_p && !keep_index_p (type, parts))
     {
       gcc_assert (parts.index);
       parts.index = force_gimple_operand_gsi (gsi,
@@ -821,6 +836,7 @@ create_mem_ref (gimple_stmt_iterator *gs
       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
       if (mem_ref)
        return mem_ref;
+      scaled_p = false;
     }
 
   /* Add offset to invariant part by transforming address expression:
@@ -832,7 +848,9 @@ create_mem_ref (gimple_stmt_iterator *gs
        index' = index + offset;
        [base + index']
      depending on which one is invariant.  */
-  if (parts.offset && !integer_zerop (parts.offset))
+  if (parts.offset
+      && !integer_zerop (parts.offset)
+      && (!var_in_base || !scaled_p))
     {
       tree old_base = unshare_expr (parts.base);
       tree old_index = unshare_expr (parts.index);
@@ -882,7 +900,7 @@ create_mem_ref (gimple_stmt_iterator *gs
   /* Transform [base + index + ...] into:
        base' = base + index;
        [base' + ...].  */
-  if (parts.index)
+  if (parts.index && !scaled_p)
     {
       tmp = parts.index;
       parts.index = NULL_TREE;

Reply via email to