OSDN Git Service

* unwind-generic.h: Fix comment typos.
[pf3gnuchains/gcc-fork.git] / gcc / value-prof.c
index f23fd68..124a3c8 100644 (file)
@@ -1,11 +1,11 @@
 /* Transformations based on profile information for values.
-   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -14,9 +14,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -63,7 +62,7 @@ static struct value_prof_hooks *value_prof_hooks;
 
    3) Indirect/virtual call specialization. If we can determine most
       common function callee in indirect/virtual call. We can use this
-      information to improve code effectivity (espetialy info for
+      information to improve code effectiveness (especially info for
       inliner).
 
    Every such optimization should add its requirements for profiled values to
@@ -107,7 +106,7 @@ gimple_alloc_histogram_value (struct function *fun ATTRIBUTE_UNUSED,
 static hashval_t
 histogram_hash (const void *x)
 {
-  return htab_hash_pointer (((histogram_value)x)->hvalue.stmt);
+  return htab_hash_pointer (((const_histogram_value)x)->hvalue.stmt);
 }
 
 /* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y.  */
@@ -115,7 +114,7 @@ histogram_hash (const void *x)
 static int
 histogram_eq (const void *x, const void *y)
 {
-  return ((histogram_value) x)->hvalue.stmt == (tree)y;
+  return ((const_histogram_value) x)->hvalue.stmt == (const_tree)y;
 }
 
 /* Set histogram for STMT.  */
@@ -248,6 +247,28 @@ dump_histogram_value (FILE *dump_file, histogram_value hist)
       fprintf (dump_file, ".\n");
       break;
 
+    case HIST_TYPE_AVERAGE:
+      fprintf (dump_file, "Average value ");
+      if (hist->hvalue.counters)
+       {
+          fprintf (dump_file, "sum:"HOST_WIDEST_INT_PRINT_DEC
+                   " times:"HOST_WIDEST_INT_PRINT_DEC,
+                   (HOST_WIDEST_INT) hist->hvalue.counters[0],
+                   (HOST_WIDEST_INT) hist->hvalue.counters[1]);
+       }
+      fprintf (dump_file, ".\n");
+      break;
+
+    case HIST_TYPE_IOR:
+      fprintf (dump_file, "IOR value ");
+      if (hist->hvalue.counters)
+       {
+          fprintf (dump_file, "ior:"HOST_WIDEST_INT_PRINT_DEC,
+                   (HOST_WIDEST_INT) hist->hvalue.counters[0]);
+       }
+      fprintf (dump_file, ".\n");
+      break;
+
     case HIST_TYPE_CONST_DELTA:
       fprintf (dump_file, "Constant delta ");
       if (hist->hvalue.counters)
@@ -332,7 +353,7 @@ visit_hist (void **slot, void *data)
       debug_generic_stmt (hist->hvalue.stmt);
       error_found = true;
     }
-  return 0;
+  return 1;
 }
 
 /* Verify sanity of the histograms.  */
@@ -384,7 +405,7 @@ free_hist (void **slot, void *data ATTRIBUTE_UNUSED)
   memset (hist, 0xab, sizeof (*hist));
 #endif
   free (hist);
-  return 0;
+  return 1;
 }
 
 void
@@ -501,13 +522,11 @@ tree_divmod_fixed_value (tree stmt, tree operation,
 
   tmpv = create_tmp_var (optype, "PROF");
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, tmpv,
-                 fold_convert (optype, value));
-  stmt2 = build2 (GIMPLE_MODIFY_STMT, optype, tmp1, op2);
+  stmt1 = build_gimple_modify_stmt (tmpv, fold_convert (optype, value));
+  stmt2 = build_gimple_modify_stmt (tmp1, op2);
   stmt3 = build3 (COND_EXPR, void_type_node,
            build2 (NE_EXPR, boolean_type_node, tmp1, tmpv),
-           build1 (GOTO_EXPR, void_type_node, label_decl2),
-           build1 (GOTO_EXPR, void_type_node, label_decl1));
+           NULL_TREE, NULL_TREE);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
@@ -515,15 +534,17 @@ tree_divmod_fixed_value (tree stmt, tree operation,
 
   tmp2 = create_tmp_var (optype, "PROF");
   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, tmp2,
-                 build2 (TREE_CODE (operation), optype, op1, tmpv));
+  stmt1 = build_gimple_modify_stmt (tmp2,
+                                   build2 (TREE_CODE (operation), optype,
+                                           op1, tmpv));
   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb2end = stmt1;
 
   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, tmp2,
