gimple.c (gimple_build_call_1): Deal with FUNCTION_DECL fn.
authorRichard Guenther <rguenther@suse.de>
Sat, 9 Aug 2008 17:28:39 +0000 (17:28 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 9 Aug 2008 17:28:39 +0000 (17:28 +0000)
2008-08-09  Richard Guenther  <rguenther@suse.de>

* gimple.c (gimple_build_call_1): Deal with FUNCTION_DECL fn.
* gimple.h (gimple_call_fn): Adjust comment.
(gimple_call_set_fndecl): New function.
(gimple_call_fndecl): Adjust for GIMPLE_CALL no
longer having bare FUNCTION_DECL operand.
(gimple_call_return_type): Likewise.
* tree-cfg.c (verify_stmt): Verify function operand of a GIMPLE_CALL.

* value-prof.c (gimple_divmod_fixed_value): Do not emit labels.
(gimple_mod_pow2): Likewise.
(gimple_mod_subtract): Likewise.
(gimple_ic): Likewise.
(gimple_stringop_fixed_value): Likewise.
(gimple_indirect_call_to_profile): Fix for GIMPLE_CALL no
longer having bare FUNCTION_DECL operand.
* ipa-cp.c (ipcp_update_callgraph): Use gimple_call_set_fndecl.
* omp-low.c (optimize_omp_library_calls): Likewise.
* cgraphunit.c (update_call_expr): Likewise.
* tree-ssa-math-opts.c (execute_cse_reciprocals): Likewise.
(execute_convert_to_rsqrt): Likewise.
* cfgexpand.c (gimple_to_tree): Simplify.
(release_stmt_tree): Fix for GIMPLE_CALL no longer having
bare FUNCTION_DECL operand.
* tree-nested.c (init_tmp_var_with_call): Use gimple_call_return_type.
(convert_gimple_call): Use gimple_call_fndecl.
* c-common.c (c_warn_unused_result): Likewise.

* gcc.dg/tree-ssa/inline-2.c: New testcase.

From-SVN: r138907

14 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/cfgexpand.c
gcc/cgraphunit.c
gcc/gimple.c
gcc/gimple.h
gcc/ipa-cp.c
gcc/omp-low.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/inline-2.c [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-nested.c
gcc/tree-ssa-math-opts.c
gcc/value-prof.c

index 12b9e4fafb9dd9cbe1eb19b7d9f4d5989f5ed7fb..71a8477cf571a3facf7eb41f7ba35d92f508f3b0 100644 (file)
@@ -1,3 +1,32 @@
+2008-08-09  Richard Guenther  <rguenther@suse.de>
+
+       * gimple.c (gimple_build_call_1): Deal with FUNCTION_DECL fn.
+       * gimple.h (gimple_call_fn): Adjust comment.
+       (gimple_call_set_fndecl): New function.
+       (gimple_call_fndecl): Adjust for GIMPLE_CALL no
+       longer having bare FUNCTION_DECL operand.
+       (gimple_call_return_type): Likewise.
+       * tree-cfg.c (verify_stmt): Verify function operand of a GIMPLE_CALL.
+
+       * value-prof.c (gimple_divmod_fixed_value): Do not emit labels.
+       (gimple_mod_pow2): Likewise.
+       (gimple_mod_subtract): Likewise.
+       (gimple_ic): Likewise.
+       (gimple_stringop_fixed_value): Likewise.
+       (gimple_indirect_call_to_profile): Fix for GIMPLE_CALL no
+       longer having bare FUNCTION_DECL operand.
+       * ipa-cp.c (ipcp_update_callgraph): Use gimple_call_set_fndecl.
+       * omp-low.c (optimize_omp_library_calls): Likewise.
+       * cgraphunit.c (update_call_expr): Likewise.
+       * tree-ssa-math-opts.c (execute_cse_reciprocals): Likewise.
+       (execute_convert_to_rsqrt): Likewise.
+       * cfgexpand.c (gimple_to_tree): Simplify.
+       (release_stmt_tree): Fix for GIMPLE_CALL no longer having
+       bare FUNCTION_DECL operand.
+       * tree-nested.c (init_tmp_var_with_call): Use gimple_call_return_type.
+       (convert_gimple_call): Use gimple_call_fndecl.
+       * c-common.c (c_warn_unused_result): Likewise.
+
 2008-08-09  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
 
        PR c/17880
index bf75fe78e7bd47fd370188d12b0b16d9734d209e..59da62f7ecc8d0864ac35dc21ebe6a62402047bd 100644 (file)
@@ -7546,15 +7546,8 @@ c_warn_unused_result (gimple_seq seq)
          /* This is a naked call, as opposed to a GIMPLE_CALL with an
             LHS.  All calls whose value is ignored should be
             represented like this.  Look for the attribute.  */
-         fdecl = gimple_call_fn (g);
-         if (TREE_CODE (fdecl) == FUNCTION_DECL)
-           ftype = TREE_TYPE (fdecl);
-         else
-           {
-             ftype = TREE_TYPE (fdecl);
-             /* Look past pointer-to-function to the function type itself.  */
-             ftype = TREE_TYPE (ftype);
-           }
+         fdecl = gimple_call_fndecl (g);
+         ftype = TREE_TYPE (TREE_TYPE (gimple_call_fn (g)));
 
          if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
            {
index 296d74858b466571744f3140e0a0c25f22e6b03b..ac228f9b79fc23bc3e722cae072d298fc95e1ed4 100644 (file)
@@ -216,16 +216,8 @@ gimple_to_tree (gimple stmt)
         
        t = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
 
-        fn = gimple_call_fn (stmt);
-        if (TREE_CODE (fn) == FUNCTION_DECL)
-          CALL_EXPR_FN (t) = build1 (ADDR_EXPR,
-                                     build_pointer_type (TREE_TYPE (fn)),
-                                     fn);
-        else
-          CALL_EXPR_FN (t) = fn;
-        
+        CALL_EXPR_FN (t) = gimple_call_fn (stmt);
         TREE_TYPE (t) = gimple_call_return_type (stmt);
-
        CALL_EXPR_STATIC_CHAIN (t) = gimple_call_chain (stmt);
 
        for (i = 0; i < gimple_call_num_args (stmt); i++)
@@ -253,7 +245,9 @@ gimple_to_tree (gimple stmt)
 
         /* Record the original call statement, as it may be used
            to retrieve profile information during expansion.  */
-       if (TREE_CODE (fn) == FUNCTION_DECL && DECL_BUILT_IN (fn))
+
+       if ((fn = gimple_call_fndecl (stmt)) != NULL_TREE
+           && DECL_BUILT_IN (fn))
          {
            ann = get_tree_common_ann (t);
            ann->stmt = stmt;
@@ -368,15 +362,11 @@ release_stmt_tree (gimple stmt, tree stmt_tree)
     case GIMPLE_CALL:
       if (gimple_call_lhs (stmt))
        {
-         if (TREE_CODE (gimple_call_fn (stmt)) == FUNCTION_DECL)
-           ggc_free (CALL_EXPR_FN (TREE_OPERAND (stmt_tree, 1)));
          ann = tree_common_ann (TREE_OPERAND (stmt_tree, 1));
          if (ann)
            ggc_free (ann);
          ggc_free (TREE_OPERAND (stmt_tree, 1));
        }
-      else if (TREE_CODE (gimple_call_fn (stmt)) == FUNCTION_DECL)
-       ggc_free (CALL_EXPR_FN (stmt_tree));
       break;
     default:
       break;
index 48dd70bcac797448f990ef0ba722a548254543d2..ae3dee417da59c468e4d24935c74842e9e906b4c 100644 (file)
@@ -1420,7 +1420,7 @@ update_call_expr (struct cgraph_node *new_version)
 
   /* Update the call expr on the edges to call the new version.  */
   for (e = new_version->callers; e; e = e->next_caller)
-    gimple_call_set_fn (e->call_stmt, new_version->decl);
+    gimple_call_set_fndecl (e->call_stmt, new_version->decl);
 }
 
 
index 2d097c733e7b559e7cf6a7c9234d261e7aa74907..6e8971f4ec17a27eba524dd4aee2af38832b6d99 100644 (file)
@@ -285,6 +285,8 @@ static inline gimple
 gimple_build_call_1 (tree fn, unsigned nargs)
 {
   gimple s = gimple_build_with_ops (GIMPLE_CALL, 0, nargs + 3);
+  if (TREE_CODE (fn) == FUNCTION_DECL)
+    fn = build_fold_addr_expr (fn);
   gimple_set_op (s, 1, fn);
   return s;
 }
index f32600daf9150cd0bc6e6a48d54fad65b005809f..3799e062b37ecc33e53c34293e49edb0b76df781 100644 (file)
@@ -1905,7 +1905,7 @@ gimple_call_set_lhs (gimple gs, tree lhs)
 
 
 /* Return the tree node representing the function called by call
-   statement GS.  This may or may not be a FUNCTION_DECL node.  */
+   statement GS.  */
 
 static inline tree
 gimple_call_fn (const_gimple gs)
@@ -1937,6 +1937,17 @@ gimple_call_set_fn (gimple gs, tree fn)
 }
 
 
+/* Set FNDECL to be the function called by call statement GS.  */
+
+static inline void
+gimple_call_set_fndecl (gimple gs, tree decl)
+{
+  GIMPLE_CHECK (gs, GIMPLE_CALL);
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gimple_set_op (gs, 1, build_fold_addr_expr (decl));
+}
+
+
 /* If a given GIMPLE_CALL's callee is a FUNCTION_DECL, return it.
    Otherwise return NULL.  This function is analogous to
    get_callee_fndecl in tree land.  */
@@ -1944,8 +1955,13 @@ gimple_call_set_fn (gimple gs, tree fn)
 static inline tree
 gimple_call_fndecl (const_gimple gs)
 {
-  tree decl = gimple_call_fn (gs);
-  return (TREE_CODE (decl) == FUNCTION_DECL) ? decl : NULL_TREE;
+  tree addr = gimple_call_fn (gs);
+  if (TREE_CODE (addr) == ADDR_EXPR)
+    {
+      gcc_assert (TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL);
+      return TREE_OPERAND (addr, 0);
+    }
+  return NULL_TREE;
 }
 
 
@@ -1957,9 +1973,9 @@ gimple_call_return_type (const_gimple gs)
   tree fn = gimple_call_fn (gs);
   tree type = TREE_TYPE (fn);
 
-  /* See through pointers.  */
-  if (POINTER_TYPE_P (type))
-    type = TREE_TYPE (type);
+  /* See through the pointer.  */
+  gcc_assert (POINTER_TYPE_P (type));
+  type = TREE_TYPE (type);
 
   gcc_assert (TREE_CODE (type) == FUNCTION_TYPE
              || TREE_CODE (type) == METHOD_TYPE);
index 8ad6ddb3fec185ad3291e3336af8a97fb181de8c..a129a74c7ffd3f510bcaf4927b43d57179a9b5e2 100644 (file)
@@ -809,7 +809,7 @@ ipcp_update_callgraph (void)
            if (ipcp_need_redirect_p (cs))
              {
                cgraph_redirect_edge_callee (cs, orig_callee);
-               gimple_call_set_fn (cs->call_stmt, orig_callee->decl);
+               gimple_call_set_fndecl (cs->call_stmt, orig_callee->decl);
              }
          }
     }
