Commit 523fe5b6 by Aldy Hernandez Committed by Aldy Hernandez

Disentangle range_fold_*ary_expr() into various independent pieces.

From-SVN: r276654
parent 3faf75d4
2019-10-07 Aldy Hernandez <aldyh@redhat.com> 2019-10-07 Aldy Hernandez <aldyh@redhat.com>
* ipa-prop.c (ipa_vr::nonzero_p): New.
(ipcp_update_vr): Use nonzero_p instead of open-coding check for
non-zero range.
* ipa-prop.h (class ipa_vr): Add nonzero_p.
* tree-vrp.c (range_has_numeric_bounds_p): New.
(range_int_cst_p): Use range_has_numeric_bounds_p.
(get_range_op_handler): New.
(supported_types_p): New.
(defined_ranges_p): New.
(drop_undefines_to_varying): New.
(range_fold_binary_symbolics_p): New.
(range_fold_unary_symbolics_p): New.
(range_fold_unary_expr): Extract out into above functions.
(range_fold_binary_expr): Same.
(value_range_base::normalize_addresses): New.
(value_range_base::normalize_symbolics): Normalize addresses.
* tree-vrp.h (class value_range_base): Add normalize_addresses.
2019-10-07 Aldy Hernandez <aldyh@redhat.com>
* tree-vrp.c (value_range_base::singleton_p): Use * tree-vrp.c (value_range_base::singleton_p): Use
value_range_base::num_pairs instead of vrp_val_is* to check value_range_base::num_pairs instead of vrp_val_is* to check
if a range has one sub-range. if a range has one sub-range.
......
...@@ -5109,6 +5109,18 @@ ipcp_update_bits (struct cgraph_node *node) ...@@ -5109,6 +5109,18 @@ ipcp_update_bits (struct cgraph_node *node)
} }
} }
bool
ipa_vr::nonzero_p (tree expr_type) const
{
if (type == VR_ANTI_RANGE && wi::eq_p (min, 0) && wi::eq_p (max, 0))
return true;
unsigned prec = TYPE_PRECISION (expr_type);
return (type == VR_RANGE
&& wi::eq_p (min, wi::one (prec))
&& wi::eq_p (max, wi::max_value (prec, TYPE_SIGN (expr_type))));
}
/* Update value range of formal parameters as described in /* Update value range of formal parameters as described in
ipcp_transformation. */ ipcp_transformation. */
...@@ -5181,9 +5193,7 @@ ipcp_update_vr (struct cgraph_node *node) ...@@ -5181,9 +5193,7 @@ ipcp_update_vr (struct cgraph_node *node)
TYPE_SIGN (type))); TYPE_SIGN (type)));
} }
else if (POINTER_TYPE_P (TREE_TYPE (ddef)) else if (POINTER_TYPE_P (TREE_TYPE (ddef))
&& vr[i].type == VR_ANTI_RANGE && vr[i].nonzero_p (TREE_TYPE (ddef)))
&& wi::eq_p (vr[i].min, 0)
&& wi::eq_p (vr[i].max, 0))
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, "Setting nonnull for %u\n", i); fprintf (dump_file, "Setting nonnull for %u\n", i);
......
...@@ -165,6 +165,7 @@ public: ...@@ -165,6 +165,7 @@ public:
enum value_range_kind type; enum value_range_kind type;
wide_int min; wide_int min;
wide_int max; wide_int max;
bool nonzero_p (tree) const;
}; };
/* A jump function for a callsite represents the values passed as actual /* A jump function for a callsite represents the values passed as actual
......
...@@ -910,15 +910,21 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2) ...@@ -910,15 +910,21 @@ vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
&& bitmap_equal_p (b1, b2))); && bitmap_equal_p (b1, b2)));
} }
static bool
range_has_numeric_bounds_p (const value_range_base *vr)
{
return (vr->min ()
&& TREE_CODE (vr->min ()) == INTEGER_CST
&& TREE_CODE (vr->max ()) == INTEGER_CST);
}
/* Return true if max and min of VR are INTEGER_CST. It's not necessary /* Return true if max and min of VR are INTEGER_CST. It's not necessary
a singleton. */ a singleton. */
bool bool
range_int_cst_p (const value_range_base *vr) range_int_cst_p (const value_range_base *vr)
{ {
return (vr->kind () == VR_RANGE return (vr->kind () == VR_RANGE && range_has_numeric_bounds_p (vr));
&& TREE_CODE (vr->min ()) == INTEGER_CST
&& TREE_CODE (vr->max ()) == INTEGER_CST);
} }
/* Return true if VR is a INTEGER_CST singleton. */ /* Return true if VR is a INTEGER_CST singleton. */
...@@ -1760,119 +1766,102 @@ extract_range_from_plus_minus_expr (value_range_base *vr, ...@@ -1760,119 +1766,102 @@ extract_range_from_plus_minus_expr (value_range_base *vr,
vr->set (kind, min, max); vr->set (kind, min, max);
} }
/* Normalize a value_range for use in range_ops and return it. */ /* Return the range-ops handler for CODE and EXPR_TYPE. If no
suitable operator is found, return NULL and set VR to VARYING. */
static value_range_base static const range_operator *
normalize_for_range_ops (const value_range_base &vr) get_range_op_handler (value_range_base *vr,
enum tree_code code,
tree expr_type)
{ {
tree type = vr.type (); const range_operator *op = range_op_handler (code, expr_type);
if (!op)
vr->set_varying (expr_type);
return op;
}
/* If the types passed are supported, return TRUE, otherwise set VR to
VARYING and return FALSE. */
/* This will return ~[0,0] for [&var, &var]. */ static bool
if (POINTER_TYPE_P (type) && !range_includes_zero_p (&vr)) supported_types_p (value_range_base *vr,
tree type0,
tree type1 = NULL)
{
if (!value_range_base::supports_type_p (type0)
|| (type1 && !value_range_base::supports_type_p (type1)))
{ {
value_range_base temp; vr->set_varying (type0);
temp.set_nonzero (type); return false;
return temp;
} }
if (vr.symbolic_p ()) return true;
return normalize_for_range_ops (vr.normalize_symbolics ());
if (TREE_CODE (vr.min ()) == INTEGER_CST
&& TREE_CODE (vr.max ()) == INTEGER_CST)
return vr;
/* Anything not strictly numeric at this point becomes varying. */
return value_range_base (vr.type ());
} }
/* Fold a binary expression of two value_range's with range-ops. */ /* If any of the ranges passed are defined, return TRUE, otherwise set
VR to UNDEFINED and return FALSE. */
void static bool
range_fold_binary_expr (value_range_base *vr, defined_ranges_p (value_range_base *vr,
enum tree_code code, const value_range_base *vr0,
tree expr_type, const value_range_base *vr1 = NULL)
const value_range_base *vr0_,
const value_range_base *vr1_)
{ {
if (!value_range_base::supports_type_p (expr_type) if (vr0->undefined_p () && (!vr1 || vr1->undefined_p ()))
|| (!vr0_->undefined_p ()
&& !value_range_base::supports_type_p (vr0_->type ()))
|| (!vr1_->undefined_p ()
&& !value_range_base::supports_type_p (vr1_->type ())))
{
vr->set_varying (expr_type);
return;
}
if (vr0_->undefined_p () && vr1_->undefined_p ())
{ {
vr->set_undefined (); vr->set_undefined ();
return; return false;
}
range_operator *op = range_op_handler (code, expr_type);
if (!op)
{
vr->set_varying (expr_type);
return;
} }
return true;
}
/* Mimic any behavior users of extract_range_from_binary_expr may static value_range_base
expect. */ drop_undefines_to_varying (const value_range_base *vr, tree expr_type)
value_range_base vr0 = *vr0_, vr1 = *vr1_; {
if (vr0.undefined_p ()) if (vr->undefined_p ())
vr0.set_varying (expr_type); return value_range_base (expr_type);
else if (vr1.undefined_p ()) else
vr1.set_varying (expr_type); return *vr;
}
/* If any operand is symbolic, perform a binary operation on them and
return TRUE, otherwise return FALSE. */
/* Handle symbolics. */ static bool
if (vr0.symbolic_p () || vr1.symbolic_p ()) range_fold_binary_symbolics_p (value_range_base *vr,
tree_code code,
tree expr_type,
const value_range_base *vr0,
const value_range_base *vr1)
{
if (vr0->symbolic_p () || vr1->symbolic_p ())
{ {
if ((code == PLUS_EXPR || code == MINUS_EXPR)) if ((code == PLUS_EXPR || code == MINUS_EXPR))
{ {
extract_range_from_plus_minus_expr (vr, code, expr_type, extract_range_from_plus_minus_expr (vr, code, expr_type, vr0, vr1);
&vr0, &vr1); return true;
return;
} }
if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR) if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR)
{ {
extract_range_from_pointer_plus_expr (vr, code, expr_type, extract_range_from_pointer_plus_expr (vr, code, expr_type, vr0, vr1);
&vr0, &vr1); return true;
return;
} }
const range_operator *op = get_range_op_handler (vr, code, expr_type);
*vr = op->fold_range (expr_type,
vr0->normalize_symbolics (),
vr1->normalize_symbolics ());
return true;
} }
return false;
/* Do the range-ops dance. */
value_range_base n0 = normalize_for_range_ops (vr0);
value_range_base n1 = normalize_for_range_ops (vr1);
*vr = op->fold_range (expr_type, n0, n1);
} }
/* Fold a unary expression of a value_range with range-ops. */ /* If operand is symbolic, perform a unary operation on it and return
TRUE, otherwise return FALSE. */
void static bool
range_fold_unary_expr (value_range_base *vr, range_fold_unary_symbolics_p (value_range_base *vr,
enum tree_code code, tree expr_type, tree_code code,
const value_range_base *vr0, tree expr_type,
tree vr0_type) const value_range_base *vr0)
{ {
/* Mimic any behavior users of extract_range_from_unary_expr may
expect. */
if (!value_range_base::supports_type_p (expr_type)
|| !value_range_base::supports_type_p (vr0_type))
{
vr->set_varying (expr_type);
return;
}
if (vr0->undefined_p ())
{
vr->set_undefined ();
return;
}
range_operator *op = range_op_handler (code, expr_type);
if (!op)
{
vr->set_varying (expr_type);
return;
}
/* Handle symbolics. */
if (vr0->symbolic_p ()) if (vr0->symbolic_p ())
{ {
if (code == NEGATE_EXPR) if (code == NEGATE_EXPR)
...@@ -1881,7 +1870,7 @@ range_fold_unary_expr (value_range_base *vr, ...@@ -1881,7 +1870,7 @@ range_fold_unary_expr (value_range_base *vr,
value_range_base zero; value_range_base zero;
zero.set_zero (vr0->type ()); zero.set_zero (vr0->type ());
range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0); range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0);
return; return true;
} }
if (code == BIT_NOT_EXPR) if (code == BIT_NOT_EXPR)
{ {
...@@ -1889,30 +1878,64 @@ range_fold_unary_expr (value_range_base *vr, ...@@ -1889,30 +1878,64 @@ range_fold_unary_expr (value_range_base *vr,
value_range_base minusone; value_range_base minusone;
minusone.set (build_int_cst (vr0->type (), -1)); minusone.set (build_int_cst (vr0->type (), -1));
range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0); range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
return; return true;
} }
const range_operator *op = get_range_op_handler (vr, code, expr_type);
*vr = op->fold_range (expr_type, *vr = op->fold_range (expr_type,
normalize_for_range_ops (*vr0), vr0->normalize_symbolics (),
value_range_base (expr_type)); value_range_base (expr_type));
return; return true;
}
if (CONVERT_EXPR_CODE_P (code) && (POINTER_TYPE_P (expr_type)
|| POINTER_TYPE_P (vr0->type ())))
{
/* This handles symbolic conversions such such as [25, x_4]. */
if (!range_includes_zero_p (vr0))
vr->set_nonzero (expr_type);
else if (vr0->zero_p ())
vr->set_zero (expr_type);
else
vr->set_varying (expr_type);
return;
} }
return false;
}
/* Do the range-ops dance. */ /* Perform a binary operation on a pair of ranges. */
value_range_base n0 = normalize_for_range_ops (*vr0);
value_range_base n1 (expr_type); void
*vr = op->fold_range (expr_type, n0, n1); range_fold_binary_expr (value_range_base *vr,
enum tree_code code,
tree expr_type,
const value_range_base *vr0_,
const value_range_base *vr1_)
{
if (!supported_types_p (vr, expr_type)
|| !defined_ranges_p (vr, vr0_, vr1_))
return;
const range_operator *op = get_range_op_handler (vr, code, expr_type);
if (!op)
return;
value_range_base vr0 = drop_undefines_to_varying (vr0_, expr_type);
value_range_base vr1 = drop_undefines_to_varying (vr1_, expr_type);
if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
return;
*vr = op->fold_range (expr_type,
vr0.normalize_addresses (),
vr1.normalize_addresses ());
}
/* Perform a unary operation on a range. */
void
range_fold_unary_expr (value_range_base *vr,
enum tree_code code, tree expr_type,
const value_range_base *vr0,
tree vr0_type)
{
if (!supported_types_p (vr, expr_type, vr0_type)
|| !defined_ranges_p (vr, vr0))
return;
const range_operator *op = get_range_op_handler (vr, code, expr_type);
if (!op)
return;
if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
return;
*vr = op->fold_range (expr_type,
vr0->normalize_addresses (),
value_range_base (expr_type));
} }
/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,
...@@ -5997,7 +6020,24 @@ value_range::union_ (const value_range *other) ...@@ -5997,7 +6020,24 @@ value_range::union_ (const value_range *other)
} }
} }
/* Normalize symbolics into constants. */ /* Normalize addresses into constants. */
value_range_base
value_range_base::normalize_addresses () const
{
if (!POINTER_TYPE_P (type ()) || range_has_numeric_bounds_p (this))
return *this;
if (!range_includes_zero_p (this))
{
gcc_checking_assert (TREE_CODE (m_min) == ADDR_EXPR
|| TREE_CODE (m_max) == ADDR_EXPR);
return range_nonzero (type ());
}
return value_range_base (type ());
}
/* Normalize symbolics and addresses into constants. */
value_range_base value_range_base
value_range_base::normalize_symbolics () const value_range_base::normalize_symbolics () const
...@@ -6008,7 +6048,7 @@ value_range_base::normalize_symbolics () const ...@@ -6008,7 +6048,7 @@ value_range_base::normalize_symbolics () const
bool min_symbolic = !is_gimple_min_invariant (min ()); bool min_symbolic = !is_gimple_min_invariant (min ());
bool max_symbolic = !is_gimple_min_invariant (max ()); bool max_symbolic = !is_gimple_min_invariant (max ());
if (!min_symbolic && !max_symbolic) if (!min_symbolic && !max_symbolic)
return *this; return normalize_addresses ();
// [SYM, SYM] -> VARYING // [SYM, SYM] -> VARYING
if (min_symbolic && max_symbolic) if (min_symbolic && max_symbolic)
......
...@@ -86,6 +86,7 @@ public: ...@@ -86,6 +86,7 @@ public:
static bool supports_type_p (tree); static bool supports_type_p (tree);
value_range_base normalize_symbolics () const; value_range_base normalize_symbolics () const;
value_range_base normalize_addresses () const;
static const unsigned int m_max_pairs = 2; static const unsigned int m_max_pairs = 2;
bool contains_p (tree) const; bool contains_p (tree) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment