summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/value-range.cc14
-rw-r--r--gcc/value-range.h98
2 files changed, 82 insertions, 30 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index a341cece86d..93c44a68365 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -901,6 +901,9 @@ frange::set_nonnegative (tree type)
irange &
irange::operator= (const irange &src)
{
+ int needed = src.num_pairs ();
+ maybe_resize (needed);
+
unsigned x;
unsigned lim = src.m_num_ranges;
if (lim > m_max_ranges)
@@ -1340,6 +1343,7 @@ irange::union_ (const vrange &v)
// Now it simply needs to be copied, and if there are too many
// ranges, merge some. We wont do any analysis as to what the
// "best" merges are, simply combine the final ranges into one.
+ maybe_resize (i / 2);
if (i > m_max_ranges * 2)
{
res[m_max_ranges * 2 - 1] = res[i - 1];
@@ -1439,6 +1443,11 @@ irange::intersect (const vrange &v)
if (r.irange_contains_p (*this))
return intersect_nonzero_bits (r);
+ // ?? We could probably come up with something smarter than the
+ // worst case scenario here.
+ int needed = num_pairs () + r.num_pairs ();
+ maybe_resize (needed);
+
signop sign = TYPE_SIGN (m_type);
unsigned bld_pair = 0;
unsigned bld_lim = m_max_ranges;
@@ -1646,6 +1655,11 @@ irange::invert ()
m_num_ranges = 1;
return;
}
+
+ // At this point, we need one extra sub-range to represent the
+ // inverse.
+ maybe_resize (m_num_ranges + 1);
+
// The algorithm is as follows. To calculate INVERT ([a,b][c,d]), we
// generate [-MIN, a-1][b+1, c-1][d+1, MAX].
//
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 22b0250b11b..0da2a42764a 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -167,9 +167,10 @@ public:
void set_nonzero_bits (const wide_int &bits);
protected:
+ void maybe_resize (int needed);
virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
virtual bool contains_p (tree cst) const override;
- irange (wide_int *, unsigned);
+ irange (wide_int *, unsigned nranges, bool resizable);
// In-place operators.
bool irange_contains_p (const irange &) const;
@@ -179,6 +180,8 @@ protected:
void verify_range ();
+ // Hard limit on max ranges allowed.
+ static const int HARD_MAX_RANGES = 255;
private:
friend void gt_ggc_mx (irange *);
friend void gt_pch_nx (irange *);
@@ -192,16 +195,22 @@ private:
bool intersect (const wide_int& lb, const wide_int& ub);
unsigned char m_num_ranges;
- const unsigned char m_max_ranges;
+ bool m_resizable;
+ unsigned char m_max_ranges;
tree m_type;
wide_int m_nonzero_mask;
+protected:
wide_int *m_base;
};
// Here we describe an irange with N pairs of ranges. The storage for
// the pairs is embedded in the class as an array.
+//
+// If RESIZABLE is true, the storage will be resized on the heap when
+// the number of ranges needed goes past N up to a max of
+// HARD_MAX_RANGES. This new storage is freed upon destruction.
-template<unsigned N>
+template<unsigned N, bool RESIZABLE = false>
class GTY((user)) int_range : public irange
{
public:
@@ -211,7 +220,7 @@ public:
int_range (tree type);
int_range (const int_range &);
int_range (const irange &);
- virtual ~int_range () = default;
+ virtual ~int_range ();
int_range& operator= (const int_range &);
protected:
int_range (tree, tree, value_range_kind = VR_RANGE);
@@ -451,6 +460,38 @@ is_a <frange> (vrange &v)
return v.m_discriminator == VR_FRANGE;
}
+// For resizable ranges, resize the range up to HARD_MAX_RANGES if the
+// NEEDED pairs is greater than the current capacity of the range.
+
+inline void
+irange::maybe_resize (int needed)
+{
+ if (!m_resizable || m_max_ranges == HARD_MAX_RANGES)
+ return;
+
+ if (needed > m_max_ranges)
+ {
+ m_max_ranges = HARD_MAX_RANGES;
+ wide_int *newmem = new wide_int[m_max_ranges * 2];
+ memcpy (newmem, m_base, sizeof (wide_int) * num_pairs () * 2);
+ m_base = newmem;
+ }
+}
+
+template<unsigned N, bool RESIZABLE>
+inline
+int_range<N, RESIZABLE>::~int_range ()
+{
+ if (RESIZABLE && m_base != m_ranges)
+ delete m_base;
+}
+
+// This is an "infinite" precision irange for use in temporary
+// calculations. It starts with a sensible default covering 99% of
+// uses, and goes up to HARD_MAX_RANGES when needed. Any allocated
+// storage is freed upon destruction.
+typedef int_range<3, /*RESIZABLE=*/true> int_range_max;
+
class vrange_visitor
{
public:
@@ -461,10 +502,6 @@ public:
typedef int_range<2> value_range;
-// This is an "infinite" precision irange for use in temporary
-// calculations.
-typedef int_range<255> int_range_max;
-
// This is an "infinite" precision range object for use in temporary
// calculations for any of the handled types. The object can be
// transparently used as a vrange.
@@ -757,8 +794,9 @@ gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie)
// Constructors for irange
inline
-irange::irange (wide_int *base, unsigned nranges)
+irange::irange (wide_int *base, unsigned nranges, bool resizable)
: vrange (VR_IRANGE),
+ m_resizable (resizable),
m_max_ranges (nranges)
{
m_base = base;
@@ -767,52 +805,52 @@ irange::irange (wide_int *base, unsigned nranges)
// Constructors for int_range<>.
-template<unsigned N>
+template<unsigned N, bool RESIZABLE>
inline
-int_range<N>::int_range ()
- : irange (m_ranges, N)
+int_range<N, RESIZABLE>::int_range ()
+ : irange (m_ranges, N, RESIZABLE)
{
}
-template<unsigned N>
-int_range<N>::int_range (const int_range &other)
- : irange (m_ranges, N)
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>::int_range (const int_range &other)
+ : irange (m_ranges, N, RESIZABLE)
{
irange::operator= (other);
}
-template<unsigned N>
-int_range<N>::int_range (tree min, tree max, value_range_kind kind)
- : irange (m_ranges, N)
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>::int_range (tree min, tree max, value_range_kind kind)
+ : irange (m_ranges, N, RESIZABLE)
{
irange::set (min, max, kind);
}
-template<unsigned N>
-int_range<N>::int_range (tree type)
- : irange (m_ranges, N)
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>::int_range (tree type)
+ : irange (m_ranges, N, RESIZABLE)
{
set_varying (type);
}
-template<unsigned N>
-int_range<N>::int_range (tree type, const wide_int &wmin, const wide_int &wmax,
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>::int_range (tree type, const wide_int &wmin, const wide_int &wmax,
value_range_kind kind)
- : irange (m_ranges, N)
+ : irange (m_ranges, N, RESIZABLE)
{
set (type, wmin, wmax, kind);
}
-template<unsigned N>
-int_range<N>::int_range (const irange &other)
- : irange (m_ranges, N)
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>::int_range (const irange &other)
+ : irange (m_ranges, N, RESIZABLE)
{
irange::operator= (other);
}
-template<unsigned N>
-int_range<N>&
-int_range<N>::operator= (const int_range &src)
+template<unsigned N, bool RESIZABLE>
+int_range<N, RESIZABLE>&
+int_range<N, RESIZABLE>::operator= (const int_range &src)
{
irange::operator= (src);
return *this;