Hi! Here is an updated patch for what Tobias has posted earlier: http://gcc.gnu.org/ml/gcc-patches/2014-03/msg00043.html While that version bootstrapped/regtested fine, most of the Fortran tests ICEd, primarily because the 3 operand __builtin_expect wasn't being removed from the IL and for expansion we only allow it for !optimize or couple of similar cases.
This (combined) patch fixes that, fixes a couple of if (*predictor) to if (predictor),. The biggest change is to introduce IFN_BUILTIN_EXPECT, because as we don't want to allow user code to specify 3+ argument __builtin_expect form, we probably don't want to make the builtin prototype a varargs function, but in that case it means e.g. gimple_builtin_p (stmt, BUILT_IN_EXPECT) will never match the 3 operand __builtin_expect. Also, predict.c would happily predict that &__gthrw___pthread_key_create != 0 is PRED_UNCONDITIONALly true (and also that &__gthrw___pthread_key_create == 0 is PRED_UNCONDITIONALly true), that is just wrong. I wanted to minimize the amount of changes for 4.9, so this patch only uses the internal fn for the 3 operand __builtin_expect, after branching I'd like to use it always and remove handling of non-internal __builtin_expect after gimplification. The advantage could be e.g. that the argument/return value doesn't have to be necessarily long, we could just fold it at gimplification time. The predict.c changes affect inlining in libstdc++-v3/src/c++11/thread.cc somewhat, so it is not inlining one ctor any longer, Jonathan has kindly committed a gnu.ver fix for that yesterday. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2014-03-15 Jakub Jelinek <ja...@redhat.com> 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-15 Tobias Burnus <bur...@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-15 Jan Hubicka <hubi...@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. --- gcc/predict.c.jj 2014-01-03 11:40:46.957378605 +0100 +++ gcc/predict.c 2014-03-14 13:16:15.246017052 +0100 @@ -956,7 +956,8 @@ combine_predictions_for_bb (basic_block 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 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 o 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 o 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 o 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 o 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 o 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 o 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 o 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 o 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. --- gcc/predict.def.jj 2014-01-03 11:40:57.220320576 +0100 +++ gcc/predict.def 2014-03-14 10:12:26.255478253 +0100 @@ -57,6 +57,11 @@ DEF_PREDICTOR (PRED_UNCONDITIONAL, "unco 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 labe /* 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) --- gcc/internal-fn.c.jj 2014-02-06 22:54:01.000000000 +0100 +++ gcc/internal-fn.c 2014-03-14 13:05:28.276790384 +0100 @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. #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: --- gcc/gimplify.c.jj 2014-03-06 13:05:17.000000000 +0100 +++ gcc/gimplify.c 2014-03-14 13:03:22.017522169 +0100 @@ -2215,7 +2215,7 @@ gimplify_call_expr (tree *expr_p, gimple 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, gimp 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); --- gcc/ipa-inline-analysis.c.jj 2014-02-06 11:50:58.000000000 +0100 +++ gcc/ipa-inline-analysis.c 2014-03-14 13:15:54.824136137 +0100 @@ -2306,7 +2306,10 @@ find_foldable_builtin_expect (basic_bloc 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); --- gcc/gimple-fold.c.jj 2014-02-12 17:46:47.000000000 +0100 +++ gcc/gimple-fold.c 2014-03-14 14:02:40.322947112 +0100 @@ -1181,6 +1181,20 @@ gimple_fold_call (gimple_stmt_iterator * 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; } --- gcc/tree.h.jj 2014-02-06 11:52:50.000000000 +0100 +++ gcc/tree.h 2014-03-14 13:54:45.941695181 +0100 @@ -4548,6 +4548,7 @@ extern tree fold_builtin_stxcpy_chk (loc 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 *); --- gcc/builtins.c.jj 2014-03-12 10:13:41.000000000 +0100 +++ gcc/builtins.c 2014-03-14 13:53:50.027019261 +0100 @@ -140,7 +140,6 @@ static rtx expand_builtin_frame_address 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 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 /* 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, tre 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 fnd 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 fnd 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; } --- gcc/internal-fn.def.jj 2014-01-29 12:43:24.000000000 +0100 +++ gcc/internal-fn.def 2014-03-14 13:04:07.333259773 +0100 @@ -52,3 +52,4 @@ DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CO 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) --- gcc/fortran/trans-array.c.jj 2014-03-07 13:57:22.936517443 +0100 +++ gcc/fortran/trans-array.c 2014-03-14 10:12:26.148478839 +0100 @@ -4993,12 +4993,14 @@ gfc_array_init_size (tree descriptor, in 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, in 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_exp 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_exp 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 --- gcc/fortran/trans-expr.c.jj 2014-03-07 13:57:22.917517547 +0100 +++ gcc/fortran/trans-expr.c 2014-03-14 10:12:26.173478725 +0100 @@ -4099,7 +4099,7 @@ gfc_conv_procedure_call (gfc_se * se, gf 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); --- gcc/fortran/trans.h.jj 2014-03-07 13:57:22.970517258 +0100 +++ gcc/fortran/trans.h 2014-03-14 10:12:26.235478369 +0100 @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. #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_e /* 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, ...); --- gcc/fortran/trans.c.jj 2014-03-07 13:57:22.968517269 +0100 +++ gcc/fortran/trans.c 2014-03-14 14:12:04.909731639 +0100 @@ -501,6 +501,11 @@ gfc_trans_runtime_check (bool error, boo 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, boo } 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 * 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 * 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 * 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 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 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_bl /* 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; } --- gcc/fortran/trans-io.c.jj 2014-01-09 21:07:24.238165839 +0100 +++ gcc/fortran/trans-io.c 2014-03-14 10:12:26.212478499 +0100 @@ -230,9 +230,10 @@ gfc_build_st_parameter (enum ioparam_typ 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, t /* 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, t } 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, 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, 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 * 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); --- gcc/fortran/trans-stmt.c.jj 2014-03-07 13:57:22.968517269 +0100 +++ gcc/fortran/trans-stmt.c 2014-03-14 10:12:26.221478449 +0100 @@ -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); --- gcc/fortran/trans-intrinsic.c.jj 2014-03-07 13:57:22.983517187 +0100 +++ gcc/fortran/trans-intrinsic.c 2014-03-14 10:12:26.183478666 +0100 @@ -1196,8 +1196,7 @@ trans_image_index (gfc_se * se, gfc_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. */ Jakub