diff options
Diffstat (limited to 'gcc/tree-ssa-loop.c')
-rw-r--r-- | gcc/tree-ssa-loop.c | 741 |
1 files changed, 0 insertions, 741 deletions
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c deleted file mode 100644 index 73aa466..0000000 --- a/gcc/tree-ssa-loop.c +++ /dev/null @@ -1,741 +0,0 @@ -/* Loop optimizations over tree-ssa. - Copyright (C) 2003-2022 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 -<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 "memmodel.h" -#include "tm_p.h" -#include "fold-const.h" -#include "gimple-iterator.h" -#include "tree-ssa-loop-ivopts.h" -#include "tree-ssa-loop-manip.h" -#include "tree-ssa-loop-niter.h" -#include "tree-ssa-loop.h" -#include "cfgloop.h" -#include "tree-inline.h" -#include "tree-scalar-evolution.h" -#include "tree-vectorizer.h" -#include "omp-general.h" -#include "diagnostic-core.h" -#include "stringpool.h" -#include "attribs.h" - - -/* A pass making sure loops are fixed up. */ - -namespace { - -const pass_data pass_data_fix_loops = -{ - GIMPLE_PASS, /* type */ - "fix_loops", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_fix_loops : public gimple_opt_pass -{ -public: - pass_fix_loops (gcc::context *ctxt) - : gimple_opt_pass (pass_data_fix_loops, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) { return flag_tree_loop_optimize; } - - virtual unsigned int execute (function *fn); -}; // class pass_fix_loops - -unsigned int -pass_fix_loops::execute (function *) -{ - if (loops_state_satisfies_p (LOOPS_NEED_FIXUP)) - { - calculate_dominance_info (CDI_DOMINATORS); - fix_loop_structure (NULL); - } - return 0; -} - -} // anon namespace - -gimple_opt_pass * -make_pass_fix_loops (gcc::context *ctxt) -{ - return new pass_fix_loops (ctxt); -} - - -/* Gate for loop pass group. The group is controlled by -ftree-loop-optimize - but we also avoid running it when the IL doesn't contain any loop. */ - -static bool -gate_loop (function *fn) -{ - if (!flag_tree_loop_optimize) - return false; - - /* For -fdump-passes which runs before loop discovery print the - state of -ftree-loop-optimize. */ - if (!loops_for_fn (fn)) - return true; - - return number_of_loops (fn) > 1; -} - -/* The loop superpass. */ - -namespace { - -const pass_data pass_data_tree_loop = -{ - GIMPLE_PASS, /* type */ - "loop", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_tree_loop : public gimple_opt_pass -{ -public: - pass_tree_loop (gcc::context *ctxt) - : gimple_opt_pass (pass_data_tree_loop, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *fn) { return gate_loop (fn); } - -}; // class pass_tree_loop - -} // anon namespace - -gimple_opt_pass * -make_pass_tree_loop (gcc::context *ctxt) -{ - return new pass_tree_loop (ctxt); -} - -/* Gate for oacc kernels pass group. */ - -static bool -gate_oacc_kernels (function *fn) -{ - if (!flag_openacc) - return false; - - if (!lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn->decl))) - return false; - - for (auto loop : loops_list (cfun, 0)) - if (loop->in_oacc_kernels_region) - return true; - - return false; -} - -/* The oacc kernels superpass. */ - -namespace { - -const pass_data pass_data_oacc_kernels = -{ - GIMPLE_PASS, /* type */ - "oacc_kernels", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_oacc_kernels : public gimple_opt_pass -{ -public: - pass_oacc_kernels (gcc::context *ctxt) - : gimple_opt_pass (pass_data_oacc_kernels, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *fn) { return gate_oacc_kernels (fn); } - -}; // class pass_oacc_kernels - -} // anon namespace - -gimple_opt_pass * -make_pass_oacc_kernels (gcc::context *ctxt) -{ - return new pass_oacc_kernels (ctxt); -} - -/* The ipa oacc superpass. */ - -namespace { - -const pass_data pass_data_ipa_oacc = -{ - SIMPLE_IPA_PASS, /* type */ - "ipa_oacc", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_ipa_oacc : public simple_ipa_opt_pass -{ -public: - pass_ipa_oacc (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_ipa_oacc, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) - { - return (optimize - && flag_openacc - /* Don't bother doing anything if the program has errors. */ - && !seen_error ()); - } - -}; // class pass_ipa_oacc - -} // anon namespace - -simple_ipa_opt_pass * -make_pass_ipa_oacc (gcc::context *ctxt) -{ - return new pass_ipa_oacc (ctxt); -} - -/* The ipa oacc kernels pass. */ - -namespace { - -const pass_data pass_data_ipa_oacc_kernels = -{ - SIMPLE_IPA_PASS, /* type */ - "ipa_oacc_kernels", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_ipa_oacc_kernels : public simple_ipa_opt_pass -{ -public: - pass_ipa_oacc_kernels (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_ipa_oacc_kernels, ctxt) - {} - -}; // class pass_ipa_oacc_kernels - -} // anon namespace - -simple_ipa_opt_pass * -make_pass_ipa_oacc_kernels (gcc::context *ctxt) -{ - return new pass_ipa_oacc_kernels (ctxt); -} - -/* The no-loop superpass. */ - -namespace { - -const pass_data pass_data_tree_no_loop = -{ - GIMPLE_PASS, /* type */ - "no_loop", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_TREE_NOLOOP, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_tree_no_loop : public gimple_opt_pass -{ -public: - pass_tree_no_loop (gcc::context *ctxt) - : gimple_opt_pass (pass_data_tree_no_loop, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *fn) { return !gate_loop (fn); } - -}; // class pass_tree_no_loop - -} // anon namespace - -gimple_opt_pass * -make_pass_tree_no_loop (gcc::context *ctxt) -{ - return new pass_tree_no_loop (ctxt); -} - - -/* Loop optimizer initialization. */ - -namespace { - -const pass_data pass_data_tree_loop_init = -{ - GIMPLE_PASS, /* type */ - "loopinit", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_NONE, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - TODO_update_address_taken, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_tree_loop_init : public gimple_opt_pass -{ -public: - pass_tree_loop_init (gcc::context *ctxt) - : gimple_opt_pass (pass_data_tree_loop_init, ctxt) - {} - - /* opt_pass methods: */ - virtual unsigned int execute (function *); - -}; // class pass_tree_loop_init - -unsigned int -pass_tree_loop_init::execute (function *fun ATTRIBUTE_UNUSED) -{ - /* When processing a loop in the loop pipeline, we should be able to assert - that: - (loops_state_satisfies_p (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS - | LOOP_CLOSED_SSA) - && scev_initialized_p ()) - */ - loop_optimizer_init (LOOPS_NORMAL - | LOOPS_HAVE_RECORDED_EXITS); - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); - scev_initialize (); - - return 0; -} - -} // anon namespace - -gimple_opt_pass * -make_pass_tree_loop_init (gcc::context *ctxt) -{ - return new pass_tree_loop_init (ctxt); -} - -/* Propagation of constants using scev. */ - -namespace { - -const pass_data pass_data_scev_cprop = -{ - GIMPLE_PASS, /* type */ - "sccp", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_SCEV_CONST, /* tv_id */ - ( PROP_cfg | PROP_ssa ), /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_scev_cprop : public gimple_opt_pass -{ -public: - pass_scev_cprop (gcc::context *ctxt) - : gimple_opt_pass (pass_data_scev_cprop, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) { return flag_tree_scev_cprop; } - virtual unsigned int execute (function *); - -}; // class pass_scev_cprop - -unsigned -pass_scev_cprop::execute (function *) -{ - bool any = false; - - /* Perform final value replacement in loops, in case the replacement - expressions are cheap. */ - for (auto loop : loops_list (cfun, LI_FROM_INNERMOST)) - any |= final_value_replacement_loop (loop); - - return any ? TODO_cleanup_cfg | TODO_update_ssa_only_virtuals : 0; -} - -} // anon namespace - -gimple_opt_pass * -make_pass_scev_cprop (gcc::context *ctxt) -{ - return new pass_scev_cprop (ctxt); -} - -/* Induction variable optimizations. */ - -namespace { - -const pass_data pass_data_iv_optimize = -{ - GIMPLE_PASS, /* type */ - "ivopts", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_TREE_LOOP_IVOPTS, /* tv_id */ - ( PROP_cfg | PROP_ssa ), /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_update_ssa, /* todo_flags_finish */ -}; - -class pass_iv_optimize : public gimple_opt_pass -{ -public: - pass_iv_optimize (gcc::context *ctxt) - : gimple_opt_pass (pass_data_iv_optimize, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) { return flag_ivopts != 0; } - virtual unsigned int execute (function *); - -}; // class pass_iv_optimize - -unsigned int -pass_iv_optimize::execute (function *fun) -{ - if (number_of_loops (fun) <= 1) - return 0; - - tree_ssa_iv_optimize (); - return 0; -} - -} // anon namespace - -gimple_opt_pass * -make_pass_iv_optimize (gcc::context *ctxt) -{ - return new pass_iv_optimize (ctxt); -} - -/* Loop optimizer finalization. */ - -static unsigned int -tree_ssa_loop_done (void) -{ - free_numbers_of_iterations_estimates (cfun); - scev_finalize (); - loop_optimizer_finalize (cfun, true); - return 0; -} - -namespace { - -const pass_data pass_data_tree_loop_done = -{ - GIMPLE_PASS, /* type */ - "loopdone", /* name */ - OPTGROUP_LOOP, /* optinfo_flags */ - TV_NONE, /* tv_id */ - PROP_cfg, /* properties_required */ - PROP_loop_opts_done, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_cleanup_cfg, /* todo_flags_finish */ -}; - -class pass_tree_loop_done : public gimple_opt_pass -{ -public: - pass_tree_loop_done (gcc::context *ctxt) - : gimple_opt_pass (pass_data_tree_loop_done, ctxt) - {} - - /* opt_pass methods: */ - virtual unsigned int execute (function *) { return tree_ssa_loop_done (); } - -}; // class pass_tree_loop_done - -} // anon namespace - -gimple_opt_pass * -make_pass_tree_loop_done (gcc::context *ctxt) -{ - return new pass_tree_loop_done (ctxt); -} - -/* Calls CBCK for each index in memory reference ADDR_P. There are two - kinds situations handled; in each of these cases, the memory reference - and DATA are passed to the callback: - - Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also - pass the pointer to the index to the callback. - - Pointer dereference: INDIRECT_REF (addr). In this case we also pass the - pointer to addr to the callback. - - If the callback returns false, the whole search stops and false is returned. - Otherwise the function returns true after traversing through the whole - reference *ADDR_P. */ - -bool -for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data) -{ - tree *nxt, *idx; - - for (; ; addr_p = nxt) - { - switch (TREE_CODE (*addr_p)) - { - case SSA_NAME: - return cbck (*addr_p, addr_p, data); - - case MEM_REF: - nxt = &TREE_OPERAND (*addr_p, 0); - return cbck (*addr_p, nxt, data); - - case BIT_FIELD_REF: - case VIEW_CONVERT_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - nxt = &TREE_OPERAND (*addr_p, 0); - break; - - case COMPONENT_REF: - /* If the component has varying offset, it behaves like index - as well. */ - idx = &TREE_OPERAND (*addr_p, 2); - if (*idx - && !cbck (*addr_p, idx, data)) - return false; - - nxt = &TREE_OPERAND (*addr_p, 0); - break; - - case ARRAY_REF: - case ARRAY_RANGE_REF: - nxt = &TREE_OPERAND (*addr_p, 0); - if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data)) - return false; - break; - - case CONSTRUCTOR: - return true; - - case ADDR_EXPR: - gcc_assert (is_gimple_min_invariant (*addr_p)); - return true; - - case TARGET_MEM_REF: - idx = &TMR_BASE (*addr_p); - if (*idx - && !cbck (*addr_p, idx, data)) - return false; - idx = &TMR_INDEX (*addr_p); - if (*idx - && !cbck (*addr_p, idx, data)) - return false; - idx = &TMR_INDEX2 (*addr_p); - if (*idx - && !cbck (*addr_p, idx, data)) - return false; - return true; - - default: - if (DECL_P (*addr_p) - || CONSTANT_CLASS_P (*addr_p)) - return true; - gcc_unreachable (); - } - } -} - - -/* The name and the length of the currently generated variable - for lsm. */ -#define MAX_LSM_NAME_LENGTH 40 -static char lsm_tmp_name[MAX_LSM_NAME_LENGTH + 1]; -static int lsm_tmp_name_length; - -/* Adds S to lsm_tmp_name. */ - -static void -lsm_tmp_name_add (const char *s) -{ - int l = strlen (s) + lsm_tmp_name_length; - if (l > MAX_LSM_NAME_LENGTH) - return; - - strcpy (lsm_tmp_name + lsm_tmp_name_length, s); - lsm_tmp_name_length = l; -} - -/* Stores the name for temporary variable that replaces REF to - lsm_tmp_name. */ - -static void -gen_lsm_tmp_name (tree ref) -{ - const char *name; - - switch (TREE_CODE (ref)) - { - case MEM_REF: - case TARGET_MEM_REF: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - lsm_tmp_name_add ("_"); - break; - - case ADDR_EXPR: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - break; - - case BIT_FIELD_REF: - case VIEW_CONVERT_EXPR: - case ARRAY_RANGE_REF: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - break; - - case REALPART_EXPR: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - lsm_tmp_name_add ("_RE"); - break; - - case IMAGPART_EXPR: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - lsm_tmp_name_add ("_IM"); - break; - - case COMPONENT_REF: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - lsm_tmp_name_add ("_"); - name = get_name (TREE_OPERAND (ref, 1)); - if (!name) - name = "F"; - lsm_tmp_name_add (name); - break; - - case ARRAY_REF: - gen_lsm_tmp_name (TREE_OPERAND (ref, 0)); - lsm_tmp_name_add ("_I"); - break; - - case SSA_NAME: - case VAR_DECL: - case PARM_DECL: - case FUNCTION_DECL: - case LABEL_DECL: - name = get_name (ref); - if (!name) - name = "D"; - lsm_tmp_name_add (name); - break; - - case STRING_CST: - lsm_tmp_name_add ("S"); - break; - - case RESULT_DECL: - lsm_tmp_name_add ("R"); - break; - - case INTEGER_CST: - default: - /* Nothing. */ - break; - } -} - -/* Determines name for temporary variable that replaces REF. - The name is accumulated into the lsm_tmp_name variable. - N is added to the name of the temporary. */ - -char * -get_lsm_tmp_name (tree ref, unsigned n, const char *suffix) -{ - char ns[2]; - - lsm_tmp_name_length = 0; - gen_lsm_tmp_name (ref); - lsm_tmp_name_add ("_lsm"); - if (n < 10) - { - ns[0] = '0' + n; - ns[1] = 0; - lsm_tmp_name_add (ns); - } - if (suffix != NULL) - lsm_tmp_name_add (suffix); - return lsm_tmp_name; -} - -/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */ - -unsigned -tree_num_loop_insns (class loop *loop, eni_weights *weights) -{ - basic_block *body = get_loop_body (loop); - gimple_stmt_iterator gsi; - unsigned size = 0, i; - - for (i = 0; i < loop->num_nodes; i++) - for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi)) - size += estimate_num_insns (gsi_stmt (gsi), weights); - free (body); - - return size; -} - - - |