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