2014-10-27 Andrew MacLeod <amacleod@redhat.com> * testsuite/gcc.dg/plugin/ggcplug.c: Shuffle includes to include gcc-plugin.h earlier. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * c/c-typeck.c: Adjust include files. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * c-family/c-gimplify.c: Adjust include files. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * cp/cp-gimplify.c: Adjust include files. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * go/go-gcc.cc: Adjust include files. * go/go-lang.c: Ditto. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * java/java-gimplify.c: Adjust include files. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * lto/lto-lang.c: Adjust include files. * lto/lto-object.c: Ditto. * lto/lto-partition.c: Ditto. * lto/lto-symtab.c: Ditto. * lto/lto.c: Ditto. 2014-10-27 Andrew MacLeod <amacleod@redhat.com> * basic-block.h: Remove all includes. (enum profile_status_d, struct control_flow_graph): Move to cfg.h * cfg.h (profile_status_d, struct control_flow_graph): Relocate here. * Makefile.in (GTFILES): Add cfg.h to list. * cgraph.h (symbol_table::create_empty): Move to cgraph.c. * cgraph.c (symbol_table::create_empty): Relocate from cgraph.h. * genconditions.c (write_header): Add predict.h and basic-block.h to lits of includes. * genemit.c (main): Ditto. * genpreds.c (write_insn_preds_c): Ditto. * genrecog.c (write_header): Ditto. * gengtype.c (open_base_files): Add predict.h, basic-block.h, and cfg.h to list of includes. * alias.c: Adjust include files. * asan.c: Ditto. * auto-inc-dec.c: Ditto. * auto-profile.c: Ditto. * bb-reorder.c: Ditto. * bt-load.c: Ditto. * builtins.c: Ditto. * caller-save.c: Ditto. * calls.c: Ditto. * cfg.c: Ditto. * cfganal.c: Ditto. * cfgbuild.c: Ditto. * cfgcleanup.c: Ditto. * cfgexpand.c: Ditto. * cfghooks.c: Ditto. * cfgloop.c: Ditto. * cfgloopanal.c: Ditto. * cfgloopmanip.c: Ditto. * cfgrtl.c: Ditto. * cgraphbuild.c: Ditto. * cgraphclones.c: Ditto. * cgraphunit.c: Ditto. * combine-stack-adj.c: Ditto. * combine.c: Ditto. * compare-elim.c: Ditto. * coverage.c: Ditto. * cprop.c: Ditto. * cse.c: Ditto. * cselib.c: Ditto. * data-streamer-in.c: Ditto. * data-streamer-out.c: Ditto. * data-streamer.c: Ditto. * dce.c: Ditto. * ddg.c: Ditto. * ddg.h: Ditto. * df-core.c: Ditto. * df-problems.c: Ditto. * df-scan.c: Ditto. * df.h: Ditto. * dojump.c: Ditto. * dominance.c: Ditto. * domwalk.c: Ditto. * dse.c: Ditto. * dwarf2cfi.c: Ditto. * emit-rtl.c: Ditto. * et-forest.c: Ditto. * except.c: Ditto. * expmed.c: Ditto. * expr.c: Ditto. * final.c: Ditto. * fold-const.c: Ditto. * function.c: Ditto. * fwprop.c: Ditto. * gcc-plugin.h: Ditto. * gcse.c: Ditto. * generic-match-head.c: Ditto. * ggc-page.c: Ditto. * gimple-builder.c: Ditto. * gimple-expr.c: Ditto. * gimple-fold.c: Ditto. * gimple-iterator.c: Ditto. * gimple-low.c: Ditto. * gimple-match-head.c: Ditto. * gimple-pretty-print.c: Ditto. * gimple-ssa-isolate-paths.c: Ditto. * gimple-ssa-strength-reduction.c: Ditto. * gimple-streamer-in.c: Ditto. * gimple-streamer-out.c: Ditto. * gimple-streamer.h: Ditto. * gimple-walk.c: Ditto. * gimple.c: Ditto. * gimplify-me.c: Ditto. * gimplify.c: Ditto. * graph.c: Ditto. * graphite-blocking.c: Ditto. * graphite-clast-to-gimple.c: Ditto. * graphite-dependences.c: Ditto. * graphite-interchange.c: Ditto. * graphite-isl-ast-to-gimple.c: Ditto. * graphite-optimize-isl.c: Ditto. * graphite-poly.c: Ditto. * graphite-scop-detection.c: Ditto. * graphite-sese-to-poly.c: Ditto. * graphite.c: Ditto. * haifa-sched.c: Ditto. * hw-doloop.c: Ditto. * ifcvt.c: Ditto. * init-regs.c: Ditto. * internal-fn.c: Ditto. * ipa-cp.c: Ditto. * ipa-devirt.c: Ditto. * ipa-icf-gimple.c: Ditto. * ipa-icf.c: Ditto. * ipa-inline-analysis.c: Ditto. * ipa-inline.c: Ditto. * ipa-polymorphic-call.c: Ditto. * ipa-profile.c: Ditto. * ipa-prop.c: Ditto. * ipa-pure-const.c: Ditto. * ipa-reference.c: Ditto. * ipa-split.c: Ditto. * ipa-utils.c: Ditto. * ipa.c: Ditto. * ira-build.c: Ditto. * ira-color.c: Ditto. * ira-conflicts.c: Ditto. * ira-costs.c: Ditto. * ira-emit.c: Ditto. * ira-lives.c: Ditto. * ira.c: Ditto. * jump.c: Ditto. * lcm.c: Ditto. * loop-doloop.c: Ditto. * loop-init.c: Ditto. * loop-invariant.c: Ditto. * loop-iv.c: Ditto. * loop-unroll.c: Ditto. * lower-subreg.c: Ditto. * lra-assigns.c: Ditto. * lra-coalesce.c: Ditto. * lra-constraints.c: Ditto. * lra-eliminations.c: Ditto. * lra-lives.c: Ditto. * lra-spills.c: Ditto. * lra.c: Ditto. * lto-cgraph.c: Ditto. * lto-compress.c: Ditto. * lto-opts.c: Ditto. * lto-section-in.c: Ditto. * lto-section-out.c: Ditto. * lto-streamer-in.c: Ditto. * lto-streamer-out.c: Ditto. * lto-streamer.c: Ditto. * mcf.c: Ditto. * mode-switching.c: Ditto. * modulo-sched.c: Ditto. * omp-low.c: Ditto. * optabs.c: Ditto. * opts-global.c: Ditto. * passes.c: Ditto. * postreload-gcse.c: Ditto. * postreload.c: Ditto. * predict.c: Ditto. * print-rtl.c: Ditto. * profile.c: Ditto. * recog.c: Ditto. * ree.c: Ditto. * reg-stack.c: Ditto. * regcprop.c: Ditto. * regcprop.h: Ditto. * reginfo.c: Ditto. * regrename.c: Ditto. * regstat.c: Ditto. * reload.c: Ditto. * reload1.c: Ditto. * reorg.c: Ditto. * resource.c: Ditto. * rtlanal.c: Ditto. * sched-deps.c: Ditto. * sched-ebb.c: Ditto. * sched-int.h: Ditto. * sched-rgn.c: Ditto. * sched-vis.c: Ditto. * sel-sched-dump.c: Ditto. * sel-sched-ir.c: Ditto. * sel-sched-ir.h: Ditto. * sel-sched.c: Ditto. * sese.c: Ditto. * shrink-wrap.c: Ditto. * stack-ptr-mod.c: Ditto. * stmt.c: Ditto. * store-motion.c: Ditto. * symtab.c: Ditto. * toplev.c: Ditto. * tracer.c: Ditto. * trans-mem.c: Ditto. * tree-affine.c: Ditto. * tree-call-cdce.c: Ditto. * tree-cfg.c: Ditto. * tree-cfgcleanup.c: Ditto. * tree-chrec.c: Ditto. * tree-complex.c: Ditto. * tree-data-ref.c: Ditto. * tree-dfa.c: Ditto. * tree-eh.c: Ditto. * tree-emutls.c: Ditto. * tree-if-conv.c: Ditto. * tree-inline.c: Ditto. * tree-into-ssa.c: Ditto. * tree-loop-distribution.c: Ditto. * tree-nested.c: Ditto. * tree-nrv.c: Ditto. * tree-object-size.c: Ditto. * tree-outof-ssa.c: Ditto. * tree-parloops.c: Ditto. * tree-phinodes.c: Ditto. * tree-predcom.c: Ditto. * tree-pretty-print.c: Ditto. * tree-profile.c: Ditto. * tree-scalar-evolution.c: Ditto. * tree-sra.c: Ditto. * tree-ssa-address.c: Ditto. * tree-ssa-alias.c: Ditto. * tree-ssa-ccp.c: Ditto. * tree-ssa-coalesce.c: Ditto. * tree-ssa-copy.c: Ditto. * tree-ssa-copyrename.c: Ditto. * tree-ssa-dce.c: Ditto. * tree-ssa-dom.c: Ditto. * tree-ssa-dse.c: Ditto. * tree-ssa-forwprop.c: Ditto. * tree-ssa-ifcombine.c: Ditto. * tree-ssa-live.c: Ditto. * tree-ssa-loop-ch.c: Ditto. * tree-ssa-loop-im.c: Ditto. * tree-ssa-loop-ivcanon.c: Ditto. * tree-ssa-loop-ivopts.c: Ditto. * tree-ssa-loop-manip.c: Ditto. * tree-ssa-loop-niter.c: Ditto. * tree-ssa-loop-prefetch.c: Ditto. * tree-ssa-loop-unswitch.c: Ditto. * tree-ssa-loop.c: Ditto. * tree-ssa-math-opts.c: Ditto. * tree-ssa-operands.c: Ditto. * tree-ssa-phiopt.c: Ditto. * tree-ssa-phiprop.c: Ditto. * tree-ssa-pre.c: Ditto. * tree-ssa-propagate.c: Ditto. * tree-ssa-reassoc.c: Ditto. * tree-ssa-sccvn.c: Ditto. * tree-ssa-sink.c: Ditto. * tree-ssa-strlen.c: Ditto. * tree-ssa-structalias.c: Ditto. * tree-ssa-tail-merge.c: Ditto. * tree-ssa-ter.c: Ditto. * tree-ssa-threadedge.c: Ditto. * tree-ssa-threadupdate.c: Ditto. * tree-ssa-uncprop.c: Ditto. * tree-ssa-uninit.c: Ditto. * tree-ssa.c: Ditto. * tree-ssanames.c: Ditto. * tree-stdarg.c: Ditto. * tree-streamer-in.c: Ditto. * tree-streamer-out.c: Ditto. * tree-streamer.c: Ditto. * tree-switch-conversion.c: Ditto. * tree-tailcall.c: Ditto. * tree-vect-data-refs.c: Ditto. * tree-vect-generic.c: Ditto. * tree-vect-loop-manip.c: Ditto. * tree-vect-loop.c: Ditto. * tree-vect-patterns.c: Ditto. * tree-vect-slp.c: Ditto. * tree-vect-stmts.c: Ditto. * tree-vectorizer.c: Ditto. * tree-vrp.c: Ditto. * tree.c: Ditto. * tsan.c: Ditto. * ubsan.c: Ditto. * valtrack.c: Ditto. * valtrack.h: Ditto. * value-prof.c: Ditto. * var-tracking.c: Ditto. * varasm.c: Ditto. * varpool.c: Ditto. * vtable-verify.c: Ditto. * web.c: Ditto. * config/aarch64/aarch64-builtins.c: Ditto. * config/aarch64/aarch64.c: Ditto. * config/alpha/alpha.c: Ditto. * config/arc/arc.c: Ditto. * config/arm/arm.c: Ditto. * config/avr/avr.c: Ditto. * config/bfin/bfin.c: Ditto. * config/c6x/c6x.c: Ditto. * config/cr16/cr16.c: Ditto. * config/cris/cris.c: Ditto. * config/darwin-c.c: Ditto. * config/darwin.c: Ditto. * config/epiphany/epiphany.c: Ditto. * config/epiphany/mode-switch-use.c: Ditto. * config/epiphany/resolve-sw-modes.c: Ditto. * config/fr30/fr30.c: Ditto. * config/frv/frv.c: Ditto. * config/h8300/h8300.c: Ditto. * config/i386/i386.c: Ditto. * config/i386/winnt.c: Ditto. * config/ia64/ia64.c: Ditto. * config/iq2000/iq2000.c: Ditto. * config/lm32/lm32.c: Ditto. * config/m32c/m32c.c: Ditto. * config/m32r/m32r.c: Ditto. * config/m68k/m68k.c: Ditto. * config/mcore/mcore.c: Ditto. * config/mep/mep.c: Ditto. * config/microblaze/microblaze.c: Ditto. * config/mips/mips.c: Ditto. * config/mmix/mmix.c: Ditto. * config/mn10300/mn10300.c: Ditto. * config/moxie/moxie.c: Ditto. * config/msp430/msp430.c: Ditto. * config/nds32/nds32-cost.c: Ditto. * config/nds32/nds32-fp-as-gp.c: Ditto. * config/nds32/nds32-intrinsic.c: Ditto. * config/nds32/nds32-isr.c: Ditto. * config/nds32/nds32-md-auxiliary.c: Ditto. * config/nds32/nds32-memory-manipulation.c: Ditto. * config/nds32/nds32-pipelines-auxiliary.c: Ditto. * config/nds32/nds32-predicates.c: Ditto. * config/nds32/nds32.c: Ditto. * config/nios2/nios2.c: Ditto. * config/pa/pa.c: Ditto. * config/pdp11/pdp11.c: Ditto. * config/rl78/rl78.c: Ditto. * config/rs6000/rs6000.c: Ditto. * config/rx/rx.c: Ditto. * config/s390/s390.c: Ditto. * config/sh/sh-mem.cc: Ditto. * config/sh/sh.c: Ditto. * config/sh/sh_optimize_sett_clrt.cc: Ditto. * config/sh/sh_treg_combine.cc: Ditto. * config/sparc/sparc.c: Ditto. * config/spu/spu.c: Ditto. * config/stormy16/stormy16.c: Ditto. * config/tilegx/tilegx.c: Ditto. * config/tilepro/tilepro.c: Ditto. * config/v850/v850.c: Ditto. * config/vax/vax.c: Ditto. * config/xtensa/xtensa.c: Ditto. From-SVN: r216735
664 lines
16 KiB
C
664 lines
16 KiB
C
/* Loop optimizer initialization routines and RTL loop optimization passes.
|
||
Copyright (C) 2002-2014 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 "tm.h"
|
||
#include "rtl.h"
|
||
#include "tree.h"
|
||
#include "regs.h"
|
||
#include "obstack.h"
|
||
#include "predict.h"
|
||
#include "vec.h"
|
||
#include "hashtab.h"
|
||
#include "hash-set.h"
|
||
#include "machmode.h"
|
||
#include "hard-reg-set.h"
|
||
#include "input.h"
|
||
#include "function.h"
|
||
#include "dominance.h"
|
||
#include "cfg.h"
|
||
#include "cfgcleanup.h"
|
||
#include "basic-block.h"
|
||
#include "cfgloop.h"
|
||
#include "tree-pass.h"
|
||
#include "flags.h"
|
||
#include "df.h"
|
||
#include "ggc.h"
|
||
#include "tree-ssa-loop-niter.h"
|
||
#include "loop-unroll.h"
|
||
|
||
|
||
/* Apply FLAGS to the loop state. */
|
||
|
||
static void
|
||
apply_loop_flags (unsigned flags)
|
||
{
|
||
if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES)
|
||
{
|
||
/* If the loops may have multiple latches, we cannot canonicalize
|
||
them further (and most of the loop manipulation functions will
|
||
not work). However, we avoid modifying cfg, which some
|
||
passes may want. */
|
||
gcc_assert ((flags & ~(LOOPS_MAY_HAVE_MULTIPLE_LATCHES
|
||
| LOOPS_HAVE_RECORDED_EXITS)) == 0);
|
||
loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
|
||
}
|
||
else
|
||
disambiguate_loops_with_multiple_latches ();
|
||
|
||
/* Create pre-headers. */
|
||
if (flags & LOOPS_HAVE_PREHEADERS)
|
||
{
|
||
int cp_flags = CP_SIMPLE_PREHEADERS;
|
||
|
||
if (flags & LOOPS_HAVE_FALLTHRU_PREHEADERS)
|
||
cp_flags |= CP_FALLTHRU_PREHEADERS;
|
||
|
||
create_preheaders (cp_flags);
|
||
}
|
||
|
||
/* Force all latches to have only single successor. */
|
||
if (flags & LOOPS_HAVE_SIMPLE_LATCHES)
|
||
force_single_succ_latches ();
|
||
|
||
/* Mark irreducible loops. */
|
||
if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
|
||
mark_irreducible_loops ();
|
||
|
||
if (flags & LOOPS_HAVE_RECORDED_EXITS)
|
||
record_loop_exits ();
|
||
}
|
||
|
||
/* Initialize loop structures. This is used by the tree and RTL loop
|
||
optimizers. FLAGS specify what properties to compute and/or ensure for
|
||
loops. */
|
||
|
||
void
|
||
loop_optimizer_init (unsigned flags)
|
||
{
|
||
timevar_push (TV_LOOP_INIT);
|
||
|
||
if (!current_loops)
|
||
{
|
||
gcc_assert (!(cfun->curr_properties & PROP_loops));
|
||
|
||
/* Find the loops. */
|
||
current_loops = flow_loops_find (NULL);
|
||
}
|
||
else
|
||
{
|
||
bool recorded_exits = loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS);
|
||
bool needs_fixup = loops_state_satisfies_p (LOOPS_NEED_FIXUP);
|
||
|
||
gcc_assert (cfun->curr_properties & PROP_loops);
|
||
|
||
/* Ensure that the dominators are computed, like flow_loops_find does. */
|
||
calculate_dominance_info (CDI_DOMINATORS);
|
||
|
||
#ifdef ENABLE_CHECKING
|
||
if (!needs_fixup)
|
||
verify_loop_structure ();
|
||
#endif
|
||
|
||
/* Clear all flags. */
|
||
if (recorded_exits)
|
||
release_recorded_exits ();
|
||
loops_state_clear (~0U);
|
||
|
||
if (needs_fixup)
|
||
{
|
||
/* Apply LOOPS_MAY_HAVE_MULTIPLE_LATCHES early as fix_loop_structure
|
||
re-applies flags. */
|
||
loops_state_set (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
|
||
fix_loop_structure (NULL);
|
||
}
|
||
}
|
||
|
||
/* Apply flags to loops. */
|
||
apply_loop_flags (flags);
|
||
|
||
/* Dump loops. */
|
||
flow_loops_dump (dump_file, NULL, 1);
|
||
|
||
#ifdef ENABLE_CHECKING
|
||
verify_loop_structure ();
|
||
#endif
|
||
|
||
timevar_pop (TV_LOOP_INIT);
|
||
}
|
||
|
||
/* Finalize loop structures. */
|
||
|
||
void
|
||
loop_optimizer_finalize (void)
|
||
{
|
||
struct loop *loop;
|
||
basic_block bb;
|
||
|
||
timevar_push (TV_LOOP_FINI);
|
||
|
||
if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
|
||
release_recorded_exits ();
|
||
|
||
free_numbers_of_iterations_estimates ();
|
||
|
||
/* If we should preserve loop structure, do not free it but clear
|
||
flags that advanced properties are there as we are not preserving
|
||
that in full. */
|
||
if (cfun->curr_properties & PROP_loops)
|
||
{
|
||
loops_state_clear (LOOP_CLOSED_SSA
|
||
| LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS
|
||
| LOOPS_HAVE_PREHEADERS
|
||
| LOOPS_HAVE_SIMPLE_LATCHES
|
||
| LOOPS_HAVE_FALLTHRU_PREHEADERS);
|
||
loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
|
||
goto loop_fini_done;
|
||
}
|
||
|
||
gcc_assert (current_loops != NULL);
|
||
|
||
FOR_EACH_LOOP (loop, 0)
|
||
free_simple_loop_desc (loop);
|
||
|
||
/* Clean up. */
|
||
flow_loops_free (current_loops);
|
||
ggc_free (current_loops);
|
||
current_loops = NULL;
|
||
|
||
FOR_ALL_BB_FN (bb, cfun)
|
||
{
|
||
bb->loop_father = NULL;
|
||
}
|
||
|
||
loop_fini_done:
|
||
timevar_pop (TV_LOOP_FINI);
|
||
}
|
||
|
||
/* The structure of loops might have changed. Some loops might get removed
|
||
(and their headers and latches were set to NULL), loop exists might get
|
||
removed (thus the loop nesting may be wrong), and some blocks and edges
|
||
were changed (so the information about bb --> loop mapping does not have
|
||
to be correct). But still for the remaining loops the header dominates
|
||
the latch, and loops did not get new subloops (new loops might possibly
|
||
get created, but we are not interested in them). Fix up the mess.
|
||
|
||
If CHANGED_BBS is not NULL, basic blocks whose loop depth has changed are
|
||
marked in it.
|
||
|
||
Returns the number of new discovered loops. */
|
||
|
||
unsigned
|
||
fix_loop_structure (bitmap changed_bbs)
|
||
{
|
||
basic_block bb;
|
||
int record_exits = 0;
|
||
struct loop *loop;
|
||
unsigned old_nloops, i;
|
||
|
||
timevar_push (TV_LOOP_INIT);
|
||
|
||
/* We need exact and fast dominance info to be available. */
|
||
gcc_assert (dom_info_state (CDI_DOMINATORS) == DOM_OK);
|
||
|
||
if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
|
||
{
|
||
release_recorded_exits ();
|
||
record_exits = LOOPS_HAVE_RECORDED_EXITS;
|
||
}
|
||
|
||
/* Remember the depth of the blocks in the loop hierarchy, so that we can
|
||
recognize blocks whose loop nesting relationship has changed. */
|
||
if (changed_bbs)
|
||
FOR_EACH_BB_FN (bb, cfun)
|
||
bb->aux = (void *) (size_t) loop_depth (bb->loop_father);
|
||
|
||
/* Remove the dead loops from structures. We start from the innermost
|
||
loops, so that when we remove the loops, we know that the loops inside
|
||
are preserved, and do not waste time relinking loops that will be
|
||
removed later. */
|
||
FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
|
||
{
|
||
/* Detect the case that the loop is no longer present even though
|
||
it wasn't marked for removal.
|
||
??? If we do that we can get away with not marking loops for
|
||
removal at all. And possibly avoid some spurious removals. */
|
||
if (loop->header
|
||
&& bb_loop_header_p (loop->header))
|
||
continue;
|
||
|
||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||
fprintf (dump_file, "fix_loop_structure: removing loop %d\n",
|
||
loop->num);
|
||
|
||
while (loop->inner)
|
||
{
|
||
struct loop *ploop = loop->inner;
|
||
flow_loop_tree_node_remove (ploop);
|
||
flow_loop_tree_node_add (loop_outer (loop), ploop);
|
||
}
|
||
|
||
/* Remove the loop. */
|
||
if (loop->header)
|
||
loop->former_header = loop->header;
|
||
else
|
||
gcc_assert (loop->former_header != NULL);
|
||
loop->header = NULL;
|
||
flow_loop_tree_node_remove (loop);
|
||
}
|
||
|
||
/* Remember the number of loops so we can return how many new loops
|
||
flow_loops_find discovered. */
|
||
old_nloops = number_of_loops (cfun);
|
||
|
||
/* Re-compute loop structure in-place. */
|
||
flow_loops_find (current_loops);
|
||
|
||
/* Mark the blocks whose loop has changed. */
|
||
if (changed_bbs)
|
||
{
|
||
FOR_EACH_BB_FN (bb, cfun)
|
||
{
|
||
if ((void *) (size_t) loop_depth (bb->loop_father) != bb->aux)
|
||
bitmap_set_bit (changed_bbs, bb->index);
|
||
|
||
bb->aux = NULL;
|
||
}
|
||
}
|
||
|
||
/* Finally free deleted loops. */
|
||
FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop)
|
||
if (loop && loop->header == NULL)
|
||
{
|
||
if (dump_file
|
||
&& ((unsigned) loop->former_header->index
|
||
< basic_block_info_for_fn (cfun)->length ()))
|
||
{
|
||
basic_block former_header
|
||
= BASIC_BLOCK_FOR_FN (cfun, loop->former_header->index);
|
||
/* If the old header still exists we want to check if the
|
||
original loop is re-discovered or the old header is now
|
||
part of a newly discovered loop.
|
||
In both cases we should have avoided removing the loop. */
|
||
if (former_header == loop->former_header)
|
||
{
|
||
if (former_header->loop_father->header == former_header)
|
||
fprintf (dump_file, "fix_loop_structure: rediscovered "
|
||
"removed loop %d as loop %d with old header %d\n",
|
||
loop->num, former_header->loop_father->num,
|
||
former_header->index);
|
||
else if ((unsigned) former_header->loop_father->num
|
||
>= old_nloops)
|
||
fprintf (dump_file, "fix_loop_structure: header %d of "
|
||
"removed loop %d is part of the newly "
|
||
"discovered loop %d with header %d\n",
|
||
former_header->index, loop->num,
|
||
former_header->loop_father->num,
|
||
former_header->loop_father->header->index);
|
||
}
|
||
}
|
||
(*get_loops (cfun))[i] = NULL;
|
||
flow_loop_free (loop);
|
||
}
|
||
|
||
loops_state_clear (LOOPS_NEED_FIXUP);
|
||
|
||
/* Apply flags to loops. */
|
||
apply_loop_flags (current_loops->state | record_exits);
|
||
|
||
#ifdef ENABLE_CHECKING
|
||
verify_loop_structure ();
|
||
#endif
|
||
|
||
timevar_pop (TV_LOOP_INIT);
|
||
|
||
return number_of_loops (cfun) - old_nloops;
|
||
}
|
||
|
||
/* The RTL loop superpass. The actual passes are subpasses. See passes.c for
|
||
more on that. */
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_loop2 =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
0, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
0, /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_loop2 : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_loop2 (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_loop2, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual bool gate (function *);
|
||
|
||
}; // class pass_loop2
|
||
|
||
bool
|
||
pass_loop2::gate (function *fun)
|
||
{
|
||
if (optimize > 0
|
||
&& (flag_move_loop_invariants
|
||
|| flag_unswitch_loops
|
||
|| flag_unroll_loops
|
||
#ifdef HAVE_doloop_end
|
||
|| (flag_branch_on_count_reg && HAVE_doloop_end)
|
||
#endif
|
||
))
|
||
return true;
|
||
else
|
||
{
|
||
/* No longer preserve loops, remove them now. */
|
||
fun->curr_properties &= ~PROP_loops;
|
||
if (current_loops)
|
||
loop_optimizer_finalize ();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_loop2 (gcc::context *ctxt)
|
||
{
|
||
return new pass_loop2 (ctxt);
|
||
}
|
||
|
||
|
||
/* Initialization of the RTL loop passes. */
|
||
static unsigned int
|
||
rtl_loop_init (void)
|
||
{
|
||
gcc_assert (current_ir_type () == IR_RTL_CFGLAYOUT);
|
||
|
||
if (dump_file)
|
||
{
|
||
dump_reg_info (dump_file);
|
||
dump_flow_info (dump_file, dump_flags);
|
||
}
|
||
|
||
loop_optimizer_init (LOOPS_NORMAL);
|
||
return 0;
|
||
}
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_rtl_loop_init =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2_init", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
0, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
0, /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_rtl_loop_init : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_rtl_loop_init (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_rtl_loop_init, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual unsigned int execute (function *) { return rtl_loop_init (); }
|
||
|
||
}; // class pass_rtl_loop_init
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_rtl_loop_init (gcc::context *ctxt)
|
||
{
|
||
return new pass_rtl_loop_init (ctxt);
|
||
}
|
||
|
||
|
||
/* Finalization of the RTL loop passes. */
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_rtl_loop_done =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2_done", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
PROP_loops, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
0, /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_rtl_loop_done : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_rtl_loop_done (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_rtl_loop_done, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual unsigned int execute (function *);
|
||
|
||
}; // class pass_rtl_loop_done
|
||
|
||
unsigned int
|
||
pass_rtl_loop_done::execute (function *fun)
|
||
{
|
||
/* No longer preserve loops, remove them now. */
|
||
fun->curr_properties &= ~PROP_loops;
|
||
loop_optimizer_finalize ();
|
||
free_dominance_info (CDI_DOMINATORS);
|
||
|
||
cleanup_cfg (0);
|
||
if (dump_file)
|
||
{
|
||
dump_reg_info (dump_file);
|
||
dump_flow_info (dump_file, dump_flags);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_rtl_loop_done (gcc::context *ctxt)
|
||
{
|
||
return new pass_rtl_loop_done (ctxt);
|
||
}
|
||
|
||
|
||
/* Loop invariant code motion. */
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_rtl_move_loop_invariants =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2_invariant", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP_MOVE_INVARIANTS, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
0, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
( TODO_df_verify | TODO_df_finish ), /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_rtl_move_loop_invariants : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_rtl_move_loop_invariants (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_rtl_move_loop_invariants, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual bool gate (function *) { return flag_move_loop_invariants; }
|
||
virtual unsigned int execute (function *fun)
|
||
{
|
||
if (number_of_loops (fun) > 1)
|
||
move_loop_invariants ();
|
||
return 0;
|
||
}
|
||
|
||
}; // class pass_rtl_move_loop_invariants
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_rtl_move_loop_invariants (gcc::context *ctxt)
|
||
{
|
||
return new pass_rtl_move_loop_invariants (ctxt);
|
||
}
|
||
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_rtl_unroll_loops =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2_unroll", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP_UNROLL, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
0, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
0, /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_rtl_unroll_loops : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_rtl_unroll_loops (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_rtl_unroll_loops, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual bool gate (function *)
|
||
{
|
||
return (flag_peel_loops || flag_unroll_loops || flag_unroll_all_loops);
|
||
}
|
||
|
||
virtual unsigned int execute (function *);
|
||
|
||
}; // class pass_rtl_unroll_loops
|
||
|
||
unsigned int
|
||
pass_rtl_unroll_loops::execute (function *fun)
|
||
{
|
||
if (number_of_loops (fun) > 1)
|
||
{
|
||
int flags = 0;
|
||
if (dump_file)
|
||
df_dump (dump_file);
|
||
|
||
if (flag_unroll_loops)
|
||
flags |= UAP_UNROLL;
|
||
if (flag_unroll_all_loops)
|
||
flags |= UAP_UNROLL_ALL;
|
||
|
||
unroll_loops (flags);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_rtl_unroll_loops (gcc::context *ctxt)
|
||
{
|
||
return new pass_rtl_unroll_loops (ctxt);
|
||
}
|
||
|
||
|
||
namespace {
|
||
|
||
const pass_data pass_data_rtl_doloop =
|
||
{
|
||
RTL_PASS, /* type */
|
||
"loop2_doloop", /* name */
|
||
OPTGROUP_LOOP, /* optinfo_flags */
|
||
TV_LOOP_DOLOOP, /* tv_id */
|
||
0, /* properties_required */
|
||
0, /* properties_provided */
|
||
0, /* properties_destroyed */
|
||
0, /* todo_flags_start */
|
||
0, /* todo_flags_finish */
|
||
};
|
||
|
||
class pass_rtl_doloop : public rtl_opt_pass
|
||
{
|
||
public:
|
||
pass_rtl_doloop (gcc::context *ctxt)
|
||
: rtl_opt_pass (pass_data_rtl_doloop, ctxt)
|
||
{}
|
||
|
||
/* opt_pass methods: */
|
||
virtual bool gate (function *);
|
||
virtual unsigned int execute (function *);
|
||
|
||
}; // class pass_rtl_doloop
|
||
|
||
bool
|
||
pass_rtl_doloop::gate (function *)
|
||
{
|
||
#ifdef HAVE_doloop_end
|
||
return (flag_branch_on_count_reg && HAVE_doloop_end);
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
|
||
unsigned int
|
||
pass_rtl_doloop::execute (function *fun ATTRIBUTE_UNUSED)
|
||
{
|
||
#ifdef HAVE_doloop_end
|
||
if (number_of_loops (fun) > 1)
|
||
doloop_optimize_loops ();
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
} // anon namespace
|
||
|
||
rtl_opt_pass *
|
||
make_pass_rtl_doloop (gcc::context *ctxt)
|
||
{
|
||
return new pass_rtl_doloop (ctxt);
|
||
}
|