mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
Implement generic range temporaries.
Now that we have generic ranges, we need a way to define generic local temporaries on the stack for intermediate calculations in the ranger and elsewhere. We need temporaries analogous to int_range_max, but for any of the supported types (currently just integers, but soon integers, pointers, and floats). The Value_Range object is such a temporary. It is designed to be transparently used as a vrange. It shares vrange's abstract API, and implicitly casts itself to a vrange when passed around. The ultimate name will be value_range, but we need to remove legacy first for that to happen. Until then, Value_Range will do. Sample usage is as follows. Instead of: extern void foo (vrange &); int_range_max t; t.set_nonzero (type); foo (t); one does: Value_Range t (type); t.set_nonzero (type); foo (t); You can also delay initialization, for use in loops for example: Value_Range t; ... t.set_type (type); t.set_varying (type); Creating an supported range type, will result in an unsupported_range object being created, which will trap if anything but set_undefined() and undefined_p() are called on it. There's no size penalty for the unsupported_range, since its immutable and can be shared across instances. Since supports_type_p() is called at construction time for each temporary, I've removed the non-zero check from this function, which was mostly unneeded. I fixed the handful of callers that were passing null types, and in the process sped things up a bit. As more range types come about, the Value_Range class will be augmented to support them by adding the relevant bits in the initialization code, etc. Tested on x86-64 & ppc64le Linux. gcc/ChangeLog: * gimple-range-fold.h (gimple_range_type): Check type before calling supports_type_p. * gimple-range-path.cc (path_range_query::range_of_stmt): Same. * value-query.cc (range_query::get_tree_range): Same. * value-range.cc (Value_Range::lower_bound): New. (Value_Range::upper_bound): New. (Value_Range::dump): New. * value-range.h (class Value_Range): New. (irange::supports_type_p): Do not check if type is non-zero.
This commit is contained in:
@@ -81,7 +81,7 @@ gimple_range_type (const gimple *s)
|
||||
type = TREE_TYPE (type);
|
||||
}
|
||||
}
|
||||
if (irange::supports_type_p (type))
|
||||
if (type && irange::supports_type_p (type))
|
||||
return type;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
@@ -755,7 +755,7 @@ path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
|
||||
{
|
||||
tree type = gimple_range_type (stmt);
|
||||
|
||||
if (!irange::supports_type_p (type))
|
||||
if (!type || !irange::supports_type_p (type))
|
||||
return false;
|
||||
|
||||
// If resolving unknowns, fold the statement making use of any
|
||||
|
||||
@@ -249,7 +249,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
|
||||
if (UNARY_CLASS_P (expr))
|
||||
{
|
||||
range_operator *op = range_op_handler (TREE_CODE (expr), type);
|
||||
if (op)
|
||||
tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
|
||||
if (op && irange::supports_type_p (op0_type))
|
||||
{
|
||||
int_range_max r0;
|
||||
range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
|
||||
|
||||
@@ -30,6 +30,42 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "fold-const.h"
|
||||
#include "gimple-range.h"
|
||||
|
||||
// Convenience function only available for integers and pointers.
|
||||
|
||||
wide_int
|
||||
Value_Range::lower_bound () const
|
||||
{
|
||||
if (is_a <irange> (*m_vrange))
|
||||
return as_a <irange> (*m_vrange).lower_bound ();
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
// Convenience function only available for integers and pointers.
|
||||
|
||||
wide_int
|
||||
Value_Range::upper_bound () const
|
||||
{
|
||||
if (is_a <irange> (*m_vrange))
|
||||
return as_a <irange> (*m_vrange).upper_bound ();
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
void
|
||||
Value_Range::dump (FILE *out) const
|
||||
{
|
||||
if (m_vrange)
|
||||
m_vrange->dump (out);
|
||||
else
|
||||
fprintf (out, "NULL");
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION void
|
||||
debug (const Value_Range &r)
|
||||
{
|
||||
r.dump (stderr);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
// Default implementation when none has been defined.
|
||||
|
||||
bool
|
||||
@@ -186,6 +222,8 @@ unsupported_range::fits_p (const vrange &) const
|
||||
return false;
|
||||
}
|
||||
|
||||
unsupported_range Value_Range::m_unsupported;
|
||||
|
||||
// Here we copy between any two irange's. The ranges can be legacy or
|
||||
// multi-ranges, and copying between any combination works correctly.
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ enum value_range_discriminator
|
||||
class vrange
|
||||
{
|
||||
template <typename T> friend bool is_a (vrange &);
|
||||
friend class Value_Range;
|
||||
public:
|
||||
virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
|
||||
virtual tree type () const = 0;
|
||||
@@ -313,6 +314,136 @@ typedef int_range<1> value_range;
|
||||
// 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.
|
||||
|
||||
class Value_Range
|
||||
{
|
||||
public:
|
||||
Value_Range ();
|
||||
Value_Range (const vrange &r);
|
||||
Value_Range (tree type);
|
||||
void set_type (tree type);
|
||||
vrange& operator= (const vrange &);
|
||||
bool operator== (const Value_Range &r) const;
|
||||
bool operator!= (const Value_Range &r) const;
|
||||
operator vrange &();
|
||||
operator const vrange &() const;
|
||||
void dump (FILE *out = stderr) const;
|
||||
|
||||
// Convenience methods for vrange compatability.
|
||||
void set (tree min, tree max, value_range_kind kind = VR_RANGE)
|
||||
{ return m_vrange->set (min, max, kind); }
|
||||
tree type () { return m_vrange->type (); }
|
||||
enum value_range_kind kind () { return m_vrange->kind (); }
|
||||
bool varying_p () const { return m_vrange->varying_p (); }
|
||||
bool undefined_p () const { return m_vrange->undefined_p (); }
|
||||
void set_varying (tree type) { m_vrange->set_varying (type); }
|
||||
void set_undefined () { m_vrange->set_undefined (); }
|
||||
bool union_ (const vrange &r) { return m_vrange->union_ (r); }
|
||||
bool intersect (const vrange &r) { return m_vrange->intersect (r); }
|
||||
bool singleton_p (tree *result = NULL) const
|
||||
{ return m_vrange->singleton_p (result); }
|
||||
bool zero_p () const { return m_vrange->zero_p (); }
|
||||
wide_int lower_bound () const; // For irange/prange compatability.
|
||||
wide_int upper_bound () const; // For irange/prange compatability.
|
||||
private:
|
||||
void init (tree type);
|
||||
static unsupported_range m_unsupported;
|
||||
vrange *m_vrange;
|
||||
int_range_max m_irange;
|
||||
DISABLE_COPY_AND_ASSIGN (Value_Range);
|
||||
};
|
||||
|
||||
inline
|
||||
Value_Range::Value_Range ()
|
||||
{
|
||||
m_vrange = &m_unsupported;
|
||||
}
|
||||
|
||||
// Copy constructor from a vrange.
|
||||
|
||||
inline
|
||||
Value_Range::Value_Range (const vrange &r)
|
||||
{
|
||||
*this = r;
|
||||
}
|
||||
|
||||
// Copy constructor from a TYPE. The range of the temporary is set to
|
||||
// UNDEFINED.
|
||||
|
||||
inline
|
||||
Value_Range::Value_Range (tree type)
|
||||
{
|
||||
init (type);
|
||||
}
|
||||
|
||||
// Initialize object so it is possible to store temporaries of TYPE
|
||||
// into it.
|
||||
|
||||
inline void
|
||||
Value_Range::init (tree type)
|
||||
{
|
||||
gcc_checking_assert (TYPE_P (type));
|
||||
|
||||
if (irange::supports_type_p (type))
|
||||
m_vrange = &m_irange;
|
||||
else
|
||||
m_vrange = &m_unsupported;
|
||||
}
|
||||
|
||||
// Set the temporary to allow storing temporaries of TYPE. The range
|
||||
// of the temporary is set to UNDEFINED.
|
||||
|
||||
inline void
|
||||
Value_Range::set_type (tree type)
|
||||
{
|
||||
init (type);
|
||||
m_vrange->set_undefined ();
|
||||
}
|
||||
|
||||
// Assignment operator for temporaries. Copying incompatible types is
|
||||
// allowed.
|
||||
|
||||
inline vrange &
|
||||
Value_Range::operator= (const vrange &r)
|
||||
{
|
||||
if (is_a <irange> (r))
|
||||
{
|
||||
m_irange = as_a <irange> (r);
|
||||
m_vrange = &m_irange;
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
return *m_vrange;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Value_Range::operator== (const Value_Range &r) const
|
||||
{
|
||||
return *m_vrange == *r.m_vrange;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Value_Range::operator!= (const Value_Range &r) const
|
||||
{
|
||||
return *m_vrange != *r.m_vrange;
|
||||
}
|
||||
|
||||
inline
|
||||
Value_Range::operator vrange &()
|
||||
{
|
||||
return *m_vrange;
|
||||
}
|
||||
|
||||
inline
|
||||
Value_Range::operator const vrange &() const
|
||||
{
|
||||
return *m_vrange;
|
||||
}
|
||||
|
||||
// Returns true for an old-school value_range as described above.
|
||||
inline bool
|
||||
irange::legacy_mode_p () const
|
||||
@@ -451,9 +582,7 @@ irange::nonzero_p () const
|
||||
inline bool
|
||||
irange::supports_type_p (tree type)
|
||||
{
|
||||
if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
|
||||
return type;
|
||||
return false;
|
||||
return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
||||
Reference in New Issue
Block a user