-                 build2 (TREE_CODE (operation), optype, op1, op2));
+  stmt1 = build_gimple_modify_stmt (tmp2,
+                                   build2 (TREE_CODE (operation), optype,
+                                           op1, op2));
   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb3end = stmt1;
@@ -658,15 +679,15 @@ tree_mod_pow2 (tree stmt, tree operation, tree op1, tree op2, int prob,
 
   tmp2 = create_tmp_var (optype, "PROF");
   tmp3 = create_tmp_var (optype, "PROF");
-  stmt2 = build2 (GIMPLE_MODIFY_STMT, optype, tmp2, 
-                 build2 (PLUS_EXPR, optype, op2, build_int_cst (optype, -1)));
-  stmt3 = build2 (GIMPLE_MODIFY_STMT, optype, tmp3,
-                 build2 (BIT_AND_EXPR, optype, tmp2, op2));
+  stmt2 = build_gimple_modify_stmt (tmp2, 
+                                   build2 (PLUS_EXPR, optype, op2,
+                                           build_int_cst (optype, -1)));
+  stmt3 = build_gimple_modify_stmt (tmp3,
+                                   build2 (BIT_AND_EXPR, optype, tmp2, op2));
   stmt4 = build3 (COND_EXPR, void_type_node,
                  build2 (NE_EXPR, boolean_type_node,
                          tmp3, build_int_cst (optype, 0)),
-                 build1 (GOTO_EXPR, void_type_node, label_decl2),
-                 build1 (GOTO_EXPR, void_type_node, label_decl1));
+                 NULL_TREE, NULL_TREE);
   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
@@ -674,15 +695,16 @@ tree_mod_pow2 (tree stmt, tree operation, tree op1, tree op2, int prob,
 
   /* tmp2 == op2-1 inherited from previous block */
   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, result,
-                 build2 (BIT_AND_EXPR, optype, op1, tmp2));
+  stmt1 = build_gimple_modify_stmt (result,
+                                   build2 (BIT_AND_EXPR, optype, op1, tmp2));
   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb2end = stmt1;
 
   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, result,
-                 build2 (TREE_CODE (operation), optype, op1, op2));
+  stmt1 = build_gimple_modify_stmt (result,
+                                   build2 (TREE_CODE (operation), optype,
+                                           op1, op2));
   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb3end = stmt1;
@@ -816,13 +838,11 @@ tree_mod_subtract (tree stmt, tree operation, tree op1, tree op2,
   bsi = bsi_for_stmt (stmt);
 
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, result, op1);
-  stmt2 = build2 (GIMPLE_MODIFY_STMT, optype, tmp1, op2);
+  stmt1 = build_gimple_modify_stmt (result, op1);
+  stmt2 = build_gimple_modify_stmt (tmp1, op2);
   stmt3 = build3 (COND_EXPR, void_type_node,
            build2 (LT_EXPR, boolean_type_node, result, tmp1),
-           build1 (GOTO_EXPR, void_type_node, label_decl3),
-           build1 (GOTO_EXPR, void_type_node, 
-                   ncounts ? label_decl1 : label_decl2));
+           NULL_TREE, NULL_TREE);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
@@ -831,12 +851,12 @@ tree_mod_subtract (tree stmt, tree operation, tree op1, tree op2,
   if (ncounts) /* Assumed to be 0 or 1 */
     {
       label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-      stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, result,
-                     build2 (MINUS_EXPR, optype, result, tmp1));
+      stmt1 = build_gimple_modify_stmt (result,
+                                       build2 (MINUS_EXPR, optype,
+                                               result, tmp1));
       stmt2 = build3 (COND_EXPR, void_type_node,
                build2 (LT_EXPR, boolean_type_node, result, tmp1),
-               build1 (GOTO_EXPR, void_type_node, label_decl3),
-               build1 (GOTO_EXPR, void_type_node, label_decl2));
+               NULL_TREE, NULL_TREE);
       bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
       bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
       bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
@@ -845,8 +865,9 @@ tree_mod_subtract (tree stmt, tree operation, tree op1, tree op2,
 
   /* Fallback case. */
   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, result,
-                   build2 (TREE_CODE (operation), optype, result, tmp1));
+  stmt1 = build_gimple_modify_stmt (result,
+                                   build2 (TREE_CODE (operation), optype,
+                                           result, tmp1));
   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb3end = stmt1;
