Implement global ranges for all vrange types (SSA_NAME_RANGE_INFO).

Currently SSA_NAME_RANGE_INFO only handles integer ranges, and loses
half the precision in the process because its use of legacy
value_range's.  This patch rewrites all the SSA_NAME_RANGE_INFO
(nonzero bits included) to use the recently contributed
vrange_storage.  With it, we'll be able to efficiently save any ranges
supported by ranger in GC memory.  Presently this will only be
irange's, but shortly we'll add floating ranges and others to the mix.

As per the discussion with the trailing_wide_ints adjustments and
vrange_storage, we'll be able to save integer ranges with a maximum of
5 sub-ranges.  This could be adjusted later if more sub-ranges are
needed (unlikely).

Since this is a behavior changing patch, I would like to take a few
days for discussion, and commit early next week if all goes well.

A few notes.

First, we get rid of the SSA_NAME_ANTI_RANGE_P bit in the SSA_NAME
since we store full resolution ranges.  Perhaps it could be re-used
for something else.

The range_info_def struct is gone in favor of an opaque type handled
by vrange_storage.  It currently supports irange, but will support
frange, prange, etc, in due time.

From the looks of it, set_range_info was an update operation despite
its name, as we improved the nonzero bits with each call, even though
we clobbered the ranges.  Presumably this was because doing a proper
intersect of ranges lost information with the anti-range hack.  We no
longer have this limitation so now we formalize both set_range_info
and set_nonzero_bits to an update operation.  After all, we should
never be losing information, but enhancing it whenever possible.  This
means, that if folks' finger-memory is not offended, as a follow-up,
I'd like to rename set_nonzero_bits and set_range_info to update_*.

I have kept the same global API we had in tree-ssanames.h, with the
caveat that all set operations are now update as discussed above.

There is a 2% performance penalty for evrp and a 3% penalty for VRP
that is coincidentally in line with a previous improvement of the same
amount in the vrange abstraction patchset.  Interestingly, this
penalty is mostly due to the wide int to tree dance we keep doing with
irange and legacy.  In a first draft of this patch where I was
streaming trees directly, there was actually a small improvement
instead.  I hope to get some of the gain back when we move irange's to
wide-ints, though I'm not in a hurry ;-).

Tested and benchmarked on x86-64 Linux.  Tested on ppc64le Linux.

Comments welcome.

gcc/ChangeLog:

	* gimple-range.cc (gimple_ranger::export_global_ranges): Remove
	verification against legacy value_range.
	(gimple_ranger::register_inferred_ranges): Same.
	(gimple_ranger::export_global_ranges): Rename update_global_range
	to set_range_info.
	* tree-core.h (struct range_info_def): Remove.
	(struct irange_storage_slot): New.
	(struct tree_base): Remove SSA_NAME_ANTI_RANGE_P documentation.
	(struct tree_ssa_name): Add vrange_storage support.
	* tree-ssanames.cc (range_info_p): New.
	(range_info_fits_p): New.
	(range_info_alloc): New.
	(range_info_free): New.
	(range_info_get_range): New.
	(range_info_set_range): New.
	(set_range_info_raw): Remove.
	(set_range_info): Adjust to use vrange_storage.
	(set_nonzero_bits): Same.
	(get_nonzero_bits): Same.
	(duplicate_ssa_name_range_info): Remove overload taking
	value_range_kind.
	Rewrite tree overload to use vrange_storage.
	(duplicate_ssa_name_fn): Adjust to use vrange_storage.
	* tree-ssanames.h (struct range_info_def): Remove.
	(set_range_info): Adjust prototype to take vrange.
	* tree-vrp.cc (vrp_asserts::remove_range_assertions): Call
	duplicate_ssa_name_range_info.
	* tree.h (SSA_NAME_ANTI_RANGE_P): Remove.
	(SSA_NAME_RANGE_TYPE): Remove.
	* value-query.cc (get_ssa_name_range_info): Adjust to use
	vrange_storage.
	(update_global_range): Remove.
	(get_range_global): Remove as_a<irange>.
	* value-query.h (update_global_range): Remove.
	* tree-ssa-dom.cc (set_global_ranges_from_unreachable_edges):
	Rename update_global_range to set_range_info.
	* value-range-storage.cc (vrange_storage::alloc_slot): Remove
	gcc_unreachable.
