if (type)
set_op_handler (code, type);
- if (m_valid)
+ if (m_operator)
switch (gimple_code (m_stmt))
{
case GIMPLE_COND:
m_op2 = gimple_cond_rhs (m_stmt);
// Check that operands are supported types. One check is enough.
if (!Value_Range::supports_type_p (TREE_TYPE (m_op1)))
- m_valid = false;
+ m_operator = NULL;
return;
case GIMPLE_ASSIGN:
m_op1 = gimple_range_base_of_assignment (m_stmt);
m_op2 = gimple_assign_rhs2 (m_stmt);
// Check that operands are supported types. One check is enough.
if ((m_op1 && !Value_Range::supports_type_p (TREE_TYPE (m_op1))))
- m_valid = false;
+ m_operator = NULL;
return;
default:
gcc_unreachable ();
{
case WIDEN_MULT_EXPR:
{
- m_valid = false;
m_op1 = gimple_assign_rhs1 (m_stmt);
m_op2 = gimple_assign_rhs2 (m_stmt);
tree ret = gimple_assign_lhs (m_stmt);
if ((signed1 ^ signed2) && signed_ret)
return;
- m_valid = true;
if (signed2 && !signed1)
std::swap (m_op1, m_op2);
if (signed1 || signed2)
- m_int = signed_op;
+ m_operator = signed_op;
else
- m_int = unsigned_op;
+ m_operator = unsigned_op;
break;
}
default:
{
case CFN_BUILT_IN_CONSTANT_P:
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
if (irange::supports_p (TREE_TYPE (m_op1)))
- m_int = &op_cfn_constant_p;
+ m_operator = &op_cfn_constant_p;
else if (frange::supports_p (TREE_TYPE (m_op1)))
- m_float = &op_cfn_constant_float_p;
+ m_operator = &op_cfn_constant_float_p;
else
- m_valid = false;
+ m_operator = NULL;
break;
CASE_FLT_FN (CFN_BUILT_IN_SIGNBIT):
m_op1 = gimple_call_arg (call, 0);
- m_float = &op_cfn_signbit;
- m_valid = true;
+ m_operator = &op_cfn_signbit;
break;
CASE_CFN_COPYSIGN_ALL:
m_op1 = gimple_call_arg (call, 0);
m_op2 = gimple_call_arg (call, 1);
- m_float = &op_cfn_copysign;
- m_valid = true;
+ m_operator = &op_cfn_copysign;
break;
CASE_CFN_SQRT:
CASE_CFN_SQRT_FN:
m_op1 = gimple_call_arg (call, 0);
- m_float = &op_cfn_sqrt;
- m_valid = true;
+ m_operator = &op_cfn_sqrt;
break;
CASE_CFN_SIN:
CASE_CFN_SIN_FN:
m_op1 = gimple_call_arg (call, 0);
- m_float = &op_cfn_sin;
- m_valid = true;
+ m_operator = &op_cfn_sin;
break;
CASE_CFN_COS:
CASE_CFN_COS_FN:
m_op1 = gimple_call_arg (call, 0);
- m_float = &op_cfn_cos;
- m_valid = true;
+ m_operator = &op_cfn_cos;
break;
case CFN_BUILT_IN_TOUPPER:
// Only proceed If the argument is compatible with the LHS.
m_op1 = gimple_call_arg (call, 0);
if (range_compatible_p (type, TREE_TYPE (m_op1)))
- {
- m_valid = true;
- m_int = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower
- : &op_cfn_toupper;
- }
+ m_operator = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower
+ : &op_cfn_toupper;
break;
CASE_CFN_FFS:
m_op1 = gimple_call_arg (call, 0);
- m_int = &op_cfn_ffs;
- m_valid = true;
+ m_operator = &op_cfn_ffs;
break;
CASE_CFN_POPCOUNT:
m_op1 = gimple_call_arg (call, 0);
- m_int = &op_cfn_popcount;
- m_valid = true;
+ m_operator = &op_cfn_popcount;
break;
CASE_CFN_CLZ:
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
if (gimple_call_internal_p (call))
- m_int = &op_cfn_clz_internal;
+ m_operator = &op_cfn_clz_internal;
else
- m_int = &op_cfn_clz;
+ m_operator = &op_cfn_clz;
break;
CASE_CFN_CTZ:
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
if (gimple_call_internal_p (call))
- m_int = &op_cfn_ctz_internal;
+ m_operator = &op_cfn_ctz_internal;
else
- m_int = &op_cfn_ctz;
+ m_operator = &op_cfn_ctz;
break;
CASE_CFN_CLRSB:
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
- m_int = &op_cfn_clrsb;
+ m_operator = &op_cfn_clrsb;
break;
case CFN_UBSAN_CHECK_ADD:
m_op1 = gimple_call_arg (call, 0);
m_op2 = gimple_call_arg (call, 1);
- m_valid = true;
- m_int = &op_cfn_ubsan_add;
+ m_operator = &op_cfn_ubsan_add;
break;
case CFN_UBSAN_CHECK_SUB:
m_op1 = gimple_call_arg (call, 0);
m_op2 = gimple_call_arg (call, 1);
- m_valid = true;
- m_int = &op_cfn_ubsan_sub;
+ m_operator = &op_cfn_ubsan_sub;
break;
case CFN_UBSAN_CHECK_MUL:
m_op1 = gimple_call_arg (call, 0);
m_op2 = gimple_call_arg (call, 1);
- m_valid = true;
- m_int = &op_cfn_ubsan_mul;
+ m_operator = &op_cfn_ubsan_mul;
break;
case CFN_BUILT_IN_STRLEN:
== TYPE_PRECISION (TREE_TYPE (lhs))))
{
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
- m_int = &op_cfn_strlen;
+ m_operator = &op_cfn_strlen;
}
break;
}
// This call will ensure all the asserts are triggered.
oacc_get_ifn_dim_arg (call);
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
- m_int = &op_cfn_goacc_dim_size;
+ m_operator = &op_cfn_goacc_dim_size;
break;
case CFN_GOACC_DIM_POS:
// This call will ensure all the asserts are triggered.
oacc_get_ifn_dim_arg (call);
m_op1 = gimple_call_arg (call, 0);
- m_valid = true;
- m_int = &op_cfn_goacc_dim_pos;
+ m_operator = &op_cfn_goacc_dim_pos;
break;
CASE_CFN_PARITY:
- m_valid = true;
- m_int = &op_cfn_parity;
+ m_operator = &op_cfn_parity;
break;
default:
unsigned arg;
if (gimple_call_fnspec (call).returns_arg (&arg) && arg == 0)
{
- m_valid = true;
m_op1 = gimple_call_arg (call, 0);
- m_int = &op_cfn_pass_through_arg1;
+ m_operator = &op_cfn_pass_through_arg1;
}
break;
}
#include "range-op.h"
#include "tree-ssa-ccp.h"
+// Instantiate a range op table for integral operations.
+
+class integral_table : public range_op_table
+{
+public:
+ integral_table ();
+} integral_tree_table;
+
+// Instantiate a range op table for pointer operations.
+
+class pointer_table : public range_op_table
+{
+public:
+ pointer_table ();
+} pointer_tree_table;
+
+
+// The tables are hidden and accessed via a simple extern function.
+
+range_operator *
+get_op_handler (enum tree_code code, tree type)
+{
+ // First check if there is a pointer specialization.
+ if (POINTER_TYPE_P (type))
+ return pointer_tree_table[code];
+ if (INTEGRAL_TYPE_P (type))
+ return integral_tree_table[code];
+ if (frange::supports_p (type))
+ return (*floating_tree_table)[code];
+ return NULL;
+}
+
+range_op_handler::range_op_handler ()
+{
+ m_operator = NULL;
+}
+
+void
+range_op_handler::set_op_handler (tree_code code, tree type)
+{
+ m_operator = get_op_handler (code, type);
+}
+
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+ set_op_handler (code, type);
+}
+
+// Create a dispatch pattern for value range discriminators LHS, OP1, and OP2.
+// This is used to produce a unique value for each dispatch pattern. Shift
+// values are based on the size of the m_discriminator field in value_range.h.
+
+constexpr unsigned
+dispatch_trio (unsigned lhs, unsigned op1, unsigned op2)
+{
+ return ((lhs << 8) + (op1 << 4) + (op2));
+}
+
+// These are the supported dispatch patterns. These map to the parameter list
+// of the routines in range_operator. Note the last 3 characters are
+// shorthand for the LHS, OP1, and OP2 range discriminator class.
+
+const unsigned RO_III = dispatch_trio (VR_IRANGE, VR_IRANGE, VR_IRANGE);
+const unsigned RO_IFI = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_IRANGE);
+const unsigned RO_IFF = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_FRANGE);
+const unsigned RO_FFF = dispatch_trio (VR_FRANGE, VR_FRANGE, VR_FRANGE);
+const unsigned RO_FIF = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_FRANGE);
+const unsigned RO_FII = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_IRANGE);
+
+// Return a dispatch value for parameter types LHS, OP1 and OP2.
+
+unsigned
+range_op_handler::dispatch_kind (const vrange &lhs, const vrange &op1,
+ const vrange& op2) const
+{
+ return dispatch_trio (lhs.m_discriminator, op1.m_discriminator,
+ op2.m_discriminator);
+}
+
+// Dispatch a call to fold_range based on the types of R, LH and RH.
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+ const vrange &lh,
+ const vrange &rh,
+ relation_trio rel) const
+{
+ gcc_checking_assert (m_operator);
+ switch (dispatch_kind (r, lh, rh))
+ {
+ case RO_III:
+ return m_operator->fold_range (as_a <irange> (r), type,
+ as_a <irange> (lh),
+ as_a <irange> (rh), rel);
+ case RO_IFI:
+ return m_operator->fold_range (as_a <irange> (r), type,
+ as_a <frange> (lh),
+ as_a <irange> (rh), rel);
+ case RO_IFF:
+ return m_operator->fold_range (as_a <irange> (r), type,
+ as_a <frange> (lh),
+ as_a <frange> (rh), rel);
+ case RO_FFF:
+ return m_operator->fold_range (as_a <frange> (r), type,
+ as_a <frange> (lh),
+ as_a <frange> (rh), rel);
+ default:
+ return false;
+ }
+}
+
+// Dispatch a call to op1_range based on the types of R, LHS and OP2.
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+ const vrange &lhs,
+ const vrange &op2,
+ relation_trio rel) const
+{
+ gcc_checking_assert (m_operator);
+
+ if (lhs.undefined_p ())
+ return false;
+ switch (dispatch_kind (r, lhs, op2))
+ {
+ case RO_III:
+ return m_operator->op1_range (as_a <irange> (r), type,
+ as_a <irange> (lhs),
+ as_a <irange> (op2), rel);
+ case RO_FIF:
+ return m_operator->op1_range (as_a <frange> (r), type,
+ as_a <irange> (lhs),
+ as_a <frange> (op2), rel);
+ case RO_FFF:
+ return m_operator->op1_range (as_a <frange> (r), type,
+ as_a <frange> (lhs),
+ as_a <frange> (op2), rel);
+ default:
+ return false;
+ }
+}
+
+// Dispatch a call to op2_range based on the types of R, LHS and OP1.
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+ const vrange &lhs,
+ const vrange &op1,
+ relation_trio rel) const
+{
+ gcc_checking_assert (m_operator);
+ if (lhs.undefined_p ())
+ return false;
+
+ switch (dispatch_kind (r, lhs, op1))
+ {
+ case RO_III:
+ return m_operator->op2_range (as_a <irange> (r), type,
+ as_a <irange> (lhs),
+ as_a <irange> (op1), rel);
+ case RO_FIF:
+ return m_operator->op2_range (as_a <frange> (r), type,
+ as_a <irange> (lhs),
+ as_a <frange> (op1), rel);
+ case RO_FFF:
+ return m_operator->op2_range (as_a <frange> (r), type,
+ as_a <frange> (lhs),
+ as_a <frange> (op1), rel);
+ default:
+ return false;
+ }
+}
+
+// Dispatch a call to lhs_op1_relation based on the types of LHS, OP1 and OP2.
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+ const vrange &op1,
+ const vrange &op2,
+ relation_kind rel) const
+{
+ gcc_checking_assert (m_operator);
+
+ switch (dispatch_kind (lhs, op1, op2))
+ {
+ case RO_III:
+ return m_operator->lhs_op1_relation (as_a <irange> (lhs),
+ as_a <irange> (op1),
+ as_a <irange> (op2), rel);
+ case RO_IFF:
+ return m_operator->lhs_op1_relation (as_a <irange> (lhs),
+ as_a <frange> (op1),
+ as_a <frange> (op2), rel);
+ case RO_FFF:
+ return m_operator->lhs_op1_relation (as_a <frange> (lhs),
+ as_a <frange> (op1),
+ as_a <frange> (op2), rel);
+ default:
+ return VREL_VARYING;
+ }
+}
+
+// Dispatch a call to lhs_op2_relation based on the types of LHS, OP1 and OP2.
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+ const vrange &op1,
+ const vrange &op2,
+ relation_kind rel) const
+{
+ gcc_checking_assert (m_operator);
+ switch (dispatch_kind (lhs, op1, op2))
+ {
+ case RO_III:
+ return m_operator->lhs_op2_relation (as_a <irange> (lhs),
+ as_a <irange> (op1),
+ as_a <irange> (op2), rel);
+ case RO_IFF:
+ return m_operator->lhs_op2_relation (as_a <irange> (lhs),
+ as_a <frange> (op1),
+ as_a <frange> (op2), rel);
+ case RO_FFF:
+ return m_operator->lhs_op2_relation (as_a <frange> (lhs),
+ as_a <frange> (op1),
+ as_a <frange> (op2), rel);
+ default:
+ return VREL_VARYING;
+ }
+}
+
+// Dispatch a call to op1_op2_relation based on the type of LHS.
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+ gcc_checking_assert (m_operator);
+ switch (dispatch_kind (lhs, lhs, lhs))
+ {
+ case RO_III:
+ return m_operator->op1_op2_relation (as_a <irange> (lhs));
+
+ case RO_FFF:
+ return m_operator->op1_op2_relation (as_a <frange> (lhs));
+
+ default:
+ return VREL_VARYING;
+ }
+}
+
+
// Convert irange bitmasks into a VALUE MASK pair suitable for calling CCP.
static void
r.set_varying (type);
}
\f
-// Return a pointer to the range_operator instance, if there is one
-// associated with tree_code CODE.
-
-range_operator *
-range_op_table::operator[] (enum tree_code code)
-{
- gcc_checking_assert (code > 0 && code < MAX_TREE_CODES);
- return m_range_tree[code];
-}
-
-// Add OP to the handler table for CODE.
-
-void
-range_op_table::set (enum tree_code code, range_operator &op)
-{
- gcc_checking_assert (m_range_tree[code] == NULL);
- m_range_tree[code] = &op;
-}
-
-// Instantiate a range op table for integral operations.
-
-class integral_table : public range_op_table
-{
-public:
- integral_table ();
-} integral_tree_table;
-
integral_table::integral_table ()
{
set (EQ_EXPR, op_equal);
set (ADDR_EXPR, op_addr);
}
-// Instantiate a range op table for pointer operations.
-
-class pointer_table : public range_op_table
-{
-public:
- pointer_table ();
-} pointer_tree_table;
-
pointer_table::pointer_table ()
{
set (BIT_AND_EXPR, op_pointer_and);
set (BIT_XOR_EXPR, op_bitwise_xor);
}
-// The tables are hidden and accessed via a simple extern function.
-
-static inline range_operator *
-get_handler (enum tree_code code, tree type)
-{
- // First check if there is a pointer specialization.
- if (POINTER_TYPE_P (type))
- return pointer_tree_table[code];
- if (INTEGRAL_TYPE_P (type))
- return integral_tree_table[code];
- return NULL;
-}
-
-// Return the floating point operator for CODE or NULL if none available.
-
-static inline range_operator *
-get_float_handler (enum tree_code code, tree)
-{
- return (*floating_tree_table)[code];
-}
-
-void
-range_op_handler::set_op_handler (tree_code code, tree type)
-{
- if (irange::supports_p (type))
- {
- m_float = NULL;
- m_int = get_handler (code, type);
- m_valid = m_int != NULL;
- }
- else if (frange::supports_p (type))
- {
- m_int = NULL;
- m_float = get_float_handler (code, type);
- m_valid = m_float != NULL;
- }
- else
- {
- m_int = NULL;
- m_float = NULL;
- m_valid = false;
- }
-}
-
-range_op_handler::range_op_handler ()
-{
- m_int = NULL;
- m_float = NULL;
- m_valid = false;
-}
-
-range_op_handler::range_op_handler (tree_code code, tree type)
-{
- set_op_handler (code, type);
-}
-
-
-bool
-range_op_handler::fold_range (vrange &r, tree type,
- const vrange &lh,
- const vrange &rh,
- relation_trio rel) const
-{
- gcc_checking_assert (m_valid);
- if (m_int)
- return m_int->fold_range (as_a <irange> (r), type,
- as_a <irange> (lh),
- as_a <irange> (rh), rel);
-
- if (is_a <irange> (r))
- {
- if (is_a <irange> (rh))
- return m_float->fold_range (as_a <irange> (r), type,
- as_a <frange> (lh),
- as_a <irange> (rh), rel);
- else
- return m_float->fold_range (as_a <irange> (r), type,
- as_a <frange> (lh),
- as_a <frange> (rh), rel);
- }
- return m_float->fold_range (as_a <frange> (r), type,
- as_a <frange> (lh),
- as_a <frange> (rh), rel);
-}
-
-bool
-range_op_handler::op1_range (vrange &r, tree type,
- const vrange &lhs,
- const vrange &op2,
- relation_trio rel) const
-{
- gcc_checking_assert (m_valid);
-
- if (lhs.undefined_p ())
- return false;
- if (m_int)
- return m_int->op1_range (as_a <irange> (r), type,
- as_a <irange> (lhs),
- as_a <irange> (op2), rel);
-
- if (is_a <irange> (lhs))
- return m_float->op1_range (as_a <frange> (r), type,
- as_a <irange> (lhs),
- as_a <frange> (op2), rel);
- return m_float->op1_range (as_a <frange> (r), type,
- as_a <frange> (lhs),
- as_a <frange> (op2), rel);
-}
-
-bool
-range_op_handler::op2_range (vrange &r, tree type,
- const vrange &lhs,
- const vrange &op1,
- relation_trio rel) const
-{
- gcc_checking_assert (m_valid);
- if (lhs.undefined_p ())
- return false;
- if (m_int)
- return m_int->op2_range (as_a <irange> (r), type,
- as_a <irange> (lhs),
- as_a <irange> (op1), rel);
-
- if (is_a <irange> (lhs))
- return m_float->op2_range (as_a <frange> (r), type,
- as_a <irange> (lhs),
- as_a <frange> (op1), rel);
- return m_float->op2_range (as_a <frange> (r), type,
- as_a <frange> (lhs),
- as_a <frange> (op1), rel);
-}
-
-relation_kind
-range_op_handler::lhs_op1_relation (const vrange &lhs,
- const vrange &op1,
- const vrange &op2,
- relation_kind rel) const
-{
- gcc_checking_assert (m_valid);
- if (m_int)
- return m_int->lhs_op1_relation (as_a <irange> (lhs),
- as_a <irange> (op1),
- as_a <irange> (op2), rel);
-
- if (is_a <irange> (lhs))
- return m_float->lhs_op1_relation (as_a <irange> (lhs),
- as_a <frange> (op1),
- as_a <frange> (op2), rel);
- return m_float->lhs_op1_relation (as_a <frange> (lhs),
- as_a <frange> (op1),
- as_a <frange> (op2), rel);
-}
-
-relation_kind
-range_op_handler::lhs_op2_relation (const vrange &lhs,
- const vrange &op1,
- const vrange &op2,
- relation_kind rel) const
-{
- gcc_checking_assert (m_valid);
- if (m_int)
- return m_int->lhs_op2_relation (as_a <irange> (lhs),
- as_a <irange> (op1),
- as_a <irange> (op2), rel);
-
- if (is_a <irange> (lhs))
- return m_float->lhs_op2_relation (as_a <irange> (lhs),
- as_a <frange> (op1),
- as_a <frange> (op2), rel);
- return m_float->lhs_op2_relation (as_a <frange> (lhs),
- as_a <frange> (op1),
- as_a <frange> (op2), rel);
-}
-
-relation_kind
-range_op_handler::op1_op2_relation (const vrange &lhs) const
-{
- gcc_checking_assert (m_valid);
- if (m_int)
- return m_int->op1_op2_relation (as_a <irange> (lhs));
- if (is_a <irange> (lhs))
- return m_float->op1_op2_relation (as_a <irange> (lhs));
- return m_float->op1_op2_relation (as_a <frange> (lhs));
-}
-
// Cast the range in R to TYPE.
bool