gimple-ssa-store-merging.c (count_multiple_uses): New function.
authorJakub Jelinek <jakub@redhat.com>
Thu, 9 Nov 2017 13:08:41 +0000 (14:08 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 9 Nov 2017 13:08:41 +0000 (14:08 +0100)
* gimple-ssa-store-merging.c (count_multiple_uses): New function.
(split_group): Add total_orig and total_new arguments, estimate the
number of statements related to the store group without store merging
and with store merging.
(imm_store_chain_info::output_merged_store): Adjust split_group
callers, punt if estimated number of statements with store merging
is not smaller than estimated number of statements without it.
Formatting fix.
(handled_load): Remove has_single_use checks.
(pass_store_merging::process_store): Likewise.

From-SVN: r254579

gcc/ChangeLog
gcc/gimple-ssa-store-merging.c

index f4ba0f525c16502984d12f225b7bb6c5f2c342b1..df371fd5391412ae62c9980c06a9ae532fad161f 100644 (file)
@@ -1,3 +1,16 @@
+2017-11-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * gimple-ssa-store-merging.c (count_multiple_uses): New function.
+       (split_group): Add total_orig and total_new arguments, estimate the
+       number of statements related to the store group without store merging
+       and with store merging.
+       (imm_store_chain_info::output_merged_store): Adjust split_group
+       callers, punt if estimated number of statements with store merging
+       is not smaller than estimated number of statements without it.
+       Formatting fix.
+       (handled_load): Remove has_single_use checks.
+       (pass_store_merging::process_store): Likewise.
+
 2017-11-09  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/82902
index 34c9e7cf421c0c84859ff9f1b50d35bcd7428b5a..4bae70dc7ac6fd3bdd6344b9fa9ffa377be4a376 100644 (file)
@@ -1370,6 +1370,65 @@ find_constituent_stores (struct merged_store_group *group,
   return ret;
 }
 
+/* Return how many SSA_NAMEs used to compute value to store in the INFO
+   store have multiple uses.  If any SSA_NAME has multiple uses, also
+   count statements needed to compute it.  */
+
+static unsigned
+count_multiple_uses (store_immediate_info *info)
+{
+  gimple *stmt = info->stmt;
+  unsigned ret = 0;
+  switch (info->rhs_code)
+    {
+    case INTEGER_CST:
+      return 0;
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      if (!has_single_use (gimple_assign_rhs1 (stmt)))
+       {
+         ret += 1 + info->ops[0].bit_not_p;
+         if (info->ops[1].base_addr)
+           ret += 1 + info->ops[1].bit_not_p;
+         return ret + 1;
+       }
+      stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+      /* stmt is now the BIT_*_EXPR.  */
+      if (!has_single_use (gimple_assign_rhs1 (stmt)))
+       ret += 1 + info->ops[0].bit_not_p;
+      else if (info->ops[0].bit_not_p)
+       {
+         gimple *stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+         if (!has_single_use (gimple_assign_rhs1 (stmt2)))
+           ++ret;
+       }
+      if (info->ops[1].base_addr == NULL_TREE)
+       return ret;
+      if (!has_single_use (gimple_assign_rhs2 (stmt)))
+       ret += 1 + info->ops[1].bit_not_p;
+      else if (info->ops[1].bit_not_p)
+       {
+         gimple *stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
+         if (!has_single_use (gimple_assign_rhs1 (stmt2)))
+           ++ret;
+       }
+      return ret;
+    case MEM_REF:
+      if (!has_single_use (gimple_assign_rhs1 (stmt)))
+       return 1 + info->ops[0].bit_not_p;
+      else if (info->ops[0].bit_not_p)
+       {
+         stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+         if (!has_single_use (gimple_assign_rhs1 (stmt)))
+           return 1;
+       }
+      return 0;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Split a merged store described by GROUP by populating the SPLIT_STORES
    vector (if non-NULL) with split_store structs describing the byte offset
    (from the base), the bit size and alignment of each store as well as the
@@ -1385,7 +1444,9 @@ find_constituent_stores (struct merged_store_group *group,
 static unsigned int
 split_group (merged_store_group *group, bool allow_unaligned_store,
             bool allow_unaligned_load,
-            vec<struct split_store *> *split_stores)
+            vec<struct split_store *> *split_stores,
+            unsigned *total_orig,
+            unsigned *total_new)
 {
   unsigned HOST_WIDE_INT pos = group->bitregion_start;
   unsigned HOST_WIDE_INT size = group->bitregion_end - pos;
@@ -1393,6 +1454,7 @@ split_group (merged_store_group *group, bool allow_unaligned_store,
   unsigned HOST_WIDE_INT group_align = group->align;
   unsigned HOST_WIDE_INT align_base = group->align_base;
   unsigned HOST_WIDE_INT group_load_align = group_align;
+  bool any_orig = false;
 
   gcc_assert ((size % BITS_PER_UNIT == 0) && (pos % BITS_PER_UNIT == 0));
 
@@ -1400,6 +1462,34 @@ split_group (merged_store_group *group, bool allow_unaligned_store,
   unsigned HOST_WIDE_INT try_pos = bytepos;
   group->stores.qsort (sort_by_bitpos);
 
+  if (total_orig)
+    {
+      unsigned int i;
+      store_immediate_info *info = group->stores[0];
+
+      total_new[0] = 0;
+      total_orig[0] = 1; /* The orig store.  */
+      info = group->stores[0];
+      if (info->ops[0].base_addr)
+       total_orig[0] += 1 + info->ops[0].bit_not_p;
+      if (info->ops[1].base_addr)
+       total_orig[0] += 1 + info->ops[1].bit_not_p;
+      switch (info->rhs_code)
+       {
+       case BIT_AND_EXPR:
+       case BIT_IOR_EXPR:
+       case BIT_XOR_EXPR:
+         total_orig[0]++; /* The orig BIT_*_EXPR stmt.  */
+         break;
+       default:
+         break;
+       }
+      total_orig[0] *= group->stores.length ();
+
+      FOR_EACH_VEC_ELT (group->stores, i, info)
+       total_new[0] += count_multiple_uses (info);
+    }
+
   if (!allow_unaligned_load)
     for (int i = 0; i < 2; ++i)
       if (group->load_align[i])
@@ -1524,7 +1614,10 @@ split_group (merged_store_group *group, bool allow_unaligned_store,
          if (info
              && info->bitpos >= try_bitpos
              && info->bitpos + info->bitsize <= try_bitpos + try_size)
-           store->orig = true;
+           {
+             store->orig = true;
+             any_orig = true;
+           }
          split_stores->safe_push (store);
        }
 
@@ -1532,6 +1625,37 @@ split_group (merged_store_group *group, bool allow_unaligned_store,
       size -= try_size;
     }
 
+  if (total_orig)
+    {
+      /* If we are reusing some original stores and any of the
+        original SSA_NAMEs had multiple uses, we need to subtract
+        those now before we add the new ones.  */
+      if (total_new[0] && any_orig)
+       {
+         unsigned int i;
+         struct split_store *store;
+         FOR_EACH_VEC_ELT (*split_stores, i, store)
+           if (store->orig)
+             total_new[0] -= count_multiple_uses (store->orig_stores[0]);
+       }
+      total_new[0] += ret; /* The new store.  */
+      store_immediate_info *info = group->stores[0];
+      if (info->ops[0].base_addr)
+       total_new[0] += ret * (1 + info->ops[0].bit_not_p);
+      if (info->ops[1].base_addr)
+       total_new[0] += ret * (1 + info->ops[1].bit_not_p);
+      switch (info->rhs_code)
+       {
+       case BIT_AND_EXPR:
+       case BIT_IOR_EXPR:
+       case BIT_XOR_EXPR:
+         total_new[0] += ret; /* The new BIT_*_EXPR stmt.  */
+         break;
+       default:
+         break;
+       }
+    }
+
   return ret;
 }
 
@@ -1564,26 +1688,35 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
         for unaligned and how many stores we'd emit for aligned stores.
         Only use unaligned stores if it allows fewer stores than aligned.  */
       unsigned aligned_cnt
-       = split_group (group, false, allow_unaligned_load, NULL);
+       = split_group (group, false, allow_unaligned_load, NULL, NULL, NULL);
       unsigned unaligned_cnt
-       = split_group (group, true, allow_unaligned_load, NULL);
+       = split_group (group, true, allow_unaligned_load, NULL, NULL, NULL);
       if (aligned_cnt <= unaligned_cnt)
        allow_unaligned_store = false;
     }
+  unsigned total_orig, total_new;
   split_group (group, allow_unaligned_store, allow_unaligned_load,
-              &split_stores);
+              &split_stores, &total_orig, &total_new);
 
   if (split_stores.length () >= orig_num_stmts)
     {
       /* We didn't manage to reduce the number of statements.  Bail out.  */
       if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Exceeded original number of stmts (%u)."
-                             "  Not profitable to emit new sequence.\n",
-                  orig_num_stmts);
-       }
+       fprintf (dump_file, "Exceeded original number of stmts (%u)."
+                           "  Not profitable to emit new sequence.\n",
+                orig_num_stmts);
       return false;
     }
+  if (total_orig <= total_new)
+    {
+      /* If number of estimated new statements is above estimated original
+        statements, bail out too.  */
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "Estimated number of original stmts (%u)"
+                           " not larger than estimated number of new"
+                           " stmts (%u).\n",
+                total_orig, total_new);
+    }
 
   gimple_stmt_iterator last_gsi = gsi_for_stmt (group->last_stmt);
   gimple_seq seq = NULL;
