> +/* Analyze EXPR if it represents a series of simple operations performed on > + a function parameter and return true if so. FBI, STMT, EXPR, INDEX_P and > + AGGPOS have the same meaning like in unmodified_parm_or_parm_agg_item. > + Type of the parameter or load from an aggregate via the parameter is > + stored in *TYPE_P. Operations on the parameter are recorded to > + PARAM_OPS_P if it is not NULL. */ > + > +static bool > +decompose_param_expr (struct ipa_func_body_info *fbi, > + gimple *stmt, tree expr, > + int *index_p, tree *type_p, > + struct agg_position_info *aggpos, > + expr_eval_ops *param_ops_p = NULL) > +{ > + int op_limit = PARAM_VALUE (PARAM_IPA_MAX_PARAM_EXPR_OPS); > + int op_count = 0; > + > + if (param_ops_p) > + *param_ops_p = NULL; > + > + while (true) > + { > + expr_eval_op eval_op; > + poly_int64 size; > + > + if (unmodified_parm_or_parm_agg_item (fbi, stmt, expr, index_p, &size, > + aggpos)) > + { > + tree type = TREE_TYPE (expr); > + > + /* Stop if found bit-field whose size does not equal any natural > + integral type. */ > + if (maybe_ne (tree_to_poly_int64 (TYPE_SIZE (type)), size)) > + break;
Why is this needed? > + > + *type_p = type; > + return true; > + } > + > + if (TREE_CODE (expr) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (expr)) > + break; > + > + if (!is_gimple_assign (stmt = SSA_NAME_DEF_STMT (expr))) > + break; > + > + switch (gimple_assign_rhs_class (stmt)) > + { > + case GIMPLE_SINGLE_RHS: > + expr = gimple_assign_rhs1 (stmt); > + continue; > + > + case GIMPLE_UNARY_RHS: > + expr = gimple_assign_rhs1 (stmt); > + > + eval_op.val_is_rhs = false; I find val_is_rhs to be confusing, lhs/rhs is usually used for the gimple assignments. Here everything is rhs, but it depends whether the val is operand0 or operand1. So I guess we could do val_is_op1. > @@ -1183,10 +1301,8 @@ set_cond_stmt_execution_predicate (struct > ipa_func_body_info *fbi, > if (!is_gimple_ip_invariant (gimple_cond_rhs (last))) > return; > op = gimple_cond_lhs (last); > - /* TODO: handle conditionals like > - var = op0 < 4; > - if (var != 0). */ > - if (unmodified_parm_or_parm_agg_item (fbi, last, op, &index, &size, > &aggpos)) > + > + if (decompose_param_expr (fbi, last, op, &index, &type, &aggpos, > ¶m_ops)) > { > code = gimple_cond_code (last); > inverted_code = invert_tree_comparison (code, HONOR_NANS (op)); > @@ -1201,13 +1317,13 @@ set_cond_stmt_execution_predicate (struct > ipa_func_body_info *fbi, > if (this_code != ERROR_MARK) > { > predicate p > - = add_condition (summary, index, size, &aggpos, this_code, > - unshare_expr_without_location > - (gimple_cond_rhs (last))); > + = add_condition (summary, index, type, &aggpos, this_code, > + gimple_cond_rhs (last), param_ops); An why unsharing is no longer needed here? It is importnat to avoid anything which reffers to function local blocks to get into the global LTO stream. > +/* Check whether two set of operations have same effects. */ > +static bool > +expr_eval_ops_equal_p (expr_eval_ops ops1, expr_eval_ops ops2) > +{ > + if (ops1) > + { > + if (!ops2 || ops1->length () != ops2->length ()) > + return false; > + > + for (unsigned i = 0; i < ops1->length (); i++) > + { > + expr_eval_op &op1 = (*ops1)[i]; > + expr_eval_op &op2 = (*ops2)[i]; > + > + if (op1.code != op2.code > + || op1.val_is_rhs != op2.val_is_rhs > + || !vrp_operand_equal_p (op1.val, op2.val) Why you need vrp_operand_equal_p instead of operand_equal_p here? Overall the patch looks very reasonable. We may end up with bit more general expressions (i.e. supporting arithmetics involving more than one operand). I see you also fixed a lot of typos in comments, please go head and commit them separately as obvious. Thank for all the work! Honza