This commit is contained in:
Aldy Hernandez 2022-06-10 15:11:06 +02:00
parent b53ebbc541
commit 0a7e721a64
10 changed files with 149 additions and 237 deletions

View File

@ -468,22 +468,12 @@ gimple_ranger::register_inferred_ranges (gimple *s)
{
Value_Range tmp (TREE_TYPE (lhs));
if (range_of_stmt (tmp, s, lhs) && !tmp.varying_p ()
&& update_global_range (tmp, lhs) && dump_file)
&& set_range_info (lhs, tmp) && dump_file)
{
// ?? This section should be adjusted when non-iranges can
// be exported. For now, the only way update_global_range
// above can succeed is with an irange so this is safe.
value_range vr = as_a <irange> (tmp);
fprintf (dump_file, "Global Exported: ");
print_generic_expr (dump_file, lhs, TDF_SLIM);
fprintf (dump_file, " = ");
vr.dump (dump_file);
int_range_max same = vr;
if (same != as_a <irange> (tmp))
{
fprintf (dump_file, " ... irange was : ");
tmp.dump (dump_file);
}
tmp.dump (dump_file);
fputc ('\n', dump_file);
}
}
@ -509,7 +499,7 @@ gimple_ranger::export_global_ranges ()
&& m_cache.get_global_range (r, name)
&& !r.varying_p())
{
bool updated = update_global_range (r, name);
bool updated = set_range_info (name, r);
if (!updated || !dump_file)
continue;
@ -522,22 +512,10 @@ gimple_ranger::export_global_ranges ()
print_header = false;
}
if (!irange::supports_p (TREE_TYPE (name)))
continue;
vrange &v = r;
value_range vr = as_a <irange> (v);
print_generic_expr (dump_file, name , TDF_SLIM);
fprintf (dump_file, " : ");
vr.dump (dump_file);
r.dump (dump_file);
fprintf (dump_file, "\n");
int_range_max same = vr;
if (same != as_a <irange> (v))
{
fprintf (dump_file, " irange : ");
r.dump (dump_file);
fprintf (dump_file, "\n");
}
}
}
}

View File

