11debfc3dSmrg /* Loop optimizations over tree-ssa.
2*8feb0f0bSmrg Copyright (C) 2003-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it
71debfc3dSmrg under the terms of the GNU General Public License as published by the
81debfc3dSmrg Free Software Foundation; either version 3, or (at your option) any
91debfc3dSmrg later version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT
121debfc3dSmrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "system.h"
221debfc3dSmrg #include "coretypes.h"
231debfc3dSmrg #include "backend.h"
241debfc3dSmrg #include "tree.h"
251debfc3dSmrg #include "gimple.h"
261debfc3dSmrg #include "tree-pass.h"
271debfc3dSmrg #include "memmodel.h"
281debfc3dSmrg #include "tm_p.h"
291debfc3dSmrg #include "fold-const.h"
301debfc3dSmrg #include "gimple-iterator.h"
311debfc3dSmrg #include "tree-ssa-loop-ivopts.h"
321debfc3dSmrg #include "tree-ssa-loop-manip.h"
331debfc3dSmrg #include "tree-ssa-loop-niter.h"
341debfc3dSmrg #include "tree-ssa-loop.h"
351debfc3dSmrg #include "cfgloop.h"
361debfc3dSmrg #include "tree-inline.h"
371debfc3dSmrg #include "tree-scalar-evolution.h"
381debfc3dSmrg #include "tree-vectorizer.h"
391debfc3dSmrg #include "omp-general.h"
401debfc3dSmrg #include "diagnostic-core.h"
41a2dc1f3fSmrg #include "stringpool.h"
42a2dc1f3fSmrg #include "attribs.h"
431debfc3dSmrg
441debfc3dSmrg
451debfc3dSmrg /* A pass making sure loops are fixed up. */
461debfc3dSmrg
471debfc3dSmrg namespace {
481debfc3dSmrg
491debfc3dSmrg const pass_data pass_data_fix_loops =
501debfc3dSmrg {
511debfc3dSmrg GIMPLE_PASS, /* type */
521debfc3dSmrg "fix_loops", /* name */
531debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
541debfc3dSmrg TV_TREE_LOOP, /* tv_id */
551debfc3dSmrg PROP_cfg, /* properties_required */
561debfc3dSmrg 0, /* properties_provided */
571debfc3dSmrg 0, /* properties_destroyed */
581debfc3dSmrg 0, /* todo_flags_start */
591debfc3dSmrg 0, /* todo_flags_finish */
601debfc3dSmrg };
611debfc3dSmrg
621debfc3dSmrg class pass_fix_loops : public gimple_opt_pass
631debfc3dSmrg {
641debfc3dSmrg public:
pass_fix_loops(gcc::context * ctxt)651debfc3dSmrg pass_fix_loops (gcc::context *ctxt)
661debfc3dSmrg : gimple_opt_pass (pass_data_fix_loops, ctxt)
671debfc3dSmrg {}
681debfc3dSmrg
691debfc3dSmrg /* opt_pass methods: */
gate(function *)701debfc3dSmrg virtual bool gate (function *) { return flag_tree_loop_optimize; }
711debfc3dSmrg
721debfc3dSmrg virtual unsigned int execute (function *fn);
731debfc3dSmrg }; // class pass_fix_loops
741debfc3dSmrg
751debfc3dSmrg unsigned int
execute(function *)761debfc3dSmrg pass_fix_loops::execute (function *)
771debfc3dSmrg {
781debfc3dSmrg if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
791debfc3dSmrg {
801debfc3dSmrg calculate_dominance_info (CDI_DOMINATORS);
811debfc3dSmrg fix_loop_structure (NULL);
821debfc3dSmrg }
831debfc3dSmrg return 0;
841debfc3dSmrg }
851debfc3dSmrg
861debfc3dSmrg } // anon namespace
871debfc3dSmrg
881debfc3dSmrg gimple_opt_pass *
make_pass_fix_loops(gcc::context * ctxt)891debfc3dSmrg make_pass_fix_loops (gcc::context *ctxt)
901debfc3dSmrg {
911debfc3dSmrg return new pass_fix_loops (ctxt);
921debfc3dSmrg }
931debfc3dSmrg
941debfc3dSmrg
951debfc3dSmrg /* Gate for loop pass group. The group is controlled by -ftree-loop-optimize
961debfc3dSmrg but we also avoid running it when the IL doesn't contain any loop. */
971debfc3dSmrg
981debfc3dSmrg static bool
gate_loop(function * fn)991debfc3dSmrg gate_loop (function *fn)
1001debfc3dSmrg {
1011debfc3dSmrg if (!flag_tree_loop_optimize)
1021debfc3dSmrg return false;
1031debfc3dSmrg
1041debfc3dSmrg /* For -fdump-passes which runs before loop discovery print the
1051debfc3dSmrg state of -ftree-loop-optimize. */
1061debfc3dSmrg if (!loops_for_fn (fn))
1071debfc3dSmrg return true;
1081debfc3dSmrg
1091debfc3dSmrg return number_of_loops (fn) > 1;
1101debfc3dSmrg }
1111debfc3dSmrg
1121debfc3dSmrg /* The loop superpass. */
1131debfc3dSmrg
1141debfc3dSmrg namespace {
1151debfc3dSmrg
1161debfc3dSmrg const pass_data pass_data_tree_loop =
1171debfc3dSmrg {
1181debfc3dSmrg GIMPLE_PASS, /* type */
1191debfc3dSmrg "loop", /* name */
1201debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
1211debfc3dSmrg TV_TREE_LOOP, /* tv_id */
1221debfc3dSmrg PROP_cfg, /* properties_required */
1231debfc3dSmrg 0, /* properties_provided */
1241debfc3dSmrg 0, /* properties_destroyed */
1251debfc3dSmrg 0, /* todo_flags_start */
1261debfc3dSmrg 0, /* todo_flags_finish */
1271debfc3dSmrg };
1281debfc3dSmrg
1291debfc3dSmrg class pass_tree_loop : public gimple_opt_pass
1301debfc3dSmrg {
1311debfc3dSmrg public:
pass_tree_loop(gcc::context * ctxt)1321debfc3dSmrg pass_tree_loop (gcc::context *ctxt)
1331debfc3dSmrg : gimple_opt_pass (pass_data_tree_loop, ctxt)
1341debfc3dSmrg {}
1351debfc3dSmrg
1361debfc3dSmrg /* opt_pass methods: */
gate(function * fn)1371debfc3dSmrg virtual bool gate (function *fn) { return gate_loop (fn); }
1381debfc3dSmrg
1391debfc3dSmrg }; // class pass_tree_loop
1401debfc3dSmrg
1411debfc3dSmrg } // anon namespace
1421debfc3dSmrg
1431debfc3dSmrg gimple_opt_pass *
make_pass_tree_loop(gcc::context * ctxt)1441debfc3dSmrg make_pass_tree_loop (gcc::context *ctxt)
1451debfc3dSmrg {
1461debfc3dSmrg return new pass_tree_loop (ctxt);
1471debfc3dSmrg }
1481debfc3dSmrg
1491debfc3dSmrg /* Gate for oacc kernels pass group. */
1501debfc3dSmrg
1511debfc3dSmrg static bool
gate_oacc_kernels(function * fn)1521debfc3dSmrg gate_oacc_kernels (function *fn)
1531debfc3dSmrg {
1541debfc3dSmrg if (!flag_openacc)
1551debfc3dSmrg return false;
1561debfc3dSmrg
157a2dc1f3fSmrg if (!lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn->decl)))
1581debfc3dSmrg return false;
1591debfc3dSmrg
160*8feb0f0bSmrg class loop *loop;
1611debfc3dSmrg FOR_EACH_LOOP (loop, 0)
1621debfc3dSmrg if (loop->in_oacc_kernels_region)
1631debfc3dSmrg return true;
1641debfc3dSmrg
1651debfc3dSmrg return false;
1661debfc3dSmrg }
1671debfc3dSmrg
1681debfc3dSmrg /* The oacc kernels superpass. */
1691debfc3dSmrg
1701debfc3dSmrg namespace {
1711debfc3dSmrg
1721debfc3dSmrg const pass_data pass_data_oacc_kernels =
1731debfc3dSmrg {
1741debfc3dSmrg GIMPLE_PASS, /* type */
1751debfc3dSmrg "oacc_kernels", /* name */
1761debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
1771debfc3dSmrg TV_TREE_LOOP, /* tv_id */
1781debfc3dSmrg PROP_cfg, /* properties_required */
1791debfc3dSmrg 0, /* properties_provided */
1801debfc3dSmrg 0, /* properties_destroyed */
1811debfc3dSmrg 0, /* todo_flags_start */
1821debfc3dSmrg 0, /* todo_flags_finish */
1831debfc3dSmrg };
1841debfc3dSmrg
1851debfc3dSmrg class pass_oacc_kernels : public gimple_opt_pass
1861debfc3dSmrg {
1871debfc3dSmrg public:
pass_oacc_kernels(gcc::context * ctxt)1881debfc3dSmrg pass_oacc_kernels (gcc::context *ctxt)
1891debfc3dSmrg : gimple_opt_pass (pass_data_oacc_kernels, ctxt)
1901debfc3dSmrg {}
1911debfc3dSmrg
1921debfc3dSmrg /* opt_pass methods: */
gate(function * fn)1931debfc3dSmrg virtual bool gate (function *fn) { return gate_oacc_kernels (fn); }
1941debfc3dSmrg
1951debfc3dSmrg }; // class pass_oacc_kernels
1961debfc3dSmrg
1971debfc3dSmrg } // anon namespace
1981debfc3dSmrg
1991debfc3dSmrg gimple_opt_pass *
make_pass_oacc_kernels(gcc::context * ctxt)2001debfc3dSmrg make_pass_oacc_kernels (gcc::context *ctxt)
2011debfc3dSmrg {
2021debfc3dSmrg return new pass_oacc_kernels (ctxt);
2031debfc3dSmrg }
2041debfc3dSmrg
2051debfc3dSmrg /* The ipa oacc superpass. */
2061debfc3dSmrg
2071debfc3dSmrg namespace {
2081debfc3dSmrg
2091debfc3dSmrg const pass_data pass_data_ipa_oacc =
2101debfc3dSmrg {
2111debfc3dSmrg SIMPLE_IPA_PASS, /* type */
2121debfc3dSmrg "ipa_oacc", /* name */
2131debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
2141debfc3dSmrg TV_TREE_LOOP, /* tv_id */
2151debfc3dSmrg PROP_cfg, /* properties_required */
2161debfc3dSmrg 0, /* properties_provided */
2171debfc3dSmrg 0, /* properties_destroyed */
2181debfc3dSmrg 0, /* todo_flags_start */
2191debfc3dSmrg 0, /* todo_flags_finish */
2201debfc3dSmrg };
2211debfc3dSmrg
2221debfc3dSmrg class pass_ipa_oacc : public simple_ipa_opt_pass
2231debfc3dSmrg {
2241debfc3dSmrg public:
pass_ipa_oacc(gcc::context * ctxt)2251debfc3dSmrg pass_ipa_oacc (gcc::context *ctxt)
2261debfc3dSmrg : simple_ipa_opt_pass (pass_data_ipa_oacc, ctxt)
2271debfc3dSmrg {}
2281debfc3dSmrg
2291debfc3dSmrg /* opt_pass methods: */
gate(function *)2301debfc3dSmrg virtual bool gate (function *)
2311debfc3dSmrg {
2321debfc3dSmrg return (optimize
2331debfc3dSmrg && flag_openacc
2341debfc3dSmrg /* Don't bother doing anything if the program has errors. */
2351debfc3dSmrg && !seen_error ());
2361debfc3dSmrg }
2371debfc3dSmrg
2381debfc3dSmrg }; // class pass_ipa_oacc
2391debfc3dSmrg
2401debfc3dSmrg } // anon namespace
2411debfc3dSmrg
2421debfc3dSmrg simple_ipa_opt_pass *
make_pass_ipa_oacc(gcc::context * ctxt)2431debfc3dSmrg make_pass_ipa_oacc (gcc::context *ctxt)
2441debfc3dSmrg {
2451debfc3dSmrg return new pass_ipa_oacc (ctxt);
2461debfc3dSmrg }
2471debfc3dSmrg
2481debfc3dSmrg /* The ipa oacc kernels pass. */
2491debfc3dSmrg
2501debfc3dSmrg namespace {
2511debfc3dSmrg
2521debfc3dSmrg const pass_data pass_data_ipa_oacc_kernels =
2531debfc3dSmrg {
2541debfc3dSmrg SIMPLE_IPA_PASS, /* type */
2551debfc3dSmrg "ipa_oacc_kernels", /* name */
2561debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
2571debfc3dSmrg TV_TREE_LOOP, /* tv_id */
2581debfc3dSmrg PROP_cfg, /* properties_required */
2591debfc3dSmrg 0, /* properties_provided */
2601debfc3dSmrg 0, /* properties_destroyed */
2611debfc3dSmrg 0, /* todo_flags_start */
2621debfc3dSmrg 0, /* todo_flags_finish */
2631debfc3dSmrg };
2641debfc3dSmrg
2651debfc3dSmrg class pass_ipa_oacc_kernels : public simple_ipa_opt_pass
2661debfc3dSmrg {
2671debfc3dSmrg public:
pass_ipa_oacc_kernels(gcc::context * ctxt)2681debfc3dSmrg pass_ipa_oacc_kernels (gcc::context *ctxt)
2691debfc3dSmrg : simple_ipa_opt_pass (pass_data_ipa_oacc_kernels, ctxt)
2701debfc3dSmrg {}
2711debfc3dSmrg
2721debfc3dSmrg }; // class pass_ipa_oacc_kernels
2731debfc3dSmrg
2741debfc3dSmrg } // anon namespace
2751debfc3dSmrg
2761debfc3dSmrg simple_ipa_opt_pass *
make_pass_ipa_oacc_kernels(gcc::context * ctxt)2771debfc3dSmrg make_pass_ipa_oacc_kernels (gcc::context *ctxt)
2781debfc3dSmrg {
2791debfc3dSmrg return new pass_ipa_oacc_kernels (ctxt);
2801debfc3dSmrg }
2811debfc3dSmrg
2821debfc3dSmrg /* The no-loop superpass. */
2831debfc3dSmrg
2841debfc3dSmrg namespace {
2851debfc3dSmrg
2861debfc3dSmrg const pass_data pass_data_tree_no_loop =
2871debfc3dSmrg {
2881debfc3dSmrg GIMPLE_PASS, /* type */
2891debfc3dSmrg "no_loop", /* name */
2901debfc3dSmrg OPTGROUP_NONE, /* optinfo_flags */
2911debfc3dSmrg TV_TREE_NOLOOP, /* tv_id */
2921debfc3dSmrg PROP_cfg, /* properties_required */
2931debfc3dSmrg 0, /* properties_provided */
2941debfc3dSmrg 0, /* properties_destroyed */
2951debfc3dSmrg 0, /* todo_flags_start */
2961debfc3dSmrg 0, /* todo_flags_finish */
2971debfc3dSmrg };
2981debfc3dSmrg
2991debfc3dSmrg class pass_tree_no_loop : public gimple_opt_pass
3001debfc3dSmrg {
3011debfc3dSmrg public:
pass_tree_no_loop(gcc::context * ctxt)3021debfc3dSmrg pass_tree_no_loop (gcc::context *ctxt)
3031debfc3dSmrg : gimple_opt_pass (pass_data_tree_no_loop, ctxt)
3041debfc3dSmrg {}
3051debfc3dSmrg
3061debfc3dSmrg /* opt_pass methods: */
gate(function * fn)3071debfc3dSmrg virtual bool gate (function *fn) { return !gate_loop (fn); }
3081debfc3dSmrg
3091debfc3dSmrg }; // class pass_tree_no_loop
3101debfc3dSmrg
3111debfc3dSmrg } // anon namespace
3121debfc3dSmrg
3131debfc3dSmrg gimple_opt_pass *
make_pass_tree_no_loop(gcc::context * ctxt)3141debfc3dSmrg make_pass_tree_no_loop (gcc::context *ctxt)
3151debfc3dSmrg {
3161debfc3dSmrg return new pass_tree_no_loop (ctxt);
3171debfc3dSmrg }
3181debfc3dSmrg
3191debfc3dSmrg
3201debfc3dSmrg /* Loop optimizer initialization. */
3211debfc3dSmrg
3221debfc3dSmrg namespace {
3231debfc3dSmrg
3241debfc3dSmrg const pass_data pass_data_tree_loop_init =
3251debfc3dSmrg {
3261debfc3dSmrg GIMPLE_PASS, /* type */
3271debfc3dSmrg "loopinit", /* name */
3281debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
3291debfc3dSmrg TV_NONE, /* tv_id */
3301debfc3dSmrg PROP_cfg, /* properties_required */
3311debfc3dSmrg 0, /* properties_provided */
3321debfc3dSmrg 0, /* properties_destroyed */
333*8feb0f0bSmrg TODO_update_address_taken, /* todo_flags_start */
3341debfc3dSmrg 0, /* todo_flags_finish */
3351debfc3dSmrg };
3361debfc3dSmrg
3371debfc3dSmrg class pass_tree_loop_init : public gimple_opt_pass
3381debfc3dSmrg {
3391debfc3dSmrg public:
pass_tree_loop_init(gcc::context * ctxt)3401debfc3dSmrg pass_tree_loop_init (gcc::context *ctxt)
3411debfc3dSmrg : gimple_opt_pass (pass_data_tree_loop_init, ctxt)
3421debfc3dSmrg {}
3431debfc3dSmrg
3441debfc3dSmrg /* opt_pass methods: */
3451debfc3dSmrg virtual unsigned int execute (function *);
3461debfc3dSmrg
3471debfc3dSmrg }; // class pass_tree_loop_init
3481debfc3dSmrg
3491debfc3dSmrg unsigned int
execute(function * fun ATTRIBUTE_UNUSED)3501debfc3dSmrg pass_tree_loop_init::execute (function *fun ATTRIBUTE_UNUSED)
3511debfc3dSmrg {
3521debfc3dSmrg /* When processing a loop in the loop pipeline, we should be able to assert
3531debfc3dSmrg that:
3541debfc3dSmrg (loops_state_satisfies_p (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS
3551debfc3dSmrg | LOOP_CLOSED_SSA)
3561debfc3dSmrg && scev_initialized_p ())
3571debfc3dSmrg */
3581debfc3dSmrg loop_optimizer_init (LOOPS_NORMAL
3591debfc3dSmrg | LOOPS_HAVE_RECORDED_EXITS);
3601debfc3dSmrg rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
3611debfc3dSmrg scev_initialize ();
3621debfc3dSmrg
3631debfc3dSmrg return 0;
3641debfc3dSmrg }
3651debfc3dSmrg
3661debfc3dSmrg } // anon namespace
3671debfc3dSmrg
3681debfc3dSmrg gimple_opt_pass *
make_pass_tree_loop_init(gcc::context * ctxt)3691debfc3dSmrg make_pass_tree_loop_init (gcc::context *ctxt)
3701debfc3dSmrg {
3711debfc3dSmrg return new pass_tree_loop_init (ctxt);
3721debfc3dSmrg }
3731debfc3dSmrg
3741debfc3dSmrg /* Loop autovectorization. */
3751debfc3dSmrg
3761debfc3dSmrg namespace {
3771debfc3dSmrg
3781debfc3dSmrg const pass_data pass_data_vectorize =
3791debfc3dSmrg {
3801debfc3dSmrg GIMPLE_PASS, /* type */
3811debfc3dSmrg "vect", /* name */
3821debfc3dSmrg OPTGROUP_LOOP | OPTGROUP_VEC, /* optinfo_flags */
3831debfc3dSmrg TV_TREE_VECTORIZATION, /* tv_id */
3841debfc3dSmrg ( PROP_cfg | PROP_ssa ), /* properties_required */
3851debfc3dSmrg 0, /* properties_provided */
3861debfc3dSmrg 0, /* properties_destroyed */
3871debfc3dSmrg 0, /* todo_flags_start */
3881debfc3dSmrg 0, /* todo_flags_finish */
3891debfc3dSmrg };
3901debfc3dSmrg
3911debfc3dSmrg class pass_vectorize : public gimple_opt_pass
3921debfc3dSmrg {
3931debfc3dSmrg public:
pass_vectorize(gcc::context * ctxt)3941debfc3dSmrg pass_vectorize (gcc::context *ctxt)
3951debfc3dSmrg : gimple_opt_pass (pass_data_vectorize, ctxt)
3961debfc3dSmrg {}
3971debfc3dSmrg
3981debfc3dSmrg /* opt_pass methods: */
gate(function * fun)3991debfc3dSmrg virtual bool gate (function *fun)
4001debfc3dSmrg {
4011debfc3dSmrg return flag_tree_loop_vectorize || fun->has_force_vectorize_loops;
4021debfc3dSmrg }
4031debfc3dSmrg
4041debfc3dSmrg virtual unsigned int execute (function *);
4051debfc3dSmrg
4061debfc3dSmrg }; // class pass_vectorize
4071debfc3dSmrg
4081debfc3dSmrg unsigned int
execute(function * fun)4091debfc3dSmrg pass_vectorize::execute (function *fun)
4101debfc3dSmrg {
4111debfc3dSmrg if (number_of_loops (fun) <= 1)
4121debfc3dSmrg return 0;
4131debfc3dSmrg
4141debfc3dSmrg return vectorize_loops ();
4151debfc3dSmrg }
4161debfc3dSmrg
4171debfc3dSmrg } // anon namespace
4181debfc3dSmrg
4191debfc3dSmrg gimple_opt_pass *
make_pass_vectorize(gcc::context * ctxt)4201debfc3dSmrg make_pass_vectorize (gcc::context *ctxt)
4211debfc3dSmrg {
4221debfc3dSmrg return new pass_vectorize (ctxt);
4231debfc3dSmrg }
4241debfc3dSmrg
4251debfc3dSmrg /* Propagation of constants using scev. */
4261debfc3dSmrg
4271debfc3dSmrg namespace {
4281debfc3dSmrg
4291debfc3dSmrg const pass_data pass_data_scev_cprop =
4301debfc3dSmrg {
4311debfc3dSmrg GIMPLE_PASS, /* type */
4321debfc3dSmrg "sccp", /* name */
4331debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
4341debfc3dSmrg TV_SCEV_CONST, /* tv_id */
4351debfc3dSmrg ( PROP_cfg | PROP_ssa ), /* properties_required */
4361debfc3dSmrg 0, /* properties_provided */
4371debfc3dSmrg 0, /* properties_destroyed */
4381debfc3dSmrg 0, /* todo_flags_start */
439c0a68be4Smrg 0, /* todo_flags_finish */
4401debfc3dSmrg };
4411debfc3dSmrg
4421debfc3dSmrg class pass_scev_cprop : public gimple_opt_pass
4431debfc3dSmrg {
4441debfc3dSmrg public:
pass_scev_cprop(gcc::context * ctxt)4451debfc3dSmrg pass_scev_cprop (gcc::context *ctxt)
4461debfc3dSmrg : gimple_opt_pass (pass_data_scev_cprop, ctxt)
4471debfc3dSmrg {}
4481debfc3dSmrg
4491debfc3dSmrg /* opt_pass methods: */
gate(function *)4501debfc3dSmrg virtual bool gate (function *) { return flag_tree_scev_cprop; }
451c0a68be4Smrg virtual unsigned int execute (function *);
4521debfc3dSmrg
4531debfc3dSmrg }; // class pass_scev_cprop
4541debfc3dSmrg
455c0a68be4Smrg unsigned
execute(function *)456c0a68be4Smrg pass_scev_cprop::execute (function *)
457c0a68be4Smrg {
458*8feb0f0bSmrg class loop *loop;
459c0a68be4Smrg bool any = false;
460c0a68be4Smrg
461c0a68be4Smrg /* Perform final value replacement in loops, in case the replacement
462c0a68be4Smrg expressions are cheap. */
463c0a68be4Smrg FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
464c0a68be4Smrg any |= final_value_replacement_loop (loop);
465c0a68be4Smrg
466c0a68be4Smrg return any ? TODO_cleanup_cfg | TODO_update_ssa_only_virtuals : 0;
467c0a68be4Smrg }
468c0a68be4Smrg
4691debfc3dSmrg } // anon namespace
4701debfc3dSmrg
4711debfc3dSmrg gimple_opt_pass *
make_pass_scev_cprop(gcc::context * ctxt)4721debfc3dSmrg make_pass_scev_cprop (gcc::context *ctxt)
4731debfc3dSmrg {
4741debfc3dSmrg return new pass_scev_cprop (ctxt);
4751debfc3dSmrg }
4761debfc3dSmrg
4771debfc3dSmrg /* Induction variable optimizations. */
4781debfc3dSmrg
4791debfc3dSmrg namespace {
4801debfc3dSmrg
4811debfc3dSmrg const pass_data pass_data_iv_optimize =
4821debfc3dSmrg {
4831debfc3dSmrg GIMPLE_PASS, /* type */
4841debfc3dSmrg "ivopts", /* name */
4851debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
4861debfc3dSmrg TV_TREE_LOOP_IVOPTS, /* tv_id */
4871debfc3dSmrg ( PROP_cfg | PROP_ssa ), /* properties_required */
4881debfc3dSmrg 0, /* properties_provided */
4891debfc3dSmrg 0, /* properties_destroyed */
4901debfc3dSmrg 0, /* todo_flags_start */
4911debfc3dSmrg TODO_update_ssa, /* todo_flags_finish */
4921debfc3dSmrg };
4931debfc3dSmrg
4941debfc3dSmrg class pass_iv_optimize : public gimple_opt_pass
4951debfc3dSmrg {
4961debfc3dSmrg public:
pass_iv_optimize(gcc::context * ctxt)4971debfc3dSmrg pass_iv_optimize (gcc::context *ctxt)
4981debfc3dSmrg : gimple_opt_pass (pass_data_iv_optimize, ctxt)
4991debfc3dSmrg {}
5001debfc3dSmrg
5011debfc3dSmrg /* opt_pass methods: */
gate(function *)5021debfc3dSmrg virtual bool gate (function *) { return flag_ivopts != 0; }
5031debfc3dSmrg virtual unsigned int execute (function *);
5041debfc3dSmrg
5051debfc3dSmrg }; // class pass_iv_optimize
5061debfc3dSmrg
5071debfc3dSmrg unsigned int
execute(function * fun)5081debfc3dSmrg pass_iv_optimize::execute (function *fun)
5091debfc3dSmrg {
5101debfc3dSmrg if (number_of_loops (fun) <= 1)
5111debfc3dSmrg return 0;
5121debfc3dSmrg
5131debfc3dSmrg tree_ssa_iv_optimize ();
5141debfc3dSmrg return 0;
5151debfc3dSmrg }
5161debfc3dSmrg
5171debfc3dSmrg } // anon namespace
5181debfc3dSmrg
5191debfc3dSmrg gimple_opt_pass *
make_pass_iv_optimize(gcc::context * ctxt)5201debfc3dSmrg make_pass_iv_optimize (gcc::context *ctxt)
5211debfc3dSmrg {
5221debfc3dSmrg return new pass_iv_optimize (ctxt);
5231debfc3dSmrg }
5241debfc3dSmrg
5251debfc3dSmrg /* Loop optimizer finalization. */
5261debfc3dSmrg
5271debfc3dSmrg static unsigned int
tree_ssa_loop_done(void)5281debfc3dSmrg tree_ssa_loop_done (void)
5291debfc3dSmrg {
5301debfc3dSmrg free_numbers_of_iterations_estimates (cfun);
5311debfc3dSmrg scev_finalize ();
5321debfc3dSmrg loop_optimizer_finalize ();
5331debfc3dSmrg return 0;
5341debfc3dSmrg }
5351debfc3dSmrg
5361debfc3dSmrg namespace {
5371debfc3dSmrg
5381debfc3dSmrg const pass_data pass_data_tree_loop_done =
5391debfc3dSmrg {
5401debfc3dSmrg GIMPLE_PASS, /* type */
5411debfc3dSmrg "loopdone", /* name */
5421debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
5431debfc3dSmrg TV_NONE, /* tv_id */
5441debfc3dSmrg PROP_cfg, /* properties_required */
5451debfc3dSmrg 0, /* properties_provided */
5461debfc3dSmrg 0, /* properties_destroyed */
5471debfc3dSmrg 0, /* todo_flags_start */
5481debfc3dSmrg TODO_cleanup_cfg, /* todo_flags_finish */
5491debfc3dSmrg };
5501debfc3dSmrg
5511debfc3dSmrg class pass_tree_loop_done : public gimple_opt_pass
5521debfc3dSmrg {
5531debfc3dSmrg public:
pass_tree_loop_done(gcc::context * ctxt)5541debfc3dSmrg pass_tree_loop_done (gcc::context *ctxt)
5551debfc3dSmrg : gimple_opt_pass (pass_data_tree_loop_done, ctxt)
5561debfc3dSmrg {}
5571debfc3dSmrg
5581debfc3dSmrg /* opt_pass methods: */
execute(function *)5591debfc3dSmrg virtual unsigned int execute (function *) { return tree_ssa_loop_done (); }
5601debfc3dSmrg
5611debfc3dSmrg }; // class pass_tree_loop_done
5621debfc3dSmrg
5631debfc3dSmrg } // anon namespace
5641debfc3dSmrg
5651debfc3dSmrg gimple_opt_pass *
make_pass_tree_loop_done(gcc::context * ctxt)5661debfc3dSmrg make_pass_tree_loop_done (gcc::context *ctxt)
5671debfc3dSmrg {
5681debfc3dSmrg return new pass_tree_loop_done (ctxt);
5691debfc3dSmrg }
5701debfc3dSmrg
5711debfc3dSmrg /* Calls CBCK for each index in memory reference ADDR_P. There are two
5721debfc3dSmrg kinds situations handled; in each of these cases, the memory reference
5731debfc3dSmrg and DATA are passed to the callback:
5741debfc3dSmrg
5751debfc3dSmrg Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
5761debfc3dSmrg pass the pointer to the index to the callback.
5771debfc3dSmrg
5781debfc3dSmrg Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
5791debfc3dSmrg pointer to addr to the callback.
5801debfc3dSmrg
5811debfc3dSmrg If the callback returns false, the whole search stops and false is returned.
5821debfc3dSmrg Otherwise the function returns true after traversing through the whole
5831debfc3dSmrg reference *ADDR_P. */
5841debfc3dSmrg
5851debfc3dSmrg bool
for_each_index(tree * addr_p,bool (* cbck)(tree,tree *,void *),void * data)5861debfc3dSmrg for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
5871debfc3dSmrg {
5881debfc3dSmrg tree *nxt, *idx;
5891debfc3dSmrg
5901debfc3dSmrg for (; ; addr_p = nxt)
5911debfc3dSmrg {
5921debfc3dSmrg switch (TREE_CODE (*addr_p))
5931debfc3dSmrg {
5941debfc3dSmrg case SSA_NAME:
5951debfc3dSmrg return cbck (*addr_p, addr_p, data);
5961debfc3dSmrg
5971debfc3dSmrg case MEM_REF:
5981debfc3dSmrg nxt = &TREE_OPERAND (*addr_p, 0);
5991debfc3dSmrg return cbck (*addr_p, nxt, data);
6001debfc3dSmrg
6011debfc3dSmrg case BIT_FIELD_REF:
6021debfc3dSmrg case VIEW_CONVERT_EXPR:
6031debfc3dSmrg case REALPART_EXPR:
6041debfc3dSmrg case IMAGPART_EXPR:
6051debfc3dSmrg nxt = &TREE_OPERAND (*addr_p, 0);
6061debfc3dSmrg break;
6071debfc3dSmrg
6081debfc3dSmrg case COMPONENT_REF:
6091debfc3dSmrg /* If the component has varying offset, it behaves like index
6101debfc3dSmrg as well. */
6111debfc3dSmrg idx = &TREE_OPERAND (*addr_p, 2);
6121debfc3dSmrg if (*idx
6131debfc3dSmrg && !cbck (*addr_p, idx, data))
6141debfc3dSmrg return false;
6151debfc3dSmrg
6161debfc3dSmrg nxt = &TREE_OPERAND (*addr_p, 0);
6171debfc3dSmrg break;
6181debfc3dSmrg
6191debfc3dSmrg case ARRAY_REF:
6201debfc3dSmrg case ARRAY_RANGE_REF:
6211debfc3dSmrg nxt = &TREE_OPERAND (*addr_p, 0);
6221debfc3dSmrg if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data))
6231debfc3dSmrg return false;
6241debfc3dSmrg break;
6251debfc3dSmrg
6261debfc3dSmrg case CONSTRUCTOR:
6271debfc3dSmrg return true;
6281debfc3dSmrg
6291debfc3dSmrg case ADDR_EXPR:
6301debfc3dSmrg gcc_assert (is_gimple_min_invariant (*addr_p));
6311debfc3dSmrg return true;
6321debfc3dSmrg
6331debfc3dSmrg case TARGET_MEM_REF:
6341debfc3dSmrg idx = &TMR_BASE (*addr_p);
6351debfc3dSmrg if (*idx
6361debfc3dSmrg && !cbck (*addr_p, idx, data))
6371debfc3dSmrg return false;
6381debfc3dSmrg idx = &TMR_INDEX (*addr_p);
6391debfc3dSmrg if (*idx
6401debfc3dSmrg && !cbck (*addr_p, idx, data))
6411debfc3dSmrg return false;
6421debfc3dSmrg idx = &TMR_INDEX2 (*addr_p);
6431debfc3dSmrg if (*idx
6441debfc3dSmrg && !cbck (*addr_p, idx, data))
6451debfc3dSmrg return false;
6461debfc3dSmrg return true;
6471debfc3dSmrg
6481debfc3dSmrg default:
649c0a68be4Smrg if (DECL_P (*addr_p)
650c0a68be4Smrg || CONSTANT_CLASS_P (*addr_p))
651c0a68be4Smrg return true;
6521debfc3dSmrg gcc_unreachable ();
6531debfc3dSmrg }
6541debfc3dSmrg }
6551debfc3dSmrg }
6561debfc3dSmrg
6571debfc3dSmrg
6581debfc3dSmrg /* The name and the length of the currently generated variable
6591debfc3dSmrg for lsm. */
6601debfc3dSmrg #define MAX_LSM_NAME_LENGTH 40
6611debfc3dSmrg static char lsm_tmp_name[MAX_LSM_NAME_LENGTH + 1];
6621debfc3dSmrg static int lsm_tmp_name_length;
6631debfc3dSmrg
6641debfc3dSmrg /* Adds S to lsm_tmp_name. */
6651debfc3dSmrg
6661debfc3dSmrg static void
lsm_tmp_name_add(const char * s)6671debfc3dSmrg lsm_tmp_name_add (const char *s)
6681debfc3dSmrg {
6691debfc3dSmrg int l = strlen (s) + lsm_tmp_name_length;
6701debfc3dSmrg if (l > MAX_LSM_NAME_LENGTH)
6711debfc3dSmrg return;
6721debfc3dSmrg
6731debfc3dSmrg strcpy (lsm_tmp_name + lsm_tmp_name_length, s);
6741debfc3dSmrg lsm_tmp_name_length = l;
6751debfc3dSmrg }
6761debfc3dSmrg
6771debfc3dSmrg /* Stores the name for temporary variable that replaces REF to
6781debfc3dSmrg lsm_tmp_name. */
6791debfc3dSmrg
6801debfc3dSmrg static void
gen_lsm_tmp_name(tree ref)6811debfc3dSmrg gen_lsm_tmp_name (tree ref)
6821debfc3dSmrg {
6831debfc3dSmrg const char *name;
6841debfc3dSmrg
6851debfc3dSmrg switch (TREE_CODE (ref))
6861debfc3dSmrg {
6871debfc3dSmrg case MEM_REF:
6881debfc3dSmrg case TARGET_MEM_REF:
6891debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
6901debfc3dSmrg lsm_tmp_name_add ("_");
6911debfc3dSmrg break;
6921debfc3dSmrg
6931debfc3dSmrg case ADDR_EXPR:
6941debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
6951debfc3dSmrg break;
6961debfc3dSmrg
6971debfc3dSmrg case BIT_FIELD_REF:
6981debfc3dSmrg case VIEW_CONVERT_EXPR:
6991debfc3dSmrg case ARRAY_RANGE_REF:
7001debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
7011debfc3dSmrg break;
7021debfc3dSmrg
7031debfc3dSmrg case REALPART_EXPR:
7041debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
7051debfc3dSmrg lsm_tmp_name_add ("_RE");
7061debfc3dSmrg break;
7071debfc3dSmrg
7081debfc3dSmrg case IMAGPART_EXPR:
7091debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
7101debfc3dSmrg lsm_tmp_name_add ("_IM");
7111debfc3dSmrg break;
7121debfc3dSmrg
7131debfc3dSmrg case COMPONENT_REF:
7141debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
7151debfc3dSmrg lsm_tmp_name_add ("_");
7161debfc3dSmrg name = get_name (TREE_OPERAND (ref, 1));
7171debfc3dSmrg if (!name)
7181debfc3dSmrg name = "F";
7191debfc3dSmrg lsm_tmp_name_add (name);
7201debfc3dSmrg break;
7211debfc3dSmrg
7221debfc3dSmrg case ARRAY_REF:
7231debfc3dSmrg gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
7241debfc3dSmrg lsm_tmp_name_add ("_I");
7251debfc3dSmrg break;
7261debfc3dSmrg
7271debfc3dSmrg case SSA_NAME:
7281debfc3dSmrg case VAR_DECL:
7291debfc3dSmrg case PARM_DECL:
7301debfc3dSmrg case FUNCTION_DECL:
7311debfc3dSmrg case LABEL_DECL:
7321debfc3dSmrg name = get_name (ref);
7331debfc3dSmrg if (!name)
7341debfc3dSmrg name = "D";
7351debfc3dSmrg lsm_tmp_name_add (name);
7361debfc3dSmrg break;
7371debfc3dSmrg
7381debfc3dSmrg case STRING_CST:
7391debfc3dSmrg lsm_tmp_name_add ("S");
7401debfc3dSmrg break;
7411debfc3dSmrg
7421debfc3dSmrg case RESULT_DECL:
7431debfc3dSmrg lsm_tmp_name_add ("R");
7441debfc3dSmrg break;
7451debfc3dSmrg
7461debfc3dSmrg case INTEGER_CST:
7471debfc3dSmrg default:
7481debfc3dSmrg /* Nothing. */
7491debfc3dSmrg break;
7501debfc3dSmrg }
7511debfc3dSmrg }
7521debfc3dSmrg
7531debfc3dSmrg /* Determines name for temporary variable that replaces REF.
7541debfc3dSmrg The name is accumulated into the lsm_tmp_name variable.
7551debfc3dSmrg N is added to the name of the temporary. */
7561debfc3dSmrg
7571debfc3dSmrg char *
get_lsm_tmp_name(tree ref,unsigned n,const char * suffix)7581debfc3dSmrg get_lsm_tmp_name (tree ref, unsigned n, const char *suffix)
7591debfc3dSmrg {
7601debfc3dSmrg char ns[2];
7611debfc3dSmrg
7621debfc3dSmrg lsm_tmp_name_length = 0;
7631debfc3dSmrg gen_lsm_tmp_name (ref);
7641debfc3dSmrg lsm_tmp_name_add ("_lsm");
7651debfc3dSmrg if (n < 10)
7661debfc3dSmrg {
7671debfc3dSmrg ns[0] = '0' + n;
7681debfc3dSmrg ns[1] = 0;
7691debfc3dSmrg lsm_tmp_name_add (ns);
7701debfc3dSmrg }
7711debfc3dSmrg if (suffix != NULL)
7721debfc3dSmrg lsm_tmp_name_add (suffix);
773*8feb0f0bSmrg return lsm_tmp_name;
7741debfc3dSmrg }
7751debfc3dSmrg
7761debfc3dSmrg /* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */
7771debfc3dSmrg
7781debfc3dSmrg unsigned
tree_num_loop_insns(class loop * loop,eni_weights * weights)779*8feb0f0bSmrg tree_num_loop_insns (class loop *loop, eni_weights *weights)
7801debfc3dSmrg {
7811debfc3dSmrg basic_block *body = get_loop_body (loop);
7821debfc3dSmrg gimple_stmt_iterator gsi;
7831debfc3dSmrg unsigned size = 0, i;
7841debfc3dSmrg
7851debfc3dSmrg for (i = 0; i < loop->num_nodes; i++)
7861debfc3dSmrg for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
7871debfc3dSmrg size += estimate_num_insns (gsi_stmt (gsi), weights);
7881debfc3dSmrg free (body);
7891debfc3dSmrg
7901debfc3dSmrg return size;
7911debfc3dSmrg }
7921debfc3dSmrg
7931debfc3dSmrg
7941debfc3dSmrg
795