11debfc3dSmrg /* SSA Jump Threading
2*8feb0f0bSmrg Copyright (C) 2005-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
71debfc3dSmrg it under the terms of the GNU General Public License as published by
81debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
91debfc3dSmrg any later version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful,
121debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
131debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
141debfc3dSmrg GNU General Public License 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 "predict.h"
251debfc3dSmrg #include "tree.h"
261debfc3dSmrg #include "gimple.h"
271debfc3dSmrg #include "fold-const.h"
281debfc3dSmrg #include "cfgloop.h"
291debfc3dSmrg #include "gimple-iterator.h"
301debfc3dSmrg #include "tree-cfg.h"
311debfc3dSmrg #include "tree-ssa-threadupdate.h"
321debfc3dSmrg #include "tree-ssa-loop.h"
331debfc3dSmrg #include "cfganal.h"
341debfc3dSmrg #include "tree-pass.h"
351debfc3dSmrg #include "gimple-ssa.h"
361debfc3dSmrg #include "tree-phinodes.h"
371debfc3dSmrg #include "tree-inline.h"
381debfc3dSmrg #include "tree-vectorizer.h"
391debfc3dSmrg
40a2dc1f3fSmrg class thread_jumps
41a2dc1f3fSmrg {
42a2dc1f3fSmrg public:
43a2dc1f3fSmrg void find_jump_threads_backwards (basic_block bb, bool speed_p);
44a2dc1f3fSmrg private:
45a2dc1f3fSmrg edge profitable_jump_thread_path (basic_block bbi, tree name, tree arg,
46a2dc1f3fSmrg bool *creates_irreducible_loop);
47a2dc1f3fSmrg void convert_and_register_current_path (edge taken_edge);
48a2dc1f3fSmrg void register_jump_thread_path_if_profitable (tree name, tree arg,
49a2dc1f3fSmrg basic_block def_bb);
50a2dc1f3fSmrg void handle_assignment (gimple *stmt, tree name, basic_block def_bb);
51a2dc1f3fSmrg void handle_phi (gphi *phi, tree name, basic_block def_bb);
52a2dc1f3fSmrg void fsm_find_control_statement_thread_paths (tree name);
53a2dc1f3fSmrg bool check_subpath_and_update_thread_path (basic_block last_bb,
54a2dc1f3fSmrg basic_block new_bb,
55a2dc1f3fSmrg int *next_path_length);
56a2dc1f3fSmrg
57a2dc1f3fSmrg /* Maximum number of BBs we are allowed to thread. */
58a2dc1f3fSmrg int m_max_threaded_paths;
59a2dc1f3fSmrg /* Hash to keep track of seen bbs. */
60a2dc1f3fSmrg hash_set<basic_block> m_visited_bbs;
61a2dc1f3fSmrg /* Current path we're analyzing. */
62a2dc1f3fSmrg auto_vec<basic_block> m_path;
63a2dc1f3fSmrg /* Tracks if we have recursed through a loop PHI node. */
64a2dc1f3fSmrg bool m_seen_loop_phi;
65a2dc1f3fSmrg /* Indicate that we could increase code size to improve the
66a2dc1f3fSmrg code path. */
67a2dc1f3fSmrg bool m_speed_p;
68a2dc1f3fSmrg };
691debfc3dSmrg
701debfc3dSmrg /* Simple helper to get the last statement from BB, which is assumed
711debfc3dSmrg to be a control statement. Return NULL if the last statement is
721debfc3dSmrg not a control statement. */
731debfc3dSmrg
741debfc3dSmrg static gimple *
get_gimple_control_stmt(basic_block bb)751debfc3dSmrg get_gimple_control_stmt (basic_block bb)
761debfc3dSmrg {
771debfc3dSmrg gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
781debfc3dSmrg
791debfc3dSmrg if (gsi_end_p (gsi))
801debfc3dSmrg return NULL;
811debfc3dSmrg
821debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
831debfc3dSmrg enum gimple_code code = gimple_code (stmt);
841debfc3dSmrg if (code == GIMPLE_COND || code == GIMPLE_SWITCH || code == GIMPLE_GOTO)
851debfc3dSmrg return stmt;
861debfc3dSmrg return NULL;
871debfc3dSmrg }
881debfc3dSmrg
89a2dc1f3fSmrg /* Return true if the CFG contains at least one path from START_BB to
90a2dc1f3fSmrg END_BB. When a path is found, record in PATH the blocks from
91a2dc1f3fSmrg END_BB to START_BB. LOCAL_VISITED_BBS is used to make sure we
92a2dc1f3fSmrg don't fall into an infinite loop. Bound the recursion to basic
93a2dc1f3fSmrg blocks belonging to LOOP. */
941debfc3dSmrg
951debfc3dSmrg static bool
fsm_find_thread_path(basic_block start_bb,basic_block end_bb,vec<basic_block> & path,hash_set<basic_block> & local_visited_bbs,loop_p loop)961debfc3dSmrg fsm_find_thread_path (basic_block start_bb, basic_block end_bb,
97a2dc1f3fSmrg vec<basic_block> &path,
98a2dc1f3fSmrg hash_set<basic_block> &local_visited_bbs,
99a2dc1f3fSmrg loop_p loop)
1001debfc3dSmrg {
1011debfc3dSmrg if (loop != start_bb->loop_father)
1021debfc3dSmrg return false;
1031debfc3dSmrg
1041debfc3dSmrg if (start_bb == end_bb)
1051debfc3dSmrg {
106a2dc1f3fSmrg path.safe_push (start_bb);
1071debfc3dSmrg return true;
1081debfc3dSmrg }
1091debfc3dSmrg
110a2dc1f3fSmrg if (!local_visited_bbs.add (start_bb))
1111debfc3dSmrg {
1121debfc3dSmrg edge e;
1131debfc3dSmrg edge_iterator ei;
1141debfc3dSmrg FOR_EACH_EDGE (e, ei, start_bb->succs)
115a2dc1f3fSmrg if (fsm_find_thread_path (e->dest, end_bb, path, local_visited_bbs,
116a2dc1f3fSmrg loop))
1171debfc3dSmrg {
118a2dc1f3fSmrg path.safe_push (start_bb);
1191debfc3dSmrg return true;
1201debfc3dSmrg }
1211debfc3dSmrg }
1221debfc3dSmrg
1231debfc3dSmrg return false;
1241debfc3dSmrg }
1251debfc3dSmrg
1261debfc3dSmrg /* Examine jump threading path PATH to which we want to add BBI.
1271debfc3dSmrg
1281debfc3dSmrg If the resulting path is profitable to thread, then return the
1291debfc3dSmrg final taken edge from the path, NULL otherwise.
1301debfc3dSmrg
1311debfc3dSmrg NAME is the SSA_NAME of the variable we found to have a constant
132a2dc1f3fSmrg value on PATH. ARG is the constant value of NAME on that path.
1331debfc3dSmrg
134a2dc1f3fSmrg BBI will be appended to PATH when we have a profitable jump
135a2dc1f3fSmrg threading path. Callers are responsible for removing BBI from PATH
136a2dc1f3fSmrg in that case. */
1371debfc3dSmrg
138a2dc1f3fSmrg edge
profitable_jump_thread_path(basic_block bbi,tree name,tree arg,bool * creates_irreducible_loop)139a2dc1f3fSmrg thread_jumps::profitable_jump_thread_path (basic_block bbi, tree name,
140a2dc1f3fSmrg tree arg,
1411debfc3dSmrg bool *creates_irreducible_loop)
1421debfc3dSmrg {
1431debfc3dSmrg /* Note BBI is not in the path yet, hence the +1 in the test below
1441debfc3dSmrg to make sure BBI is accounted for in the path length test. */
1451debfc3dSmrg
1461debfc3dSmrg /* We can get a length of 0 here when the statement that
1471debfc3dSmrg makes a conditional generate a compile-time constant
1481debfc3dSmrg result is in the same block as the conditional.
1491debfc3dSmrg
1501debfc3dSmrg That's not really a jump threading opportunity, but instead is
1511debfc3dSmrg simple cprop & simplification. We could handle it here if we
1521debfc3dSmrg wanted by wiring up all the incoming edges. If we run this
1531debfc3dSmrg early in IPA, that might be worth doing. For now we just
1541debfc3dSmrg reject that case. */
155a2dc1f3fSmrg if (m_path.is_empty ())
1561debfc3dSmrg return NULL;
1571debfc3dSmrg
158a2dc1f3fSmrg if (m_path.length () + 1
159*8feb0f0bSmrg > (unsigned) param_max_fsm_thread_length)
1601debfc3dSmrg {
1611debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
1621debfc3dSmrg fprintf (dump_file, "FSM jump-thread path not considered: "
1631debfc3dSmrg "the number of basic blocks on the path "
1641debfc3dSmrg "exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n");
1651debfc3dSmrg return NULL;
1661debfc3dSmrg }
1671debfc3dSmrg
168a2dc1f3fSmrg if (m_max_threaded_paths <= 0)
1691debfc3dSmrg {
1701debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
1711debfc3dSmrg fprintf (dump_file, "FSM jump-thread path not considered: "
1721debfc3dSmrg "the number of previously recorded FSM paths to "
1731debfc3dSmrg "thread exceeds PARAM_MAX_FSM_THREAD_PATHS.\n");
1741debfc3dSmrg return NULL;
1751debfc3dSmrg }
1761debfc3dSmrg
1771debfc3dSmrg /* Add BBI to the path.
1781debfc3dSmrg From this point onward, if we decide we the path is not profitable
1791debfc3dSmrg to thread, we must remove BBI from the path. */
180a2dc1f3fSmrg m_path.safe_push (bbi);
1811debfc3dSmrg
1821debfc3dSmrg int n_insns = 0;
1831debfc3dSmrg gimple_stmt_iterator gsi;
184a2dc1f3fSmrg loop_p loop = m_path[0]->loop_father;
1851debfc3dSmrg bool path_crosses_loops = false;
1861debfc3dSmrg bool threaded_through_latch = false;
1871debfc3dSmrg bool multiway_branch_in_path = false;
1881debfc3dSmrg bool threaded_multiway_branch = false;
1891debfc3dSmrg bool contains_hot_bb = false;
1901debfc3dSmrg
1911debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
1921debfc3dSmrg fprintf (dump_file, "Checking profitability of path (backwards): ");
1931debfc3dSmrg
1941debfc3dSmrg /* Count the number of instructions on the path: as these instructions
1951debfc3dSmrg will have to be duplicated, we will not record the path if there
1961debfc3dSmrg are too many instructions on the path. Also check that all the
1971debfc3dSmrg blocks in the path belong to a single loop. */
198a2dc1f3fSmrg for (unsigned j = 0; j < m_path.length (); j++)
1991debfc3dSmrg {
200a2dc1f3fSmrg basic_block bb = m_path[j];
2011debfc3dSmrg
2021debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
2031debfc3dSmrg fprintf (dump_file, " bb:%i", bb->index);
2041debfc3dSmrg /* Remember, blocks in the path are stored in opposite order
2051debfc3dSmrg in the PATH array. The last entry in the array represents
2061debfc3dSmrg the block with an outgoing edge that we will redirect to the
2071debfc3dSmrg jump threading path. Thus we don't care about that block's
2081debfc3dSmrg loop father, nor how many statements are in that block because
2091debfc3dSmrg it will not be copied or whether or not it ends in a multiway
2101debfc3dSmrg branch. */
211a2dc1f3fSmrg if (j < m_path.length () - 1)
2121debfc3dSmrg {
2131debfc3dSmrg int orig_n_insns = n_insns;
2141debfc3dSmrg if (bb->loop_father != loop)
2151debfc3dSmrg {
2161debfc3dSmrg path_crosses_loops = true;
2171debfc3dSmrg break;
2181debfc3dSmrg }
2191debfc3dSmrg
2201debfc3dSmrg /* PHIs in the path will create degenerate PHIS in the
2211debfc3dSmrg copied path which will then get propagated away, so
2221debfc3dSmrg looking at just the duplicate path the PHIs would
2231debfc3dSmrg seem unimportant.
2241debfc3dSmrg
2251debfc3dSmrg But those PHIs, because they're assignments to objects
2261debfc3dSmrg typically with lives that exist outside the thread path,
2271debfc3dSmrg will tend to generate PHIs (or at least new PHI arguments)
2281debfc3dSmrg at points where we leave the thread path and rejoin
2291debfc3dSmrg the original blocks. So we do want to account for them.
2301debfc3dSmrg
2311debfc3dSmrg We ignore virtual PHIs. We also ignore cases where BB
2321debfc3dSmrg has a single incoming edge. That's the most common
2331debfc3dSmrg degenerate PHI we'll see here. Finally we ignore PHIs
2341debfc3dSmrg that are associated with the value we're tracking as
2351debfc3dSmrg that object likely dies. */
2361debfc3dSmrg if (EDGE_COUNT (bb->succs) > 1 && EDGE_COUNT (bb->preds) > 1)
2371debfc3dSmrg {
2381debfc3dSmrg for (gphi_iterator gsip = gsi_start_phis (bb);
2391debfc3dSmrg !gsi_end_p (gsip);
2401debfc3dSmrg gsi_next (&gsip))
2411debfc3dSmrg {
2421debfc3dSmrg gphi *phi = gsip.phi ();
2431debfc3dSmrg tree dst = gimple_phi_result (phi);
2441debfc3dSmrg
2451debfc3dSmrg /* Note that if both NAME and DST are anonymous
2461debfc3dSmrg SSA_NAMEs, then we do not have enough information
2471debfc3dSmrg to consider them associated. */
2481debfc3dSmrg if (dst != name
2491debfc3dSmrg && (SSA_NAME_VAR (dst) != SSA_NAME_VAR (name)
2501debfc3dSmrg || !SSA_NAME_VAR (dst))
2511debfc3dSmrg && !virtual_operand_p (dst))
2521debfc3dSmrg ++n_insns;
2531debfc3dSmrg }
2541debfc3dSmrg }
2551debfc3dSmrg
256a2dc1f3fSmrg if (!contains_hot_bb && m_speed_p)
2571debfc3dSmrg contains_hot_bb |= optimize_bb_for_speed_p (bb);
2581debfc3dSmrg for (gsi = gsi_after_labels (bb);
2591debfc3dSmrg !gsi_end_p (gsi);
2601debfc3dSmrg gsi_next_nondebug (&gsi))
2611debfc3dSmrg {
2621debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
263*8feb0f0bSmrg if (gimple_call_internal_p (stmt, IFN_UNIQUE))
264*8feb0f0bSmrg {
265*8feb0f0bSmrg m_path.pop ();
266*8feb0f0bSmrg return NULL;
267*8feb0f0bSmrg }
2681debfc3dSmrg /* Do not count empty statements and labels. */
2691debfc3dSmrg if (gimple_code (stmt) != GIMPLE_NOP
2701debfc3dSmrg && !(gimple_code (stmt) == GIMPLE_ASSIGN
2711debfc3dSmrg && gimple_assign_rhs_code (stmt) == ASSERT_EXPR)
2721debfc3dSmrg && !is_gimple_debug (stmt))
2731debfc3dSmrg n_insns += estimate_num_insns (stmt, &eni_size_weights);
2741debfc3dSmrg }
2751debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
2761debfc3dSmrg fprintf (dump_file, " (%i insns)", n_insns-orig_n_insns);
2771debfc3dSmrg
2781debfc3dSmrg /* We do not look at the block with the threaded branch
2791debfc3dSmrg in this loop. So if any block with a last statement that
2801debfc3dSmrg is a GIMPLE_SWITCH or GIMPLE_GOTO is seen, then we have a
2811debfc3dSmrg multiway branch on our path.
2821debfc3dSmrg
2831debfc3dSmrg The block in PATH[0] is special, it's the block were we're
2841debfc3dSmrg going to be able to eliminate its branch. */
2851debfc3dSmrg gimple *last = last_stmt (bb);
2861debfc3dSmrg if (last && (gimple_code (last) == GIMPLE_SWITCH
2871debfc3dSmrg || gimple_code (last) == GIMPLE_GOTO))
2881debfc3dSmrg {
2891debfc3dSmrg if (j == 0)
2901debfc3dSmrg threaded_multiway_branch = true;
2911debfc3dSmrg else
2921debfc3dSmrg multiway_branch_in_path = true;
2931debfc3dSmrg }
2941debfc3dSmrg }
2951debfc3dSmrg
2961debfc3dSmrg /* Note if we thread through the latch, we will want to include
2971debfc3dSmrg the last entry in the array when determining if we thread
2981debfc3dSmrg through the loop latch. */
2991debfc3dSmrg if (loop->latch == bb)
3001debfc3dSmrg threaded_through_latch = true;
3011debfc3dSmrg }
3021debfc3dSmrg
303a2dc1f3fSmrg gimple *stmt = get_gimple_control_stmt (m_path[0]);
3041debfc3dSmrg gcc_assert (stmt);
3051debfc3dSmrg
3061debfc3dSmrg /* We are going to remove the control statement at the end of the
3071debfc3dSmrg last block in the threading path. So don't count it against our
3081debfc3dSmrg statement count. */
3091debfc3dSmrg
3101debfc3dSmrg int stmt_insns = estimate_num_insns (stmt, &eni_size_weights);
3111debfc3dSmrg n_insns-= stmt_insns;
3121debfc3dSmrg
3131debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
3141debfc3dSmrg fprintf (dump_file, "\n Control statement insns: %i\n"
3151debfc3dSmrg " Overall: %i insns\n",
3161debfc3dSmrg stmt_insns, n_insns);
3171debfc3dSmrg
3181debfc3dSmrg /* We have found a constant value for ARG. For GIMPLE_SWITCH
3191debfc3dSmrg and GIMPLE_GOTO, we use it as-is. However, for a GIMPLE_COND
3201debfc3dSmrg we need to substitute, fold and simplify so we can determine
3211debfc3dSmrg the edge taken out of the last block. */
3221debfc3dSmrg if (gimple_code (stmt) == GIMPLE_COND)
3231debfc3dSmrg {
3241debfc3dSmrg enum tree_code cond_code = gimple_cond_code (stmt);
3251debfc3dSmrg
3261debfc3dSmrg /* We know the underyling format of the condition. */
3271debfc3dSmrg arg = fold_binary (cond_code, boolean_type_node,
3281debfc3dSmrg arg, gimple_cond_rhs (stmt));
3291debfc3dSmrg }
3301debfc3dSmrg
3311debfc3dSmrg /* If this path threaded through the loop latch back into the
3321debfc3dSmrg same loop and the destination does not dominate the loop
3331debfc3dSmrg latch, then this thread would create an irreducible loop.
3341debfc3dSmrg
3351debfc3dSmrg We have to know the outgoing edge to figure this out. */
336a2dc1f3fSmrg edge taken_edge = find_taken_edge (m_path[0], arg);
3371debfc3dSmrg
3381debfc3dSmrg /* There are cases where we may not be able to extract the
3391debfc3dSmrg taken edge. For example, a computed goto to an absolute
3401debfc3dSmrg address. Handle those cases gracefully. */
3411debfc3dSmrg if (taken_edge == NULL)
3421debfc3dSmrg {
343a2dc1f3fSmrg m_path.pop ();
3441debfc3dSmrg return NULL;
3451debfc3dSmrg }
3461debfc3dSmrg
3471debfc3dSmrg *creates_irreducible_loop = false;
3481debfc3dSmrg if (threaded_through_latch
3491debfc3dSmrg && loop == taken_edge->dest->loop_father
3501debfc3dSmrg && (determine_bb_domination_status (loop, taken_edge->dest)
3511debfc3dSmrg == DOMST_NONDOMINATING))
3521debfc3dSmrg *creates_irreducible_loop = true;
3531debfc3dSmrg
3541debfc3dSmrg if (path_crosses_loops)
3551debfc3dSmrg {
3561debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
3571debfc3dSmrg fprintf (dump_file, "FSM jump-thread path not considered: "
3581debfc3dSmrg "the path crosses loops.\n");
359a2dc1f3fSmrg m_path.pop ();
3601debfc3dSmrg return NULL;
3611debfc3dSmrg }
3621debfc3dSmrg
3631debfc3dSmrg /* Threading is profitable if the path duplicated is hot but also
3641debfc3dSmrg in a case we separate cold path from hot path and permit optimization
3651debfc3dSmrg of the hot path later. Be on the agressive side here. In some testcases,
3661debfc3dSmrg as in PR 78407 this leads to noticeable improvements. */
367a2dc1f3fSmrg if (m_speed_p && (optimize_edge_for_speed_p (taken_edge) || contains_hot_bb))
3681debfc3dSmrg {
369*8feb0f0bSmrg if (n_insns >= param_max_fsm_thread_path_insns)
3701debfc3dSmrg {
3711debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
3721debfc3dSmrg fprintf (dump_file, "FSM jump-thread path not considered: "
3731debfc3dSmrg "the number of instructions on the path "
3741debfc3dSmrg "exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n");
375a2dc1f3fSmrg m_path.pop ();
3761debfc3dSmrg return NULL;
3771debfc3dSmrg }
3781debfc3dSmrg }
3791debfc3dSmrg else if (n_insns > 1)
3801debfc3dSmrg {
3811debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
3821debfc3dSmrg fprintf (dump_file, "FSM jump-thread path not considered: "
3831debfc3dSmrg "duplication of %i insns is needed and optimizing for size.\n",
3841debfc3dSmrg n_insns);
385a2dc1f3fSmrg m_path.pop ();
3861debfc3dSmrg return NULL;
3871debfc3dSmrg }
3881debfc3dSmrg
3891debfc3dSmrg /* We avoid creating irreducible inner loops unless we thread through
3901debfc3dSmrg a multiway branch, in which case we have deemed it worth losing
3911debfc3dSmrg other loop optimizations later.
3921debfc3dSmrg
3931debfc3dSmrg We also consider it worth creating an irreducible inner loop if
3941debfc3dSmrg the number of copied statement is low relative to the length of
3951debfc3dSmrg the path -- in that case there's little the traditional loop
3961debfc3dSmrg optimizer would have done anyway, so an irreducible loop is not
3971debfc3dSmrg so bad. */
3981debfc3dSmrg if (!threaded_multiway_branch && *creates_irreducible_loop
399*8feb0f0bSmrg && (n_insns * (unsigned) param_fsm_scale_path_stmts
400a2dc1f3fSmrg > (m_path.length () *
401*8feb0f0bSmrg (unsigned) param_fsm_scale_path_blocks)))
4021debfc3dSmrg
4031debfc3dSmrg {
4041debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
4051debfc3dSmrg fprintf (dump_file,
4061debfc3dSmrg "FSM would create irreducible loop without threading "
4071debfc3dSmrg "multiway branch.\n");
408a2dc1f3fSmrg m_path.pop ();
4091debfc3dSmrg return NULL;
4101debfc3dSmrg }
4111debfc3dSmrg
4121debfc3dSmrg
4131debfc3dSmrg /* If this path does not thread through the loop latch, then we are
4141debfc3dSmrg using the FSM threader to find old style jump threads. This
4151debfc3dSmrg is good, except the FSM threader does not re-use an existing
4161debfc3dSmrg threading path to reduce code duplication.
4171debfc3dSmrg
4181debfc3dSmrg So for that case, drastically reduce the number of statements
4191debfc3dSmrg we are allowed to copy. */
4201debfc3dSmrg if (!(threaded_through_latch && threaded_multiway_branch)
421*8feb0f0bSmrg && (n_insns * param_fsm_scale_path_stmts
422*8feb0f0bSmrg >= param_max_jump_thread_duplication_stmts))
4231debfc3dSmrg {
4241debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
4251debfc3dSmrg fprintf (dump_file,
4261debfc3dSmrg "FSM did not thread around loop and would copy too "
4271debfc3dSmrg "many statements.\n");
428a2dc1f3fSmrg m_path.pop ();
4291debfc3dSmrg return NULL;
4301debfc3dSmrg }
4311debfc3dSmrg
4321debfc3dSmrg /* When there is a multi-way branch on the path, then threading can
4331debfc3dSmrg explode the CFG due to duplicating the edges for that multi-way
4341debfc3dSmrg branch. So like above, only allow a multi-way branch on the path
4351debfc3dSmrg if we actually thread a multi-way branch. */
4361debfc3dSmrg if (!threaded_multiway_branch && multiway_branch_in_path)
4371debfc3dSmrg {
4381debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
4391debfc3dSmrg fprintf (dump_file,
4401debfc3dSmrg "FSM Thread through multiway branch without threading "
4411debfc3dSmrg "a multiway branch.\n");
442a2dc1f3fSmrg m_path.pop ();
4431debfc3dSmrg return NULL;
4441debfc3dSmrg }
4451debfc3dSmrg return taken_edge;
4461debfc3dSmrg }
4471debfc3dSmrg
448a2dc1f3fSmrg /* The current path PATH is a vector of blocks forming a jump threading
449a2dc1f3fSmrg path in reverse order. TAKEN_EDGE is the edge taken from path[0].
4501debfc3dSmrg
451a2dc1f3fSmrg Convert the current path into the form used by register_jump_thread and
452a2dc1f3fSmrg register it. */
4531debfc3dSmrg
454a2dc1f3fSmrg void
convert_and_register_current_path(edge taken_edge)455a2dc1f3fSmrg thread_jumps::convert_and_register_current_path (edge taken_edge)
4561debfc3dSmrg {
4571debfc3dSmrg vec<jump_thread_edge *> *jump_thread_path = new vec<jump_thread_edge *> ();
4581debfc3dSmrg
4591debfc3dSmrg /* Record the edges between the blocks in PATH. */
460a2dc1f3fSmrg for (unsigned int j = 0; j + 1 < m_path.length (); j++)
4611debfc3dSmrg {
462a2dc1f3fSmrg basic_block bb1 = m_path[m_path.length () - j - 1];
463a2dc1f3fSmrg basic_block bb2 = m_path[m_path.length () - j - 2];
4641debfc3dSmrg
4651debfc3dSmrg edge e = find_edge (bb1, bb2);
4661debfc3dSmrg gcc_assert (e);
4671debfc3dSmrg jump_thread_edge *x = new jump_thread_edge (e, EDGE_FSM_THREAD);
4681debfc3dSmrg jump_thread_path->safe_push (x);
4691debfc3dSmrg }
4701debfc3dSmrg
4711debfc3dSmrg /* Add the edge taken when the control variable has value ARG. */
4721debfc3dSmrg jump_thread_edge *x
4731debfc3dSmrg = new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK);
4741debfc3dSmrg jump_thread_path->safe_push (x);
4751debfc3dSmrg
4761debfc3dSmrg register_jump_thread (jump_thread_path);
477a2dc1f3fSmrg --m_max_threaded_paths;
4781debfc3dSmrg }
4791debfc3dSmrg
480a2dc1f3fSmrg /* While following a chain of SSA_NAME definitions, we jumped from a
481a2dc1f3fSmrg definition in LAST_BB to a definition in NEW_BB (walking
482a2dc1f3fSmrg backwards).
4831debfc3dSmrg
484a2dc1f3fSmrg Verify there is a single path between the blocks and none of the
485a2dc1f3fSmrg blocks in the path is already in VISITED_BBS. If so, then update
486a2dc1f3fSmrg VISISTED_BBS, add the new blocks to PATH and return TRUE.
487a2dc1f3fSmrg Otherwise return FALSE.
4881debfc3dSmrg
4891debfc3dSmrg Store the length of the subpath in NEXT_PATH_LENGTH. */
4901debfc3dSmrg
491a2dc1f3fSmrg bool
check_subpath_and_update_thread_path(basic_block last_bb,basic_block new_bb,int * next_path_length)492a2dc1f3fSmrg thread_jumps::check_subpath_and_update_thread_path (basic_block last_bb,
493a2dc1f3fSmrg basic_block new_bb,
4941debfc3dSmrg int *next_path_length)
4951debfc3dSmrg {
4961debfc3dSmrg edge e;
4971debfc3dSmrg int e_count = 0;
4981debfc3dSmrg edge_iterator ei;
499a2dc1f3fSmrg auto_vec<basic_block> next_path;
5001debfc3dSmrg
5011debfc3dSmrg FOR_EACH_EDGE (e, ei, last_bb->preds)
5021debfc3dSmrg {
503a2dc1f3fSmrg hash_set<basic_block> local_visited_bbs;
5041debfc3dSmrg
505a2dc1f3fSmrg if (fsm_find_thread_path (new_bb, e->src, next_path,
506a2dc1f3fSmrg local_visited_bbs, e->src->loop_father))
5071debfc3dSmrg ++e_count;
5081debfc3dSmrg
5091debfc3dSmrg /* If there is more than one path, stop. */
5101debfc3dSmrg if (e_count > 1)
5111debfc3dSmrg return false;
5121debfc3dSmrg }
5131debfc3dSmrg
5141debfc3dSmrg /* Stop if we have not found a path: this could occur when the recursion
5151debfc3dSmrg is stopped by one of the bounds. */
5161debfc3dSmrg if (e_count == 0)
5171debfc3dSmrg return false;
5181debfc3dSmrg
5191debfc3dSmrg /* Make sure we haven't already visited any of the nodes in
5201debfc3dSmrg NEXT_PATH. Don't add them here to avoid pollution. */
521a2dc1f3fSmrg for (unsigned int i = 0; i + 1 < next_path.length (); i++)
5221debfc3dSmrg {
523a2dc1f3fSmrg if (m_visited_bbs.contains (next_path[i]))
5241debfc3dSmrg return false;
5251debfc3dSmrg }
5261debfc3dSmrg
5271debfc3dSmrg /* Now add the nodes to VISISTED_BBS. */
528a2dc1f3fSmrg for (unsigned int i = 0; i + 1 < next_path.length (); i++)
529a2dc1f3fSmrg m_visited_bbs.add (next_path[i]);
5301debfc3dSmrg
5311debfc3dSmrg /* Append all the nodes from NEXT_PATH to PATH. */
532a2dc1f3fSmrg m_path.safe_splice (next_path);
533a2dc1f3fSmrg *next_path_length = next_path.length ();
5341debfc3dSmrg
5351debfc3dSmrg return true;
5361debfc3dSmrg }
5371debfc3dSmrg
538a2dc1f3fSmrg /* If this is a profitable jump thread path, register it.
5391debfc3dSmrg
540a2dc1f3fSmrg NAME is an SSA NAME with a possible constant value of ARG on PATH.
541a2dc1f3fSmrg
542a2dc1f3fSmrg DEF_BB is the basic block that ultimately defines the constant. */
543a2dc1f3fSmrg
544a2dc1f3fSmrg void
register_jump_thread_path_if_profitable(tree name,tree arg,basic_block def_bb)545a2dc1f3fSmrg thread_jumps::register_jump_thread_path_if_profitable (tree name, tree arg,
546a2dc1f3fSmrg basic_block def_bb)
547a2dc1f3fSmrg {
548a2dc1f3fSmrg if (TREE_CODE_CLASS (TREE_CODE (arg)) != tcc_constant)
549a2dc1f3fSmrg return;
550a2dc1f3fSmrg
551a2dc1f3fSmrg bool irreducible = false;
552a2dc1f3fSmrg edge taken_edge = profitable_jump_thread_path (def_bb, name, arg,
553a2dc1f3fSmrg &irreducible);
554a2dc1f3fSmrg if (taken_edge)
555a2dc1f3fSmrg {
556a2dc1f3fSmrg convert_and_register_current_path (taken_edge);
557a2dc1f3fSmrg m_path.pop ();
558a2dc1f3fSmrg
559a2dc1f3fSmrg if (irreducible)
560a2dc1f3fSmrg vect_free_loop_info_assumptions (m_path[0]->loop_father);
561a2dc1f3fSmrg }
562a2dc1f3fSmrg }
563a2dc1f3fSmrg
564a2dc1f3fSmrg /* Given PHI which defines NAME in block DEF_BB, recurse through the
5651debfc3dSmrg PHI's arguments searching for paths where NAME will ultimately have
5661debfc3dSmrg a constant value.
5671debfc3dSmrg
5681debfc3dSmrg PATH contains the series of blocks to traverse that will result in
569a2dc1f3fSmrg NAME having a constant value. */
5701debfc3dSmrg
571a2dc1f3fSmrg void
handle_phi(gphi * phi,tree name,basic_block def_bb)572a2dc1f3fSmrg thread_jumps::handle_phi (gphi *phi, tree name, basic_block def_bb)
5731debfc3dSmrg {
5741debfc3dSmrg /* Iterate over the arguments of PHI. */
5751debfc3dSmrg for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++)
5761debfc3dSmrg {
5771debfc3dSmrg tree arg = gimple_phi_arg_def (phi, i);
5781debfc3dSmrg basic_block bbi = gimple_phi_arg_edge (phi, i)->src;
5791debfc3dSmrg
5801debfc3dSmrg /* Skip edges pointing outside the current loop. */
581a2dc1f3fSmrg if (!arg || def_bb->loop_father != bbi->loop_father)
5821debfc3dSmrg continue;
5831debfc3dSmrg
5841debfc3dSmrg if (TREE_CODE (arg) == SSA_NAME)
5851debfc3dSmrg {
586a2dc1f3fSmrg m_path.safe_push (bbi);
5871debfc3dSmrg /* Recursively follow SSA_NAMEs looking for a constant
5881debfc3dSmrg definition. */
589a2dc1f3fSmrg fsm_find_control_statement_thread_paths (arg);
5901debfc3dSmrg
591a2dc1f3fSmrg m_path.pop ();
5921debfc3dSmrg continue;
5931debfc3dSmrg }
5941debfc3dSmrg
595a2dc1f3fSmrg register_jump_thread_path_if_profitable (name, arg, bbi);
5961debfc3dSmrg }
5971debfc3dSmrg }
5981debfc3dSmrg
5991debfc3dSmrg /* Return TRUE if STMT is a gimple assignment we want to either directly
6001debfc3dSmrg handle or recurse through. Return FALSE otherwise.
6011debfc3dSmrg
6021debfc3dSmrg Note that adding more cases here requires adding cases to handle_assignment
6031debfc3dSmrg below. */
6041debfc3dSmrg
6051debfc3dSmrg static bool
handle_assignment_p(gimple * stmt)6061debfc3dSmrg handle_assignment_p (gimple *stmt)
6071debfc3dSmrg {
6081debfc3dSmrg if (is_gimple_assign (stmt))
6091debfc3dSmrg {
6101debfc3dSmrg enum tree_code def_code = gimple_assign_rhs_code (stmt);
6111debfc3dSmrg
6121debfc3dSmrg /* If the RHS is an SSA_NAME, then we will recurse through it.
6131debfc3dSmrg Go ahead and filter out cases where the SSA_NAME is a default
6141debfc3dSmrg definition. There's little to be gained by trying to handle that. */
6151debfc3dSmrg if (def_code == SSA_NAME
6161debfc3dSmrg && !SSA_NAME_IS_DEFAULT_DEF (gimple_assign_rhs1 (stmt)))
6171debfc3dSmrg return true;
6181debfc3dSmrg
6191debfc3dSmrg /* If the RHS is a constant, then it's a terminal that we'll want
6201debfc3dSmrg to handle as well. */
6211debfc3dSmrg if (TREE_CODE_CLASS (def_code) == tcc_constant)
6221debfc3dSmrg return true;
6231debfc3dSmrg }
6241debfc3dSmrg
6251debfc3dSmrg /* Anything not explicitly allowed is not handled. */
6261debfc3dSmrg return false;
6271debfc3dSmrg }
6281debfc3dSmrg
629a2dc1f3fSmrg /* Given STMT which defines NAME in block DEF_BB, recurse through the
6301debfc3dSmrg PHI's arguments searching for paths where NAME will ultimately have
6311debfc3dSmrg a constant value.
6321debfc3dSmrg
6331debfc3dSmrg PATH contains the series of blocks to traverse that will result in
634a2dc1f3fSmrg NAME having a constant value. */
6351debfc3dSmrg
636a2dc1f3fSmrg void
handle_assignment(gimple * stmt,tree name,basic_block def_bb)637a2dc1f3fSmrg thread_jumps::handle_assignment (gimple *stmt, tree name, basic_block def_bb)
6381debfc3dSmrg {
6391debfc3dSmrg tree arg = gimple_assign_rhs1 (stmt);
6401debfc3dSmrg
6411debfc3dSmrg if (TREE_CODE (arg) == SSA_NAME)
642a2dc1f3fSmrg fsm_find_control_statement_thread_paths (arg);
6431debfc3dSmrg
6441debfc3dSmrg else
6451debfc3dSmrg {
646a2dc1f3fSmrg /* register_jump_thread_path_if_profitable will push the current
6471debfc3dSmrg block onto the path. But the path will always have the current
6481debfc3dSmrg block at this point. So we can just pop it. */
649a2dc1f3fSmrg m_path.pop ();
6501debfc3dSmrg
651a2dc1f3fSmrg register_jump_thread_path_if_profitable (name, arg, def_bb);
6521debfc3dSmrg
6531debfc3dSmrg /* And put the current block back onto the path so that the
6541debfc3dSmrg state of the stack is unchanged when we leave. */
655a2dc1f3fSmrg m_path.safe_push (def_bb);
6561debfc3dSmrg }
6571debfc3dSmrg }
6581debfc3dSmrg
659a2dc1f3fSmrg /* We trace the value of the SSA_NAME NAME back through any phi nodes
660a2dc1f3fSmrg looking for places where it gets a constant value and save the
661a2dc1f3fSmrg path. */
6621debfc3dSmrg
663a2dc1f3fSmrg void
fsm_find_control_statement_thread_paths(tree name)664a2dc1f3fSmrg thread_jumps::fsm_find_control_statement_thread_paths (tree name)
6651debfc3dSmrg {
6661debfc3dSmrg /* If NAME appears in an abnormal PHI, then don't try to trace its
6671debfc3dSmrg value back through PHI nodes. */
6681debfc3dSmrg if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
6691debfc3dSmrg return;
6701debfc3dSmrg
6711debfc3dSmrg gimple *def_stmt = SSA_NAME_DEF_STMT (name);
672a2dc1f3fSmrg basic_block def_bb = gimple_bb (def_stmt);
6731debfc3dSmrg
674a2dc1f3fSmrg if (def_bb == NULL)
6751debfc3dSmrg return;
6761debfc3dSmrg
6771debfc3dSmrg /* We allow the SSA chain to contains PHIs and simple copies and constant
6781debfc3dSmrg initializations. */
6791debfc3dSmrg if (gimple_code (def_stmt) != GIMPLE_PHI
6801debfc3dSmrg && gimple_code (def_stmt) != GIMPLE_ASSIGN)
6811debfc3dSmrg return;
6821debfc3dSmrg
6831debfc3dSmrg if (gimple_code (def_stmt) == GIMPLE_PHI
6841debfc3dSmrg && (gimple_phi_num_args (def_stmt)
685*8feb0f0bSmrg >= (unsigned) param_fsm_maximum_phi_arguments))
6861debfc3dSmrg return;
6871debfc3dSmrg
6881debfc3dSmrg if (is_gimple_assign (def_stmt)
6891debfc3dSmrg && ! handle_assignment_p (def_stmt))
6901debfc3dSmrg return;
6911debfc3dSmrg
6921debfc3dSmrg /* Avoid infinite recursion. */
693a2dc1f3fSmrg if (m_visited_bbs.add (def_bb))
6941debfc3dSmrg return;
6951debfc3dSmrg
6961debfc3dSmrg int next_path_length = 0;
697a2dc1f3fSmrg basic_block last_bb_in_path = m_path.last ();
6981debfc3dSmrg
6991debfc3dSmrg if (loop_containing_stmt (def_stmt)->header == gimple_bb (def_stmt))
7001debfc3dSmrg {
7011debfc3dSmrg /* Do not walk through more than one loop PHI node. */
702a2dc1f3fSmrg if (m_seen_loop_phi)
7031debfc3dSmrg return;
704a2dc1f3fSmrg m_seen_loop_phi = true;
7051debfc3dSmrg }
7061debfc3dSmrg
7071debfc3dSmrg /* Following the chain of SSA_NAME definitions, we jumped from a definition in
708a2dc1f3fSmrg LAST_BB_IN_PATH to a definition in DEF_BB. When these basic blocks are
709a2dc1f3fSmrg different, append to PATH the blocks from LAST_BB_IN_PATH to DEF_BB. */
710a2dc1f3fSmrg if (def_bb != last_bb_in_path)
7111debfc3dSmrg {
712a2dc1f3fSmrg /* When DEF_BB == LAST_BB_IN_PATH, then the first block in the path
7131debfc3dSmrg will already be in VISITED_BBS. When they are not equal, then we
7141debfc3dSmrg must ensure that first block is accounted for to ensure we do not
7151debfc3dSmrg create bogus jump threading paths. */
716a2dc1f3fSmrg m_visited_bbs.add (m_path[0]);
717a2dc1f3fSmrg if (!check_subpath_and_update_thread_path (last_bb_in_path, def_bb,
7181debfc3dSmrg &next_path_length))
7191debfc3dSmrg return;
7201debfc3dSmrg }
7211debfc3dSmrg
722a2dc1f3fSmrg gcc_assert (m_path.last () == def_bb);
7231debfc3dSmrg
7241debfc3dSmrg if (gimple_code (def_stmt) == GIMPLE_PHI)
725a2dc1f3fSmrg handle_phi (as_a <gphi *> (def_stmt), name, def_bb);
7261debfc3dSmrg else if (gimple_code (def_stmt) == GIMPLE_ASSIGN)
727a2dc1f3fSmrg handle_assignment (def_stmt, name, def_bb);
7281debfc3dSmrg
7291debfc3dSmrg /* Remove all the nodes that we added from NEXT_PATH. */
7301debfc3dSmrg if (next_path_length)
731a2dc1f3fSmrg m_path.truncate (m_path.length () - next_path_length);
7321debfc3dSmrg }
7331debfc3dSmrg
7341debfc3dSmrg /* Search backwards from BB looking for paths where NAME (an SSA_NAME)
7351debfc3dSmrg is a constant. Record such paths for jump threading.
7361debfc3dSmrg
7371debfc3dSmrg It is assumed that BB ends with a control statement and that by
7381debfc3dSmrg finding a path where NAME is a constant, we can thread the path.
739a2dc1f3fSmrg SPEED_P indicates that we could increase code size to improve the
740a2dc1f3fSmrg code path. */
7411debfc3dSmrg
7421debfc3dSmrg void
find_jump_threads_backwards(basic_block bb,bool speed_p)743a2dc1f3fSmrg thread_jumps::find_jump_threads_backwards (basic_block bb, bool speed_p)
7441debfc3dSmrg {
7451debfc3dSmrg gimple *stmt = get_gimple_control_stmt (bb);
7461debfc3dSmrg if (!stmt)
7471debfc3dSmrg return;
7481debfc3dSmrg
7491debfc3dSmrg enum gimple_code code = gimple_code (stmt);
7501debfc3dSmrg tree name = NULL;
7511debfc3dSmrg if (code == GIMPLE_SWITCH)
7521debfc3dSmrg name = gimple_switch_index (as_a <gswitch *> (stmt));
7531debfc3dSmrg else if (code == GIMPLE_GOTO)
7541debfc3dSmrg name = gimple_goto_dest (stmt);
7551debfc3dSmrg else if (code == GIMPLE_COND)
7561debfc3dSmrg {
7571debfc3dSmrg if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME
7581debfc3dSmrg && TREE_CODE_CLASS (TREE_CODE (gimple_cond_rhs (stmt))) == tcc_constant
7591debfc3dSmrg && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
7601debfc3dSmrg || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
7611debfc3dSmrg name = gimple_cond_lhs (stmt);
7621debfc3dSmrg }
7631debfc3dSmrg
7641debfc3dSmrg if (!name || TREE_CODE (name) != SSA_NAME)
7651debfc3dSmrg return;
7661debfc3dSmrg
767a2dc1f3fSmrg /* Initialize pass local data that's different for each BB. */
768a2dc1f3fSmrg m_path.truncate (0);
769a2dc1f3fSmrg m_path.safe_push (bb);
770a2dc1f3fSmrg m_visited_bbs.empty ();
771a2dc1f3fSmrg m_seen_loop_phi = false;
772a2dc1f3fSmrg m_speed_p = speed_p;
773*8feb0f0bSmrg m_max_threaded_paths = param_max_fsm_thread_paths;
7741debfc3dSmrg
775a2dc1f3fSmrg fsm_find_control_statement_thread_paths (name);
7761debfc3dSmrg }
7771debfc3dSmrg
7781debfc3dSmrg namespace {
7791debfc3dSmrg
7801debfc3dSmrg const pass_data pass_data_thread_jumps =
7811debfc3dSmrg {
7821debfc3dSmrg GIMPLE_PASS,
7831debfc3dSmrg "thread",
7841debfc3dSmrg OPTGROUP_NONE,
7851debfc3dSmrg TV_TREE_SSA_THREAD_JUMPS,
7861debfc3dSmrg ( PROP_cfg | PROP_ssa ),
7871debfc3dSmrg 0,
7881debfc3dSmrg 0,
7891debfc3dSmrg 0,
7901debfc3dSmrg TODO_update_ssa,
7911debfc3dSmrg };
7921debfc3dSmrg
7931debfc3dSmrg class pass_thread_jumps : public gimple_opt_pass
7941debfc3dSmrg {
7951debfc3dSmrg public:
pass_thread_jumps(gcc::context * ctxt)7961debfc3dSmrg pass_thread_jumps (gcc::context *ctxt)
7971debfc3dSmrg : gimple_opt_pass (pass_data_thread_jumps, ctxt)
7981debfc3dSmrg {}
7991debfc3dSmrg
clone(void)8001debfc3dSmrg opt_pass * clone (void) { return new pass_thread_jumps (m_ctxt); }
8011debfc3dSmrg virtual bool gate (function *);
8021debfc3dSmrg virtual unsigned int execute (function *);
8031debfc3dSmrg };
8041debfc3dSmrg
8051debfc3dSmrg bool
gate(function * fun ATTRIBUTE_UNUSED)8061debfc3dSmrg pass_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED)
8071debfc3dSmrg {
8081debfc3dSmrg return flag_expensive_optimizations;
8091debfc3dSmrg }
8101debfc3dSmrg
8111debfc3dSmrg
8121debfc3dSmrg unsigned int
execute(function * fun)8131debfc3dSmrg pass_thread_jumps::execute (function *fun)
8141debfc3dSmrg {
8151debfc3dSmrg loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES);
8161debfc3dSmrg
8171debfc3dSmrg /* Try to thread each block with more than one successor. */
818a2dc1f3fSmrg thread_jumps threader;
8191debfc3dSmrg basic_block bb;
8201debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
8211debfc3dSmrg {
8221debfc3dSmrg if (EDGE_COUNT (bb->succs) > 1)
823a2dc1f3fSmrg threader.find_jump_threads_backwards (bb, true);
8241debfc3dSmrg }
8251debfc3dSmrg bool changed = thread_through_all_blocks (true);
8261debfc3dSmrg
8271debfc3dSmrg loop_optimizer_finalize ();
8281debfc3dSmrg return changed ? TODO_cleanup_cfg : 0;
8291debfc3dSmrg }
8301debfc3dSmrg
8311debfc3dSmrg }
8321debfc3dSmrg
8331debfc3dSmrg gimple_opt_pass *
make_pass_thread_jumps(gcc::context * ctxt)8341debfc3dSmrg make_pass_thread_jumps (gcc::context *ctxt)
8351debfc3dSmrg {
8361debfc3dSmrg return new pass_thread_jumps (ctxt);
8371debfc3dSmrg }
8381debfc3dSmrg
8391debfc3dSmrg namespace {
8401debfc3dSmrg
8411debfc3dSmrg const pass_data pass_data_early_thread_jumps =
8421debfc3dSmrg {
8431debfc3dSmrg GIMPLE_PASS,
8441debfc3dSmrg "ethread",
8451debfc3dSmrg OPTGROUP_NONE,
8461debfc3dSmrg TV_TREE_SSA_THREAD_JUMPS,
8471debfc3dSmrg ( PROP_cfg | PROP_ssa ),
8481debfc3dSmrg 0,
8491debfc3dSmrg 0,
8501debfc3dSmrg 0,
8511debfc3dSmrg ( TODO_cleanup_cfg | TODO_update_ssa ),
8521debfc3dSmrg };
8531debfc3dSmrg
8541debfc3dSmrg class pass_early_thread_jumps : public gimple_opt_pass
8551debfc3dSmrg {
8561debfc3dSmrg public:
pass_early_thread_jumps(gcc::context * ctxt)8571debfc3dSmrg pass_early_thread_jumps (gcc::context *ctxt)
8581debfc3dSmrg : gimple_opt_pass (pass_data_early_thread_jumps, ctxt)
8591debfc3dSmrg {}
8601debfc3dSmrg
clone(void)8611debfc3dSmrg opt_pass * clone (void) { return new pass_early_thread_jumps (m_ctxt); }
8621debfc3dSmrg virtual bool gate (function *);
8631debfc3dSmrg virtual unsigned int execute (function *);
8641debfc3dSmrg };
8651debfc3dSmrg
8661debfc3dSmrg bool
gate(function * fun ATTRIBUTE_UNUSED)8671debfc3dSmrg pass_early_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED)
8681debfc3dSmrg {
8691debfc3dSmrg return true;
8701debfc3dSmrg }
8711debfc3dSmrg
8721debfc3dSmrg
8731debfc3dSmrg unsigned int
execute(function * fun)8741debfc3dSmrg pass_early_thread_jumps::execute (function *fun)
8751debfc3dSmrg {
8761debfc3dSmrg loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
8771debfc3dSmrg
8781debfc3dSmrg /* Try to thread each block with more than one successor. */
879a2dc1f3fSmrg thread_jumps threader;
8801debfc3dSmrg basic_block bb;
8811debfc3dSmrg FOR_EACH_BB_FN (bb, fun)
8821debfc3dSmrg {
8831debfc3dSmrg if (EDGE_COUNT (bb->succs) > 1)
884a2dc1f3fSmrg threader.find_jump_threads_backwards (bb, false);
8851debfc3dSmrg }
8861debfc3dSmrg thread_through_all_blocks (true);
8871debfc3dSmrg
8881debfc3dSmrg loop_optimizer_finalize ();
8891debfc3dSmrg return 0;
8901debfc3dSmrg }
8911debfc3dSmrg
8921debfc3dSmrg }
8931debfc3dSmrg
8941debfc3dSmrg gimple_opt_pass *
make_pass_early_thread_jumps(gcc::context * ctxt)8951debfc3dSmrg make_pass_early_thread_jumps (gcc::context *ctxt)
8961debfc3dSmrg {
8971debfc3dSmrg return new pass_early_thread_jumps (ctxt);
8981debfc3dSmrg }
899