@ -33,7 +33,7 @@ struct function;
struct real_value;
struct fixed_value;
struct ptr_info_def;
struct range_info_def;
struct irange_storage_slot;
struct die_struct;
@ -1194,9 +1194,6 @@ struct GTY(()) tree_base {
TRANSACTION_EXPR_OUTER in
TRANSACTION_EXPR
SSA_NAME_ANTI_RANGE_P in
SSA_NAME
MUST_TAIL_CALL in
CALL_EXPR
@ -1594,8 +1591,12 @@ struct GTY(()) tree_ssa_name {
union ssa_name_info_type {
/* Pointer attributes used for alias analysis. */
struct GTY ((tag ("0"))) ptr_info_def *ptr_info;
/* Value range attributes used for zero/sign extension elimination. */
struct GTY ((tag ("1"))) range_info_def *range_info;
/* This holds any range info supported by ranger (except ptr_info
above) and is managed by vrange_storage. */
void * GTY ((skip)) range_info;
/* GTY tag when the range in the range_info slot above satisfies
irange::supports_type_p. */
struct GTY ((tag ("1"))) irange_storage_slot *irange_info;
} GTY ((desc ("%1.typed.type ?" \
"!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info;

View File

@ -1255,7 +1255,7 @@ dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb)
&& !r.varying_p ()
&& !r.undefined_p ())
{
update_global_range (r, name);
set_range_info (name, r);
maybe_set_nonzero_bits (pred_e, name);
}
}

View File

@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "value-query.h"
#include "value-range-storage.h"
/* Rewriting a function into SSA form can create a huge number of SSA_NAMEs,
many of which may be thrown away shortly after their creation if jumps
@ -71,6 +72,74 @@ unsigned int ssa_name_nodes_created;
#define FREE_SSANAMES(fun) (fun)->gimple_df->free_ssanames
#define FREE_SSANAMES_QUEUE(fun) (fun)->gimple_df->free_ssanames_queue
static ggc_vrange_allocator ggc_allocator;
static vrange_storage vstore (&ggc_allocator);
/* Return TRUE if NAME has global range info. */
inline bool
range_info_p (const_tree name)
{
return SSA_NAME_RANGE_INFO (name);
}
/* Return TRUE if R fits in the global range of NAME. */
inline bool
range_info_fits_p (tree name, const vrange &r)
{
gcc_checking_assert (range_info_p (name));
void *mem = SSA_NAME_RANGE_INFO (name);
return vrange_storage::fits_p (mem, r);
}
/* Allocate a new global range for NAME and set it to R. Return the
allocation slot. */
inline void *
range_info_alloc (tree name, const vrange &r)
{
void *mem = vstore.alloc_slot (r);
SSA_NAME_RANGE_INFO (name) = mem;
return mem;
}
/* Free storage allocated for the global range for NAME. */
inline void
range_info_free (tree name)
{
void *mem = SSA_NAME_RANGE_INFO (name);
vstore.free (mem);
}
/* Return the global range for NAME in R. */
inline void
range_info_get_range (tree name, vrange &r)
{
vstore.get_vrange (SSA_NAME_RANGE_INFO (name), r, TREE_TYPE (name));
}
/* Set the global range for NAME from R. Return TRUE if successfull,
or FALSE if we can't set a range of NAME's type. */
inline bool
range_info_set_range (tree name, const vrange &r)
{
if (!range_info_p (name) || !range_info_fits_p (name, r))
{
if (range_info_p (name))
range_info_free (name);
return range_info_alloc (name, r);
}
else
{
vstore.set_vrange (SSA_NAME_RANGE_INFO (name), r);
return true;
}
}
/* Initialize management of SSA_NAMEs to default SIZE. If SIZE is
zero use default. */
@ -343,94 +412,38 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
return t;
}
/* Helper function for set_range_info.
/* Update the range information for NAME, intersecting into an existing
range if applicable. Return TRUE if the range was updated. */
Store range information RANGE_TYPE, MIN, and MAX to tree ssa_name
NAME. */
void
set_range_info_raw (tree name, enum value_range_kind range_type,
const wide_int_ref &min, const wide_int_ref &max)
bool
set_range_info (tree name, const vrange &r)
{
gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
gcc_assert (range_type == VR_RANGE || range_type == VR_ANTI_RANGE);
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
unsigned int precision = TYPE_PRECISION (TREE_TYPE (name));
/* Allocate if not available. */
if (ri == NULL)
{
size_t size = (sizeof (range_info_def)
+ trailing_wide_ints <3>::extra_size (precision));
ri = static_cast<range_info_def *> (ggc_internal_alloc (size));
ri->ints.set_precision (precision);
SSA_NAME_RANGE_INFO (name) = ri;
ri->set_nonzero_bits (wi::shwi (-1, precision));
}
/* Record the range type. */
if (SSA_NAME_RANGE_TYPE (name) != range_type)
SSA_NAME_ANTI_RANGE_P (name) = (range_type == VR_ANTI_RANGE);
/* Set the values. */
ri->set_min (min);
ri->set_max (max);
/* If it is a range, try to improve nonzero_bits from the min/max. */
if (range_type == VR_RANGE)
{
wide_int xorv = ri->get_min () ^ ri->get_max ();
if (xorv != 0)
xorv = wi::mask (precision - wi::clz (xorv), false, precision);
ri->set_nonzero_bits (ri->get_nonzero_bits () & (ri->get_min () | xorv));
}
}
/* Store range information RANGE_TYPE, MIN, and MAX to tree ssa_name
NAME while making sure we don't store useless range info. */
static void
set_range_info (tree name, enum value_range_kind range_type,
const wide_int_ref &min, const wide_int_ref &max)
{
gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
if (r.undefined_p () || r.varying_p ())
return false;
tree type = TREE_TYPE (name);
if (range_type == VR_VARYING)
if (POINTER_TYPE_P (type))
{
/* SSA_NAME_RANGE_TYPE can only hold a VR_RANGE or
VR_ANTI_RANGE. Denormalize VR_VARYING to VR_RANGE. */
range_type = VR_RANGE;
gcc_checking_assert (min == wi::min_value (type));
gcc_checking_assert (max == wi::max_value (type));
}
/* A range of the entire domain is really no range at all. */
if (min == wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type))
&& max == wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
{
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
if (ri == NULL)
return;
if (ri->get_nonzero_bits () == -1)
if (r.nonzero_p ())
{
ggc_free (ri);
SSA_NAME_RANGE_INFO (name) = NULL;
return;
set_ptr_nonnull (name);
return true;
}
return false;
}
set_range_info_raw (name, range_type, min, max);
}
/* If a global range already exists, incorporate it. */
if (range_info_p (name))
{
Value_Range tmp (type);
range_info_get_range (name, tmp);
tmp.intersect (r);
if (tmp.undefined_p ())
return false;
/* Store range information for NAME from a value_range. */
void
set_range_info (tree name, const value_range &vr)
{
wide_int min = wi::to_wide (vr.min ());
wide_int max = wi::to_wide (vr.max ());
set_range_info (name, vr.kind (), min, max);
return range_info_set_range (name, tmp);
}
return range_info_set_range (name, r);
}
/* Set nonnull attribute to pointer NAME. */
@ -443,22 +456,16 @@ set_ptr_nonnull (tree name)
pi->pt.null = 0;
}
/* Change non-zero bits bitmask of NAME. */
/* Update the non-zero bits bitmask of NAME. */
void
set_nonzero_bits (tree name, const wide_int_ref &mask)
{
gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
if (SSA_NAME_RANGE_INFO (name) == NULL)
{
if (mask == -1)
return;
set_range_info_raw (name, VR_RANGE,
wi::to_wide (TYPE_MIN_VALUE (TREE_TYPE (name))),
wi::to_wide (TYPE_MAX_VALUE (TREE_TYPE (name))));
}
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
ri->set_nonzero_bits (mask);
int_range<2> r (TREE_TYPE (name));
r.set_nonzero_bits (mask);
set_range_info (name, r);
}
/* Return a widest_int with potentially non-zero bits in SSA_NAME
@ -482,10 +489,15 @@ get_nonzero_bits (const_tree name)
return wi::shwi (-1, precision);
}
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
if (!ri)
if (!range_info_p (name))
return wi::shwi (-1, precision);
/* Optimization to get at the nonzero bits because we know the
storage type. This saves us measurable time compared to going
through vrange_storage. */
gcc_checking_assert (irange::supports_p (TREE_TYPE (name)));
irange_storage_slot *ri
= static_cast <irange_storage_slot *> (SSA_NAME_RANGE_INFO (name));
return ri->get_nonzero_bits ();
}
@ -727,38 +739,18 @@ duplicate_ssa_name_ptr_info (tree name, struct ptr_info_def *ptr_info)
SSA_NAME_PTR_INFO (name) = new_ptr_info;
}
/* Creates a duplicate of the range_info_def at RANGE_INFO of type
RANGE_TYPE for use by the SSA name NAME. */
static void
duplicate_ssa_name_range_info (tree name, enum value_range_kind range_type,
struct range_info_def *range_info)
{
struct range_info_def *new_range_info;
gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
gcc_assert (!SSA_NAME_RANGE_INFO (name));
if (!range_info)
return;
unsigned int precision = TYPE_PRECISION (TREE_TYPE (name));
size_t size = (sizeof (range_info_def)
+ trailing_wide_ints <3>::extra_size (precision));
new_range_info = static_cast<range_info_def *> (ggc_internal_alloc (size));
memcpy (new_range_info, range_info, size);
gcc_assert (range_type == VR_RANGE || range_type == VR_ANTI_RANGE);
SSA_NAME_ANTI_RANGE_P (name) = (range_type == VR_ANTI_RANGE);
SSA_NAME_RANGE_INFO (name) = new_range_info;
}
void
duplicate_ssa_name_range_info (tree name, tree src)
{
gcc_checking_assert (!POINTER_TYPE_P (TREE_TYPE (src)));
duplicate_ssa_name_range_info (name,
SSA_NAME_RANGE_TYPE (src),
SSA_NAME_RANGE_INFO (src));
gcc_checking_assert (!range_info_p (name));
if (range_info_p (src))
{
Value_Range src_range (TREE_TYPE (src));
range_info_get_range (src, src_range);
range_info_set_range (name, src_range);
}
}
@ -776,14 +768,8 @@ duplicate_ssa_name_fn (struct function *fn, tree name, gimple *stmt)
if (old_ptr_info)
duplicate_ssa_name_ptr_info (new_name, old_ptr_info);
}
else
{
struct range_info_def *old_range_info = SSA_NAME_RANGE_INFO (name);
if (old_range_info)
duplicate_ssa_name_range_info (new_name, SSA_NAME_RANGE_TYPE (name),
old_range_info);
}
else if (range_info_p (name))
duplicate_ssa_name_range_info (new_name, name);
return new_name;
}