@@ -2096,7 +2229,6 @@ handled_load (gimple *stmt, store_operand_info *op,
     {
       tree rhs1 = gimple_assign_rhs1 (stmt);
       if (TREE_CODE (rhs1) == SSA_NAME
-         && has_single_use (rhs1)
          && handled_load (SSA_NAME_DEF_STMT (rhs1), op, bitsize, bitpos,
                           bitregion_start, bitregion_end))
        {
@@ -2159,7 +2291,7 @@ pass_store_merging::process_store (gimple *stmt)
       rhs_code = INTEGER_CST;
       ops[0].val = rhs;
     }
-  else if (TREE_CODE (rhs) != SSA_NAME || !has_single_use (rhs))
+  else if (TREE_CODE (rhs) != SSA_NAME)
     invalid = true;
   else
     {
@@ -2179,7 +2311,7 @@ pass_store_merging::process_store (gimple *stmt)
            rhs1 = gimple_assign_rhs1 (def_stmt);
            rhs2 = gimple_assign_rhs2 (def_stmt);
            invalid = true;
-           if (TREE_CODE (rhs1) != SSA_NAME || !has_single_use (rhs1))
+           if (TREE_CODE (rhs1) != SSA_NAME)
              break;
            def_stmt1 = SSA_NAME_DEF_STMT (rhs1);
            if (!is_gimple_assign (def_stmt1)
@@ -2188,7 +2320,7 @@ pass_store_merging::process_store (gimple *stmt)
              break;
            if (rhs_valid_for_store_merging_p (rhs2))
              ops[1].val = rhs2;
-           else if (TREE_CODE (rhs2) != SSA_NAME || !has_single_use (rhs2))
+           else if (TREE_CODE (rhs2) != SSA_NAME)
              break;
            else
              {