163aace61Smrg /* Back-propagation of usage information to definitions.
2*dd083157Smrg Copyright (C) 2015-2020 Free Software Foundation, Inc.
363aace61Smrg
463aace61Smrg This file is part of GCC.
563aace61Smrg
663aace61Smrg GCC is free software; you can redistribute it and/or modify
763aace61Smrg it under the terms of the GNU General Public License as published by
863aace61Smrg the Free Software Foundation; either version 3, or (at your option)
963aace61Smrg any later version.
1063aace61Smrg
1163aace61Smrg GCC is distributed in the hope that it will be useful,
1263aace61Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1363aace61Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1463aace61Smrg GNU General Public License for more details.
1563aace61Smrg
1663aace61Smrg You should have received a copy of the GNU General Public License
1763aace61Smrg along with GCC; see the file COPYING3. If not see
1863aace61Smrg <http://www.gnu.org/licenses/>. */
1963aace61Smrg
2063aace61Smrg /* This pass propagates information that is common to all uses of an SSA
2163aace61Smrg name back up through the sequence of statements that generate it,
2263aace61Smrg simplifying the statements where possible. Sometimes this can expose
2363aace61Smrg fully or partially dead code, but the main focus is simplifying
2463aace61Smrg computations.
2563aace61Smrg
2663aace61Smrg At the moment the pass only handles one piece of information: whether the
2763aace61Smrg sign of a value matters, and therefore whether sign-changing operations
2863aace61Smrg can be skipped. The pass could be extended to more interesting
2963aace61Smrg information in future, such as which bits of an integer are significant.
3063aace61Smrg
3163aace61Smrg For example, take the function:
3263aace61Smrg
3363aace61Smrg double
3463aace61Smrg f (double *a, int n, double start)
3563aace61Smrg {
3663aace61Smrg double x = fabs (start);
3763aace61Smrg for (int i = 0; i < n; ++i)
3863aace61Smrg x *= a[i];
3963aace61Smrg return __builtin_cos (x);
4063aace61Smrg }
4163aace61Smrg
4263aace61Smrg cos(x) == cos(-x), so the sign of the final x doesn't matter.
4363aace61Smrg That x is the result of a series of multiplications, and if
4463aace61Smrg the sign of the result of a multiplication doesn't matter,
4563aace61Smrg the signs of the inputs don't matter either.
4663aace61Smrg
4763aace61Smrg The pass would replace the incoming value of x (i.e. fabs(start))
4863aace61Smrg with start. Since there are no other uses of the fabs result,
4963aace61Smrg the call would get deleted as dead.
5063aace61Smrg
5163aace61Smrg The algorithm is:
5263aace61Smrg
5363aace61Smrg (1) Do a post-order traversal of the blocks in the function, walking
5463aace61Smrg each block backwards. For each potentially-simplifiable statement
5563aace61Smrg that defines an SSA name X, examine all uses of X to see what
5663aace61Smrg information is actually significant. Record this as INFO_MAP[X].
5763aace61Smrg Optimistically ignore for now any back-edge references to
5863aace61Smrg unprocessed phis.
5963aace61Smrg
6063aace61Smrg (An alternative would be to record each use when we visit its
6163aace61Smrg statement and take the intersection as we go along. However,
6263aace61Smrg this would lead to more SSA names being entered into INFO_MAP
6363aace61Smrg unnecessarily, only to be taken out again later. At the moment
6463aace61Smrg very few SSA names end up with useful information.)
6563aace61Smrg
6663aace61Smrg (2) Iteratively reduce the optimistic result of (1) until we reach
6763aace61Smrg a maximal fixed point (which at the moment would mean revisiting
6863aace61Smrg statements at most once). First push all SSA names that used an
6963aace61Smrg optimistic assumption about a backedge phi onto a worklist.
7063aace61Smrg While the worklist is nonempty, pick off an SSA name X and recompute
7163aace61Smrg INFO_MAP[X]. If the value changes, push all SSA names used in the
7263aace61Smrg definition of X onto the worklist.
7363aace61Smrg
7463aace61Smrg (3) Iterate over each SSA name X with info in INFO_MAP, in the
7563aace61Smrg opposite order to (1), i.e. a forward reverse-post-order walk.
7663aace61Smrg Try to optimize the definition of X using INFO_MAP[X] and fold
7763aace61Smrg the result. (This ensures that we fold definitions before uses.)
7863aace61Smrg
7963aace61Smrg (4) Iterate over each SSA name X with info in INFO_MAP, in the same
8063aace61Smrg order as (1), and delete any statements that are now dead.
8163aace61Smrg (This ensures that if a sequence of statements is dead,
8263aace61Smrg we delete the last statement first.)
8363aace61Smrg
8463aace61Smrg Note that this pass does not deal with direct redundancies,
8563aace61Smrg such as cos(-x)->cos(x). match.pd handles those cases instead. */
8663aace61Smrg
8763aace61Smrg #include "config.h"
8863aace61Smrg #include "system.h"
8963aace61Smrg #include "coretypes.h"
9063aace61Smrg #include "backend.h"
9163aace61Smrg #include "tree.h"
9263aace61Smrg #include "gimple.h"
9363aace61Smrg #include "gimple-iterator.h"
9463aace61Smrg #include "ssa.h"
9563aace61Smrg #include "fold-const.h"
9663aace61Smrg #include "tree-pass.h"
9763aace61Smrg #include "cfganal.h"
9863aace61Smrg #include "gimple-pretty-print.h"
9963aace61Smrg #include "tree-cfg.h"
10063aace61Smrg #include "tree-ssa.h"
10163aace61Smrg #include "tree-ssa-propagate.h"
10263aace61Smrg #include "gimple-fold.h"
10363aace61Smrg #include "alloc-pool.h"
10463aace61Smrg #include "tree-hash-traits.h"
10563aace61Smrg #include "case-cfn-macros.h"
10663aace61Smrg
10763aace61Smrg namespace {
10863aace61Smrg
10963aace61Smrg /* Information about a group of uses of an SSA name. */
110*dd083157Smrg class usage_info
11163aace61Smrg {
112*dd083157Smrg public:
usage_info()11363aace61Smrg usage_info () : flag_word (0) {}
11463aace61Smrg usage_info &operator &= (const usage_info &);
11563aace61Smrg usage_info operator & (const usage_info &) const;
11663aace61Smrg bool operator == (const usage_info &) const;
11763aace61Smrg bool operator != (const usage_info &) const;
11863aace61Smrg bool is_useful () const;
11963aace61Smrg
12063aace61Smrg static usage_info intersection_identity ();
12163aace61Smrg
12263aace61Smrg union
12363aace61Smrg {
12463aace61Smrg struct
12563aace61Smrg {
12663aace61Smrg /* True if the uses treat x and -x in the same way. */
12763aace61Smrg unsigned int ignore_sign : 1;
12863aace61Smrg } flags;
12963aace61Smrg /* All the flag bits as a single int. */
13063aace61Smrg unsigned int flag_word;
13163aace61Smrg };
13263aace61Smrg };
13363aace61Smrg
13463aace61Smrg /* Return an X such that X & Y == Y for all Y. This is the most
13563aace61Smrg optimistic assumption possible. */
13663aace61Smrg
13763aace61Smrg usage_info
intersection_identity()13863aace61Smrg usage_info::intersection_identity ()
13963aace61Smrg {
14063aace61Smrg usage_info ret;
14163aace61Smrg ret.flag_word = -1;
14263aace61Smrg return ret;
14363aace61Smrg }
14463aace61Smrg
14563aace61Smrg /* Intersect *THIS with OTHER, so that *THIS describes all uses covered
14663aace61Smrg by the original *THIS and OTHER. */
14763aace61Smrg
14863aace61Smrg usage_info &
14963aace61Smrg usage_info::operator &= (const usage_info &other)
15063aace61Smrg {
15163aace61Smrg flag_word &= other.flag_word;
15263aace61Smrg return *this;
15363aace61Smrg }
15463aace61Smrg
15563aace61Smrg /* Return the intersection of *THIS and OTHER, i.e. a structure that
15663aace61Smrg describes all uses covered by *THIS and OTHER. */
15763aace61Smrg
15863aace61Smrg usage_info
15963aace61Smrg usage_info::operator & (const usage_info &other) const
16063aace61Smrg {
16163aace61Smrg usage_info info (*this);
16263aace61Smrg info &= other;
16363aace61Smrg return info;
16463aace61Smrg }
16563aace61Smrg
16663aace61Smrg bool
16763aace61Smrg usage_info::operator == (const usage_info &other) const
16863aace61Smrg {
16963aace61Smrg return flag_word == other.flag_word;
17063aace61Smrg }
17163aace61Smrg
17263aace61Smrg bool
17363aace61Smrg usage_info::operator != (const usage_info &other) const
17463aace61Smrg {
17563aace61Smrg return !operator == (other);
17663aace61Smrg }
17763aace61Smrg
17863aace61Smrg /* Return true if *THIS is not simply the default, safe assumption. */
17963aace61Smrg
18063aace61Smrg bool
is_useful()18163aace61Smrg usage_info::is_useful () const
18263aace61Smrg {
18363aace61Smrg return flag_word != 0;
18463aace61Smrg }
18563aace61Smrg
18663aace61Smrg /* Start a dump line about SSA name VAR. */
18763aace61Smrg
18863aace61Smrg static void
dump_usage_prefix(FILE * file,tree var)18963aace61Smrg dump_usage_prefix (FILE *file, tree var)
19063aace61Smrg {
19163aace61Smrg fprintf (file, " ");
1923903d7f3Smrg print_generic_expr (file, var);
19363aace61Smrg fprintf (file, ": ");
19463aace61Smrg }
19563aace61Smrg
19663aace61Smrg /* Print INFO to FILE. */
19763aace61Smrg
19863aace61Smrg static void
dump_usage_info(FILE * file,tree var,usage_info * info)19963aace61Smrg dump_usage_info (FILE *file, tree var, usage_info *info)
20063aace61Smrg {
20163aace61Smrg if (info->flags.ignore_sign)
20263aace61Smrg {
20363aace61Smrg dump_usage_prefix (file, var);
20463aace61Smrg fprintf (file, "sign bit not important\n");
20563aace61Smrg }
20663aace61Smrg }
20763aace61Smrg
20863aace61Smrg /* Represents one execution of the pass. */
20963aace61Smrg class backprop
21063aace61Smrg {
21163aace61Smrg public:
21263aace61Smrg backprop (function *);
21363aace61Smrg ~backprop ();
21463aace61Smrg
21563aace61Smrg void execute ();
21663aace61Smrg
21763aace61Smrg private:
21863aace61Smrg const usage_info *lookup_operand (tree);
21963aace61Smrg
22063aace61Smrg void push_to_worklist (tree);
22163aace61Smrg tree pop_from_worklist ();
22263aace61Smrg
22363aace61Smrg void process_builtin_call_use (gcall *, tree, usage_info *);
22463aace61Smrg void process_assign_use (gassign *, tree, usage_info *);
22563aace61Smrg void process_phi_use (gphi *, usage_info *);
22663aace61Smrg void process_use (gimple *, tree, usage_info *);
22763aace61Smrg bool intersect_uses (tree, usage_info *);
22863aace61Smrg void reprocess_inputs (gimple *);
22963aace61Smrg void process_var (tree);
23063aace61Smrg void process_block (basic_block);
23163aace61Smrg
23263aace61Smrg void prepare_change (tree);
23363aace61Smrg void complete_change (gimple *);
23463aace61Smrg void optimize_builtin_call (gcall *, tree, const usage_info *);
23563aace61Smrg void replace_assign_rhs (gassign *, tree, tree, tree, tree);
23663aace61Smrg void optimize_assign (gassign *, tree, const usage_info *);
23763aace61Smrg void optimize_phi (gphi *, tree, const usage_info *);
23863aace61Smrg
23963aace61Smrg typedef hash_map <tree_ssa_name_hash, usage_info *> info_map_type;
24063aace61Smrg typedef std::pair <tree, usage_info *> var_info_pair;
24163aace61Smrg
24263aace61Smrg /* The function we're optimizing. */
24363aace61Smrg function *m_fn;
24463aace61Smrg
24563aace61Smrg /* Pool for allocating usage_info structures. */
24663aace61Smrg object_allocator <usage_info> m_info_pool;
24763aace61Smrg
24863aace61Smrg /* Maps an SSA name to a description of all uses of that SSA name.
24963aace61Smrg All the usage_infos satisfy is_useful.
25063aace61Smrg
25163aace61Smrg We use a hash_map because the map is expected to be sparse
25263aace61Smrg (i.e. most SSA names won't have useful information attached to them).
25363aace61Smrg We could move to a directly-indexed array if that situation changes. */
25463aace61Smrg info_map_type m_info_map;
25563aace61Smrg
25663aace61Smrg /* Post-ordered list of all potentially-interesting SSA names,
25763aace61Smrg along with information that describes all uses. */
25863aace61Smrg auto_vec <var_info_pair, 128> m_vars;
25963aace61Smrg
26063aace61Smrg /* A bitmap of blocks that we have finished processing in the initial
26163aace61Smrg post-order walk. */
2626a5c9aabSmrg auto_sbitmap m_visited_blocks;
26363aace61Smrg
26416b7cd4fSmrg /* A bitmap of phis that we have finished processing in the initial
26516b7cd4fSmrg post-order walk, excluding those from blocks mentioned in
26616b7cd4fSmrg M_VISITED_BLOCKS. */
2676a5c9aabSmrg auto_bitmap m_visited_phis;
26816b7cd4fSmrg
26963aace61Smrg /* A worklist of SSA names whose definitions need to be reconsidered. */
27063aace61Smrg auto_vec <tree, 64> m_worklist;
27163aace61Smrg
27263aace61Smrg /* The SSA names in M_WORKLIST, identified by their SSA_NAME_VERSION.
27363aace61Smrg We use a bitmap rather than an sbitmap because most SSA names are
27463aace61Smrg never added to the worklist. */
27563aace61Smrg bitmap m_worklist_names;
27663aace61Smrg };
27763aace61Smrg
backprop(function * fn)27863aace61Smrg backprop::backprop (function *fn)
27963aace61Smrg : m_fn (fn),
28063aace61Smrg m_info_pool ("usage_info"),
2816a5c9aabSmrg m_visited_blocks (last_basic_block_for_fn (m_fn)),
28263aace61Smrg m_worklist_names (BITMAP_ALLOC (NULL))
28363aace61Smrg {
28463aace61Smrg bitmap_clear (m_visited_blocks);
28563aace61Smrg }
28663aace61Smrg
~backprop()28763aace61Smrg backprop::~backprop ()
28863aace61Smrg {
28963aace61Smrg BITMAP_FREE (m_worklist_names);
29063aace61Smrg m_info_pool.release ();
29163aace61Smrg }
29263aace61Smrg
29363aace61Smrg /* Return usage information for general operand OP, or null if none. */
29463aace61Smrg
29563aace61Smrg const usage_info *
lookup_operand(tree op)29663aace61Smrg backprop::lookup_operand (tree op)
29763aace61Smrg {
29863aace61Smrg if (op && TREE_CODE (op) == SSA_NAME)
29963aace61Smrg {
30063aace61Smrg usage_info **slot = m_info_map.get (op);
30163aace61Smrg if (slot)
30263aace61Smrg return *slot;
30363aace61Smrg }
30463aace61Smrg return NULL;
30563aace61Smrg }
30663aace61Smrg
30763aace61Smrg /* Add SSA name VAR to the worklist, if it isn't on the worklist already. */
30863aace61Smrg
30963aace61Smrg void
push_to_worklist(tree var)31063aace61Smrg backprop::push_to_worklist (tree var)
31163aace61Smrg {
31263aace61Smrg if (!bitmap_set_bit (m_worklist_names, SSA_NAME_VERSION (var)))
31363aace61Smrg return;
31463aace61Smrg m_worklist.safe_push (var);
31563aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
31663aace61Smrg {
31763aace61Smrg fprintf (dump_file, "[WORKLIST] Pushing ");
3183903d7f3Smrg print_generic_expr (dump_file, var);
31963aace61Smrg fprintf (dump_file, "\n");
32063aace61Smrg }
32163aace61Smrg }
32263aace61Smrg
32363aace61Smrg /* Remove and return the next SSA name from the worklist. The worklist
32463aace61Smrg is known to be nonempty. */
32563aace61Smrg
32663aace61Smrg tree
pop_from_worklist()32763aace61Smrg backprop::pop_from_worklist ()
32863aace61Smrg {
32963aace61Smrg tree var = m_worklist.pop ();
33063aace61Smrg bitmap_clear_bit (m_worklist_names, SSA_NAME_VERSION (var));
33163aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
33263aace61Smrg {
33363aace61Smrg fprintf (dump_file, "[WORKLIST] Popping ");
3343903d7f3Smrg print_generic_expr (dump_file, var);
33563aace61Smrg fprintf (dump_file, "\n");
33663aace61Smrg }
33763aace61Smrg return var;
33863aace61Smrg }
33963aace61Smrg
34063aace61Smrg /* Make INFO describe all uses of RHS in CALL, which is a call to a
34163aace61Smrg built-in function. */
34263aace61Smrg
34363aace61Smrg void
process_builtin_call_use(gcall * call,tree rhs,usage_info * info)34463aace61Smrg backprop::process_builtin_call_use (gcall *call, tree rhs, usage_info *info)
34563aace61Smrg {
34663aace61Smrg combined_fn fn = gimple_call_combined_fn (call);
34763aace61Smrg tree lhs = gimple_call_lhs (call);
34863aace61Smrg switch (fn)
34963aace61Smrg {
35063aace61Smrg case CFN_LAST:
35163aace61Smrg break;
35263aace61Smrg
35363aace61Smrg CASE_CFN_COS:
35463aace61Smrg CASE_CFN_COSH:
35563aace61Smrg CASE_CFN_CCOS:
35663aace61Smrg CASE_CFN_CCOSH:
35763aace61Smrg CASE_CFN_HYPOT:
35863aace61Smrg /* The signs of all inputs are ignored. */
35963aace61Smrg info->flags.ignore_sign = true;
36063aace61Smrg break;
36163aace61Smrg
36263aace61Smrg CASE_CFN_COPYSIGN:
3633903d7f3Smrg CASE_CFN_COPYSIGN_FN:
36463aace61Smrg /* The sign of the first input is ignored. */
36563aace61Smrg if (rhs != gimple_call_arg (call, 1))
36663aace61Smrg info->flags.ignore_sign = true;
36763aace61Smrg break;
36863aace61Smrg
36963aace61Smrg CASE_CFN_POW:
37063aace61Smrg {
37163aace61Smrg /* The sign of the first input is ignored as long as the second
37263aace61Smrg input is an even real. */
37363aace61Smrg tree power = gimple_call_arg (call, 1);
37463aace61Smrg HOST_WIDE_INT n;
37563aace61Smrg if (TREE_CODE (power) == REAL_CST
37663aace61Smrg && real_isinteger (&TREE_REAL_CST (power), &n)
37763aace61Smrg && (n & 1) == 0)
37863aace61Smrg info->flags.ignore_sign = true;
37963aace61Smrg break;
38063aace61Smrg }
38163aace61Smrg
38263aace61Smrg CASE_CFN_FMA:
3833903d7f3Smrg CASE_CFN_FMA_FN:
38481418a27Smrg case CFN_FMS:
38581418a27Smrg case CFN_FNMA:
38681418a27Smrg case CFN_FNMS:
38763aace61Smrg /* In X * X + Y, where Y is distinct from X, the sign of X doesn't
38863aace61Smrg matter. */
38963aace61Smrg if (gimple_call_arg (call, 0) == rhs
39063aace61Smrg && gimple_call_arg (call, 1) == rhs
39163aace61Smrg && gimple_call_arg (call, 2) != rhs)
39263aace61Smrg info->flags.ignore_sign = true;
39363aace61Smrg break;
39463aace61Smrg
39563aace61Smrg default:
39663aace61Smrg if (negate_mathfn_p (fn))
39763aace61Smrg {
39863aace61Smrg /* The sign of the (single) input doesn't matter provided
39963aace61Smrg that the sign of the output doesn't matter. */
40063aace61Smrg const usage_info *lhs_info = lookup_operand (lhs);
40163aace61Smrg if (lhs_info)
40263aace61Smrg info->flags.ignore_sign = lhs_info->flags.ignore_sign;
40363aace61Smrg }
40463aace61Smrg break;
40563aace61Smrg }
40663aace61Smrg }
40763aace61Smrg
40863aace61Smrg /* Make INFO describe all uses of RHS in ASSIGN. */
40963aace61Smrg
41063aace61Smrg void
process_assign_use(gassign * assign,tree rhs,usage_info * info)41163aace61Smrg backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info)
41263aace61Smrg {
41363aace61Smrg tree lhs = gimple_assign_lhs (assign);
41463aace61Smrg switch (gimple_assign_rhs_code (assign))
41563aace61Smrg {
41663aace61Smrg case ABS_EXPR:
41781418a27Smrg case ABSU_EXPR:
41863aace61Smrg /* The sign of the input doesn't matter. */
41963aace61Smrg info->flags.ignore_sign = true;
42063aace61Smrg break;
42163aace61Smrg
42263aace61Smrg case COND_EXPR:
42363aace61Smrg /* For A = B ? C : D, propagate information about all uses of A
42463aace61Smrg to C and D. */
42563aace61Smrg if (rhs != gimple_assign_rhs1 (assign))
42663aace61Smrg {
42763aace61Smrg const usage_info *lhs_info = lookup_operand (lhs);
42863aace61Smrg if (lhs_info)
42963aace61Smrg *info = *lhs_info;
43063aace61Smrg }
43163aace61Smrg break;
43263aace61Smrg
43363aace61Smrg case MULT_EXPR:
43463aace61Smrg /* In X * X, the sign of X doesn't matter. */
43563aace61Smrg if (gimple_assign_rhs1 (assign) == rhs
43663aace61Smrg && gimple_assign_rhs2 (assign) == rhs)
43763aace61Smrg info->flags.ignore_sign = true;
43863aace61Smrg /* Fall through. */
43963aace61Smrg
44063aace61Smrg case NEGATE_EXPR:
44163aace61Smrg case RDIV_EXPR:
44263aace61Smrg /* If the sign of the result doesn't matter, the sign of the inputs
44363aace61Smrg doesn't matter either. */
44463aace61Smrg if (FLOAT_TYPE_P (TREE_TYPE (rhs)))
44563aace61Smrg {
44663aace61Smrg const usage_info *lhs_info = lookup_operand (lhs);
44763aace61Smrg if (lhs_info)
44863aace61Smrg info->flags.ignore_sign = lhs_info->flags.ignore_sign;
44963aace61Smrg }
45063aace61Smrg break;
45163aace61Smrg
45263aace61Smrg default:
45363aace61Smrg break;
45463aace61Smrg }
45563aace61Smrg }
45663aace61Smrg
45763aace61Smrg /* Make INFO describe the uses of PHI's result. */
45863aace61Smrg
45963aace61Smrg void
process_phi_use(gphi * phi,usage_info * info)46063aace61Smrg backprop::process_phi_use (gphi *phi, usage_info *info)
46163aace61Smrg {
46263aace61Smrg tree result = gimple_phi_result (phi);
46363aace61Smrg if (const usage_info *result_info = lookup_operand (result))
46463aace61Smrg *info = *result_info;
46563aace61Smrg }
46663aace61Smrg
46763aace61Smrg /* Make INFO describe all uses of RHS in STMT. */
46863aace61Smrg
46963aace61Smrg void
process_use(gimple * stmt,tree rhs,usage_info * info)47063aace61Smrg backprop::process_use (gimple *stmt, tree rhs, usage_info *info)
47163aace61Smrg {
47263aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
47363aace61Smrg {
47463aace61Smrg fprintf (dump_file, "[USE] ");
4753903d7f3Smrg print_generic_expr (dump_file, rhs);
47663aace61Smrg fprintf (dump_file, " in ");
47763aace61Smrg print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
47863aace61Smrg }
47963aace61Smrg
48063aace61Smrg if (gcall *call = dyn_cast <gcall *> (stmt))
48163aace61Smrg process_builtin_call_use (call, rhs, info);
48263aace61Smrg else if (gassign *assign = dyn_cast <gassign *> (stmt))
48363aace61Smrg process_assign_use (assign, rhs, info);
48463aace61Smrg else if (gphi *phi = dyn_cast <gphi *> (stmt))
48563aace61Smrg process_phi_use (phi, info);
48663aace61Smrg
48763aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
48863aace61Smrg dump_usage_info (dump_file, rhs, info);
48963aace61Smrg }
49063aace61Smrg
49163aace61Smrg /* Make INFO describe all uses of VAR, returning true if the result
49263aace61Smrg is useful. If the uses include phis that haven't been processed yet,
49363aace61Smrg make the most optimistic assumption possible, so that we aim for
49463aace61Smrg a maximum rather than a minimum fixed point. */
49563aace61Smrg
49663aace61Smrg bool
intersect_uses(tree var,usage_info * info)49763aace61Smrg backprop::intersect_uses (tree var, usage_info *info)
49863aace61Smrg {
49963aace61Smrg imm_use_iterator iter;
5003903d7f3Smrg use_operand_p use_p;
50163aace61Smrg *info = usage_info::intersection_identity ();
5023903d7f3Smrg FOR_EACH_IMM_USE_FAST (use_p, iter, var)
50363aace61Smrg {
5043903d7f3Smrg gimple *stmt = USE_STMT (use_p);
50563aace61Smrg if (is_gimple_debug (stmt))
50663aace61Smrg continue;
50716b7cd4fSmrg gphi *phi = dyn_cast <gphi *> (stmt);
50816b7cd4fSmrg if (phi
50916b7cd4fSmrg && !bitmap_bit_p (m_visited_blocks, gimple_bb (phi)->index)
51016b7cd4fSmrg && !bitmap_bit_p (m_visited_phis,
51116b7cd4fSmrg SSA_NAME_VERSION (gimple_phi_result (phi))))
51263aace61Smrg {
51363aace61Smrg /* Skip unprocessed phis. */
51463aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
51563aace61Smrg {
51663aace61Smrg fprintf (dump_file, "[BACKEDGE] ");
5173903d7f3Smrg print_generic_expr (dump_file, var);
51863aace61Smrg fprintf (dump_file, " in ");
51916b7cd4fSmrg print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
52063aace61Smrg }
52163aace61Smrg }
52263aace61Smrg else
52363aace61Smrg {
52463aace61Smrg usage_info subinfo;
52563aace61Smrg process_use (stmt, var, &subinfo);
52663aace61Smrg *info &= subinfo;
52763aace61Smrg if (!info->is_useful ())
52863aace61Smrg return false;
52963aace61Smrg }
53063aace61Smrg }
53163aace61Smrg return true;
53263aace61Smrg }
53363aace61Smrg
53463aace61Smrg /* Queue for reconsideration any input of STMT that has information
53563aace61Smrg associated with it. This is used if that information might be
53663aace61Smrg too optimistic. */
53763aace61Smrg
53863aace61Smrg void
reprocess_inputs(gimple * stmt)53963aace61Smrg backprop::reprocess_inputs (gimple *stmt)
54063aace61Smrg {
54163aace61Smrg use_operand_p use_p;
54263aace61Smrg ssa_op_iter oi;
54363aace61Smrg FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, oi, SSA_OP_USE)
54463aace61Smrg {
54563aace61Smrg tree var = get_use_from_ptr (use_p);
54663aace61Smrg if (lookup_operand (var))
54763aace61Smrg push_to_worklist (var);
54863aace61Smrg }
54963aace61Smrg }
55063aace61Smrg
55163aace61Smrg /* Say that we're recording INFO for SSA name VAR, or that we're deleting
55263aace61Smrg existing information if INFO is null. INTRO describes the change. */
55363aace61Smrg
55463aace61Smrg static void
dump_var_info(tree var,usage_info * info,const char * intro)55563aace61Smrg dump_var_info (tree var, usage_info *info, const char *intro)
55663aace61Smrg {
55763aace61Smrg fprintf (dump_file, "[DEF] %s for ", intro);
55863aace61Smrg print_gimple_stmt (dump_file, SSA_NAME_DEF_STMT (var), 0, TDF_SLIM);
55963aace61Smrg if (info)
56063aace61Smrg dump_usage_info (dump_file, var, info);
56163aace61Smrg }
56263aace61Smrg
56363aace61Smrg /* Process all uses of VAR and record or update the result in
56463aace61Smrg M_INFO_MAP and M_VARS. */
56563aace61Smrg
56663aace61Smrg void
process_var(tree var)56763aace61Smrg backprop::process_var (tree var)
56863aace61Smrg {
56963aace61Smrg if (has_zero_uses (var))
57063aace61Smrg return;
57163aace61Smrg
57263aace61Smrg usage_info info;
57363aace61Smrg intersect_uses (var, &info);
57463aace61Smrg
57563aace61Smrg gimple *stmt = SSA_NAME_DEF_STMT (var);
57663aace61Smrg if (info.is_useful ())
57763aace61Smrg {
57863aace61Smrg bool existed;
57963aace61Smrg usage_info *&map_info = m_info_map.get_or_insert (var, &existed);
58063aace61Smrg if (!existed)
58163aace61Smrg {
58263aace61Smrg /* Recording information about VAR for the first time. */
58363aace61Smrg map_info = m_info_pool.allocate ();
58463aace61Smrg *map_info = info;
58563aace61Smrg m_vars.safe_push (var_info_pair (var, map_info));
58663aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
58763aace61Smrg dump_var_info (var, map_info, "Recording new information");
58863aace61Smrg
58963aace61Smrg /* If STMT is a phi, reprocess any backedge uses. This is a
59063aace61Smrg no-op for other uses, which won't have any information
59163aace61Smrg associated with them. */
59263aace61Smrg if (is_a <gphi *> (stmt))
59363aace61Smrg reprocess_inputs (stmt);
59463aace61Smrg }
59563aace61Smrg else if (info != *map_info)
59663aace61Smrg {
59763aace61Smrg /* Recording information that is less optimistic than before. */
59863aace61Smrg gcc_checking_assert ((info & *map_info) == info);
59963aace61Smrg *map_info = info;
60063aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
60163aace61Smrg dump_var_info (var, map_info, "Updating information");
60263aace61Smrg reprocess_inputs (stmt);
60363aace61Smrg }
60463aace61Smrg }
60563aace61Smrg else
60663aace61Smrg {
60763aace61Smrg if (usage_info **slot = m_info_map.get (var))
60863aace61Smrg {
60963aace61Smrg /* Removing previously-recorded information. */
61063aace61Smrg **slot = info;
61163aace61Smrg m_info_map.remove (var);
61263aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
61363aace61Smrg dump_var_info (var, NULL, "Deleting information");
61463aace61Smrg reprocess_inputs (stmt);
61563aace61Smrg }
61663aace61Smrg else
61763aace61Smrg {
61863aace61Smrg /* If STMT is a phi, remove any information recorded for
61963aace61Smrg its arguments. */
62063aace61Smrg if (is_a <gphi *> (stmt))
62163aace61Smrg reprocess_inputs (stmt);
62263aace61Smrg }
62363aace61Smrg }
62463aace61Smrg }
62563aace61Smrg
62663aace61Smrg /* Process all statements and phis in BB, during the first post-order walk. */
62763aace61Smrg
62863aace61Smrg void
process_block(basic_block bb)62963aace61Smrg backprop::process_block (basic_block bb)
63063aace61Smrg {
63163aace61Smrg for (gimple_stmt_iterator gsi = gsi_last_bb (bb); !gsi_end_p (gsi);
63263aace61Smrg gsi_prev (&gsi))
63363aace61Smrg {
63463aace61Smrg tree lhs = gimple_get_lhs (gsi_stmt (gsi));
63563aace61Smrg if (lhs && TREE_CODE (lhs) == SSA_NAME)
63663aace61Smrg process_var (lhs);
63763aace61Smrg }
63863aace61Smrg for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
63963aace61Smrg gsi_next (&gpi))
64016b7cd4fSmrg {
64116b7cd4fSmrg tree result = gimple_phi_result (gpi.phi ());
64216b7cd4fSmrg process_var (result);
64316b7cd4fSmrg bitmap_set_bit (m_visited_phis, SSA_NAME_VERSION (result));
64416b7cd4fSmrg }
64516b7cd4fSmrg bitmap_clear (m_visited_phis);
64663aace61Smrg }
64763aace61Smrg
64863aace61Smrg /* Delete the definition of VAR, which has no uses. */
64963aace61Smrg
65063aace61Smrg static void
remove_unused_var(tree var)65163aace61Smrg remove_unused_var (tree var)
65263aace61Smrg {
65363aace61Smrg gimple *stmt = SSA_NAME_DEF_STMT (var);
65463aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
65563aace61Smrg {
65663aace61Smrg fprintf (dump_file, "Deleting ");
65763aace61Smrg print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
65863aace61Smrg }
65963aace61Smrg gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
66063aace61Smrg gsi_remove (&gsi, true);
66163aace61Smrg release_defs (stmt);
66263aace61Smrg }
66363aace61Smrg
66463aace61Smrg /* Note that we're replacing OLD_RHS with NEW_RHS in STMT. */
66563aace61Smrg
66663aace61Smrg static void
note_replacement(gimple * stmt,tree old_rhs,tree new_rhs)66763aace61Smrg note_replacement (gimple *stmt, tree old_rhs, tree new_rhs)
66863aace61Smrg {
66963aace61Smrg fprintf (dump_file, "Replacing use of ");
6703903d7f3Smrg print_generic_expr (dump_file, old_rhs);
67163aace61Smrg fprintf (dump_file, " with ");
6723903d7f3Smrg print_generic_expr (dump_file, new_rhs);
67363aace61Smrg fprintf (dump_file, " in ");
67463aace61Smrg print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
67563aace61Smrg }
67663aace61Smrg
67763aace61Smrg /* If RHS is an SSA name whose definition just changes the sign of a value,
67863aace61Smrg return that other value, otherwise return null. */
67963aace61Smrg
68063aace61Smrg static tree
strip_sign_op_1(tree rhs)68163aace61Smrg strip_sign_op_1 (tree rhs)
68263aace61Smrg {
68363aace61Smrg if (TREE_CODE (rhs) != SSA_NAME)
68463aace61Smrg return NULL_TREE;
68563aace61Smrg
68663aace61Smrg gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
68763aace61Smrg if (gassign *assign = dyn_cast <gassign *> (def_stmt))
68863aace61Smrg switch (gimple_assign_rhs_code (assign))
68963aace61Smrg {
69063aace61Smrg case ABS_EXPR:
69181418a27Smrg case ABSU_EXPR:
69263aace61Smrg case NEGATE_EXPR:
69363aace61Smrg return gimple_assign_rhs1 (assign);
69463aace61Smrg
69563aace61Smrg default:
69663aace61Smrg break;
69763aace61Smrg }
69863aace61Smrg else if (gcall *call = dyn_cast <gcall *> (def_stmt))
69963aace61Smrg switch (gimple_call_combined_fn (call))
70063aace61Smrg {
70163aace61Smrg CASE_CFN_COPYSIGN:
7023903d7f3Smrg CASE_CFN_COPYSIGN_FN:
70363aace61Smrg return gimple_call_arg (call, 0);
70463aace61Smrg
70563aace61Smrg default:
70663aace61Smrg break;
70763aace61Smrg }
70863aace61Smrg
70963aace61Smrg return NULL_TREE;
71063aace61Smrg }
71163aace61Smrg
71263aace61Smrg /* If RHS is an SSA name whose definition just changes the sign of a value,
71363aace61Smrg strip all such operations and return the ultimate input to them.
71463aace61Smrg Return null otherwise.
71563aace61Smrg
71663aace61Smrg Although this could in principle lead to quadratic searching,
71763aace61Smrg in practice a long sequence of sign manipulations should already
71863aace61Smrg have been folded down. E.g. --x -> x, abs(-x) -> abs(x). We search
71963aace61Smrg for more than one operation in order to catch cases like -abs(x). */
72063aace61Smrg
72163aace61Smrg static tree
strip_sign_op(tree rhs)72263aace61Smrg strip_sign_op (tree rhs)
72363aace61Smrg {
72463aace61Smrg tree new_rhs = strip_sign_op_1 (rhs);
72563aace61Smrg if (!new_rhs)
72663aace61Smrg return NULL_TREE;
72763aace61Smrg while (tree next = strip_sign_op_1 (new_rhs))
72863aace61Smrg new_rhs = next;
72963aace61Smrg return new_rhs;
73063aace61Smrg }
73163aace61Smrg
73263aace61Smrg /* Start a change in the value of VAR that is suitable for all non-debug
73363aace61Smrg uses of VAR. We need to make sure that debug statements continue to
73463aace61Smrg use the original definition of VAR where possible, or are nullified
73563aace61Smrg otherwise. */
73663aace61Smrg
73763aace61Smrg void
prepare_change(tree var)73863aace61Smrg backprop::prepare_change (tree var)
73963aace61Smrg {
7403903d7f3Smrg if (MAY_HAVE_DEBUG_BIND_STMTS)
74163aace61Smrg insert_debug_temp_for_var_def (NULL, var);
7426a5c9aabSmrg reset_flow_sensitive_info (var);
74363aace61Smrg }
74463aace61Smrg
74563aace61Smrg /* STMT has been changed. Give the fold machinery a chance to simplify
74663aace61Smrg and canonicalize it (e.g. by ensuring that commutative operands have
74763aace61Smrg the right order), then record the updates. */
74863aace61Smrg
74963aace61Smrg void
complete_change(gimple * stmt)75063aace61Smrg backprop::complete_change (gimple *stmt)
75163aace61Smrg {
75263aace61Smrg gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
75363aace61Smrg if (fold_stmt (&gsi))
75463aace61Smrg {
75563aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
75663aace61Smrg {
75763aace61Smrg fprintf (dump_file, " which folds to: ");
75863aace61Smrg print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, TDF_SLIM);
75963aace61Smrg }
76063aace61Smrg }
76163aace61Smrg update_stmt (gsi_stmt (gsi));
76263aace61Smrg }
76363aace61Smrg
76463aace61Smrg /* Optimize CALL, a call to a built-in function with lhs LHS, on the
76563aace61Smrg basis that INFO describes all uses of LHS. */
76663aace61Smrg
76763aace61Smrg void
optimize_builtin_call(gcall * call,tree lhs,const usage_info * info)76863aace61Smrg backprop::optimize_builtin_call (gcall *call, tree lhs, const usage_info *info)
76963aace61Smrg {
77063aace61Smrg /* If we have an f such that -f(x) = f(-x), and if the sign of the result
77163aace61Smrg doesn't matter, strip any sign operations from the input. */
77263aace61Smrg if (info->flags.ignore_sign
77363aace61Smrg && negate_mathfn_p (gimple_call_combined_fn (call)))
77463aace61Smrg {
77563aace61Smrg tree new_arg = strip_sign_op (gimple_call_arg (call, 0));
77663aace61Smrg if (new_arg)
77763aace61Smrg {
77863aace61Smrg prepare_change (lhs);
77963aace61Smrg gimple_call_set_arg (call, 0, new_arg);
78063aace61Smrg complete_change (call);
78163aace61Smrg }
78263aace61Smrg }
78363aace61Smrg }
78463aace61Smrg
78563aace61Smrg /* Optimize ASSIGN, an assignment to LHS, by replacing rhs operand N
78663aace61Smrg with RHS<N>, if RHS<N> is nonnull. This may change the value of LHS. */
78763aace61Smrg
78863aace61Smrg void
replace_assign_rhs(gassign * assign,tree lhs,tree rhs1,tree rhs2,tree rhs3)78963aace61Smrg backprop::replace_assign_rhs (gassign *assign, tree lhs, tree rhs1,
79063aace61Smrg tree rhs2, tree rhs3)
79163aace61Smrg {
79263aace61Smrg if (!rhs1 && !rhs2 && !rhs3)
79363aace61Smrg return;
79463aace61Smrg
79563aace61Smrg prepare_change (lhs);
79663aace61Smrg if (rhs1)
79763aace61Smrg gimple_assign_set_rhs1 (assign, rhs1);
79863aace61Smrg if (rhs2)
79963aace61Smrg gimple_assign_set_rhs2 (assign, rhs2);
80063aace61Smrg if (rhs3)
80163aace61Smrg gimple_assign_set_rhs3 (assign, rhs3);
80263aace61Smrg complete_change (assign);
80363aace61Smrg }
80463aace61Smrg
80563aace61Smrg /* Optimize ASSIGN, an assignment to LHS, on the basis that INFO
80663aace61Smrg describes all uses of LHS. */
80763aace61Smrg
80863aace61Smrg void
optimize_assign(gassign * assign,tree lhs,const usage_info * info)80963aace61Smrg backprop::optimize_assign (gassign *assign, tree lhs, const usage_info *info)
81063aace61Smrg {
81163aace61Smrg switch (gimple_assign_rhs_code (assign))
81263aace61Smrg {
81363aace61Smrg case MULT_EXPR:
81463aace61Smrg case RDIV_EXPR:
81563aace61Smrg /* If the sign of the result doesn't matter, strip sign operations
81663aace61Smrg from both inputs. */
81763aace61Smrg if (info->flags.ignore_sign)
81863aace61Smrg replace_assign_rhs (assign, lhs,
81963aace61Smrg strip_sign_op (gimple_assign_rhs1 (assign)),
82063aace61Smrg strip_sign_op (gimple_assign_rhs2 (assign)),
82163aace61Smrg NULL_TREE);
82263aace61Smrg break;
82363aace61Smrg
82463aace61Smrg case COND_EXPR:
82563aace61Smrg /* If the sign of A ? B : C doesn't matter, strip sign operations
82663aace61Smrg from both B and C. */
82763aace61Smrg if (info->flags.ignore_sign)
82863aace61Smrg replace_assign_rhs (assign, lhs,
82963aace61Smrg NULL_TREE,
83063aace61Smrg strip_sign_op (gimple_assign_rhs2 (assign)),
83163aace61Smrg strip_sign_op (gimple_assign_rhs3 (assign)));
83263aace61Smrg break;
83363aace61Smrg
83463aace61Smrg default:
83563aace61Smrg break;
83663aace61Smrg }
83763aace61Smrg }
83863aace61Smrg
83963aace61Smrg /* Optimize PHI, which defines VAR, on the basis that INFO describes all
84063aace61Smrg uses of the result. */
84163aace61Smrg
84263aace61Smrg void
optimize_phi(gphi * phi,tree var,const usage_info * info)84363aace61Smrg backprop::optimize_phi (gphi *phi, tree var, const usage_info *info)
84463aace61Smrg {
84563aace61Smrg /* If the sign of the result doesn't matter, try to strip sign operations
84663aace61Smrg from arguments. */
84763aace61Smrg if (info->flags.ignore_sign)
84863aace61Smrg {
84963aace61Smrg basic_block bb = gimple_bb (phi);
85063aace61Smrg use_operand_p use;
85163aace61Smrg ssa_op_iter oi;
85263aace61Smrg bool replaced = false;
85363aace61Smrg FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
85463aace61Smrg {
85563aace61Smrg /* Propagating along abnormal edges is delicate, punt for now. */
85663aace61Smrg const int index = PHI_ARG_INDEX_FROM_USE (use);
85763aace61Smrg if (EDGE_PRED (bb, index)->flags & EDGE_ABNORMAL)
85863aace61Smrg continue;
85963aace61Smrg
86063aace61Smrg tree new_arg = strip_sign_op (USE_FROM_PTR (use));
86163aace61Smrg if (new_arg)
86263aace61Smrg {
86363aace61Smrg if (!replaced)
86463aace61Smrg prepare_change (var);
86563aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
86663aace61Smrg note_replacement (phi, USE_FROM_PTR (use), new_arg);
86763aace61Smrg replace_exp (use, new_arg);
86863aace61Smrg replaced = true;
86963aace61Smrg }
87063aace61Smrg }
87163aace61Smrg }
87263aace61Smrg }
87363aace61Smrg
87463aace61Smrg void
execute()87563aace61Smrg backprop::execute ()
87663aace61Smrg {
87763aace61Smrg /* Phase 1: Traverse the function, making optimistic assumptions
87863aace61Smrg about any phi whose definition we haven't seen. */
87963aace61Smrg int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (m_fn));
88063aace61Smrg unsigned int postorder_num = post_order_compute (postorder, false, false);
88163aace61Smrg for (unsigned int i = 0; i < postorder_num; ++i)
88263aace61Smrg {
88363aace61Smrg process_block (BASIC_BLOCK_FOR_FN (m_fn, postorder[i]));
88463aace61Smrg bitmap_set_bit (m_visited_blocks, postorder[i]);
88563aace61Smrg }
88663aace61Smrg XDELETEVEC (postorder);
88763aace61Smrg
88863aace61Smrg /* Phase 2: Use the initial (perhaps overly optimistic) information
88963aace61Smrg to create a maximal fixed point solution. */
89063aace61Smrg while (!m_worklist.is_empty ())
89163aace61Smrg process_var (pop_from_worklist ());
89263aace61Smrg
89363aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
89463aace61Smrg fprintf (dump_file, "\n");
89563aace61Smrg
89663aace61Smrg /* Phase 3: Do a reverse post-order walk, using information about
89763aace61Smrg the uses of SSA names to optimize their definitions. */
89863aace61Smrg for (unsigned int i = m_vars.length (); i-- > 0;)
89963aace61Smrg {
90063aace61Smrg usage_info *info = m_vars[i].second;
90163aace61Smrg if (info->is_useful ())
90263aace61Smrg {
90363aace61Smrg tree var = m_vars[i].first;
90463aace61Smrg gimple *stmt = SSA_NAME_DEF_STMT (var);
90563aace61Smrg if (gcall *call = dyn_cast <gcall *> (stmt))
90663aace61Smrg optimize_builtin_call (call, var, info);
90763aace61Smrg else if (gassign *assign = dyn_cast <gassign *> (stmt))
90863aace61Smrg optimize_assign (assign, var, info);
90963aace61Smrg else if (gphi *phi = dyn_cast <gphi *> (stmt))
91063aace61Smrg optimize_phi (phi, var, info);
91163aace61Smrg }
91263aace61Smrg }
91363aace61Smrg
91463aace61Smrg /* Phase 4: Do a post-order walk, deleting statements that are no
91563aace61Smrg longer needed. */
91663aace61Smrg for (unsigned int i = 0; i < m_vars.length (); ++i)
91763aace61Smrg {
91863aace61Smrg tree var = m_vars[i].first;
91963aace61Smrg if (has_zero_uses (var))
92063aace61Smrg remove_unused_var (var);
92163aace61Smrg }
92263aace61Smrg
92363aace61Smrg if (dump_file && (dump_flags & TDF_DETAILS))
92463aace61Smrg fprintf (dump_file, "\n");
92563aace61Smrg }
92663aace61Smrg
92763aace61Smrg const pass_data pass_data_backprop =
92863aace61Smrg {
92963aace61Smrg GIMPLE_PASS, /* type */
93063aace61Smrg "backprop", /* name */
93163aace61Smrg OPTGROUP_NONE, /* optinfo_flags */
93263aace61Smrg TV_TREE_BACKPROP, /* tv_id */
93363aace61Smrg ( PROP_cfg | PROP_ssa ), /* properties_required */
93463aace61Smrg 0, /* properties_provided */
93563aace61Smrg 0, /* properties_destroyed */
93663aace61Smrg 0, /* todo_flags_start */
93763aace61Smrg 0, /* todo_flags_finish */
93863aace61Smrg };
93963aace61Smrg
94063aace61Smrg class pass_backprop : public gimple_opt_pass
94163aace61Smrg {
94263aace61Smrg public:
pass_backprop(gcc::context * ctxt)94363aace61Smrg pass_backprop (gcc::context *ctxt)
94463aace61Smrg : gimple_opt_pass (pass_data_backprop, ctxt)
94563aace61Smrg {}
94663aace61Smrg
94763aace61Smrg /* opt_pass methods: */
clone()94863aace61Smrg opt_pass * clone () { return new pass_backprop (m_ctxt); }
gate(function *)94963aace61Smrg virtual bool gate (function *) { return flag_ssa_backprop; }
95063aace61Smrg virtual unsigned int execute (function *);
95163aace61Smrg
95263aace61Smrg }; // class pass_backprop
95363aace61Smrg
95463aace61Smrg unsigned int
execute(function * fn)95563aace61Smrg pass_backprop::execute (function *fn)
95663aace61Smrg {
95763aace61Smrg backprop (fn).execute ();
95863aace61Smrg return 0;
95963aace61Smrg }
96063aace61Smrg
96163aace61Smrg } // anon namespace
96263aace61Smrg
96363aace61Smrg gimple_opt_pass *
make_pass_backprop(gcc::context * ctxt)96463aace61Smrg make_pass_backprop (gcc::context *ctxt)
96563aace61Smrg {
96663aace61Smrg return new pass_backprop (ctxt);
96763aace61Smrg }
968