View File

@ -45,16 +45,6 @@ struct GTY(()) ptr_info_def
unsigned int misalign;
};
/* Value range information for SSA_NAMEs representing non-pointer variables. */
struct GTY ((variable_size)) range_info_def {
/* Minimum, maximum and nonzero bits. */
TRAILING_WIDE_INT_ACCESSOR (min, ints, 0)
TRAILING_WIDE_INT_ACCESSOR (max, ints, 1)
TRAILING_WIDE_INT_ACCESSOR (nonzero_bits, ints, 2)
trailing_wide_ints <3> ints;
};
#define SSANAMES(fun) (fun)->gimple_df->ssa_names
#define DEFAULT_DEFS(fun) (fun)->gimple_df->default_defs
@ -67,7 +57,7 @@ struct GTY ((variable_size)) range_info_def {
if (VAR)
/* Sets the value range to SSA. */
extern void set_range_info (tree, const value_range &);
extern bool set_range_info (tree, const vrange &);
extern void set_nonzero_bits (tree, const wide_int_ref &);
extern wide_int get_nonzero_bits (const_tree);
extern bool ssa_name_has_boolean_range (tree);

View File

@ -3739,16 +3739,18 @@ vrp_asserts::remove_range_assertions ()
&& all_imm_uses_in_stmt_or_feed_cond (var, stmt,
single_pred (bb)))
{
/* We could use duplicate_ssa_name_range_info here
instead of peeking inside SSA_NAME_RANGE_INFO,
but the aforementioned asserts that the
destination has no global range. This is
slated for removal anyhow. */
value_range r (TREE_TYPE (lhs),
SSA_NAME_RANGE_INFO (lhs)->get_min (),
SSA_NAME_RANGE_INFO (lhs)->get_max (),
SSA_NAME_RANGE_TYPE (lhs));
set_range_info (var, r);
if (SSA_NAME_RANGE_INFO (var))
{
/* ?? This is a minor wart exposing the
internals of SSA_NAME_RANGE_INFO in order
to maintain existing behavior. This is
because duplicate_ssa_name_range_info below
needs a NULL destination range. This is
all slated for removal... */
ggc_free (SSA_NAME_RANGE_INFO (var));
SSA_NAME_RANGE_INFO (var) = NULL;
}
duplicate_ssa_name_range_info (var, lhs);
maybe_set_nonzero_bits (single_pred_edge (bb), var);
}
}