@@ -1033,7 +1054,7 @@ tree_ic (tree stmt, tree call, struct cgraph_node* direct_call,
         int prob, gcov_type count, gcov_type all)
 {
   tree stmt1, stmt2, stmt3;
-  tree tmp1, tmpv;
+  tree tmp1, tmpv, tmp;
   tree label_decl1 = create_artificial_label ();
   tree label_decl2 = create_artificial_label ();
   tree label1, label2;
@@ -1050,15 +1071,14 @@ tree_ic (tree stmt, tree call, struct cgraph_node* direct_call,
 
   tmpv = create_tmp_var (optype, "PROF");
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, tmpv, 
-                 unshare_expr (TREE_OPERAND (call, 0)));
-  stmt2 = build2 (GIMPLE_MODIFY_STMT, optype, tmp1
-                 fold_convert (optype, build_addr (direct_call->decl, 
-                                                   current_function_decl)));
+  stmt1 = build_gimple_modify_stmt (tmpv, 
+                                   unshare_expr (CALL_EXPR_FN (call)));
+  tmp = fold_convert (optype, build_addr (direct_call->decl
+                                         current_function_decl));
+  stmt2 = build_gimple_modify_stmt (tmp1, tmp);
   stmt3 = build3 (COND_EXPR, void_type_node,
                  build2 (NE_EXPR, boolean_type_node, tmp1, tmpv),
-                 build1 (GOTO_EXPR, void_type_node, label_decl2),
-                 build1 (GOTO_EXPR, void_type_node, label_decl1));
+                 NULL_TREE, NULL_TREE);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
@@ -1067,8 +1087,8 @@ tree_ic (tree stmt, tree call, struct cgraph_node* direct_call,
   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
   stmt1 = unshare_expr (stmt);
   new_call = get_call_expr_in (stmt1);
-  TREE_OPERAND (new_call, 0) = build_addr (direct_call->decl, 
-                                          current_function_decl);
+  CALL_EXPR_FN (new_call) = build_addr (direct_call->decl, 
+                                       current_function_decl);
   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bb2end = stmt1;
@@ -1143,7 +1163,7 @@ tree_ic_transform (tree stmt)
   if (!call || TREE_CODE (call) != CALL_EXPR)
     return false;
 
-  callee = TREE_OPERAND (call, 0);
+  callee = CALL_EXPR_FN (call);
 
   if (TREE_CODE (callee) == ADDR_EXPR)
     return false;
@@ -1183,9 +1203,9 @@ tree_ic_transform (tree stmt)
   return true;
 }
 
-/* Return true if the stringop FNDECL with ARGLIST shall be profiled.  */
+/* Return true if the stringop CALL with FNDECL shall be profiled.  */
 static bool
-interesting_stringop_to_profile_p (tree fndecl, tree arglist)
+interesting_stringop_to_profile_p (tree fndecl, tree call)
 {
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
 
@@ -1197,18 +1217,18 @@ interesting_stringop_to_profile_p (tree fndecl, tree arglist)
     {
      case BUILT_IN_MEMCPY:
      case BUILT_IN_MEMPCPY:
-       return validate_arglist (arglist,
-                                POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
-                                VOID_TYPE);
+       return validate_arglist (call,
+                               POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
+                               VOID_TYPE);
      case BUILT_IN_MEMSET:
-       return validate_arglist (arglist,
-                                POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
-                                VOID_TYPE);
+       return validate_arglist (call,
+                               POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
+                               VOID_TYPE);
      case BUILT_IN_BZERO:
-        return validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE,
-                                VOID_TYPE);
+       return validate_arglist (call, POINTER_TYPE, INTEGER_TYPE,
+                               VOID_TYPE);
      default:
-       gcc_unreachable ();
+       gcc_unreachable ();
     }
 }
 
