re PR ipa/58721 (The subroutine perdida is no longer inlined in fatigue.f90)

PR ipa/58721
gcc/
	* 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.
gcc/fortran/
	* 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
gcc/
	* 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.
gcc/fortran/
	* 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-18  Jan Hubicka  <hubicka@ucw.cz>

	PR ipa/58721
gcc/
	* 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.

From-SVN: r208641
This commit is contained in:
Jakub Jelinek 2014-03-18 12:31:04 +01:00
parent e33da4a113
commit ed9c79e1ea
18 changed files with 354 additions and 101 deletions

View File

@ -1,3 +1,42 @@
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

View File

@ -140,7 +140,6 @@ static rtx expand_builtin_frame_address (tree, tree);
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);
@ -6978,7 +6977,8 @@ fold_builtin_constant_p (tree arg)
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;
@ -6990,7 +6990,8 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
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));
@ -6999,8 +7000,8 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
/* 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;
@ -7035,8 +7036,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1)
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);
@ -10852,7 +10853,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
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);
@ -11032,6 +11033,9 @@ fold_builtin_3 (location_t loc, tree fndecl,
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;
}

View File

@ -1,3 +1,26 @@
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

View File

@ -4993,12 +4993,14 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
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,
@ -5095,12 +5097,14 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
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,
@ -5282,7 +5286,8 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
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));
}
@ -5303,7 +5308,8 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
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

View File

@ -4099,7 +4099,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
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);

View File

@ -1196,8 +1196,7 @@ trans_image_index (gfc_se * se, gfc_expr *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. */

View File

@ -230,9 +230,10 @@ gfc_build_st_parameter (enum ioparam_type ptype, tree *types)
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;
@ -246,6 +247,13 @@ gfc_trans_io_runtime_check (tree cond, tree var, int error_code,
/* 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),
@ -268,7 +276,6 @@ gfc_trans_io_runtime_check (tree cond, tree var, int 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);
}
@ -494,8 +501,8 @@ set_parameter_const (stmtblock_t *block, tree var, enum iofield type,
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;
@ -520,18 +527,18 @@ set_parameter_value (stmtblock_t *block, tree var, enum iofield type,
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);
}
@ -960,7 +967,8 @@ gfc_trans_open (gfc_code * code)
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,
@ -1010,7 +1018,7 @@ gfc_trans_open (gfc_code * code)
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);
@ -1063,7 +1071,7 @@ gfc_trans_close (gfc_code * code)
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);
@ -1114,7 +1122,7 @@ build_filepos (tree function, gfc_code * code)
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);
@ -1375,7 +1383,7 @@ gfc_trans_inquire (gfc_code * code)
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);
@ -1422,12 +1430,12 @@ gfc_trans_wait (gfc_code * code)
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,
@ -1718,7 +1726,8 @@ build_dt (tree function, gfc_code * code)
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,
@ -1749,7 +1758,8 @@ build_dt (tree function, gfc_code * code)
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,
@ -1801,7 +1811,8 @@ build_dt (tree function, gfc_code * code)
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);

View File

@ -5107,8 +5107,8 @@ gfc_trans_allocate (gfc_code * code)
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);
}
@ -5501,7 +5501,7 @@ gfc_trans_deallocate (gfc_code *code)
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);
@ -5541,7 +5541,7 @@ gfc_trans_deallocate (gfc_code *code)
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);

View File

@ -501,6 +501,11 @@ gfc_trans_runtime_check (bool error, bool once, tree cond, stmtblock_t * pblock,
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,
@ -519,14 +524,12 @@ gfc_trans_runtime_check (bool error, bool once, tree cond, stmtblock_t * pblock,
}
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));
@ -616,7 +619,8 @@ void
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. */
@ -640,20 +644,31 @@ gfc_allocate_using_malloc (stmtblock_t * block, tree pointer,
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);
@ -750,7 +765,8 @@ gfc_allocate_allocatable (stmtblock_t * block, tree mem, tree size, tree token,
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. */
@ -770,8 +786,8 @@ gfc_allocate_allocatable (stmtblock_t * block, tree mem, tree size, tree token,
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);
}
}
@ -1268,8 +1284,8 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg,
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);
}
}
@ -1327,8 +1343,8 @@ gfc_deallocate_with_status (tree pointer, tree status, tree errmsg,
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);
}
}
@ -2015,15 +2031,20 @@ gfc_finish_wrapped_block (gfc_wrapped_block* block)
/* 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;
}
@ -2032,15 +2053,20 @@ gfc_unlikely (tree 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;
}

View File

@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#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)
@ -580,8 +582,8 @@ void gfc_generate_constructors (void);
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 *);
@ -630,7 +632,6 @@ tree gfc_trans_pointer_assignment (gfc_expr *, gfc_expr *);
/* 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, ...);

View File

@ -1181,6 +1181,20 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
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;
}

View File

@ -2215,7 +2215,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
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);
@ -4566,8 +4566,20 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
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);

View File

@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#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[] = {
@ -865,6 +866,23 @@ expand_ABNORMAL_DISPATCHER (gimple)
{
}
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:

View File

@ -52,3 +52,4 @@ DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW)
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)

View File

@ -2306,7 +2306,10 @@ find_foldable_builtin_expect (basic_block bb)
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);

View File

@ -956,7 +956,8 @@ combine_predictions_for_bb (basic_block bb)
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;
@ -1788,16 +1789,19 @@ guess_outgoing_edge_probabilities (basic_block bb)
combine_predictions_for_insn (BB_END (bb), bb);
}
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))
@ -1822,6 +1826,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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,
@ -1832,7 +1837,12 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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)
@ -1851,14 +1861,34 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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))
{
@ -1870,6 +1900,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
val = gimple_call_arg (def, 0);
if (TREE_CONSTANT (val))
return val;
if (predictor)
*predictor = PRED_BUILTIN_EXPECT;
return gimple_call_arg (def, 1);
}
@ -1888,6 +1920,8 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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;
}
}
@ -1898,10 +1932,13 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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);
@ -1912,7 +1949,7 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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);
@ -1932,17 +1969,22 @@ expr_expected_value_1 (tree type, tree op0, enum tree_code code,
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);
}
@ -1967,14 +2009,16 @@ strip_predict_hints (void)
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)
@ -2008,6 +2052,7 @@ tree_predict_by_opcode (basic_block bb)
enum tree_code cmp;
bitmap visited;
edge_iterator ei;
enum br_predictor predictor;
if (!stmt || gimple_code (stmt) != GIMPLE_COND)
return;
@ -2019,16 +2064,23 @@ tree_predict_by_opcode (basic_block bb)
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.

View File

@ -57,6 +57,11 @@ DEF_PREDICTOR (PRED_UNCONDITIONAL, "unconditional jump", PROB_ALWAYS,
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).
@ -133,3 +138,41 @@ DEF_PREDICTOR (PRED_HOT_LABEL, "hot label", HITRATE (85), 0)
/* 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)

View File

@ -4548,6 +4548,7 @@ extern tree fold_builtin_stxcpy_chk (location_t, tree, tree, tree, tree, tree, b
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 *);