From d5e2d6eb39d0e1c74b1d0e8c389f62f5e22a0640 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 31 May 2023 13:10:31 -0400
Subject: [PATCH 03/11] Provide a new dispatch mechanism for range-ops.
Simplify range_op_handler to have a single range-operator pointer and
provide a more flexible dispatch mechanism for calls via generic vrange
classes. This is more extensible for adding new classes of range support.
* gimple-range-op.cc
(gimple_range_op_handler::gimple_range_op_handler): Adjust.
(gimple_range_op_handler::maybe_builtin_call): Adjust.
* gimple-range-op.h (operand1, operand2): Use m_operator.
* range-op.cc (integral_table, pointer_table): Relocate.
(get_op_handler): Rename from get_handler and handle all types.
(range_op_handler::range_op_handler): Relocate.
(range_op_handler::set_op_handler): Relocate and adjust.
(range_op_handler::range_op_handler): Relocate.
(dispatch_trio): New.
(RO_III, RO_IFI, RO_IFF, RO_FFF, RO_FIF, RO_FII): New consts.
(range_op_handler::dispatch_kind): New.
(range_op_handler::fold_range): Relocate and Use new dispatch value.
(range_op_handler::op1_range): Ditto.
(range_op_handler::op2_range): Ditto.
(range_op_handler::lhs_op1_relation): Ditto.
(range_op_handler::lhs_op2_relation): Ditto.
(range_op_handler::op1_op2_relation): Ditto.
(range_op_handler::set_op_handler): Use m_operator member.
* range-op.h (range_op_handler::operator bool): Use m_operator.
(range_op_handler::dispatch_kind): New.
(range_op_handler::m_valid): Delete.
(range_op_handler::m_int): Delete
(range_op_handler::m_float): Delete
(range_op_handler::m_operator): New.
(range_op_table::operator[]): Relocate from .cc file.
(range_op_table::set): Ditto.
* value-range.h (class vrange): Make range_op_handler a friend.
---
gcc/gimple-range-op.cc | 84 +++-----
gcc/gimple-range-op.h | 4 +-
gcc/range-op.cc | 474 ++++++++++++++++++++++-------------------
gcc/range-op.h | 27 ++-
gcc/value-range.h | 1 +
5 files changed, 310 insertions(+), 280 deletions(-)
@@ -144,7 +144,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
if (type)
set_op_handler (code, type);
- if (m_valid)
+ if (m_operator)
switch (gimple_code (m_stmt))
{
case GIMPLE_COND:
@@ -152,7 +152,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
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);
@@ -171,7 +171,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
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 ();
@@ -1199,7 +1199,6 @@ gimple_range_op_handler::maybe_non_standard ()
gcc_fallthrough ();
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);
@@ -1216,14 +1215,13 @@ gimple_range_op_handler::maybe_non_standard ()
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:
@@ -1252,47 +1250,41 @@ gimple_range_op_handler::maybe_builtin_call ()
{
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:
@@ -1300,68 +1292,57 @@ gimple_range_op_handler::maybe_builtin_call ()
// 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:
@@ -1371,8 +1352,7 @@ gimple_range_op_handler::maybe_builtin_call ()
== 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;
}
@@ -1384,21 +1364,18 @@ gimple_range_op_handler::maybe_builtin_call ()
// 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:
@@ -1406,9 +1383,8 @@ gimple_range_op_handler::maybe_builtin_call ()
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;
}
@@ -32,8 +32,8 @@ public:
gimple_range_op_handler (gimple *s);
inline gimple *stmt () const { return m_stmt; }
inline tree lhs () const { return gimple_get_lhs (m_stmt); }
- tree operand1 () const { gcc_checking_assert (m_valid); return m_op1; }
- tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; }
+ tree operand1 () const { gcc_checking_assert (m_operator); return m_op1; }
+ tree operand2 () const { gcc_checking_assert (m_operator); return m_op2; }
bool calc_op1 (vrange &r, const vrange &lhs_range);
bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range,
relation_trio = TRIO_VARYING);
@@ -48,6 +48,260 @@ along with GCC; see the file COPYING3. If not see
#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. The
+// denser the values, the more efficient dispatch can be created via
+// jump tables.
+// Ensure the shifts are appropriate for the number of range types supported.
+// Current only INT and FLOAT are supported, so a shift of 1 is sufficient
+// producing a value of 0-7 value for dispatching.
+
+constexpr unsigned
+dispatch_trio (unsigned lhs, unsigned op1, unsigned op2)
+{
+ return ((lhs << 2) + (op1 << 1) + (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
@@ -4612,33 +4866,6 @@ pointer_or_operator::wi_fold (irange &r, tree type,
r.set_varying (type);
}
-// 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);
@@ -4682,14 +4909,6 @@ integral_table::integral_table ()
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);
@@ -4714,191 +4933,6 @@ pointer_table::pointer_table ()
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
@@ -186,7 +186,7 @@ class range_op_handler
public:
range_op_handler ();
range_op_handler (enum tree_code code, tree type);
- inline operator bool () const { return m_valid; }
+ inline operator bool () const { return m_operator != NULL; }
bool fold_range (vrange &r, tree type,
const vrange &lh,
@@ -210,10 +210,10 @@ public:
relation_kind = VREL_VARYING) const;
relation_kind op1_op2_relation (const vrange &lhs) const;
protected:
+ unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
+ const vrange& op2) const;
void set_op_handler (enum tree_code code, tree type);
- bool m_valid;
- range_operator *m_int;
- range_operator *m_float;
+ range_operator *m_operator;
};
extern bool range_cast (vrange &, tree type);
@@ -296,6 +296,25 @@ private:
};
+// Return a pointer to the range_operator instance, if there is one
+// associated with tree_code CODE.
+
+inline 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.
+
+inline 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;
+}
+
// This holds the range op table for floating point operations.
extern range_op_table *floating_tree_table;
@@ -77,6 +77,7 @@ class GTY((user)) vrange
template <typename T> friend bool is_a (vrange &);
friend class Value_Range;
friend void streamer_write_vrange (struct output_block *, const vrange &);
+ friend class range_op_handler;
public:
virtual void accept (const class vrange_visitor &v) const = 0;
virtual void set (tree, tree, value_range_kind = VR_RANGE);
--
2.40.1