xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-ssa-loop.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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