@@ -1234,8 +1254,7 @@ tree_stringop_fixed_value (tree stmt, tree value, int prob, gcov_type count,
   edge e12, e13, e23, e24, e34;
   block_stmt_iterator bsi;
   tree call = get_call_expr_in (stmt);
-  tree arglist = TREE_OPERAND (call, 1);
-  tree blck_size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree blck_size = CALL_EXPR_ARG (call, 2);
   tree optype = TREE_TYPE (blck_size);
   int region;
 
@@ -1258,13 +1277,11 @@ tree_stringop_fixed_value (tree stmt, tree value, int prob, gcov_type count,
 
   tmpv = create_tmp_var (optype, "PROF");
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (GIMPLE_MODIFY_STMT, optype, tmpv,
-                 fold_convert (optype, value));
-  stmt2 = build2 (GIMPLE_MODIFY_STMT, optype, tmp1, blck_size);
+  stmt1 = build_gimple_modify_stmt (tmpv, fold_convert (optype, value));
+  stmt2 = build_gimple_modify_stmt (tmp1, blck_size);
   stmt3 = build3 (COND_EXPR, void_type_node,
            build2 (NE_EXPR, boolean_type_node, tmp1, tmpv),
-           build1 (GOTO_EXPR, void_type_node, label_decl2),
-           build1 (GOTO_EXPR, void_type_node, label_decl1));
+           NULL_TREE, NULL_TREE);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
@@ -1273,8 +1290,7 @@ tree_stringop_fixed_value (tree stmt, tree value, int prob, gcov_type count,
   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
   stmt1 = unshare_expr (stmt);
   call = get_call_expr_in (stmt1);
-  arglist = TREE_OPERAND (call, 1);
-  TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))) = value;
+  CALL_EXPR_ARG (call, 2) = value;
   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
   region = lookup_stmt_eh_region (stmt);
@@ -1320,7 +1336,6 @@ tree_stringops_transform (block_stmt_iterator *bsi)
   tree stmt = bsi_stmt (*bsi);
   tree call = get_call_expr_in (stmt);
   tree fndecl;
-  tree arglist;
   tree blck_size;
   enum built_in_function fcode;
   histogram_value histogram;
@@ -1337,14 +1352,13 @@ tree_stringops_transform (block_stmt_iterator *bsi)
   if (!fndecl)
     return false;
   fcode = DECL_FUNCTION_CODE (fndecl);
-  arglist = TREE_OPERAND (call, 1);
-  if (!interesting_stringop_to_profile_p (fndecl, arglist))
+  if (!interesting_stringop_to_profile_p (fndecl, call))
     return false;
 
   if (fcode == BUILT_IN_BZERO)
-    blck_size = TREE_VALUE (TREE_CHAIN (arglist));
+    blck_size = CALL_EXPR_ARG (call, 1);
   else
-    blck_size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+    blck_size = CALL_EXPR_ARG (call, 2);
   if (TREE_CODE (blck_size) == INTEGER_CST)
     return false;
 
@@ -1364,27 +1378,27 @@ tree_stringops_transform (block_stmt_iterator *bsi)
   if (check_counter (stmt, "value", all, bb_for_stmt (stmt)->count))
     return false;
   prob = (count * REG_BR_PROB_BASE + all / 2) / all;
-  dest = TREE_VALUE (arglist);
+  dest = CALL_EXPR_ARG (call, 0);
   dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
   switch (fcode)
     {
     case BUILT_IN_MEMCPY:
     case BUILT_IN_MEMPCPY:
-      src = TREE_VALUE (TREE_CHAIN (arglist));
+      src = CALL_EXPR_ARG (call, 1);
       src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       if (!can_move_by_pieces (val, MIN (dest_align, src_align)))
        return false;
       break;
     case BUILT_IN_MEMSET:
       if (!can_store_by_pieces (val, builtin_memset_read_str,
-                               TREE_VALUE (TREE_CHAIN (arglist)),
-                               dest_align))
+                               CALL_EXPR_ARG (call, 1),
+                               dest_align, true))
        return false;
       break;
     case BUILT_IN_BZERO:
       if (!can_store_by_pieces (val, builtin_memset_read_str,
                                integer_zero_node,
-                               dest_align))
+                               dest_align, true))
        return false;
       break;
     default:
@@ -1404,6 +1418,55 @@ tree_stringops_transform (block_stmt_iterator *bsi)
   return true;
 }
 
