/* 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
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"
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
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. */
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)
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;
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;
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;
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;
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;
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);
{
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;
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;
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:
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 *);
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 (!call)
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
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 ();
}