+2014-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR ipa/58721
+ * internal-fn.c: Include diagnostic-core.h.
+ (expand_BUILTIN_EXPECT): New function.
+ * gimplify.c (gimplify_call_expr): Use false instead of FALSE.
+ (gimplify_modify_expr): Gimplify 3 argument __builtin_expect into
+ IFN_BUILTIN_EXPECT call instead of __builtin_expect builtin call.
+ * ipa-inline-analysis.c (find_foldable_builtin_expect): Handle
+ IFN_BUILTIN_EXPECT.
+ * predict.c (expr_expected_value_1): Handle IFN_BUILTIN_EXPECT.
+ Revert 3 argument __builtin_expect code.
+ (strip_predict_hints): Handle IFN_BUILTIN_EXPECT.
+ * gimple-fold.c (gimple_fold_call): Likewise.
+ * tree.h (fold_builtin_expect): New prototype.
+ * builtins.c (build_builtin_expect_predicate): Add predictor
+ argument, if non-NULL, create 3 argument __builtin_expect.
+ (fold_builtin_expect): No longer static. Add ARG2 argument,
+ pass it through to build_builtin_expect_predicate.
+ (fold_builtin_2): Adjust caller.
+ (fold_builtin_3): Handle BUILT_IN_EXPECT.
+ * internal-fn.def (BUILTIN_EXPECT): New.
+
+2014-03-18 Tobias Burnus <burnus@net-b.de>
+
+ PR ipa/58721
+ * predict.def (PRED_FORTRAN_OVERFLOW, PRED_FORTRAN_FAIL_ALLOC,
+ PRED_FORTRAN_FAIL_IO, PRED_FORTRAN_WARN_ONCE, PRED_FORTRAN_SIZE_ZERO,
+ PRED_FORTRAN_INVALID_BOUND, PRED_FORTRAN_ABSENT_DUMMY): Add.
+
+2014-03-18 Jan Hubicka <hubicka@ucw.cz>
+
+ PR ipa/58721
+ * predict.c (combine_predictions_for_bb): Fix up formatting.
+ (expr_expected_value_1, expr_expected_value): Add predictor argument,
+ fill what it points to if non-NULL.
+ (tree_predict_by_opcode): Adjust caller, use the predictor.
+ * predict.def (PRED_COMPARE_AND_SWAP): Add.
+
2014-03-18 Eric Botcazou <ebotcazou@adacore.com>
* config/sparc/sparc.c (sparc_do_work_around_errata): Speed up and use
static tree stabilize_va_list_loc (location_t, tree, int);
static rtx expand_builtin_expect (tree, rtx);
static tree fold_builtin_constant_p (tree);
-static tree fold_builtin_expect (location_t, tree, tree);
static tree fold_builtin_classify_type (tree);
static tree fold_builtin_strlen (location_t, tree, tree);
static tree fold_builtin_inf (location_t, tree, int);
return it as a truthvalue. */
static tree
-build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
+build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
+ tree predictor)
{
tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
pred = fold_convert_loc (loc, pred_type, pred);
expected = fold_convert_loc (loc, expected_type, expected);
- call_expr = build_call_expr_loc (loc, fn, 2, pred, expected);
+ call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
+ predictor);
return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
build_int_cst (ret_type, 0));
/* Fold a call to builtin_expect with arguments ARG0 and ARG1. Return
NULL_TREE if no simplification is possible. */
-static tree
-fold_builtin_expect (location_t loc, tree arg0, tree arg1)
+tree
+fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
{
tree inner, fndecl, inner_arg0;
enum tree_code code;
tree op0 = TREE_OPERAND (inner, 0);
tree op1 = TREE_OPERAND (inner, 1);
- op0 = build_builtin_expect_predicate (loc, op0, arg1);
- op1 = build_builtin_expect_predicate (loc, op1, arg1);
+ op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2);
+ op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2);
inner = build2 (code, TREE_TYPE (inner), op0, op1);
return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
return fold_builtin_strpbrk (loc, arg0, arg1, type);
case BUILT_IN_EXPECT:
- return fold_builtin_expect (loc, arg0, arg1);
+ return fold_builtin_expect (loc, arg0, arg1, NULL_TREE);
CASE_FLT_FN (BUILT_IN_POW):
return fold_builtin_pow (loc, fndecl, arg0, arg1, type);
return fold_builtin_fprintf (loc, fndecl, arg0, arg2, NULL_TREE,
ignore, fcode);
+ case BUILT_IN_EXPECT:
+ return fold_builtin_expect (loc, arg0, arg1, arg2);
+
default:
break;
}
+2014-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR ipa/58721
+ * trans.c (gfc_unlikely, gfc_likely): Don't add __builtin_expect
+ if !optimize.
+
+2014-03-18 Tobias Burnus <burnus@net-b.de>
+
+ PR ipa/58721
+ * trans.h (gfc_unlikely, gfc_likely): Add predictor as argument.
+ (gfc_trans_io_runtime_check): Remove.
+ * trans-io.c (gfc_trans_io_runtime_check): Make static; add has_iostat
+ as argument, add predictor to block.
+ (set_parameter_value, gfc_trans_open, gfc_trans_close, build_filepos,
+ gfc_trans_inquire, gfc_trans_wait, build_dt): Update calls.
+ * trans.c (gfc_unlikely, gfc_likely): Add predictor as argument.
+ (gfc_trans_runtime_check, gfc_allocate_using_malloc,
+ gfc_allocate_allocatable, gfc_deallocate_with_status): Set explicitly
+ branch predictor.
+ * trans-expr.c (gfc_conv_procedure_call): Ditto.
+ * trans-stmt.c (gfc_trans_allocate): Ditto.
+ * trans-array.c (gfc_array_init_size, gfc_array_allocate): Ditto.
+
2014-03-15 Janus Weil <janus@gcc.gnu.org>
PR fortran/55207
TYPE_MAX_VALUE (gfc_array_index_type)),
size);
cond = gfc_unlikely (fold_build2_loc (input_location, LT_EXPR,
- boolean_type_node, tmp, stride));
+ boolean_type_node, tmp, stride),
+ PRED_FORTRAN_OVERFLOW);
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
integer_one_node, integer_zero_node);
cond = gfc_unlikely (fold_build2_loc (input_location, EQ_EXPR,
boolean_type_node, size,
- gfc_index_zero_node));
+ gfc_index_zero_node),
+ PRED_FORTRAN_SIZE_ZERO);
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
integer_zero_node, tmp);
tmp = fold_build2_loc (input_location, PLUS_EXPR, integer_type_node,
size_type_node,
TYPE_MAX_VALUE (size_type_node), element_size);
cond = gfc_unlikely (fold_build2_loc (input_location, LT_EXPR,
- boolean_type_node, tmp, stride));
+ boolean_type_node, tmp, stride),
+ PRED_FORTRAN_OVERFLOW);
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
integer_one_node, integer_zero_node);
cond = gfc_unlikely (fold_build2_loc (input_location, EQ_EXPR,
boolean_type_node, element_size,
- build_int_cst (size_type_node, 0)));
+ build_int_cst (size_type_node, 0)),
+ PRED_FORTRAN_SIZE_ZERO);
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
integer_zero_node, tmp);
tmp = fold_build2_loc (input_location, PLUS_EXPR, integer_type_node,
if (dimension)
{
cond = gfc_unlikely (fold_build2_loc (input_location, NE_EXPR,
- boolean_type_node, var_overflow, integer_zero_node));
+ boolean_type_node, var_overflow, integer_zero_node),
+ PRED_FORTRAN_OVERFLOW);
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
error, gfc_finish_block (&elseblock));
}
build_int_cst (TREE_TYPE (status), 0));
gfc_add_expr_to_block (&se->pre,
fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_likely (cond), set_descriptor,
+ gfc_likely (cond, PRED_FORTRAN_FAIL_ALLOC),
+ set_descriptor,
build_empty_stmt (input_location)));
}
else
parmse.expr
= fold_build3_loc (input_location, COND_EXPR,
TREE_TYPE (parmse.expr),
- gfc_unlikely (tmp),
+ gfc_unlikely (tmp, PRED_FORTRAN_ABSENT_DUMMY),
fold_convert (TREE_TYPE (parmse.expr),
null_pointer_node),
parmse.expr);
boolean_type_node, invalid_bound, cond);
}
- invalid_bound = gfc_unlikely (invalid_bound);
-
+ invalid_bound = gfc_unlikely (invalid_bound, PRED_FORTRAN_INVALID_BOUND);
/* See Fortran 2008, C.10 for the following algorithm. */
Therefore, the code to set these flags must be generated before
this function is used. */
-void
-gfc_trans_io_runtime_check (tree cond, tree var, int error_code,
- const char * msgid, stmtblock_t * pblock)
+static void
+gfc_trans_io_runtime_check (bool has_iostat, tree cond, tree var,
+ int error_code, const char * msgid,
+ stmtblock_t * pblock)
{
stmtblock_t block;
tree body;
/* The code to generate the error. */
gfc_start_block (&block);
+ if (has_iostat)
+ gfc_add_expr_to_block (&block, build_predict_expr (PRED_FORTRAN_FAIL_IO,
+ NOT_TAKEN));
+ else
+ gfc_add_expr_to_block (&block, build_predict_expr (PRED_NORETURN,
+ NOT_TAKEN));
+
arg1 = gfc_build_addr_expr (NULL_TREE, var);
arg2 = build_int_cst (integer_type_node, error_code),
}
else
{
- cond = gfc_unlikely (cond);
tmp = build3_v (COND_EXPR, cond, body, build_empty_stmt (input_location));
gfc_add_expr_to_block (pblock, tmp);
}
st_parameter_XXX structure. This is a pass by value. */
static unsigned int
-set_parameter_value (stmtblock_t *block, tree var, enum iofield type,
- gfc_expr *e)
+set_parameter_value (stmtblock_t *block, bool has_iostat, tree var,
+ enum iofield type, gfc_expr *e)
{
gfc_se se;
tree tmp;
cond = fold_build2_loc (input_location, LT_EXPR, boolean_type_node,
se.expr,
fold_convert (TREE_TYPE (se.expr), val));
- gfc_trans_io_runtime_check (cond, var, LIBERROR_BAD_UNIT,
- "Unit number in I/O statement too small",
- &se.pre);
+ gfc_trans_io_runtime_check (has_iostat, cond, var, LIBERROR_BAD_UNIT,
+ "Unit number in I/O statement too small",
+ &se.pre);
/* UNIT numbers should be less than the max. */
val = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, 4);
cond = fold_build2_loc (input_location, GT_EXPR, boolean_type_node,
se.expr,
fold_convert (TREE_TYPE (se.expr), val));
- gfc_trans_io_runtime_check (cond, var, LIBERROR_BAD_UNIT,
- "Unit number in I/O statement too large",
- &se.pre);
+ gfc_trans_io_runtime_check (has_iostat, cond, var, LIBERROR_BAD_UNIT,
+ "Unit number in I/O statement too large",
+ &se.pre);
}
mask |= set_string (&block, &post_block, var, IOPARM_open_form, p->form);
if (p->recl)
- mask |= set_parameter_value (&block, var, IOPARM_open_recl_in, p->recl);
+ mask |= set_parameter_value (&block, p->iostat, var, IOPARM_open_recl_in,
+ p->recl);
if (p->blank)
mask |= set_string (&block, &post_block, var, IOPARM_open_blank,
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (p->unit)
- set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
+ set_parameter_value (&block, p->iostat, var, IOPARM_common_unit, p->unit);
else
set_parameter_const (&block, var, IOPARM_common_unit, 0);
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (p->unit)
- set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
+ set_parameter_value (&block, p->iostat, var, IOPARM_common_unit, p->unit);
else
set_parameter_const (&block, var, IOPARM_common_unit, 0);
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (p->unit)
- set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
+ set_parameter_value (&block, p->iostat, var, IOPARM_common_unit, p->unit);
else
set_parameter_const (&block, var, IOPARM_common_unit, 0);
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (p->unit)
- set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
+ set_parameter_value (&block, p->iostat, var, IOPARM_common_unit, p->unit);
else
set_parameter_const (&block, var, IOPARM_common_unit, 0);
mask |= IOPARM_common_err;
if (p->id)
- mask |= set_parameter_value (&block, var, IOPARM_wait_id, p->id);
+ mask |= set_parameter_value (&block, p->iostat, var, IOPARM_wait_id, p->id);
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (p->unit)
- set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
+ set_parameter_value (&block, p->iostat, var, IOPARM_common_unit, p->unit);
tmp = gfc_build_addr_expr (NULL_TREE, var);
tmp = build_call_expr_loc (input_location,
IOPARM_dt_id, dt->id);
if (dt->pos)
- mask |= set_parameter_value (&block, var, IOPARM_dt_pos, dt->pos);
+ mask |= set_parameter_value (&block, dt->iostat, var, IOPARM_dt_pos,
+ dt->pos);
if (dt->asynchronous)
mask |= set_string (&block, &post_block, var, IOPARM_dt_asynchronous,
dt->sign);
if (dt->rec)
- mask |= set_parameter_value (&block, var, IOPARM_dt_rec, dt->rec);
+ mask |= set_parameter_value (&block, dt->iostat, var, IOPARM_dt_rec,
+ dt->rec);
if (dt->advance)
mask |= set_string (&block, &post_block, var, IOPARM_dt_advance,
set_parameter_const (&block, var, IOPARM_common_flags, mask);
if (dt->io_unit && dt->io_unit->ts.type == BT_INTEGER)
- set_parameter_value (&block, var, IOPARM_common_unit, dt->io_unit);
+ set_parameter_value (&block, dt->iostat, var, IOPARM_common_unit,
+ dt->io_unit);
}
else
set_parameter_const (&block, var, IOPARM_common_flags, mask);
boolean_type_node, stat,
build_int_cst (TREE_TYPE (stat), 0));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (parm), tmp,
- build_empty_stmt (input_location));
+ gfc_unlikely (parm, PRED_FORTRAN_FAIL_ALLOC),
+ tmp, build_empty_stmt (input_location));
gfc_add_expr_to_block (&block, tmp);
}
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, stat,
build_int_cst (TREE_TYPE (stat), 0));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (cond),
+ gfc_unlikely (cond, PRED_FORTRAN_FAIL_ALLOC),
build1_v (GOTO_EXPR, label_errmsg),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&se.pre, tmp);
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, stat,
build_int_cst (TREE_TYPE (stat), 0));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (cond), tmp,
+ gfc_unlikely (cond, PRED_FORTRAN_FAIL_ALLOC), tmp,
build_empty_stmt (input_location));
gfc_add_expr_to_block (&block, tmp);
gfc_start_block (&block);
+ /* For error, runtime_error_at already implies PRED_NORETURN. */
+ if (!error && once)
+ gfc_add_expr_to_block (&block, build_predict_expr (PRED_FORTRAN_WARN_ONCE,
+ NOT_TAKEN));
+
/* The code to generate the error. */
va_start (ap, msgid);
gfc_add_expr_to_block (&block,
}
else
{
- /* Tell the compiler that this isn't likely. */
if (once)
cond = fold_build2_loc (where->lb->location, TRUTH_AND_EXPR,
long_integer_type_node, tmpvar, cond);
else
cond = fold_convert (long_integer_type_node, cond);
- cond = gfc_unlikely (cond);
tmp = fold_build3_loc (where->lb->location, COND_EXPR, void_type_node,
cond, body,
build_empty_stmt (where->lb->location));
gfc_allocate_using_malloc (stmtblock_t * block, tree pointer,
tree size, tree status)
{
- tree tmp, on_error, error_cond;
+ tree tmp, error_cond;
+ stmtblock_t on_error;
tree status_type = status ? TREE_TYPE (status) : NULL_TREE;
/* Evaluate size only once, and make sure it has the right type. */
build_int_cst (size_type_node, 1)))));
/* What to do in case of error. */
+ gfc_start_block (&on_error);
if (status != NULL_TREE)
- on_error = fold_build2_loc (input_location, MODIFY_EXPR, status_type,
- status, build_int_cst (status_type, LIBERROR_ALLOCATION));
+ {
+ gfc_add_expr_to_block (&on_error,
+ build_predict_expr (PRED_FORTRAN_FAIL_ALLOC,
+ NOT_TAKEN));
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, status,
+ build_int_cst (status_type, LIBERROR_ALLOCATION));
+ gfc_add_expr_to_block (&on_error, tmp);
+ }
else
- on_error = build_call_expr_loc (input_location, gfor_fndecl_os_error, 1,
+ {
+ /* Here, os_error already implies PRED_NORETURN. */
+ tmp = build_call_expr_loc (input_location, gfor_fndecl_os_error, 1,
gfc_build_addr_expr (pchar_type_node,
gfc_build_localized_cstring_const
- ("Allocation would exceed memory limit")));
+ ("Allocation would exceed memory limit")));
+ gfc_add_expr_to_block (&on_error, tmp);
+ }
error_cond = fold_build2_loc (input_location, EQ_EXPR,
boolean_type_node, pointer,
build_int_cst (prvoid_type_node, 0));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (error_cond), on_error,
+ error_cond, gfc_finish_block (&on_error),
build_empty_stmt (input_location));
gfc_add_expr_to_block (block, tmp);
null_mem = gfc_unlikely (fold_build2_loc (input_location, NE_EXPR,
boolean_type_node, mem,
- build_int_cst (type, 0)));
+ build_int_cst (type, 0)),
+ PRED_FORTRAN_FAIL_ALLOC);
/* If mem is NULL, we call gfc_allocate_using_malloc or
gfc_allocate_using_lib. */
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
status, build_zero_cst (TREE_TYPE (status)));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (cond), tmp,
- build_empty_stmt (input_location));
+ gfc_unlikely (cond, PRED_FORTRAN_FAIL_ALLOC),
+ tmp, build_empty_stmt (input_location));
gfc_add_expr_to_block (&alloc_block, tmp);
}
}
status_type, status),
build_int_cst (status_type, 0));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (cond2), tmp,
- build_empty_stmt (input_location));
+ gfc_unlikely (cond2, PRED_FORTRAN_FAIL_ALLOC),
+ tmp, build_empty_stmt (input_location));
gfc_add_expr_to_block (&non_null, tmp);
}
}
cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
stat, build_zero_cst (TREE_TYPE (stat)));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- gfc_unlikely (cond2), tmp,
- build_empty_stmt (input_location));
+ gfc_unlikely (cond2, PRED_FORTRAN_FAIL_ALLOC),
+ tmp, build_empty_stmt (input_location));
gfc_add_expr_to_block (&non_null, tmp);
}
}
/* Helper function for marking a boolean expression tree as unlikely. */
tree
-gfc_unlikely (tree cond)
+gfc_unlikely (tree cond, enum br_predictor predictor)
{
tree tmp;
- cond = fold_convert (long_integer_type_node, cond);
- tmp = build_zero_cst (long_integer_type_node);
- cond = build_call_expr_loc (input_location,
- builtin_decl_explicit (BUILT_IN_EXPECT),
- 2, cond, tmp);
+ if (optimize)
+ {
+ cond = fold_convert (long_integer_type_node, cond);
+ tmp = build_zero_cst (long_integer_type_node);
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_EXPECT),
+ 3, cond, tmp,
+ build_int_cst (integer_type_node,
+ predictor));
+ }
cond = fold_convert (boolean_type_node, cond);
return cond;
}
/* Helper function for marking a boolean expression tree as likely. */
tree
-gfc_likely (tree cond)
+gfc_likely (tree cond, enum br_predictor predictor)
{
tree tmp;
- cond = fold_convert (long_integer_type_node, cond);
- tmp = build_one_cst (long_integer_type_node);
- cond = build_call_expr_loc (input_location,
- builtin_decl_explicit (BUILT_IN_EXPECT),
- 2, cond, tmp);
+ if (optimize)
+ {
+ cond = fold_convert (long_integer_type_node, cond);
+ tmp = build_one_cst (long_integer_type_node);
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_EXPECT),
+ 3, cond, tmp,
+ build_int_cst (integer_type_node,
+ predictor));
+ }
cond = fold_convert (boolean_type_node, cond);
return cond;
}
#ifndef GFC_TRANS_H
#define GFC_TRANS_H
+#include "predict.h" /* For enum br_predictor and PRED_*. */
+
/* Mangled symbols take the form __module__name. */
#define GFC_MAX_MANGLED_SYMBOL_LEN (GFC_MAX_SYMBOL_LEN*2+4)
bool get_array_ctor_strlen (stmtblock_t *, gfc_constructor_base, tree *);
/* Mark a condition as likely or unlikely. */
-tree gfc_likely (tree);
-tree gfc_unlikely (tree);
+tree gfc_likely (tree, enum br_predictor);
+tree gfc_unlikely (tree, enum br_predictor);
/* Return the string length of a deferred character length component. */
bool gfc_deferred_strlen (gfc_component *, tree *);
/* Initialize function decls for library functions. */
void gfc_build_intrinsic_lib_fndecls (void);
/* Create function decls for IO library functions. */
-void gfc_trans_io_runtime_check (tree, tree, int, const char *, stmtblock_t *);
void gfc_build_io_library_fndecls (void);
/* Build a function decl for a library function. */
tree gfc_build_library_function_decl (tree, tree, int, ...);
else if (gimple_call_builtin_p (stmt, BUILT_IN_MD))
changed |= targetm.gimple_fold_builtin (gsi);
}
+ else if (gimple_call_internal_p (stmt)
+ && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT)
+ {
+ tree result = fold_builtin_expect (gimple_location (stmt),
+ gimple_call_arg (stmt, 0),
+ gimple_call_arg (stmt, 1),
+ gimple_call_arg (stmt, 2));
+ if (result)
+ {
+ if (!update_call_from_tree (gsi, result))
+ gimplify_and_update_call_from_tree (gsi, result);
+ changed = true;
+ }
+ }
return changed;
}
enum gimplify_status ret;
int i, nargs;
gimple call;
- bool builtin_va_start_p = FALSE;
+ bool builtin_va_start_p = false;
location_t loc = EXPR_LOCATION (*expr_p);
gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
- assign = gimple_build_call_from_tree (*from_p);
- gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+ tree fndecl = get_callee_fndecl (*from_p);
+ if (fndecl
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+ && call_expr_nargs (*from_p) == 3)
+ assign = gimple_build_call_internal (IFN_BUILTIN_EXPECT, 3,
+ CALL_EXPR_ARG (*from_p, 0),
+ CALL_EXPR_ARG (*from_p, 1),
+ CALL_EXPR_ARG (*from_p, 2));
+ else
+ {
+ assign = gimple_build_call_from_tree (*from_p);
+ gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+ }
notice_special_calls (assign);
if (!gimple_call_noreturn_p (assign))
gimple_call_set_lhs (assign, *to_p);
#include "predict.h"
#include "stringpool.h"
#include "tree-ssanames.h"
+#include "diagnostic-core.h"
/* The names of each internal function, indexed by function number. */
const char *const internal_fn_name_array[] = {
{
}
+static void
+expand_BUILTIN_EXPECT (gimple stmt)
+{
+ /* When guessing was done, the hints should be already stripped away. */
+ gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
+
+ rtx target;
+ tree lhs = gimple_call_lhs (stmt);
+ if (lhs)
+ target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ else
+ target = const0_rtx;
+ rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
+ if (lhs && val != target)
+ emit_move_insn (target, val);
+}
+
/* Routines to expand each internal function, indexed by function number.
Each routine has the prototype:
DEF_INTERNAL_FN (UBSAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
DEF_INTERNAL_FN (UBSAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN)
+DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple stmt = gsi_stmt (bsi);
- if (gimple_call_builtin_p (stmt, BUILT_IN_EXPECT))
+ if (gimple_call_builtin_p (stmt, BUILT_IN_EXPECT)
+ || (is_gimple_call (stmt)
+ && gimple_call_internal_p (stmt)
+ && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT))
{
tree var = gimple_call_lhs (stmt);
tree arg = gimple_call_arg (stmt, 0);
struct edge_prediction *pred2;
int prob = probability;
- for (pred2 = (struct edge_prediction *) *preds; pred2; pred2 = pred2->ep_next)
+ for (pred2 = (struct edge_prediction *) *preds;
+ pred2; pred2 = pred2->ep_next)
if (pred2 != pred && pred2->ep_predictor == pred->ep_predictor)
{
int probability2 = pred->ep_probability;
combine_predictions_for_insn (BB_END (bb), bb);
}
\f
-static tree expr_expected_value (tree, bitmap);
+static tree expr_expected_value (tree, bitmap, enum br_predictor *predictor);
/* Helper function for expr_expected_value. */
static tree
expr_expected_value_1 (tree type, tree op0, enum tree_code code,
- tree op1, bitmap visited)
+ tree op1, bitmap visited, enum br_predictor *predictor)
{
gimple def;
+ if (predictor)
+ *predictor = PRED_UNCONDITIONAL;
+
if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS)
{
if (TREE_CONSTANT (op0))
for (i = 0; i < n; i++)
{
tree arg = PHI_ARG_DEF (def, i);
+ enum br_predictor predictor2;
/* If this PHI has itself as an argument, we cannot
determine the string length of this argument. However,
if (arg == PHI_RESULT (def))
continue;
- new_val = expr_expected_value (arg, visited);
+ new_val = expr_expected_value (arg, visited, &predictor2);
+
+ /* It is difficult to combine value predictors. Simply assume
+ that later predictor is weaker and take its prediction. */
+ if (predictor && *predictor < predictor2)
+ *predictor = predictor2;
if (!new_val)
return NULL;
if (!val)
gimple_assign_rhs1 (def),
gimple_assign_rhs_code (def),
gimple_assign_rhs2 (def),
- visited);
+ visited, predictor);
}
if (is_gimple_call (def))
{
tree decl = gimple_call_fndecl (def);
if (!decl)
- return NULL;
+ {
+ if (gimple_call_internal_p (def)
+ && gimple_call_internal_fn (def) == IFN_BUILTIN_EXPECT)
+ {
+ gcc_assert (gimple_call_num_args (def) == 3);
+ tree val = gimple_call_arg (def, 0);
+ if (TREE_CONSTANT (val))
+ return val;
+ if (predictor)
+ {
+ *predictor = PRED_BUILTIN_EXPECT;
+ tree val2 = gimple_call_arg (def, 2);
+ gcc_assert (TREE_CODE (val2) == INTEGER_CST
+ && tree_fits_uhwi_p (val2)
+ && tree_to_uhwi (val2) < END_PREDICTORS);
+ *predictor = (enum br_predictor) tree_to_uhwi (val2);
+ }
+ return gimple_call_arg (def, 1);
+ }
+ return NULL;
+ }
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (decl))
{
val = gimple_call_arg (def, 0);
if (TREE_CONSTANT (val))
return val;
+ if (predictor)
+ *predictor = PRED_BUILTIN_EXPECT;
return gimple_call_arg (def, 1);
}
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
/* Assume that any given atomic operation has low contention,
and thus the compare-and-swap operation succeeds. */
+ if (predictor)
+ *predictor = PRED_COMPARE_AND_SWAP;
return boolean_true_node;
}
}
if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS)
{
tree res;
- op0 = expr_expected_value (op0, visited);
+ enum br_predictor predictor2;
+ op0 = expr_expected_value (op0, visited, predictor);
if (!op0)
return NULL;
- op1 = expr_expected_value (op1, visited);
+ op1 = expr_expected_value (op1, visited, &predictor2);
+ if (predictor && *predictor < predictor2)
+ *predictor = predictor2;
if (!op1)
return NULL;
res = fold_build2 (code, type, op0, op1);
if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
{
tree res;
- op0 = expr_expected_value (op0, visited);
+ op0 = expr_expected_value (op0, visited, predictor);
if (!op0)
return NULL;
res = fold_build1 (code, type, op0);
implementation. */
static tree
-expr_expected_value (tree expr, bitmap visited)
+expr_expected_value (tree expr, bitmap visited,
+ enum br_predictor *predictor)
{
enum tree_code code;
tree op0, op1;
if (TREE_CONSTANT (expr))
- return expr;
+ {
+ if (predictor)
+ *predictor = PRED_UNCONDITIONAL;
+ return expr;
+ }
extract_ops_from_tree (expr, &code, &op0, &op1);
return expr_expected_value_1 (TREE_TYPE (expr),
- op0, code, op1, visited);
+ op0, code, op1, visited, predictor);
}
\f
gsi_remove (&bi, true);
continue;
}
- else if (gimple_code (stmt) == GIMPLE_CALL)
+ else if (is_gimple_call (stmt))
{
tree fndecl = gimple_call_fndecl (stmt);
- if (fndecl
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
- && gimple_call_num_args (stmt) == 2)
+ if ((fndecl
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+ && gimple_call_num_args (stmt) == 2)
+ || (gimple_call_internal_p (stmt)
+ && gimple_call_internal_fn (stmt) == IFN_BUILTIN_EXPECT))
{
var = gimple_call_lhs (stmt);
if (var)
enum tree_code cmp;
bitmap visited;
edge_iterator ei;
+ enum br_predictor predictor;
if (!stmt || gimple_code (stmt) != GIMPLE_COND)
return;
cmp = gimple_cond_code (stmt);
type = TREE_TYPE (op0);
visited = BITMAP_ALLOC (NULL);
- val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, visited);
+ val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, visited,
+ &predictor);
BITMAP_FREE (visited);
- if (val)
+ if (val && TREE_CODE (val) == INTEGER_CST)
{
- int percent = PARAM_VALUE (BUILTIN_EXPECT_PROBABILITY);
+ if (predictor == PRED_BUILTIN_EXPECT)
+ {
+ int percent = PARAM_VALUE (BUILTIN_EXPECT_PROBABILITY);
- gcc_assert (percent >= 0 && percent <= 100);
- if (integer_zerop (val))
- percent = 100 - percent;
- predict_edge (then_edge, PRED_BUILTIN_EXPECT, HITRATE (percent));
+ gcc_assert (percent >= 0 && percent <= 100);
+ if (integer_zerop (val))
+ percent = 100 - percent;
+ predict_edge (then_edge, PRED_BUILTIN_EXPECT, HITRATE (percent));
+ }
+ else
+ predict_edge (then_edge, predictor,
+ integer_zerop (val) ? NOT_TAKEN : TAKEN);
}
/* Try "pointer heuristic."
A comparison ptr == 0 is predicted as false.
DEF_PREDICTOR (PRED_LOOP_ITERATIONS, "loop iterations", PROB_ALWAYS,
PRED_FLAG_FIRST_MATCH)
+/* Assume that any given atomic operation has low contention,
+ and thus the compare-and-swap operation succeeds. */
+DEF_PREDICTOR (PRED_COMPARE_AND_SWAP, "compare and swap", PROB_VERY_LIKELY,
+ PRED_FLAG_FIRST_MATCH)
+
/* Hints dropped by user via __builtin_expect feature. Note: the
probability of PROB_VERY_LIKELY is now overwritten by param
builtin_expect_probability with a default value of HITRATE(90).
/* Branches to cold labels are extremely unlikely. */
DEF_PREDICTOR (PRED_COLD_LABEL, "cold label", PROB_VERY_LIKELY,
PRED_FLAG_FIRST_MATCH)
+
+
+/* The following predictors are used in Fortran. */
+
+/* Branch leading to an integer overflow are extremely unlikely. */
+DEF_PREDICTOR (PRED_FORTRAN_OVERFLOW, "overflow", PROB_ALWAYS,
+ PRED_FLAG_FIRST_MATCH)
+
+/* Branch leading to a failure status are unlikely. This can occur for out
+ of memory or when trying to allocate an already allocated allocated or
+ deallocating an already deallocated allocatable. This predictor only
+ occurs when the user explicitly asked for a return status. By default,
+ the code aborts, which is handled via PRED_NORETURN. */
+DEF_PREDICTOR (PRED_FORTRAN_FAIL_ALLOC, "fail alloc", PROB_VERY_LIKELY, 0)
+
+/* Branch leading to an I/O failure status are unlikely. This predictor is
+ used for I/O failures such as for invalid unit numbers. This predictor
+ only occurs when the user explicitly asked for a return status. By default,
+ the code aborts, which is handled via PRED_NORETURN. */
+DEF_PREDICTOR (PRED_FORTRAN_FAIL_IO, "fail alloc", HITRATE(85), 0)
+
+/* Branch leading to a run-time warning message which is printed only once
+ are unlikely. The print-warning branch itself can be likely or unlikely. */
+DEF_PREDICTOR (PRED_FORTRAN_WARN_ONCE, "warn once", HITRATE (75), 0)
+
+/* Branch belonging to a zero-sized array. */
+DEF_PREDICTOR (PRED_FORTRAN_SIZE_ZERO, "zero-sized array", HITRATE(70), 0)
+
+/* Branch belonging to an invalid bound index, in a context where it is
+ standard conform and well defined but rather pointless and, hence, rather
+ unlikely to occur. */
+DEF_PREDICTOR (PRED_FORTRAN_INVALID_BOUND, "zero-sized array", HITRATE(90), 0)
+
+/* Branch belonging to the handling of absent optional arguments. This
+ predictor is used when an optional dummy argument, associated with an
+ absent argument, is passed on as actual argument to another procedure,
+ which in turn has an optional argument. */
+DEF_PREDICTOR (PRED_FORTRAN_ABSENT_DUMMY, "absent dummy", HITRATE(60), 0)
enum built_in_function);
extern tree fold_builtin_stxncpy_chk (location_t, tree, tree, tree, tree, tree, bool,
enum built_in_function);
+extern tree fold_builtin_expect (location_t, tree, tree, tree);
extern bool fold_builtin_next_arg (tree, bool);
extern enum built_in_function builtin_mathfn_code (const_tree);
extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);