| /* Header file for mixed range operator class. |
| Copyright (C) 2017-2023 Free Software Foundation, Inc. |
| Contributed by Andrew MacLeod <amacleod@redhat.com> |
| and Aldy Hernandez <aldyh@redhat.com>. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef GCC_RANGE_OP_MIXED_H |
| #define GCC_RANGE_OP_MIXED_H |
| |
| void update_known_bitmask (irange &, tree_code, const irange &, const irange &); |
| bool minus_op1_op2_relation_effect (irange &lhs_range, tree type, |
| const irange &, const irange &, |
| relation_kind rel); |
| |
| |
| // Return TRUE if 0 is within [WMIN, WMAX]. |
| |
| inline bool |
| wi_includes_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) |
| { |
| signop sign = TYPE_SIGN (type); |
| return wi::le_p (wmin, 0, sign) && wi::ge_p (wmax, 0, sign); |
| } |
| |
| // Return TRUE if [WMIN, WMAX] is the singleton 0. |
| |
| inline bool |
| wi_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) |
| { |
| unsigned prec = TYPE_PRECISION (type); |
| return wmin == wmax && wi::eq_p (wmin, wi::zero (prec)); |
| } |
| |
| |
| enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL }; |
| bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type); |
| |
| // If the range of either op1 or op2 is undefined, set the result to |
| // varying and return TRUE. If the caller truly cares about a result, |
| // they should pass in a varying if it has an undefined that it wants |
| // treated as a varying. |
| |
| inline bool |
| empty_range_varying (vrange &r, tree type, |
| const vrange &op1, const vrange & op2) |
| { |
| if (op1.undefined_p () || op2.undefined_p ()) |
| { |
| r.set_varying (type); |
| return true; |
| } |
| else |
| return false; |
| } |
| |
| // For relation opcodes, first try to see if the supplied relation |
| // forces a true or false result, and return that. |
| // Then check for undefined operands. If none of this applies, |
| // return false. |
| |
| inline bool |
| relop_early_resolve (irange &r, tree type, const vrange &op1, |
| const vrange &op2, relation_trio trio, |
| relation_kind my_rel) |
| { |
| relation_kind rel = trio.op1_op2 (); |
| // If known relation is a complete subset of this relation, always true. |
| if (relation_union (rel, my_rel) == my_rel) |
| { |
| r = range_true (type); |
| return true; |
| } |
| |
| // If known relation has no subset of this relation, always false. |
| if (relation_intersect (rel, my_rel) == VREL_UNDEFINED) |
| { |
| r = range_false (type); |
| return true; |
| } |
| |
| // If either operand is undefined, return VARYING. |
| if (empty_range_varying (r, type, op1, op2)) |
| return true; |
| |
| return false; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Mixed Mode Operators. |
| // ---------------------------------------------------------------------- |
| |
| class operator_equal : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &val, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &val, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (frange &r, tree type, |
| const irange &lhs, const frange &op1, |
| relation_trio rel = TRIO_VARYING) const final override; |
| |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_not_equal : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_lt : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (frange &r, tree type, |
| const irange &lhs, const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_le : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (frange &r, tree type, |
| const irange &lhs, const frange &op1, |
| relation_trio rel = TRIO_VARYING) const final override; |
| |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_gt : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (frange &r, tree type, |
| const irange &lhs, const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_ge : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::op1_op2_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool fold_range (irange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const irange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op2_range (frange &r, tree type, |
| const irange &lhs, const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| relation_kind op1_op2_relation (const irange &lhs) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| }; |
| |
| class operator_identity : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::lhs_op1_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED, |
| const frange &op1, const frange &op2 ATTRIBUTE_UNUSED, |
| relation_trio = TRIO_VARYING) const final override; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED, |
| const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED, |
| relation_trio = TRIO_VARYING) const final override; |
| relation_kind lhs_op1_relation (const irange &lhs, |
| const irange &op1, const irange &op2, |
| relation_kind rel) const final override; |
| }; |
| |
| class operator_cst : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool fold_range (frange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| }; |
| |
| |
| class operator_cast: public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::lhs_op1_relation; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| relation_kind lhs_op1_relation (const irange &lhs, |
| const irange &op1, const irange &op2, |
| relation_kind) const final override; |
| private: |
| bool truncating_cast_p (const irange &inner, const irange &outer) const; |
| bool inside_domain_p (const wide_int &min, const wide_int &max, |
| const irange &outer) const; |
| void fold_pair (irange &r, unsigned index, const irange &inner, |
| const irange &outer) const; |
| }; |
| |
| class operator_plus : public range_operator |
| { |
| public: |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::lhs_op1_relation; |
| using range_operator::lhs_op2_relation; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio) const final override; |
| bool op1_range (frange &r, tree type, |
| const frange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio) const final override; |
| bool op2_range (frange &r, tree type, |
| const frange &lhs, const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, |
| const irange &op2, |
| relation_kind rel) const final override; |
| relation_kind lhs_op2_relation (const irange &lhs, const irange &op1, |
| const irange &op2, |
| relation_kind rel) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| private: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const final override; |
| void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, |
| bool &maybe_nan, tree type, |
| const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
| const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
| relation_kind) const final override; |
| }; |
| |
| class operator_abs : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| bool fold_range (frange &r, tree type, |
| const frange &op1, const frange &, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, const irange &lhs, |
| const irange &op2, relation_trio) const final override; |
| bool op1_range (frange &r, tree type, |
| const frange &lhs, const frange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| private: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const final override; |
| |
| }; |
| |
| class operator_minus : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::lhs_op1_relation; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio) const final override; |
| bool op1_range (frange &r, tree type, |
| const frange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio) const final override; |
| bool op2_range (frange &r, tree type, |
| const frange &lhs, |
| const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| relation_kind lhs_op1_relation (const irange &lhs, |
| const irange &op1, const irange &op2, |
| relation_kind rel) const final override; |
| bool op1_op2_relation_effect (irange &lhs_range, tree type, |
| const irange &op1_range, |
| const irange &op2_range, |
| relation_kind rel) const final override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| private: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const final override; |
| void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, |
| bool &maybe_nan, tree type, |
| const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
| const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
| relation_kind) const final override; |
| }; |
| |
| class operator_negate : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool fold_range (frange &r, tree type, |
| const frange &op1, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_range (frange &r, tree type, |
| const frange &lhs, const frange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| }; |
| |
| |
| class cross_product_operator : public range_operator |
| { |
| public: |
| virtual bool wi_op_overflows (wide_int &r, |
| tree type, |
| const wide_int &, |
| const wide_int &) const = 0; |
| void wi_cross_product (irange &r, tree type, |
| const wide_int &lh_lb, |
| const wide_int &lh_ub, |
| const wide_int &rh_lb, |
| const wide_int &rh_ub) const; |
| }; |
| |
| class operator_mult : public cross_product_operator |
| { |
| public: |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio) const final override; |
| bool op1_range (frange &r, tree type, |
| const frange &lhs, const frange &op2, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio) const final override; |
| bool op2_range (frange &r, tree type, |
| const frange &lhs, const frange &op1, |
| relation_trio = TRIO_VARYING) const final override; |
| |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const final override; |
| bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, |
| const wide_int &w1) const final override; |
| |
| void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, |
| bool &maybe_nan, tree type, |
| const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
| const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
| relation_kind kind) const final override; |
| }; |
| |
| class operator_addr_expr : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| bool fold_range (irange &r, tree type, |
| const irange &op1, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| }; |
| |
| class operator_bitwise_not : public range_operator |
| { |
| public: |
| using range_operator::fold_range; |
| using range_operator::op1_range; |
| bool fold_range (irange &r, tree type, |
| const irange &lh, const irange &rh, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| }; |
| |
| class operator_bitwise_xor : public range_operator |
| { |
| public: |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio rel = TRIO_VARYING) const final override; |
| bool op1_op2_relation_effect (irange &lhs_range, |
| tree type, |
| const irange &op1_range, |
| const irange &op2_range, |
| relation_kind rel) const; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const final override; |
| private: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const final override; |
| }; |
| |
| class operator_bitwise_and : public range_operator |
| { |
| public: |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| using range_operator::lhs_op1_relation; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const override; |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio rel = TRIO_VARYING) const override; |
| relation_kind lhs_op1_relation (const irange &lhs, |
| const irange &op1, const irange &op2, |
| relation_kind) const override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const override; |
| protected: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const override; |
| void simple_op1_range_solver (irange &r, tree type, |
| const irange &lhs, |
| const irange &op2) const; |
| }; |
| |
| class operator_bitwise_or : public range_operator |
| { |
| public: |
| using range_operator::op1_range; |
| using range_operator::op2_range; |
| bool op1_range (irange &r, tree type, |
| const irange &lhs, const irange &op2, |
| relation_trio rel = TRIO_VARYING) const override; |
| bool op2_range (irange &r, tree type, |
| const irange &lhs, const irange &op1, |
| relation_trio rel = TRIO_VARYING) const override; |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const override; |
| protected: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const override; |
| }; |
| |
| class operator_min : public range_operator |
| { |
| public: |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const override; |
| protected: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const override; |
| }; |
| |
| class operator_max : public range_operator |
| { |
| public: |
| void update_bitmask (irange &r, const irange &lh, |
| const irange &rh) const override; |
| protected: |
| void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
| const wide_int &lh_ub, const wide_int &rh_lb, |
| const wide_int &rh_ub) const override; |
| }; |
| #endif // GCC_RANGE_OP_MIXED_H |