tree-ssa-address.c: Include header file.
authorBin Cheng <bin.cheng@arm.com>
Thu, 11 May 2017 09:51:41 +0000 (09:51 +0000)
committerBin Cheng <amker@gcc.gnu.org>
Thu, 11 May 2017 09:51:41 +0000 (09:51 +0000)
* tree-ssa-address.c: Include header file.
(move_hint_to_base): Return TRUE if BASE_HINT is moved to memory
address.
(add_to_parts): Refactor.
(addr_to_parts): New parameter.  Update use of move_hint_to_base.
(create_mem_ref): Update use of addr_to_parts.  Re-associate addr
in new order.

From-SVN: r247894

gcc/ChangeLog
gcc/tree-ssa-address.c

index 55cc30f12aa14fc61b28479c9056a2e3f3f266d7..96c7b3f5238707907feb5955f17124d3812cded8 100644 (file)
@@ -1,3 +1,13 @@
+2017-05-11  Bin Cheng  <bin.cheng@arm.com>
+
+       * tree-ssa-address.c: Include header file.
+       (move_hint_to_base): Return TRUE if BASE_HINT is moved to memory
+       address.
+       (add_to_parts): Refactor.
+       (addr_to_parts): New parameter.  Update use of move_hint_to_base.
+       (create_mem_ref): Update use of addr_to_parts.  Re-associate addr
+       in new order.
+
 2017-05-11  Bin Cheng  <bin.cheng@arm.com>
 
        PR tree-optimization/53090
index 8aefed695d524d1e6511491672646cb4b714d187..8257fde524049f0c39b48f5477d594b037729b0a 100644 (file)
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "dumpfile.h"
 #include "tree-affine.h"
+#include "gimplify.h"
 
 /* FIXME: We compute address costs using RTL.  */
 #include "tree-ssa-address.h"
@@ -427,9 +428,10 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
   aff_combination_remove_elt (addr, i);
 }
 
-/* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
+/* Return true if ADDR contains an instance of BASE_HINT and it's moved to
+   PARTS->base.  */
 
-static void
+static bool
 move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
                   aff_tree *addr)
 {
@@ -448,7 +450,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
     }
 
   if (i == addr->n)
-    return;
+    return false;
 
   /* Cast value to appropriate pointer type.  We cannot use a pointer
      to TYPE directly, as the back-end will assume registers of pointer
@@ -458,6 +460,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
   type = build_qualified_type (void_type_node, qual);
   parts->base = fold_convert (build_pointer_type (type), val);
   aff_combination_remove_elt (addr, i);
+  return true;
 }
 
 /* If ADDR contains an address of a dereferenced pointer, move it to
@@ -535,8 +538,7 @@ add_to_parts (struct mem_address *parts, tree elt)
   if (POINTER_TYPE_P (type))
     parts->base = fold_build_pointer_plus (parts->base, elt);
   else
-    parts->base = fold_build2 (PLUS_EXPR, type,
-                              parts->base, elt);
+    parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
 }
 
 /* Returns true if multiplying by RATIO is allowed in an address.  Test the
@@ -668,7 +670,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts,
 /* Splits address ADDR for a memory access of type TYPE into PARTS.
    If BASE_HINT is non-NULL, it specifies an SSA name to be used
    preferentially as base of the reference, and IV_CAND is the selected
-   iv candidate used in ADDR.
+   iv candidate used in ADDR.  Store true to VAR_IN_BASE if variant
+   part of address is split to PARTS.base.
 
    TODO -- be more clever about the distribution of the elements of ADDR
    to PARTS.  Some architectures do not support anything but single
@@ -678,9 +681,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts,
    addressing modes is useless.  */
 
 static void
