138fd1498Szrj /* Back-propagation of usage information to definitions.
238fd1498Szrj Copyright (C) 2015-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify
738fd1498Szrj it under the terms of the GNU General Public License as published by
838fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
938fd1498Szrj any later version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful,
1238fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1338fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1438fd1498Szrj GNU General Public License for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj /* This pass propagates information that is common to all uses of an SSA
2138fd1498Szrj name back up through the sequence of statements that generate it,
2238fd1498Szrj simplifying the statements where possible. Sometimes this can expose
2338fd1498Szrj fully or partially dead code, but the main focus is simplifying
2438fd1498Szrj computations.
2538fd1498Szrj
2638fd1498Szrj At the moment the pass only handles one piece of information: whether the
2738fd1498Szrj sign of a value matters, and therefore whether sign-changing operations
2838fd1498Szrj can be skipped. The pass could be extended to more interesting
2938fd1498Szrj information in future, such as which bits of an integer are significant.
3038fd1498Szrj
3138fd1498Szrj For example, take the function:
3238fd1498Szrj
3338fd1498Szrj double
3438fd1498Szrj f (double *a, int n, double start)
3538fd1498Szrj {
3638fd1498Szrj double x = fabs (start);
3738fd1498Szrj for (int i = 0; i < n; ++i)
3838fd1498Szrj x *= a[i];
3938fd1498Szrj return __builtin_cos (x);
4038fd1498Szrj }
4138fd1498Szrj
4238fd1498Szrj cos(x) == cos(-x), so the sign of the final x doesn't matter.
4338fd1498Szrj That x is the result of a series of multiplications, and if
4438fd1498Szrj the sign of the result of a multiplication doesn't matter,
4538fd1498Szrj the signs of the inputs don't matter either.
4638fd1498Szrj
4738fd1498Szrj The pass would replace the incoming value of x (i.e. fabs(start))
4838fd1498Szrj with start. Since there are no other uses of the fabs result,
4938fd1498Szrj the call would get deleted as dead.
5038fd1498Szrj
5138fd1498Szrj The algorithm is:
5238fd1498Szrj
5338fd1498Szrj (1) Do a post-order traversal of the blocks in the function, walking
5438fd1498Szrj each block backwards. For each potentially-simplifiable statement
5538fd1498Szrj that defines an SSA name X, examine all uses of X to see what
5638fd1498Szrj information is actually significant. Record this as INFO_MAP[X].
5738fd1498Szrj Optimistically ignore for now any back-edge references to
5838fd1498Szrj unprocessed phis.
5938fd1498Szrj
6038fd1498Szrj (An alternative would be to record each use when we visit its
6138fd1498Szrj statement and take the intersection as we go along. However,
6238fd1498Szrj this would lead to more SSA names being entered into INFO_MAP
6338fd1498Szrj unnecessarily, only to be taken out again later. At the moment
6438fd1498Szrj very few SSA names end up with useful information.)
6538fd1498Szrj
6638fd1498Szrj (2) Iteratively reduce the optimistic result of (1) until we reach
6738fd1498Szrj a maximal fixed point (which at the moment would mean revisiting
6838fd1498Szrj statements at most once). First push all SSA names that used an
6938fd1498Szrj optimistic assumption about a backedge phi onto a worklist.
7038fd1498Szrj While the worklist is nonempty, pick off an SSA name X and recompute
7138fd1498Szrj INFO_MAP[X]. If the value changes, push all SSA names used in the
7238fd1498Szrj definition of X onto the worklist.
7338fd1498Szrj
7438fd1498Szrj (3) Iterate over each SSA name X with info in INFO_MAP, in the
7538fd1498Szrj opposite order to (1), i.e. a forward reverse-post-order walk.
7638fd1498Szrj Try to optimize the definition of X using INFO_MAP[X] and fold
7738fd1498Szrj the result. (This ensures that we fold definitions before uses.)
7838fd1498Szrj
7938fd1498Szrj (4) Iterate over each SSA name X with info in INFO_MAP, in the same
8038fd1498Szrj order as (1), and delete any statements that are now dead.
8138fd1498Szrj (This ensures that if a sequence of statements is dead,
8238fd1498Szrj we delete the last statement first.)
8338fd1498Szrj
8438fd1498Szrj Note that this pass does not deal with direct redundancies,
8538fd1498Szrj such as cos(-x)->cos(x). match.pd handles those cases instead. */
8638fd1498Szrj
8738fd1498Szrj #include "config.h"
8838fd1498Szrj #include "system.h"
8938fd1498Szrj #include "coretypes.h"
9038fd1498Szrj #include "backend.h"
9138fd1498Szrj #include "tree.h"
9238fd1498Szrj #include "gimple.h"
9338fd1498Szrj #include "gimple-iterator.h"
9438fd1498Szrj #include "ssa.h"
9538fd1498Szrj #include "fold-const.h"
9638fd1498Szrj #include "tree-pass.h"
9738fd1498Szrj #include "cfganal.h"
9838fd1498Szrj #include "gimple-pretty-print.h"
9938fd1498Szrj #include "tree-cfg.h"
10038fd1498Szrj #include "tree-ssa.h"
10138fd1498Szrj #include "tree-ssa-propagate.h"
10238fd1498Szrj #include "gimple-fold.h"
10338fd1498Szrj #include "alloc-pool.h"
10438fd1498Szrj #include "tree-hash-traits.h"
10538fd1498Szrj #include "case-cfn-macros.h"
10638fd1498Szrj
10738fd1498Szrj namespace {
10838fd1498Szrj
10938fd1498Szrj /* Information about a group of uses of an SSA name. */
11038fd1498Szrj struct usage_info
11138fd1498Szrj {
usage_infousage_info11238fd1498Szrj usage_info () : flag_word (0) {}
11338fd1498Szrj usage_info &operator &= (const usage_info &);
11438fd1498Szrj usage_info operator & (const usage_info &) const;
11538fd1498Szrj bool operator == (const usage_info &) const;
11638fd1498Szrj bool operator != (const usage_info &) const;
11738fd1498Szrj bool is_useful () const;
11838fd1498Szrj
11938fd1498Szrj static usage_info intersection_identity ();
12038fd1498Szrj
12138fd1498Szrj union
12238fd1498Szrj {
12338fd1498Szrj struct
12438fd1498Szrj {
12538fd1498Szrj /* True if the uses treat x and -x in the same way. */
12638fd1498Szrj unsigned int ignore_sign : 1;
12738fd1498Szrj } flags;
12838fd1498Szrj /* All the flag bits as a single int. */
12938fd1498Szrj unsigned int flag_word;
13038fd1498Szrj };
13138fd1498Szrj };
13238fd1498Szrj
13338fd1498Szrj /* Return an X such that X & Y == Y for all Y. This is the most
13438fd1498Szrj optimistic assumption possible. */
13538fd1498Szrj
13638fd1498Szrj usage_info
intersection_identity()13738fd1498Szrj usage_info::intersection_identity ()
13838fd1498Szrj {
13938fd1498Szrj usage_info ret;
14038fd1498Szrj ret.flag_word = -1;
14138fd1498Szrj return ret;
14238fd1498Szrj }
14338fd1498Szrj
14438fd1498Szrj /* Intersect *THIS with OTHER, so that *THIS describes all uses covered
14538fd1498Szrj by the original *THIS and OTHER. */
14638fd1498Szrj
14738fd1498Szrj usage_info &
14838fd1498Szrj usage_info::operator &= (const usage_info &other)
14938fd1498Szrj {
15038fd1498Szrj flag_word &= other.flag_word;
15138fd1498Szrj return *this;
15238fd1498Szrj }
15338fd1498Szrj
15438fd1498Szrj /* Return the intersection of *THIS and OTHER, i.e. a structure that
15538fd1498Szrj describes all uses covered by *THIS and OTHER. */
15638fd1498Szrj
15738fd1498Szrj usage_info
15838fd1498Szrj usage_info::operator & (const usage_info &other) const
15938fd1498Szrj {
16038fd1498Szrj usage_info info (*this);
16138fd1498Szrj info &= other;
16238fd1498Szrj return info;
16338fd1498Szrj }
16438fd1498Szrj
16538fd1498Szrj bool
16638fd1498Szrj usage_info::operator == (const usage_info &other) const
16738fd1498Szrj {
16838fd1498Szrj return flag_word == other.flag_word;
16938fd1498Szrj }
17038fd1498Szrj
17138fd1498Szrj bool
17238fd1498Szrj usage_info::operator != (const usage_info &other) const
17338fd1498Szrj {
17438fd1498Szrj return !operator == (other);
17538fd1498Szrj }
17638fd1498Szrj
17738fd1498Szrj /* Return true if *THIS is not simply the default, safe assumption. */
17838fd1498Szrj
17938fd1498Szrj bool
is_useful()18038fd1498Szrj usage_info::is_useful () const
18138fd1498Szrj {
18238fd1498Szrj return flag_word != 0;
18338fd1498Szrj }
18438fd1498Szrj
18538fd1498Szrj /* Start a dump line about SSA name VAR. */
18638fd1498Szrj
18738fd1498Szrj static void
dump_usage_prefix(FILE * file,tree var)18838fd1498Szrj dump_usage_prefix (FILE *file, tree var)
18938fd1498Szrj {
19038fd1498Szrj fprintf (file, " ");
19138fd1498Szrj print_generic_expr (file, var);
19238fd1498Szrj fprintf (file, ": ");
19338fd1498Szrj }
19438fd1498Szrj
19538fd1498Szrj /* Print INFO to FILE. */
19638fd1498Szrj
19738fd1498Szrj static void
dump_usage_info(FILE * file,tree var,usage_info * info)19838fd1498Szrj dump_usage_info (FILE *file, tree var, usage_info *info)
19938fd1498Szrj {
20038fd1498Szrj if (info->flags.ignore_sign)
20138fd1498Szrj {
20238fd1498Szrj dump_usage_prefix (file, var);
20338fd1498Szrj fprintf (file, "sign bit not important\n");
20438fd1498Szrj }
20538fd1498Szrj }
20638fd1498Szrj
20738fd1498Szrj /* Represents one execution of the pass. */
20838fd1498Szrj class backprop
20938fd1498Szrj {
21038fd1498Szrj public:
21138fd1498Szrj backprop (function *);
21238fd1498Szrj ~backprop ();
21338fd1498Szrj
21438fd1498Szrj void execute ();
21538fd1498Szrj
21638fd1498Szrj private:
21738fd1498Szrj const usage_info *lookup_operand (tree);
21838fd1498Szrj
21938fd1498Szrj void push_to_worklist (tree);
22038fd1498Szrj tree pop_from_worklist ();
22138fd1498Szrj
22238fd1498Szrj void process_builtin_call_use (gcall *, tree, usage_info *);
22338fd1498Szrj void process_assign_use (gassign *, tree, usage_info *);
22438fd1498Szrj void process_phi_use (gphi *, usage_info *);
22538fd1498Szrj void process_use (gimple *, tree, usage_info *);
22638fd1498Szrj bool intersect_uses (tree, usage_info *);
22738fd1498Szrj void reprocess_inputs (gimple *);
22838fd1498Szrj void process_var (tree);
22938fd1498Szrj void process_block (basic_block);
23038fd1498Szrj
23138fd1498Szrj void prepare_change (tree);
23238fd1498Szrj void complete_change (gimple *);
23338fd1498Szrj void optimize_builtin_call (gcall *, tree, const usage_info *);
23438fd1498Szrj void replace_assign_rhs (gassign *, tree, tree, tree, tree);
23538fd1498Szrj void optimize_assign (gassign *, tree, const usage_info *);
23638fd1498Szrj void optimize_phi (gphi *, tree, const usage_info *);
23738fd1498Szrj
23838fd1498Szrj typedef hash_map <tree_ssa_name_hash, usage_info *> info_map_type;
23938fd1498Szrj typedef std::pair <tree, usage_info *> var_info_pair;
24038fd1498Szrj
24138fd1498Szrj /* The function we're optimizing. */
24238fd1498Szrj function *m_fn;
24338fd1498Szrj
24438fd1498Szrj /* Pool for allocating usage_info structures. */
24538fd1498Szrj object_allocator <usage_info> m_info_pool;
24638fd1498Szrj
24738fd1498Szrj /* Maps an SSA name to a description of all uses of that SSA name.
24838fd1498Szrj All the usage_infos satisfy is_useful.
24938fd1498Szrj
25038fd1498Szrj We use a hash_map because the map is expected to be sparse
25138fd1498Szrj (i.e. most SSA names won't have useful information attached to them).
25238fd1498Szrj We could move to a directly-indexed array if that situation changes. */
25338fd1498Szrj info_map_type m_info_map;
25438fd1498Szrj
25538fd1498Szrj /* Post-ordered list of all potentially-interesting SSA names,
25638fd1498Szrj along with information that describes all uses. */
25738fd1498Szrj auto_vec <var_info_pair, 128> m_vars;
25838fd1498Szrj
25938fd1498Szrj /* A bitmap of blocks that we have finished processing in the initial
26038fd1498Szrj post-order walk. */
26138fd1498Szrj auto_sbitmap m_visited_blocks;
26238fd1498Szrj
263*58e805e6Szrj /* A bitmap of phis that we have finished processing in the initial
264*58e805e6Szrj post-order walk, excluding those from blocks mentioned in
265*58e805e6Szrj M_VISITED_BLOCKS. */
266*58e805e6Szrj auto_bitmap m_visited_phis;
267*58e805e6Szrj
26838fd1498Szrj /* A worklist of SSA names whose definitions need to be reconsidered. */
26938fd1498Szrj auto_vec <tree, 64> m_worklist;
27038fd1498Szrj
27138fd1498Szrj /* The SSA names in M_WORKLIST, identified by their SSA_NAME_VERSION.
27238fd1498Szrj We use a bitmap rather than an sbitmap because most SSA names are
27338fd1498Szrj never added to the worklist. */
27438fd1498Szrj bitmap m_worklist_names;
27538fd1498Szrj };
27638fd1498Szrj
backprop(function * fn)27738fd1498Szrj backprop::backprop (function *fn)
27838fd1498Szrj : m_fn (fn),
27938fd1498Szrj m_info_pool ("usage_info"),
28038fd1498Szrj m_visited_blocks (last_basic_block_for_fn (m_fn)),
28138fd1498Szrj m_worklist_names (BITMAP_ALLOC (NULL))
28238fd1498Szrj {
28338fd1498Szrj bitmap_clear (m_visited_blocks);
28438fd1498Szrj }
28538fd1498Szrj
~backprop()28638fd1498Szrj backprop::~backprop ()
28738fd1498Szrj {
28838fd1498Szrj BITMAP_FREE (m_worklist_names);
28938fd1498Szrj m_info_pool.release ();
29038fd1498Szrj }
29138fd1498Szrj
29238fd1498Szrj /* Return usage information for general operand OP, or null if none. */
29338fd1498Szrj
29438fd1498Szrj const usage_info *
lookup_operand(tree op)29538fd1498Szrj backprop::lookup_operand (tree op)
29638fd1498Szrj {
29738fd1498Szrj if (op && TREE_CODE (op) == SSA_NAME)
29838fd1498Szrj {
29938fd1498Szrj usage_info **slot = m_info_map.get (op);
30038fd1498Szrj if (slot)
30138fd1498Szrj return *slot;
30238fd1498Szrj }
30338fd1498Szrj return NULL;
30438fd1498Szrj }
30538fd1498Szrj
30638fd1498Szrj /* Add SSA name VAR to the worklist, if it isn't on the worklist already. */
30738fd1498Szrj
30838fd1498Szrj void
push_to_worklist(tree var)30938fd1498Szrj backprop::push_to_worklist (tree var)
31038fd1498Szrj {
31138fd1498Szrj if (!bitmap_set_bit (m_worklist_names, SSA_NAME_VERSION (var)))
31238fd1498Szrj return;
31338fd1498Szrj m_worklist.safe_push (var);
31438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
31538fd1498Szrj {
31638fd1498Szrj fprintf (dump_file, "[WORKLIST] Pushing ");
31738fd1498Szrj print_generic_expr (dump_file, var);
31838fd1498Szrj fprintf (dump_file, "\n");
31938fd1498Szrj }
32038fd1498Szrj }
32138fd1498Szrj
32238fd1498Szrj /* Remove and return the next SSA name from the worklist. The worklist
32338fd1498Szrj is known to be nonempty. */
32438fd1498Szrj
32538fd1498Szrj tree
pop_from_worklist()32638fd1498Szrj backprop::pop_from_worklist ()
32738fd1498Szrj {
32838fd1498Szrj tree var = m_worklist.pop ();
32938fd1498Szrj bitmap_clear_bit (m_worklist_names, SSA_NAME_VERSION (var));
33038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
33138fd1498Szrj {
33238fd1498Szrj fprintf (dump_file, "[WORKLIST] Popping ");
33338fd1498Szrj print_generic_expr (dump_file, var);
33438fd1498Szrj fprintf (dump_file, "\n");
33538fd1498Szrj }
33638fd1498Szrj return var;
33738fd1498Szrj }
33838fd1498Szrj
33938fd1498Szrj /* Make INFO describe all uses of RHS in CALL, which is a call to a
34038fd1498Szrj built-in function. */
34138fd1498Szrj
34238fd1498Szrj void
process_builtin_call_use(gcall * call,tree rhs,usage_info * info)34338fd1498Szrj backprop::process_builtin_call_use (gcall *call, tree rhs, usage_info *info)
34438fd1498Szrj {
34538fd1498Szrj combined_fn fn = gimple_call_combined_fn (call);
34638fd1498Szrj tree lhs = gimple_call_lhs (call);
34738fd1498Szrj switch (fn)
34838fd1498Szrj {
34938fd1498Szrj case CFN_LAST:
35038fd1498Szrj break;
35138fd1498Szrj
35238fd1498Szrj CASE_CFN_COS:
35338fd1498Szrj CASE_CFN_COSH:
35438fd1498Szrj CASE_CFN_CCOS:
35538fd1498Szrj CASE_CFN_CCOSH:
35638fd1498Szrj CASE_CFN_HYPOT:
35738fd1498Szrj /* The signs of all inputs are ignored. */
35838fd1498Szrj info->flags.ignore_sign = true;
35938fd1498Szrj break;
36038fd1498Szrj
36138fd1498Szrj CASE_CFN_COPYSIGN:
36238fd1498Szrj CASE_CFN_COPYSIGN_FN:
36338fd1498Szrj /* The sign of the first input is ignored. */
36438fd1498Szrj if (rhs != gimple_call_arg (call, 1))
36538fd1498Szrj info->flags.ignore_sign = true;
36638fd1498Szrj break;
36738fd1498Szrj
36838fd1498Szrj CASE_CFN_POW:
36938fd1498Szrj {
37038fd1498Szrj /* The sign of the first input is ignored as long as the second
37138fd1498Szrj input is an even real. */
37238fd1498Szrj tree power = gimple_call_arg (call, 1);
37338fd1498Szrj HOST_WIDE_INT n;
37438fd1498Szrj if (TREE_CODE (power) == REAL_CST
37538fd1498Szrj && real_isinteger (&TREE_REAL_CST (power), &n)
37638fd1498Szrj && (n & 1) == 0)
37738fd1498Szrj info->flags.ignore_sign = true;
37838fd1498Szrj break;
37938fd1498Szrj }
38038fd1498Szrj
38138fd1498Szrj CASE_CFN_FMA:
38238fd1498Szrj CASE_CFN_FMA_FN:
38338fd1498Szrj /* In X * X + Y, where Y is distinct from X, the sign of X doesn't
38438fd1498Szrj matter. */
38538fd1498Szrj if (gimple_call_arg (call, 0) == rhs
38638fd1498Szrj && gimple_call_arg (call, 1) == rhs
38738fd1498Szrj && gimple_call_arg (call, 2) != rhs)
38838fd1498Szrj info->flags.ignore_sign = true;
38938fd1498Szrj break;
39038fd1498Szrj
39138fd1498Szrj default:
39238fd1498Szrj if (negate_mathfn_p (fn))
39338fd1498Szrj {
39438fd1498Szrj /* The sign of the (single) input doesn't matter provided
39538fd1498Szrj that the sign of the output doesn't matter. */
39638fd1498Szrj const usage_info *lhs_info = lookup_operand (lhs);
39738fd1498Szrj if (lhs_info)
39838fd1498Szrj info->flags.ignore_sign = lhs_info->flags.ignore_sign;
39938fd1498Szrj }
40038fd1498Szrj break;
40138fd1498Szrj }
40238fd1498Szrj }
40338fd1498Szrj
40438fd1498Szrj /* Make INFO describe all uses of RHS in ASSIGN. */
40538fd1498Szrj
40638fd1498Szrj void
process_assign_use(gassign * assign,tree rhs,usage_info * info)40738fd1498Szrj backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info)
40838fd1498Szrj {
40938fd1498Szrj tree lhs = gimple_assign_lhs (assign);
41038fd1498Szrj switch (gimple_assign_rhs_code (assign))
41138fd1498Szrj {
41238fd1498Szrj case ABS_EXPR:
41338fd1498Szrj /* The sign of the input doesn't matter. */
41438fd1498Szrj info->flags.ignore_sign = true;
41538fd1498Szrj break;
41638fd1498Szrj
41738fd1498Szrj case COND_EXPR:
41838fd1498Szrj /* For A = B ? C : D, propagate information about all uses of A
41938fd1498Szrj to C and D. */
42038fd1498Szrj if (rhs != gimple_assign_rhs1 (assign))
42138fd1498Szrj {
42238fd1498Szrj const usage_info *lhs_info = lookup_operand (lhs);
42338fd1498Szrj if (lhs_info)
42438fd1498Szrj *info = *lhs_info;
42538fd1498Szrj }
42638fd1498Szrj break;
42738fd1498Szrj
42838fd1498Szrj case FMA_EXPR:
42938fd1498Szrj /* In X * X + Y, where Y is distinct from X, the sign of X doesn't
43038fd1498Szrj matter. */
43138fd1498Szrj if (gimple_assign_rhs1 (assign) == rhs
43238fd1498Szrj && gimple_assign_rhs2 (assign) == rhs
43338fd1498Szrj && gimple_assign_rhs3 (assign) != rhs)
43438fd1498Szrj info->flags.ignore_sign = true;
43538fd1498Szrj break;
43638fd1498Szrj
43738fd1498Szrj case MULT_EXPR:
43838fd1498Szrj /* In X * X, the sign of X doesn't matter. */
43938fd1498Szrj if (gimple_assign_rhs1 (assign) == rhs
44038fd1498Szrj && gimple_assign_rhs2 (assign) == rhs)
44138fd1498Szrj info->flags.ignore_sign = true;
44238fd1498Szrj /* Fall through. */
44338fd1498Szrj
44438fd1498Szrj case NEGATE_EXPR:
44538fd1498Szrj case RDIV_EXPR:
44638fd1498Szrj /* If the sign of the result doesn't matter, the sign of the inputs
44738fd1498Szrj doesn't matter either. */
44838fd1498Szrj if (FLOAT_TYPE_P (TREE_TYPE (rhs)))
44938fd1498Szrj {
45038fd1498Szrj const usage_info *lhs_info = lookup_operand (lhs);
45138fd1498Szrj if (lhs_info)
45238fd1498Szrj info->flags.ignore_sign = lhs_info->flags.ignore_sign;
45338fd1498Szrj }
45438fd1498Szrj break;
45538fd1498Szrj
45638fd1498Szrj default:
45738fd1498Szrj break;
45838fd1498Szrj }
45938fd1498Szrj }
46038fd1498Szrj
46138fd1498Szrj /* Make INFO describe the uses of PHI's result. */
46238fd1498Szrj
46338fd1498Szrj void
process_phi_use(gphi * phi,usage_info * info)46438fd1498Szrj backprop::process_phi_use (gphi *phi, usage_info *info)
46538fd1498Szrj {
46638fd1498Szrj tree result = gimple_phi_result (phi);
46738fd1498Szrj if (const usage_info *result_info = lookup_operand (result))
46838fd1498Szrj *info = *result_info;
46938fd1498Szrj }
47038fd1498Szrj
47138fd1498Szrj /* Make INFO describe all uses of RHS in STMT. */
47238fd1498Szrj
47338fd1498Szrj void
process_use(gimple * stmt,tree rhs,usage_info * info)47438fd1498Szrj backprop::process_use (gimple *stmt, tree rhs, usage_info *info)
47538fd1498Szrj {
47638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
47738fd1498Szrj {
47838fd1498Szrj fprintf (dump_file, "[USE] ");
47938fd1498Szrj print_generic_expr (dump_file, rhs);
48038fd1498Szrj fprintf (dump_file, " in ");
48138fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
48238fd1498Szrj }
48338fd1498Szrj
48438fd1498Szrj if (gcall *call = dyn_cast <gcall *> (stmt))
48538fd1498Szrj process_builtin_call_use (call, rhs, info);
48638fd1498Szrj else if (gassign *assign = dyn_cast <gassign *> (stmt))
48738fd1498Szrj process_assign_use (assign, rhs, info);
48838fd1498Szrj else if (gphi *phi = dyn_cast <gphi *> (stmt))
48938fd1498Szrj process_phi_use (phi, info);
49038fd1498Szrj
49138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
49238fd1498Szrj dump_usage_info (dump_file, rhs, info);
49338fd1498Szrj }
49438fd1498Szrj
49538fd1498Szrj /* Make INFO describe all uses of VAR, returning true if the result
49638fd1498Szrj is useful. If the uses include phis that haven't been processed yet,
49738fd1498Szrj make the most optimistic assumption possible, so that we aim for
49838fd1498Szrj a maximum rather than a minimum fixed point. */
49938fd1498Szrj
50038fd1498Szrj bool
intersect_uses(tree var,usage_info * info)50138fd1498Szrj backprop::intersect_uses (tree var, usage_info *info)
50238fd1498Szrj {
50338fd1498Szrj imm_use_iterator iter;
504*58e805e6Szrj use_operand_p use_p;
50538fd1498Szrj *info = usage_info::intersection_identity ();
506*58e805e6Szrj FOR_EACH_IMM_USE_FAST (use_p, iter, var)
50738fd1498Szrj {
508*58e805e6Szrj gimple *stmt = USE_STMT (use_p);
50938fd1498Szrj if (is_gimple_debug (stmt))
51038fd1498Szrj continue;
511*58e805e6Szrj gphi *phi = dyn_cast <gphi *> (stmt);
512*58e805e6Szrj if (phi
513*58e805e6Szrj && !bitmap_bit_p (m_visited_blocks, gimple_bb (phi)->index)
514*58e805e6Szrj && !bitmap_bit_p (m_visited_phis,
515*58e805e6Szrj SSA_NAME_VERSION (gimple_phi_result (phi))))
51638fd1498Szrj {
51738fd1498Szrj /* Skip unprocessed phis. */
51838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
51938fd1498Szrj {
52038fd1498Szrj fprintf (dump_file, "[BACKEDGE] ");
52138fd1498Szrj print_generic_expr (dump_file, var);
52238fd1498Szrj fprintf (dump_file, " in ");
523*58e805e6Szrj print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
52438fd1498Szrj }
52538fd1498Szrj }
52638fd1498Szrj else
52738fd1498Szrj {
52838fd1498Szrj usage_info subinfo;
52938fd1498Szrj process_use (stmt, var, &subinfo);
53038fd1498Szrj *info &= subinfo;
53138fd1498Szrj if (!info->is_useful ())
53238fd1498Szrj return false;
53338fd1498Szrj }
53438fd1498Szrj }
53538fd1498Szrj return true;
53638fd1498Szrj }
53738fd1498Szrj
53838fd1498Szrj /* Queue for reconsideration any input of STMT that has information
53938fd1498Szrj associated with it. This is used if that information might be
54038fd1498Szrj too optimistic. */
54138fd1498Szrj
54238fd1498Szrj void
reprocess_inputs(gimple * stmt)54338fd1498Szrj backprop::reprocess_inputs (gimple *stmt)
54438fd1498Szrj {
54538fd1498Szrj use_operand_p use_p;
54638fd1498Szrj ssa_op_iter oi;
54738fd1498Szrj FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, oi, SSA_OP_USE)
54838fd1498Szrj {
54938fd1498Szrj tree var = get_use_from_ptr (use_p);
55038fd1498Szrj if (lookup_operand (var))
55138fd1498Szrj push_to_worklist (var);
55238fd1498Szrj }
55338fd1498Szrj }
55438fd1498Szrj
55538fd1498Szrj /* Say that we're recording INFO for SSA name VAR, or that we're deleting
55638fd1498Szrj existing information if INFO is null. INTRO describes the change. */
55738fd1498Szrj
55838fd1498Szrj static void
dump_var_info(tree var,usage_info * info,const char * intro)55938fd1498Szrj dump_var_info (tree var, usage_info *info, const char *intro)
56038fd1498Szrj {
56138fd1498Szrj fprintf (dump_file, "[DEF] %s for ", intro);
56238fd1498Szrj print_gimple_stmt (dump_file, SSA_NAME_DEF_STMT (var), 0, TDF_SLIM);
56338fd1498Szrj if (info)
56438fd1498Szrj dump_usage_info (dump_file, var, info);
56538fd1498Szrj }
56638fd1498Szrj
56738fd1498Szrj /* Process all uses of VAR and record or update the result in
56838fd1498Szrj M_INFO_MAP and M_VARS. */
56938fd1498Szrj
57038fd1498Szrj void
process_var(tree var)57138fd1498Szrj backprop::process_var (tree var)
57238fd1498Szrj {
57338fd1498Szrj if (has_zero_uses (var))
57438fd1498Szrj return;
57538fd1498Szrj
57638fd1498Szrj usage_info info;
57738fd1498Szrj intersect_uses (var, &info);
57838fd1498Szrj
57938fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (var);
58038fd1498Szrj if (info.is_useful ())
58138fd1498Szrj {
58238fd1498Szrj bool existed;
58338fd1498Szrj usage_info *&map_info = m_info_map.get_or_insert (var, &existed);
58438fd1498Szrj if (!existed)
58538fd1498Szrj {
58638fd1498Szrj /* Recording information about VAR for the first time. */
58738fd1498Szrj map_info = m_info_pool.allocate ();
58838fd1498Szrj *map_info = info;
58938fd1498Szrj m_vars.safe_push (var_info_pair (var, map_info));
59038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
59138fd1498Szrj dump_var_info (var, map_info, "Recording new information");
59238fd1498Szrj
59338fd1498Szrj /* If STMT is a phi, reprocess any backedge uses. This is a
59438fd1498Szrj no-op for other uses, which won't have any information
59538fd1498Szrj associated with them. */
59638fd1498Szrj if (is_a <gphi *> (stmt))
59738fd1498Szrj reprocess_inputs (stmt);
59838fd1498Szrj }
59938fd1498Szrj else if (info != *map_info)
60038fd1498Szrj {
60138fd1498Szrj /* Recording information that is less optimistic than before. */
60238fd1498Szrj gcc_checking_assert ((info & *map_info) == info);
60338fd1498Szrj *map_info = info;
60438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
60538fd1498Szrj dump_var_info (var, map_info, "Updating information");
60638fd1498Szrj reprocess_inputs (stmt);
60738fd1498Szrj }
60838fd1498Szrj }
60938fd1498Szrj else
61038fd1498Szrj {
61138fd1498Szrj if (usage_info **slot = m_info_map.get (var))
61238fd1498Szrj {
61338fd1498Szrj /* Removing previously-recorded information. */
61438fd1498Szrj **slot = info;
61538fd1498Szrj m_info_map.remove (var);
61638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
61738fd1498Szrj dump_var_info (var, NULL, "Deleting information");
61838fd1498Szrj reprocess_inputs (stmt);
61938fd1498Szrj }
62038fd1498Szrj else
62138fd1498Szrj {
62238fd1498Szrj /* If STMT is a phi, remove any information recorded for
62338fd1498Szrj its arguments. */
62438fd1498Szrj if (is_a <gphi *> (stmt))
62538fd1498Szrj reprocess_inputs (stmt);
62638fd1498Szrj }
62738fd1498Szrj }
62838fd1498Szrj }
62938fd1498Szrj
63038fd1498Szrj /* Process all statements and phis in BB, during the first post-order walk. */
63138fd1498Szrj
63238fd1498Szrj void
process_block(basic_block bb)63338fd1498Szrj backprop::process_block (basic_block bb)
63438fd1498Szrj {
63538fd1498Szrj for (gimple_stmt_iterator gsi = gsi_last_bb (bb); !gsi_end_p (gsi);
63638fd1498Szrj gsi_prev (&gsi))
63738fd1498Szrj {
63838fd1498Szrj tree lhs = gimple_get_lhs (gsi_stmt (gsi));
63938fd1498Szrj if (lhs && TREE_CODE (lhs) == SSA_NAME)
64038fd1498Szrj process_var (lhs);
64138fd1498Szrj }
64238fd1498Szrj for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
64338fd1498Szrj gsi_next (&gpi))
644*58e805e6Szrj {
645*58e805e6Szrj tree result = gimple_phi_result (gpi.phi ());
646*58e805e6Szrj process_var (result);
647*58e805e6Szrj bitmap_set_bit (m_visited_phis, SSA_NAME_VERSION (result));
648*58e805e6Szrj }
649*58e805e6Szrj bitmap_clear (m_visited_phis);
65038fd1498Szrj }
65138fd1498Szrj
65238fd1498Szrj /* Delete the definition of VAR, which has no uses. */
65338fd1498Szrj
65438fd1498Szrj static void
remove_unused_var(tree var)65538fd1498Szrj remove_unused_var (tree var)
65638fd1498Szrj {
65738fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (var);
65838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
65938fd1498Szrj {
66038fd1498Szrj fprintf (dump_file, "Deleting ");
66138fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
66238fd1498Szrj }
66338fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
66438fd1498Szrj gsi_remove (&gsi, true);
66538fd1498Szrj release_defs (stmt);
66638fd1498Szrj }
66738fd1498Szrj
66838fd1498Szrj /* Note that we're replacing OLD_RHS with NEW_RHS in STMT. */
66938fd1498Szrj
67038fd1498Szrj static void
note_replacement(gimple * stmt,tree old_rhs,tree new_rhs)67138fd1498Szrj note_replacement (gimple *stmt, tree old_rhs, tree new_rhs)
67238fd1498Szrj {
67338fd1498Szrj fprintf (dump_file, "Replacing use of ");
67438fd1498Szrj print_generic_expr (dump_file, old_rhs);
67538fd1498Szrj fprintf (dump_file, " with ");
67638fd1498Szrj print_generic_expr (dump_file, new_rhs);
67738fd1498Szrj fprintf (dump_file, " in ");
67838fd1498Szrj print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
67938fd1498Szrj }
68038fd1498Szrj
68138fd1498Szrj /* If RHS is an SSA name whose definition just changes the sign of a value,
68238fd1498Szrj return that other value, otherwise return null. */
68338fd1498Szrj
68438fd1498Szrj static tree
strip_sign_op_1(tree rhs)68538fd1498Szrj strip_sign_op_1 (tree rhs)
68638fd1498Szrj {
68738fd1498Szrj if (TREE_CODE (rhs) != SSA_NAME)
68838fd1498Szrj return NULL_TREE;
68938fd1498Szrj
69038fd1498Szrj gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
69138fd1498Szrj if (gassign *assign = dyn_cast <gassign *> (def_stmt))
69238fd1498Szrj switch (gimple_assign_rhs_code (assign))
69338fd1498Szrj {
69438fd1498Szrj case ABS_EXPR:
69538fd1498Szrj case NEGATE_EXPR:
69638fd1498Szrj return gimple_assign_rhs1 (assign);
69738fd1498Szrj
69838fd1498Szrj default:
69938fd1498Szrj break;
70038fd1498Szrj }
70138fd1498Szrj else if (gcall *call = dyn_cast <gcall *> (def_stmt))
70238fd1498Szrj switch (gimple_call_combined_fn (call))
70338fd1498Szrj {
70438fd1498Szrj CASE_CFN_COPYSIGN:
70538fd1498Szrj CASE_CFN_COPYSIGN_FN:
70638fd1498Szrj return gimple_call_arg (call, 0);
70738fd1498Szrj
70838fd1498Szrj default:
70938fd1498Szrj break;
71038fd1498Szrj }
71138fd1498Szrj
71238fd1498Szrj return NULL_TREE;
71338fd1498Szrj }
71438fd1498Szrj
71538fd1498Szrj /* If RHS is an SSA name whose definition just changes the sign of a value,
71638fd1498Szrj strip all such operations and return the ultimate input to them.
71738fd1498Szrj Return null otherwise.
71838fd1498Szrj
71938fd1498Szrj Although this could in principle lead to quadratic searching,
72038fd1498Szrj in practice a long sequence of sign manipulations should already
72138fd1498Szrj have been folded down. E.g. --x -> x, abs(-x) -> abs(x). We search
72238fd1498Szrj for more than one operation in order to catch cases like -abs(x). */
72338fd1498Szrj
72438fd1498Szrj static tree
strip_sign_op(tree rhs)72538fd1498Szrj strip_sign_op (tree rhs)
72638fd1498Szrj {
72738fd1498Szrj tree new_rhs = strip_sign_op_1 (rhs);
72838fd1498Szrj if (!new_rhs)
72938fd1498Szrj return NULL_TREE;
73038fd1498Szrj while (tree next = strip_sign_op_1 (new_rhs))
73138fd1498Szrj new_rhs = next;
73238fd1498Szrj return new_rhs;
73338fd1498Szrj }
73438fd1498Szrj
73538fd1498Szrj /* Start a change in the value of VAR that is suitable for all non-debug
73638fd1498Szrj uses of VAR. We need to make sure that debug statements continue to
73738fd1498Szrj use the original definition of VAR where possible, or are nullified
73838fd1498Szrj otherwise. */
73938fd1498Szrj
74038fd1498Szrj void
prepare_change(tree var)74138fd1498Szrj backprop::prepare_change (tree var)
74238fd1498Szrj {
74338fd1498Szrj if (MAY_HAVE_DEBUG_BIND_STMTS)
74438fd1498Szrj insert_debug_temp_for_var_def (NULL, var);
74538fd1498Szrj reset_flow_sensitive_info (var);
74638fd1498Szrj }
74738fd1498Szrj
74838fd1498Szrj /* STMT has been changed. Give the fold machinery a chance to simplify
74938fd1498Szrj and canonicalize it (e.g. by ensuring that commutative operands have
75038fd1498Szrj the right order), then record the updates. */
75138fd1498Szrj
75238fd1498Szrj void
complete_change(gimple * stmt)75338fd1498Szrj backprop::complete_change (gimple *stmt)
75438fd1498Szrj {
75538fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
75638fd1498Szrj if (fold_stmt (&gsi))
75738fd1498Szrj {
75838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
75938fd1498Szrj {
76038fd1498Szrj fprintf (dump_file, " which folds to: ");
76138fd1498Szrj print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, TDF_SLIM);
76238fd1498Szrj }
76338fd1498Szrj }
76438fd1498Szrj update_stmt (gsi_stmt (gsi));
76538fd1498Szrj }
76638fd1498Szrj
76738fd1498Szrj /* Optimize CALL, a call to a built-in function with lhs LHS, on the
76838fd1498Szrj basis that INFO describes all uses of LHS. */
76938fd1498Szrj
77038fd1498Szrj void
optimize_builtin_call(gcall * call,tree lhs,const usage_info * info)77138fd1498Szrj backprop::optimize_builtin_call (gcall *call, tree lhs, const usage_info *info)
77238fd1498Szrj {
77338fd1498Szrj /* If we have an f such that -f(x) = f(-x), and if the sign of the result
77438fd1498Szrj doesn't matter, strip any sign operations from the input. */
77538fd1498Szrj if (info->flags.ignore_sign
77638fd1498Szrj && negate_mathfn_p (gimple_call_combined_fn (call)))
77738fd1498Szrj {
77838fd1498Szrj tree new_arg = strip_sign_op (gimple_call_arg (call, 0));
77938fd1498Szrj if (new_arg)
78038fd1498Szrj {
78138fd1498Szrj prepare_change (lhs);
78238fd1498Szrj gimple_call_set_arg (call, 0, new_arg);
78338fd1498Szrj complete_change (call);
78438fd1498Szrj }
78538fd1498Szrj }
78638fd1498Szrj }
78738fd1498Szrj
78838fd1498Szrj /* Optimize ASSIGN, an assignment to LHS, by replacing rhs operand N
78938fd1498Szrj with RHS<N>, if RHS<N> is nonnull. This may change the value of LHS. */
79038fd1498Szrj
79138fd1498Szrj void
replace_assign_rhs(gassign * assign,tree lhs,tree rhs1,tree rhs2,tree rhs3)79238fd1498Szrj backprop::replace_assign_rhs (gassign *assign, tree lhs, tree rhs1,
79338fd1498Szrj tree rhs2, tree rhs3)
79438fd1498Szrj {
79538fd1498Szrj if (!rhs1 && !rhs2 && !rhs3)
79638fd1498Szrj return;
79738fd1498Szrj
79838fd1498Szrj prepare_change (lhs);
79938fd1498Szrj if (rhs1)
80038fd1498Szrj gimple_assign_set_rhs1 (assign, rhs1);
80138fd1498Szrj if (rhs2)
80238fd1498Szrj gimple_assign_set_rhs2 (assign, rhs2);
80338fd1498Szrj if (rhs3)
80438fd1498Szrj gimple_assign_set_rhs3 (assign, rhs3);
80538fd1498Szrj complete_change (assign);
80638fd1498Szrj }
80738fd1498Szrj
80838fd1498Szrj /* Optimize ASSIGN, an assignment to LHS, on the basis that INFO
80938fd1498Szrj describes all uses of LHS. */
81038fd1498Szrj
81138fd1498Szrj void
optimize_assign(gassign * assign,tree lhs,const usage_info * info)81238fd1498Szrj backprop::optimize_assign (gassign *assign, tree lhs, const usage_info *info)
81338fd1498Szrj {
81438fd1498Szrj switch (gimple_assign_rhs_code (assign))
81538fd1498Szrj {
81638fd1498Szrj case MULT_EXPR:
81738fd1498Szrj case RDIV_EXPR:
81838fd1498Szrj /* If the sign of the result doesn't matter, strip sign operations
81938fd1498Szrj from both inputs. */
82038fd1498Szrj if (info->flags.ignore_sign)
82138fd1498Szrj replace_assign_rhs (assign, lhs,
82238fd1498Szrj strip_sign_op (gimple_assign_rhs1 (assign)),
82338fd1498Szrj strip_sign_op (gimple_assign_rhs2 (assign)),
82438fd1498Szrj NULL_TREE);
82538fd1498Szrj break;
82638fd1498Szrj
82738fd1498Szrj case COND_EXPR:
82838fd1498Szrj /* If the sign of A ? B : C doesn't matter, strip sign operations
82938fd1498Szrj from both B and C. */
83038fd1498Szrj if (info->flags.ignore_sign)
83138fd1498Szrj replace_assign_rhs (assign, lhs,
83238fd1498Szrj NULL_TREE,
83338fd1498Szrj strip_sign_op (gimple_assign_rhs2 (assign)),
83438fd1498Szrj strip_sign_op (gimple_assign_rhs3 (assign)));
83538fd1498Szrj break;
83638fd1498Szrj
83738fd1498Szrj default:
83838fd1498Szrj break;
83938fd1498Szrj }
84038fd1498Szrj }
84138fd1498Szrj
84238fd1498Szrj /* Optimize PHI, which defines VAR, on the basis that INFO describes all
84338fd1498Szrj uses of the result. */
84438fd1498Szrj
84538fd1498Szrj void
optimize_phi(gphi * phi,tree var,const usage_info * info)84638fd1498Szrj backprop::optimize_phi (gphi *phi, tree var, const usage_info *info)
84738fd1498Szrj {
84838fd1498Szrj /* If the sign of the result doesn't matter, try to strip sign operations
84938fd1498Szrj from arguments. */
85038fd1498Szrj if (info->flags.ignore_sign)
85138fd1498Szrj {
85238fd1498Szrj basic_block bb = gimple_bb (phi);
85338fd1498Szrj use_operand_p use;
85438fd1498Szrj ssa_op_iter oi;
85538fd1498Szrj bool replaced = false;
85638fd1498Szrj FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
85738fd1498Szrj {
85838fd1498Szrj /* Propagating along abnormal edges is delicate, punt for now. */
85938fd1498Szrj const int index = PHI_ARG_INDEX_FROM_USE (use);
86038fd1498Szrj if (EDGE_PRED (bb, index)->flags & EDGE_ABNORMAL)
86138fd1498Szrj continue;
86238fd1498Szrj
86338fd1498Szrj tree new_arg = strip_sign_op (USE_FROM_PTR (use));
86438fd1498Szrj if (new_arg)
86538fd1498Szrj {
86638fd1498Szrj if (!replaced)
86738fd1498Szrj prepare_change (var);
86838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
86938fd1498Szrj note_replacement (phi, USE_FROM_PTR (use), new_arg);
87038fd1498Szrj replace_exp (use, new_arg);
87138fd1498Szrj replaced = true;
87238fd1498Szrj }
87338fd1498Szrj }
87438fd1498Szrj }
87538fd1498Szrj }
87638fd1498Szrj
87738fd1498Szrj void
execute()87838fd1498Szrj backprop::execute ()
87938fd1498Szrj {
88038fd1498Szrj /* Phase 1: Traverse the function, making optimistic assumptions
88138fd1498Szrj about any phi whose definition we haven't seen. */
88238fd1498Szrj int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (m_fn));
88338fd1498Szrj unsigned int postorder_num = post_order_compute (postorder, false, false);
88438fd1498Szrj for (unsigned int i = 0; i < postorder_num; ++i)
88538fd1498Szrj {
88638fd1498Szrj process_block (BASIC_BLOCK_FOR_FN (m_fn, postorder[i]));
88738fd1498Szrj bitmap_set_bit (m_visited_blocks, postorder[i]);
88838fd1498Szrj }
88938fd1498Szrj XDELETEVEC (postorder);
89038fd1498Szrj
89138fd1498Szrj /* Phase 2: Use the initial (perhaps overly optimistic) information
89238fd1498Szrj to create a maximal fixed point solution. */
89338fd1498Szrj while (!m_worklist.is_empty ())
89438fd1498Szrj process_var (pop_from_worklist ());
89538fd1498Szrj
89638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
89738fd1498Szrj fprintf (dump_file, "\n");
89838fd1498Szrj
89938fd1498Szrj /* Phase 3: Do a reverse post-order walk, using information about
90038fd1498Szrj the uses of SSA names to optimize their definitions. */
90138fd1498Szrj for (unsigned int i = m_vars.length (); i-- > 0;)
90238fd1498Szrj {
90338fd1498Szrj usage_info *info = m_vars[i].second;
90438fd1498Szrj if (info->is_useful ())
90538fd1498Szrj {
90638fd1498Szrj tree var = m_vars[i].first;
90738fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (var);
90838fd1498Szrj if (gcall *call = dyn_cast <gcall *> (stmt))
90938fd1498Szrj optimize_builtin_call (call, var, info);
91038fd1498Szrj else if (gassign *assign = dyn_cast <gassign *> (stmt))
91138fd1498Szrj optimize_assign (assign, var, info);
91238fd1498Szrj else if (gphi *phi = dyn_cast <gphi *> (stmt))
91338fd1498Szrj optimize_phi (phi, var, info);
91438fd1498Szrj }
91538fd1498Szrj }
91638fd1498Szrj
91738fd1498Szrj /* Phase 4: Do a post-order walk, deleting statements that are no
91838fd1498Szrj longer needed. */
91938fd1498Szrj for (unsigned int i = 0; i < m_vars.length (); ++i)
92038fd1498Szrj {
92138fd1498Szrj tree var = m_vars[i].first;
92238fd1498Szrj if (has_zero_uses (var))
92338fd1498Szrj remove_unused_var (var);
92438fd1498Szrj }
92538fd1498Szrj
92638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
92738fd1498Szrj fprintf (dump_file, "\n");
92838fd1498Szrj }
92938fd1498Szrj
93038fd1498Szrj const pass_data pass_data_backprop =
93138fd1498Szrj {
93238fd1498Szrj GIMPLE_PASS, /* type */
93338fd1498Szrj "backprop", /* name */
93438fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
93538fd1498Szrj TV_TREE_BACKPROP, /* tv_id */
93638fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
93738fd1498Szrj 0, /* properties_provided */
93838fd1498Szrj 0, /* properties_destroyed */
93938fd1498Szrj 0, /* todo_flags_start */
94038fd1498Szrj 0, /* todo_flags_finish */
94138fd1498Szrj };
94238fd1498Szrj
94338fd1498Szrj class pass_backprop : public gimple_opt_pass
94438fd1498Szrj {
94538fd1498Szrj public:
pass_backprop(gcc::context * ctxt)94638fd1498Szrj pass_backprop (gcc::context *ctxt)
94738fd1498Szrj : gimple_opt_pass (pass_data_backprop, ctxt)
94838fd1498Szrj {}
94938fd1498Szrj
95038fd1498Szrj /* opt_pass methods: */
clone()95138fd1498Szrj opt_pass * clone () { return new pass_backprop (m_ctxt); }
gate(function *)95238fd1498Szrj virtual bool gate (function *) { return flag_ssa_backprop; }
95338fd1498Szrj virtual unsigned int execute (function *);
95438fd1498Szrj
95538fd1498Szrj }; // class pass_backprop
95638fd1498Szrj
95738fd1498Szrj unsigned int
execute(function * fn)95838fd1498Szrj pass_backprop::execute (function *fn)
95938fd1498Szrj {
96038fd1498Szrj backprop (fn).execute ();
96138fd1498Szrj return 0;
96238fd1498Szrj }
96338fd1498Szrj
96438fd1498Szrj } // anon namespace
96538fd1498Szrj
96638fd1498Szrj gimple_opt_pass *
make_pass_backprop(gcc::context * ctxt)96738fd1498Szrj make_pass_backprop (gcc::context *ctxt)
96838fd1498Szrj {
96938fd1498Szrj return new pass_backprop (ctxt);
97038fd1498Szrj }
971