From: Andrew MacLeod Date: Mon, 19 Oct 2020 23:04:40 +0000 (-0400) Subject: Use precision and sign to compare types for ranges X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6e02de946125c36871bd4d8eff21f7f88f01a8aa;p=gcc.git 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. --- diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index c4bfc658319..983f4c97e87 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -552,7 +552,7 @@ is_gimple_logical_p (const gimple *gs) case BIT_AND_EXPR: case BIT_IOR_EXPR: // 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)) return true; 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, // so true can be ~[0, 0] (i.e. [1,MAX]). 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))); } @@ -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 (m_gori_map->is_export_p (name, e->src)) - return 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 - // low cost. + { + if (compute_operand_range (r, stmt, lhs, name)) + { + // Sometimes compatible types get interchanged. See PR97360. + // 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; } @@ -1156,7 +1165,7 @@ bool logical_stmt_cache::cacheable_p (gimple *stmt, const irange *lhs_range) const { 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) && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) { diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 999d631c5ee..e4864ba60f6 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -392,8 +392,14 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name) { if (r.undefined_p ()) 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 ()) - 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 false; @@ -928,7 +934,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) else gcc_assert (range_of_expr (r, name, s)); 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. @@ -948,7 +954,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) range_on_exit (r, e->src, name); 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. if (m_cache.outgoing_edge_range_p (edge_range, e, name)) diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 041dc7c2a97..a6e8793f284 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -115,6 +115,18 @@ gimple_range_ssa_p (tree exp) 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 VARYING. diff --git a/gcc/testsuite/gcc.dg/pr97360-2.c b/gcc/testsuite/gcc.dg/pr97360-2.c new file mode 100644 index 00000000000..48aebf1b100 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr97360-2.c @@ -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; +}