-addr_to_parts (tree type, aff_tree *addr, tree iv_cand,
-              tree base_hint, struct mem_address *parts,
-               bool speed)
+addr_to_parts (tree type, aff_tree *addr, tree iv_cand, tree base_hint,
+              struct mem_address *parts, bool *var_in_base, bool speed)
 {
   tree part;
   unsigned i;
@@ -698,23 +700,20 @@ addr_to_parts (tree type, aff_tree *addr, tree iv_cand,
   /* Try to find a symbol.  */
   move_fixed_address_to_symbol (parts, addr);
 
-  /* No need to do address parts reassociation if the number of parts
-     is <= 2 -- in that case, no loop invariant code motion can be
-     exposed.  */
-
-  if (!base_hint && (addr->n > 2))
+  /* Since at the moment there is no reliable way to know how to
+     distinguish between pointer and its offset, we decide if var
+     part is the pointer based on guess.  */
+  *var_in_base = (base_hint != NULL && parts->symbol == NULL);
+  if (*var_in_base)
+    *var_in_base = move_hint_to_base (type, parts, base_hint, addr);
+  else
     move_variant_to_index (parts, addr, iv_cand);
 
-  /* First move the most expensive feasible multiplication
-     to index.  */
+  /* First move the most expensive feasible multiplication to index.  */
   if (!parts->index)
     most_expensive_mult_to_index (type, parts, addr, speed);
 
-  /* Try to find a base of the reference.  Since at the moment
-     there is no reliable way how to distinguish between pointer and its
-     offset, this is just a guess.  */
-  if (!parts->symbol && base_hint)
-    move_hint_to_base (type, parts, base_hint, addr);
+  /* Move pointer into base.  */
   if (!parts->symbol && !parts->base)
     move_pointer_to_base (parts, addr);
 
@@ -756,10 +755,11 @@ tree
 create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
                tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
 {
+  bool var_in_base;
   tree mem_ref, tmp;
   struct mem_address parts;
 
-  addr_to_parts (type, addr, iv_cand, base_hint, &parts, speed);
+  addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
   gimplify_mem_ref_parts (gsi, &parts);
   mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
   if (mem_ref)
@@ -767,9 +767,49 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
 
   /* The expression is too complicated.  Try making it simpler.  */
 
+  /* Merge symbol into other parts.  */
+  if (parts.symbol)
+    {
+      tmp = parts.symbol;
+      parts.symbol = NULL_TREE;
+      gcc_assert (is_gimple_val (tmp));
+
+      if (parts.base)
+       {
+         gcc_assert (useless_type_conversion_p (sizetype,
+                                                TREE_TYPE (parts.base)));
+
+         if (parts.index)
+           {
+             /* Add the symbol to base, eventually forcing it to register.  */
+             tmp = fold_build_pointer_plus (tmp, parts.base);
+             tmp = force_gimple_operand_gsi_1 (gsi, tmp,
+                                               is_gimple_mem_ref_addr,
+                                               NULL_TREE, true,
+                                               GSI_SAME_STMT);
+           }
+         else
+           {
+             /* Move base to index, then move the symbol to base.  */
+             parts.index = parts.base;
+           }
+         parts.base = tmp;
+       }
+      else
+       parts.base = tmp;
+
+      mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
+      if (mem_ref)
+       return mem_ref;
+    }
+
+  /* Move multiplication to index by transforming address expression:
+       [... + index << step + ...]
+     into:
+       index' = index << step;
+       [... + index' + ,,,].  */
   if (parts.step && !integer_onep (parts.step))
     {
-      /* Move the multiplication to index.  */
       gcc_assert (parts.index);
       parts.index = force_gimple_operand_gsi (gsi,
                                fold_build2 (MULT_EXPR, sizetype,
@@ -782,69 +822,100 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
        return mem_ref;
     }
 
-  if (parts.symbol)
+  /* Add offset to invariant part by transforming address expression:
+       [base + index + offset]
+     into:
+       base' = base + offset;
+       [base' + index]
+     or:
+       index' = index + offset;
+       [base + index']
+     depending on which one is invariant.  */
+  if (parts.offset && !integer_zerop (parts.offset))
     {
-      tmp = parts.symbol;
-      gcc_assert (is_gimple_val (tmp));
+      tree old_base = unshare_expr (parts.base);
+      tree old_index = unshare_expr (parts.index);
+      tree old_offset = unshare_expr (parts.offset);
 
-      /* Add the symbol to base, eventually forcing it to register.  */
-      if (parts.base)
+      tmp = parts.offset;
+      parts.offset = NULL_TREE;
+      /* Add offset to invariant part.  */
+      if (!var_in_base)
        {
-         gcc_assert (useless_type_conversion_p
-                               (sizetype, TREE_TYPE (parts.base)));
-
-         if (parts.index)
+         if (parts.base)
            {
-             parts.base = force_gimple_operand_gsi_1 (gsi,
-                       fold_build_pointer_plus (tmp, parts.base),
-                       is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
+             tmp = fold_build_pointer_plus (parts.base, tmp);
+             tmp = force_gimple_operand_gsi_1 (gsi, tmp,
+                                               is_gimple_mem_ref_addr,
+                                               NULL_TREE, true,
+                                               GSI_SAME_STMT);
            }
-         else
+         parts.base = tmp;
+       }
+      else
+       {
+         if (parts.index)
            {
-             parts.index = parts.base;
-             parts.base = tmp;
+             tmp = fold_build_pointer_plus (parts.index, tmp);
+             tmp = force_gimple_operand_gsi_1 (gsi, tmp,
+                                               is_gimple_mem_ref_addr,
+                                               NULL_TREE, true,
+                                               GSI_SAME_STMT);
            }
+         parts.index = tmp;
        }
-      else
-       parts.base = tmp;
-      parts.symbol = NULL_TREE;
 
       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
       if (mem_ref)
        return mem_ref;
+
+      /* Restore parts.base, index and offset so that we can check if
+        [base + offset] addressing mode is supported in next step.
+        This is necessary for targets only support [base + offset],
+        but not [base + index] addressing mode.  */
+      parts.base = old_base;
+      parts.index = old_index;
+      parts.offset = old_offset;
     }
 
+  /* Transform [base + index + ...] into:
+       base' = base + index;
+       [base' + ...].  */
   if (parts.index)
     {
+      tmp = parts.index;
+      parts.index = NULL_TREE;
       /* Add index to base.  */
       if (parts.base)
        {
-         parts.base = force_gimple_operand_gsi_1 (gsi,
-                       fold_build_pointer_plus (parts.base, parts.index),
-                       is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
+         tmp = fold_build_pointer_plus (parts.base, tmp);
+         tmp = force_gimple_operand_gsi_1 (gsi, tmp,
+                                           is_gimple_mem_ref_addr,
+                                           NULL_TREE, true, GSI_SAME_STMT);
        }
-      else
-       parts.base = parts.index;
-      parts.index = NULL_TREE;
+      parts.base = tmp;
 
       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
       if (mem_ref)
        return mem_ref;
     }
 
+  /* Transform [base + offset] into:
+       base' = base + offset;
+       [base'].  */
   if (parts.offset && !integer_zerop (parts.offset))
     {
-      /* Try adding offset to base.  */
+      tmp = parts.offset;
+      parts.offset = NULL_TREE;
+      /* Add offset to base.  */
       if (parts.base)
        {
-         parts.base = force_gimple_operand_gsi_1 (gsi,
-                       fold_build_pointer_plus (parts.base, parts.offset),
-                       is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
+         tmp = fold_build_pointer_plus (parts.base, tmp);
+         tmp = force_gimple_operand_gsi_1 (gsi, tmp,
+                                           is_gimple_mem_ref_addr,
+                                           NULL_TREE, true, GSI_SAME_STMT);
        }
-      else
-       parts.base = parts.offset;
-
-      parts.offset = NULL_TREE;
+      parts.base = tmp;
 
       mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
       if (mem_ref)