1 /* Support routines for value ranges.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by Aldy Hernandez <aldyh@redhat.com> and
4 Andrew Macleod <amacleod@redhat.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #ifndef GCC_VALUE_RANGE_H
23 #define GCC_VALUE_RANGE_H
27 // Types of value ranges.
32 /* Range spans the entire domain. */
34 /* Range is [MIN, MAX]. */
36 /* Range is ~[MIN, MAX]. */
38 /* Range is a nice guy. */
42 // Discriminator between different vrange types.
44 enum value_range_discriminator
46 // Range holds an integer or pointer.
48 // Range holds an unsupported type.
52 // Abstract class for ranges of any of the supported types.
54 // To query what types ranger and the entire ecosystem can support,
55 // use Value_Range::supports_type_p(tree type). This is a static
56 // method available independently of any vrange object.
58 // To query what a given vrange variant can support, use:
59 // irange::supports_p ()
60 // frange::supports_p ()
63 // To query what a range object can support, use:
64 // void foo (vrange &v, irange &i, frange &f)
66 // if (v.supports_type_p (type)) ...
67 // if (i.supports_type_p (type)) ...
68 // if (f.supports_type_p (type)) ...
73 template <typename T
> friend bool is_a (vrange
&);
74 friend class Value_Range
;
76 virtual void set (tree
, tree
, value_range_kind
= VR_RANGE
);
77 virtual tree
type () const;
78 virtual bool supports_type_p (tree type
) const;
79 virtual void set_varying (tree type
);
80 virtual void set_undefined ();
81 virtual void dump (FILE * = stderr
) const = 0;
82 virtual bool union_ (const vrange
&);
83 virtual bool intersect (const vrange
&);
84 virtual bool singleton_p (tree
*result
= NULL
) const;
85 virtual bool contains_p (tree cst
) const;
86 virtual bool zero_p () const;
87 virtual bool nonzero_p () const;
88 virtual void set_nonzero (tree type
);
89 virtual void set_zero (tree type
);
90 virtual void set_nonnegative (tree type
);
91 virtual bool fits_p (const vrange
&r
) const;
93 bool varying_p () const;
94 bool undefined_p () const;
95 vrange
& operator= (const vrange
&);
96 bool operator== (const vrange
&) const;
97 bool operator!= (const vrange
&r
) const { return !(*this == r
); }
99 enum value_range_kind
kind () const; // DEPRECATED
103 ENUM_BITFIELD(value_range_kind
) m_kind
: 8;
104 ENUM_BITFIELD(value_range_discriminator
) m_discriminator
: 4;
107 // An integer range without any storage.
109 class GTY((user
)) irange
: public vrange
111 friend class vrange_allocator
;
114 virtual void set (tree
, tree
, value_range_kind
= VR_RANGE
) override
;
115 virtual void set_nonzero (tree type
) override
;
116 virtual void set_zero (tree type
) override
;
117 virtual void set_nonnegative (tree type
) override
;
118 virtual void set_varying (tree type
) override
;
119 virtual void set_undefined () override
;
122 static bool supports_p (tree type
);
123 virtual bool supports_type_p (tree type
) const override
;
124 virtual tree
type () const override
;
126 // Iteration over sub-ranges.
127 unsigned num_pairs () const;
128 wide_int
lower_bound (unsigned = 0) const;
129 wide_int
upper_bound (unsigned) const;
130 wide_int
upper_bound () const;
133 virtual bool zero_p () const override
;
134 virtual bool nonzero_p () const override
;
135 virtual bool singleton_p (tree
*result
= NULL
) const override
;
136 virtual bool contains_p (tree cst
) const override
;
138 // In-place operators.
139 virtual bool union_ (const vrange
&) override
;
140 virtual bool intersect (const vrange
&) override
;
143 // Operator overloads.
144 irange
& operator= (const irange
&);
145 bool operator== (const irange
&) const;
146 bool operator!= (const irange
&r
) const { return !(*this == r
); }
149 virtual bool fits_p (const vrange
&r
) const override
;
150 virtual void dump (FILE * = stderr
) const override
;
152 // Deprecated legacy public methods.
153 tree
min () const; // DEPRECATED
154 tree
max () const; // DEPRECATED
155 bool symbolic_p () const; // DEPRECATED
156 bool constant_p () const; // DEPRECATED
157 void normalize_symbolics (); // DEPRECATED
158 void normalize_addresses (); // DEPRECATED
159 bool may_contain_p (tree
) const; // DEPRECATED
160 void set (tree
); // DEPRECATED
161 bool equal_p (const irange
&) const; // DEPRECATED
162 bool legacy_verbose_union_ (const class irange
*); // DEPRECATED
163 bool legacy_verbose_intersect (const irange
*); // DEPRECATED
166 irange (tree
*, unsigned);
167 // potential promotion to public?
168 tree
tree_lower_bound (unsigned = 0) const;
169 tree
tree_upper_bound (unsigned) const;
170 tree
tree_upper_bound () const;
172 // In-place operators.
173 bool irange_union (const irange
&);
174 bool irange_intersect (const irange
&);
175 void irange_set (tree
, tree
);
176 void irange_set_anti_range (tree
, tree
);
177 bool irange_contains_p (const irange
&) const;
178 bool irange_single_pair_union (const irange
&r
);
180 void normalize_kind ();
182 bool legacy_mode_p () const;
183 bool legacy_equal_p (const irange
&) const;
184 void legacy_union (irange
*, const irange
*);
185 void legacy_intersect (irange
*, const irange
*);
186 void verify_range ();
187 wide_int
legacy_lower_bound (unsigned = 0) const;
188 wide_int
legacy_upper_bound (unsigned) const;
189 int value_inside_range (tree
) const;
190 bool maybe_anti_range () const;
191 void copy_to_legacy (const irange
&);
192 void copy_legacy_to_multi_range (const irange
&);
195 friend void gt_ggc_mx (irange
*);
196 friend void gt_pch_nx (irange
*);
197 friend void gt_pch_nx (irange
*, gt_pointer_operator
, void *);
199 void irange_set_1bit_anti_range (tree
, tree
);
200 bool varying_compatible_p () const;
202 bool intersect (const wide_int
& lb
, const wide_int
& ub
);
203 unsigned char m_num_ranges
;
204 unsigned char m_max_ranges
;
208 // Here we describe an irange with N pairs of ranges. The storage for
209 // the pairs is embedded in the class as an array.
212 class GTY((user
)) int_range
: public irange
216 int_range (tree
, tree
, value_range_kind
= VR_RANGE
);
217 int_range (tree type
, const wide_int
&, const wide_int
&,
218 value_range_kind
= VR_RANGE
);
219 int_range (tree type
);
220 int_range (const int_range
&);
221 int_range (const irange
&);
222 int_range
& operator= (const int_range
&);
224 template <unsigned X
> friend void gt_ggc_mx (int_range
<X
> *);
225 template <unsigned X
> friend void gt_pch_nx (int_range
<X
> *);
226 template <unsigned X
> friend void gt_pch_nx (int_range
<X
> *,
227 gt_pointer_operator
, void *);
229 // ?? These stubs are for ipa-prop.cc which use a value_range in a
230 // hash_traits. hash-traits.h defines an extern of gt_ggc_mx (T &)
231 // instead of picking up the gt_ggc_mx (T *) version.
232 friend void gt_ggc_mx (int_range
<1> *&);
233 friend void gt_pch_nx (int_range
<1> *&);
238 // Unsupported temporaries may be created by ranger before it's known
239 // they're unsupported, or by vr_values::get_value_range.
241 class unsupported_range
: public vrange
244 unsupported_range ();
245 virtual void dump (FILE *) const override
;
248 // is_a<> and as_a<> implementation for vrange.
250 // Anything we haven't specialized is a hard fail.
251 template <typename T
>
259 template <typename T
>
261 is_a (const vrange
&v
)
263 // Reuse is_a <vrange> to implement the const version.
264 const T
&derived
= static_cast<const T
&> (v
);
265 return is_a
<T
> (const_cast<T
&> (derived
));
268 template <typename T
>
272 gcc_checking_assert (is_a
<T
> (v
));
273 return static_cast <T
&> (v
);
276 template <typename T
>
278 as_a (const vrange
&v
)
280 gcc_checking_assert (is_a
<T
> (v
));
281 return static_cast <const T
&> (v
);
284 // Specializations for the different range types.
288 is_a
<irange
> (vrange
&v
)
290 return v
.m_discriminator
== VR_IRANGE
;
293 // This is a special int_range<1> with only one pair, plus
294 // VR_ANTI_RANGE magic to describe slightly more than can be described
295 // in one pair. It is described in the code as a "legacy range" (as
296 // opposed to multi-ranges which have multiple sub-ranges). It is
297 // provided for backward compatibility with code that has not been
298 // converted to multi-range irange's.
300 // There are copy operators to seamlessly copy to/fro multi-ranges.
301 typedef int_range
<1> value_range
;
303 // This is an "infinite" precision irange for use in temporary
305 typedef int_range
<255> int_range_max
;
307 // This is an "infinite" precision range object for use in temporary
308 // calculations for any of the handled types. The object can be
309 // transparently used as a vrange.
315 Value_Range (const vrange
&r
);
316 Value_Range (tree type
);
317 Value_Range (const Value_Range
&);
318 void set_type (tree type
);
319 vrange
& operator= (const vrange
&);
320 bool operator== (const Value_Range
&r
) const;
321 bool operator!= (const Value_Range
&r
) const;
323 operator const vrange
&() const;
324 void dump (FILE *out
= stderr
) const;
325 static bool supports_type_p (tree type
);
327 // Convenience methods for vrange compatability.
328 void set (tree min
, tree max
, value_range_kind kind
= VR_RANGE
)
329 { return m_vrange
->set (min
, max
, kind
); }
330 tree
type () { return m_vrange
->type (); }
331 enum value_range_kind
kind () { return m_vrange
->kind (); }
332 bool varying_p () const { return m_vrange
->varying_p (); }
333 bool undefined_p () const { return m_vrange
->undefined_p (); }
334 void set_varying (tree type
) { m_vrange
->set_varying (type
); }
335 void set_undefined () { m_vrange
->set_undefined (); }
336 bool union_ (const vrange
&r
) { return m_vrange
->union_ (r
); }
337 bool intersect (const vrange
&r
) { return m_vrange
->intersect (r
); }
338 bool singleton_p (tree
*result
= NULL
) const
339 { return m_vrange
->singleton_p (result
); }
340 bool zero_p () const { return m_vrange
->zero_p (); }
341 wide_int
lower_bound () const; // For irange/prange compatability.
342 wide_int
upper_bound () const; // For irange/prange compatability.
344 void init (tree type
);
345 unsupported_range m_unsupported
;
347 int_range_max m_irange
;
351 Value_Range::Value_Range ()
353 m_vrange
= &m_unsupported
;
356 // Copy constructor from a vrange.
359 Value_Range::Value_Range (const vrange
&r
)
364 // Copy constructor from a TYPE. The range of the temporary is set to
368 Value_Range::Value_Range (tree type
)
374 Value_Range::Value_Range (const Value_Range
&r
)
376 m_vrange
= r
.m_vrange
;
379 // Initialize object so it is possible to store temporaries of TYPE
383 Value_Range::init (tree type
)
385 gcc_checking_assert (TYPE_P (type
));
387 if (irange::supports_p (type
))
388 m_vrange
= &m_irange
;
390 m_vrange
= &m_unsupported
;
393 // Set the temporary to allow storing temporaries of TYPE. The range
394 // of the temporary is set to UNDEFINED.
397 Value_Range::set_type (tree type
)
400 m_vrange
->set_undefined ();
403 // Assignment operator for temporaries. Copying incompatible types is
407 Value_Range::operator= (const vrange
&r
)
409 if (is_a
<irange
> (r
))
411 m_irange
= as_a
<irange
> (r
);
412 m_vrange
= &m_irange
;
421 Value_Range::operator== (const Value_Range
&r
) const
423 return *m_vrange
== *r
.m_vrange
;
427 Value_Range::operator!= (const Value_Range
&r
) const
429 return *m_vrange
!= *r
.m_vrange
;
433 Value_Range::operator vrange
&()
439 Value_Range::operator const vrange
&() const
444 // Return TRUE if TYPE is supported by the vrange infrastructure.
447 Value_Range::supports_type_p (tree type
)
449 return irange::supports_p (type
);
452 // Returns true for an old-school value_range as described above.
454 irange::legacy_mode_p () const
456 return m_max_ranges
== 1;
459 extern bool range_has_numeric_bounds_p (const irange
*);
460 extern bool ranges_from_anti_range (const value_range
*,
461 value_range
*, value_range
*);
462 extern void dump_value_range (FILE *, const vrange
*);
463 extern bool vrp_val_is_min (const_tree
);
464 extern bool vrp_val_is_max (const_tree
);
465 extern bool vrp_operand_equal_p (const_tree
, const_tree
);
467 inline value_range_kind
468 vrange::kind () const
473 // Number of sub-ranges in a range.
476 irange::num_pairs () const
478 if (m_kind
== VR_ANTI_RANGE
)
479 return constant_p () ? 2 : 1;
485 irange::type () const
487 gcc_checking_assert (m_num_ranges
> 0);
488 return TREE_TYPE (m_base
[0]);
491 // Return the lower bound of a sub-range expressed as a tree. PAIR is
492 // the sub-range in question.
495 irange::tree_lower_bound (unsigned pair
) const
497 return m_base
[pair
* 2];
500 // Return the upper bound of a sub-range expressed as a tree. PAIR is
501 // the sub-range in question.
504 irange::tree_upper_bound (unsigned pair
) const
506 return m_base
[pair
* 2 + 1];
509 // Return the highest bound of a range expressed as a tree.
512 irange::tree_upper_bound () const
514 gcc_checking_assert (m_num_ranges
);
515 return tree_upper_bound (m_num_ranges
- 1);
521 return tree_lower_bound (0);
528 return tree_upper_bound ();
534 irange::varying_compatible_p () const
536 if (m_num_ranges
!= 1)
541 tree t
= TREE_TYPE (l
);
543 if (m_kind
== VR_VARYING
&& t
== error_mark_node
)
546 unsigned prec
= TYPE_PRECISION (t
);
547 signop sign
= TYPE_SIGN (t
);
548 if (INTEGRAL_TYPE_P (t
))
549 return (wi::to_wide (l
) == wi::min_value (prec
, sign
)
550 && wi::to_wide (u
) == wi::max_value (prec
, sign
));
551 if (POINTER_TYPE_P (t
))
552 return (wi::to_wide (l
) == 0
553 && wi::to_wide (u
) == wi::max_value (prec
, sign
));
558 vrange::varying_p () const
560 return m_kind
== VR_VARYING
;
564 vrange::undefined_p () const
566 return m_kind
== VR_UNDEFINED
;
570 irange::zero_p () const
572 return (m_kind
== VR_RANGE
&& m_num_ranges
== 1
573 && integer_zerop (tree_lower_bound (0))
574 && integer_zerop (tree_upper_bound (0)));
578 irange::nonzero_p () const
583 tree zero
= build_zero_cst (type ());
584 return *this == int_range
<1> (zero
, zero
, VR_ANTI_RANGE
);
588 irange::supports_p (tree type
)
590 return INTEGRAL_TYPE_P (type
) || POINTER_TYPE_P (type
);
594 range_includes_zero_p (const irange
*vr
)
596 if (vr
->undefined_p ())
599 if (vr
->varying_p ())
602 return vr
->may_contain_p (build_zero_cst (vr
->type ()));
606 gt_ggc_mx (irange
*x
)
608 for (unsigned i
= 0; i
< x
->m_num_ranges
; ++i
)
610 gt_ggc_mx (x
->m_base
[i
* 2]);
611 gt_ggc_mx (x
->m_base
[i
* 2 + 1]);
616 gt_pch_nx (irange
*x
)
618 for (unsigned i
= 0; i
< x
->m_num_ranges
; ++i
)
620 gt_pch_nx (x
->m_base
[i
* 2]);
621 gt_pch_nx (x
->m_base
[i
* 2 + 1]);
626 gt_pch_nx (irange
*x
, gt_pointer_operator op
, void *cookie
)
628 for (unsigned i
= 0; i
< x
->m_num_ranges
; ++i
)
630 op (&x
->m_base
[i
* 2], NULL
, cookie
);
631 op (&x
->m_base
[i
* 2 + 1], NULL
, cookie
);
637 gt_ggc_mx (int_range
<N
> *x
)
639 gt_ggc_mx ((irange
*) x
);
644 gt_pch_nx (int_range
<N
> *x
)
646 gt_pch_nx ((irange
*) x
);
651 gt_pch_nx (int_range
<N
> *x
, gt_pointer_operator op
, void *cookie
)
653 gt_pch_nx ((irange
*) x
, op
, cookie
);
656 // Constructors for irange
659 irange::irange (tree
*base
, unsigned nranges
)
661 m_discriminator
= VR_IRANGE
;
663 m_max_ranges
= nranges
;
667 // Constructors for int_range<>.
671 int_range
<N
>::int_range ()
672 : irange (m_ranges
, N
)
677 int_range
<N
>::int_range (const int_range
&other
)
678 : irange (m_ranges
, N
)
680 irange::operator= (other
);
684 int_range
<N
>::int_range (tree min
, tree max
, value_range_kind kind
)
685 : irange (m_ranges
, N
)
687 irange::set (min
, max
, kind
);
691 int_range
<N
>::int_range (tree type
)
692 : irange (m_ranges
, N
)
698 int_range
<N
>::int_range (tree type
, const wide_int
&wmin
, const wide_int
&wmax
,
699 value_range_kind kind
)
700 : irange (m_ranges
, N
)
702 tree min
= wide_int_to_tree (type
, wmin
);
703 tree max
= wide_int_to_tree (type
, wmax
);
704 set (min
, max
, kind
);
708 int_range
<N
>::int_range (const irange
&other
)
709 : irange (m_ranges
, N
)
711 irange::operator= (other
);
716 int_range
<N
>::operator= (const int_range
&src
)
718 irange::operator= (src
);
723 irange::set (tree val
)
729 irange::set_undefined ()
731 m_kind
= VR_UNDEFINED
;
736 irange::set_varying (tree type
)
741 if (INTEGRAL_TYPE_P (type
))
743 // Strict enum's require varying to be not TYPE_MIN/MAX, but rather
744 // min_value and max_value.
745 wide_int min
= wi::min_value (TYPE_PRECISION (type
), TYPE_SIGN (type
));
746 wide_int max
= wi::max_value (TYPE_PRECISION (type
), TYPE_SIGN (type
));
747 if (wi::eq_p (max
, wi::to_wide (TYPE_MAX_VALUE (type
)))
748 && wi::eq_p (min
, wi::to_wide (TYPE_MIN_VALUE (type
))))
750 m_base
[0] = TYPE_MIN_VALUE (type
);
751 m_base
[1] = TYPE_MAX_VALUE (type
);
755 m_base
[0] = wide_int_to_tree (type
, min
);
756 m_base
[1] = wide_int_to_tree (type
, max
);
759 else if (POINTER_TYPE_P (type
))
761 m_base
[0] = build_int_cst (type
, 0);
762 m_base
[1] = build_int_cst (type
, -1);
765 m_base
[0] = m_base
[1] = error_mark_node
;
769 irange::operator== (const irange
&r
) const
774 // Return the lower bound of a sub-range. PAIR is the sub-range in
778 irange::lower_bound (unsigned pair
) const
780 if (legacy_mode_p ())
781 return legacy_lower_bound (pair
);
782 gcc_checking_assert (m_num_ranges
> 0);
783 gcc_checking_assert (pair
+ 1 <= num_pairs ());
784 return wi::to_wide (tree_lower_bound (pair
));
787 // Return the upper bound of a sub-range. PAIR is the sub-range in
791 irange::upper_bound (unsigned pair
) const
793 if (legacy_mode_p ())
794 return legacy_upper_bound (pair
);
795 gcc_checking_assert (m_num_ranges
> 0);
796 gcc_checking_assert (pair
+ 1 <= num_pairs ());
797 return wi::to_wide (tree_upper_bound (pair
));
800 // Return the highest bound of a range.
803 irange::upper_bound () const
805 unsigned pairs
= num_pairs ();
806 gcc_checking_assert (pairs
> 0);
807 return upper_bound (pairs
- 1);
811 irange::union_ (const vrange
&r
)
813 dump_flags_t m_flags
= dump_flags
;
814 dump_flags
&= ~TDF_DETAILS
;
815 bool ret
= irange::legacy_verbose_union_ (&as_a
<irange
> (r
));
816 dump_flags
= m_flags
;
821 irange::intersect (const vrange
&r
)
823 dump_flags_t m_flags
= dump_flags
;
824 dump_flags
&= ~TDF_DETAILS
;
825 bool ret
= irange::legacy_verbose_intersect (&as_a
<irange
> (r
));
826 dump_flags
= m_flags
;
830 // Set value range VR to a nonzero range of type TYPE.
833 irange::set_nonzero (tree type
)
835 tree zero
= build_int_cst (type
, 0);
836 if (legacy_mode_p ())
837 set (zero
, zero
, VR_ANTI_RANGE
);
839 irange_set_anti_range (zero
, zero
);
842 // Set value range VR to a ZERO range of type TYPE.
845 irange::set_zero (tree type
)
847 tree z
= build_int_cst (type
, 0);
848 if (legacy_mode_p ())
854 // Normalize a range to VARYING or UNDEFINED if possible.
857 irange::normalize_kind ()
859 if (m_num_ranges
== 0)
860 m_kind
= VR_UNDEFINED
;
861 else if (varying_compatible_p ())
863 if (m_kind
== VR_RANGE
)
865 else if (m_kind
== VR_ANTI_RANGE
)
872 // Return the maximum value for TYPE.
875 vrp_val_max (const_tree type
)
877 if (INTEGRAL_TYPE_P (type
))
878 return TYPE_MAX_VALUE (type
);
879 if (POINTER_TYPE_P (type
))
881 wide_int max
= wi::max_value (TYPE_PRECISION (type
), TYPE_SIGN (type
));
882 return wide_int_to_tree (const_cast<tree
> (type
), max
);
887 // Return the minimum value for TYPE.
890 vrp_val_min (const_tree type
)
892 if (INTEGRAL_TYPE_P (type
))
893 return TYPE_MIN_VALUE (type
);
894 if (POINTER_TYPE_P (type
))
895 return build_zero_cst (const_cast<tree
> (type
));
899 // This is the range storage class. It is used to allocate the
900 // minimum amount of storage needed for a given range. Storage is
901 // automatically freed at destruction of the class.
903 class vrange_allocator
907 ~vrange_allocator ();
908 // Allocate a range of TYPE.
909 vrange
*alloc_vrange (tree type
);
910 // Allocate a memory block of BYTES.
911 void *alloc (unsigned bytes
);
912 // Return a clone of SRC.
913 template <typename T
> T
*clone (const T
&src
);
915 irange
*alloc_irange (unsigned pairs
);
916 DISABLE_COPY_AND_ASSIGN (vrange_allocator
);
917 struct obstack m_obstack
;
921 vrange_allocator::vrange_allocator ()
923 obstack_init (&m_obstack
);
927 vrange_allocator::~vrange_allocator ()
929 obstack_free (&m_obstack
, NULL
);
932 // Provide a hunk of memory from the obstack.
935 vrange_allocator::alloc (unsigned bytes
)
937 return obstack_alloc (&m_obstack
, bytes
);
940 // Return a new range to hold ranges of TYPE. The newly allocated
941 // range is initialized to VR_UNDEFINED.
944 vrange_allocator::alloc_vrange (tree type
)
946 if (irange::supports_p (type
))
947 return alloc_irange (2);
952 // Return a new range with NUM_PAIRS.
955 vrange_allocator::alloc_irange (unsigned num_pairs
)
957 // Never allocate 0 pairs.
958 // Don't allocate 1 either, or we get legacy value_range's.
962 size_t nbytes
= sizeof (tree
) * 2 * num_pairs
;
964 // Allocate the irange and required memory for the vector.
965 void *r
= alloc (sizeof (irange
));
966 tree
*mem
= static_cast <tree
*> (alloc (nbytes
));
967 return new (r
) irange (mem
, num_pairs
);
970 // Return a clone of an irange.
974 vrange_allocator::clone
<irange
> (const irange
&src
)
976 irange
*r
= alloc_irange (src
.num_pairs ());
981 // Return a clone of a vrange.
985 vrange_allocator::clone
<vrange
> (const vrange
&src
)
987 if (is_a
<irange
> (src
))
988 return clone
<irange
> (as_a
<irange
> (src
));
993 #endif // GCC_VALUE_RANGE_H