+void
+stringop_block_profile (tree stmt, unsigned int *expected_align,
+                       HOST_WIDE_INT *expected_size)
+{
+  histogram_value histogram;
+  histogram = gimple_histogram_value_of_type (cfun, stmt, HIST_TYPE_AVERAGE);
+  if (!histogram)
+    *expected_size = -1;
+  else if (!histogram->hvalue.counters[1])
+    {
+      *expected_size = -1;
+      gimple_remove_histogram_value (cfun, stmt, histogram);
+    }
+  else
+    {
+      gcov_type size;
+      size = ((histogram->hvalue.counters[0]
+             + histogram->hvalue.counters[1] / 2)
+              / histogram->hvalue.counters[1]);
+      /* Even if we can hold bigger value in SIZE, INT_MAX
+        is safe "infinity" for code generation strategies.  */
+      if (size > INT_MAX)
+       size = INT_MAX;
+      *expected_size = size;
+      gimple_remove_histogram_value (cfun, stmt, histogram);
+    }
+  histogram = gimple_histogram_value_of_type (cfun, stmt, HIST_TYPE_IOR);
+  if (!histogram)
+    *expected_align = 0;
+  else if (!histogram->hvalue.counters[0])
+    {
+      gimple_remove_histogram_value (cfun, stmt, histogram);
+      *expected_align = 0;
+    }
+  else
+    {
+      gcov_type count;
+      int alignment;
+
+      count = histogram->hvalue.counters[0];
+      alignment = 1;
+      while (!(count & alignment)
+            && (alignment * 2 * BITS_PER_UNIT))
+       alignment <<= 1;
+      *expected_align = alignment * BITS_PER_UNIT;
+      gimple_remove_histogram_value (cfun, stmt, histogram);
+    }
+}
+
 struct value_prof_hooks {
   /* Find list of values for which we want to measure histograms.  */
   void (*find_values_to_profile) (histogram_values *);
@@ -1490,7 +1553,7 @@ tree_indirect_call_to_profile (tree stmt, histogram_values *values)
   if (!call || TREE_CODE (call) != CALL_EXPR)
     return;
 
-  callee = TREE_OPERAND (call, 0);
+  callee = CALL_EXPR_FN (call);
   
   if (TREE_CODE (callee) == ADDR_EXPR)
     return;
@@ -1511,8 +1574,8 @@ tree_stringops_values_to_profile (tree stmt, histogram_values *values)
 {
   tree call = get_call_expr_in (stmt);
   tree fndecl;
-  tree arglist;
   tree blck_size;
+  tree dest;
   enum built_in_function fcode;
 
   if (!call)
@@ -1521,20 +1584,29 @@ tree_stringops_values_to_profile (tree stmt, histogram_values *values)
   if (!fndecl)
     return;
   fcode = DECL_FUNCTION_CODE (fndecl);
-  arglist = TREE_OPERAND (call, 1);
 
-  if (!interesting_stringop_to_profile_p (fndecl, arglist))
+  if (!interesting_stringop_to_profile_p (fndecl, call))
     return;
 
+  dest = CALL_EXPR_ARG (call, 0);
   if (fcode == BUILT_IN_BZERO)
-    blck_size = TREE_VALUE (TREE_CHAIN (arglist));
+    blck_size = CALL_EXPR_ARG (call, 1);
   else
-    blck_size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+    blck_size = CALL_EXPR_ARG (call, 2);
 
   if (TREE_CODE (blck_size) != INTEGER_CST)
+    {
+      VEC_safe_push (histogram_value, heap, *values,
+                    gimple_alloc_histogram_value (cfun, HIST_TYPE_SINGLE_VALUE,
+                                                  stmt, blck_size));
+      VEC_safe_push (histogram_value, heap, *values,
+                    gimple_alloc_histogram_value (cfun, HIST_TYPE_AVERAGE,
+                                                  stmt, blck_size));
+    }
+  if (TREE_CODE (blck_size) != INTEGER_CST)
     VEC_safe_push (histogram_value, heap, *values,
-                  gimple_alloc_histogram_value (cfun, HIST_TYPE_SINGLE_VALUE,
-                                                stmt, blck_size));
+                  gimple_alloc_histogram_value (cfun, HIST_TYPE_IOR,
+                                                stmt, dest));
 }
 
 /* Find values inside STMT for that we want to measure histograms and adds
@@ -1588,6 +1660,14 @@ tree_find_values_to_profile (histogram_values *values)
          hist->n_counters = 3;
          break;
 
+       case HIST_TYPE_AVERAGE:
+         hist->n_counters = 2;
+         break;
+
+       case HIST_TYPE_IOR:
+         hist->n_counters = 1;
+         break;
+
        default:
          gcc_unreachable ();
        }