aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-loop-manip.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-loop-manip.c')
-rw-r--r--gcc/tree-ssa-loop-manip.c1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
new file mode 100644
index 00000000000..5102cf3b349
--- /dev/null
+++ b/gcc/tree-ssa-loop-manip.c
@@ -0,0 +1,1020 @@
+/* High-level loop manipulation functions.
+ Copyright (C) 2004 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, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "output.h"
+#include "diagnostic.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "tree-pass.h"
+
+static basic_block lv_adjust_loop_entry_edge (basic_block, basic_block, edge,
+ tree);
+static void lv_update_pending_stmts (edge e);
+static void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block,
+ edge);
+
+/* Copies phi nodes in newly created copies of the LOOP. The new blocks start
+ since FIRST_NEW_BLOCK index. PEELING is true if we were peeling
+ the loop. */
+
+static void
+copy_phi_nodes (struct loop *loop, unsigned first_new_block, bool peeling)
+{
+ unsigned i;
+ basic_block bb, orig;
+ tree phi, new_phi, def;
+ edge e, new_e;
+ edge latch = loop_latch_edge (loop), entry = loop_preheader_edge (loop);
+
+ for (i = first_new_block; i < (unsigned) last_basic_block; i++)
+ {
+ tree nlist;
+ bb = BASIC_BLOCK (i);
+ orig = bb->rbi->original;
+
+ for (phi = phi_nodes (orig); phi; phi = TREE_CHAIN (phi))
+ {
+ new_phi = create_phi_node (PHI_RESULT (phi), bb);
+
+ if (orig == loop->header)
+ {
+ if (!bb->pred || bb->pred->pred_next)
+ abort ();
+
+ new_e = bb->pred;
+ e = (peeling && bb->rbi->copy_number == 1 ? entry : latch);
+ def = phi_element_for_edge (phi, e)->def;
+ add_phi_arg (&new_phi, def, new_e);
+ continue;
+ }
+
+ for (new_e = bb->pred; new_e; new_e = new_e->pred_next)
+ {
+ e = find_edge (new_e->src->rbi->original, orig);
+ if (!e)
+ abort ();
+
+ def = phi_element_for_edge (phi, e)->def;
+ add_phi_arg (&new_phi, def, new_e);
+ }
+ }
+
+ /* neverse phi nodes to keep them in original order. */
+ nlist = nreverse (phi_nodes (bb));
+ set_phi_nodes (bb, nlist);
+ }
+
+ if (peeling)
+ {
+ /* Update the phi nodes in the header so that the latch value comes from
+ both edges. */
+ for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
+ {
+ def = phi_element_for_edge (phi, latch)->def;
+ phi_element_for_edge (phi, entry)->def = def;
+ }
+ }
+}
+
+/* Constructs list of all ssa names defined inside LOOP. */
+
+static tree
+collect_defs (struct loop *loop)
+{
+ basic_block *body = get_loop_body (loop);
+ unsigned i, j;
+ tree phi, stmt;
+ block_stmt_iterator bsi;
+ def_optype defs;
+ vdef_optype vdefs;
+ tree ret = NULL_TREE;
+
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ for (bsi = bsi_start (body[i]); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ stmt = bsi_stmt (bsi);
+
+ get_stmt_operands (stmt);
+
+ defs = STMT_DEF_OPS (stmt);
+ for (j = 0; j < NUM_DEFS (defs); j++)
+ ret = tree_cons (NULL, DEF_OP (defs, j), ret);
+
+ vdefs = STMT_VDEF_OPS (stmt);
+ for (j = 0; j < NUM_VDEFS (vdefs); j++)
+ ret = tree_cons (NULL, VDEF_RESULT (vdefs, j), ret);
+ }
+
+ for (phi = phi_nodes (body[i]); phi; phi = TREE_CHAIN (phi))
+ ret = tree_cons (NULL, PHI_RESULT (phi), ret);
+ }
+
+ return ret;
+}
+
+/* For each definition in DEFINITIONS allocates NDUPL + 1 copies
+ (one for each duplicate of the loop body). */
+
+static void
+allocate_new_names (tree definitions, unsigned ndupl)
+{
+ tree def;
+ unsigned i;
+ ssa_name_ann_t ann;
+ tree *new_names;
+ bool abnormal;
+
+ for (; definitions; definitions = TREE_CHAIN (definitions))
+ {
+ def = TREE_VALUE (definitions);
+ ann = get_ssa_name_ann (def);
+ new_names = xmalloc (sizeof (tree) * (ndupl + 1));
+ ann->common.aux = new_names;
+
+ abnormal = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def);
+ for (i = 0; i <= ndupl; i++)
+ {
+ new_names[i] = duplicate_ssa_name (def, SSA_NAME_DEF_STMT (def));
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_names[i]) = abnormal;
+ }
+ }
+}
+
+/* Renames the variable *OP_P in statement STMT. If DEF is true,
+ *OP_P is defined by the statement. N_COPY is the number of the
+ copy of the loop body we are renaming. */
+
+static void
+rename_op (tree *op_p, bool def, tree stmt, unsigned n_copy)
+{
+ ssa_name_ann_t ann;
+ tree *new_names;
+
+ if (TREE_CODE (*op_p) != SSA_NAME)
+ return;
+
+ ann = ssa_name_ann (*op_p);
+ new_names = ann ? ann->common.aux : NULL;
+
+ /* Something defined outside of the loop. */
+ if (!new_names)
+ return;
+
+ /* An ordinary ssa name defined in the loop. */
+
+ *op_p = new_names[n_copy];
+ if (def)
+ SSA_NAME_DEF_STMT (*op_p) = stmt;
+}
+
+/* Renames the variables in basic block BB. */
+
+static void
+rename_variables_in_bb (basic_block bb)
+{
+ tree phi;
+ block_stmt_iterator bsi;
+ tree stmt;
+ stmt_ann_t ann;
+ use_optype uses;
+ vuse_optype vuses;
+ def_optype defs;
+ vdef_optype vdefs;
+ unsigned i, nbb = bb->rbi->copy_number;
+ edge e;
+
+ for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ rename_op (&PHI_RESULT (phi), true, phi, nbb);
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ stmt = bsi_stmt (bsi);
+ get_stmt_operands (stmt);
+ ann = stmt_ann (stmt);
+
+ uses = USE_OPS (ann);
+ for (i = 0; i < NUM_USES (uses); i++)
+ rename_op (USE_OP_PTR (uses, i), false, stmt, nbb);
+
+ defs = DEF_OPS (ann);
+ for (i = 0; i < NUM_DEFS (defs); i++)
+ rename_op (DEF_OP_PTR (defs, i), true, stmt, nbb);
+
+ vuses = VUSE_OPS (ann);
+ for (i = 0; i < NUM_VUSES (vuses); i++)
+ rename_op (VUSE_OP_PTR (vuses, i), false, stmt, nbb);
+
+ vdefs = VDEF_OPS (ann);
+ for (i = 0; i < NUM_VDEFS (vdefs); i++)
+ {
+ rename_op (VDEF_OP_PTR (vdefs, i), false, stmt, nbb);
+ rename_op (VDEF_RESULT_PTR (vdefs, i), true, stmt, nbb);
+ }
+ }
+
+ for (e = bb->succ; e; e = e->succ_next)
+ for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
+ rename_op (&phi_element_for_edge (phi, e)->def, false, phi, nbb);
+}
+
+/* Renames variables in the area copied by tree_duplicate_loop_to_header_edge.
+ FIRST_NEW_BLOCK is the first block in the copied area. */
+
+static void
+rename_variables (unsigned first_new_block)
+{
+ unsigned i;
+ basic_block bb;
+
+ for (i = first_new_block; i < (unsigned) last_basic_block; i++)
+ {
+ bb = BASIC_BLOCK (i);
+
+ rename_variables_in_bb (bb);
+
+ if (bb->rbi->copy_number == 1)
+ rename_variables_in_bb (bb->rbi->original);
+ }
+}
+
+/* Releases the structures holding the new ssa names. The original ssa names
+ are released. */
+
+static void
+free_new_names (tree definitions)
+{
+ tree def;
+ ssa_name_ann_t ann;
+
+ for (; definitions; definitions = TREE_CHAIN (definitions))
+ {
+ def = TREE_VALUE (definitions);
+ ann = ssa_name_ann (def);
+
+ free (ann->common.aux);
+ ann->common.aux = NULL;
+
+ release_ssa_name (def);
+ }
+}
+
+/* Sets SSA_NAME_DEF_STMT for results of all phi nodes in BB. */
+
+static void
+set_phi_def_stmts (basic_block bb)
+{
+ tree phi;
+
+ for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = phi;
+}
+
+/* Extends phi nodes on EXIT to the newly created edges. */
+
+static void
+extend_exit_phi_nodes (unsigned first_new_block, edge exit)
+{
+ basic_block exit_block = exit->dest;
+ edge ae;
+ tree phi, def;
+
+ for (phi = phi_nodes (exit_block); phi; phi = TREE_CHAIN (phi))
+ {
+ def = phi_element_for_edge (phi, exit)->def;
+
+ for (ae = exit_block->pred; ae; ae = ae->pred_next)
+ {
+ if (ae->src->index < (int) first_new_block)
+ continue;
+
+ if (ae->src->rbi->original != exit->src)
+ continue;
+
+ add_phi_arg (&phi, def, ae);
+ }
+ }
+}
+
+/* The same ad cfgloopmanip.c:duplicate_loop_to_header_edge, but also updates
+ ssa. In order to achieve this, only loops whose exits all lead to the same
+ location are handled.
+
+ FIXME: we create some degenerate phi nodes that could be avoided by copy
+ propagating them instead. Unfortunately this is not completely
+ straightforward due to problems with constant folding. */
+
+bool
+tree_duplicate_loop_to_header_edge (struct loop *loop, edge e,
+ struct loops *loops,
+ unsigned int ndupl, sbitmap wont_exit,
+ edge orig, edge *to_remove,
+ unsigned int *n_to_remove, int flags)
+{
+ unsigned first_new_block;
+ basic_block bb;
+ unsigned i;
+ bool peeling = (e != loop_latch_edge (loop));
+ edge latch, latch_copy;
+ tree phi, arg, map, def;
+ tree definitions;
+ edge *exits;
+ unsigned n_exits;
+
+ if (!(loops->state & LOOPS_HAVE_SIMPLE_LATCHES))
+ return false;
+ if (!(loops->state & LOOPS_HAVE_PREHEADERS))
+ return false;
+
+#ifdef ENABLE_CHECKING
+ verify_loop_closed_ssa ();
+#endif
+
+ exits = get_loop_exit_edges (loop, &n_exits);
+ definitions = collect_defs (loop);
+
+ first_new_block = last_basic_block;
+ if (!duplicate_loop_to_header_edge (loop, e, loops, ndupl, wont_exit,
+ orig, to_remove, n_to_remove, flags))
+ return false;
+
+ allocate_new_names (definitions, ndupl);
+
+ /* Readd the removed phi args for e. */
+ latch = loop_latch_edge (loop);
+ latch_copy = peeling ? loop_preheader_edge (loop) : latch;
+ map = PENDING_STMT (e);
+ PENDING_STMT (e) = NULL;
+
+ for (phi = phi_nodes (loop->header), arg = map;
+ phi;
+ phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
+ {
+ def = TREE_VALUE (arg);
+ add_phi_arg (&phi, def, latch_copy);
+ }
+ if (arg)
+ abort ();
+
+ /* Extend exit phi nodes. */
+ for (i = 0; i < n_exits; i++)
+ extend_exit_phi_nodes (first_new_block, exits[i]);
+ free (exits);
+
+ /* Copy the phi nodes. */
+ copy_phi_nodes (loop, first_new_block, peeling);
+
+ /* Rename the variables. */
+ rename_variables (first_new_block);
+ free_new_names (definitions);
+
+ /* For some time we have the identical ssa names as results in multiple phi
+ nodes. When phi node is resized, it sets SSA_NAME_DEF_STMT of its result
+ to the new copy. This means that we cannot easily ensure that the ssa
+ names defined in those phis are pointing to the right one -- so just
+ recompute SSA_NAME_DEF_STMT for them. */
+
+ for (i = first_new_block; i < (unsigned) last_basic_block; i++)
+ {
+ bb = BASIC_BLOCK (i);
+ set_phi_def_stmts (bb);
+ if (bb->rbi->copy_number == 1)
+ set_phi_def_stmts (bb->rbi->original);
+ }
+
+#ifdef ENABLE_CHECKING
+ verify_loop_closed_ssa ();
+#endif
+
+ return true;
+}
+
+/* Unrolls and peels each loop twice for testing. */
+
+void
+test_unrolling_and_peeling (struct loops *loops)
+{
+ struct loop *loop;
+ unsigned i;
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+
+ if (!loop
+ || loop->inner)
+ continue;
+
+ tree_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, 2, NULL, NULL, NULL, NULL, 0);
+ verify_loop_structure (loops);
+ verify_ssa ();
+
+ tree_duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
+ loops, 2, NULL, NULL, NULL, NULL, 0);
+ verify_loop_structure (loops);
+ verify_ssa ();
+ }
+}
+
+/*---------------------------------------------------------------------------
+ Loop versioning
+ ---------------------------------------------------------------------------*/
+
+/* Adjust entry edge for lv.
+
+ e is a incoming edge.
+
+ --- edge e ---- > [second_head]
+
+ Split it and insert new conditional expression and adjust edges.
+
+ --- edge e ---> [cond expr] ---> [first_head]
+ |
+ +---------> [second_head]
+
+*/
+
+static basic_block
+lv_adjust_loop_entry_edge (basic_block first_head,
+ basic_block second_head,
+ edge e,
+ tree cond_expr)
+{
+ block_stmt_iterator bsi;
+ basic_block orig_head = e->src;
+ basic_block new_head = NULL;
+ tree goto1 = NULL_TREE;
+ tree goto2 = NULL_TREE;
+ tree new_cond_expr = NULL_TREE;
+ edge e0, e1;
+
+ /* Split edge 'e'. This will create a new basic block, where we can
+ insert conditioanl expr. */
+ new_head = split_edge (e);
+ set_immediate_dominator (CDI_DOMINATORS, new_head, orig_head);
+
+ /* Build new conditional expr */
+ goto1 = build1 (GOTO_EXPR, void_type_node, tree_block_label (first_head));
+ goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head));
+ new_cond_expr = build (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
+
+ /* Add new cond. in new head. */
+ bsi = bsi_start (new_head);
+ bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
+
+ /* Adjust edges appropriately to connect new head with first head
+ as well as second head. */
+ e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE);
+ set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
+ make_edge (new_head, second_head, EDGE_FALSE_VALUE);
+ set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
+
+ /* Adjust loop header phi nodes. */
+ lv_adjust_loop_header_phi (first_head, second_head, new_head, e1);
+
+ /* When edge 'e' was split, it created a fall through edge
+ from new head to second head. Above created FALSE edge
+ from new head to second head and now we do not need the
+ fall through edge. */
+ for (e0 = new_head->succ; e0; e0 = e0->succ_next)
+ if (e0->dest == second_head)
+ e0->flags &= ~EDGE_FALLTHRU;
+
+ return new_head;
+}
+
+/* Add phi args using PENDINT_STMT list. */
+
+static void
+lv_update_pending_stmts (edge e)
+{
+ basic_block dest;
+ tree phi, arg, def;
+
+ if (!PENDING_STMT (e))
+ return;
+
+ dest = e->dest;
+
+ for (phi = phi_nodes (dest), arg = PENDING_STMT (e);
+ phi;
+ phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
+ {
+ def = TREE_VALUE (arg);
+ add_phi_arg (&phi, def, e);
+ }
+
+ PENDING_STMT (e) = NULL;
+}
+
+/* Adjust phi nodes for 'first' basic block. 'second' basic block is a copy
+ of 'first'. Both of them are dominated by 'new_head' basic block. When
+ 'new_head' was created by 'second's incoming edge it received phi arguments
+ on the edge by split_edge(). Later, additional edge 'e' was created to
+ connect 'new_head' and 'first'. Now this routnine adds phi args on this
+ additional edge 'e' that new_head to second edge received as part of edge
+ splitting.
+*/
+
+static void
+lv_adjust_loop_header_phi (basic_block first, basic_block second,
+ basic_block new_head, edge e)
+{
+ tree phi1, phi2;
+
+ /* Browse all 'second' basic block phi nodes and add phi args to
+ edge 'e' for 'first' head. PHI args are always in correct order. */
+
+ for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
+ phi2 && phi1;
+ phi2 = TREE_CHAIN (phi2), phi1 = TREE_CHAIN (phi1))
+ {
+ int i;
+ for (i = 0; i < PHI_NUM_ARGS (phi2); i++)
+ {
+ if (PHI_ARG_EDGE (phi2, i)->src == new_head)
+ {
+ tree def = PHI_ARG_DEF (phi2, i);
+ add_phi_arg (&phi1, def, e);
+ }
+ }
+ }
+}
+
+
+/* Main entry point for Loop Versioning transformation.
+
+This transformation given a condition and a loop, creates
+-if (condition) { loop_copy1 } else { loop_copy2 },
+where loop_copy1 is the loop transformed in one way, and loop_copy2
+is the loop transformed in another way (or unchanged). 'condition'
+may be a run time test for things that were not resolved by static
+analysis (overlapping ranges (anti-aliasing), alignment, etc.). */
+
+struct loop *
+tree_ssa_loop_version (struct loops *loops, struct loop * loop,
+ tree cond_expr, basic_block *condition_bb)
+{
+ edge entry, latch_edge;
+ basic_block first_head, second_head;
+ int irred_flag;
+ struct loop *nloop;
+
+ /* CHECKME: Loop versioning does not handle nested loop at this point. */
+ if (loop->inner)
+ return NULL;
+
+ /* Record entry and latch edges for the loop */
+ entry = loop_preheader_edge (loop);
+
+ /* Note down head of loop as first_head. */
+ first_head = entry->dest;
+
+ /* Duplicate loop. */
+ irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP;
+ entry->flags &= ~EDGE_IRREDUCIBLE_LOOP;
+ if (!tree_duplicate_loop_to_header_edge (loop, entry, loops, 1,
+ NULL, NULL, NULL, NULL, 0))
+ {
+ entry->flags |= irred_flag;
+ return NULL;
+ }
+
+ /* After duplication entry edge now points to new loop head block.
+ Note down new head as second_head. */
+ second_head = entry->dest;
+
+ /* Split loop entry edge and insert new block with cond expr. */
+ *condition_bb = lv_adjust_loop_entry_edge (first_head, second_head, entry,
+ cond_expr);
+
+ latch_edge = loop->latch->rbi->copy->succ;
+ nloop = loopify (loops,
+ latch_edge,
+ loop->header->rbi->copy->pred,
+ *condition_bb,
+ false /* Do not redirect all edges. */);
+
+ /* loopify redirected latch_edge. Update its PENDING_STMTS. */
+ lv_update_pending_stmts (latch_edge);
+
+ /* loopify redirected condition_bb's succ edge. Update its PENDING_STMTS. */
+ lv_update_pending_stmts (FALLTHRU_EDGE (*condition_bb));
+
+ /* Adjust irreducible flag. */
+ if (irred_flag)
+ {
+ (*condition_bb)->flags |= BB_IRREDUCIBLE_LOOP;
+ loop_preheader_edge (loop)->flags |= EDGE_IRREDUCIBLE_LOOP;
+ loop_preheader_edge (nloop)->flags |= EDGE_IRREDUCIBLE_LOOP;
+ (*condition_bb)->pred->flags |= EDGE_IRREDUCIBLE_LOOP;
+ }
+
+ /* At this point condition_bb is loop predheader with two successors,
+ first_head and second_head. Make sure that loop predheader has only
+ one successor. */
+ loop_split_edge_with (loop_preheader_edge (loop), NULL);
+ loop_split_edge_with (loop_preheader_edge (nloop), NULL);
+
+ /* Ensure that the latch has just a single successor. */
+ loop_split_edge_with (loop_latch_edge (loop), NULL);
+ loop_split_edge_with (loop_latch_edge (nloop), NULL);
+
+ return nloop;
+}
+
+/* Update loop versioning condition.
+ This is used by other optimizations/transformations to disable
+ one loop version. */
+void
+update_lv_condition (basic_block *bb, tree new_cond)
+{
+ tree stmt;
+ block_stmt_iterator bsi = bsi_last (*bb);
+
+ stmt = bsi_stmt (bsi);
+
+ if (TREE_CODE (stmt) == COND_EXPR)
+ {
+ TREE_OPERAND (stmt, 0) = new_cond;
+ modify_stmt (stmt);
+ }
+ else
+ abort ();
+}
+
+void
+test_loop_versioning (struct loops *loops)
+{
+ struct loop *loop;
+ unsigned i;
+ tree cond_expr;
+
+ for (i = 1; i < loops->num; i = i+ 2)
+ {
+ struct loop *nloop;
+ basic_block condition_bb;
+ loop = loops->parray[i];
+
+ if (!loop)
+ continue;
+
+ cond_expr = build (EQ_EXPR, boolean_type_node,
+ integer_one_node,
+ integer_zero_node);
+
+ nloop = tree_ssa_loop_version (loops, loop, cond_expr, &condition_bb);
+
+ if (nloop)
+ {
+ verify_loop_structure (loops);
+ verify_dominators (CDI_DOMINATORS);
+ verify_ssa ();
+
+ update_lv_condition (&condition_bb, boolean_true_node);
+ }
+ }
+
+}
+
+/* Add exit phis for the USE on EXIT. */
+
+static void
+add_exit_phis_edge (basic_block exit, tree use)
+{
+ tree phi, def_stmt = SSA_NAME_DEF_STMT (use);
+ basic_block def_bb = bb_for_stmt (def_stmt);
+ struct loop *def_loop;
+ edge e;
+
+ /* Check that some of the edges entering the EXIT block exits a loop in
+ that USE is defined. */
+ for (e = exit->pred; e; e = e->pred_next)
+ {
+ def_loop = find_common_loop (def_bb->loop_father, e->src->loop_father);
+ if (!flow_bb_inside_loop_p (def_loop, e->dest))
+ break;
+ }
+
+ if (!e)
+ return;
+
+ phi = create_phi_node (use, exit);
+
+ for (e = exit->pred; e; e = e->pred_next)
+ add_phi_arg (&phi, use, e);
+
+ SSA_NAME_DEF_STMT (use) = def_stmt;
+}
+
+/* Add exit phis for VAR that is used in LIVEIN.
+ Exits of the loops are stored in EXITS. */
+
+static void
+add_exit_phis_var (tree var, bitmap livein, bitmap exits)
+{
+ bitmap def;
+ int index;
+ basic_block def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
+
+ bitmap_clear_bit (livein, def_bb->index);
+
+ def = BITMAP_XMALLOC ();
+ bitmap_set_bit (def, def_bb->index);
+ compute_global_livein (livein, def);
+ BITMAP_XFREE (def);
+
+ EXECUTE_IF_AND_IN_BITMAP (exits, livein, 0, index,
+ add_exit_phis_edge (BASIC_BLOCK (index), var));
+}
+
+/* Add exit phis for the names marked in NAMES_TO_RENAME.
+ Exits of the loops are stored in EXITS. Sets of blocks where the ssa
+ names are used are stored in USE_BLOCKS. SSA_NAMES is the array of ssa
+ names indexed by their versions. */
+
+static void
+add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap loop_exits,
+ tree *ssa_names)
+{
+ unsigned i;
+
+ EXECUTE_IF_SET_IN_BITMAP (names_to_rename, 0, i,
+ {
+ add_exit_phis_var (ssa_names[i], use_blocks[i], loop_exits);
+ });
+}
+
+/* Returns a bitmap of all loop exit edge targets. */
+
+static bitmap
+get_loops_exits (void)
+{
+ bitmap exits = BITMAP_XMALLOC ();
+ basic_block bb;
+ edge e;
+
+ FOR_EACH_BB (bb)
+ {
+ for (e = bb->pred; e; e = e->pred_next)
+ if (e->src != ENTRY_BLOCK_PTR
+ && !flow_bb_inside_loop_p (e->src->loop_father, bb))
+ {
+ bitmap_set_bit (exits, bb->index);
+ break;
+ }
+ }
+
+ return exits;
+}
+
+/* For USE in BB, if it is used outside of the loop it is defined in,
+ mark it in NAMES_TO_RENAME. Record basic block BB where it is used
+ to USE_BLOCKS, and the ssa name itself to NAMES. */
+
+static void
+find_uses_to_rename_use (basic_block bb, tree use, bitmap names_to_rename,
+ bitmap *use_blocks, tree *names)
+{
+ unsigned ver;
+ basic_block def_bb;
+ struct loop *def_loop;
+
+ if (TREE_CODE (use) != SSA_NAME)
+ return;
+
+ ver = SSA_NAME_VERSION (use);
+ def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (use));
+ if (!def_bb)
+ return;
+ def_loop = def_bb->loop_father;
+
+ /* If the definition is not inside loop, it is not interesting. */
+ if (!def_loop->outer)
+ return;
+
+ names[ver] = use;
+ if (!use_blocks[ver])
+ use_blocks[ver] = BITMAP_XMALLOC ();
+ bitmap_set_bit (use_blocks[ver], bb->index);
+
+ if (!flow_bb_inside_loop_p (def_loop, bb))
+ bitmap_set_bit (names_to_rename, ver);
+}
+
+/* For uses in STMT, mark names that are used outside of the loop they are
+ defined in in NAMES_TO_RENAME. Record the set of blocks in that the ssa
+ names are defined to USE_BLOCKS, and the names themselves to NAMES. */
+
+static void
+find_uses_to_rename_stmt (tree stmt, bitmap names_to_rename,
+ bitmap *use_blocks, tree *names)
+{
+ use_optype uses;
+ vuse_optype vuses;
+ vdef_optype vdefs;
+ stmt_ann_t ann;
+ unsigned i;
+ basic_block bb = bb_for_stmt (stmt);
+
+ get_stmt_operands (stmt);
+ ann = stmt_ann (stmt);
+
+ uses = USE_OPS (ann);
+ for (i = 0; i < NUM_USES (uses); i++)
+ find_uses_to_rename_use (bb, USE_OP (uses, i),
+ names_to_rename, use_blocks, names);
+
+ vuses = VUSE_OPS (ann);
+ for (i = 0; i < NUM_VUSES (vuses); i++)
+ find_uses_to_rename_use (bb, VUSE_OP (vuses, i),
+ names_to_rename, use_blocks, names);
+
+ vdefs = VDEF_OPS (ann);
+ for (i = 0; i < NUM_VDEFS (vdefs); i++)
+ find_uses_to_rename_use (bb, VDEF_OP (vdefs, i),
+ names_to_rename, use_blocks, names);
+}
+
+/* Marks names that are used outside of the loop they are defined in
+ in NAMES_TO_RENAME. Records the set of blocks in that the ssa
+ names are defined to USE_BLOCKS, and the names themselves to NAMES. */
+
+static void
+find_uses_to_rename (bitmap names_to_rename, bitmap *use_blocks, tree *names)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+ tree phi;
+ unsigned i;
+
+ FOR_EACH_BB (bb)
+ {
+ for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
+ find_uses_to_rename_use (PHI_ARG_EDGE (phi, i)->src,
+ PHI_ARG_DEF (phi, i),
+ names_to_rename, use_blocks, names);
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ find_uses_to_rename_stmt (bsi_stmt (bsi),
+ names_to_rename, use_blocks, names);
+ }
+}
+
+/* Rewrites the program into a loop closed ssa form -- i.e. inserts extra
+ phi nodes to ensure that no variable is used outside the loop it is
+ defined in.
+
+ This strenghtening of the basic ssa form has several advantages:
+
+ 1) Updating it during unrolling/peeling/versioning is trivial, since
+ we do not need to care about the uses outside of the loop.
+ 2) The behavior of all uses of an induction variable is the same.
+ Without this, you need to distinguish the case when the variable
+ is used outside of the loop it is defined in, for example
+
+ for (i = 0; i < 100; i++)
+ {
+ for (j = 0; j < 100; j++)
+ {
+ k = i + j;
+ use1 (k);
+ }
+ use2 (k);
+ }
+
+ Looking from the outer loop with the normal SSA form, the first use of k
+ is not well-behaved, while the second one is an induction variable with
+ base 99 and step 1. */
+
+void
+rewrite_into_loop_closed_ssa (void)
+{
+ bitmap names_to_rename = BITMAP_XMALLOC ();
+ bitmap loop_exits = get_loops_exits ();
+ bitmap *use_blocks;
+ tree *ssa_names;
+ unsigned i;
+
+ tree_ssa_dce_no_cfg_changes ();
+
+ use_blocks = xcalloc (highest_ssa_version, sizeof (bitmap));
+ ssa_names = xcalloc (highest_ssa_version, sizeof (tree));
+
+ /* Find the uses outside loops. */
+ find_uses_to_rename (names_to_rename, use_blocks, ssa_names);
+
+ /* Add the phi nodes on exits of the loops for the names we need to
+ rewrite. */
+ add_exit_phis (names_to_rename, use_blocks, loop_exits, ssa_names);
+
+ for (i = 0; i < highest_ssa_version; i++)
+ BITMAP_XFREE (use_blocks[i]);
+ free (use_blocks);
+ free (ssa_names);
+ BITMAP_XFREE (loop_exits);
+
+ /* Do the rewriting. */
+ rewrite_ssa_into_ssa (names_to_rename);
+ BITMAP_XFREE (names_to_rename);
+ BITMAP_XFREE (loop_exits);
+}
+
+/* Check invariants of the loop closed ssa form for the USE in BB. */
+
+static void
+check_loop_closed_ssa_use (basic_block bb, tree use)
+{
+ tree def;
+ basic_block def_bb;
+
+ if (TREE_CODE (use) != SSA_NAME)
+ return;
+
+ def = SSA_NAME_DEF_STMT (use);
+ def_bb = bb_for_stmt (def);
+ if (def_bb
+ && !flow_bb_inside_loop_p (def_bb->loop_father, bb))
+ abort ();
+}
+
+/* Checks invariants of loop closed ssa form in statement STMT in BB. */
+
+static void
+check_loop_closed_ssa_stmt (basic_block bb, tree stmt)
+{
+ use_optype uses;
+ vuse_optype vuses;
+ vdef_optype vdefs;
+ stmt_ann_t ann;
+ unsigned i;
+
+ get_stmt_operands (stmt);
+ ann = stmt_ann (stmt);
+
+ uses = USE_OPS (ann);
+ for (i = 0; i < NUM_USES (uses); i++)
+ check_loop_closed_ssa_use (bb, USE_OP (uses, i));
+
+ vuses = VUSE_OPS (ann);
+ for (i = 0; i < NUM_VUSES (vuses); i++)
+ check_loop_closed_ssa_use (bb, VUSE_OP (vuses, i));
+
+ vdefs = VDEF_OPS (ann);
+ for (i = 0; i < NUM_VDEFS (vdefs); i++)
+ check_loop_closed_ssa_use (bb, VDEF_OP (vdefs, i));
+}
+
+/* Checks that invariants of the loop closed ssa form are preserved. */
+
+void
+verify_loop_closed_ssa (void)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+ tree phi;
+ unsigned i;
+
+ verify_ssa ();
+
+ FOR_EACH_BB (bb)
+ {
+ for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+ for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
+ check_loop_closed_ssa_use (PHI_ARG_EDGE (phi, i)->src,
+ PHI_ARG_DEF (phi, i));
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ check_loop_closed_ssa_stmt (bb, bsi_stmt (bsi));
+ }
+}