#include "domwalk.h"
#include "tree-cfg.h"
#include "attribs.h"
+#include "tree-pass.h"
+#include "gimple-range.h"
-array_bounds_checker::array_bounds_checker (struct function *func,
- range_query *qry)
- : fun (func), m_ptr_qry (qry)
+// Always use the current range query for the bounds checker.
+array_bounds_checker::array_bounds_checker (struct function *func)
+ : fun (func), m_ptr_qry (get_range_query (func))
{
/* No-op. */
}
{
public:
check_array_bounds_dom_walker (array_bounds_checker *checker)
- : dom_walker (CDI_DOMINATORS,
- /* Discover non-executable edges, preserving EDGE_EXECUTABLE
- flags, so that we can merge in information on
- non-executable edges from vrp_folder . */
- REACHABLE_BLOCKS_PRESERVING_FLAGS),
+ : dom_walker (CDI_DOMINATORS, REACHABLE_BLOCKS),
checker (checker) { }
~check_array_bounds_dom_walker () {}
check_array_bounds_dom_walker w (this);
w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
}
+
+const pass_data pass_data_array_bounds =
+{
+ GIMPLE_PASS, /* type */
+ "bounds", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_ARRAY_BOUNDS, /* tv_id */
+ PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ ( 0 ), /* No TODOs */
+};
+
+class pass_array_bounds : public gimple_opt_pass
+{
+public:
+ pass_array_bounds (gcc::context *ctxt, const pass_data &data_)
+ : gimple_opt_pass (data_, ctxt), data (data_)
+ { }
+
+ /* opt_pass methods: */
+ opt_pass * clone () final override
+ { return new pass_array_bounds (m_ctxt, data); }
+ bool gate (function *) final override
+ {
+ // Gate on the VRP pass to preserve previous behavior.
+ return flag_tree_vrp && (warn_array_bounds || warn_strict_flex_arrays);
+ }
+ unsigned int execute (function *fun) final override
+ {
+ calculate_dominance_info (CDI_DOMINATORS);
+ // Enable ranger as the current range query.
+ enable_ranger (fun, false);
+ array_bounds_checker array_checker (fun);
+ array_checker.check ();
+ disable_ranger (fun);
+ return 0;
+ }
+
+ private:
+ const pass_data &data;
+}; // class pass_array_bounds
+
+gimple_opt_pass *
+make_pass_array_bounds (gcc::context *ctxt)
+{
+ return new pass_array_bounds (ctxt, pass_data_array_bounds);
+}
friend class check_array_bounds_dom_walker;
public:
- array_bounds_checker (struct function *, range_query *);
+ array_bounds_checker (struct function *);
void check ();
private:
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_thread_jumps_full, /*first=*/true);
NEXT_PASS (pass_vrp, false /* final_p*/);
+ NEXT_PASS (pass_array_bounds);
NEXT_PASS (pass_dse);
NEXT_PASS (pass_dce);
/* pass_stdarg is always run and at this point we execute
DEFTIMEVAR (TV_TREE_VRP_THREADER , "tree VRP threader")
DEFTIMEVAR (TV_TREE_EARLY_VRP , "tree Early VRP")
DEFTIMEVAR (TV_TREE_FAST_VRP , "tree Fast VRP")
+DEFTIMEVAR (TV_TREE_ARRAY_BOUNDS , "warn array bounds")
DEFTIMEVAR (TV_TREE_COPY_PROP , "tree copy propagation")
DEFTIMEVAR (TV_FIND_REFERENCED_VARS , "tree find ref. vars")
DEFTIMEVAR (TV_TREE_PTA , "tree PTA")
extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_array_bounds (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_fast_vrp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
from anywhere to perform a VRP pass, including from EVRP. */
unsigned int
-execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p,
- bool final_p)
+execute_ranger_vrp (struct function *fun, bool final_p)
{
loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
if (dump_file && (dump_flags & TDF_DETAILS))
ranger->dump (dump_file);
- if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
- {
- // Set all edges as executable, except those ranger says aren't.
- int non_exec_flag = ranger->non_executable_edge_flag;
- basic_block bb;
- FOR_ALL_BB_FN (bb, fun)
- {
- edge_iterator ei;
- edge e;
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & non_exec_flag)
- e->flags &= ~EDGE_EXECUTABLE;
- else
- e->flags |= EDGE_EXECUTABLE;
- }
- scev_reset ();
- array_bounds_checker array_checker (fun, ranger);
- array_checker.check ();
- }
-
-
if (Value_Range::supports_type_p (TREE_TYPE
(TREE_TYPE (current_function_decl)))
&& flag_ipa_vrp
class pass_vrp : public gimple_opt_pass
{
public:
- pass_vrp (gcc::context *ctxt, const pass_data &data_, bool warn_p)
- : gimple_opt_pass (data_, ctxt), data (data_),
- warn_array_bounds_p (warn_p), final_p (false)
+ pass_vrp (gcc::context *ctxt, const pass_data &data_)
+ : gimple_opt_pass (data_, ctxt), data (data_), final_p (false)
{ }
/* opt_pass methods: */
opt_pass * clone () final override
- { return new pass_vrp (m_ctxt, data, false); }
+ { return new pass_vrp (m_ctxt, data); }
void set_pass_param (unsigned int n, bool param) final override
{
gcc_assert (n == 0);
if (&data == &pass_data_fast_vrp)
return execute_fast_vrp (fun);
- return execute_ranger_vrp (fun, warn_array_bounds_p, final_p);
+ return execute_ranger_vrp (fun, final_p);
}
private:
const pass_data &data;
- bool warn_array_bounds_p;
bool final_p;
}; // class pass_vrp
gimple_opt_pass *
make_pass_vrp (gcc::context *ctxt)
{
- return new pass_vrp (ctxt, pass_data_vrp, true);
+ return new pass_vrp (ctxt, pass_data_vrp);
}
gimple_opt_pass *
make_pass_early_vrp (gcc::context *ctxt)
{
- return new pass_vrp (ctxt, pass_data_early_vrp, false);
+ return new pass_vrp (ctxt, pass_data_early_vrp);
}
gimple_opt_pass *
make_pass_fast_vrp (gcc::context *ctxt)
{
- return new pass_vrp (ctxt, pass_data_fast_vrp, false);
+ return new pass_vrp (ctxt, pass_data_fast_vrp);
}
gimple_opt_pass *