View File

@ -2030,14 +2030,6 @@ class auto_suppress_location_wrappers
#define SSA_NAME_PTR_INFO(N) \
SSA_NAME_CHECK (N)->ssa_name.info.ptr_info
/* True if SSA_NAME_RANGE_INFO describes an anti-range. */
#define SSA_NAME_ANTI_RANGE_P(N) \
SSA_NAME_CHECK (N)->base.static_flag
/* The type of range described by SSA_NAME_RANGE_INFO. */
#define SSA_NAME_RANGE_TYPE(N) \
(SSA_NAME_ANTI_RANGE_P (N) ? VR_ANTI_RANGE : VR_RANGE)
/* Value range info attributes for SSA_NAMEs of non pointer-type variables. */
#define SSA_NAME_RANGE_INFO(N) \
SSA_NAME_CHECK (N)->ssa_name.info.range_info

View File

@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "value-query.h"
#include "alloc-pool.h"
#include "gimple-range.h"
#include "value-range-storage.h"
// value_query default methods.
@ -271,13 +272,13 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
// Return the range for NAME from SSA_NAME_RANGE_INFO.
static inline void
get_ssa_name_range_info (irange &r, const_tree name)
get_ssa_name_range_info (vrange &r, const_tree name)
{
tree type = TREE_TYPE (name);
gcc_checking_assert (!POINTER_TYPE_P (type));
gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
void *ri = SSA_NAME_RANGE_INFO (name);
// Return VR_VARYING for SSA_NAMEs with NULL RANGE_INFO or SSA_NAMEs
// with integral types width > 2 * HOST_BITS_PER_WIDE_INT precision.
@ -285,9 +286,10 @@ get_ssa_name_range_info (irange &r, const_tree name)
> 2 * HOST_BITS_PER_WIDE_INT))
r.set_varying (type);
else
r.set (wide_int_to_tree (type, ri->get_min ()),
wide_int_to_tree (type, ri->get_max ()),
SSA_NAME_RANGE_TYPE (name));
{
vrange_storage vstore (NULL);
vstore.get_vrange (ri, r, TREE_TYPE (name));
}
}
// Return nonnull attribute of pointer NAME from SSA_NAME_PTR_INFO.
@ -311,43 +313,6 @@ get_ssa_name_ptr_info_nonnull (const_tree name)
}
// Update the global range for NAME into the SSA_RANGE_NAME_INFO and
// SSA_NAME_PTR_INFO fields. Return TRUE if the range for NAME was
// updated.
bool
update_global_range (vrange &r, tree name)
{
tree type = TREE_TYPE (name);
if (r.undefined_p () || r.varying_p ())
return false;
if (INTEGRAL_TYPE_P (type))
{
// If a global range already exists, incorporate it.
if (SSA_NAME_RANGE_INFO (name))
{
value_range glob;
get_ssa_name_range_info (glob, name);
r.intersect (glob);
}
if (r.undefined_p ())
return false;
set_range_info (name, as_a <irange> (r));
return true;
}
else if (POINTER_TYPE_P (type))
{
if (r.nonzero_p ())
{
set_ptr_nonnull (name);
return true;
}
}
return false;
}
// Return the legacy global range for NAME if it has one, otherwise
// return VARYING.
@ -372,7 +337,7 @@ get_range_global (vrange &r, tree name)
r.set_nonzero (type);
else if (INTEGRAL_TYPE_P (type))
{
get_ssa_name_range_info (as_a <irange> (r), name);
get_ssa_name_range_info (r, name);
if (r.undefined_p ())
r.set_varying (type);
}
@ -387,8 +352,7 @@ get_range_global (vrange &r, tree name)
}
else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
{
gcc_checking_assert (irange::supports_p (TREE_TYPE (name)));
get_ssa_name_range_info (as_a <irange> (r), name);
get_ssa_name_range_info (r, name);
if (r.undefined_p ())
r.set_varying (type);
}

View File

@ -144,6 +144,5 @@ get_range_query (const struct function *fun)
}
extern void gimple_range_global (vrange &v, tree name);
extern bool update_global_range (vrange &v, tree name);
#endif // GCC_QUERY_H

View File

@ -30,7 +30,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-range.h"
#include "value-range-storage.h"
// Return a newly allocated slot holding R.
// Return a newly allocated slot holding R, or NULL if storing a range
// of R's type is not supported.
void *
vrange_storage::alloc_slot (const vrange &r)
@ -40,7 +41,6 @@ vrange_storage::alloc_slot (const vrange &r)
if (is_a <irange> (r))
return irange_storage_slot::alloc_slot (*m_alloc, as_a <irange> (r));
gcc_unreachable ();
return NULL;
}