From 8bd7380106a0505f45fb9d81a8c4e878618c36b4 Mon Sep 17 00:00:00 2001 From: law Date: Mon, 20 Nov 2017 17:44:45 +0000 Subject: [PATCH] * Makefile.in (OBJS): Add gimple-ssa-evrp-analyze.o. * gimple-ssa-evrp-analyze.c: New file pulled from gimple-ssa-evrp.c. * gimple-ssa-evrp-analyze.h: New file pulled from gimple-ssa-evrp.c. * gimple-ssa-evrp.c: Remove bits moved into new files. Include gimple-ssa-evrp-analyze.h. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@254961 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 6 + gcc/Makefile.in | 1 + gcc/gimple-ssa-evrp-analyze.c | 343 ++++++++++++++++++++++++++++++++++++++++ gcc/gimple-ssa-evrp-analyze.h | 71 +++++++++ gcc/gimple-ssa-evrp.c | 353 +----------------------------------------- 5 files changed, 422 insertions(+), 352 deletions(-) create mode 100644 gcc/gimple-ssa-evrp-analyze.c create mode 100644 gcc/gimple-ssa-evrp-analyze.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dacc9d03b7a..05b3e656b87 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2017-11-20 Jeff Law + * Makefile.in (OBJS): Add gimple-ssa-evrp-analyze.o. + * gimple-ssa-evrp-analyze.c: New file pulled from gimple-ssa-evrp.c. + * gimple-ssa-evrp-analyze.h: New file pulled from gimple-ssa-evrp.c. + * gimple-ssa-evrp.c: Remove bits moved into new files. Include + gimple-ssa-evrp-analyze.h. + * gimple-ssa-evrp.c (evrp_dom_walker::before_dom_children): Do not set BB_VISITED here. (evrp_range_analyzer::enter): Set BB_VISITED here instead. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 5db78558c0c..38ab4e81026 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1302,6 +1302,7 @@ OBJS = \ gimple-pretty-print.o \ gimple-ssa-backprop.o \ gimple-ssa-evrp.o \ + gimple-ssa-evrp-analyze.o \ gimple-ssa-isolate-paths.o \ gimple-ssa-nonnull-compare.o \ gimple-ssa-split-paths.o \ diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c new file mode 100644 index 00000000000..9e581834d08 --- /dev/null +++ b/gcc/gimple-ssa-evrp-analyze.c @@ -0,0 +1,343 @@ +/* Support routines for Value Range Propagation (VRP). + Copyright (C) 2005-2017 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "cfganal.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "tree-ssa-loop-manip.h" +#include "tree-ssa-loop.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" +#include "tree-ssa-propagate.h" +#include "alloc-pool.h" +#include "domwalk.h" +#include "tree-cfgcleanup.h" +#include "vr-values.h" +#include "gimple-ssa-evrp-analyze.h" + +evrp_range_analyzer::evrp_range_analyzer () : stack (10) +{ + edge e; + edge_iterator ei; + basic_block bb; + FOR_EACH_BB_FN (bb, cfun) + { + bb->flags &= ~BB_VISITED; + FOR_EACH_EDGE (e, ei, bb->preds) + e->flags |= EDGE_EXECUTABLE; + } +} + +void +evrp_range_analyzer::enter (basic_block bb) +{ + stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL)); + record_ranges_from_incoming_edge (bb); + record_ranges_from_phis (bb); + bb->flags |= BB_VISITED; +} + +/* Find new range for NAME such that (OP CODE LIMIT) is true. */ +value_range * +evrp_range_analyzer::try_find_new_range (tree name, + tree op, tree_code code, tree limit) +{ + value_range vr = VR_INITIALIZER; + value_range *old_vr = get_value_range (name); + + /* Discover VR when condition is true. */ + extract_range_for_var_from_comparison_expr (name, code, op, + limit, &vr); + /* If we found any usable VR, set the VR to ssa_name and create a + PUSH old value in the stack with the old VR. */ + if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) + { + if (old_vr->type == vr.type + && vrp_operand_equal_p (old_vr->min, vr.min) + && vrp_operand_equal_p (old_vr->max, vr.max)) + return NULL; + value_range *new_vr = vr_values.vrp_value_range_pool.allocate (); + *new_vr = vr; + return new_vr; + } + return NULL; +} + +void +evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb) +{ + edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); + if (pred_e) + { + gimple *stmt = last_stmt (pred_e->src); + tree op0 = NULL_TREE; + + if (stmt + && gimple_code (stmt) == GIMPLE_COND + && (op0 = gimple_cond_lhs (stmt)) + && TREE_CODE (op0) == SSA_NAME + && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) + || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Visiting controlling predicate "); + print_gimple_stmt (dump_file, stmt, 0); + } + /* Entering a new scope. Try to see if we can find a VR + here. */ + tree op1 = gimple_cond_rhs (stmt); + if (TREE_OVERFLOW_P (op1)) + op1 = drop_tree_overflow (op1); + tree_code code = gimple_cond_code (stmt); + + auto_vec asserts; + register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); + if (TREE_CODE (op1) == SSA_NAME) + register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); + + auto_vec, 8> vrs; + for (unsigned i = 0; i < asserts.length (); ++i) + { + value_range *vr = try_find_new_range (asserts[i].name, + asserts[i].expr, + asserts[i].comp_code, + asserts[i].val); + if (vr) + vrs.safe_push (std::make_pair (asserts[i].name, vr)); + } + /* Push updated ranges only after finding all of them to avoid + ordering issues that can lead to worse ranges. */ + for (unsigned i = 0; i < vrs.length (); ++i) + push_value_range (vrs[i].first, vrs[i].second); + } + } +} + +void +evrp_range_analyzer::record_ranges_from_phis (basic_block bb) +{ + /* Visit PHI stmts and discover any new VRs possible. */ + bool has_unvisited_preds = false; + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->preds) + if (e->flags & EDGE_EXECUTABLE + && !(e->src->flags & BB_VISITED)) + { + has_unvisited_preds = true; + break; + } + + for (gphi_iterator gpi = gsi_start_phis (bb); + !gsi_end_p (gpi); gsi_next (&gpi)) + { + gphi *phi = gpi.phi (); + tree lhs = PHI_RESULT (phi); + if (virtual_operand_p (lhs)) + continue; + + value_range vr_result = VR_INITIALIZER; + bool interesting = stmt_interesting_for_vrp (phi); + if (!has_unvisited_preds && interesting) + extract_range_from_phi_node (phi, &vr_result); + else + { + set_value_range_to_varying (&vr_result); + /* When we have an unvisited executable predecessor we can't + use PHI arg ranges which may be still UNDEFINED but have + to use VARYING for them. But we can still resort to + SCEV for loop header PHIs. */ + struct loop *l; + if (interesting + && (l = loop_containing_stmt (phi)) + && l->header == gimple_bb (phi)) + adjust_range_with_scev (&vr_result, l, phi, lhs); + } + update_value_range (lhs, &vr_result); + + /* Set the SSA with the value range. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) + { + if ((vr_result.type == VR_RANGE + || vr_result.type == VR_ANTI_RANGE) + && (TREE_CODE (vr_result.min) == INTEGER_CST) + && (TREE_CODE (vr_result.max) == INTEGER_CST)) + set_range_info (lhs, vr_result.type, + wi::to_wide (vr_result.min), + wi::to_wide (vr_result.max)); + } + else if (POINTER_TYPE_P (TREE_TYPE (lhs)) + && ((vr_result.type == VR_RANGE + && range_includes_zero_p (vr_result.min, + vr_result.max) == 0) + || (vr_result.type == VR_ANTI_RANGE + && range_includes_zero_p (vr_result.min, + vr_result.max) == 1))) + set_ptr_nonnull (lhs); + } +} + +void +evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt) +{ + tree output = NULL_TREE; + + if (dyn_cast (stmt)) + ; + else if (stmt_interesting_for_vrp (stmt)) + { + edge taken_edge; + value_range vr = VR_INITIALIZER; + extract_range_from_stmt (stmt, &taken_edge, &output, &vr); + if (output + && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)) + { + update_value_range (output, &vr); + + /* Set the SSA with the value range. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (output))) + { + if ((vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) + && (TREE_CODE (vr.min) == INTEGER_CST) + && (TREE_CODE (vr.max) == INTEGER_CST)) + set_range_info (output, vr.type, + wi::to_wide (vr.min), + wi::to_wide (vr.max)); + } + else if (POINTER_TYPE_P (TREE_TYPE (output)) + && ((vr.type == VR_RANGE + && range_includes_zero_p (vr.min, vr.max) == 0) + || (vr.type == VR_ANTI_RANGE + && range_includes_zero_p (vr.min, vr.max) == 1))) + set_ptr_nonnull (output); + } + else + set_defs_to_varying (stmt); + } + else + set_defs_to_varying (stmt); + + /* See if we can derive a range for any of STMT's operands. */ + tree op; + ssa_op_iter i; + FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) + { + tree value; + enum tree_code comp_code; + + /* If OP is used in such a way that we can infer a value + range for it, and we don't find a previous assertion for + it, create a new assertion location node for OP. */ + if (infer_value_range (stmt, op, &comp_code, &value)) + { + /* If we are able to infer a nonzero value range for OP, + then walk backwards through the use-def chain to see if OP + was set via a typecast. + If so, then we can also infer a nonzero value range + for the operand of the NOP_EXPR. */ + if (comp_code == NE_EXPR && integer_zerop (value)) + { + tree t = op; + gimple *def_stmt = SSA_NAME_DEF_STMT (t); + while (is_gimple_assign (def_stmt) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) + && TREE_CODE + (gimple_assign_rhs1 (def_stmt)) == SSA_NAME + && POINTER_TYPE_P + (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))) + { + t = gimple_assign_rhs1 (def_stmt); + def_stmt = SSA_NAME_DEF_STMT (t); + + /* Add VR when (T COMP_CODE value) condition is + true. */ + value_range *op_range + = try_find_new_range (t, t, comp_code, value); + if (op_range) + push_value_range (t, op_range); + } + } + /* Add VR when (OP COMP_CODE value) condition is true. */ + value_range *op_range = try_find_new_range (op, op, + comp_code, value); + if (op_range) + push_value_range (op, op_range); + } + } +} + +/* Restore/pop VRs valid only for BB when we leave BB. */ + +void +evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED) +{ + gcc_checking_assert (!stack.is_empty ()); + while (stack.last ().first != NULL_TREE) + pop_value_range (stack.last ().first); + stack.pop (); +} + +/* Push the Value Range of VAR to the stack and update it with new VR. */ + +void +evrp_range_analyzer::push_value_range (tree var, value_range *vr) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "pushing new range for "); + print_generic_expr (dump_file, var); + fprintf (dump_file, ": "); + dump_value_range (dump_file, vr); + fprintf (dump_file, "\n"); + } + stack.safe_push (std::make_pair (var, get_value_range (var))); + set_vr_value (var, vr); +} + +/* Pop the Value Range from the vrp_stack and update VAR with it. */ + +value_range * +evrp_range_analyzer::pop_value_range (tree var) +{ + value_range *vr = stack.last ().second; + gcc_checking_assert (var == stack.last ().first); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "popping range for "); + print_generic_expr (dump_file, var); + fprintf (dump_file, ", restoring "); + dump_value_range (dump_file, vr); + fprintf (dump_file, "\n"); + } + set_vr_value (var, vr); + stack.pop (); + return vr; +} diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h new file mode 100644 index 00000000000..2e6c609c45b --- /dev/null +++ b/gcc/gimple-ssa-evrp-analyze.h @@ -0,0 +1,71 @@ +/* Support routines for Value Range Propagation (VRP). + Copyright (C) 2016-2017 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 +. */ + +#ifndef GCC_GIMPLE_SSA_EVRP_ANALYZE_H +#define GCC_GIMPLE_SSA_EVRP_ANALYZE_H + +class evrp_range_analyzer +{ + public: + evrp_range_analyzer (void); + ~evrp_range_analyzer (void) { stack.release (); } + + void enter (basic_block); + void leave (basic_block); + void record_ranges_from_stmt (gimple *); + + class vr_values vr_values; + + private: + DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer); + void push_value_range (tree var, value_range *vr); + value_range *pop_value_range (tree var); + value_range *try_find_new_range (tree, tree op, tree_code code, tree limit); + void record_ranges_from_incoming_edge (basic_block); + void record_ranges_from_phis (basic_block); + + /* STACK holds the old VR. */ + auto_vec > stack; + + /* Temporary delegators. */ + value_range *get_value_range (const_tree op) + { return vr_values.get_value_range (op); } + bool update_value_range (const_tree op, value_range *vr) + { return vr_values.update_value_range (op, vr); } + void extract_range_from_phi_node (gphi *phi, value_range *vr) + { vr_values.extract_range_from_phi_node (phi, vr); } + void adjust_range_with_scev (value_range *vr, struct loop *loop, + gimple *stmt, tree var) + { vr_values.adjust_range_with_scev (vr, loop, stmt, var); } + void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p, + tree *output_p, value_range *vr) + { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); } + void set_defs_to_varying (gimple *stmt) + { return vr_values.set_defs_to_varying (stmt); } + void set_vr_value (tree name, value_range *vr) + { vr_values.set_vr_value (name, vr); } + void extract_range_for_var_from_comparison_expr (tree var, + enum tree_code cond_code, + tree op, tree limit, + value_range *vr_p) + { vr_values.extract_range_for_var_from_comparison_expr (var, cond_code, + op, limit, vr_p); } +}; + +#endif /* GCC_GIMPLE_SSA_EVRP_ANALYZE_H */ diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c index 8afec31e76b..27a983dd9ae 100644 --- a/gcc/gimple-ssa-evrp.c +++ b/gcc/gimple-ssa-evrp.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "domwalk.h" #include "tree-cfgcleanup.h" #include "vr-values.h" +#include "gimple-ssa-evrp-analyze.h" class evrp_folder : public substitute_and_fold_engine { @@ -55,69 +56,6 @@ evrp_folder::get_value (tree op) return vr_values->op_with_constant_singleton_value_range (op); } -class evrp_range_analyzer -{ - public: - evrp_range_analyzer (void); - ~evrp_range_analyzer (void) { stack.release (); } - - void enter (basic_block); - void leave (basic_block); - void record_ranges_from_stmt (gimple *); - - class vr_values vr_values; - - private: - DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer); - void push_value_range (tree var, value_range *vr); - value_range *pop_value_range (tree var); - value_range *try_find_new_range (tree, tree op, tree_code code, tree limit); - void record_ranges_from_incoming_edge (basic_block); - void record_ranges_from_phis (basic_block); - - /* STACK holds the old VR. */ - auto_vec > stack; - - /* Temporary delegators. */ - value_range *get_value_range (const_tree op) - { return vr_values.get_value_range (op); } - bool update_value_range (const_tree op, value_range *vr) - { return vr_values.update_value_range (op, vr); } - void extract_range_from_phi_node (gphi *phi, value_range *vr) - { vr_values.extract_range_from_phi_node (phi, vr); } - void adjust_range_with_scev (value_range *vr, struct loop *loop, - gimple *stmt, tree var) - { vr_values.adjust_range_with_scev (vr, loop, stmt, var); } - void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p, - tree *output_p, value_range *vr) - { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); } - void set_defs_to_varying (gimple *stmt) - { return vr_values.set_defs_to_varying (stmt); } - void set_vr_value (tree name, value_range *vr) - { vr_values.set_vr_value (name, vr); } - void extract_range_for_var_from_comparison_expr (tree var, - enum tree_code cond_code, - tree op, tree limit, - value_range *vr_p) - { vr_values.extract_range_for_var_from_comparison_expr (var, cond_code, - op, limit, vr_p); } -}; - -evrp_range_analyzer::evrp_range_analyzer () : stack (10) -{ - edge e; - edge_iterator ei; - basic_block bb; - - FOR_EACH_BB_FN (bb, cfun) - { - bb->flags &= ~BB_VISITED; - FOR_EACH_EDGE (e, ei, bb->preds) - e->flags |= EDGE_EXECUTABLE; - } -} - - /* evrp_dom_walker visits the basic blocks in the dominance order and set the Value Ranges (VR) for SSA_NAMEs in the scope. Use this VR to discover more VRs. */ @@ -154,247 +92,6 @@ public: { evrp_range_analyzer.vr_values.vrp_visit_cond_stmt (cond, e); } }; -void -evrp_range_analyzer::enter (basic_block bb) -{ - stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL)); - record_ranges_from_incoming_edge (bb); - record_ranges_from_phis (bb); - bb->flags |= BB_VISITED; -} - -/* Find new range for NAME such that (OP CODE LIMIT) is true. */ -value_range * -evrp_range_analyzer::try_find_new_range (tree name, - tree op, tree_code code, tree limit) -{ - value_range vr = VR_INITIALIZER; - value_range *old_vr = get_value_range (name); - - /* Discover VR when condition is true. */ - extract_range_for_var_from_comparison_expr (name, code, op, - limit, &vr); - /* If we found any usable VR, set the VR to ssa_name and create a - PUSH old value in the stack with the old VR. */ - if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) - { - if (old_vr->type == vr.type - && vrp_operand_equal_p (old_vr->min, vr.min) - && vrp_operand_equal_p (old_vr->max, vr.max)) - return NULL; - value_range *new_vr = vr_values.vrp_value_range_pool.allocate (); - *new_vr = vr; - return new_vr; - } - return NULL; -} - -/* If BB is reached by a single incoming edge (ignoring loop edges), - then derive ranges implied by traversing that edge. */ - -void -evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb) -{ - edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); - if (pred_e) - { - gimple *stmt = last_stmt (pred_e->src); - tree op0 = NULL_TREE; - - if (stmt - && gimple_code (stmt) == GIMPLE_COND - && (op0 = gimple_cond_lhs (stmt)) - && TREE_CODE (op0) == SSA_NAME - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Visiting controlling predicate "); - print_gimple_stmt (dump_file, stmt, 0); - } - /* Entering a new scope. Try to see if we can find a VR - here. */ - tree op1 = gimple_cond_rhs (stmt); - if (TREE_OVERFLOW_P (op1)) - op1 = drop_tree_overflow (op1); - tree_code code = gimple_cond_code (stmt); - - auto_vec asserts; - register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); - if (TREE_CODE (op1) == SSA_NAME) - register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); - - auto_vec, 8> vrs; - for (unsigned i = 0; i < asserts.length (); ++i) - { - value_range *vr = try_find_new_range (asserts[i].name, - asserts[i].expr, - asserts[i].comp_code, - asserts[i].val); - if (vr) - vrs.safe_push (std::make_pair (asserts[i].name, vr)); - } - /* Push updated ranges only after finding all of them to avoid - ordering issues that can lead to worse ranges. */ - for (unsigned i = 0; i < vrs.length (); ++i) - push_value_range (vrs[i].first, vrs[i].second); - } - } -} - -void -evrp_range_analyzer::record_ranges_from_phis (basic_block bb) -{ - /* Visit PHI stmts and discover any new VRs possible. */ - bool has_unvisited_preds = false; - edge_iterator ei; - edge e; - FOR_EACH_EDGE (e, ei, bb->preds) - if (e->flags & EDGE_EXECUTABLE - && !(e->src->flags & BB_VISITED)) - { - has_unvisited_preds = true; - break; - } - - for (gphi_iterator gpi = gsi_start_phis (bb); - !gsi_end_p (gpi); gsi_next (&gpi)) - { - gphi *phi = gpi.phi (); - tree lhs = PHI_RESULT (phi); - if (virtual_operand_p (lhs)) - continue; - - value_range vr_result = VR_INITIALIZER; - bool interesting = stmt_interesting_for_vrp (phi); - if (!has_unvisited_preds && interesting) - extract_range_from_phi_node (phi, &vr_result); - else - { - set_value_range_to_varying (&vr_result); - /* When we have an unvisited executable predecessor we can't - use PHI arg ranges which may be still UNDEFINED but have - to use VARYING for them. But we can still resort to - SCEV for loop header PHIs. */ - struct loop *l; - if (interesting - && (l = loop_containing_stmt (phi)) - && l->header == gimple_bb (phi)) - adjust_range_with_scev (&vr_result, l, phi, lhs); - } - update_value_range (lhs, &vr_result); - - /* Set the SSA with the value range. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) - { - if ((vr_result.type == VR_RANGE - || vr_result.type == VR_ANTI_RANGE) - && (TREE_CODE (vr_result.min) == INTEGER_CST) - && (TREE_CODE (vr_result.max) == INTEGER_CST)) - set_range_info (lhs, vr_result.type, - wi::to_wide (vr_result.min), - wi::to_wide (vr_result.max)); - } - else if (POINTER_TYPE_P (TREE_TYPE (lhs)) - && ((vr_result.type == VR_RANGE - && range_includes_zero_p (vr_result.min, - vr_result.max) == 0) - || (vr_result.type == VR_ANTI_RANGE - && range_includes_zero_p (vr_result.min, - vr_result.max) == 1))) - set_ptr_nonnull (lhs); - } -} - -/* Record any ranges created by statement STMT. */ - -void -evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt) -{ - tree output = NULL_TREE; - - if (dyn_cast (stmt)) - ; - else if (stmt_interesting_for_vrp (stmt)) - { - edge taken_edge; - value_range vr = VR_INITIALIZER; - extract_range_from_stmt (stmt, &taken_edge, &output, &vr); - if (output && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)) - { - update_value_range (output, &vr); - - /* Set the SSA with the value range. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (output))) - { - if ((vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) - && (TREE_CODE (vr.min) == INTEGER_CST) - && (TREE_CODE (vr.max) == INTEGER_CST)) - set_range_info (output, vr.type, - wi::to_wide (vr.min), - wi::to_wide (vr.max)); - } - else if (POINTER_TYPE_P (TREE_TYPE (output)) - && ((vr.type == VR_RANGE - && range_includes_zero_p (vr.min, vr.max) == 0) - || (vr.type == VR_ANTI_RANGE - && range_includes_zero_p (vr.min, vr.max) == 1))) - set_ptr_nonnull (output); - } - else - set_defs_to_varying (stmt); - } - else - set_defs_to_varying (stmt); - - /* See if we can derive a range for any of STMT's operands. */ - tree op; - ssa_op_iter i; - FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) - { - tree value; - enum tree_code comp_code; - - /* If OP is used in such a way that we can infer a value - range for it, and we don't find a previous assertion for - it, create a new assertion location node for OP. */ - if (infer_value_range (stmt, op, &comp_code, &value)) - { - /* If we are able to infer a nonzero value range for OP, - then walk backwards through the use-def chain to see if OP - was set via a typecast. - If so, then we can also infer a nonzero value range - for the operand of the NOP_EXPR. */ - if (comp_code == NE_EXPR && integer_zerop (value)) - { - tree t = op; - gimple *def_stmt = SSA_NAME_DEF_STMT (t); - while (is_gimple_assign (def_stmt) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) - && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME - && POINTER_TYPE_P - (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))) - { - t = gimple_assign_rhs1 (def_stmt); - def_stmt = SSA_NAME_DEF_STMT (t); - - /* Add VR when (T COMP_CODE value) condition is true. */ - value_range *op_range - = try_find_new_range (t, t, comp_code, value); - if (op_range) - push_value_range (t, op_range); - } - } - /* Add VR when (OP COMP_CODE value) condition is true. */ - value_range *op_range = try_find_new_range (op, op, - comp_code, value); - if (op_range) - push_value_range (op, op_range); - } - } -} - edge evrp_dom_walker::before_dom_children (basic_block bb) { @@ -540,54 +237,6 @@ evrp_dom_walker::after_dom_children (basic_block bb) evrp_range_analyzer.leave (bb); } -/* Restore/pop VRs valid only for BB when we leave BB. */ - -void -evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED) -{ - gcc_checking_assert (!stack.is_empty ()); - while (stack.last ().first != NULL_TREE) - pop_value_range (stack.last ().first); - stack.pop (); -} - -/* Push the Value Range of VAR to the stack and update it with new VR. */ - -void -evrp_range_analyzer::push_value_range (tree var, value_range *vr) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "pushing new range for "); - print_generic_expr (dump_file, var); - fprintf (dump_file, ": "); - dump_value_range (dump_file, vr); - fprintf (dump_file, "\n"); - } - stack.safe_push (std::make_pair (var, get_value_range (var))); - set_vr_value (var, vr); -} - -/* Pop the Value Range from the vrp_stack and update VAR with it. */ - -value_range * -evrp_range_analyzer::pop_value_range (tree var) -{ - value_range *vr = stack.last ().second; - gcc_checking_assert (var == stack.last ().first); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "popping range for "); - print_generic_expr (dump_file, var); - fprintf (dump_file, ", restoring "); - dump_value_range (dump_file, vr); - fprintf (dump_file, "\n"); - } - set_vr_value (var, vr); - stack.pop (); - return vr; -} - /* Perform any cleanups after the main phase of EVRP has completed. */ void -- 2.11.4.GIT