index cda05a449caa8744bf4f1bf57bf1815bf0a7b207..d6c5500319aa6442bdfdb12b3facc48e03ed3d33 100644 (file)
@@ -3222,7 +3222,7 @@ optimize_omp_library_calls (gimple entry_stmt)
                   != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (built_in))))
              continue;
 
-           gimple_call_set_fn (call, build_fold_addr_expr (built_in));
+           gimple_call_set_fndecl (call, built_in);
          }
       }
 }
index 4e3cf60c62b0df45b0c9d7b10013aab44a147681..4c98fca979f7c620a586061e005dac2a810b2a0e 100644 (file)
@@ -1,3 +1,7 @@
+2008-08-09  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/inline-2.c: New testcase.
+
 2008-08-09  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>
 
        PR c/17880
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/inline-2.c b/gcc/testsuite/gcc.dg/tree-ssa/inline-2.c
new file mode 100644 (file)
index 0000000..8a7b907
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do link } */
+/* { dg-options "-O" } */
+
+/* When optimized we expect the call to foo () in bar to be inlined
+   and the call to link_error optimized away.  */
+
+extern void link_error (void);
+int __attribute__((always_inline)) foo(void) { return 0; }
+
+int main()
+{
+  int (*fn)(void) = foo;
+  if (fn())
+    link_error ();
+  return 0;
+}
+
index 00979bd82ab10929ea522a1c595b2caa83a79029..99978efe35b7b496530ab765a5f6c987260ad162 100644 (file)
@@ -3810,9 +3810,17 @@ verify_stmt (gimple_stmt_iterator *gsi)
      didn't see a function declaration before the call.  */
   if (is_gimple_call (stmt))
     {
-      tree decl = gimple_call_fn (stmt);
+      tree decl;
 
-      if (TREE_CODE (decl) == FUNCTION_DECL 
+      if (!is_gimple_call_addr (gimple_call_fn (stmt)))
+       {
+         error ("invalid function in call statement");
+         return true;
+       }
+
+      decl = gimple_call_fndecl (stmt);
+      if (decl
+         && TREE_CODE (decl) == FUNCTION_DECL
          && DECL_LOOPING_CONST_OR_PURE_P (decl)
          && (!DECL_PURE_P (decl))
          && (!TREE_READONLY (decl)))
index 8f4ab047ae9d9b7aa10f2d9c5e210494a921ba52..cfa1dd4b1eef0c3e212df3e5e1b12b0bb3057975 100644 (file)
@@ -363,8 +363,7 @@ init_tmp_var_with_call (struct nesting_info *info, gimple_stmt_iterator *gsi,
 {
   tree t;
 
-  t = create_tmp_var_for (info, TREE_TYPE (TREE_TYPE (gimple_call_fn (call))),
-                          NULL);
+  t = create_tmp_var_for (info, gimple_call_return_type (call), NULL);
   gimple_call_set_lhs (call, t);
   if (! gsi_end_p (*gsi))
     gimple_set_location (call, gimple_location (gsi_stmt (*gsi)));
@@ -1851,8 +1850,8 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p,
   switch (gimple_code (stmt))
     {
     case GIMPLE_CALL:
-      decl = gimple_call_fn (stmt);
-      if (TREE_CODE (decl) != FUNCTION_DECL)
+      decl = gimple_call_fndecl (stmt);
+      if (!decl)
        break;
       target_context = decl_function_context (decl);
       if (target_context && !DECL_NO_STATIC_CHAIN (decl))
index dfc00bcdd12aa2f46fec4a34f0679334646ad899..844ec9d1ad0cca60c10718fc57846a2947d5df31 100644 (file)
@@ -533,7 +533,7 @@ execute_cse_reciprocals (void)
                  if (!fndecl)
                    continue;
 
-                 gimple_call_set_fn (stmt1, fndecl);
+                 gimple_call_set_fndecl (stmt1, fndecl);
                  update_stmt (stmt1);
 
                  gimple_assign_set_rhs_code (stmt, MULT_EXPR);
@@ -840,7 +840,7 @@ execute_convert_to_rsqrt (void)
                  fold_stmt_inplace (stmt1);
                  update_stmt (stmt1);
 
-                 gimple_call_set_fn (stmt, fndecl);
+                 gimple_call_set_fndecl (stmt, fndecl);
                  update_stmt (stmt);
                }
            }
index da35008ca8e29f2c92f53218aebd48ce0218a43f..7f776ccaf890ad10e52de07043a3a62da0eec333 100644 (file)
@@ -541,10 +541,8 @@ static tree
 gimple_divmod_fixed_value (gimple stmt, tree value, int prob, gcov_type count,
                           gcov_type all)
 {
-  gimple stmt1, stmt2, stmt3, label1, label2;
+  gimple stmt1, stmt2, stmt3;
   tree tmp1, tmp2, tmpv;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
   gimple bb1end, bb2end, bb3end;
   basic_block bb, bb2, bb3, bb4;
   tree optype, op1, op2;
@@ -573,17 +571,13 @@ gimple_divmod_fixed_value (gimple stmt, tree value, int prob, gcov_type count,
   bb1end = stmt3;
 
   tmp2 = create_tmp_var (optype, "PROF");
-  label1 = gimple_build_label (label_decl1);
   stmt1 = gimple_build_assign_with_ops (gimple_assign_rhs_code (stmt), tmp2,
                                        op1, tmpv);
-  gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb2end = stmt1;
 
-  label2 = gimple_build_label (label_decl2);
   stmt1 = gimple_build_assign_with_ops (gimple_assign_rhs_code (stmt), tmp2,
                                        op1, op2);
-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb3end = stmt1;
 
@@ -702,9 +696,6 @@ gimple_mod_pow2 (gimple stmt, int prob, gcov_type count, gcov_type all)
 {
   gimple stmt1, stmt2, stmt3, stmt4;
   tree tmp2, tmp3;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  gimple label1, label2;
   gimple bb1end, bb2end, bb3end;
   basic_block bb, bb2, bb3, bb4;
   tree optype, op1, op2;
@@ -736,16 +727,12 @@ gimple_mod_pow2 (gimple stmt, int prob, gcov_type count, gcov_type all)
   bb1end = stmt4;
 
   /* tmp2 == op2-1 inherited from previous block.  */
-  label1 = gimple_build_label (label_decl1);
   stmt1 = gimple_build_assign_with_ops (BIT_AND_EXPR, result, op1, tmp2);
-  gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb2end = stmt1;
 
-  label2 = gimple_build_label (label_decl2);
   stmt1 = gimple_build_assign_with_ops (gimple_assign_rhs_code (stmt), result,
                                        op1, op2);
-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb3end = stmt1;
 
@@ -861,10 +848,6 @@ gimple_mod_subtract (gimple stmt, int prob1, int prob2, int ncounts,
 {
   gimple stmt1, stmt2, stmt3;
   tree tmp1;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  tree label_decl3 = create_artificial_label ();
-  gimple label1, label2, label3;
   gimple bb1end, bb2end = NULL, bb3end;
   basic_block bb, bb2, bb3, bb4;
   tree optype, op1, op2;
@@ -894,26 +877,19 @@ gimple_mod_subtract (gimple stmt, int prob1, int prob2, int ncounts,
 
   if (ncounts) /* Assumed to be 0 or 1 */
     {
-      label1 = gimple_build_label (label_decl1);
       stmt1 = gimple_build_assign_with_ops (MINUS_EXPR, result, result, tmp1);
       stmt2 = gimple_build_cond (LT_EXPR, result, tmp1, NULL_TREE, NULL_TREE);
-      gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
       gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
       gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
       bb2end = stmt2;
     }
 
   /* Fallback case. */
-  label2 = gimple_build_label (label_decl2);
   stmt1 = gimple_build_assign_with_ops (gimple_assign_rhs_code (stmt), result,
                                        result, tmp1);
-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb3end = stmt1;
 
-  label3 = gimple_build_label (label_decl3);
-  gsi_insert_before (&gsi, label3, GSI_SAME_STMT);
-
   /* Fix CFG. */
   /* Edge e23 connects bb2 to bb3, etc. */
   /* However block 3 is optional; if it is not there, references
@@ -1098,9 +1074,6 @@ gimple_ic (gimple stmt, gimple call, struct cgraph_node *direct_call,
 {
   gimple stmt1, stmt2, stmt3;
   tree tmp1, tmpv, tmp;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  gimple label1, label2;
   gimple bb1end, bb2end, bb3end;
   basic_block bb, bb2, bb3, bb4;
   tree optype = build_pointer_type (void_type_node);
@@ -1124,16 +1097,11 @@ gimple_ic (gimple stmt, gimple call, struct cgraph_node *direct_call,
   gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
   bb1end = stmt3;
 
-  label1 = gimple_build_label (label_decl1);
   stmt1 = gimple_copy (stmt);
   gimple_call_set_fn (stmt,
                      build_addr (direct_call->decl, current_function_decl));
-  gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   bb2end = stmt1;
-
-  label2 = gimple_build_label (label_decl2);
-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
   bb3end = stmt;
 
   /* Fix CFG. */
@@ -1287,9 +1255,6 @@ gimple_stringop_fixed_value (gimple stmt, tree value, int prob, gcov_type count,
 {
   gimple stmt1, stmt2, stmt3;
   tree tmp1, tmpv;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  gimple label1, label2;
   gimple bb1end, bb2end;
   basic_block bb, bb2, bb3, bb4;
   edge e12, e13, e23, e24, e34;
@@ -1325,17 +1290,13 @@ gimple_stringop_fixed_value (gimple stmt, tree value, int prob, gcov_type count,
   gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
   bb1end = stmt3;
 
-  label1 = gimple_build_label (label_decl1);
   stmt1 = gimple_copy (stmt);
   gimple_call_set_arg (stmt1, 2, value);
-  gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
   region = lookup_stmt_eh_region (stmt);
   if (region >= 0)
     add_stmt_to_eh_region (stmt1, region);
   bb2end = stmt1;
-  label2 = gimple_build_label (label_decl2);
-  gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
 
   /* Fix CFG. */
   /* Edge e23 connects bb2 to bb3, etc. */
@@ -1581,13 +1542,11 @@ gimple_indirect_call_to_profile (gimple stmt, histogram_values *values)
 {
   tree callee;
 
-  if (gimple_code (stmt) != GIMPLE_CALL)
+  if (gimple_code (stmt) != GIMPLE_CALL
+      || gimple_call_fndecl (stmt) != NULL_TREE)
     return;
 
   callee = gimple_call_fn (stmt);
-  
-  if (TREE_CODE (callee) == FUNCTION_DECL)
-    return;
 
   VEC_reserve (histogram_value, heap, *values, 3);