diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/gimple-range-op.cc | 84 | ||||
-rw-r--r-- | gcc/gimple-range-op.h | 4 | ||||
-rw-r--r-- | gcc/range-op.cc | 470 | ||||
-rw-r--r-- | gcc/range-op.h | 27 | ||||
-rw-r--r-- | gcc/value-range.h | 1 |
5 files changed, 306 insertions, 280 deletions
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 293d764..b6b10e4 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -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 (); @@ -1193,7 +1193,6 @@ gimple_range_op_handler::maybe_non_standard () { 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); @@ -1210,14 +1209,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: @@ -1246,47 +1244,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: @@ -1294,68 +1286,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: @@ -1365,8 +1346,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; } @@ -1378,21 +1358,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: @@ -1400,9 +1377,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; } diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h index 1bf63c5..e7bb009 100644 --- a/gcc/gimple-range-op.h +++ b/gcc/gimple-range-op.h @@ -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); diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 203c30f..4d122de 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -48,6 +48,256 @@ 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. 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 @@ -4612,33 +4862,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 +4905,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 +4929,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 diff --git a/gcc/range-op.h b/gcc/range-op.h index cad16f4..7af5873 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -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; diff --git a/gcc/value-range.h b/gcc/value-range.h index 2b4ebab..9103e9c 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -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); |