return ctx;
}
+/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
+ DST_TYPE on value range in SRC_VR and store it to DST_VR. Return true if
+ the result is a range or an anti-range. */
+
+static bool
+ipa_vr_operation_and_type_effects (value_range *dst_vr,
+ value_range *src_vr,
+ enum tree_code operation,
+ tree dst_type, tree src_type)
+{
+ range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
+ if (dst_vr->varying_p () || dst_vr->undefined_p ())
+ return false;
+ return true;
+}
+
+/* Determine value_range of JFUNC given that INFO describes the caller node or
+ the one it is inlined to, CS is the call graph edge corresponding to JFUNC
+ and PARM_TYPE of the parameter. */
+
+value_range
+ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
+ ipa_jump_func *jfunc, tree parm_type)
+{
+ value_range vr;
+ return vr;
+ if (jfunc->m_vr)
+ ipa_vr_operation_and_type_effects (&vr,
+ jfunc->m_vr,
+ NOP_EXPR, parm_type,
+ jfunc->m_vr->type ());
+ if (vr.singleton_p ())
+ return vr;
+ if (jfunc->type == IPA_JF_PASS_THROUGH)
+ {
+ int idx;
+ ipcp_transformation *sum
+ = ipcp_get_transformation_summary (cs->caller->inlined_to
+ ? cs->caller->inlined_to
+ : cs->caller);
+ if (!sum || !sum->m_vr)
+ return vr;
+
+ idx = ipa_get_jf_pass_through_formal_id (jfunc);
+
+ if (!(*sum->m_vr)[idx].known)
+ return vr;
+ tree vr_type = ipa_get_type (info, idx);
+ value_range srcvr (wide_int_to_tree (vr_type, (*sum->m_vr)[idx].min),
+ wide_int_to_tree (vr_type, (*sum->m_vr)[idx].max),
+ (*sum->m_vr)[idx].type);
+
+ enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
+
+ if (TREE_CODE_CLASS (operation) == tcc_unary)
+ {
+ value_range res;
+
+ if (ipa_vr_operation_and_type_effects (&res,
+ &srcvr,
+ operation, parm_type,
+ vr_type))
+ vr.intersect (res);
+ }
+ else
+ {
+ value_range op_res, res;
+ tree op = ipa_get_jf_pass_through_operand (jfunc);
+ value_range op_vr (op, op);
+
+ range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr);
+ if (ipa_vr_operation_and_type_effects (&res,
+ &op_res,
+ NOP_EXPR, parm_type,
+ vr_type))
+ vr.intersect (res);
+ }
+ }
+ return vr;
+}
+
/* See if NODE is a clone with a known aggregate value at a given OFFSET of a
parameter with the given INDEX. */
return dest_lattice->set_to_bottom ();
}
-/* Emulate effects of unary OPERATION and/or conversion from SRC_TYPE to
- DST_TYPE on value range in SRC_VR and store it to DST_VR. Return true if
- the result is a range or an anti-range. */
-
-static bool
-ipa_vr_operation_and_type_effects (value_range *dst_vr,
- value_range *src_vr,
- enum tree_code operation,
- tree dst_type, tree src_type)
-{
- range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
- if (dst_vr->varying_p () || dst_vr->undefined_p ())
- return false;
- return true;
-}
-
/* Propagate value range across jump function JFUNC that is associated with
edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
accordingly. */
evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p,
vec<tree> known_vals,
+ vec<value_range> known_value_ranges,
vec<ipa_agg_value_set> known_aggs,
clause_t *ret_clause,
clause_t *ret_nonspec_clause)
val = NULL_TREE;
}
- if (!val)
+ if (!val
+ && (c->code == predicate::changed
+ || c->code == predicate::is_not_constant))
{
clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
- if (TYPE_SIZE (c->type) != TYPE_SIZE (TREE_TYPE (val)))
- {
- clause |= 1 << (i + predicate::first_dynamic_condition);
- nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
- continue;
- }
if (c->code == predicate::is_not_constant)
{
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
continue;
}
- val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
- for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+ if (val && TYPE_SIZE (c->type) == TYPE_SIZE (TREE_TYPE (val)))
{
- if (!val)
- break;
- if (!op->val[0])
- val = fold_unary (op->code, op->type, val);
- else if (!op->val[1])
- val = fold_binary (op->code, op->type,
- op->index ? op->val[0] : val,
- op->index ? val : op->val[0]);
- else if (op->index == 0)
- val = fold_ternary (op->code, op->type,
- val, op->val[0], op->val[1]);
- else if (op->index == 1)
- val = fold_ternary (op->code, op->type,
- op->val[0], val, op->val[1]);
- else if (op->index == 2)
- val = fold_ternary (op->code, op->type,
- op->val[0], op->val[1], val);
- else
- val = NULL_TREE;
+ if (c->type != TREE_TYPE (val))
+ val = fold_unary (VIEW_CONVERT_EXPR, c->type, val);
+ for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+ {
+ if (!val)
+ break;
+ if (!op->val[0])
+ val = fold_unary (op->code, op->type, val);
+ else if (!op->val[1])
+ val = fold_binary (op->code, op->type,
+ op->index ? op->val[0] : val,
+ op->index ? val : op->val[0]);
+ else if (op->index == 0)
+ val = fold_ternary (op->code, op->type,
+ val, op->val[0], op->val[1]);
+ else if (op->index == 1)
+ val = fold_ternary (op->code, op->type,
+ op->val[0], val, op->val[1]);
+ else if (op->index == 2)
+ val = fold_ternary (op->code, op->type,
+ op->val[0], op->val[1], val);
+ else
+ val = NULL_TREE;
+ }
+
+ res = val
+ ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
+ : NULL;
+
+ if (res && integer_zerop (res))
+ continue;
+ if (res && integer_onep (res))
+ {
+ clause |= 1 << (i + predicate::first_dynamic_condition);
+ nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
+ continue;
+ }
}
+ if (c->operand_num < (int) known_value_ranges.length ()
+ && !c->agg_contents
+ && !known_value_ranges[c->operand_num].undefined_p ()
+ && !known_value_ranges[c->operand_num].varying_p ()
+ && TYPE_SIZE (c->type)
+ == TYPE_SIZE (known_value_ranges[c->operand_num].type ())
+ && (!val || TREE_CODE (val) != INTEGER_CST))
+ {
+ value_range vr = known_value_ranges[c->operand_num];
+ if (!useless_type_conversion_p (c->type, vr.type ()))
+ {
+ value_range res;
+ range_fold_unary_expr (&res, NOP_EXPR,
+ c->type, &vr, vr.type ());
+ vr = res;
+ }
+ tree type = c->type;
- res = val
- ? fold_binary_to_constant (c->code, boolean_type_node, val, c->val)
- : NULL;
+ for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
+ {
+ if (vr.varying_p () || vr.undefined_p ())
+ break;
- if (res && integer_zerop (res))
- continue;
+ value_range res;
+ if (!op->val[0])
+ range_fold_unary_expr (&res, op->code, op->type, &vr, type);
+ else if (!op->val[1])
+ {
+ value_range op0 (op->val[0], op->val[0]);
+ range_fold_binary_expr (&res, op->code, op->type,
+ op->index ? &op0 : &vr,
+ op->index ? &vr : &op0);
+ }
+ else
+ gcc_unreachable ();
+ type = op->type;
+ vr = res;
+ }
+ if (!vr.varying_p () && !vr.undefined_p ())
+ {
+ value_range res;
+ value_range val_vr (c->val, c->val);
+ range_fold_binary_expr (&res, c->code, boolean_type_node,
+ &vr,
+ &val_vr);
+ if (res.zero_p ())
+ continue;
+ }
+ }
clause |= 1 << (i + predicate::first_dynamic_condition);
nonspec_clause |= 1 << (i + predicate::first_dynamic_condition);
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
vec<tree> known_vals = vNULL;
+ auto_vec<value_range, 32> known_value_ranges;
vec<ipa_agg_value_set> known_aggs = vNULL;
class ipa_edge_args *args;
if (count && (info->conds || known_vals_ptr))
known_vals.safe_grow_cleared (count);
+ if (count && info->conds)
+ known_value_ranges.safe_grow_cleared (count);
if (count && (info->conds || known_aggs_ptr))
known_aggs.safe_grow_cleared (count);
if (count && known_contexts_ptr)
known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
caller, &jf->agg);
+ if (info->conds)
+ known_value_ranges[i]
+ = ipa_value_range_from_jfunc (caller_parms_info, e, jf,
+ ipa_get_type (callee_pi, i));
}
else
gcc_assert (callee->thunk.thunk_p);
}
evaluate_conditions_for_known_args (callee, inline_p,
- known_vals, known_aggs, clause_ptr,
+ known_vals,
+ known_value_ranges,
+ known_aggs, clause_ptr,
nonspec_clause_ptr);
if (known_vals_ptr)
evaluate_conditions_for_known_args (dst, false,
known_vals,
vNULL,
+ vNULL,
&possible_truths,
/* We are going to specialize,
so ignore nonspec truths. */
{
clause_t clause, nonspec_clause;
- evaluate_conditions_for_known_args (node, false, known_vals, known_aggs,
- &clause, &nonspec_clause);
+ /* TODO: Also pass known value ranges. */
+ evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
+ known_aggs, &clause, &nonspec_clause);
ipa_call_context ctx (node, clause, nonspec_clause,
known_vals, known_contexts,
known_aggs, vNULL);
info->fp_expressions |= callee_info->fp_expressions;
if (callee_info->conds)
- evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL, NULL);
+ evaluate_properties_for_edge (edge, true, &clause,
+ NULL, NULL, NULL, NULL);
if (ipa_node_params_sum && callee_info->conds)
{
class ipa_edge_args *args = IPA_EDGE_REF (edge);