aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/cfgloopanal.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/cfgloopanal.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/cfgloopanal.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/cfgloopanal.c b/gcc-4.2.1-5666.3/gcc/cfgloopanal.c
new file mode 100644
index 000000000..da5458384
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/cfgloopanal.c
@@ -0,0 +1,595 @@
+/* Natural loop analysis code for GNU compiler.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 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 2, 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 COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "hard-reg-set.h"
+#include "obstack.h"
+#include "basic-block.h"
+#include "cfgloop.h"
+#include "expr.h"
+#include "output.h"
+
+/* Checks whether BB is executed exactly once in each LOOP iteration. */
+
+bool
+just_once_each_iteration_p (const struct loop *loop, basic_block bb)
+{
+ /* It must be executed at least once each iteration. */
+ if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
+ return false;
+
+ /* And just once. */
+ if (bb->loop_father != loop)
+ return false;
+
+ /* But this was not enough. We might have some irreducible loop here. */
+ if (bb->flags & BB_IRREDUCIBLE_LOOP)
+ return false;
+
+ return true;
+}
+
+/* Structure representing edge of a graph. */
+
+struct edge
+{
+ int src, dest; /* Source and destination. */
+ struct edge *pred_next, *succ_next;
+ /* Next edge in predecessor and successor lists. */
+ void *data; /* Data attached to the edge. */
+};
+
+/* Structure representing vertex of a graph. */
+
+struct vertex
+{
+ struct edge *pred, *succ;
+ /* Lists of predecessors and successors. */
+ int component; /* Number of dfs restarts before reaching the
+ vertex. */
+ int post; /* Postorder number. */
+};
+
+/* Structure representing a graph. */
+
+struct graph
+{
+ int n_vertices; /* Number of vertices. */
+ struct vertex *vertices;
+ /* The vertices. */
+};
+
+/* Dumps graph G into F. */
+
+extern void dump_graph (FILE *, struct graph *);
+
+void
+dump_graph (FILE *f, struct graph *g)
+{
+ int i;
+ struct edge *e;
+
+ for (i = 0; i < g->n_vertices; i++)
+ {
+ if (!g->vertices[i].pred
+ && !g->vertices[i].succ)
+ continue;
+
+ fprintf (f, "%d (%d)\t<-", i, g->vertices[i].component);
+ for (e = g->vertices[i].pred; e; e = e->pred_next)
+ fprintf (f, " %d", e->src);
+ fprintf (f, "\n");
+
+ fprintf (f, "\t->");
+ for (e = g->vertices[i].succ; e; e = e->succ_next)
+ fprintf (f, " %d", e->dest);
+ fprintf (f, "\n");
+ }
+}
+
+/* Creates a new graph with N_VERTICES vertices. */
+
+static struct graph *
+new_graph (int n_vertices)
+{
+ struct graph *g = XNEW (struct graph);
+
+ g->n_vertices = n_vertices;
+ g->vertices = XCNEWVEC (struct vertex, n_vertices);
+
+ return g;
+}
+
+/* Adds an edge from F to T to graph G, with DATA attached. */
+
+static void
+add_edge (struct graph *g, int f, int t, void *data)
+{
+ struct edge *e = xmalloc (sizeof (struct edge));
+
+ e->src = f;
+ e->dest = t;
+ e->data = data;
+
+ e->pred_next = g->vertices[t].pred;
+ g->vertices[t].pred = e;
+
+ e->succ_next = g->vertices[f].succ;
+ g->vertices[f].succ = e;
+}
+
+/* Runs dfs search over vertices of G, from NQ vertices in queue QS.
+ The vertices in postorder are stored into QT. If FORWARD is false,
+ backward dfs is run. */
+
+static void
+dfs (struct graph *g, int *qs, int nq, int *qt, bool forward)
+{
+ int i, tick = 0, v, comp = 0, top;
+ struct edge *e;
+ struct edge **stack = xmalloc (sizeof (struct edge *) * g->n_vertices);
+
+ for (i = 0; i < g->n_vertices; i++)
+ {
+ g->vertices[i].component = -1;
+ g->vertices[i].post = -1;
+ }
+
+#define FST_EDGE(V) (forward ? g->vertices[(V)].succ : g->vertices[(V)].pred)
+#define NEXT_EDGE(E) (forward ? (E)->succ_next : (E)->pred_next)
+#define EDGE_SRC(E) (forward ? (E)->src : (E)->dest)
+#define EDGE_DEST(E) (forward ? (E)->dest : (E)->src)
+
+ for (i = 0; i < nq; i++)
+ {
+ v = qs[i];
+ if (g->vertices[v].post != -1)
+ continue;
+
+ g->vertices[v].component = comp++;
+ e = FST_EDGE (v);
+ top = 0;
+
+ while (1)
+ {
+ while (e && g->vertices[EDGE_DEST (e)].component != -1)
+ e = NEXT_EDGE (e);
+
+ if (!e)
+ {
+ if (qt)
+ qt[tick] = v;
+ g->vertices[v].post = tick++;
+
+ if (!top)
+ break;
+
+ e = stack[--top];
+ v = EDGE_SRC (e);
+ e = NEXT_EDGE (e);
+ continue;
+ }
+
+ stack[top++] = e;
+ v = EDGE_DEST (e);
+ e = FST_EDGE (v);
+ g->vertices[v].component = comp - 1;
+ }
+ }
+
+ free (stack);
+}
+
+/* Marks the edge E in graph G irreducible if it connects two vertices in the
+ same scc. */
+
+static void
+check_irred (struct graph *g, struct edge *e)
+{
+ edge real = e->data;
+
+ /* All edges should lead from a component with higher number to the
+ one with lower one. */
+ gcc_assert (g->vertices[e->src].component >= g->vertices[e->dest].component);
+
+ if (g->vertices[e->src].component != g->vertices[e->dest].component)
+ return;
+
+ real->flags |= EDGE_IRREDUCIBLE_LOOP;
+ if (flow_bb_inside_loop_p (real->src->loop_father, real->dest))
+ real->src->flags |= BB_IRREDUCIBLE_LOOP;
+}
+
+/* Runs CALLBACK for all edges in G. */
+
+static void
+for_each_edge (struct graph *g,
+ void (callback) (struct graph *, struct edge *))
+{
+ struct edge *e;
+ int i;
+
+ for (i = 0; i < g->n_vertices; i++)
+ for (e = g->vertices[i].succ; e; e = e->succ_next)
+ callback (g, e);
+}
+
+/* Releases the memory occupied by G. */
+
+static void
+free_graph (struct graph *g)
+{
+ struct edge *e, *n;
+ int i;
+
+ for (i = 0; i < g->n_vertices; i++)
+ for (e = g->vertices[i].succ; e; e = n)
+ {
+ n = e->succ_next;
+ free (e);
+ }
+ free (g->vertices);
+ free (g);
+}
+
+/* Marks blocks and edges that are part of non-recognized loops; i.e. we
+ throw away all latch edges and mark blocks inside any remaining cycle.
+ Everything is a bit complicated due to fact we do not want to do this
+ for parts of cycles that only "pass" through some loop -- i.e. for
+ each cycle, we want to mark blocks that belong directly to innermost
+ loop containing the whole cycle.
+
+ LOOPS is the loop tree. */
+
+#define LOOP_REPR(LOOP) ((LOOP)->num + last_basic_block)
+#define BB_REPR(BB) ((BB)->index + 1)
+
+void
+mark_irreducible_loops (struct loops *loops)
+{
+ basic_block act;
+ edge e;
+ edge_iterator ei;
+ int i, src, dest;
+ struct graph *g;
+ int *queue1 = XNEWVEC (int, last_basic_block + loops->num);
+ int *queue2 = XNEWVEC (int, last_basic_block + loops->num);
+ int nq, depth;
+ struct loop *cloop;
+
+ /* Reset the flags. */
+ FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+ {
+ act->flags &= ~BB_IRREDUCIBLE_LOOP;
+ FOR_EACH_EDGE (e, ei, act->succs)
+ e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
+ }
+
+ /* Create the edge lists. */
+ g = new_graph (last_basic_block + loops->num);
+
+ FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+ FOR_EACH_EDGE (e, ei, act->succs)
+ {
+ /* Ignore edges to exit. */
+ if (e->dest == EXIT_BLOCK_PTR)
+ continue;
+
+ /* And latch edges. */
+ if (e->dest->loop_father->header == e->dest
+ && e->dest->loop_father->latch == act)
+ continue;
+
+ /* Edges inside a single loop should be left where they are. Edges
+ to subloop headers should lead to representative of the subloop,
+ but from the same place.
+
+ Edges exiting loops should lead from representative
+ of the son of nearest common ancestor of the loops in that
+ act lays. */
+
+ src = BB_REPR (act);
+ dest = BB_REPR (e->dest);
+
+ if (e->dest->loop_father->header == e->dest)
+ dest = LOOP_REPR (e->dest->loop_father);
+
+ if (!flow_bb_inside_loop_p (act->loop_father, e->dest))
+ {
+ depth = find_common_loop (act->loop_father,
+ e->dest->loop_father)->depth + 1;
+ if (depth == act->loop_father->depth)
+ cloop = act->loop_father;
+ else
+ cloop = act->loop_father->pred[depth];
+
+ src = LOOP_REPR (cloop);
+ }
+
+ add_edge (g, src, dest, e);
+ }
+
+ /* Find the strongly connected components. Use the algorithm of Tarjan --
+ first determine the postorder dfs numbering in reversed graph, then
+ run the dfs on the original graph in the order given by decreasing
+ numbers assigned by the previous pass. */
+ nq = 0;
+ FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+ {
+ queue1[nq++] = BB_REPR (act);
+ }
+ for (i = 1; i < (int) loops->num; i++)
+ if (loops->parray[i])
+ queue1[nq++] = LOOP_REPR (loops->parray[i]);
+ dfs (g, queue1, nq, queue2, false);
+ for (i = 0; i < nq; i++)
+ queue1[i] = queue2[nq - i - 1];
+ dfs (g, queue1, nq, NULL, true);
+
+ /* Mark the irreducible loops. */
+ for_each_edge (g, check_irred);
+
+ free_graph (g);
+ free (queue1);
+ free (queue2);
+
+ loops->state |= LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
+}
+
+/* Counts number of insns inside LOOP. */
+int
+num_loop_insns (struct loop *loop)
+{
+ basic_block *bbs, bb;
+ unsigned i, ninsns = 0;
+ rtx insn;
+
+ bbs = get_loop_body (loop);
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ bb = bbs[i];
+ ninsns++;
+ for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ ninsns++;
+ }
+ free(bbs);
+
+ return ninsns;
+}
+
+/* Counts number of insns executed on average per iteration LOOP. */
+int
+average_num_loop_insns (struct loop *loop)
+{
+ basic_block *bbs, bb;
+ unsigned i, binsns, ninsns, ratio;
+ rtx insn;
+
+ ninsns = 0;
+ bbs = get_loop_body (loop);
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ bb = bbs[i];
+
+ binsns = 1;
+ for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ binsns++;
+
+ ratio = loop->header->frequency == 0
+ ? BB_FREQ_MAX
+ : (bb->frequency * BB_FREQ_MAX) / loop->header->frequency;
+ ninsns += binsns * ratio;
+ }
+ free(bbs);
+
+ ninsns /= BB_FREQ_MAX;
+ if (!ninsns)
+ ninsns = 1; /* To avoid division by zero. */
+
+ return ninsns;
+}
+
+/* Returns expected number of LOOP iterations.
+ Compute upper bound on number of iterations in case they do not fit integer
+ to help loop peeling heuristics. Use exact counts if at all possible. */
+unsigned
+expected_loop_iterations (const struct loop *loop)
+{
+ edge e;
+ edge_iterator ei;
+
+ if (loop->latch->count || loop->header->count)
+ {
+ gcov_type count_in, count_latch, expected;
+
+ count_in = 0;
+ count_latch = 0;
+
+ FOR_EACH_EDGE (e, ei, loop->header->preds)
+ if (e->src == loop->latch)
+ count_latch = e->count;
+ else
+ count_in += e->count;
+
+ if (count_in == 0)
+ expected = count_latch * 2;
+ else
+ expected = (count_latch + count_in - 1) / count_in;
+
+ /* Avoid overflows. */
+ return (expected > REG_BR_PROB_BASE ? REG_BR_PROB_BASE : expected);
+ }
+ else
+ {
+ int freq_in, freq_latch;
+
+ freq_in = 0;
+ freq_latch = 0;
+
+ FOR_EACH_EDGE (e, ei, loop->header->preds)
+ if (e->src == loop->latch)
+ freq_latch = EDGE_FREQUENCY (e);
+ else
+ freq_in += EDGE_FREQUENCY (e);
+
+ if (freq_in == 0)
+ return freq_latch * 2;
+
+ return (freq_latch + freq_in - 1) / freq_in;
+ }
+}
+
+/* Returns the maximum level of nesting of subloops of LOOP. */
+
+unsigned
+get_loop_level (const struct loop *loop)
+{
+ const struct loop *ploop;
+ unsigned mx = 0, l;
+
+ for (ploop = loop->inner; ploop; ploop = ploop->next)
+ {
+ l = get_loop_level (ploop);
+ if (l >= mx)
+ mx = l + 1;
+ }
+ return mx;
+}
+
+/* Returns estimate on cost of computing SEQ. */
+
+static unsigned
+seq_cost (rtx seq)
+{
+ unsigned cost = 0;
+ rtx set;
+
+ for (; seq; seq = NEXT_INSN (seq))
+ {
+ set = single_set (seq);
+ if (set)
+ cost += rtx_cost (set, SET);
+ else
+ cost++;
+ }
+
+ return cost;
+}
+
+/* The properties of the target. */
+
+unsigned target_avail_regs; /* Number of available registers. */
+unsigned target_res_regs; /* Number of reserved registers. */
+unsigned target_small_cost; /* The cost for register when there is a free one. */
+unsigned target_pres_cost; /* The cost for register when there are not too many
+ free ones. */
+unsigned target_spill_cost; /* The cost for register when we need to spill. */
+
+/* Initialize the constants for computing set costs. */
+
+void
+init_set_costs (void)
+{
+ rtx seq;
+ rtx reg1 = gen_raw_REG (SImode, FIRST_PSEUDO_REGISTER);
+ rtx reg2 = gen_raw_REG (SImode, FIRST_PSEUDO_REGISTER + 1);
+ rtx addr = gen_raw_REG (Pmode, FIRST_PSEUDO_REGISTER + 2);
+ rtx mem = validize_mem (gen_rtx_MEM (SImode, addr));
+ unsigned i;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)
+ && !fixed_regs[i])
+ target_avail_regs++;
+
+ target_res_regs = 3;
+
+ /* These are really just heuristic values. */
+
+ start_sequence ();
+ emit_move_insn (reg1, reg2);
+ seq = get_insns ();
+ end_sequence ();
+ target_small_cost = seq_cost (seq);
+ target_pres_cost = 2 * target_small_cost;
+
+ start_sequence ();
+ emit_move_insn (mem, reg1);
+ emit_move_insn (reg2, mem);
+ seq = get_insns ();
+ end_sequence ();
+ target_spill_cost = seq_cost (seq);
+}
+
+/* Calculates cost for having SIZE new loop global variables. REGS_USED is the
+ number of global registers used in loop. N_USES is the number of relevant
+ variable uses. */
+
+unsigned
+global_cost_for_size (unsigned size, unsigned regs_used, unsigned n_uses)
+{
+ unsigned regs_needed = regs_used + size;
+ unsigned cost = 0;
+
+ if (regs_needed + target_res_regs <= target_avail_regs)
+ cost += target_small_cost * size;
+ else if (regs_needed <= target_avail_regs)
+ cost += target_pres_cost * size;
+ else
+ {
+ cost += target_pres_cost * size;
+ cost += target_spill_cost * n_uses * (regs_needed - target_avail_regs) / regs_needed;
+ }
+
+ return cost;
+}
+
+/* Sets EDGE_LOOP_EXIT flag for all exits of LOOPS. */
+
+void
+mark_loop_exit_edges (struct loops *loops)
+{
+ basic_block bb;
+ edge e;
+
+ if (loops->num <= 1)
+ return;
+
+ FOR_EACH_BB (bb)
+ {
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (bb->loop_father->outer
+ && loop_exit_edge_p (bb->loop_father, e))
+ e->flags |= EDGE_LOOP_EXIT;
+ else
+ e->flags &= ~EDGE_LOOP_EXIT;
+ }
+ }
+}
+