Use precision and sign to compare types for ranges

Sanity check ranges by comparing just SIGN and PRECISION.

	gcc/
	PR tree-optimization/97360
	* gimple-range.h (range_compatible_p): New.
	* gimple-range-gori.cc (is_gimple_logical_p): Use range_compatible_p.
	(range_is_either_true_or_false): Ditto.
	(gori_compute::outgoing_edge_range_p): Cast result to the correct
	type if necessary.
	(logical_stmt_cache::cacheable_p): Use range_compatible_p.
	* gimple-range.cc (gimple_ranger::calc_stmt): Check range_compatible_p
	before casting the range.
	(gimple_ranger::range_on_exit): Use range_compatible_p.
	(gimple_ranger::range_on_edge): Ditto.

	gcc/testsuite/
	* gcc.dg/pr97360-2.c: New test.
This commit is contained in:
Andrew MacLeod 2020-10-19 19:04:40 -04:00
parent f000b7c436
commit 6e02de9461
4 changed files with 52 additions and 11 deletions

View File

@ -552,7 +552,7 @@ is_gimple_logical_p (const gimple *gs)
case BIT_AND_EXPR: case BIT_AND_EXPR:
case BIT_IOR_EXPR: case BIT_IOR_EXPR:
// Bitwise operations on single bits are logical too. // Bitwise operations on single bits are logical too.
if (types_compatible_p (TREE_TYPE (gimple_assign_rhs1 (gs)), if (range_compatible_p (TREE_TYPE (gimple_assign_rhs1 (gs)),
boolean_type_node)) boolean_type_node))
return true; return true;
break; break;
@ -618,7 +618,7 @@ range_is_either_true_or_false (const irange &r)
// This is complicated by the fact that Ada has multi-bit booleans, // This is complicated by the fact that Ada has multi-bit booleans,
// so true can be ~[0, 0] (i.e. [1,MAX]). // so true can be ~[0, 0] (i.e. [1,MAX]).
tree type = r.type (); tree type = r.type ();
gcc_checking_assert (types_compatible_p (type, boolean_type_node)); gcc_checking_assert (range_compatible_p (type, boolean_type_node));
return (r.singleton_p () || !r.contains_p (build_zero_cst (type))); return (r.singleton_p () || !r.contains_p (build_zero_cst (type)));
} }
@ -999,11 +999,20 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name)
// If NAME can be calculated on the edge, use that. // If NAME can be calculated on the edge, use that.
if (m_gori_map->is_export_p (name, e->src)) if (m_gori_map->is_export_p (name, e->src))
return compute_operand_range (r, stmt, lhs, name); {
if (compute_operand_range (r, stmt, lhs, name))
// Otherwise see if NAME is derived from something that can be {
// calculated. This performs no dynamic lookups whatsover, so it is // Sometimes compatible types get interchanged. See PR97360.
// low cost. // Make sure we are returning the type of the thing we asked for.
if (!r.undefined_p () && r.type () != TREE_TYPE (name))
{
gcc_checking_assert (range_compatible_p (r.type (),
TREE_TYPE (name)));
range_cast (r, TREE_TYPE (name));
}
return true;
}
}
return false; return false;
} }
@ -1156,7 +1165,7 @@ bool
logical_stmt_cache::cacheable_p (gimple *stmt, const irange *lhs_range) const logical_stmt_cache::cacheable_p (gimple *stmt, const irange *lhs_range) const
{ {
if (gimple_code (stmt) == GIMPLE_ASSIGN if (gimple_code (stmt) == GIMPLE_ASSIGN
&& types_compatible_p (TREE_TYPE (gimple_assign_lhs (stmt)), && range_compatible_p (TREE_TYPE (gimple_assign_lhs (stmt)),
boolean_type_node) boolean_type_node)
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
{ {

View File

@ -392,8 +392,14 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name)
{ {
if (r.undefined_p ()) if (r.undefined_p ())
return true; return true;
// We sometimes get compatible types copied from operands, make sure
// the correct type is being returned.
if (name && TREE_TYPE (name) != r.type ()) if (name && TREE_TYPE (name) != r.type ())
range_cast (r, TREE_TYPE (name)); {
gcc_checking_assert (range_compatible_p (r.type (),
TREE_TYPE (name)));
range_cast (r, TREE_TYPE (name));
}
return true; return true;
} }
return false; return false;
@ -928,7 +934,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
else else
gcc_assert (range_of_expr (r, name, s)); gcc_assert (range_of_expr (r, name, s));
gcc_checking_assert (r.undefined_p () gcc_checking_assert (r.undefined_p ()
|| types_compatible_p (r.type(), TREE_TYPE (name))); || range_compatible_p (r.type (), TREE_TYPE (name)));
} }
// Calculate a range for NAME on edge E and return it in R. // Calculate a range for NAME on edge E and return it in R.
@ -948,7 +954,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
range_on_exit (r, e->src, name); range_on_exit (r, e->src, name);
gcc_checking_assert (r.undefined_p () gcc_checking_assert (r.undefined_p ()
|| types_compatible_p (r.type(), TREE_TYPE (name))); || range_compatible_p (r.type(), TREE_TYPE (name)));
// Check to see if NAME is defined on edge e. // Check to see if NAME is defined on edge e.
if (m_cache.outgoing_edge_range_p (edge_range, e, name)) if (m_cache.outgoing_edge_range_p (edge_range, e, name))

View File

@ -115,6 +115,18 @@ gimple_range_ssa_p (tree exp)
return NULL_TREE; return NULL_TREE;
} }
// Return true if TYPE1 and TYPE2 are compatible range types.
static inline bool
range_compatible_p (tree type1, tree type2)
{
// types_compatible_p requires conversion in both directions to be useless.
// GIMPLE only requires a cast one way in order to be compatible.
// Ranges really only need the sign and precision to be the same.
return (TYPE_PRECISION (type1) == TYPE_PRECISION (type2)
&& TYPE_SIGN (type1) == TYPE_SIGN (type2));
}
// Return the legacy GCC global range for NAME if it has one, otherwise // Return the legacy GCC global range for NAME if it has one, otherwise
// return VARYING. // return VARYING.

View File

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-O2 " } */
void *a;
void *b(void);
void *e(void);
void *
c() {
void *d;
if (d == b && e())
d = a;
return d;
}