| /* Value range propagation pass using the ranger. |
| Copyright (C) 2020 Free Software Foundation, Inc. |
| Contributed by Aldy Hernandez <aldyh@redhat.com>. |
| |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| #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" |
| #include "gimple-range.h" |
| |
| class rvrp_ranger : public range_store |
| { |
| public: |
| rvrp_ranger () : range_pool ("rvrp value range pool") { } |
| ~rvrp_ranger () |
| { |
| range_pool.release (); |
| } |
| // This is the range getter for the simplifier, but is really only |
| // used for the conditional folding which still uses equivalences. |
| virtual const value_range_equiv *get_value_range (const_tree expr, |
| gimple *stmt) OVERRIDE |
| { |
| widest_irange r; |
| if (ranger.range_of_expr (r, const_cast<tree> (expr), stmt)) |
| return new (range_pool.allocate ()) value_range_equiv (r); |
| return new (range_pool.allocate ()) value_range_equiv (TREE_TYPE (expr)); |
| } |
| virtual bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL) |
| { |
| return ranger.range_of_expr (r, expr, stmt); |
| } |
| gimple_ranger ranger; |
| private: |
| object_allocator<value_range_equiv> range_pool; |
| }; |
| |
| class rvrp_folder : public substitute_and_fold_engine |
| { |
| public: |
| rvrp_folder (bool allow_il_changes) |
| : simplifier (&ranger), allow_il_changes (allow_il_changes) { } |
| |
| tree get_value (tree op, gimple *stmt) OVERRIDE |
| { |
| widest_irange r; |
| tree singleton; |
| if (ranger.ranger.range_of_expr (r, op, stmt) && r.singleton_p (&singleton) |
| && allow_il_changes) |
| return singleton; |
| return NULL; |
| } |
| |
| bool fold_cond (gcond *cond) |
| { |
| if (!irange::supports_type_p (gimple_expr_type (cond))) |
| return false; |
| |
| widest_irange r; |
| if (ranger.ranger.range_of_stmt (r, cond) && r.singleton_p ()) |
| { |
| if (allow_il_changes) |
| { |
| if (r.zero_p ()) |
| gimple_cond_make_false (cond); |
| else |
| gimple_cond_make_true (cond); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE |
| { |
| gcond *cond = dyn_cast <gcond *> (gsi_stmt (*gsi)); |
| if (cond && fold_cond (cond)) |
| return true; |
| |
| if (allow_il_changes) |
| return simplifier.simplify (gsi); |
| return false; |
| } |
| |
| private: |
| rvrp_ranger ranger; |
| simplify_using_ranges simplifier; |
| bool allow_il_changes; |
| }; |
| |
| static unsigned int |
| execute_ranger_vrp (bool allow_il_changes) |
| { |
| loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); |
| rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); |
| scev_initialize (); |
| calculate_dominance_info (CDI_DOMINATORS); |
| |
| rvrp_folder folder (allow_il_changes); |
| folder.substitute_and_fold (); |
| |
| scev_finalize (); |
| loop_optimizer_finalize (); |
| return 0; |
| } |
| |
| namespace { |
| |
| const pass_data pass_data_ranger_vrp = |
| { |
| GIMPLE_PASS, // type |
| "rvrp", // name |
| OPTGROUP_NONE, // optinfo_flags |
| TV_TREE_EARLY_VRP, // tv_id |
| PROP_ssa, // properties_required |
| 0, // properties_provided |
| 0, // properties_destroyed |
| 0, // todo_flags_start |
| ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), |
| }; |
| |
| class pass_ranger_vrp : public gimple_opt_pass |
| { |
| public: |
| pass_ranger_vrp (gcc::context *ctxt) |
| : gimple_opt_pass (pass_data_ranger_vrp, ctxt) |
| { |
| static int pass = 1; |
| rvrp_pass_num = pass; |
| pass++; |
| } |
| opt_pass *clone () { return new pass_ranger_vrp (m_ctxt); } |
| virtual bool gate (function *) |
| { return flag_tree_vrp != 0; } |
| virtual unsigned int execute (function *) |
| { |
| if (rvrp_pass_num == 1) |
| allow_il_changes = flag_rvrp1_changes; |
| if (rvrp_pass_num == 2) |
| allow_il_changes = flag_rvrp2_changes; |
| return execute_ranger_vrp (allow_il_changes); |
| } |
| private: |
| bool allow_il_changes; |
| int rvrp_pass_num; |
| }; |
| |
| } // anon namespace |
| |
| gimple_opt_pass * |
| make_pass_ranger_vrp (gcc::context *ctxt) |
| { |
| return new pass_ranger_vrp (ctxt); |
| } |