Hi, while analyzing Firefox I noticed that it uses builtin_expect quite extensively and this sometimes causes ipa-predicates to be computed very conservatively. There are more possible improvements, but I will leave it for stage1. This handles the common case where builtin_expect is applied to parameter.
Bootstrapped/regtested x86_64-linux, will commit it later for tester to catch up. Honza * ipa-fnsummary.c (builtin_expect_call_p, strip_copies): New function. (unmodified_parm, unmodified_parm_or_parm_agg_item, will_be_nonconstant_expr_predicate): Use it. Index: ipa-fnsummary.c =================================================================== --- ipa-fnsummary.c (revision 267610) +++ ipa-fnsummary.c (working copy) @@ -936,6 +936,57 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUS return true; } +/* Return ture if STMT is builtin_expect on one of its variants. */ + +static bool +builtin_expect_call_p (gimple *stmt) +{ + return ((gimple_call_builtin_p (stmt, BUILT_IN_EXPECT) + || gimple_call_builtin_p (stmt, BUILT_IN_EXPECT_WITH_PROBABILITY) + || gimple_call_internal_p (stmt, IFN_BUILTIN_EXPECT)) + && gimple_call_num_args (stmt)); +} + +/* Walk to the original assignment to OP skipping wrapping noop casts, + builtin expectes etc. */ + +static tree +strip_copies (tree op, gimple **stmt = NULL) +{ + STRIP_NOPS (op); + /* TODO: We should have some common way to tell if function returns its + argument. */ + if (TREE_CODE (op) == CALL_EXPR) + { + tree fndecl = get_callee_fndecl (op); + if (!fndecl) + return op; + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT + || DECL_FUNCTION_CODE (fndecl) + == BUILT_IN_EXPECT_WITH_PROBABILITY)) + return strip_copies (CALL_EXPR_ARG (op, 0), stmt); + return op; + } + if (TREE_CODE (op) == SSA_NAME + && builtin_expect_call_p (SSA_NAME_DEF_STMT (op))) + { + if (stmt) + *stmt = SSA_NAME_DEF_STMT (op); + return strip_copies (gimple_call_arg (SSA_NAME_DEF_STMT (op), 0), stmt); + } + if (TREE_CODE (op) == SSA_NAME + && !SSA_NAME_IS_DEFAULT_DEF (op) + && gimple_assign_single_p (SSA_NAME_DEF_STMT (op))) + { + if (stmt) + *stmt = SSA_NAME_DEF_STMT (op); + return strip_copies (gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)), + stmt); + } + return op; +} + /* If OP refers to value of function parameter, return the corresponding parameter. If non-NULL, the size of the memory load (or the SSA_NAME of the PARM_DECL) will be stored to *SIZE_P in that case too. */ @@ -979,16 +1030,10 @@ unmodified_parm_1 (gimple *stmt, tree op static tree unmodified_parm (gimple *stmt, tree op, HOST_WIDE_INT *size_p) { + op = strip_copies (op, &stmt); tree res = unmodified_parm_1 (stmt, op, size_p); if (res) return res; - - if (TREE_CODE (op) == SSA_NAME - && !SSA_NAME_IS_DEFAULT_DEF (op) - && gimple_assign_single_p (SSA_NAME_DEF_STMT (op))) - return unmodified_parm (SSA_NAME_DEF_STMT (op), - gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)), - size_p); return NULL_TREE; } @@ -1005,6 +1050,7 @@ unmodified_parm_or_parm_agg_item (struct HOST_WIDE_INT *size_p, struct agg_position_info *aggpos) { + op = strip_copies (op, &stmt); tree res = unmodified_parm_1 (stmt, op, size_p); gcc_checking_assert (aggpos); @@ -1450,12 +1496,13 @@ will_be_nonconstant_expr_predicate (stru nonconstant_names); return p2.or_with (summary->conds, p1); } - else if (TREE_CODE (expr) == CALL_EXPR) - return true; - else + else { - debug_tree (expr); - gcc_unreachable (); + tree expr2 = strip_copies (expr); + if (expr2 != expr) + return will_be_nonconstant_expr_predicate (info, summary, expr2, + nonconstant_names); + return true; } return false; }