/* Transformations based on profile information for values.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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
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"
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. */
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. */
}
}
+
+/* Move all histograms associated with OSTMT to STMT. */
+
+void
+gimple_move_stmt_histograms (struct function *fun, tree stmt, tree ostmt)
+{
+ histogram_value val = gimple_histogram_value (fun, ostmt);
+ if (val)
+ {
+ /* The following three statements can't be reordered,
+ because histogram hashtab relies on stmt field value
+ for finding the exact slot. */
+ set_histogram_value (fun, ostmt, NULL);
+ for (; val != NULL; val = val->hvalue.next)
+ val->hvalue.stmt = stmt;
+ set_histogram_value (fun, stmt, val);
+ }
+}
+
static bool error_found = false;
/* Helper function for verify_histograms. For each histogram reachable via htab
debug_generic_stmt (hist->hvalue.stmt);
error_found = true;
}
- return 0;
+ return 1;
}
/* Verify sanity of the histograms. */
memset (hist, 0xab, sizeof (*hist));
#endif
free (hist);
- return 0;
+ return 1;
}
void
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);
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;
enum tree_code code;
gcov_type val, count, all;
tree modify, op, op1, op2, result, value, tree_val;
- int prob;
+ gcov_type prob;
modify = stmt;
if (TREE_CODE (stmt) == RETURN_EXPR
return false;
/* Compute probability of taking the optimal path. */
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ if (all > 0)
+ prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ else
+ prob = 0;
tree_val = build_int_cst_wide (get_gcov_type (),
(unsigned HOST_WIDE_INT) val,
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);
/* 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;
enum tree_code code;
gcov_type count, wrong_values, all;
tree modify, op, op1, op2, result, value;
- int prob;
+ gcov_type prob;
modify = stmt;
if (TREE_CODE (stmt) == RETURN_EXPR
if (check_counter (stmt, "pow2", all, bb_for_stmt (stmt)->count))
return false;
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ if (all > 0)
+ prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ else
+ prob = 0;
result = tree_mod_pow2 (stmt, op, op1, op2, prob, count, all);
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);
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);
/* 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;
enum tree_code code;
gcov_type count, wrong_values, all;
tree modify, op, op1, op2, result, value;
- int prob1, prob2;
+ gcov_type prob1, prob2;
unsigned int i, steps;
gcov_type count1, count2;
}
/* Compute probability of taking the optimal path(s). */
- prob1 = (count1 * REG_BR_PROB_BASE + all / 2) / all;
- prob2 = (count2 * REG_BR_PROB_BASE + all / 2) / all;
+ if (all > 0)
+ {
+ prob1 = (count1 * REG_BR_PROB_BASE + all / 2) / all;
+ prob2 = (count2 * REG_BR_PROB_BASE + all / 2) / all;
+ }
+ else
+ {
+ prob1 = prob2 = 0;
+ }
/* In practice, "steps" is always 2. This interface reflects this,
and will need to be changed if "steps" can change. */
/* Do transformation
- if (actual_callee_addres == addres_of_most_common_function/method)
+ if (actual_callee_address == address_of_most_common_function/method)
do direct call
else
old 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;
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);
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;
{
histogram_value histogram;
gcov_type val, count, all;
- int prob;
+ gcov_type prob;
tree call, callee, modify;
struct cgraph_node *direct_call;
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;
if (4 * count <= 3 * all)
return false;
- prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ if (all > 0)
+ prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ else
+ prob = 0;
direct_call = find_func_by_pid ((int)val);
if (direct_call == NULL)
print_generic_stmt (dump_file, stmt, TDF_SLIM);
fprintf (dump_file, " to ");
print_generic_stmt (dump_file, modify, TDF_SLIM);
+ fprintf (dump_file, "hist->count "HOST_WIDEST_INT_PRINT_DEC
+ " hist->all "HOST_WIDEST_INT_PRINT_DEC"\n", count, all);
}
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);
- if (fcode != BUILT_IN_MEMSET && fcode != BUILT_IN_MEMCPY
- && fcode != BUILT_IN_BZERO)
+ if (fcode != BUILT_IN_MEMCPY && fcode != BUILT_IN_MEMPCPY
+ && fcode != BUILT_IN_MEMSET && fcode != BUILT_IN_BZERO)
return false;
switch (fcode)
{
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 ();
}
}
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;
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);
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);
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;
tree value;
tree dest, src;
unsigned int dest_align, src_align;
- int prob;
+ gcov_type prob;
tree tree_val;
if (!call)
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;
return false;
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);
+ if (all > 0)
+ prob = (count * REG_BR_PROB_BASE + all / 2) / all;
+ else
+ prob = 0;
+ 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:
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;
{
tree call = get_call_expr_in (stmt);
tree fndecl;
- tree arglist;
tree blck_size;
tree dest;
enum built_in_function fcode;
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 = TREE_VALUE (arglist);
+ 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)
{
return (value_prof_hooks->value_profile_transformations) ();
}
\f
-