diff --git a/gcc/function-tests.c b/gcc/function-tests.c index 1b8f665cde1..0ac1d37f8ff 100644 --- a/gcc/function-tests.c +++ b/gcc/function-tests.c @@ -581,6 +581,11 @@ test_ranges () push_cfun (fun); range_tests (); range_op_tests (); + + build_cfg (fndecl); + convert_to_ssa (fndecl); + gimple_range_tests (); + pop_cfun (); } diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index cc27574b7b4..c58acf48dfb 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -827,7 +827,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt) { if (!gimple_range_ssa_p (name)) { - get_tree_range (r, name); + get_tree_range (r, name, stmt); return true; } @@ -860,7 +860,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt) } } else - get_tree_range (r, expr); + get_tree_range (r, expr, NULL); return false; } diff --git a/gcc/gimple-range-tests.cc b/gcc/gimple-range-tests.cc new file mode 100644 index 00000000000..9ee4c5aa6cd --- /dev/null +++ b/gcc/gimple-range-tests.cc @@ -0,0 +1,72 @@ +/* Unit tests for GIMPLE range related routines. + Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#if CHECKING_P + +#include "selftest.h" + +namespace selftest { + +// Test ranges of tree expressions. +class test_expr_eval : public gimple_ranger +{ +public: + test_expr_eval () + { + type = integer_type_node; + op0 = make_ssa_name (type); + op1 = make_ssa_name (type); + + // [5,10] + [15,20] => [20, 30] + tree expr = fold_build2 (PLUS_EXPR, type, op0, op1); + int_range<2> expect (build_int_cst (type, 20), build_int_cst (type, 30)); + int_range_max r; + + ASSERT_TRUE (range_of_expr (r, expr)); + ASSERT_TRUE (r == expect); + } + + virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) OVERRIDE + { + if (expr == op0) + { + r.set (build_int_cst (type, 5), build_int_cst (type, 10)); + return true; + } + if (expr == op1) + { + r.set (build_int_cst (type, 15), build_int_cst (type, 20)); + return true; + } + return gimple_ranger::range_of_expr (r, expr); + } + +private: + tree op0, op1, type; +}; + +void +gimple_range_tests () +{ + test_expr_eval e; +} + +} // namespace selftest + +#endif // CHECKING_P diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index af426207092..db8419bc4c6 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -54,16 +54,6 @@ along with GCC; see the file COPYING3. If not see bool fur_source::get_operand (irange &r, tree expr) { - if (!gimple_range_ssa_p (expr)) - return get_tree_range (r, expr); - - // If no query engine is present, simply get the global value. - if (!m_query) - { - r = gimple_range_global (expr); - return true; - } - // First look for a stmt. if (m_stmt) return m_query->range_of_expr (r, expr, m_stmt); @@ -168,56 +158,6 @@ gimple_range_adjustment (irange &res, const gimple *stmt) } } -// Return a range in R for the tree EXPR. Return true if a range is -// representable, and UNDEFINED/false if not. - -bool -get_tree_range (irange &r, tree expr) -{ - tree type; - if (TYPE_P (expr)) - type = expr; - else - type = TREE_TYPE (expr); - - // Return false if the type isn't suported. - if (!irange::supports_type_p (type)) - { - r.set_undefined (); - return false; - } - - switch (TREE_CODE (expr)) - { - case INTEGER_CST: - if (TREE_OVERFLOW_P (expr)) - expr = drop_tree_overflow (expr); - r.set (expr, expr); - return true; - - case SSA_NAME: - r = gimple_range_global (expr); - return true; - - case ADDR_EXPR: - { - // Handle &var which can show up in phi arguments. - bool ov; - if (tree_single_nonzero_warnv_p (expr, &ov)) - { - r = range_nonzero (type); - return true; - } - break; - } - - default: - break; - } - r.set_varying (type); - return true; -} - // Return the base of the RHS of an assignment. static tree @@ -961,7 +901,7 @@ bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) { if (!gimple_range_ssa_p (expr)) - return get_tree_range (r, expr); + return get_tree_range (r, expr, stmt); // If there is no statement, just get the global value. if (!stmt) @@ -1466,3 +1406,5 @@ disable_ranger (struct function *fun) fun->x_range_query = &global_ranges; } + +#include "gimple-range-tests.cc" diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 65f62e4ba9b..02b891fad69 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -159,6 +159,8 @@ inline bool fold_range (irange &r, gimple *s, range_query *q = NULL) { fold_using_range f; + if (q == NULL) + q = get_global_range_query (); fur_source src (q, s); return f.fold_stmt (r, s, src); } @@ -169,13 +171,12 @@ inline bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL) { fold_using_range f; + if (q == NULL) + q = get_global_range_query (); fur_source src (q, on_edge); return f.fold_stmt (r, s, src); } -// Calculate a basic range for a tree node expression. -extern bool get_tree_range (irange &r, tree expr); - // These routines provide a GIMPLE interface to the range-ops code. extern tree gimple_range_operand1 (const gimple *s); extern tree gimple_range_operand2 (const gimple *s); diff --git a/gcc/selftest.h b/gcc/selftest.h index e609117ec2b..80459d63a39 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -249,6 +249,7 @@ extern void predict_c_tests (); extern void pretty_print_c_tests (); extern void range_tests (); extern void range_op_tests (); +extern void gimple_range_tests (); extern void read_rtl_function_c_tests (); extern void rtl_tests_c_tests (); extern void sbitmap_c_tests (); diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 070d706166e..821f224d4ab 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -182,6 +182,86 @@ range_query::~range_query () delete equiv_alloc; } +// Return a range in R for the tree EXPR. Return true if a range is +// representable, and UNDEFINED/false if not. + +bool +range_query::get_tree_range (irange &r, tree expr, gimple *stmt) +{ + tree type; + if (TYPE_P (expr)) + type = expr; + else + type = TREE_TYPE (expr); + + if (!irange::supports_type_p (type)) + { + r.set_undefined (); + return false; + } + if (expr == type) + { + r.set_varying (type); + return true; + } + switch (TREE_CODE (expr)) + { + case INTEGER_CST: + if (TREE_OVERFLOW_P (expr)) + expr = drop_tree_overflow (expr); + r.set (expr, expr); + return true; + + case SSA_NAME: + r = gimple_range_global (expr); + return true; + + case ADDR_EXPR: + { + // Handle &var which can show up in phi arguments. + bool ov; + if (tree_single_nonzero_warnv_p (expr, &ov)) + { + r = range_nonzero (type); + return true; + } + break; + } + + default: + break; + } + if (BINARY_CLASS_P (expr)) + { + range_operator *op = range_op_handler (TREE_CODE (expr), type); + if (op) + { + int_range_max r0, r1; + range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); + range_of_expr (r1, TREE_OPERAND (expr, 1), stmt); + op->fold_range (r, type, r0, r1); + } + else + r.set_varying (type); + return true; + } + if (UNARY_CLASS_P (expr)) + { + range_operator *op = range_op_handler (TREE_CODE (expr), type); + if (op) + { + int_range_max r0; + range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); + op->fold_range (r, type, r0, int_range<1> (type)); + } + else + r.set_varying (type); + return true; + } + r.set_varying (type); + return true; +} + // Return the range for NAME from SSA_NAME_RANGE_INFO. static inline void @@ -355,12 +435,12 @@ get_global_range_query () } bool -global_range_query::range_of_expr (irange &r, tree expr, gimple *) +global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt) { tree type = TREE_TYPE (expr); if (!irange::supports_type_p (type) || !gimple_range_ssa_p (expr)) - return get_tree_range (r, expr); + return get_tree_range (r, expr, stmt); get_range_global (r, expr); diff --git a/gcc/value-query.h b/gcc/value-query.h index d0512e40c5a..77e49e9a906 100644 --- a/gcc/value-query.h +++ b/gcc/value-query.h @@ -100,6 +100,8 @@ public: protected: class value_range_equiv *allocate_value_range_equiv (); void free_value_range_equiv (class value_range_equiv *); + bool get_tree_range (irange &r, tree expr, gimple *stmt); + bool get_arith_expr_range (irange &r, tree expr, gimple *stmt); private: class equiv_allocator *equiv_alloc; diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 3d0be8edb3b..509c8b093c5 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -180,7 +180,7 @@ bool vr_values::range_of_expr (irange &r, tree expr, gimple *stmt) { if (!gimple_range_ssa_p (expr)) - return get_tree_range (r, expr); + return get_tree_range (r, expr, stmt); if (const value_range *vr = get_value_range (expr, stmt)) {