/* Loop unswitching.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007, 2008 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
+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
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. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "tree-dump.h"
#include "timevar.h"
#include "cfgloop.h"
-#include "domwalk.h"
#include "params.h"
#include "tree-pass.h"
+#include "tree-inline.h"
/* This file implements the loop unswitching, i.e. transformation of loops like
tree-ssa-loop-im.c ensures that all the suitable conditions are in this
shape. */
-static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
- tree);
-static bool tree_unswitch_single_loop (struct loops *, struct loop *, int);
+static struct loop *tree_unswitch_loop (struct loop *, basic_block, tree);
+static bool tree_unswitch_single_loop (struct loop *, int);
static tree tree_may_unswitch_on (basic_block, struct loop *);
-/* Main entry point. Perform loop unswitching on all suitable LOOPS. */
+/* Main entry point. Perform loop unswitching on all suitable loops. */
-void
-tree_ssa_unswitch_loops (struct loops *loops)
+unsigned int
+tree_ssa_unswitch_loops (void)
{
- int i, num;
+ loop_iterator li;
struct loop *loop;
bool changed = false;
/* Go through inner loops (only original ones). */
- num = loops->num;
-
- for (i = 1; i < num; i++)
+ FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
{
- /* Removed loop? */
- loop = loops->parray[i];
- if (!loop)
- continue;
-
- if (loop->inner)
- continue;
-
- changed |= tree_unswitch_single_loop (loops, loop, 0);
-#ifdef ENABLE_CHECKING
- verify_dominators (CDI_DOMINATORS);
- verify_loop_structure (loops);
-#endif
+ changed |= tree_unswitch_single_loop (loop, 0);
}
-#if 0
- /* The necessary infrastructure is not in yet. */
if (changed)
- cleanup_tree_cfg_loop ();
-#endif
+ return TODO_cleanup_cfg;
+ return 0;
}
/* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
static tree
tree_may_unswitch_on (basic_block bb, struct loop *loop)
{
- tree stmt, def, cond;
+ gimple stmt, def;
+ tree cond, use;
basic_block def_bb;
- use_optype uses;
- unsigned i;
+ ssa_op_iter iter;
/* BB must end in a simple conditional jump. */
stmt = last_stmt (bb);
- if (!stmt || TREE_CODE (stmt) != COND_EXPR)
+ if (!stmt || gimple_code (stmt) != GIMPLE_COND)
return NULL_TREE;
/* Condition must be invariant. */
- get_stmt_operands (stmt);
- uses = STMT_USE_OPS (stmt);
- for (i = 0; i < NUM_USES (uses); i++)
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
- def = SSA_NAME_DEF_STMT (USE_OP (uses, i));
- def_bb = bb_for_stmt (def);
+ def = SSA_NAME_DEF_STMT (use);
+ def_bb = gimple_bb (def);
if (def_bb
&& flow_bb_inside_loop_p (loop, def_bb))
return NULL_TREE;
}
- cond = COND_EXPR_COND (stmt);
+ cond = build2 (gimple_cond_code (stmt), boolean_type_node,
+ gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
+
/* To keep the things simple, we do not directly remove the conditions,
but just replace tests with 0/1. Prevent the infinite loop where we
would unswitch again on such a condition. */
simplify_using_entry_checks (struct loop *loop, tree cond)
{
edge e = loop_preheader_edge (loop);
- tree stmt;
+ gimple stmt;
while (1)
{
stmt = last_stmt (e->src);
if (stmt
- && TREE_CODE (stmt) == COND_EXPR
- && operand_equal_p (COND_EXPR_COND (stmt), cond, 0))
+ && gimple_code (stmt) == GIMPLE_COND
+ && gimple_cond_code (stmt) == TREE_CODE (cond)
+ && operand_equal_p (gimple_cond_lhs (stmt),
+ TREE_OPERAND (cond, 0), 0)
+ && operand_equal_p (gimple_cond_rhs (stmt),
+ TREE_OPERAND (cond, 1), 0))
return (e->flags & EDGE_TRUE_VALUE
? boolean_true_node
: boolean_false_node);
- if (e->src->pred->pred_next)
+ if (!single_pred_p (e->src))
return cond;
- e = e->src->pred;
+ e = single_pred_edge (e->src);
if (e->src == ENTRY_BLOCK_PTR)
return cond;
}
grow exponentially. */
static bool
-tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
+tree_unswitch_single_loop (struct loop *loop, int num)
{
basic_block *bbs;
struct loop *nloop;
unsigned i;
- tree cond = NULL_TREE, stmt;
+ tree cond = NULL_TREE;
+ gimple stmt;
bool changed = false;
/* Do not unswitch too much. */
return false;
}
+ /* Do not unswitch in cold regions. */
+ if (optimize_loop_for_size_p (loop))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ";; Not unswitching cold loops\n");
+ return false;
+ }
+
/* The loop should not be too large, to limit code growth. */
- if (tree_num_loop_insns (loop)
+ if (tree_num_loop_insns (loop, &eni_size_weights)
> (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
{
if (dump_file && (dump_flags & TDF_DETAILS))
if (integer_nonzerop (cond))
{
/* Remove false path. */
- COND_EXPR_COND (stmt) = boolean_true_node;
+ gimple_cond_set_condition_from_tree (stmt, boolean_true_node);
changed = true;
}
else if (integer_zerop (cond))
{
/* Remove true path. */
- COND_EXPR_COND (stmt) = boolean_false_node;
+ gimple_cond_set_condition_from_tree (stmt, boolean_false_node);
changed = true;
}
else
break;
- modify_stmt (stmt);
+ update_stmt (stmt);
i++;
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ";; Unswitching loop\n");
+ initialize_original_copy_tables ();
/* Unswitch the loop on this condition. */
- nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
+ nloop = tree_unswitch_loop (loop, bbs[i], cond);
if (!nloop)
- return changed;
+ {
+ free_original_copy_tables ();
+ free (bbs);
+ return changed;
+ }
+
+ /* Update the SSA form after unswitching. */
+ update_ssa (TODO_update_ssa);
+ free_original_copy_tables ();
/* Invoke itself on modified loops. */
- tree_unswitch_single_loop (loops, nloop, num + 1);
- tree_unswitch_single_loop (loops, loop, num + 1);
+ tree_unswitch_single_loop (nloop, num + 1);
+ tree_unswitch_single_loop (loop, num + 1);
+ free (bbs);
return true;
}
if impossible, new loop otherwise. */
static struct loop *
-tree_unswitch_loop (struct loops *loops, struct loop *loop,
+tree_unswitch_loop (struct loop *loop,
basic_block unswitch_on, tree cond)
{
- basic_block condition_bb;
+ unsigned prob_true;
+ edge edge_true, edge_false;
/* Some sanity checking. */
gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
- gcc_assert (unswitch_on->succ != NULL);
- gcc_assert (unswitch_on->succ->succ_next != NULL);
- gcc_assert (unswitch_on->succ->succ_next->succ_next == NULL);
+ gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
gcc_assert (loop->inner == NULL);
- return tree_ssa_loop_version (loops, loop, unshare_expr (cond),
- &condition_bb);
+ extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false);
+ prob_true = edge_true->probability;
+ return loop_version (loop, unshare_expr (cond),
+ NULL, prob_true, prob_true,
+ REG_BR_PROB_BASE - prob_true, false);
}