11debfc3dSmrg /* Loop unswitching.
2*8feb0f0bSmrg Copyright (C) 2004-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it
71debfc3dSmrg under the terms of the GNU General Public License as published by the
81debfc3dSmrg Free Software Foundation; either version 3, or (at your option) any
91debfc3dSmrg later version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT
121debfc3dSmrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "system.h"
221debfc3dSmrg #include "coretypes.h"
231debfc3dSmrg #include "backend.h"
241debfc3dSmrg #include "tree.h"
251debfc3dSmrg #include "gimple.h"
261debfc3dSmrg #include "tree-pass.h"
271debfc3dSmrg #include "ssa.h"
281debfc3dSmrg #include "fold-const.h"
291debfc3dSmrg #include "gimplify.h"
301debfc3dSmrg #include "tree-cfg.h"
311debfc3dSmrg #include "tree-ssa.h"
321debfc3dSmrg #include "tree-ssa-loop-niter.h"
331debfc3dSmrg #include "tree-ssa-loop.h"
341debfc3dSmrg #include "tree-into-ssa.h"
351debfc3dSmrg #include "cfgloop.h"
361debfc3dSmrg #include "tree-inline.h"
371debfc3dSmrg #include "gimple-iterator.h"
381debfc3dSmrg #include "cfghooks.h"
391debfc3dSmrg #include "tree-ssa-loop-manip.h"
401debfc3dSmrg
411debfc3dSmrg /* This file implements the loop unswitching, i.e. transformation of loops like
421debfc3dSmrg
431debfc3dSmrg while (A)
441debfc3dSmrg {
451debfc3dSmrg if (inv)
461debfc3dSmrg B;
471debfc3dSmrg
481debfc3dSmrg X;
491debfc3dSmrg
501debfc3dSmrg if (!inv)
511debfc3dSmrg C;
521debfc3dSmrg }
531debfc3dSmrg
541debfc3dSmrg where inv is the loop invariant, into
551debfc3dSmrg
561debfc3dSmrg if (inv)
571debfc3dSmrg {
581debfc3dSmrg while (A)
591debfc3dSmrg {
601debfc3dSmrg B;
611debfc3dSmrg X;
621debfc3dSmrg }
631debfc3dSmrg }
641debfc3dSmrg else
651debfc3dSmrg {
661debfc3dSmrg while (A)
671debfc3dSmrg {
681debfc3dSmrg X;
691debfc3dSmrg C;
701debfc3dSmrg }
711debfc3dSmrg }
721debfc3dSmrg
731debfc3dSmrg Inv is considered invariant iff the values it compares are both invariant;
741debfc3dSmrg tree-ssa-loop-im.c ensures that all the suitable conditions are in this
751debfc3dSmrg shape. */
761debfc3dSmrg
77*8feb0f0bSmrg static class loop *tree_unswitch_loop (class loop *, basic_block, tree);
78*8feb0f0bSmrg static bool tree_unswitch_single_loop (class loop *, int);
79*8feb0f0bSmrg static tree tree_may_unswitch_on (basic_block, class loop *);
80*8feb0f0bSmrg static bool tree_unswitch_outer_loop (class loop *);
81*8feb0f0bSmrg static edge find_loop_guard (class loop *);
82*8feb0f0bSmrg static bool empty_bb_without_guard_p (class loop *, basic_block);
83*8feb0f0bSmrg static bool used_outside_loop_p (class loop *, tree);
84*8feb0f0bSmrg static void hoist_guard (class loop *, edge);
85*8feb0f0bSmrg static bool check_exit_phi (class loop *);
86*8feb0f0bSmrg static tree get_vop_from_header (class loop *);
871debfc3dSmrg
881debfc3dSmrg /* Main entry point. Perform loop unswitching on all suitable loops. */
891debfc3dSmrg
901debfc3dSmrg unsigned int
tree_ssa_unswitch_loops(void)911debfc3dSmrg tree_ssa_unswitch_loops (void)
921debfc3dSmrg {
93*8feb0f0bSmrg class loop *loop;
941debfc3dSmrg bool changed = false;
951debfc3dSmrg
961debfc3dSmrg /* Go through all loops starting from innermost. */
971debfc3dSmrg FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
981debfc3dSmrg {
991debfc3dSmrg if (!loop->inner)
1001debfc3dSmrg /* Unswitch innermost loop. */
1011debfc3dSmrg changed |= tree_unswitch_single_loop (loop, 0);
1021debfc3dSmrg else
1031debfc3dSmrg changed |= tree_unswitch_outer_loop (loop);
1041debfc3dSmrg }
1051debfc3dSmrg
1061debfc3dSmrg if (changed)
1071debfc3dSmrg return TODO_cleanup_cfg;
1081debfc3dSmrg return 0;
1091debfc3dSmrg }
1101debfc3dSmrg
1111debfc3dSmrg /* Return TRUE if an SSA_NAME maybe undefined and is therefore
1121debfc3dSmrg unsuitable for unswitching. STMT is the statement we are
1131debfc3dSmrg considering for unswitching and LOOP is the loop it appears in. */
1141debfc3dSmrg
1151debfc3dSmrg static bool
is_maybe_undefined(const tree name,gimple * stmt,class loop * loop)116*8feb0f0bSmrg is_maybe_undefined (const tree name, gimple *stmt, class loop *loop)
1171debfc3dSmrg {
1181debfc3dSmrg /* The loop header is the only block we can trivially determine that
1191debfc3dSmrg will always be executed. If the comparison is in the loop
1201debfc3dSmrg header, we know it's OK to unswitch on it. */
1211debfc3dSmrg if (gimple_bb (stmt) == loop->header)
1221debfc3dSmrg return false;
1231debfc3dSmrg
1241debfc3dSmrg auto_bitmap visited_ssa;
1251debfc3dSmrg auto_vec<tree> worklist;
1261debfc3dSmrg worklist.safe_push (name);
1271debfc3dSmrg bitmap_set_bit (visited_ssa, SSA_NAME_VERSION (name));
1281debfc3dSmrg while (!worklist.is_empty ())
1291debfc3dSmrg {
1301debfc3dSmrg tree t = worklist.pop ();
1311debfc3dSmrg
1321debfc3dSmrg /* If it's obviously undefined, avoid further computations. */
1331debfc3dSmrg if (ssa_undefined_value_p (t, true))
1341debfc3dSmrg return true;
1351debfc3dSmrg
1361debfc3dSmrg if (ssa_defined_default_def_p (t))
1371debfc3dSmrg continue;
1381debfc3dSmrg
1391debfc3dSmrg gimple *def = SSA_NAME_DEF_STMT (t);
1401debfc3dSmrg
1411debfc3dSmrg /* Check that all the PHI args are fully defined. */
1421debfc3dSmrg if (gphi *phi = dyn_cast <gphi *> (def))
1431debfc3dSmrg {
1441debfc3dSmrg for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
1451debfc3dSmrg {
1461debfc3dSmrg tree t = gimple_phi_arg_def (phi, i);
1471debfc3dSmrg /* If an SSA has already been seen, it may be a loop,
1481debfc3dSmrg but we can continue and ignore this use. Otherwise,
1491debfc3dSmrg add the SSA_NAME to the queue and visit it later. */
1501debfc3dSmrg if (TREE_CODE (t) == SSA_NAME
1511debfc3dSmrg && bitmap_set_bit (visited_ssa, SSA_NAME_VERSION (t)))
1521debfc3dSmrg worklist.safe_push (t);
1531debfc3dSmrg }
1541debfc3dSmrg continue;
1551debfc3dSmrg }
1561debfc3dSmrg
1571debfc3dSmrg /* Uses in stmts always executed when the region header executes
1581debfc3dSmrg are fine. */
1591debfc3dSmrg if (dominated_by_p (CDI_DOMINATORS, loop->header, gimple_bb (def)))
1601debfc3dSmrg continue;
1611debfc3dSmrg
1621debfc3dSmrg /* Handle calls and memory loads conservatively. */
1631debfc3dSmrg if (!is_gimple_assign (def)
1641debfc3dSmrg || (gimple_assign_single_p (def)
1651debfc3dSmrg && gimple_vuse (def)))
1661debfc3dSmrg return true;
1671debfc3dSmrg
1681debfc3dSmrg /* Check that any SSA names used to define NAME are also fully
1691debfc3dSmrg defined. */
1701debfc3dSmrg use_operand_p use_p;
1711debfc3dSmrg ssa_op_iter iter;
1721debfc3dSmrg FOR_EACH_SSA_USE_OPERAND (use_p, def, iter, SSA_OP_USE)
1731debfc3dSmrg {
1741debfc3dSmrg tree t = USE_FROM_PTR (use_p);
1751debfc3dSmrg /* If an SSA has already been seen, it may be a loop,
1761debfc3dSmrg but we can continue and ignore this use. Otherwise,
1771debfc3dSmrg add the SSA_NAME to the queue and visit it later. */
1781debfc3dSmrg if (bitmap_set_bit (visited_ssa, SSA_NAME_VERSION (t)))
1791debfc3dSmrg worklist.safe_push (t);
1801debfc3dSmrg }
1811debfc3dSmrg }
1821debfc3dSmrg return false;
1831debfc3dSmrg }
1841debfc3dSmrg
1851debfc3dSmrg /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
1861debfc3dSmrg basic blocks (for what it means see comments below). */
1871debfc3dSmrg
1881debfc3dSmrg static tree
tree_may_unswitch_on(basic_block bb,class loop * loop)189*8feb0f0bSmrg tree_may_unswitch_on (basic_block bb, class loop *loop)
1901debfc3dSmrg {
1911debfc3dSmrg gimple *last, *def;
1921debfc3dSmrg gcond *stmt;
1931debfc3dSmrg tree cond, use;
1941debfc3dSmrg basic_block def_bb;
1951debfc3dSmrg ssa_op_iter iter;
1961debfc3dSmrg
1971debfc3dSmrg /* BB must end in a simple conditional jump. */
1981debfc3dSmrg last = last_stmt (bb);
1991debfc3dSmrg if (!last || gimple_code (last) != GIMPLE_COND)
2001debfc3dSmrg return NULL_TREE;
2011debfc3dSmrg stmt = as_a <gcond *> (last);
2021debfc3dSmrg
2031debfc3dSmrg /* To keep the things simple, we do not directly remove the conditions,
2041debfc3dSmrg but just replace tests with 0 != 0 resp. 1 != 0. Prevent the infinite
2051debfc3dSmrg loop where we would unswitch again on such a condition. */
2061debfc3dSmrg if (gimple_cond_true_p (stmt) || gimple_cond_false_p (stmt))
2071debfc3dSmrg return NULL_TREE;
2081debfc3dSmrg
2091debfc3dSmrg /* Condition must be invariant. */
2101debfc3dSmrg FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
2111debfc3dSmrg {
2121debfc3dSmrg def = SSA_NAME_DEF_STMT (use);
2131debfc3dSmrg def_bb = gimple_bb (def);
2141debfc3dSmrg if (def_bb
2151debfc3dSmrg && flow_bb_inside_loop_p (loop, def_bb))
2161debfc3dSmrg return NULL_TREE;
2171debfc3dSmrg /* Unswitching on undefined values would introduce undefined
2181debfc3dSmrg behavior that the original program might never exercise. */
2191debfc3dSmrg if (is_maybe_undefined (use, stmt, loop))
2201debfc3dSmrg return NULL_TREE;
2211debfc3dSmrg }
2221debfc3dSmrg
2231debfc3dSmrg cond = build2 (gimple_cond_code (stmt), boolean_type_node,
2241debfc3dSmrg gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
2251debfc3dSmrg
2261debfc3dSmrg return cond;
2271debfc3dSmrg }
2281debfc3dSmrg
2291debfc3dSmrg /* Simplifies COND using checks in front of the entry of the LOOP. Just very
2301debfc3dSmrg simplish (sufficient to prevent us from duplicating loop in unswitching
2311debfc3dSmrg unnecessarily). */
2321debfc3dSmrg
2331debfc3dSmrg static tree
simplify_using_entry_checks(class loop * loop,tree cond)234*8feb0f0bSmrg simplify_using_entry_checks (class loop *loop, tree cond)
2351debfc3dSmrg {
2361debfc3dSmrg edge e = loop_preheader_edge (loop);
2371debfc3dSmrg gimple *stmt;
2381debfc3dSmrg
2391debfc3dSmrg while (1)
2401debfc3dSmrg {
2411debfc3dSmrg stmt = last_stmt (e->src);
2421debfc3dSmrg if (stmt
2431debfc3dSmrg && gimple_code (stmt) == GIMPLE_COND
2441debfc3dSmrg && gimple_cond_code (stmt) == TREE_CODE (cond)
2451debfc3dSmrg && operand_equal_p (gimple_cond_lhs (stmt),
2461debfc3dSmrg TREE_OPERAND (cond, 0), 0)
2471debfc3dSmrg && operand_equal_p (gimple_cond_rhs (stmt),
2481debfc3dSmrg TREE_OPERAND (cond, 1), 0))
2491debfc3dSmrg return (e->flags & EDGE_TRUE_VALUE
2501debfc3dSmrg ? boolean_true_node
2511debfc3dSmrg : boolean_false_node);
2521debfc3dSmrg
2531debfc3dSmrg if (!single_pred_p (e->src))
2541debfc3dSmrg return cond;
2551debfc3dSmrg
2561debfc3dSmrg e = single_pred_edge (e->src);
2571debfc3dSmrg if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
2581debfc3dSmrg return cond;
2591debfc3dSmrg }
2601debfc3dSmrg }
2611debfc3dSmrg
2621debfc3dSmrg /* Unswitch single LOOP. NUM is number of unswitchings done; we do not allow
2631debfc3dSmrg it to grow too much, it is too easy to create example on that the code would
2641debfc3dSmrg grow exponentially. */
2651debfc3dSmrg
2661debfc3dSmrg static bool
tree_unswitch_single_loop(class loop * loop,int num)267*8feb0f0bSmrg tree_unswitch_single_loop (class loop *loop, int num)
2681debfc3dSmrg {
2691debfc3dSmrg basic_block *bbs;
270*8feb0f0bSmrg class loop *nloop;
2711debfc3dSmrg unsigned i, found;
2721debfc3dSmrg tree cond = NULL_TREE;
2731debfc3dSmrg gimple *stmt;
2741debfc3dSmrg bool changed = false;
2751debfc3dSmrg HOST_WIDE_INT iterations;
2761debfc3dSmrg
2771debfc3dSmrg /* Perform initial tests if unswitch is eligible. */
2781debfc3dSmrg if (num == 0)
2791debfc3dSmrg {
2801debfc3dSmrg /* Do not unswitch in cold regions. */
2811debfc3dSmrg if (optimize_loop_for_size_p (loop))
2821debfc3dSmrg {
2831debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
2841debfc3dSmrg fprintf (dump_file, ";; Not unswitching cold loops\n");
2851debfc3dSmrg return false;
2861debfc3dSmrg }
2871debfc3dSmrg
2881debfc3dSmrg /* The loop should not be too large, to limit code growth. */
2891debfc3dSmrg if (tree_num_loop_insns (loop, &eni_size_weights)
290*8feb0f0bSmrg > (unsigned) param_max_unswitch_insns)
2911debfc3dSmrg {
2921debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
2931debfc3dSmrg fprintf (dump_file, ";; Not unswitching, loop too big\n");
2941debfc3dSmrg return false;
2951debfc3dSmrg }
2961debfc3dSmrg
2971debfc3dSmrg /* If the loop is not expected to iterate, there is no need
2981debfc3dSmrg for unswitching. */
2991debfc3dSmrg iterations = estimated_loop_iterations_int (loop);
3001debfc3dSmrg if (iterations < 0)
3011debfc3dSmrg iterations = likely_max_loop_iterations_int (loop);
3021debfc3dSmrg if (iterations >= 0 && iterations <= 1)
3031debfc3dSmrg {
3041debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
3051debfc3dSmrg fprintf (dump_file, ";; Not unswitching, loop is not expected"
3061debfc3dSmrg " to iterate\n");
3071debfc3dSmrg return false;
3081debfc3dSmrg }
3091debfc3dSmrg }
3101debfc3dSmrg
3111debfc3dSmrg i = 0;
3121debfc3dSmrg bbs = get_loop_body (loop);
3131debfc3dSmrg found = loop->num_nodes;
3141debfc3dSmrg
3151debfc3dSmrg while (1)
3161debfc3dSmrg {
3171debfc3dSmrg /* Find a bb to unswitch on. */
3181debfc3dSmrg for (; i < loop->num_nodes; i++)
3191debfc3dSmrg if ((cond = tree_may_unswitch_on (bbs[i], loop)))
3201debfc3dSmrg break;
3211debfc3dSmrg
3221debfc3dSmrg if (i == loop->num_nodes)
3231debfc3dSmrg {
3241debfc3dSmrg if (dump_file
325*8feb0f0bSmrg && num > param_max_unswitch_level
3261debfc3dSmrg && (dump_flags & TDF_DETAILS))
3271debfc3dSmrg fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
3281debfc3dSmrg
3291debfc3dSmrg if (found == loop->num_nodes)
3301debfc3dSmrg {
3311debfc3dSmrg free (bbs);
3321debfc3dSmrg return changed;
3331debfc3dSmrg }
3341debfc3dSmrg break;
3351debfc3dSmrg }
3361debfc3dSmrg
3371debfc3dSmrg cond = simplify_using_entry_checks (loop, cond);
3381debfc3dSmrg stmt = last_stmt (bbs[i]);
3391debfc3dSmrg if (integer_nonzerop (cond))
3401debfc3dSmrg {
3411debfc3dSmrg /* Remove false path. */
3421debfc3dSmrg gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
3431debfc3dSmrg boolean_true_node);
3441debfc3dSmrg changed = true;
3451debfc3dSmrg }
3461debfc3dSmrg else if (integer_zerop (cond))
3471debfc3dSmrg {
3481debfc3dSmrg /* Remove true path. */
3491debfc3dSmrg gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt),
3501debfc3dSmrg boolean_false_node);
3511debfc3dSmrg changed = true;
3521debfc3dSmrg }
3531debfc3dSmrg /* Do not unswitch too much. */
354*8feb0f0bSmrg else if (num > param_max_unswitch_level)
3551debfc3dSmrg {
3561debfc3dSmrg i++;
3571debfc3dSmrg continue;
3581debfc3dSmrg }
3591debfc3dSmrg /* In nested tree_unswitch_single_loop first optimize all conditions
3601debfc3dSmrg using entry checks, then discover still reachable blocks in the
3611debfc3dSmrg loop and find the condition only among those still reachable bbs. */
3621debfc3dSmrg else if (num != 0)
3631debfc3dSmrg {
3641debfc3dSmrg if (found == loop->num_nodes)
3651debfc3dSmrg found = i;
3661debfc3dSmrg i++;
3671debfc3dSmrg continue;
3681debfc3dSmrg }
3691debfc3dSmrg else
3701debfc3dSmrg {
3711debfc3dSmrg found = i;
3721debfc3dSmrg break;
3731debfc3dSmrg }
3741debfc3dSmrg
3751debfc3dSmrg update_stmt (stmt);
3761debfc3dSmrg i++;
3771debfc3dSmrg }
3781debfc3dSmrg
3791debfc3dSmrg if (num != 0)
3801debfc3dSmrg {
3811debfc3dSmrg basic_block *tos, *worklist;
3821debfc3dSmrg
3831debfc3dSmrg /* When called recursively, first do a quick discovery
3841debfc3dSmrg of reachable bbs after the above changes and only
3851debfc3dSmrg consider conditions in still reachable bbs. */
3861debfc3dSmrg tos = worklist = XNEWVEC (basic_block, loop->num_nodes);
3871debfc3dSmrg
3881debfc3dSmrg for (i = 0; i < loop->num_nodes; i++)
3891debfc3dSmrg bbs[i]->flags &= ~BB_REACHABLE;
3901debfc3dSmrg
3911debfc3dSmrg /* Start with marking header. */
3921debfc3dSmrg *tos++ = bbs[0];
3931debfc3dSmrg bbs[0]->flags |= BB_REACHABLE;
3941debfc3dSmrg
3951debfc3dSmrg /* Iterate: find everything reachable from what we've already seen
3961debfc3dSmrg within the same innermost loop. Don't look through false edges
3971debfc3dSmrg if condition is always true or true edges if condition is
3981debfc3dSmrg always false. */
3991debfc3dSmrg while (tos != worklist)
4001debfc3dSmrg {
4011debfc3dSmrg basic_block b = *--tos;
4021debfc3dSmrg edge e;
4031debfc3dSmrg edge_iterator ei;
4041debfc3dSmrg int flags = 0;
4051debfc3dSmrg
4061debfc3dSmrg if (EDGE_COUNT (b->succs) == 2)
4071debfc3dSmrg {
4081debfc3dSmrg gimple *stmt = last_stmt (b);
4091debfc3dSmrg if (stmt
4101debfc3dSmrg && gimple_code (stmt) == GIMPLE_COND)
4111debfc3dSmrg {
4121debfc3dSmrg gcond *cond_stmt = as_a <gcond *> (stmt);
4131debfc3dSmrg if (gimple_cond_true_p (cond_stmt))
4141debfc3dSmrg flags = EDGE_FALSE_VALUE;
4151debfc3dSmrg else if (gimple_cond_false_p (cond_stmt))
4161debfc3dSmrg flags = EDGE_TRUE_VALUE;
4171debfc3dSmrg }
4181debfc3dSmrg }
4191debfc3dSmrg
4201debfc3dSmrg FOR_EACH_EDGE (e, ei, b->succs)
4211debfc3dSmrg {
4221debfc3dSmrg basic_block dest = e->dest;
4231debfc3dSmrg
4241debfc3dSmrg if (dest->loop_father == loop
4251debfc3dSmrg && !(dest->flags & BB_REACHABLE)
4261debfc3dSmrg && !(e->flags & flags))
4271debfc3dSmrg {
4281debfc3dSmrg *tos++ = dest;
4291debfc3dSmrg dest->flags |= BB_REACHABLE;
4301debfc3dSmrg }
4311debfc3dSmrg }
4321debfc3dSmrg }
4331debfc3dSmrg
4341debfc3dSmrg free (worklist);
4351debfc3dSmrg
4361debfc3dSmrg /* Find a bb to unswitch on. */
4371debfc3dSmrg for (; found < loop->num_nodes; found++)
4381debfc3dSmrg if ((bbs[found]->flags & BB_REACHABLE)
4391debfc3dSmrg && (cond = tree_may_unswitch_on (bbs[found], loop)))
4401debfc3dSmrg break;
4411debfc3dSmrg
4421debfc3dSmrg if (found == loop->num_nodes)
4431debfc3dSmrg {
4441debfc3dSmrg free (bbs);
4451debfc3dSmrg return changed;
4461debfc3dSmrg }
4471debfc3dSmrg }
4481debfc3dSmrg
4491debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
4501debfc3dSmrg fprintf (dump_file, ";; Unswitching loop\n");
4511debfc3dSmrg
4521debfc3dSmrg initialize_original_copy_tables ();
4531debfc3dSmrg /* Unswitch the loop on this condition. */
4541debfc3dSmrg nloop = tree_unswitch_loop (loop, bbs[found], cond);
4551debfc3dSmrg if (!nloop)
4561debfc3dSmrg {
4571debfc3dSmrg free_original_copy_tables ();
4581debfc3dSmrg free (bbs);
4591debfc3dSmrg return changed;
4601debfc3dSmrg }
4611debfc3dSmrg
4621debfc3dSmrg /* Update the SSA form after unswitching. */
4631debfc3dSmrg update_ssa (TODO_update_ssa);
4641debfc3dSmrg free_original_copy_tables ();
4651debfc3dSmrg
4661debfc3dSmrg /* Invoke itself on modified loops. */
4671debfc3dSmrg tree_unswitch_single_loop (nloop, num + 1);
4681debfc3dSmrg tree_unswitch_single_loop (loop, num + 1);
4691debfc3dSmrg free (bbs);
4701debfc3dSmrg return true;
4711debfc3dSmrg }
4721debfc3dSmrg
4731debfc3dSmrg /* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON. We only support
4741debfc3dSmrg unswitching of innermost loops. COND is the condition determining which
4751debfc3dSmrg loop is entered -- the new loop is entered if COND is true. Returns NULL
4761debfc3dSmrg if impossible, new loop otherwise. */
4771debfc3dSmrg
478*8feb0f0bSmrg static class loop *
tree_unswitch_loop(class loop * loop,basic_block unswitch_on,tree cond)479*8feb0f0bSmrg tree_unswitch_loop (class loop *loop,
4801debfc3dSmrg basic_block unswitch_on, tree cond)
4811debfc3dSmrg {
482a2dc1f3fSmrg profile_probability prob_true;
4831debfc3dSmrg edge edge_true, edge_false;
4841debfc3dSmrg
4851debfc3dSmrg /* Some sanity checking. */
4861debfc3dSmrg gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
4871debfc3dSmrg gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
4881debfc3dSmrg gcc_assert (loop->inner == NULL);
4891debfc3dSmrg
4901debfc3dSmrg extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false);
4911debfc3dSmrg prob_true = edge_true->probability;
4921debfc3dSmrg return loop_version (loop, unshare_expr (cond),
493a2dc1f3fSmrg NULL, prob_true,
494a2dc1f3fSmrg prob_true.invert (),
495a2dc1f3fSmrg prob_true, prob_true.invert (),
496a2dc1f3fSmrg false);
4971debfc3dSmrg }
4981debfc3dSmrg
4991debfc3dSmrg /* Unswitch outer loops by hoisting invariant guard on
5001debfc3dSmrg inner loop without code duplication. */
5011debfc3dSmrg static bool
tree_unswitch_outer_loop(class loop * loop)502*8feb0f0bSmrg tree_unswitch_outer_loop (class loop *loop)
5031debfc3dSmrg {
5041debfc3dSmrg edge exit, guard;
5051debfc3dSmrg HOST_WIDE_INT iterations;
5061debfc3dSmrg
5071debfc3dSmrg gcc_assert (loop->inner);
5081debfc3dSmrg if (loop->inner->next)
5091debfc3dSmrg return false;
5101debfc3dSmrg /* Accept loops with single exit only which is not from inner loop. */
5111debfc3dSmrg exit = single_exit (loop);
5121debfc3dSmrg if (!exit || exit->src->loop_father != loop)
5131debfc3dSmrg return false;
5141debfc3dSmrg /* Check that phi argument of exit edge is not defined inside loop. */
5151debfc3dSmrg if (!check_exit_phi (loop))
5161debfc3dSmrg return false;
5171debfc3dSmrg /* If the loop is not expected to iterate, there is no need
5181debfc3dSmrg for unswitching. */
5191debfc3dSmrg iterations = estimated_loop_iterations_int (loop);
5201debfc3dSmrg if (iterations < 0)
5211debfc3dSmrg iterations = likely_max_loop_iterations_int (loop);
5221debfc3dSmrg if (iterations >= 0 && iterations <= 1)
5231debfc3dSmrg {
5241debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
5251debfc3dSmrg fprintf (dump_file, ";; Not unswitching, loop is not expected"
5261debfc3dSmrg " to iterate\n");
5271debfc3dSmrg return false;
5281debfc3dSmrg }
5291debfc3dSmrg
5301debfc3dSmrg bool changed = false;
5311debfc3dSmrg while ((guard = find_loop_guard (loop)))
5321debfc3dSmrg {
5331debfc3dSmrg if (! changed)
5341debfc3dSmrg rewrite_virtuals_into_loop_closed_ssa (loop);
5351debfc3dSmrg hoist_guard (loop, guard);
5361debfc3dSmrg changed = true;
5371debfc3dSmrg }
5381debfc3dSmrg return changed;
5391debfc3dSmrg }
5401debfc3dSmrg
5411debfc3dSmrg /* Checks if the body of the LOOP is within an invariant guard. If this
5421debfc3dSmrg is the case, returns the edge that jumps over the real body of the loop,
5431debfc3dSmrg otherwise returns NULL. */
5441debfc3dSmrg
5451debfc3dSmrg static edge
find_loop_guard(class loop * loop)546*8feb0f0bSmrg find_loop_guard (class loop *loop)
5471debfc3dSmrg {
5481debfc3dSmrg basic_block header = loop->header;
5491debfc3dSmrg edge guard_edge, te, fe;
5501debfc3dSmrg basic_block *body = NULL;
5511debfc3dSmrg unsigned i;
5521debfc3dSmrg tree use;
5531debfc3dSmrg ssa_op_iter iter;
5541debfc3dSmrg
5551debfc3dSmrg /* We check for the following situation:
5561debfc3dSmrg
5571debfc3dSmrg while (1)
5581debfc3dSmrg {
5591debfc3dSmrg [header]]
5601debfc3dSmrg loop_phi_nodes;
5611debfc3dSmrg something1;
5621debfc3dSmrg if (cond1)
5631debfc3dSmrg body;
5641debfc3dSmrg nvar = phi(orig, bvar) ... for all variables changed in body;
5651debfc3dSmrg [guard_end]
5661debfc3dSmrg something2;
5671debfc3dSmrg if (cond2)
5681debfc3dSmrg break;
5691debfc3dSmrg something3;
5701debfc3dSmrg }
5711debfc3dSmrg
5721debfc3dSmrg where:
5731debfc3dSmrg
5741debfc3dSmrg 1) cond1 is loop invariant
5751debfc3dSmrg 2) If cond1 is false, then the loop is essentially empty; i.e.,
5761debfc3dSmrg a) nothing in something1, something2 and something3 has side
5771debfc3dSmrg effects
5781debfc3dSmrg b) anything defined in something1, something2 and something3
5791debfc3dSmrg is not used outside of the loop. */
5801debfc3dSmrg
5811debfc3dSmrg gcond *cond;
5821debfc3dSmrg do
5831debfc3dSmrg {
5841debfc3dSmrg basic_block next = NULL;
5851debfc3dSmrg if (single_succ_p (header))
5861debfc3dSmrg next = single_succ (header);
5871debfc3dSmrg else
5881debfc3dSmrg {
589*8feb0f0bSmrg cond = safe_dyn_cast <gcond *> (last_stmt (header));
5901debfc3dSmrg if (! cond)
5911debfc3dSmrg return NULL;
5921debfc3dSmrg extract_true_false_edges_from_block (header, &te, &fe);
5931debfc3dSmrg /* Make sure to skip earlier hoisted guards that are left
5941debfc3dSmrg in place as if (true). */
5951debfc3dSmrg if (gimple_cond_true_p (cond))
5961debfc3dSmrg next = te->dest;
5971debfc3dSmrg else if (gimple_cond_false_p (cond))
5981debfc3dSmrg next = fe->dest;
5991debfc3dSmrg else
6001debfc3dSmrg break;
6011debfc3dSmrg }
6021debfc3dSmrg /* Never traverse a backedge. */
6031debfc3dSmrg if (header->loop_father->header == next)
6041debfc3dSmrg return NULL;
6051debfc3dSmrg header = next;
6061debfc3dSmrg }
6071debfc3dSmrg while (1);
6081debfc3dSmrg if (!flow_bb_inside_loop_p (loop, te->dest)
6091debfc3dSmrg || !flow_bb_inside_loop_p (loop, fe->dest))
6101debfc3dSmrg return NULL;
6111debfc3dSmrg
6121debfc3dSmrg if (just_once_each_iteration_p (loop, te->dest)
6131debfc3dSmrg || (single_succ_p (te->dest)
6141debfc3dSmrg && just_once_each_iteration_p (loop, single_succ (te->dest))))
6151debfc3dSmrg {
6161debfc3dSmrg if (just_once_each_iteration_p (loop, fe->dest))
6171debfc3dSmrg return NULL;
6181debfc3dSmrg guard_edge = te;
6191debfc3dSmrg }
6201debfc3dSmrg else if (just_once_each_iteration_p (loop, fe->dest)
6211debfc3dSmrg || (single_succ_p (fe->dest)
6221debfc3dSmrg && just_once_each_iteration_p (loop, single_succ (fe->dest))))
6231debfc3dSmrg guard_edge = fe;
6241debfc3dSmrg else
6251debfc3dSmrg return NULL;
6261debfc3dSmrg
6271debfc3dSmrg /* Guard edge must skip inner loop. */
6281debfc3dSmrg if (!dominated_by_p (CDI_DOMINATORS, loop->inner->header,
6291debfc3dSmrg guard_edge == fe ? te->dest : fe->dest))
6301debfc3dSmrg {
6311debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6321debfc3dSmrg fprintf (dump_file, "Guard edge %d --> %d is not around the loop!\n",
6331debfc3dSmrg guard_edge->src->index, guard_edge->dest->index);
6341debfc3dSmrg return NULL;
6351debfc3dSmrg }
6361debfc3dSmrg if (guard_edge->dest == loop->latch)
6371debfc3dSmrg {
6381debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6391debfc3dSmrg fprintf (dump_file, "Guard edge destination is loop latch.\n");
6401debfc3dSmrg return NULL;
6411debfc3dSmrg }
6421debfc3dSmrg
6431debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6441debfc3dSmrg fprintf (dump_file,
6451debfc3dSmrg "Considering guard %d -> %d in loop %d\n",
6461debfc3dSmrg guard_edge->src->index, guard_edge->dest->index, loop->num);
6471debfc3dSmrg /* Check if condition operands do not have definitions inside loop since
6481debfc3dSmrg any bb copying is not performed. */
6491debfc3dSmrg FOR_EACH_SSA_TREE_OPERAND (use, cond, iter, SSA_OP_USE)
6501debfc3dSmrg {
6511debfc3dSmrg gimple *def = SSA_NAME_DEF_STMT (use);
6521debfc3dSmrg basic_block def_bb = gimple_bb (def);
6531debfc3dSmrg if (def_bb
6541debfc3dSmrg && flow_bb_inside_loop_p (loop, def_bb))
6551debfc3dSmrg {
6561debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6571debfc3dSmrg fprintf (dump_file, " guard operands have definitions"
6581debfc3dSmrg " inside loop\n");
6591debfc3dSmrg return NULL;
6601debfc3dSmrg }
6611debfc3dSmrg }
6621debfc3dSmrg
6631debfc3dSmrg body = get_loop_body (loop);
6641debfc3dSmrg for (i = 0; i < loop->num_nodes; i++)
6651debfc3dSmrg {
6661debfc3dSmrg basic_block bb = body[i];
6671debfc3dSmrg if (bb->loop_father != loop)
6681debfc3dSmrg continue;
6691debfc3dSmrg if (bb->flags & BB_IRREDUCIBLE_LOOP)
6701debfc3dSmrg {
6711debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6721debfc3dSmrg fprintf (dump_file, "Block %d is marked as irreducible in loop\n",
6731debfc3dSmrg bb->index);
6741debfc3dSmrg guard_edge = NULL;
6751debfc3dSmrg goto end;
6761debfc3dSmrg }
6771debfc3dSmrg if (!empty_bb_without_guard_p (loop, bb))
6781debfc3dSmrg {
6791debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6801debfc3dSmrg fprintf (dump_file, " block %d has side effects\n", bb->index);
6811debfc3dSmrg guard_edge = NULL;
6821debfc3dSmrg goto end;
6831debfc3dSmrg }
6841debfc3dSmrg }
6851debfc3dSmrg
6861debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
6871debfc3dSmrg fprintf (dump_file, " suitable to hoist\n");
6881debfc3dSmrg end:
6891debfc3dSmrg if (body)
6901debfc3dSmrg free (body);
6911debfc3dSmrg return guard_edge;
6921debfc3dSmrg }
6931debfc3dSmrg
6941debfc3dSmrg /* Returns true if
6951debfc3dSmrg 1) no statement in BB has side effects
6961debfc3dSmrg 2) assuming that edge GUARD is always taken, all definitions in BB
6971debfc3dSmrg are noy used outside of the loop.
6981debfc3dSmrg KNOWN_INVARIANTS is a set of ssa names we know to be invariant, and
6991debfc3dSmrg PROCESSED is a set of ssa names for that we already tested whether they
7001debfc3dSmrg are invariant or not. */
7011debfc3dSmrg
7021debfc3dSmrg static bool
empty_bb_without_guard_p(class loop * loop,basic_block bb)703*8feb0f0bSmrg empty_bb_without_guard_p (class loop *loop, basic_block bb)
7041debfc3dSmrg {
7051debfc3dSmrg basic_block exit_bb = single_exit (loop)->src;
7061debfc3dSmrg bool may_be_used_outside = (bb == exit_bb
7071debfc3dSmrg || !dominated_by_p (CDI_DOMINATORS, bb, exit_bb));
7081debfc3dSmrg tree name;
7091debfc3dSmrg ssa_op_iter op_iter;
7101debfc3dSmrg
7111debfc3dSmrg /* Phi nodes do not have side effects, but their results might be used
7121debfc3dSmrg outside of the loop. */
7131debfc3dSmrg if (may_be_used_outside)
7141debfc3dSmrg {
7151debfc3dSmrg for (gphi_iterator gsi = gsi_start_phis (bb);
7161debfc3dSmrg !gsi_end_p (gsi); gsi_next (&gsi))
7171debfc3dSmrg {
7181debfc3dSmrg gphi *phi = gsi.phi ();
7191debfc3dSmrg name = PHI_RESULT (phi);
7201debfc3dSmrg if (virtual_operand_p (name))
7211debfc3dSmrg continue;
7221debfc3dSmrg
7231debfc3dSmrg if (used_outside_loop_p (loop, name))
7241debfc3dSmrg return false;
7251debfc3dSmrg }
7261debfc3dSmrg }
7271debfc3dSmrg
7281debfc3dSmrg for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
7291debfc3dSmrg !gsi_end_p (gsi); gsi_next (&gsi))
7301debfc3dSmrg {
7311debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
7321debfc3dSmrg if (gimple_has_side_effects (stmt))
7331debfc3dSmrg return false;
7341debfc3dSmrg
7351debfc3dSmrg if (gimple_vdef(stmt))
7361debfc3dSmrg return false;
7371debfc3dSmrg
7381debfc3dSmrg FOR_EACH_SSA_TREE_OPERAND (name, stmt, op_iter, SSA_OP_DEF)
7391debfc3dSmrg {
7401debfc3dSmrg if (may_be_used_outside
7411debfc3dSmrg && used_outside_loop_p (loop, name))
7421debfc3dSmrg return false;
7431debfc3dSmrg }
7441debfc3dSmrg }
7451debfc3dSmrg return true;
7461debfc3dSmrg }
7471debfc3dSmrg
7481debfc3dSmrg /* Return true if NAME is used outside of LOOP. */
7491debfc3dSmrg
7501debfc3dSmrg static bool
used_outside_loop_p(class loop * loop,tree name)751*8feb0f0bSmrg used_outside_loop_p (class loop *loop, tree name)
7521debfc3dSmrg {
7531debfc3dSmrg imm_use_iterator it;
7541debfc3dSmrg use_operand_p use;
7551debfc3dSmrg
7561debfc3dSmrg FOR_EACH_IMM_USE_FAST (use, it, name)
7571debfc3dSmrg {
7581debfc3dSmrg gimple *stmt = USE_STMT (use);
7591debfc3dSmrg if (!flow_bb_inside_loop_p (loop, gimple_bb (stmt)))
7601debfc3dSmrg return true;
7611debfc3dSmrg }
7621debfc3dSmrg
7631debfc3dSmrg return false;
7641debfc3dSmrg }
7651debfc3dSmrg
7661debfc3dSmrg /* Return argument for loop preheader edge in header virtual phi if any. */
7671debfc3dSmrg
7681debfc3dSmrg static tree
get_vop_from_header(class loop * loop)769*8feb0f0bSmrg get_vop_from_header (class loop *loop)
7701debfc3dSmrg {
7711debfc3dSmrg for (gphi_iterator gsi = gsi_start_phis (loop->header);
7721debfc3dSmrg !gsi_end_p (gsi); gsi_next (&gsi))
7731debfc3dSmrg {
7741debfc3dSmrg gphi *phi = gsi.phi ();
7751debfc3dSmrg if (!virtual_operand_p (gimple_phi_result (phi)))
7761debfc3dSmrg continue;
7771debfc3dSmrg return PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop));
7781debfc3dSmrg }
7791debfc3dSmrg return NULL_TREE;
7801debfc3dSmrg }
7811debfc3dSmrg
7821debfc3dSmrg /* Move the check of GUARD outside of LOOP. */
7831debfc3dSmrg
7841debfc3dSmrg static void
hoist_guard(class loop * loop,edge guard)785*8feb0f0bSmrg hoist_guard (class loop *loop, edge guard)
7861debfc3dSmrg {
7871debfc3dSmrg edge exit = single_exit (loop);
7881debfc3dSmrg edge preh = loop_preheader_edge (loop);
7891debfc3dSmrg basic_block pre_header = preh->src;
7901debfc3dSmrg basic_block bb;
7911debfc3dSmrg edge te, fe, e, new_edge;
7921debfc3dSmrg gimple *stmt;
7931debfc3dSmrg basic_block guard_bb = guard->src;
7941debfc3dSmrg edge not_guard;
7951debfc3dSmrg gimple_stmt_iterator gsi;
7961debfc3dSmrg int flags = 0;
7971debfc3dSmrg bool fix_dom_of_exit;
7981debfc3dSmrg gcond *cond_stmt, *new_cond_stmt;
7991debfc3dSmrg
8001debfc3dSmrg bb = get_immediate_dominator (CDI_DOMINATORS, exit->dest);
8011debfc3dSmrg fix_dom_of_exit = flow_bb_inside_loop_p (loop, bb);
8021debfc3dSmrg gsi = gsi_last_bb (guard_bb);
8031debfc3dSmrg stmt = gsi_stmt (gsi);
8041debfc3dSmrg gcc_assert (gimple_code (stmt) == GIMPLE_COND);
8051debfc3dSmrg cond_stmt = as_a <gcond *> (stmt);
8061debfc3dSmrg extract_true_false_edges_from_block (guard_bb, &te, &fe);
8071debfc3dSmrg /* Insert guard to PRE_HEADER. */
8081debfc3dSmrg if (!empty_block_p (pre_header))
8091debfc3dSmrg gsi = gsi_last_bb (pre_header);
8101debfc3dSmrg else
8111debfc3dSmrg gsi = gsi_start_bb (pre_header);
8121debfc3dSmrg /* Create copy of COND_STMT. */
8131debfc3dSmrg new_cond_stmt = gimple_build_cond (gimple_cond_code (cond_stmt),
8141debfc3dSmrg gimple_cond_lhs (cond_stmt),
8151debfc3dSmrg gimple_cond_rhs (cond_stmt),
8161debfc3dSmrg NULL_TREE, NULL_TREE);
8171debfc3dSmrg gsi_insert_after (&gsi, new_cond_stmt, GSI_NEW_STMT);
8181debfc3dSmrg /* Convert COND_STMT to true/false conditional. */
8191debfc3dSmrg if (guard == te)
8201debfc3dSmrg gimple_cond_make_false (cond_stmt);
8211debfc3dSmrg else
8221debfc3dSmrg gimple_cond_make_true (cond_stmt);
8231debfc3dSmrg update_stmt (cond_stmt);
8241debfc3dSmrg /* Create new loop pre-header. */
8251debfc3dSmrg e = split_block (pre_header, last_stmt (pre_header));
8261debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
827a2dc1f3fSmrg {
828a2dc1f3fSmrg fprintf (dump_file, " Moving guard %i->%i (prob ",
829a2dc1f3fSmrg guard->src->index, guard->dest->index);
830a2dc1f3fSmrg guard->probability.dump (dump_file);
831a2dc1f3fSmrg fprintf (dump_file, ") to bb %i, new preheader is %i\n",
8321debfc3dSmrg e->src->index, e->dest->index);
833a2dc1f3fSmrg }
8341debfc3dSmrg
8351debfc3dSmrg gcc_assert (loop_preheader_edge (loop)->src == e->dest);
8361debfc3dSmrg
8371debfc3dSmrg if (guard == fe)
8381debfc3dSmrg {
8391debfc3dSmrg e->flags = EDGE_TRUE_VALUE;
8401debfc3dSmrg flags |= EDGE_FALSE_VALUE;
8411debfc3dSmrg not_guard = te;
8421debfc3dSmrg }
8431debfc3dSmrg else
8441debfc3dSmrg {
8451debfc3dSmrg e->flags = EDGE_FALSE_VALUE;
8461debfc3dSmrg flags |= EDGE_TRUE_VALUE;
8471debfc3dSmrg not_guard = fe;
8481debfc3dSmrg }
8491debfc3dSmrg new_edge = make_edge (pre_header, exit->dest, flags);
8501debfc3dSmrg
8511debfc3dSmrg /* Determine the probability that we skip the loop. Assume that loop has
8521debfc3dSmrg same average number of iterations regardless outcome of guard. */
8531debfc3dSmrg new_edge->probability = guard->probability;
854a2dc1f3fSmrg profile_count skip_count = guard->src->count.nonzero_p ()
855a2dc1f3fSmrg ? guard->count ().apply_scale (pre_header->count,
856a2dc1f3fSmrg guard->src->count)
857a2dc1f3fSmrg : guard->count ().apply_probability (new_edge->probability);
8581debfc3dSmrg
859a2dc1f3fSmrg if (skip_count > e->count ())
8601debfc3dSmrg {
8611debfc3dSmrg fprintf (dump_file, " Capping count; expect profile inconsistency\n");
862a2dc1f3fSmrg skip_count = e->count ();
8631debfc3dSmrg }
8641debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
865a2dc1f3fSmrg {
866a2dc1f3fSmrg fprintf (dump_file, " Estimated probability of skipping loop is ");
867a2dc1f3fSmrg new_edge->probability.dump (dump_file);
868a2dc1f3fSmrg fprintf (dump_file, "\n");
869a2dc1f3fSmrg }
8701debfc3dSmrg
8711debfc3dSmrg /* Update profile after the transform:
8721debfc3dSmrg
8731debfc3dSmrg First decrease count of path from newly hoisted loop guard
8741debfc3dSmrg to loop header... */
875a2dc1f3fSmrg e->probability = new_edge->probability.invert ();
876a2dc1f3fSmrg e->dest->count = e->count ();
8771debfc3dSmrg
8781debfc3dSmrg /* ... now update profile to represent that original guard will be optimized
8791debfc3dSmrg away ... */
880a2dc1f3fSmrg guard->probability = profile_probability::never ();
881a2dc1f3fSmrg not_guard->probability = profile_probability::always ();
8821debfc3dSmrg
8831debfc3dSmrg /* ... finally scale everything in the loop except for guarded basic blocks
8841debfc3dSmrg where profile does not change. */
8851debfc3dSmrg basic_block *body = get_loop_body (loop);
8861debfc3dSmrg
8871debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
8881debfc3dSmrg fprintf (dump_file, " Scaling nonguarded BBs in loop:");
8891debfc3dSmrg for (unsigned int i = 0; i < loop->num_nodes; i++)
8901debfc3dSmrg {
8911debfc3dSmrg basic_block bb = body[i];
8921debfc3dSmrg if (!dominated_by_p (CDI_DOMINATORS, bb, not_guard->dest))
8931debfc3dSmrg {
8941debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
8951debfc3dSmrg fprintf (dump_file, " %i", bb->index);
896a2dc1f3fSmrg if (e->probability.initialized_p ())
897a2dc1f3fSmrg scale_bbs_frequencies (&bb, 1, e->probability);
8981debfc3dSmrg }
8991debfc3dSmrg }
9001debfc3dSmrg
9011debfc3dSmrg if (fix_dom_of_exit)
9021debfc3dSmrg set_immediate_dominator (CDI_DOMINATORS, exit->dest, pre_header);
9031debfc3dSmrg /* Add NEW_ADGE argument for all phi in post-header block. */
9041debfc3dSmrg bb = exit->dest;
9051debfc3dSmrg for (gphi_iterator gsi = gsi_start_phis (bb);
9061debfc3dSmrg !gsi_end_p (gsi); gsi_next (&gsi))
9071debfc3dSmrg {
9081debfc3dSmrg gphi *phi = gsi.phi ();
9091debfc3dSmrg tree arg;
9101debfc3dSmrg if (virtual_operand_p (gimple_phi_result (phi)))
9111debfc3dSmrg {
9121debfc3dSmrg arg = get_vop_from_header (loop);
9131debfc3dSmrg if (arg == NULL_TREE)
9141debfc3dSmrg /* Use exit edge argument. */
9151debfc3dSmrg arg = PHI_ARG_DEF_FROM_EDGE (phi, exit);
9161debfc3dSmrg add_phi_arg (phi, arg, new_edge, UNKNOWN_LOCATION);
9171debfc3dSmrg }
9181debfc3dSmrg else
9191debfc3dSmrg {
9201debfc3dSmrg /* Use exit edge argument. */
9211debfc3dSmrg arg = PHI_ARG_DEF_FROM_EDGE (phi, exit);
9221debfc3dSmrg add_phi_arg (phi, arg, new_edge, UNKNOWN_LOCATION);
9231debfc3dSmrg }
9241debfc3dSmrg }
9251debfc3dSmrg
9261debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
9271debfc3dSmrg fprintf (dump_file, "\n guard hoisted.\n");
9281debfc3dSmrg
9291debfc3dSmrg free (body);
9301debfc3dSmrg }
9311debfc3dSmrg
9321debfc3dSmrg /* Return true if phi argument for exit edge can be used
9331debfc3dSmrg for edge around loop. */
9341debfc3dSmrg
9351debfc3dSmrg static bool
check_exit_phi(class loop * loop)936*8feb0f0bSmrg check_exit_phi (class loop *loop)
9371debfc3dSmrg {
9381debfc3dSmrg edge exit = single_exit (loop);
9391debfc3dSmrg basic_block pre_header = loop_preheader_edge (loop)->src;
9401debfc3dSmrg
9411debfc3dSmrg for (gphi_iterator gsi = gsi_start_phis (exit->dest);
9421debfc3dSmrg !gsi_end_p (gsi); gsi_next (&gsi))
9431debfc3dSmrg {
9441debfc3dSmrg gphi *phi = gsi.phi ();
9451debfc3dSmrg tree arg;
9461debfc3dSmrg gimple *def;
9471debfc3dSmrg basic_block def_bb;
9481debfc3dSmrg if (virtual_operand_p (gimple_phi_result (phi)))
9491debfc3dSmrg continue;
9501debfc3dSmrg arg = PHI_ARG_DEF_FROM_EDGE (phi, exit);
9511debfc3dSmrg if (TREE_CODE (arg) != SSA_NAME)
9521debfc3dSmrg continue;
9531debfc3dSmrg def = SSA_NAME_DEF_STMT (arg);
9541debfc3dSmrg if (!def)
9551debfc3dSmrg continue;
9561debfc3dSmrg def_bb = gimple_bb (def);
9571debfc3dSmrg if (!def_bb)
9581debfc3dSmrg continue;
9591debfc3dSmrg if (!dominated_by_p (CDI_DOMINATORS, pre_header, def_bb))
9601debfc3dSmrg /* Definition inside loop! */
9611debfc3dSmrg return false;
9621debfc3dSmrg /* Check loop closed phi invariant. */
9631debfc3dSmrg if (!flow_bb_inside_loop_p (def_bb->loop_father, pre_header))
9641debfc3dSmrg return false;
9651debfc3dSmrg }
9661debfc3dSmrg return true;
9671debfc3dSmrg }
9681debfc3dSmrg
9691debfc3dSmrg /* Loop unswitching pass. */
9701debfc3dSmrg
9711debfc3dSmrg namespace {
9721debfc3dSmrg
9731debfc3dSmrg const pass_data pass_data_tree_unswitch =
9741debfc3dSmrg {
9751debfc3dSmrg GIMPLE_PASS, /* type */
9761debfc3dSmrg "unswitch", /* name */
9771debfc3dSmrg OPTGROUP_LOOP, /* optinfo_flags */
9781debfc3dSmrg TV_TREE_LOOP_UNSWITCH, /* tv_id */
9791debfc3dSmrg PROP_cfg, /* properties_required */
9801debfc3dSmrg 0, /* properties_provided */
9811debfc3dSmrg 0, /* properties_destroyed */
9821debfc3dSmrg 0, /* todo_flags_start */
9831debfc3dSmrg 0, /* todo_flags_finish */
9841debfc3dSmrg };
9851debfc3dSmrg
9861debfc3dSmrg class pass_tree_unswitch : public gimple_opt_pass
9871debfc3dSmrg {
9881debfc3dSmrg public:
pass_tree_unswitch(gcc::context * ctxt)9891debfc3dSmrg pass_tree_unswitch (gcc::context *ctxt)
9901debfc3dSmrg : gimple_opt_pass (pass_data_tree_unswitch, ctxt)
9911debfc3dSmrg {}
9921debfc3dSmrg
9931debfc3dSmrg /* opt_pass methods: */
gate(function *)9941debfc3dSmrg virtual bool gate (function *) { return flag_unswitch_loops != 0; }
9951debfc3dSmrg virtual unsigned int execute (function *);
9961debfc3dSmrg
9971debfc3dSmrg }; // class pass_tree_unswitch
9981debfc3dSmrg
9991debfc3dSmrg unsigned int
execute(function * fun)10001debfc3dSmrg pass_tree_unswitch::execute (function *fun)
10011debfc3dSmrg {
10021debfc3dSmrg if (number_of_loops (fun) <= 1)
10031debfc3dSmrg return 0;
10041debfc3dSmrg
10051debfc3dSmrg return tree_ssa_unswitch_loops ();
10061debfc3dSmrg }
10071debfc3dSmrg
10081debfc3dSmrg } // anon namespace
10091debfc3dSmrg
10101debfc3dSmrg gimple_opt_pass *
make_pass_tree_unswitch(gcc::context * ctxt)10111debfc3dSmrg make_pass_tree_unswitch (gcc::context *ctxt)
10121debfc3dSmrg {
10131debfc3dSmrg return new pass_tree_unswitch (ctxt);
10141debfc3dSmrg }
10151debfc3dSmrg
10161debfc3dSmrg
1017