xref: /dflybsd-src/contrib/gcc-8.0/gcc/gimple-ssa-backprop.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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