| /* Straight-line strength reduction. | 
 |    Copyright (C) 2012-2025 Free Software Foundation, Inc. | 
 |    Contributed by Bill Schmidt, IBM <wschmidt@linux.ibm.com> | 
 |  | 
 | This file is part of GCC. | 
 |  | 
 | GCC is free software; you can redistribute it and/or modify it under | 
 | the terms of the GNU General Public License as published by the Free | 
 | Software Foundation; either version 3, or (at your option) any later | 
 | version. | 
 |  | 
 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 
 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
 | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
 | for more details. | 
 |  | 
 | You should have received a copy of the GNU General Public License | 
 | along with GCC; see the file COPYING3.  If not see | 
 | <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | /* There are many algorithms for performing strength reduction on | 
 |    loops.  This is not one of them.  IVOPTS handles strength reduction | 
 |    of induction variables just fine.  This pass is intended to pick | 
 |    up the crumbs it leaves behind, by considering opportunities for | 
 |    strength reduction along dominator paths. | 
 |  | 
 |    Strength reduction addresses explicit multiplies, and certain | 
 |    multiplies implicit in addressing expressions.  It would also be | 
 |    possible to apply strength reduction to divisions and modulos, | 
 |    but such opportunities are relatively uncommon. | 
 |  | 
 |    Strength reduction is also currently restricted to integer operations. | 
 |    If desired, it could be extended to floating-point operations under | 
 |    control of something like -funsafe-math-optimizations.  */ | 
 |  | 
 | #include "config.h" | 
 | #include "system.h" | 
 | #include "coretypes.h" | 
 | #include "backend.h" | 
 | #include "rtl.h" | 
 | #include "tree.h" | 
 | #include "gimple.h" | 
 | #include "cfghooks.h" | 
 | #include "tree-pass.h" | 
 | #include "ssa.h" | 
 | #include "expmed.h" | 
 | #include "gimple-pretty-print.h" | 
 | #include "fold-const.h" | 
 | #include "gimple-iterator.h" | 
 | #include "gimplify-me.h" | 
 | #include "stor-layout.h" | 
 | #include "cfgloop.h" | 
 | #include "tree-cfg.h" | 
 | #include "domwalk.h" | 
 | #include "tree-ssa-address.h" | 
 | #include "tree-affine.h" | 
 | #include "tree-eh.h" | 
 | #include "builtins.h" | 
 | #include "tree-ssa-dce.h" | 
 |  | 
 | /* Information about a strength reduction candidate.  Each statement | 
 |    in the candidate table represents an expression of one of the | 
 |    following forms (the special case of CAND_REF will be described | 
 |    later): | 
 |  | 
 |    (CAND_MULT)  S1:  X = (B + i) * S | 
 |    (CAND_ADD)   S1:  X = B + (i * S) | 
 |  | 
 |    Here X and B are SSA names, i is an integer constant, and S is | 
 |    either an SSA name or a constant.  We call B the "base," i the | 
 |    "index", and S the "stride." | 
 |  | 
 |    Any statement S0 that dominates S1 and is of the form: | 
 |  | 
 |    (CAND_MULT)  S0:  Y = (B + i') * S | 
 |    (CAND_ADD)   S0:  Y = B + (i' * S) | 
 |  | 
 |    is called a "basis" for S1.  In both cases, S1 may be replaced by | 
 |  | 
 |                 S1':  X = Y + (i - i') * S, | 
 |  | 
 |    where (i - i') * S is folded to the extent possible. | 
 |  | 
 |    All gimple statements are visited in dominator order, and each | 
 |    statement that may contribute to one of the forms of S1 above is | 
 |    given at least one entry in the candidate table.  Such statements | 
 |    include addition, pointer addition, subtraction, multiplication, | 
 |    negation, copies, and nontrivial type casts.  If a statement may | 
 |    represent more than one expression of the forms of S1 above, | 
 |    multiple "interpretations" are stored in the table and chained | 
 |    together.  Examples: | 
 |  | 
 |    * An add of two SSA names may treat either operand as the base. | 
 |    * A multiply of two SSA names, likewise. | 
 |    * A copy or cast may be thought of as either a CAND_MULT with | 
 |      i = 0 and S = 1, or as a CAND_ADD with i = 0 or S = 0. | 
 |  | 
 |    Candidate records are allocated from an obstack.  They are addressed | 
 |    both from a hash table keyed on S1, and from a vector of candidate | 
 |    pointers arranged in predominator order. | 
 |  | 
 |    Opportunity note | 
 |    ---------------- | 
 |    Currently we don't recognize: | 
 |  | 
 |      S0: Y = (S * i') - B | 
 |      S1: X = (S * i) - B | 
 |  | 
 |    as a strength reduction opportunity, even though this S1 would | 
 |    also be replaceable by the S1' above.  This can be added if it | 
 |    comes up in practice. | 
 |  | 
 |    Strength reduction in addressing | 
 |    -------------------------------- | 
 |    There is another kind of candidate known as CAND_REF.  A CAND_REF | 
 |    describes a statement containing a memory reference having | 
 |    complex addressing that might benefit from strength reduction. | 
 |    Specifically, we are interested in references for which | 
 |    get_inner_reference returns a base address, offset, and bitpos as | 
 |    follows: | 
 |  | 
 |      base:    MEM_REF (T1, C1) | 
 |      offset:  MULT_EXPR (PLUS_EXPR (T2, C2), C3) | 
 |      bitpos:  C4 * BITS_PER_UNIT | 
 |  | 
 |    Here T1 and T2 are arbitrary trees, and C1, C2, C3, C4 are | 
 |    arbitrary integer constants.  Note that C2 may be zero, in which | 
 |    case the offset will be MULT_EXPR (T2, C3). | 
 |  | 
 |    When this pattern is recognized, the original memory reference | 
 |    can be replaced with: | 
 |  | 
 |      MEM_REF (POINTER_PLUS_EXPR (T1, MULT_EXPR (T2, C3)), | 
 |               C1 + (C2 * C3) + C4) | 
 |  | 
 |    which distributes the multiply to allow constant folding.  When | 
 |    two or more addressing expressions can be represented by MEM_REFs | 
 |    of this form, differing only in the constants C1, C2, and C4, | 
 |    making this substitution produces more efficient addressing during | 
 |    the RTL phases.  When there are not at least two expressions with | 
 |    the same values of T1, T2, and C3, there is nothing to be gained | 
 |    by the replacement. | 
 |  | 
 |    Strength reduction of CAND_REFs uses the same infrastructure as | 
 |    that used by CAND_MULTs and CAND_ADDs.  We record T1 in the base (B) | 
 |    field, MULT_EXPR (T2, C3) in the stride (S) field, and | 
 |    C1 + (C2 * C3) + C4 in the index (i) field.  A basis for a CAND_REF | 
 |    is thus another CAND_REF with the same B and S values.  When at | 
 |    least two CAND_REFs are chained together using the basis relation, | 
 |    each of them is replaced as above, resulting in improved code | 
 |    generation for addressing. | 
 |  | 
 |    Conditional candidates | 
 |    ====================== | 
 |  | 
 |    Conditional candidates are best illustrated with an example. | 
 |    Consider the code sequence: | 
 |  | 
 |    (1)  x_0 = ...; | 
 |    (2)  a_0 = x_0 * 5;          MULT (B: x_0; i: 0; S: 5) | 
 |         if (...) | 
 |    (3)    x_1 = x_0 + 1;        ADD  (B: x_0, i: 1; S: 1) | 
 |    (4)  x_2 = PHI <x_0, x_1>;   PHI  (B: x_0, i: 0, S: 1) | 
 |    (5)  x_3 = x_2 + 1;          ADD  (B: x_2, i: 1, S: 1) | 
 |    (6)  a_1 = x_3 * 5;          MULT (B: x_2, i: 1; S: 5) | 
 |  | 
 |    Here strength reduction is complicated by the uncertain value of x_2. | 
 |    A legitimate transformation is: | 
 |  | 
 |    (1)  x_0 = ...; | 
 |    (2)  a_0 = x_0 * 5; | 
 |         if (...) | 
 | 	  { | 
 |    (3)      [x_1 = x_0 + 1;] | 
 |    (3a)     t_1 = a_0 + 5; | 
 |           } | 
 |    (4)  [x_2 = PHI <x_0, x_1>;] | 
 |    (4a) t_2 = PHI <a_0, t_1>; | 
 |    (5)  [x_3 = x_2 + 1;] | 
 |    (6r) a_1 = t_2 + 5; | 
 |  | 
 |    where the bracketed instructions may go dead. | 
 |  | 
 |    To recognize this opportunity, we have to observe that statement (6) | 
 |    has a "hidden basis" (2).  The hidden basis is unlike a normal basis | 
 |    in that the statement and the hidden basis have different base SSA | 
 |    names (x_2 and x_0, respectively).  The relationship is established | 
 |    when a statement's base name (x_2) is defined by a phi statement (4), | 
 |    each argument of which (x_0, x_1) has an identical "derived base name." | 
 |    If the argument is defined by a candidate (as x_1 is by (3)) that is a | 
 |    CAND_ADD having a stride of 1, the derived base name of the argument is | 
 |    the base name of the candidate (x_0).  Otherwise, the argument itself | 
 |    is its derived base name (as is the case with argument x_0). | 
 |  | 
 |    The hidden basis for statement (6) is the nearest dominating candidate | 
 |    whose base name is the derived base name (x_0) of the feeding phi (4), | 
 |    and whose stride is identical to that of the statement.  We can then | 
 |    create the new "phi basis" (4a) and feeding adds along incoming arcs (3a), | 
 |    allowing the final replacement of (6) by the strength-reduced (6r). | 
 |  | 
 |    To facilitate this, a new kind of candidate (CAND_PHI) is introduced. | 
 |    A CAND_PHI is not a candidate for replacement, but is maintained in the | 
 |    candidate table to ease discovery of hidden bases.  Any phi statement | 
 |    whose arguments share a common derived base name is entered into the | 
 |    table with the derived base name, an (arbitrary) index of zero, and a | 
 |    stride of 1.  A statement with a hidden basis can then be detected by | 
 |    simply looking up its feeding phi definition in the candidate table, | 
 |    extracting the derived base name, and searching for a basis in the | 
 |    usual manner after substituting the derived base name. | 
 |  | 
 |    Note that the transformation is only valid when the original phi and | 
 |    the statements that define the phi's arguments are all at the same | 
 |    position in the loop hierarchy.  */ | 
 |  | 
 |  | 
 | /* Index into the candidate vector, offset by 1.  VECs are zero-based, | 
 |    while cand_idx's are one-based, with zero indicating null.  */ | 
 | typedef unsigned cand_idx; | 
 |  | 
 | /* The kind of candidate.  */ | 
 | enum cand_kind | 
 | { | 
 |   CAND_MULT, | 
 |   CAND_ADD, | 
 |   CAND_REF, | 
 |   CAND_PHI | 
 | }; | 
 |  | 
 | class slsr_cand_d | 
 | { | 
 | public: | 
 |   /* The candidate statement S1.  */ | 
 |   gimple *cand_stmt; | 
 |  | 
 |   /* The base expression B:  often an SSA name, but not always.  */ | 
 |   tree base_expr; | 
 |  | 
 |   /* The stride S.  */ | 
 |   tree stride; | 
 |  | 
 |   /* The index constant i.  */ | 
 |   offset_int index; | 
 |  | 
 |   /* The type of the candidate.  This is normally the type of base_expr, | 
 |      but casts may have occurred when combining feeding instructions. | 
 |      A candidate can only be a basis for candidates of the same final type. | 
 |      (For CAND_REFs, this is the type to be used for operand 1 of the | 
 |      replacement MEM_REF.)  */ | 
 |   tree cand_type; | 
 |  | 
 |   /* The type to be used to interpret the stride field when the stride | 
 |      is not a constant.  Normally the same as the type of the recorded | 
 |      stride, but when the stride has been cast we need to maintain that | 
 |      knowledge in order to make legal substitutions without losing | 
 |      precision.  When the stride is a constant, this will be sizetype.  */ | 
 |   tree stride_type; | 
 |  | 
 |   /* The kind of candidate (CAND_MULT, etc.).  */ | 
 |   enum cand_kind kind; | 
 |  | 
 |   /* Index of this candidate in the candidate vector.  */ | 
 |   cand_idx cand_num; | 
 |  | 
 |   /* Index of the next candidate record for the same statement. | 
 |      A statement may be useful in more than one way (e.g., due to | 
 |      commutativity).  So we can have multiple "interpretations" | 
 |      of a statement.  */ | 
 |   cand_idx next_interp; | 
 |  | 
 |   /* Index of the first candidate record in a chain for the same | 
 |      statement.  */ | 
 |   cand_idx first_interp; | 
 |  | 
 |   /* Index of the basis statement S0, if any, in the candidate vector.  */ | 
 |   cand_idx basis; | 
 |  | 
 |   /* First candidate for which this candidate is a basis, if one exists.  */ | 
 |   cand_idx dependent; | 
 |  | 
 |   /* Next candidate having the same basis as this one.  */ | 
 |   cand_idx sibling; | 
 |  | 
 |   /* If this is a conditional candidate, the CAND_PHI candidate | 
 |      that defines the base SSA name B.  */ | 
 |   cand_idx def_phi; | 
 |  | 
 |   /* Savings that can be expected from eliminating dead code if this | 
 |      candidate is replaced.  */ | 
 |   int dead_savings; | 
 |  | 
 |   /* For PHI candidates, use a visited flag to keep from processing the | 
 |      same PHI twice from multiple paths.  */ | 
 |   int visited; | 
 |  | 
 |   /* We sometimes have to cache a phi basis with a phi candidate to | 
 |      avoid processing it twice.  Valid only if visited==1.  */ | 
 |   tree cached_basis; | 
 | }; | 
 |  | 
 | typedef class slsr_cand_d slsr_cand, *slsr_cand_t; | 
 | typedef const class slsr_cand_d *const_slsr_cand_t; | 
 |  | 
 | /* Pointers to candidates are chained together as part of a mapping | 
 |    from base expressions to the candidates that use them.  */ | 
 |  | 
 | struct cand_chain_d | 
 | { | 
 |   /* Base expression for the chain of candidates:  often, but not | 
 |      always, an SSA name.  */ | 
 |   tree base_expr; | 
 |  | 
 |   /* Pointer to a candidate.  */ | 
 |   slsr_cand_t cand; | 
 |  | 
 |   /* Chain pointer.  */ | 
 |   struct cand_chain_d *next; | 
 |  | 
 | }; | 
 |  | 
 | typedef struct cand_chain_d cand_chain, *cand_chain_t; | 
 | typedef const struct cand_chain_d *const_cand_chain_t; | 
 |  | 
 | /* Information about a unique "increment" associated with candidates | 
 |    having an SSA name for a stride.  An increment is the difference | 
 |    between the index of the candidate and the index of its basis, | 
 |    i.e., (i - i') as discussed in the module commentary. | 
 |  | 
 |    When we are not going to generate address arithmetic we treat | 
 |    increments that differ only in sign as the same, allowing sharing | 
 |    of the cost of initializers.  The absolute value of the increment | 
 |    is stored in the incr_info.  */ | 
 |  | 
 | class incr_info_d | 
 | { | 
 | public: | 
 |   /* The increment that relates a candidate to its basis.  */ | 
 |   offset_int incr; | 
 |  | 
 |   /* How many times the increment occurs in the candidate tree.  */ | 
 |   unsigned count; | 
 |  | 
 |   /* Cost of replacing candidates using this increment.  Negative and | 
 |      zero costs indicate replacement should be performed.  */ | 
 |   int cost; | 
 |  | 
 |   /* If this increment is profitable but is not -1, 0, or 1, it requires | 
 |      an initializer T_0 = stride * incr to be found or introduced in the | 
 |      nearest common dominator of all candidates.  This field holds T_0 | 
 |      for subsequent use.  */ | 
 |   tree initializer; | 
 |  | 
 |   /* If the initializer was found to already exist, this is the block | 
 |      where it was found.  */ | 
 |   basic_block init_bb; | 
 | }; | 
 |  | 
 | typedef class incr_info_d incr_info, *incr_info_t; | 
 |  | 
 | /* Candidates are maintained in a vector.  If candidate X dominates | 
 |    candidate Y, then X appears before Y in the vector; but the | 
 |    converse does not necessarily hold.  */ | 
 | static vec<slsr_cand_t> cand_vec; | 
 |  | 
 | enum cost_consts | 
 | { | 
 |   COST_NEUTRAL = 0, | 
 |   COST_INFINITE = 1000 | 
 | }; | 
 |  | 
 | enum stride_status | 
 | { | 
 |   UNKNOWN_STRIDE = 0, | 
 |   KNOWN_STRIDE = 1 | 
 | }; | 
 |  | 
 | enum phi_adjust_status | 
 | { | 
 |   NOT_PHI_ADJUST = 0, | 
 |   PHI_ADJUST = 1 | 
 | }; | 
 |  | 
 | enum count_phis_status | 
 | { | 
 |   DONT_COUNT_PHIS = 0, | 
 |   COUNT_PHIS = 1 | 
 | }; | 
 |  | 
 | /* Constrain how many PHI nodes we will visit for a conditional | 
 |    candidate (depth and breadth).  */ | 
 | const int MAX_SPREAD = 16; | 
 |  | 
 | /* Pointer map embodying a mapping from statements to candidates.  */ | 
 | static hash_map<gimple *, slsr_cand_t> *stmt_cand_map; | 
 |  | 
 | /* Obstack for candidates.  */ | 
 | static struct obstack cand_obstack; | 
 |  | 
 | /* Obstack for candidate chains.  */ | 
 | static struct obstack chain_obstack; | 
 |  | 
 | /* An array INCR_VEC of incr_infos is used during analysis of related | 
 |    candidates having an SSA name for a stride.  INCR_VEC_LEN describes | 
 |    its current length.  MAX_INCR_VEC_LEN is used to avoid costly | 
 |    pathological cases. */ | 
 | static incr_info_t incr_vec; | 
 | static unsigned incr_vec_len; | 
 | const int MAX_INCR_VEC_LEN = 16; | 
 |  | 
 | /* For a chain of candidates with unknown stride, indicates whether or not | 
 |    we must generate pointer arithmetic when replacing statements.  */ | 
 | static bool address_arithmetic_p; | 
 |  | 
 | /* Forward function declarations.  */ | 
 | static slsr_cand_t base_cand_from_table (tree); | 
 | static tree introduce_cast_before_cand (slsr_cand_t, tree, tree); | 
 | static bool legal_cast_p_1 (tree, tree); | 
 |  | 
 | /* Produce a pointer to the IDX'th candidate in the candidate vector.  */ | 
 |  | 
 | static slsr_cand_t | 
 | lookup_cand (cand_idx idx) | 
 | { | 
 |   return cand_vec[idx]; | 
 | } | 
 |  | 
 | /* Helper for hashing a candidate chain header.  */ | 
 |  | 
 | struct cand_chain_hasher : nofree_ptr_hash <cand_chain> | 
 | { | 
 |   static inline hashval_t hash (const cand_chain *); | 
 |   static inline bool equal (const cand_chain *, const cand_chain *); | 
 | }; | 
 |  | 
 | inline hashval_t | 
 | cand_chain_hasher::hash (const cand_chain *p) | 
 | { | 
 |   tree base_expr = p->base_expr; | 
 |   return iterative_hash_expr (base_expr, 0); | 
 | } | 
 |  | 
 | inline bool | 
 | cand_chain_hasher::equal (const cand_chain *chain1, const cand_chain *chain2) | 
 | { | 
 |   return operand_equal_p (chain1->base_expr, chain2->base_expr, 0); | 
 | } | 
 |  | 
 | /* Hash table embodying a mapping from base exprs to chains of candidates.  */ | 
 | static hash_table<cand_chain_hasher> *base_cand_map; | 
 |  | 
 | /* Pointer map used by tree_to_aff_combination_expand.  */ | 
 | static hash_map<tree, name_expansion *> *name_expansions; | 
 | /* Pointer map embodying a mapping from bases to alternative bases.  */ | 
 | static hash_map<tree, tree> *alt_base_map; | 
 |  | 
 | /* Given BASE, use the tree affine combiniation facilities to | 
 |    find the underlying tree expression for BASE, with any | 
 |    immediate offset excluded. | 
 |  | 
 |    N.B. we should eliminate this backtracking with better forward | 
 |    analysis in a future release.  */ | 
 |  | 
 | static tree | 
 | get_alternative_base (tree base) | 
 | { | 
 |   tree *result = alt_base_map->get (base); | 
 |  | 
 |   if (result == NULL) | 
 |     { | 
 |       tree expr; | 
 |       aff_tree aff; | 
 |  | 
 |       tree_to_aff_combination_expand (base, TREE_TYPE (base), | 
 | 				      &aff, &name_expansions); | 
 |       aff.offset = 0; | 
 |       expr = aff_combination_to_tree (&aff); | 
 |  | 
 |       bool existed = alt_base_map->put (base, base == expr ? NULL : expr); | 
 |       gcc_assert (!existed); | 
 |  | 
 |       return expr == base ? NULL : expr; | 
 |     } | 
 |  | 
 |   return *result; | 
 | } | 
 |  | 
 | /* Look in the candidate table for a CAND_PHI that defines BASE and | 
 |    return it if found; otherwise return NULL.  */ | 
 |  | 
 | static cand_idx | 
 | find_phi_def (tree base) | 
 | { | 
 |   slsr_cand_t c; | 
 |  | 
 |   if (TREE_CODE (base) != SSA_NAME) | 
 |     return 0; | 
 |  | 
 |   c = base_cand_from_table (base); | 
 |  | 
 |   if (!c || c->kind != CAND_PHI | 
 |       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (c->cand_stmt))) | 
 |     return 0; | 
 |  | 
 |   return c->cand_num; | 
 | } | 
 |  | 
 | /* Determine whether all uses of NAME are directly or indirectly | 
 |    used by STMT.  That is, we want to know whether if STMT goes | 
 |    dead, the definition of NAME also goes dead.  */ | 
 | static bool | 
 | uses_consumed_by_stmt (tree name, gimple *stmt, unsigned recurse = 0) | 
 | { | 
 |   gimple *use_stmt; | 
 |   imm_use_iterator iter; | 
 |   bool retval = true; | 
 |  | 
 |   FOR_EACH_IMM_USE_STMT (use_stmt, iter, name) | 
 |     { | 
 |       if (use_stmt == stmt || is_gimple_debug (use_stmt)) | 
 | 	continue; | 
 |  | 
 |       if (!is_gimple_assign (use_stmt) | 
 | 	  || !gimple_get_lhs (use_stmt) | 
 | 	  || !is_gimple_reg (gimple_get_lhs (use_stmt)) | 
 | 	  || recurse >= 10 | 
 | 	  || !uses_consumed_by_stmt (gimple_get_lhs (use_stmt), stmt, | 
 | 				     recurse + 1)) | 
 | 	{ | 
 | 	  retval = false; | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   return retval; | 
 | } | 
 |  | 
 | /* Helper routine for find_basis_for_candidate.  May be called twice: | 
 |    once for the candidate's base expr, and optionally again either for | 
 |    the candidate's phi definition or for a CAND_REF's alternative base | 
 |    expression.  */ | 
 |  | 
 | static slsr_cand_t | 
 | find_basis_for_base_expr (slsr_cand_t c, tree base_expr) | 
 | { | 
 |   cand_chain mapping_key; | 
 |   cand_chain_t chain; | 
 |   slsr_cand_t basis = NULL; | 
 |  | 
 |   // Limit potential of N^2 behavior for long candidate chains. | 
 |   int iters = 0; | 
 |   int max_iters = param_max_slsr_candidate_scan; | 
 |  | 
 |   mapping_key.base_expr = base_expr; | 
 |   chain = base_cand_map->find (&mapping_key); | 
 |  | 
 |   for (; chain && iters < max_iters; chain = chain->next, ++iters) | 
 |     { | 
 |       slsr_cand_t one_basis = chain->cand; | 
 |  | 
 |       if (one_basis->kind != c->kind | 
 | 	  || one_basis->cand_stmt == c->cand_stmt | 
 | 	  || !operand_equal_p (one_basis->stride, c->stride, 0) | 
 | 	  || !types_compatible_p (one_basis->cand_type, c->cand_type) | 
 | 	  || !types_compatible_p (one_basis->stride_type, c->stride_type) | 
 | 	  || !dominated_by_p (CDI_DOMINATORS, | 
 | 			      gimple_bb (c->cand_stmt), | 
 | 			      gimple_bb (one_basis->cand_stmt))) | 
 | 	continue; | 
 |  | 
 |       tree lhs = gimple_assign_lhs (one_basis->cand_stmt); | 
 |       if (lhs && TREE_CODE (lhs) == SSA_NAME | 
 | 	  && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) | 
 | 	continue; | 
 |  | 
 |       if (!basis || basis->cand_num < one_basis->cand_num) | 
 | 	basis = one_basis; | 
 |     } | 
 |  | 
 |   return basis; | 
 | } | 
 |  | 
 | /* Use the base expr from candidate C to look for possible candidates | 
 |    that can serve as a basis for C.  Each potential basis must also | 
 |    appear in a block that dominates the candidate statement and have | 
 |    the same stride and type.  If more than one possible basis exists, | 
 |    the one with highest index in the vector is chosen; this will be | 
 |    the most immediately dominating basis.  */ | 
 |  | 
 | static int | 
 | find_basis_for_candidate (slsr_cand_t c) | 
 | { | 
 |   slsr_cand_t basis = find_basis_for_base_expr (c, c->base_expr); | 
 |  | 
 |   /* If a candidate doesn't have a basis using its base expression, | 
 |      it may have a basis hidden by one or more intervening phis.  */ | 
 |   if (!basis && c->def_phi) | 
 |     { | 
 |       basic_block basis_bb, phi_bb; | 
 |       slsr_cand_t phi_cand = lookup_cand (c->def_phi); | 
 |       basis = find_basis_for_base_expr (c, phi_cand->base_expr); | 
 |  | 
 |       if (basis) | 
 | 	{ | 
 | 	  /* A hidden basis must dominate the phi-definition of the | 
 | 	     candidate's base name.  */ | 
 | 	  phi_bb = gimple_bb (phi_cand->cand_stmt); | 
 | 	  basis_bb = gimple_bb (basis->cand_stmt); | 
 |  | 
 | 	  if (phi_bb == basis_bb | 
 | 	      || !dominated_by_p (CDI_DOMINATORS, phi_bb, basis_bb)) | 
 | 	    { | 
 | 	      basis = NULL; | 
 | 	      c->basis = 0; | 
 | 	    } | 
 |  | 
 | 	  /* If we found a hidden basis, estimate additional dead-code | 
 | 	     savings if the phi and its feeding statements can be removed.  */ | 
 | 	  tree feeding_var = gimple_phi_result (phi_cand->cand_stmt); | 
 | 	  if (basis && uses_consumed_by_stmt (feeding_var, c->cand_stmt)) | 
 | 	    c->dead_savings += phi_cand->dead_savings; | 
 | 	} | 
 |     } | 
 |  | 
 |   if (flag_expensive_optimizations && !basis && c->kind == CAND_REF) | 
 |     { | 
 |       tree alt_base_expr = get_alternative_base (c->base_expr); | 
 |       if (alt_base_expr) | 
 | 	basis = find_basis_for_base_expr (c, alt_base_expr); | 
 |     } | 
 |  | 
 |   if (basis) | 
 |     { | 
 |       c->sibling = basis->dependent; | 
 |       basis->dependent = c->cand_num; | 
 |       return basis->cand_num; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Record a mapping from BASE to C, indicating that C may potentially serve | 
 |    as a basis using that base expression.  BASE may be the same as | 
 |    C->BASE_EXPR; alternatively BASE can be a different tree that share the | 
 |    underlining expression of C->BASE_EXPR.  */ | 
 |  | 
 | static void | 
 | record_potential_basis (slsr_cand_t c, tree base) | 
 | { | 
 |   cand_chain_t node; | 
 |   cand_chain **slot; | 
 |  | 
 |   gcc_assert (base); | 
 |  | 
 |   node = (cand_chain_t) obstack_alloc (&chain_obstack, sizeof (cand_chain)); | 
 |   node->base_expr = base; | 
 |   node->cand = c; | 
 |   node->next = NULL; | 
 |   slot = base_cand_map->find_slot (node, INSERT); | 
 |  | 
 |   if (*slot) | 
 |     { | 
 |       cand_chain_t head = (cand_chain_t) (*slot); | 
 |       node->next = head->next; | 
 |       head->next = node; | 
 |     } | 
 |   else | 
 |     *slot = node; | 
 | } | 
 |  | 
 | /* Allocate storage for a new candidate and initialize its fields. | 
 |    Attempt to find a basis for the candidate. | 
 |  | 
 |    For CAND_REF, an alternative base may also be recorded and used | 
 |    to find a basis.  This helps cases where the expression hidden | 
 |    behind BASE (which is usually an SSA_NAME) has immediate offset, | 
 |    e.g. | 
 |  | 
 |      a2[i][j] = 1; | 
 |      a2[i + 20][j] = 2;  */ | 
 |  | 
 | static slsr_cand_t | 
 | alloc_cand_and_find_basis (enum cand_kind kind, gimple *gs, tree base, | 
 | 			   const offset_int &index, tree stride, tree ctype, | 
 | 			   tree stype, unsigned savings) | 
 | { | 
 |   slsr_cand_t c = (slsr_cand_t) obstack_alloc (&cand_obstack, | 
 | 					       sizeof (slsr_cand)); | 
 |   c->cand_stmt = gs; | 
 |   c->base_expr = base; | 
 |   c->stride = stride; | 
 |   c->index = index; | 
 |   c->cand_type = ctype; | 
 |   c->stride_type = stype; | 
 |   c->kind = kind; | 
 |   c->cand_num = cand_vec.length (); | 
 |   c->next_interp = 0; | 
 |   c->first_interp = c->cand_num; | 
 |   c->dependent = 0; | 
 |   c->sibling = 0; | 
 |   c->def_phi = kind == CAND_MULT ? find_phi_def (base) : 0; | 
 |   c->dead_savings = savings; | 
 |   c->visited = 0; | 
 |   c->cached_basis = NULL_TREE; | 
 |  | 
 |   cand_vec.safe_push (c); | 
 |  | 
 |   if (kind == CAND_PHI) | 
 |     c->basis = 0; | 
 |   else | 
 |     c->basis = find_basis_for_candidate (c); | 
 |  | 
 |   record_potential_basis (c, base); | 
 |   if (flag_expensive_optimizations && kind == CAND_REF) | 
 |     { | 
 |       tree alt_base = get_alternative_base (base); | 
 |       if (alt_base) | 
 | 	record_potential_basis (c, alt_base); | 
 |     } | 
 |  | 
 |   return c; | 
 | } | 
 |  | 
 | /* Determine the target cost of statement GS when compiling according | 
 |    to SPEED.  */ | 
 |  | 
 | static int | 
 | stmt_cost (gimple *gs, bool speed) | 
 | { | 
 |   tree lhs, rhs1, rhs2; | 
 |   machine_mode lhs_mode; | 
 |  | 
 |   gcc_assert (is_gimple_assign (gs)); | 
 |   lhs = gimple_assign_lhs (gs); | 
 |   rhs1 = gimple_assign_rhs1 (gs); | 
 |   lhs_mode = TYPE_MODE (TREE_TYPE (lhs)); | 
 |  | 
 |   switch (gimple_assign_rhs_code (gs)) | 
 |     { | 
 |     case MULT_EXPR: | 
 |       rhs2 = gimple_assign_rhs2 (gs); | 
 |  | 
 |       if (tree_fits_shwi_p (rhs2)) | 
 | 	return mult_by_coeff_cost (tree_to_shwi (rhs2), lhs_mode, speed); | 
 |  | 
 |       gcc_assert (TREE_CODE (rhs1) != INTEGER_CST); | 
 |       return mul_cost (speed, lhs_mode); | 
 |  | 
 |     case PLUS_EXPR: | 
 |     case POINTER_PLUS_EXPR: | 
 |     case MINUS_EXPR: | 
 |       return add_cost (speed, lhs_mode); | 
 |  | 
 |     case NEGATE_EXPR: | 
 |       return neg_cost (speed, lhs_mode); | 
 |  | 
 |     CASE_CONVERT: | 
 |       return convert_cost (lhs_mode, TYPE_MODE (TREE_TYPE (rhs1)), speed); | 
 |  | 
 |     /* Note that we don't assign costs to copies that in most cases | 
 |        will go away.  */ | 
 |     case SSA_NAME: | 
 |       return 0; | 
 |  | 
 |     default: | 
 |       ; | 
 |     } | 
 |  | 
 |   gcc_unreachable (); | 
 | } | 
 |  | 
 | /* Look up the defining statement for BASE_IN and return a pointer | 
 |    to its candidate in the candidate table, if any; otherwise NULL. | 
 |    Only CAND_ADD and CAND_MULT candidates are returned.  */ | 
 |  | 
 | static slsr_cand_t | 
 | base_cand_from_table (tree base_in) | 
 | { | 
 |   slsr_cand_t *result; | 
 |  | 
 |   gimple *def = SSA_NAME_DEF_STMT (base_in); | 
 |   if (!def) | 
 |     return (slsr_cand_t) NULL; | 
 |  | 
 |   result = stmt_cand_map->get (def); | 
 |  | 
 |   if (result && (*result)->kind != CAND_REF) | 
 |     return *result; | 
 |  | 
 |   return (slsr_cand_t) NULL; | 
 | } | 
 |  | 
 | /* Add an entry to the statement-to-candidate mapping.  */ | 
 |  | 
 | static void | 
 | add_cand_for_stmt (gimple *gs, slsr_cand_t c) | 
 | { | 
 |   bool existed = stmt_cand_map->put (gs, c); | 
 |   gcc_assert (!existed); | 
 | } | 
 |  | 
 | /* Given PHI which contains a phi statement, determine whether it | 
 |    satisfies all the requirements of a phi candidate.  If so, create | 
 |    a candidate.  Note that a CAND_PHI never has a basis itself, but | 
 |    is used to help find a basis for subsequent candidates.  */ | 
 |  | 
 | static void | 
 | slsr_process_phi (gphi *phi, bool speed) | 
 | { | 
 |   unsigned i; | 
 |   tree arg0_base = NULL_TREE, base_type; | 
 |   slsr_cand_t c; | 
 |   class loop *cand_loop = gimple_bb (phi)->loop_father; | 
 |   unsigned savings = 0; | 
 |  | 
 |   /* A CAND_PHI requires each of its arguments to have the same | 
 |      derived base name.  (See the module header commentary for a | 
 |      definition of derived base names.)  Furthermore, all feeding | 
 |      definitions must be in the same position in the loop hierarchy | 
 |      as PHI.  */ | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       slsr_cand_t arg_cand; | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |       tree derived_base_name = NULL_TREE; | 
 |       gimple *arg_stmt = NULL; | 
 |       basic_block arg_bb = NULL; | 
 |  | 
 |       if (TREE_CODE (arg) != SSA_NAME) | 
 | 	return; | 
 |  | 
 |       arg_cand = base_cand_from_table (arg); | 
 |  | 
 |       if (arg_cand) | 
 | 	{ | 
 | 	  while (arg_cand->kind != CAND_ADD && arg_cand->kind != CAND_PHI) | 
 | 	    { | 
 | 	      if (!arg_cand->next_interp) | 
 | 		return; | 
 |  | 
 | 	      arg_cand = lookup_cand (arg_cand->next_interp); | 
 | 	    } | 
 |  | 
 | 	  if (!integer_onep (arg_cand->stride)) | 
 | 	    return; | 
 |  | 
 | 	  derived_base_name = arg_cand->base_expr; | 
 | 	  arg_stmt = arg_cand->cand_stmt; | 
 | 	  arg_bb = gimple_bb (arg_stmt); | 
 |  | 
 | 	  /* Gather potential dead code savings if the phi statement | 
 | 	     can be removed later on.  */ | 
 | 	  if (uses_consumed_by_stmt (arg, phi)) | 
 | 	    { | 
 | 	      if (gimple_code (arg_stmt) == GIMPLE_PHI) | 
 | 		savings += arg_cand->dead_savings; | 
 | 	      else | 
 | 		savings += stmt_cost (arg_stmt, speed); | 
 | 	    } | 
 | 	} | 
 |       else if (SSA_NAME_IS_DEFAULT_DEF (arg)) | 
 | 	{ | 
 | 	  derived_base_name = arg; | 
 | 	  arg_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); | 
 | 	} | 
 |  | 
 |       if (!arg_bb || arg_bb->loop_father != cand_loop) | 
 | 	return; | 
 |  | 
 |       if (i == 0) | 
 | 	arg0_base = derived_base_name; | 
 |       else if (!operand_equal_p (derived_base_name, arg0_base, 0)) | 
 | 	return; | 
 |     } | 
 |  | 
 |   /* Create the candidate.  "alloc_cand_and_find_basis" is named | 
 |      misleadingly for this case, as no basis will be sought for a | 
 |      CAND_PHI.  */ | 
 |   base_type = TREE_TYPE (arg0_base); | 
 |  | 
 |   c = alloc_cand_and_find_basis (CAND_PHI, phi, arg0_base, | 
 | 				 0, integer_one_node, base_type, | 
 | 				 sizetype, savings); | 
 |  | 
 |   /* Add the candidate to the statement-candidate mapping.  */ | 
 |   add_cand_for_stmt (phi, c); | 
 | } | 
 |  | 
 | /* Given PBASE which is a pointer to tree, look up the defining | 
 |    statement for it and check whether the candidate is in the | 
 |    form of: | 
 |  | 
 |      X = B + (1 * S), S is integer constant | 
 |      X = B + (i * S), S is integer one | 
 |  | 
 |    If so, set PBASE to the candidate's base_expr and return double | 
 |    int (i * S). | 
 |    Otherwise, just return double int zero.  */ | 
 |  | 
 | static offset_int | 
 | backtrace_base_for_ref (tree *pbase) | 
 | { | 
 |   tree base_in = *pbase; | 
 |   slsr_cand_t base_cand; | 
 |  | 
 |   STRIP_NOPS (base_in); | 
 |  | 
 |   /* Strip off widening conversion(s) to handle cases where | 
 |      e.g. 'B' is widened from an 'int' in order to calculate | 
 |      a 64-bit address.  */ | 
 |   if (CONVERT_EXPR_P (base_in) | 
 |       && legal_cast_p_1 (TREE_TYPE (base_in), | 
 | 			 TREE_TYPE (TREE_OPERAND (base_in, 0)))) | 
 |     base_in = get_unwidened (base_in, NULL_TREE); | 
 |  | 
 |   if (TREE_CODE (base_in) != SSA_NAME) | 
 |     return 0; | 
 |  | 
 |   base_cand = base_cand_from_table (base_in); | 
 |  | 
 |   while (base_cand && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       if (base_cand->kind == CAND_ADD | 
 | 	  && base_cand->index == 1 | 
 | 	  && TREE_CODE (base_cand->stride) == INTEGER_CST) | 
 | 	{ | 
 | 	  /* X = B + (1 * S), S is integer constant.  */ | 
 | 	  *pbase = base_cand->base_expr; | 
 | 	  return wi::to_offset (base_cand->stride); | 
 | 	} | 
 |       else if (base_cand->kind == CAND_ADD | 
 | 	       && TREE_CODE (base_cand->stride) == INTEGER_CST | 
 | 	       && integer_onep (base_cand->stride)) | 
 | 	{ | 
 | 	  /* X = B + (i * S), S is integer one.  */ | 
 | 	  *pbase = base_cand->base_expr; | 
 | 	  return base_cand->index; | 
 | 	} | 
 |  | 
 |       base_cand = lookup_cand (base_cand->next_interp); | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Look for the following pattern: | 
 |  | 
 |     *PBASE:    MEM_REF (T1, C1) | 
 |  | 
 |     *POFFSET:  MULT_EXPR (T2, C3)        [C2 is zero] | 
 |                      or | 
 |                MULT_EXPR (PLUS_EXPR (T2, C2), C3) | 
 |                      or | 
 |                MULT_EXPR (MINUS_EXPR (T2, -C2), C3) | 
 |  | 
 |     *PINDEX:   C4 * BITS_PER_UNIT | 
 |  | 
 |    If not present, leave the input values unchanged and return FALSE. | 
 |    Otherwise, modify the input values as follows and return TRUE: | 
 |  | 
 |     *PBASE:    T1 | 
 |     *POFFSET:  MULT_EXPR (T2, C3) | 
 |     *PINDEX:   C1 + (C2 * C3) + C4 | 
 |  | 
 |    When T2 is recorded by a CAND_ADD in the form of (T2' + C5), it | 
 |    will be further restructured to: | 
 |  | 
 |     *PBASE:    T1 | 
 |     *POFFSET:  MULT_EXPR (T2', C3) | 
 |     *PINDEX:   C1 + (C2 * C3) + C4 + (C5 * C3)  */ | 
 |  | 
 | static bool | 
 | restructure_reference (tree *pbase, tree *poffset, offset_int *pindex, | 
 | 		       tree *ptype) | 
 | { | 
 |   tree base = *pbase, offset = *poffset; | 
 |   offset_int index = *pindex; | 
 |   tree mult_op0, t1, t2, type; | 
 |   offset_int c1, c2, c3, c4, c5; | 
 |   offset_int mem_offset; | 
 |  | 
 |   if (!base | 
 |       || !offset | 
 |       || TREE_CODE (base) != MEM_REF | 
 |       || !mem_ref_offset (base).is_constant (&mem_offset) | 
 |       || TREE_CODE (offset) != MULT_EXPR | 
 |       || TREE_CODE (TREE_OPERAND (offset, 1)) != INTEGER_CST | 
 |       || wi::umod_floor (index, BITS_PER_UNIT) != 0) | 
 |     return false; | 
 |  | 
 |   t1 = TREE_OPERAND (base, 0); | 
 |   c1 = offset_int::from (mem_offset, SIGNED); | 
 |   type = TREE_TYPE (TREE_OPERAND (base, 1)); | 
 |  | 
 |   mult_op0 = TREE_OPERAND (offset, 0); | 
 |   c3 = wi::to_offset (TREE_OPERAND (offset, 1)); | 
 |  | 
 |   if (TREE_CODE (mult_op0) == PLUS_EXPR) | 
 |  | 
 |     if (TREE_CODE (TREE_OPERAND (mult_op0, 1)) == INTEGER_CST) | 
 |       { | 
 | 	t2 = TREE_OPERAND (mult_op0, 0); | 
 | 	c2 = wi::to_offset (TREE_OPERAND (mult_op0, 1)); | 
 |       } | 
 |     else | 
 |       return false; | 
 |  | 
 |   else if (TREE_CODE (mult_op0) == MINUS_EXPR) | 
 |  | 
 |     if (TREE_CODE (TREE_OPERAND (mult_op0, 1)) == INTEGER_CST) | 
 |       { | 
 | 	t2 = TREE_OPERAND (mult_op0, 0); | 
 | 	c2 = -wi::to_offset (TREE_OPERAND (mult_op0, 1)); | 
 |       } | 
 |     else | 
 |       return false; | 
 |  | 
 |   else | 
 |     { | 
 |       t2 = mult_op0; | 
 |       c2 = 0; | 
 |     } | 
 |  | 
 |   c4 = index >> LOG2_BITS_PER_UNIT; | 
 |   c5 = backtrace_base_for_ref (&t2); | 
 |  | 
 |   *pbase = t1; | 
 |   *poffset = fold_build2 (MULT_EXPR, sizetype, fold_convert (sizetype, t2), | 
 | 			  wide_int_to_tree (sizetype, c3)); | 
 |   *pindex = c1 + c2 * c3 + c4 + c5 * c3; | 
 |   *ptype = type; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Given GS which contains a data reference, create a CAND_REF entry in | 
 |    the candidate table and attempt to find a basis.  */ | 
 |  | 
 | static void | 
 | slsr_process_ref (gimple *gs) | 
 | { | 
 |   tree ref_expr, base, offset, type; | 
 |   poly_int64 bitsize, bitpos; | 
 |   machine_mode mode; | 
 |   int unsignedp, reversep, volatilep; | 
 |   slsr_cand_t c; | 
 |  | 
 |   if (gimple_vdef (gs)) | 
 |     ref_expr = gimple_assign_lhs (gs); | 
 |   else | 
 |     ref_expr = gimple_assign_rhs1 (gs); | 
 |  | 
 |   if (!handled_component_p (ref_expr) | 
 |       || TREE_CODE (ref_expr) == BIT_FIELD_REF | 
 |       || (TREE_CODE (ref_expr) == COMPONENT_REF | 
 | 	  && DECL_BIT_FIELD (TREE_OPERAND (ref_expr, 1)))) | 
 |     return; | 
 |  | 
 |   base = get_inner_reference (ref_expr, &bitsize, &bitpos, &offset, &mode, | 
 | 			      &unsignedp, &reversep, &volatilep); | 
 |   HOST_WIDE_INT cbitpos; | 
 |   if (reversep || !bitpos.is_constant (&cbitpos)) | 
 |     return; | 
 |   offset_int index = cbitpos; | 
 |  | 
 |   if (!restructure_reference (&base, &offset, &index, &type)) | 
 |     return; | 
 |  | 
 |   c = alloc_cand_and_find_basis (CAND_REF, gs, base, index, offset, | 
 | 				 type, sizetype, 0); | 
 |  | 
 |   /* Add the candidate to the statement-candidate mapping.  */ | 
 |   add_cand_for_stmt (gs, c); | 
 | } | 
 |  | 
 | /* Create a candidate entry for a statement GS, where GS multiplies | 
 |    two SSA names BASE_IN and STRIDE_IN.  Propagate any known information | 
 |    about the two SSA names into the new candidate.  Return the new | 
 |    candidate.  */ | 
 |  | 
 | static slsr_cand_t | 
 | create_mul_ssa_cand (gimple *gs, tree base_in, tree stride_in, bool speed) | 
 | { | 
 |   tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE; | 
 |   tree stype = NULL_TREE; | 
 |   offset_int index; | 
 |   unsigned savings = 0; | 
 |   slsr_cand_t c; | 
 |   slsr_cand_t base_cand = base_cand_from_table (base_in); | 
 |  | 
 |   /* Look at all interpretations of the base candidate, if necessary, | 
 |      to find information to propagate into this candidate.  */ | 
 |   while (base_cand && !base && base_cand->kind != CAND_PHI) | 
 |     { | 
 |  | 
 |       if (base_cand->kind == CAND_MULT && integer_onep (base_cand->stride)) | 
 | 	{ | 
 | 	  /* Y = (B + i') * 1 | 
 | 	     X = Y * Z | 
 | 	     ================ | 
 | 	     X = (B + i') * Z  */ | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = base_cand->index; | 
 | 	  stride = stride_in; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  stype = TREE_TYPE (stride_in); | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |       else if (base_cand->kind == CAND_ADD | 
 | 	       && TREE_CODE (base_cand->stride) == INTEGER_CST) | 
 | 	{ | 
 | 	  /* Y = B + (i' * S), S constant | 
 | 	     X = Y * Z | 
 | 	     ============================ | 
 | 	     X = B + ((i' * S) * Z)  */ | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = base_cand->index * wi::to_offset (base_cand->stride); | 
 | 	  stride = stride_in; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  stype = TREE_TYPE (stride_in); | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |  | 
 |       base_cand = lookup_cand (base_cand->next_interp); | 
 |     } | 
 |  | 
 |   if (!base) | 
 |     { | 
 |       /* No interpretations had anything useful to propagate, so | 
 | 	 produce X = (Y + 0) * Z.  */ | 
 |       base = base_in; | 
 |       index = 0; | 
 |       stride = stride_in; | 
 |       ctype = TREE_TYPE (base_in); | 
 |       stype = TREE_TYPE (stride_in); | 
 |     } | 
 |  | 
 |   c = alloc_cand_and_find_basis (CAND_MULT, gs, base, index, stride, | 
 | 				 ctype, stype, savings); | 
 |   return c; | 
 | } | 
 |  | 
 | /* Create a candidate entry for a statement GS, where GS multiplies | 
 |    SSA name BASE_IN by constant STRIDE_IN.  Propagate any known | 
 |    information about BASE_IN into the new candidate.  Return the new | 
 |    candidate.  */ | 
 |  | 
 | static slsr_cand_t | 
 | create_mul_imm_cand (gimple *gs, tree base_in, tree stride_in, bool speed) | 
 | { | 
 |   tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE; | 
 |   offset_int index, temp; | 
 |   unsigned savings = 0; | 
 |   slsr_cand_t c; | 
 |   slsr_cand_t base_cand = base_cand_from_table (base_in); | 
 |  | 
 |   /* Look at all interpretations of the base candidate, if necessary, | 
 |      to find information to propagate into this candidate.  */ | 
 |   while (base_cand && !base && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       if (base_cand->kind == CAND_MULT | 
 | 	  && TREE_CODE (base_cand->stride) == INTEGER_CST) | 
 | 	{ | 
 | 	  /* Y = (B + i') * S, S constant | 
 | 	     X = Y * c | 
 | 	     ============================ | 
 | 	     X = (B + i') * (S * c)  */ | 
 | 	  temp = wi::to_offset (base_cand->stride) * wi::to_offset (stride_in); | 
 | 	  if (wi::fits_to_tree_p (temp, TREE_TYPE (stride_in))) | 
 | 	    { | 
 | 	      base = base_cand->base_expr; | 
 | 	      index = base_cand->index; | 
 | 	      stride = wide_int_to_tree (TREE_TYPE (stride_in), temp); | 
 | 	      ctype = base_cand->cand_type; | 
 | 	      if (has_single_use (base_in)) | 
 | 		savings = (base_cand->dead_savings | 
 | 			   + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	    } | 
 | 	} | 
 |       else if (base_cand->kind == CAND_ADD && integer_onep (base_cand->stride)) | 
 | 	{ | 
 | 	  /* Y = B + (i' * 1) | 
 | 	     X = Y * c | 
 | 	     =========================== | 
 | 	     X = (B + i') * c  */ | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = base_cand->index; | 
 | 	  stride = stride_in; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |       else if (base_cand->kind == CAND_ADD | 
 | 	       && base_cand->index == 1 | 
 | 	       && TREE_CODE (base_cand->stride) == INTEGER_CST) | 
 | 	{ | 
 | 	  /* Y = B + (1 * S), S constant | 
 | 	     X = Y * c | 
 | 	     =========================== | 
 | 	     X = (B + S) * c  */ | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = wi::to_offset (base_cand->stride); | 
 | 	  stride = stride_in; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |  | 
 |       base_cand = lookup_cand (base_cand->next_interp); | 
 |     } | 
 |  | 
 |   if (!base) | 
 |     { | 
 |       /* No interpretations had anything useful to propagate, so | 
 | 	 produce X = (Y + 0) * c.  */ | 
 |       base = base_in; | 
 |       index = 0; | 
 |       stride = stride_in; | 
 |       ctype = TREE_TYPE (base_in); | 
 |     } | 
 |  | 
 |   c = alloc_cand_and_find_basis (CAND_MULT, gs, base, index, stride, | 
 | 				 ctype, sizetype, savings); | 
 |   return c; | 
 | } | 
 |  | 
 | /* Given GS which is a multiply of scalar integers, make an appropriate | 
 |    entry in the candidate table.  If this is a multiply of two SSA names, | 
 |    create two CAND_MULT interpretations and attempt to find a basis for | 
 |    each of them.  Otherwise, create a single CAND_MULT and attempt to | 
 |    find a basis.  */ | 
 |  | 
 | static void | 
 | slsr_process_mul (gimple *gs, tree rhs1, tree rhs2, bool speed) | 
 | { | 
 |   slsr_cand_t c, c2; | 
 |  | 
 |   /* If this is a multiply of an SSA name with itself, it is highly | 
 |      unlikely that we will get a strength reduction opportunity, so | 
 |      don't record it as a candidate.  This simplifies the logic for | 
 |      finding a basis, so if this is removed that must be considered.  */ | 
 |   if (rhs1 == rhs2) | 
 |     return; | 
 |  | 
 |   if (TREE_CODE (rhs2) == SSA_NAME) | 
 |     { | 
 |       /* Record an interpretation of this statement in the candidate table | 
 | 	 assuming RHS1 is the base expression and RHS2 is the stride.  */ | 
 |       c = create_mul_ssa_cand (gs, rhs1, rhs2, speed); | 
 |  | 
 |       /* Add the first interpretation to the statement-candidate mapping.  */ | 
 |       add_cand_for_stmt (gs, c); | 
 |  | 
 |       /* Record another interpretation of this statement assuming RHS1 | 
 | 	 is the stride and RHS2 is the base expression.  */ | 
 |       c2 = create_mul_ssa_cand (gs, rhs2, rhs1, speed); | 
 |       c->next_interp = c2->cand_num; | 
 |       c2->first_interp = c->cand_num; | 
 |     } | 
 |   else if (TREE_CODE (rhs2) == INTEGER_CST && !integer_zerop (rhs2)) | 
 |     { | 
 |       /* Record an interpretation for the multiply-immediate.  */ | 
 |       c = create_mul_imm_cand (gs, rhs1, rhs2, speed); | 
 |  | 
 |       /* Add the interpretation to the statement-candidate mapping.  */ | 
 |       add_cand_for_stmt (gs, c); | 
 |     } | 
 | } | 
 |  | 
 | /* Create a candidate entry for a statement GS, where GS adds two | 
 |    SSA names BASE_IN and ADDEND_IN if SUBTRACT_P is false, and | 
 |    subtracts ADDEND_IN from BASE_IN otherwise.  Propagate any known | 
 |    information about the two SSA names into the new candidate. | 
 |    Return the new candidate.  */ | 
 |  | 
 | static slsr_cand_t | 
 | create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in, | 
 | 		     bool subtract_p, bool speed) | 
 | { | 
 |   tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE; | 
 |   tree stype = NULL_TREE; | 
 |   offset_int index; | 
 |   unsigned savings = 0; | 
 |   slsr_cand_t c; | 
 |   slsr_cand_t base_cand = base_cand_from_table (base_in); | 
 |   slsr_cand_t addend_cand = base_cand_from_table (addend_in); | 
 |  | 
 |   /* The most useful transformation is a multiply-immediate feeding | 
 |      an add or subtract.  Look for that first.  */ | 
 |   while (addend_cand && !base && addend_cand->kind != CAND_PHI) | 
 |     { | 
 |       if (addend_cand->kind == CAND_MULT | 
 | 	  && addend_cand->index == 0 | 
 | 	  && TREE_CODE (addend_cand->stride) == INTEGER_CST) | 
 | 	{ | 
 | 	  /* Z = (B + 0) * S, S constant | 
 | 	     X = Y +/- Z | 
 | 	     =========================== | 
 | 	     X = Y + ((+/-1 * S) * B)  */ | 
 | 	  base = base_in; | 
 | 	  index = wi::to_offset (addend_cand->stride); | 
 | 	  if (subtract_p) | 
 | 	    index = -index; | 
 | 	  stride = addend_cand->base_expr; | 
 | 	  ctype = TREE_TYPE (base_in); | 
 | 	  stype = addend_cand->cand_type; | 
 | 	  if (has_single_use (addend_in)) | 
 | 	    savings = (addend_cand->dead_savings | 
 | 		       + stmt_cost (addend_cand->cand_stmt, speed)); | 
 | 	} | 
 |  | 
 |       addend_cand = lookup_cand (addend_cand->next_interp); | 
 |     } | 
 |  | 
 |   while (base_cand && !base && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       if (base_cand->kind == CAND_ADD | 
 | 	  && (base_cand->index == 0 | 
 | 	      || operand_equal_p (base_cand->stride, | 
 | 				  integer_zero_node, 0))) | 
 | 	{ | 
 | 	  /* Y = B + (i' * S), i' * S = 0 | 
 | 	     X = Y +/- Z | 
 | 	     ============================ | 
 | 	     X = B + (+/-1 * Z)  */ | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = subtract_p ? -1 : 1; | 
 | 	  stride = addend_in; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  stype = (TREE_CODE (addend_in) == INTEGER_CST ? sizetype | 
 | 		   : TREE_TYPE (addend_in)); | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |       else if (subtract_p) | 
 | 	{ | 
 | 	  slsr_cand_t subtrahend_cand = base_cand_from_table (addend_in); | 
 |  | 
 | 	  while (subtrahend_cand && !base && subtrahend_cand->kind != CAND_PHI) | 
 | 	    { | 
 | 	      if (subtrahend_cand->kind == CAND_MULT | 
 | 		  && subtrahend_cand->index == 0 | 
 | 		  && TREE_CODE (subtrahend_cand->stride) == INTEGER_CST) | 
 | 		{ | 
 | 		  /* Z = (B + 0) * S, S constant | 
 | 		     X = Y - Z | 
 | 		     =========================== | 
 | 		     Value:  X = Y + ((-1 * S) * B)  */ | 
 | 		  base = base_in; | 
 | 		  index = wi::to_offset (subtrahend_cand->stride); | 
 | 		  index = -index; | 
 | 		  stride = subtrahend_cand->base_expr; | 
 | 		  ctype = TREE_TYPE (base_in); | 
 | 		  stype = subtrahend_cand->cand_type; | 
 | 		  if (has_single_use (addend_in)) | 
 | 		    savings = (subtrahend_cand->dead_savings | 
 | 			       + stmt_cost (subtrahend_cand->cand_stmt, speed)); | 
 | 		} | 
 |  | 
 | 	      subtrahend_cand = lookup_cand (subtrahend_cand->next_interp); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       base_cand = lookup_cand (base_cand->next_interp); | 
 |     } | 
 |  | 
 |   if (!base) | 
 |     { | 
 |       /* No interpretations had anything useful to propagate, so | 
 | 	 produce X = Y + (1 * Z).  */ | 
 |       base = base_in; | 
 |       index = subtract_p ? -1 : 1; | 
 |       stride = addend_in; | 
 |       ctype = TREE_TYPE (base_in); | 
 |       stype = (TREE_CODE (addend_in) == INTEGER_CST ? sizetype | 
 | 	       : TREE_TYPE (addend_in)); | 
 |     } | 
 |  | 
 |   c = alloc_cand_and_find_basis (CAND_ADD, gs, base, index, stride, | 
 | 				 ctype, stype, savings); | 
 |   return c; | 
 | } | 
 |  | 
 | /* Create a candidate entry for a statement GS, where GS adds SSA | 
 |    name BASE_IN to constant INDEX_IN.  Propagate any known information | 
 |    about BASE_IN into the new candidate.  Return the new candidate.  */ | 
 |  | 
 | static slsr_cand_t | 
 | create_add_imm_cand (gimple *gs, tree base_in, const offset_int &index_in, | 
 | 		     bool speed) | 
 | { | 
 |   enum cand_kind kind = CAND_ADD; | 
 |   tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE; | 
 |   tree stype = NULL_TREE; | 
 |   offset_int index, multiple; | 
 |   unsigned savings = 0; | 
 |   slsr_cand_t c; | 
 |   slsr_cand_t base_cand = base_cand_from_table (base_in); | 
 |  | 
 |   while (base_cand && !base && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       signop sign = TYPE_SIGN (TREE_TYPE (base_cand->stride)); | 
 |  | 
 |       if (TREE_CODE (base_cand->stride) == INTEGER_CST | 
 | 	  && wi::multiple_of_p (index_in, wi::to_offset (base_cand->stride), | 
 | 				sign, &multiple)) | 
 | 	{ | 
 | 	  /* Y = (B + i') * S, S constant, c = kS for some integer k | 
 | 	     X = Y + c | 
 | 	     ============================ | 
 | 	     X = (B + (i'+ k)) * S | 
 | 	  OR | 
 | 	     Y = B + (i' * S), S constant, c = kS for some integer k | 
 | 	     X = Y + c | 
 | 	     ============================ | 
 | 	     X = (B + (i'+ k)) * S  */ | 
 | 	  kind = base_cand->kind; | 
 | 	  base = base_cand->base_expr; | 
 | 	  index = base_cand->index + multiple; | 
 | 	  stride = base_cand->stride; | 
 | 	  ctype = base_cand->cand_type; | 
 | 	  stype = base_cand->stride_type; | 
 | 	  if (has_single_use (base_in)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 | 	} | 
 |  | 
 |       base_cand = lookup_cand (base_cand->next_interp); | 
 |     } | 
 |  | 
 |   if (!base) | 
 |     { | 
 |       /* No interpretations had anything useful to propagate, so | 
 | 	 produce X = Y + (c * 1).  */ | 
 |       kind = CAND_ADD; | 
 |       base = base_in; | 
 |       index = index_in; | 
 |       stride = integer_one_node; | 
 |       ctype = TREE_TYPE (base_in); | 
 |       stype = sizetype; | 
 |     } | 
 |  | 
 |   c = alloc_cand_and_find_basis (kind, gs, base, index, stride, | 
 | 				 ctype, stype, savings); | 
 |   return c; | 
 | } | 
 |  | 
 | /* Given GS which is an add or subtract of scalar integers or pointers, | 
 |    make at least one appropriate entry in the candidate table.  */ | 
 |  | 
 | static void | 
 | slsr_process_add (gimple *gs, tree rhs1, tree rhs2, bool speed) | 
 | { | 
 |   bool subtract_p = gimple_assign_rhs_code (gs) == MINUS_EXPR; | 
 |   slsr_cand_t c = NULL, c2; | 
 |  | 
 |   if (TREE_CODE (rhs2) == SSA_NAME) | 
 |     { | 
 |       /* First record an interpretation assuming RHS1 is the base expression | 
 | 	 and RHS2 is the stride.  But it doesn't make sense for the | 
 | 	 stride to be a pointer, so don't record a candidate in that case.  */ | 
 |       if (!POINTER_TYPE_P (TREE_TYPE (rhs2))) | 
 | 	{ | 
 | 	  c = create_add_ssa_cand (gs, rhs1, rhs2, subtract_p, speed); | 
 |  | 
 | 	  /* Add the first interpretation to the statement-candidate | 
 | 	     mapping.  */ | 
 | 	  add_cand_for_stmt (gs, c); | 
 | 	} | 
 |  | 
 |       /* If the two RHS operands are identical, or this is a subtract, | 
 | 	 we're done.  */ | 
 |       if (operand_equal_p (rhs1, rhs2, 0) || subtract_p) | 
 | 	return; | 
 |  | 
 |       /* Otherwise, record another interpretation assuming RHS2 is the | 
 | 	 base expression and RHS1 is the stride, again provided that the | 
 | 	 stride is not a pointer.  */ | 
 |       if (!POINTER_TYPE_P (TREE_TYPE (rhs1))) | 
 | 	{ | 
 | 	  c2 = create_add_ssa_cand (gs, rhs2, rhs1, false, speed); | 
 | 	  if (c) | 
 | 	    { | 
 | 	      c->next_interp = c2->cand_num; | 
 | 	      c2->first_interp = c->cand_num; | 
 | 	    } | 
 | 	  else | 
 | 	    add_cand_for_stmt (gs, c2); | 
 | 	} | 
 |     } | 
 |   else if (TREE_CODE (rhs2) == INTEGER_CST) | 
 |     { | 
 |       /* Record an interpretation for the add-immediate.  */ | 
 |       offset_int index = wi::to_offset (rhs2); | 
 |       if (subtract_p) | 
 | 	index = -index; | 
 |  | 
 |       c = create_add_imm_cand (gs, rhs1, index, speed); | 
 |  | 
 |       /* Add the interpretation to the statement-candidate mapping.  */ | 
 |       add_cand_for_stmt (gs, c); | 
 |     } | 
 | } | 
 |  | 
 | /* Given GS which is a negate of a scalar integer, make an appropriate | 
 |    entry in the candidate table.  A negate is equivalent to a multiply | 
 |    by -1.  */ | 
 |  | 
 | static void | 
 | slsr_process_neg (gimple *gs, tree rhs1, bool speed) | 
 | { | 
 |   /* Record a CAND_MULT interpretation for the multiply by -1.  */ | 
 |   slsr_cand_t c = create_mul_imm_cand (gs, rhs1, integer_minus_one_node, speed); | 
 |  | 
 |   /* Add the interpretation to the statement-candidate mapping.  */ | 
 |   add_cand_for_stmt (gs, c); | 
 | } | 
 |  | 
 | /* Help function for legal_cast_p, operating on two trees.  Checks | 
 |    whether it's allowable to cast from RHS to LHS.  See legal_cast_p | 
 |    for more details.  */ | 
 |  | 
 | static bool | 
 | legal_cast_p_1 (tree lhs_type, tree rhs_type) | 
 | { | 
 |   unsigned lhs_size, rhs_size; | 
 |   bool lhs_wraps, rhs_wraps; | 
 |  | 
 |   lhs_size = TYPE_PRECISION (lhs_type); | 
 |   rhs_size = TYPE_PRECISION (rhs_type); | 
 |   lhs_wraps = ANY_INTEGRAL_TYPE_P (lhs_type) && TYPE_OVERFLOW_WRAPS (lhs_type); | 
 |   rhs_wraps = ANY_INTEGRAL_TYPE_P (rhs_type) && TYPE_OVERFLOW_WRAPS (rhs_type); | 
 |  | 
 |   if (lhs_size < rhs_size | 
 |       || (rhs_wraps && !lhs_wraps) | 
 |       || (rhs_wraps && lhs_wraps && rhs_size != lhs_size)) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Return TRUE if GS is a statement that defines an SSA name from | 
 |    a conversion and is legal for us to combine with an add and multiply | 
 |    in the candidate table.  For example, suppose we have: | 
 |  | 
 |      A = B + i; | 
 |      C = (type) A; | 
 |      D = C * S; | 
 |  | 
 |    Without the type-cast, we would create a CAND_MULT for D with base B, | 
 |    index i, and stride S.  We want to record this candidate only if it | 
 |    is equivalent to apply the type cast following the multiply: | 
 |  | 
 |      A = B + i; | 
 |      E = A * S; | 
 |      D = (type) E; | 
 |  | 
 |    We will record the type with the candidate for D.  This allows us | 
 |    to use a similar previous candidate as a basis.  If we have earlier seen | 
 |  | 
 |      A' = B + i'; | 
 |      C' = (type) A'; | 
 |      D' = C' * S; | 
 |  | 
 |    we can replace D with | 
 |  | 
 |      D = D' + (i - i') * S; | 
 |  | 
 |    But if moving the type-cast would change semantics, we mustn't do this. | 
 |  | 
 |    This is legitimate for casts from a non-wrapping integral type to | 
 |    any integral type of the same or larger size.  It is not legitimate | 
 |    to convert a wrapping type to a non-wrapping type, or to a wrapping | 
 |    type of a different size.  I.e., with a wrapping type, we must | 
 |    assume that the addition B + i could wrap, in which case performing | 
 |    the multiply before or after one of the "illegal" type casts will | 
 |    have different semantics.  */ | 
 |  | 
 | static bool | 
 | legal_cast_p (gimple *gs, tree rhs) | 
 | { | 
 |   if (!is_gimple_assign (gs) | 
 |       || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs))) | 
 |     return false; | 
 |  | 
 |   return legal_cast_p_1 (TREE_TYPE (gimple_assign_lhs (gs)), TREE_TYPE (rhs)); | 
 | } | 
 |  | 
 | /* Given GS which is a cast to a scalar integer type, determine whether | 
 |    the cast is legal for strength reduction.  If so, make at least one | 
 |    appropriate entry in the candidate table.  */ | 
 |  | 
 | static void | 
 | slsr_process_cast (gimple *gs, tree rhs1, bool speed) | 
 | { | 
 |   tree lhs, ctype; | 
 |   slsr_cand_t base_cand, c = NULL, c2; | 
 |   unsigned savings = 0; | 
 |  | 
 |   if (!legal_cast_p (gs, rhs1)) | 
 |     return; | 
 |  | 
 |   lhs = gimple_assign_lhs (gs); | 
 |   base_cand = base_cand_from_table (rhs1); | 
 |   ctype = TREE_TYPE (lhs); | 
 |  | 
 |   if (base_cand && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       slsr_cand_t first_cand = NULL; | 
 |  | 
 |       while (base_cand) | 
 | 	{ | 
 | 	  /* Propagate all data from the base candidate except the type, | 
 | 	     which comes from the cast, and the base candidate's cast, | 
 | 	     which is no longer applicable.  */ | 
 | 	  if (has_single_use (rhs1)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 |  | 
 | 	  c = alloc_cand_and_find_basis (base_cand->kind, gs, | 
 | 					 base_cand->base_expr, | 
 | 					 base_cand->index, base_cand->stride, | 
 | 					 ctype, base_cand->stride_type, | 
 | 					 savings); | 
 | 	  if (!first_cand) | 
 | 	    first_cand = c; | 
 |  | 
 | 	  if (first_cand != c) | 
 | 	    c->first_interp = first_cand->cand_num; | 
 |  | 
 | 	  base_cand = lookup_cand (base_cand->next_interp); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       /* If nothing is known about the RHS, create fresh CAND_ADD and | 
 | 	 CAND_MULT interpretations: | 
 |  | 
 | 	 X = Y + (0 * 1) | 
 | 	 X = (Y + 0) * 1 | 
 |  | 
 | 	 The first of these is somewhat arbitrary, but the choice of | 
 | 	 1 for the stride simplifies the logic for propagating casts | 
 | 	 into their uses.  */ | 
 |       c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1, 0, | 
 | 				     integer_one_node, ctype, sizetype, 0); | 
 |       c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1, 0, | 
 | 				      integer_one_node, ctype, sizetype, 0); | 
 |       c->next_interp = c2->cand_num; | 
 |       c2->first_interp = c->cand_num; | 
 |     } | 
 |  | 
 |   /* Add the first (or only) interpretation to the statement-candidate | 
 |      mapping.  */ | 
 |   add_cand_for_stmt (gs, c); | 
 | } | 
 |  | 
 | /* Given GS which is a copy of a scalar integer type, make at least one | 
 |    appropriate entry in the candidate table. | 
 |  | 
 |    This interface is included for completeness, but is unnecessary | 
 |    if this pass immediately follows a pass that performs copy | 
 |    propagation, such as DOM.  */ | 
 |  | 
 | static void | 
 | slsr_process_copy (gimple *gs, tree rhs1, bool speed) | 
 | { | 
 |   slsr_cand_t base_cand, c = NULL, c2; | 
 |   unsigned savings = 0; | 
 |  | 
 |   base_cand = base_cand_from_table (rhs1); | 
 |  | 
 |   if (base_cand && base_cand->kind != CAND_PHI) | 
 |     { | 
 |       slsr_cand_t first_cand = NULL; | 
 |  | 
 |       while (base_cand) | 
 | 	{ | 
 | 	  /* Propagate all data from the base candidate.  */ | 
 | 	  if (has_single_use (rhs1)) | 
 | 	    savings = (base_cand->dead_savings | 
 | 		       + stmt_cost (base_cand->cand_stmt, speed)); | 
 |  | 
 | 	  c = alloc_cand_and_find_basis (base_cand->kind, gs, | 
 | 					 base_cand->base_expr, | 
 | 					 base_cand->index, base_cand->stride, | 
 | 					 base_cand->cand_type, | 
 | 					 base_cand->stride_type, savings); | 
 | 	  if (!first_cand) | 
 | 	    first_cand = c; | 
 |  | 
 | 	  if (first_cand != c) | 
 | 	    c->first_interp = first_cand->cand_num; | 
 |  | 
 | 	  base_cand = lookup_cand (base_cand->next_interp); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       /* If nothing is known about the RHS, create fresh CAND_ADD and | 
 | 	 CAND_MULT interpretations: | 
 |  | 
 | 	 X = Y + (0 * 1) | 
 | 	 X = (Y + 0) * 1 | 
 |  | 
 | 	 The first of these is somewhat arbitrary, but the choice of | 
 | 	 1 for the stride simplifies the logic for propagating casts | 
 | 	 into their uses.  */ | 
 |       c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1, 0, | 
 | 				     integer_one_node, TREE_TYPE (rhs1), | 
 | 				     sizetype, 0); | 
 |       c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1, 0, | 
 | 				      integer_one_node, TREE_TYPE (rhs1), | 
 | 				      sizetype, 0); | 
 |       c->next_interp = c2->cand_num; | 
 |       c2->first_interp = c->cand_num; | 
 |     } | 
 |  | 
 |   /* Add the first (or only) interpretation to the statement-candidate | 
 |      mapping.  */ | 
 |   add_cand_for_stmt (gs, c); | 
 | } | 
 |  | 
 | class find_candidates_dom_walker : public dom_walker | 
 | { | 
 | public: | 
 |   find_candidates_dom_walker (cdi_direction direction) | 
 |     : dom_walker (direction) {} | 
 |   edge before_dom_children (basic_block) final override; | 
 | }; | 
 |  | 
 | /* Find strength-reduction candidates in block BB.  */ | 
 |  | 
 | edge | 
 | find_candidates_dom_walker::before_dom_children (basic_block bb) | 
 | { | 
 |   bool speed = optimize_bb_for_speed_p (bb); | 
 |  | 
 |   for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); | 
 |        gsi_next (&gsi)) | 
 |     slsr_process_phi (gsi.phi (), speed); | 
 |  | 
 |   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); | 
 |        gsi_next (&gsi)) | 
 |     { | 
 |       gimple *gs = gsi_stmt (gsi); | 
 |  | 
 |       if (stmt_could_throw_p (cfun, gs)) | 
 | 	continue; | 
 |  | 
 |       if (gimple_vuse (gs) && gimple_assign_single_p (gs)) | 
 | 	slsr_process_ref (gs); | 
 |  | 
 |       else if (is_gimple_assign (gs) | 
 | 	       && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (gs))) | 
 | 		   || POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (gs))))) | 
 | 	{ | 
 | 	  tree rhs1 = NULL_TREE, rhs2 = NULL_TREE; | 
 |  | 
 | 	  switch (gimple_assign_rhs_code (gs)) | 
 | 	    { | 
 | 	    case MULT_EXPR: | 
 | 	    case PLUS_EXPR: | 
 | 	      rhs1 = gimple_assign_rhs1 (gs); | 
 | 	      rhs2 = gimple_assign_rhs2 (gs); | 
 | 	      /* Should never happen, but currently some buggy situations | 
 | 		 in earlier phases put constants in rhs1.  */ | 
 | 	      if (TREE_CODE (rhs1) != SSA_NAME) | 
 | 		continue; | 
 | 	      break; | 
 |  | 
 | 	    /* Possible future opportunity: rhs1 of a ptr+ can be | 
 | 	       an ADDR_EXPR.  */ | 
 | 	    case POINTER_PLUS_EXPR: | 
 | 	    case MINUS_EXPR: | 
 | 	      rhs2 = gimple_assign_rhs2 (gs); | 
 | 	      gcc_fallthrough (); | 
 |  | 
 | 	    CASE_CONVERT: | 
 | 	    case SSA_NAME: | 
 | 	    case NEGATE_EXPR: | 
 | 	      rhs1 = gimple_assign_rhs1 (gs); | 
 | 	      if (TREE_CODE (rhs1) != SSA_NAME) | 
 | 		continue; | 
 | 	      break; | 
 |  | 
 | 	    default: | 
 | 	      ; | 
 | 	    } | 
 |  | 
 | 	  switch (gimple_assign_rhs_code (gs)) | 
 | 	    { | 
 | 	    case MULT_EXPR: | 
 | 	      slsr_process_mul (gs, rhs1, rhs2, speed); | 
 | 	      break; | 
 |  | 
 | 	    case PLUS_EXPR: | 
 | 	    case POINTER_PLUS_EXPR: | 
 | 	    case MINUS_EXPR: | 
 | 	      slsr_process_add (gs, rhs1, rhs2, speed); | 
 | 	      break; | 
 |  | 
 | 	    case NEGATE_EXPR: | 
 | 	      slsr_process_neg (gs, rhs1, speed); | 
 | 	      break; | 
 |  | 
 | 	    CASE_CONVERT: | 
 | 	      slsr_process_cast (gs, rhs1, speed); | 
 | 	      break; | 
 |  | 
 | 	    case SSA_NAME: | 
 | 	      slsr_process_copy (gs, rhs1, speed); | 
 | 	      break; | 
 |  | 
 | 	    default: | 
 | 	      ; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Dump a candidate for debug.  */ | 
 |  | 
 | static void | 
 | dump_candidate (slsr_cand_t c) | 
 | { | 
 |   fprintf (dump_file, "%3d  [%d] ", c->cand_num, | 
 | 	   gimple_bb (c->cand_stmt)->index); | 
 |   print_gimple_stmt (dump_file, c->cand_stmt, 0); | 
 |   switch (c->kind) | 
 |     { | 
 |     case CAND_MULT: | 
 |       fputs ("     MULT : (", dump_file); | 
 |       print_generic_expr (dump_file, c->base_expr); | 
 |       fputs (" + ", dump_file); | 
 |       print_decs (c->index, dump_file); | 
 |       fputs (") * ", dump_file); | 
 |       if (TREE_CODE (c->stride) != INTEGER_CST | 
 | 	  && c->stride_type != TREE_TYPE (c->stride)) | 
 | 	{ | 
 | 	  fputs ("(", dump_file); | 
 | 	  print_generic_expr (dump_file, c->stride_type); | 
 | 	  fputs (")", dump_file); | 
 | 	} | 
 |       print_generic_expr (dump_file, c->stride); | 
 |       fputs (" : ", dump_file); | 
 |       break; | 
 |     case CAND_ADD: | 
 |       fputs ("     ADD  : ", dump_file); | 
 |       print_generic_expr (dump_file, c->base_expr); | 
 |       fputs (" + (", dump_file); | 
 |       print_decs (c->index, dump_file); | 
 |       fputs (" * ", dump_file); | 
 |       if (TREE_CODE (c->stride) != INTEGER_CST | 
 | 	  && c->stride_type != TREE_TYPE (c->stride)) | 
 | 	{ | 
 | 	  fputs ("(", dump_file); | 
 | 	  print_generic_expr (dump_file, c->stride_type); | 
 | 	  fputs (")", dump_file); | 
 | 	} | 
 |       print_generic_expr (dump_file, c->stride); | 
 |       fputs (") : ", dump_file); | 
 |       break; | 
 |     case CAND_REF: | 
 |       fputs ("     REF  : ", dump_file); | 
 |       print_generic_expr (dump_file, c->base_expr); | 
 |       fputs (" + (", dump_file); | 
 |       print_generic_expr (dump_file, c->stride); | 
 |       fputs (") + ", dump_file); | 
 |       print_decs (c->index, dump_file); | 
 |       fputs (" : ", dump_file); | 
 |       break; | 
 |     case CAND_PHI: | 
 |       fputs ("     PHI  : ", dump_file); | 
 |       print_generic_expr (dump_file, c->base_expr); | 
 |       fputs (" + (unknown * ", dump_file); | 
 |       print_generic_expr (dump_file, c->stride); | 
 |       fputs (") : ", dump_file); | 
 |       break; | 
 |     default: | 
 |       gcc_unreachable (); | 
 |     } | 
 |   print_generic_expr (dump_file, c->cand_type); | 
 |   fprintf (dump_file, "\n     basis: %d  dependent: %d  sibling: %d\n", | 
 | 	   c->basis, c->dependent, c->sibling); | 
 |   fprintf (dump_file, | 
 | 	   "     next-interp: %d  first-interp: %d  dead-savings: %d\n", | 
 | 	   c->next_interp, c->first_interp, c->dead_savings); | 
 |   if (c->def_phi) | 
 |     fprintf (dump_file, "     phi:  %d\n", c->def_phi); | 
 |   fputs ("\n", dump_file); | 
 | } | 
 |  | 
 | /* Dump the candidate vector for debug.  */ | 
 |  | 
 | static void | 
 | dump_cand_vec (void) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t c; | 
 |  | 
 |   fprintf (dump_file, "\nStrength reduction candidate vector:\n\n"); | 
 |  | 
 |   FOR_EACH_VEC_ELT (cand_vec, i, c) | 
 |     if (c != NULL) | 
 |       dump_candidate (c); | 
 | } | 
 |  | 
 | /* Callback used to dump the candidate chains hash table.  */ | 
 |  | 
 | int | 
 | ssa_base_cand_dump_callback (cand_chain **slot, void *ignored ATTRIBUTE_UNUSED) | 
 | { | 
 |   const_cand_chain_t chain = *slot; | 
 |   cand_chain_t p; | 
 |  | 
 |   print_generic_expr (dump_file, chain->base_expr); | 
 |   fprintf (dump_file, " -> %d", chain->cand->cand_num); | 
 |  | 
 |   for (p = chain->next; p; p = p->next) | 
 |     fprintf (dump_file, " -> %d", p->cand->cand_num); | 
 |  | 
 |   fputs ("\n", dump_file); | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Dump the candidate chains.  */ | 
 |  | 
 | static void | 
 | dump_cand_chains (void) | 
 | { | 
 |   fprintf (dump_file, "\nStrength reduction candidate chains:\n\n"); | 
 |   base_cand_map->traverse_noresize <void *, ssa_base_cand_dump_callback> | 
 |     (NULL); | 
 |   fputs ("\n", dump_file); | 
 | } | 
 |  | 
 | /* Dump the increment vector for debug.  */ | 
 |  | 
 | static void | 
 | dump_incr_vec (void) | 
 | { | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       unsigned i; | 
 |  | 
 |       fprintf (dump_file, "\nIncrement vector:\n\n"); | 
 |  | 
 |       for (i = 0; i < incr_vec_len; i++) | 
 | 	{ | 
 | 	  fprintf (dump_file, "%3d  increment:   ", i); | 
 | 	  print_decs (incr_vec[i].incr, dump_file); | 
 | 	  fprintf (dump_file, "\n     count:       %d", incr_vec[i].count); | 
 | 	  fprintf (dump_file, "\n     cost:        %d", incr_vec[i].cost); | 
 | 	  fputs ("\n     initializer: ", dump_file); | 
 | 	  print_generic_expr (dump_file, incr_vec[i].initializer); | 
 | 	  fputs ("\n\n", dump_file); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Replace *EXPR in candidate C with an equivalent strength-reduced | 
 |    data reference.  */ | 
 |  | 
 | static void | 
 | replace_ref (tree *expr, slsr_cand_t c) | 
 | { | 
 |   tree add_expr, mem_ref, acc_type = TREE_TYPE (*expr); | 
 |   unsigned HOST_WIDE_INT misalign; | 
 |   unsigned align; | 
 |  | 
 |   /* Ensure the memory reference carries the minimum alignment | 
 |      requirement for the data type.  See PR58041.  */ | 
 |   get_object_alignment_1 (*expr, &align, &misalign); | 
 |   if (misalign != 0) | 
 |     align = least_bit_hwi (misalign); | 
 |   if (align < TYPE_ALIGN (acc_type)) | 
 |     acc_type = build_aligned_type (acc_type, align); | 
 |  | 
 |   add_expr = fold_build2 (POINTER_PLUS_EXPR, c->cand_type, | 
 | 			  c->base_expr, c->stride); | 
 |   mem_ref = fold_build2 (MEM_REF, acc_type, add_expr, | 
 | 			 wide_int_to_tree (c->cand_type, c->index)); | 
 |  | 
 |   /* Gimplify the base addressing expression for the new MEM_REF tree.  */ | 
 |   gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 |   TREE_OPERAND (mem_ref, 0) | 
 |     = force_gimple_operand_gsi (&gsi, TREE_OPERAND (mem_ref, 0), | 
 | 				/*simple_p=*/true, NULL, | 
 | 				/*before=*/true, GSI_SAME_STMT); | 
 |   copy_ref_info (mem_ref, *expr); | 
 |   *expr = mem_ref; | 
 |   update_stmt (c->cand_stmt); | 
 | } | 
 |  | 
 | /* Return true if CAND_REF candidate C is a valid memory reference.  */ | 
 |  | 
 | static bool | 
 | valid_mem_ref_cand_p (slsr_cand_t c) | 
 | { | 
 |   if (TREE_CODE (TREE_OPERAND (c->stride, 1)) != INTEGER_CST) | 
 |     return false; | 
 |  | 
 |   struct mem_address addr | 
 |     = { NULL_TREE, c->base_expr, TREE_OPERAND (c->stride, 0), | 
 | 	TREE_OPERAND (c->stride, 1), wide_int_to_tree (sizetype, c->index) }; | 
 |  | 
 |   return | 
 |     valid_mem_ref_p (TYPE_MODE (c->cand_type), TYPE_ADDR_SPACE (c->cand_type), | 
 | 		     &addr); | 
 | } | 
 |  | 
 | /* Replace CAND_REF candidate C, each sibling of candidate C, and each | 
 |    dependent of candidate C with an equivalent strength-reduced data | 
 |    reference.  */ | 
 |  | 
 | static void | 
 | replace_refs (slsr_cand_t c) | 
 | { | 
 |   /* Replacing a chain of only 2 candidates which are valid memory references | 
 |      is generally counter-productive because you cannot recoup the additional | 
 |      calculation added in front of them.  */ | 
 |   if (c->basis == 0 | 
 |       && c->dependent | 
 |       && !lookup_cand (c->dependent)->dependent | 
 |       && valid_mem_ref_cand_p (c) | 
 |       && valid_mem_ref_cand_p (lookup_cand (c->dependent))) | 
 |     return; | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("Replacing reference: ", dump_file); | 
 |       print_gimple_stmt (dump_file, c->cand_stmt, 0); | 
 |     } | 
 |  | 
 |   if (gimple_vdef (c->cand_stmt)) | 
 |     { | 
 |       tree *lhs = gimple_assign_lhs_ptr (c->cand_stmt); | 
 |       replace_ref (lhs, c); | 
 |     } | 
 |   else | 
 |     { | 
 |       tree *rhs = gimple_assign_rhs1_ptr (c->cand_stmt); | 
 |       replace_ref (rhs, c); | 
 |     } | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("With: ", dump_file); | 
 |       print_gimple_stmt (dump_file, c->cand_stmt, 0); | 
 |       fputs ("\n", dump_file); | 
 |     } | 
 |  | 
 |   if (c->sibling) | 
 |     replace_refs (lookup_cand (c->sibling)); | 
 |  | 
 |   if (c->dependent) | 
 |     replace_refs (lookup_cand (c->dependent)); | 
 | } | 
 |  | 
 | /* Return TRUE if candidate C is dependent upon a PHI.  */ | 
 |  | 
 | static bool | 
 | phi_dependent_cand_p (slsr_cand_t c) | 
 | { | 
 |   /* A candidate is not necessarily dependent upon a PHI just because | 
 |      it has a phi definition for its base name.  It may have a basis | 
 |      that relies upon the same phi definition, in which case the PHI | 
 |      is irrelevant to this candidate.  */ | 
 |   return (c->def_phi | 
 | 	  && c->basis | 
 | 	  && lookup_cand (c->basis)->def_phi != c->def_phi); | 
 | } | 
 |  | 
 | /* Calculate the increment required for candidate C relative to | 
 |    its basis.  */ | 
 |  | 
 | static offset_int | 
 | cand_increment (slsr_cand_t c) | 
 | { | 
 |   slsr_cand_t basis; | 
 |  | 
 |   /* If the candidate doesn't have a basis, just return its own | 
 |      index.  This is useful in record_increments to help us find | 
 |      an existing initializer.  Also, if the candidate's basis is | 
 |      hidden by a phi, then its own index will be the increment | 
 |      from the newly introduced phi basis.  */ | 
 |   if (!c->basis || phi_dependent_cand_p (c)) | 
 |     return c->index; | 
 |  | 
 |   basis = lookup_cand (c->basis); | 
 |   gcc_assert (operand_equal_p (c->base_expr, basis->base_expr, 0)); | 
 |   return c->index - basis->index; | 
 | } | 
 |  | 
 | /* Calculate the increment required for candidate C relative to | 
 |    its basis.  If we aren't going to generate pointer arithmetic | 
 |    for this candidate, return the absolute value of that increment | 
 |    instead.  */ | 
 |  | 
 | static inline offset_int | 
 | cand_abs_increment (slsr_cand_t c) | 
 | { | 
 |   offset_int increment = cand_increment (c); | 
 |  | 
 |   if (!address_arithmetic_p && wi::neg_p (increment)) | 
 |     increment = -increment; | 
 |  | 
 |   return increment; | 
 | } | 
 |  | 
 | /* Return TRUE iff candidate C has already been replaced under | 
 |    another interpretation.  */ | 
 |  | 
 | static inline bool | 
 | cand_already_replaced (slsr_cand_t c) | 
 | { | 
 |   return (gimple_bb (c->cand_stmt) == 0); | 
 | } | 
 |  | 
 | /* Common logic used by replace_unconditional_candidate and | 
 |    replace_conditional_candidate.  */ | 
 |  | 
 | static void | 
 | replace_mult_candidate (slsr_cand_t c, tree basis_name, offset_int bump, | 
 | 			auto_bitmap &sdce_worklist) | 
 | { | 
 |   tree target_type = TREE_TYPE (gimple_assign_lhs (c->cand_stmt)); | 
 |   enum tree_code cand_code = gimple_assign_rhs_code (c->cand_stmt); | 
 |  | 
 |   /* It is not useful to replace casts, copies, negates, or adds of | 
 |      an SSA name and a constant.  */ | 
 |   if (cand_code == SSA_NAME | 
 |       || CONVERT_EXPR_CODE_P (cand_code) | 
 |       || cand_code == PLUS_EXPR | 
 |       || cand_code == POINTER_PLUS_EXPR | 
 |       || cand_code == MINUS_EXPR | 
 |       || cand_code == NEGATE_EXPR) | 
 |     return; | 
 |  | 
 |   enum tree_code code = PLUS_EXPR; | 
 |   tree bump_tree; | 
 |   gimple *stmt_to_print = NULL; | 
 |  | 
 |   if (wi::neg_p (bump)) | 
 |     { | 
 |       code = MINUS_EXPR; | 
 |       bump = -bump; | 
 |     } | 
 |  | 
 |   /* It is possible that the resulting bump doesn't fit in target_type. | 
 |      Abandon the replacement in this case.  This does not affect | 
 |      siblings or dependents of C.  */ | 
 |   if (bump != wi::ext (bump, TYPE_PRECISION (target_type), | 
 | 		       TYPE_SIGN (target_type))) | 
 |     return; | 
 |  | 
 |   bump_tree = wide_int_to_tree (target_type, bump); | 
 |  | 
 |   /* If the basis name and the candidate's LHS have incompatible types, | 
 |      introduce a cast.  */ | 
 |   if (!useless_type_conversion_p (target_type, TREE_TYPE (basis_name))) | 
 |     basis_name = introduce_cast_before_cand (c, target_type, basis_name); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("Replacing: ", dump_file); | 
 |       print_gimple_stmt (dump_file, c->cand_stmt, 0); | 
 |     } | 
 |  | 
 |   if (bump == 0) | 
 |     { | 
 |       tree lhs = gimple_assign_lhs (c->cand_stmt); | 
 |       gassign *copy_stmt = gimple_build_assign (lhs, basis_name); | 
 |       gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 |       slsr_cand_t cc = lookup_cand (c->first_interp); | 
 |       gimple_set_location (copy_stmt, gimple_location (c->cand_stmt)); | 
 |       gsi_replace (&gsi, copy_stmt, false); | 
 |       while (cc) | 
 | 	{ | 
 | 	  cc->cand_stmt = copy_stmt; | 
 | 	  cc = lookup_cand (cc->next_interp); | 
 | 	} | 
 |       if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	stmt_to_print = copy_stmt; | 
 |     } | 
 |   else | 
 |     { | 
 |       tree rhs1, rhs2; | 
 |       if (cand_code != NEGATE_EXPR) { | 
 | 	rhs1 = gimple_assign_rhs1 (c->cand_stmt); | 
 | 	rhs2 = gimple_assign_rhs2 (c->cand_stmt); | 
 | 	/* Mark the 2 original rhs for maybe DCEing.  */ | 
 | 	if (TREE_CODE (rhs1) == SSA_NAME) | 
 | 	  bitmap_set_bit (sdce_worklist, SSA_NAME_VERSION (rhs1)); | 
 | 	if (TREE_CODE (rhs2) == SSA_NAME) | 
 | 	  bitmap_set_bit (sdce_worklist, SSA_NAME_VERSION (rhs2)); | 
 |       } | 
 |       if (cand_code != NEGATE_EXPR | 
 | 	  && ((operand_equal_p (rhs1, basis_name, 0) | 
 | 	       && operand_equal_p (rhs2, bump_tree, 0)) | 
 | 	      || (operand_equal_p (rhs1, bump_tree, 0) | 
 | 		  && operand_equal_p (rhs2, basis_name, 0)))) | 
 | 	{ | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    { | 
 | 	      fputs ("(duplicate, not actually replacing)", dump_file); | 
 | 	      stmt_to_print = c->cand_stmt; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 | 	  slsr_cand_t cc = lookup_cand (c->first_interp); | 
 | 	  gimple_assign_set_rhs_with_ops (&gsi, code, basis_name, bump_tree); | 
 | 	  update_stmt (gsi_stmt (gsi)); | 
 | 	  while (cc) | 
 | 	    { | 
 | 	      cc->cand_stmt = gsi_stmt (gsi); | 
 | 	      cc = lookup_cand (cc->next_interp); | 
 | 	    } | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    stmt_to_print = gsi_stmt (gsi); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("With: ", dump_file); | 
 |       print_gimple_stmt (dump_file, stmt_to_print, 0); | 
 |       fputs ("\n", dump_file); | 
 |     } | 
 | } | 
 |  | 
 | /* Replace candidate C with an add or subtract.   Note that we only | 
 |    operate on CAND_MULTs with known strides, so we will never generate | 
 |    a POINTER_PLUS_EXPR.  Each candidate X = (B + i) * S is replaced by | 
 |    X = Y + ((i - i') * S), as described in the module commentary.  The | 
 |    folded value ((i - i') * S) is referred to here as the "bump."  */ | 
 |  | 
 | static void | 
 | replace_unconditional_candidate (slsr_cand_t c, auto_bitmap &sdce_worklist) | 
 | { | 
 |   slsr_cand_t basis; | 
 |  | 
 |   if (cand_already_replaced (c)) | 
 |     return; | 
 |  | 
 |   basis = lookup_cand (c->basis); | 
 |   offset_int bump = cand_increment (c) * wi::to_offset (c->stride); | 
 |  | 
 |   replace_mult_candidate (c, gimple_assign_lhs (basis->cand_stmt), bump, | 
 | 			  sdce_worklist); | 
 | } | 
 |  | 
 | /* Return the index in the increment vector of the given INCREMENT, | 
 |    or -1 if not found.  The latter can occur if more than | 
 |    MAX_INCR_VEC_LEN increments have been found.  */ | 
 |  | 
 | static inline int | 
 | incr_vec_index (const offset_int &increment) | 
 | { | 
 |   unsigned i; | 
 |  | 
 |   for (i = 0; i < incr_vec_len && increment != incr_vec[i].incr; i++) | 
 |     ; | 
 |  | 
 |   if (i < incr_vec_len) | 
 |     return i; | 
 |   else | 
 |     return -1; | 
 | } | 
 |  | 
 | /* Create a new statement along edge E to add BASIS_NAME to the product | 
 |    of INCREMENT and the stride of candidate C.  Create and return a new | 
 |    SSA name from *VAR to be used as the LHS of the new statement. | 
 |    KNOWN_STRIDE is true iff C's stride is a constant.  */ | 
 |  | 
 | static tree | 
 | create_add_on_incoming_edge (slsr_cand_t c, tree basis_name, | 
 | 			     offset_int increment, edge e, location_t loc, | 
 | 			     bool known_stride) | 
 | { | 
 |   tree lhs, basis_type; | 
 |   gassign *new_stmt, *cast_stmt = NULL; | 
 |  | 
 |   /* If the add candidate along this incoming edge has the same | 
 |      index as C's hidden basis, the hidden basis represents this | 
 |      edge correctly.  */ | 
 |   if (increment == 0) | 
 |     return basis_name; | 
 |  | 
 |   basis_type = TREE_TYPE (basis_name); | 
 |   lhs = make_temp_ssa_name (basis_type, NULL, "slsr"); | 
 |  | 
 |   /* Occasionally people convert integers to pointers without a | 
 |      cast, leading us into trouble if we aren't careful.  */ | 
 |   enum tree_code plus_code | 
 |     = POINTER_TYPE_P (basis_type) ? POINTER_PLUS_EXPR : PLUS_EXPR; | 
 |  | 
 |   if (known_stride) | 
 |     { | 
 |       tree bump_tree; | 
 |       enum tree_code code = plus_code; | 
 |       offset_int bump = increment * wi::to_offset (c->stride); | 
 |       if (wi::neg_p (bump) && !POINTER_TYPE_P (basis_type)) | 
 | 	{ | 
 | 	  code = MINUS_EXPR; | 
 | 	  bump = -bump; | 
 | 	} | 
 |  | 
 |       tree stride_type = POINTER_TYPE_P (basis_type) ? sizetype : basis_type; | 
 |       bump_tree = wide_int_to_tree (stride_type, bump); | 
 |       new_stmt = gimple_build_assign (lhs, code, basis_name, bump_tree); | 
 |     } | 
 |   else | 
 |     { | 
 |       int i; | 
 |       bool negate_incr = !POINTER_TYPE_P (basis_type) && wi::neg_p (increment); | 
 |       i = incr_vec_index (negate_incr ? -increment : increment); | 
 |       gcc_assert (i >= 0); | 
 |  | 
 |       if (incr_vec[i].initializer) | 
 | 	{ | 
 | 	  enum tree_code code = negate_incr ? MINUS_EXPR : plus_code; | 
 | 	  new_stmt = gimple_build_assign (lhs, code, basis_name, | 
 | 					  incr_vec[i].initializer); | 
 | 	} | 
 |       else { | 
 | 	tree stride; | 
 |  | 
 | 	if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type)) | 
 | 	  { | 
 | 	    tree cast_stride = make_temp_ssa_name (c->stride_type, NULL, | 
 | 						   "slsr"); | 
 | 	    cast_stmt = gimple_build_assign (cast_stride, NOP_EXPR, | 
 | 					     c->stride); | 
 | 	    stride = cast_stride; | 
 | 	  } | 
 | 	else | 
 | 	  stride = c->stride; | 
 |  | 
 | 	if (increment == 1) | 
 | 	  new_stmt = gimple_build_assign (lhs, plus_code, basis_name, stride); | 
 | 	else if (increment == -1) | 
 | 	  new_stmt = gimple_build_assign (lhs, MINUS_EXPR, basis_name, stride); | 
 | 	else | 
 | 	  gcc_unreachable (); | 
 |       } | 
 |     } | 
 |  | 
 |   if (cast_stmt) | 
 |     { | 
 |       gimple_set_location (cast_stmt, loc); | 
 |       gsi_insert_on_edge (e, cast_stmt); | 
 |     } | 
 |  | 
 |   gimple_set_location (new_stmt, loc); | 
 |   gsi_insert_on_edge (e, new_stmt); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       if (cast_stmt) | 
 | 	{ | 
 | 	  fprintf (dump_file, "Inserting cast on edge %d->%d: ", | 
 | 		   e->src->index, e->dest->index); | 
 | 	  print_gimple_stmt (dump_file, cast_stmt, 0); | 
 | 	} | 
 |       fprintf (dump_file, "Inserting on edge %d->%d: ", e->src->index, | 
 | 	       e->dest->index); | 
 |       print_gimple_stmt (dump_file, new_stmt, 0); | 
 |     } | 
 |  | 
 |   return lhs; | 
 | } | 
 |  | 
 | /* Clear the visited field for a tree of PHI candidates.  */ | 
 |  | 
 | static void | 
 | clear_visited (gphi *phi) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     { | 
 |       phi_cand->visited = 0; | 
 |  | 
 |       for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 | 	{ | 
 | 	  tree arg = gimple_phi_arg_def (phi, i); | 
 | 	  gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 | 	  if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	    clear_visited (as_a <gphi *> (arg_def)); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Recursive helper function for create_phi_basis.  */ | 
 |  | 
 | static tree | 
 | create_phi_basis_1 (slsr_cand_t c, gimple *from_phi, tree basis_name, | 
 | 		    location_t loc, bool known_stride) | 
 | { | 
 |   int i; | 
 |   tree name, phi_arg; | 
 |   gphi *phi; | 
 |   slsr_cand_t basis = lookup_cand (c->basis); | 
 |   int nargs = gimple_phi_num_args (from_phi); | 
 |   basic_block phi_bb = gimple_bb (from_phi); | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (from_phi); | 
 |   auto_vec<tree> phi_args (nargs); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     return phi_cand->cached_basis; | 
 |   phi_cand->visited = 1; | 
 |  | 
 |   /* Process each argument of the existing phi that represents | 
 |      conditionally-executed add candidates.  */ | 
 |   for (i = 0; i < nargs; i++) | 
 |     { | 
 |       edge e = (*phi_bb->preds)[i]; | 
 |       tree arg = gimple_phi_arg_def (from_phi, i); | 
 |       tree feeding_def; | 
 |  | 
 |       /* If the phi argument is the base name of the CAND_PHI, then | 
 | 	 this incoming arc should use the hidden basis.  */ | 
 |       if (operand_equal_p (arg, phi_cand->base_expr, 0)) | 
 | 	if (basis->index == 0) | 
 | 	  feeding_def = gimple_assign_lhs (basis->cand_stmt); | 
 | 	else | 
 | 	  { | 
 | 	    offset_int incr = -basis->index; | 
 | 	    feeding_def = create_add_on_incoming_edge (c, basis_name, incr, | 
 | 						       e, loc, known_stride); | 
 | 	  } | 
 |       else | 
 | 	{ | 
 | 	  gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 | 	  /* If there is another phi along this incoming edge, we must | 
 | 	     process it in the same fashion to ensure that all basis | 
 | 	     adjustments are made along its incoming edges.  */ | 
 | 	  if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	    feeding_def = create_phi_basis_1 (c, arg_def, basis_name, | 
 | 					      loc, known_stride); | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t arg_cand = base_cand_from_table (arg); | 
 | 	      offset_int diff = arg_cand->index - basis->index; | 
 | 	      feeding_def = create_add_on_incoming_edge (c, basis_name, diff, | 
 | 							 e, loc, known_stride); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* Because of recursion, we need to save the arguments in a vector | 
 | 	 so we can create the PHI statement all at once.  Otherwise the | 
 | 	 storage for the half-created PHI can be reclaimed.  */ | 
 |       phi_args.safe_push (feeding_def); | 
 |     } | 
 |  | 
 |   /* Create the new phi basis.  */ | 
 |   name = make_temp_ssa_name (TREE_TYPE (basis_name), NULL, "slsr"); | 
 |   phi = create_phi_node (name, phi_bb); | 
 |   SSA_NAME_DEF_STMT (name) = phi; | 
 |  | 
 |   FOR_EACH_VEC_ELT (phi_args, i, phi_arg) | 
 |     { | 
 |       edge e = (*phi_bb->preds)[i]; | 
 |       add_phi_arg (phi, phi_arg, e, loc); | 
 |     } | 
 |  | 
 |   update_stmt (phi); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("Introducing new phi basis: ", dump_file); | 
 |       print_gimple_stmt (dump_file, phi, 0); | 
 |     } | 
 |  | 
 |   phi_cand->cached_basis = name; | 
 |   return name; | 
 | } | 
 |  | 
 | /* Given a candidate C with BASIS_NAME being the LHS of C's basis which | 
 |    is hidden by the phi node FROM_PHI, create a new phi node in the same | 
 |    block as FROM_PHI.  The new phi is suitable for use as a basis by C, | 
 |    with its phi arguments representing conditional adjustments to the | 
 |    hidden basis along conditional incoming paths.  Those adjustments are | 
 |    made by creating add statements (and sometimes recursively creating | 
 |    phis) along those incoming paths.  LOC is the location to attach to | 
 |    the introduced statements.  KNOWN_STRIDE is true iff C's stride is a | 
 |    constant.  */ | 
 |  | 
 | static tree | 
 | create_phi_basis (slsr_cand_t c, gimple *from_phi, tree basis_name, | 
 | 		  location_t loc, bool known_stride) | 
 | { | 
 |   tree retval = create_phi_basis_1 (c, from_phi, basis_name, loc, | 
 | 				    known_stride); | 
 |   gcc_assert (retval); | 
 |   clear_visited (as_a <gphi *> (from_phi)); | 
 |   return retval; | 
 | } | 
 |  | 
 | /* Given a candidate C whose basis is hidden by at least one intervening | 
 |    phi, introduce a matching number of new phis to represent its basis | 
 |    adjusted by conditional increments along possible incoming paths.  Then | 
 |    replace C as though it were an unconditional candidate, using the new | 
 |    basis.  */ | 
 |  | 
 | static void | 
 | replace_conditional_candidate (slsr_cand_t c, auto_bitmap &sdce_worklist) | 
 |  | 
 | { | 
 |   tree basis_name, name; | 
 |   slsr_cand_t basis; | 
 |   location_t loc; | 
 |  | 
 |   /* Look up the LHS SSA name from C's basis.  This will be the | 
 |      RHS1 of the adds we will introduce to create new phi arguments.  */ | 
 |   basis = lookup_cand (c->basis); | 
 |   basis_name = gimple_assign_lhs (basis->cand_stmt); | 
 |  | 
 |   /* Create a new phi statement which will represent C's true basis | 
 |      after the transformation is complete.  */ | 
 |   loc = gimple_location (c->cand_stmt); | 
 |   name = create_phi_basis (c, lookup_cand (c->def_phi)->cand_stmt, | 
 | 			   basis_name, loc, KNOWN_STRIDE); | 
 |  | 
 |   /* Replace C with an add of the new basis phi and a constant.  */ | 
 |   offset_int bump = c->index * wi::to_offset (c->stride); | 
 |  | 
 |   replace_mult_candidate (c, name, bump, sdce_worklist); | 
 | } | 
 |  | 
 | /* Recursive helper function for phi_add_costs.  SPREAD is a measure of | 
 |    how many PHI nodes we have visited at this point in the tree walk.  */ | 
 |  | 
 | static int | 
 | phi_add_costs_1 (gimple *phi, slsr_cand_t c, int one_add_cost, int *spread) | 
 | { | 
 |   unsigned i; | 
 |   int cost = 0; | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     return 0; | 
 |  | 
 |   phi_cand->visited = 1; | 
 |   (*spread)++; | 
 |  | 
 |   /* If we work our way back to a phi that isn't dominated by the hidden | 
 |      basis, this isn't a candidate for replacement.  Indicate this by | 
 |      returning an unreasonably high cost.  It's not easy to detect | 
 |      these situations when determining the basis, so we defer the | 
 |      decision until now.  */ | 
 |   basic_block phi_bb = gimple_bb (phi); | 
 |   slsr_cand_t basis = lookup_cand (c->basis); | 
 |   basic_block basis_bb = gimple_bb (basis->cand_stmt); | 
 |  | 
 |   if (phi_bb == basis_bb || !dominated_by_p (CDI_DOMINATORS, phi_bb, basis_bb)) | 
 |     return COST_INFINITE; | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |  | 
 |       if (arg != phi_cand->base_expr) | 
 | 	{ | 
 | 	  gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 | 	  if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	    { | 
 | 	      cost += phi_add_costs_1 (arg_def, c, one_add_cost, spread); | 
 |  | 
 | 	      if (cost >= COST_INFINITE || *spread > MAX_SPREAD) | 
 | 		return COST_INFINITE; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t arg_cand = base_cand_from_table (arg); | 
 |  | 
 | 	      if (arg_cand->index != c->index) | 
 | 		cost += one_add_cost; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   return cost; | 
 | } | 
 |  | 
 | /* Compute the expected costs of inserting basis adjustments for | 
 |    candidate C with phi-definition PHI.  The cost of inserting | 
 |    one adjustment is given by ONE_ADD_COST.  If PHI has arguments | 
 |    which are themselves phi results, recursively calculate costs | 
 |    for those phis as well.  */ | 
 |  | 
 | static int | 
 | phi_add_costs (gimple *phi, slsr_cand_t c, int one_add_cost) | 
 | { | 
 |   int spread = 0; | 
 |   int retval = phi_add_costs_1 (phi, c, one_add_cost, &spread); | 
 |   clear_visited (as_a <gphi *> (phi)); | 
 |   return retval; | 
 | } | 
 | /* For candidate C, each sibling of candidate C, and each dependent of | 
 |    candidate C, determine whether the candidate is dependent upon a | 
 |    phi that hides its basis.  If not, replace the candidate unconditionally. | 
 |    Otherwise, determine whether the cost of introducing compensation code | 
 |    for the candidate is offset by the gains from strength reduction.  If | 
 |    so, replace the candidate and introduce the compensation code.  */ | 
 |  | 
 | static void | 
 | replace_uncond_cands_and_profitable_phis (slsr_cand_t c, | 
 | 					  auto_bitmap &sdce_worklist) | 
 | { | 
 |   if (phi_dependent_cand_p (c)) | 
 |     { | 
 |       /* A multiply candidate with a stride of 1 is just an artifice | 
 | 	 of a copy or cast; there is no value in replacing it.  */ | 
 |       if (c->kind == CAND_MULT && wi::to_offset (c->stride) != 1) | 
 | 	{ | 
 | 	  /* A candidate dependent upon a phi will replace a multiply by | 
 | 	     a constant with an add, and will insert at most one add for | 
 | 	     each phi argument.  Add these costs with the potential dead-code | 
 | 	     savings to determine profitability.  */ | 
 | 	  bool speed = optimize_bb_for_speed_p (gimple_bb (c->cand_stmt)); | 
 | 	  int mult_savings = stmt_cost (c->cand_stmt, speed); | 
 | 	  gimple *phi = lookup_cand (c->def_phi)->cand_stmt; | 
 | 	  tree phi_result = gimple_phi_result (phi); | 
 | 	  int one_add_cost = add_cost (speed, | 
 | 				       TYPE_MODE (TREE_TYPE (phi_result))); | 
 | 	  int add_costs = one_add_cost + phi_add_costs (phi, c, one_add_cost); | 
 | 	  int cost = add_costs - mult_savings - c->dead_savings; | 
 |  | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    { | 
 | 	      fprintf (dump_file, "  Conditional candidate %d:\n", c->cand_num); | 
 | 	      fprintf (dump_file, "    add_costs = %d\n", add_costs); | 
 | 	      fprintf (dump_file, "    mult_savings = %d\n", mult_savings); | 
 | 	      fprintf (dump_file, "    dead_savings = %d\n", c->dead_savings); | 
 | 	      fprintf (dump_file, "    cost = %d\n", cost); | 
 | 	      if (cost <= COST_NEUTRAL) | 
 | 		fputs ("  Replacing...\n", dump_file); | 
 | 	      else | 
 | 		fputs ("  Not replaced.\n", dump_file); | 
 | 	    } | 
 |  | 
 | 	  if (cost <= COST_NEUTRAL) | 
 | 	    replace_conditional_candidate (c, sdce_worklist); | 
 | 	} | 
 |     } | 
 |   else | 
 |     replace_unconditional_candidate (c, sdce_worklist); | 
 |  | 
 |   if (c->sibling) | 
 |     replace_uncond_cands_and_profitable_phis (lookup_cand (c->sibling), | 
 | 					      sdce_worklist); | 
 |  | 
 |   if (c->dependent) | 
 |     replace_uncond_cands_and_profitable_phis (lookup_cand (c->dependent), | 
 | 					      sdce_worklist); | 
 | } | 
 |  | 
 | /* Count the number of candidates in the tree rooted at C that have | 
 |    not already been replaced under other interpretations.  */ | 
 |  | 
 | static int | 
 | count_candidates (slsr_cand_t c) | 
 | { | 
 |   unsigned count = cand_already_replaced (c) ? 0 : 1; | 
 |  | 
 |   if (c->sibling) | 
 |     count += count_candidates (lookup_cand (c->sibling)); | 
 |  | 
 |   if (c->dependent) | 
 |     count += count_candidates (lookup_cand (c->dependent)); | 
 |  | 
 |   return count; | 
 | } | 
 |  | 
 | /* Increase the count of INCREMENT by one in the increment vector. | 
 |    INCREMENT is associated with candidate C.  If INCREMENT is to be | 
 |    conditionally executed as part of a conditional candidate replacement, | 
 |    IS_PHI_ADJUST is true, otherwise false.  If an initializer | 
 |    T_0 = stride * I is provided by a candidate that dominates all | 
 |    candidates with the same increment, also record T_0 for subsequent use.  */ | 
 |  | 
 | static void | 
 | record_increment (slsr_cand_t c, offset_int increment, bool is_phi_adjust) | 
 | { | 
 |   bool found = false; | 
 |   unsigned i; | 
 |  | 
 |   /* Treat increments that differ only in sign as identical so as to | 
 |      share initializers, unless we are generating pointer arithmetic.  */ | 
 |   if (!address_arithmetic_p && wi::neg_p (increment)) | 
 |     increment = -increment; | 
 |  | 
 |   for (i = 0; i < incr_vec_len; i++) | 
 |     { | 
 |       if (incr_vec[i].incr == increment) | 
 | 	{ | 
 | 	  incr_vec[i].count++; | 
 | 	  found = true; | 
 |  | 
 | 	  /* If we previously recorded an initializer that doesn't | 
 | 	     dominate this candidate, it's not going to be useful to | 
 | 	     us after all.  */ | 
 | 	  if (incr_vec[i].initializer | 
 | 	      && !dominated_by_p (CDI_DOMINATORS, | 
 | 				  gimple_bb (c->cand_stmt), | 
 | 				  incr_vec[i].init_bb)) | 
 | 	    { | 
 | 	      incr_vec[i].initializer = NULL_TREE; | 
 | 	      incr_vec[i].init_bb = NULL; | 
 | 	    } | 
 |  | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   if (!found && incr_vec_len < MAX_INCR_VEC_LEN - 1) | 
 |     { | 
 |       /* The first time we see an increment, create the entry for it. | 
 | 	 If this is the root candidate which doesn't have a basis, set | 
 | 	 the count to zero.  We're only processing it so it can possibly | 
 | 	 provide an initializer for other candidates.  */ | 
 |       incr_vec[incr_vec_len].incr = increment; | 
 |       incr_vec[incr_vec_len].count = c->basis || is_phi_adjust ? 1 : 0; | 
 |       incr_vec[incr_vec_len].cost = COST_INFINITE; | 
 |  | 
 |       /* Optimistically record the first occurrence of this increment | 
 | 	 as providing an initializer (if it does); we will revise this | 
 | 	 opinion later if it doesn't dominate all other occurrences. | 
 |          Exception:  increments of 0, 1 never need initializers; | 
 | 	 and phi adjustments don't ever provide initializers.  */ | 
 |       if (c->kind == CAND_ADD | 
 | 	  && !is_phi_adjust | 
 | 	  && c->index == increment | 
 | 	  && (increment > 1 || increment < 0) | 
 | 	  && (gimple_assign_rhs_code (c->cand_stmt) == PLUS_EXPR | 
 | 	      || gimple_assign_rhs_code (c->cand_stmt) == POINTER_PLUS_EXPR)) | 
 | 	{ | 
 | 	  tree t0 = NULL_TREE; | 
 | 	  tree rhs1 = gimple_assign_rhs1 (c->cand_stmt); | 
 | 	  tree rhs2 = gimple_assign_rhs2 (c->cand_stmt); | 
 | 	  if (operand_equal_p (rhs1, c->base_expr, 0)) | 
 | 	    t0 = rhs2; | 
 | 	  else if (operand_equal_p (rhs2, c->base_expr, 0)) | 
 | 	    t0 = rhs1; | 
 | 	  if (t0 | 
 | 	      && SSA_NAME_DEF_STMT (t0) | 
 | 	      && gimple_bb (SSA_NAME_DEF_STMT (t0))) | 
 | 	    { | 
 | 	      incr_vec[incr_vec_len].initializer = t0; | 
 | 	      incr_vec[incr_vec_len++].init_bb | 
 | 		= gimple_bb (SSA_NAME_DEF_STMT (t0)); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      incr_vec[incr_vec_len].initializer = NULL_TREE; | 
 | 	      incr_vec[incr_vec_len++].init_bb = NULL; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  incr_vec[incr_vec_len].initializer = NULL_TREE; | 
 | 	  incr_vec[incr_vec_len++].init_bb = NULL; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Recursive helper function for record_phi_increments.  */ | 
 |  | 
 | static void | 
 | record_phi_increments_1 (slsr_cand_t basis, gimple *phi) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     return; | 
 |   phi_cand->visited = 1; | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |       gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 |       if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	record_phi_increments_1 (basis, arg_def); | 
 |       else | 
 | 	{ | 
 | 	  offset_int diff; | 
 |  | 
 | 	  if (operand_equal_p (arg, phi_cand->base_expr, 0)) | 
 | 	    { | 
 | 	      diff = -basis->index; | 
 | 	      record_increment (phi_cand, diff, PHI_ADJUST); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t arg_cand = base_cand_from_table (arg); | 
 | 	      diff = arg_cand->index - basis->index; | 
 | 	      record_increment (arg_cand, diff, PHI_ADJUST); | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Given phi statement PHI that hides a candidate from its BASIS, find | 
 |    the increments along each incoming arc (recursively handling additional | 
 |    phis that may be present) and record them.  These increments are the | 
 |    difference in index between the index-adjusting statements and the | 
 |    index of the basis.  */ | 
 |  | 
 | static void | 
 | record_phi_increments (slsr_cand_t basis, gimple *phi) | 
 | { | 
 |   record_phi_increments_1 (basis, phi); | 
 |   clear_visited (as_a <gphi *> (phi)); | 
 | } | 
 |  | 
 | /* Determine how many times each unique increment occurs in the set | 
 |    of candidates rooted at C's parent, recording the data in the | 
 |    increment vector.  For each unique increment I, if an initializer | 
 |    T_0 = stride * I is provided by a candidate that dominates all | 
 |    candidates with the same increment, also record T_0 for subsequent | 
 |    use.  */ | 
 |  | 
 | static void | 
 | record_increments (slsr_cand_t c) | 
 | { | 
 |   if (!cand_already_replaced (c)) | 
 |     { | 
 |       if (!phi_dependent_cand_p (c)) | 
 | 	record_increment (c, cand_increment (c), NOT_PHI_ADJUST); | 
 |       else | 
 | 	{ | 
 | 	  /* A candidate with a basis hidden by a phi will have one | 
 | 	     increment for its relationship to the index represented by | 
 | 	     the phi, and potentially additional increments along each | 
 | 	     incoming edge.  For the root of the dependency tree (which | 
 | 	     has no basis), process just the initial index in case it has | 
 | 	     an initializer that can be used by subsequent candidates.  */ | 
 | 	  record_increment (c, c->index, NOT_PHI_ADJUST); | 
 |  | 
 | 	  if (c->basis) | 
 | 	    record_phi_increments (lookup_cand (c->basis), | 
 | 				   lookup_cand (c->def_phi)->cand_stmt); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (c->sibling) | 
 |     record_increments (lookup_cand (c->sibling)); | 
 |  | 
 |   if (c->dependent) | 
 |     record_increments (lookup_cand (c->dependent)); | 
 | } | 
 |  | 
 | /* Recursive helper function for phi_incr_cost.  */ | 
 |  | 
 | static int | 
 | phi_incr_cost_1 (slsr_cand_t c, const offset_int &incr, gimple *phi, | 
 | 		 int *savings) | 
 | { | 
 |   unsigned i; | 
 |   int cost = 0; | 
 |   slsr_cand_t basis = lookup_cand (c->basis); | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     return 0; | 
 |   phi_cand->visited = 1; | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |       gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 |       if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	{ | 
 | 	  int feeding_savings = 0; | 
 | 	  tree feeding_var = gimple_phi_result (arg_def); | 
 | 	  cost += phi_incr_cost_1 (c, incr, arg_def, &feeding_savings); | 
 | 	  if (uses_consumed_by_stmt (feeding_var, phi)) | 
 | 	    *savings += feeding_savings; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  offset_int diff; | 
 | 	  slsr_cand_t arg_cand; | 
 |  | 
 | 	  /* When the PHI argument is just a pass-through to the base | 
 | 	     expression of the hidden basis, the difference is zero minus | 
 | 	     the index of the basis.  There is no potential savings by | 
 | 	     eliminating a statement in this case.  */ | 
 | 	  if (operand_equal_p (arg, phi_cand->base_expr, 0)) | 
 | 	    { | 
 | 	      arg_cand = (slsr_cand_t)NULL; | 
 | 	      diff = -basis->index; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      arg_cand = base_cand_from_table (arg); | 
 | 	      diff = arg_cand->index - basis->index; | 
 | 	    } | 
 |  | 
 | 	  if (incr == diff) | 
 | 	    { | 
 | 	      tree basis_lhs = gimple_assign_lhs (basis->cand_stmt); | 
 | 	      cost += add_cost (true, TYPE_MODE (TREE_TYPE (basis_lhs))); | 
 | 	      if (arg_cand) | 
 | 		{ | 
 | 		  tree lhs = gimple_assign_lhs (arg_cand->cand_stmt); | 
 | 		  if (uses_consumed_by_stmt (lhs, phi)) | 
 | 		    *savings += stmt_cost (arg_cand->cand_stmt, true); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   return cost; | 
 | } | 
 |  | 
 | /* Add up and return the costs of introducing add statements that | 
 |    require the increment INCR on behalf of candidate C and phi | 
 |    statement PHI.  Accumulate into *SAVINGS the potential savings | 
 |    from removing existing statements that feed PHI and have no other | 
 |    uses.  */ | 
 |  | 
 | static int | 
 | phi_incr_cost (slsr_cand_t c, const offset_int &incr, gimple *phi, | 
 | 	       int *savings) | 
 | { | 
 |   int retval = phi_incr_cost_1 (c, incr, phi, savings); | 
 |   clear_visited (as_a <gphi *> (phi)); | 
 |   return retval; | 
 | } | 
 |  | 
 | /* Return the first candidate in the tree rooted at C that has not | 
 |    already been replaced, favoring siblings over dependents.  */ | 
 |  | 
 | static slsr_cand_t | 
 | unreplaced_cand_in_tree (slsr_cand_t c) | 
 | { | 
 |   if (!cand_already_replaced (c)) | 
 |     return c; | 
 |  | 
 |   if (c->sibling) | 
 |     { | 
 |       slsr_cand_t sib = unreplaced_cand_in_tree (lookup_cand (c->sibling)); | 
 |       if (sib) | 
 | 	return sib; | 
 |     } | 
 |  | 
 |   if (c->dependent) | 
 |     { | 
 |       slsr_cand_t dep = unreplaced_cand_in_tree (lookup_cand (c->dependent)); | 
 |       if (dep) | 
 | 	return dep; | 
 |     } | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Return TRUE if the candidates in the tree rooted at C should be | 
 |    optimized for speed, else FALSE.  We estimate this based on the block | 
 |    containing the most dominant candidate in the tree that has not yet | 
 |    been replaced.  */ | 
 |  | 
 | static bool | 
 | optimize_cands_for_speed_p (slsr_cand_t c) | 
 | { | 
 |   slsr_cand_t c2 = unreplaced_cand_in_tree (c); | 
 |   gcc_assert (c2); | 
 |   return optimize_bb_for_speed_p (gimple_bb (c2->cand_stmt)); | 
 | } | 
 |  | 
 | /* Add COST_IN to the lowest cost of any dependent path starting at | 
 |    candidate C or any of its siblings, counting only candidates along | 
 |    such paths with increment INCR.  Assume that replacing a candidate | 
 |    reduces cost by REPL_SAVINGS.  Also account for savings from any | 
 |    statements that would go dead.  If COUNT_PHIS is true, include | 
 |    costs of introducing feeding statements for conditional candidates.  */ | 
 |  | 
 | static int | 
 | lowest_cost_path (int cost_in, int repl_savings, slsr_cand_t c, | 
 | 		  const offset_int &incr, bool count_phis) | 
 | { | 
 |   int local_cost, sib_cost, savings = 0; | 
 |   offset_int cand_incr = cand_abs_increment (c); | 
 |  | 
 |   if (cand_already_replaced (c)) | 
 |     local_cost = cost_in; | 
 |   else if (incr == cand_incr) | 
 |     local_cost = cost_in - repl_savings - c->dead_savings; | 
 |   else | 
 |     local_cost = cost_in - c->dead_savings; | 
 |  | 
 |   if (count_phis | 
 |       && phi_dependent_cand_p (c) | 
 |       && !cand_already_replaced (c)) | 
 |     { | 
 |       gimple *phi = lookup_cand (c->def_phi)->cand_stmt; | 
 |       local_cost += phi_incr_cost (c, incr, phi, &savings); | 
 |  | 
 |       if (uses_consumed_by_stmt (gimple_phi_result (phi), c->cand_stmt)) | 
 | 	local_cost -= savings; | 
 |     } | 
 |  | 
 |   if (c->dependent) | 
 |     local_cost = lowest_cost_path (local_cost, repl_savings, | 
 | 				   lookup_cand (c->dependent), incr, | 
 | 				   count_phis); | 
 |  | 
 |   if (c->sibling) | 
 |     { | 
 |       sib_cost = lowest_cost_path (cost_in, repl_savings, | 
 | 				   lookup_cand (c->sibling), incr, | 
 | 				   count_phis); | 
 |       local_cost = MIN (local_cost, sib_cost); | 
 |     } | 
 |  | 
 |   return local_cost; | 
 | } | 
 |  | 
 | /* Compute the total savings that would accrue from all replacements | 
 |    in the candidate tree rooted at C, counting only candidates with | 
 |    increment INCR.  Assume that replacing a candidate reduces cost | 
 |    by REPL_SAVINGS.  Also account for savings from statements that | 
 |    would go dead.  */ | 
 |  | 
 | static int | 
 | total_savings (int repl_savings, slsr_cand_t c, const offset_int &incr, | 
 | 	       bool count_phis) | 
 | { | 
 |   int savings = 0; | 
 |   offset_int cand_incr = cand_abs_increment (c); | 
 |  | 
 |   if (incr == cand_incr && !cand_already_replaced (c)) | 
 |     savings += repl_savings + c->dead_savings; | 
 |  | 
 |   if (count_phis | 
 |       && phi_dependent_cand_p (c) | 
 |       && !cand_already_replaced (c)) | 
 |     { | 
 |       int phi_savings = 0; | 
 |       gimple *phi = lookup_cand (c->def_phi)->cand_stmt; | 
 |       savings -= phi_incr_cost (c, incr, phi, &phi_savings); | 
 |  | 
 |       if (uses_consumed_by_stmt (gimple_phi_result (phi), c->cand_stmt)) | 
 | 	savings += phi_savings; | 
 |     } | 
 |  | 
 |   if (c->dependent) | 
 |     savings += total_savings (repl_savings, lookup_cand (c->dependent), incr, | 
 | 			      count_phis); | 
 |  | 
 |   if (c->sibling) | 
 |     savings += total_savings (repl_savings, lookup_cand (c->sibling), incr, | 
 | 			      count_phis); | 
 |  | 
 |   return savings; | 
 | } | 
 |  | 
 | /* Use target-specific costs to determine and record which increments | 
 |    in the current candidate tree are profitable to replace, assuming | 
 |    MODE and SPEED.  FIRST_DEP is the first dependent of the root of | 
 |    the candidate tree. | 
 |  | 
 |    One slight limitation here is that we don't account for the possible | 
 |    introduction of casts in some cases.  See replace_one_candidate for | 
 |    the cases where these are introduced.  This should probably be cleaned | 
 |    up sometime.  */ | 
 |  | 
 | static void | 
 | analyze_increments (slsr_cand_t first_dep, machine_mode mode, bool speed) | 
 | { | 
 |   unsigned i; | 
 |  | 
 |   for (i = 0; i < incr_vec_len; i++) | 
 |     { | 
 |       HOST_WIDE_INT incr = incr_vec[i].incr.to_shwi (); | 
 |  | 
 |       /* If somehow this increment is bigger than a HWI, we won't | 
 | 	 be optimizing candidates that use it.  And if the increment | 
 | 	 has a count of zero, nothing will be done with it.  */ | 
 |       if (!wi::fits_shwi_p (incr_vec[i].incr) || !incr_vec[i].count) | 
 | 	incr_vec[i].cost = COST_INFINITE; | 
 |  | 
 |       /* Increments of 0, 1, and -1 are always profitable to replace, | 
 | 	 because they always replace a multiply or add with an add or | 
 | 	 copy, and may cause one or more existing instructions to go | 
 | 	 dead.  Exception:  -1 can't be assumed to be profitable for | 
 | 	 pointer addition.  */ | 
 |       else if (incr == 0 | 
 | 	       || incr == 1 | 
 | 	       || (incr == -1 | 
 | 		   && !POINTER_TYPE_P (first_dep->cand_type))) | 
 | 	incr_vec[i].cost = COST_NEUTRAL; | 
 |  | 
 |       /* If we need to add an initializer, give up if a cast from the | 
 | 	 candidate's type to its stride's type can lose precision. | 
 | 	 Note that this already takes into account that the stride may | 
 | 	 have been cast to a wider type, in which case this test won't | 
 | 	 fire.  Example: | 
 |  | 
 |            short int _1; | 
 | 	   _2 = (int) _1; | 
 | 	   _3 = _2 * 10; | 
 | 	   _4 = x + _3;    ADD: x + (10 * (int)_1) : int | 
 | 	   _5 = _2 * 15; | 
 | 	   _6 = x + _5;    ADD: x + (15 * (int)_1) : int | 
 |  | 
 | 	 Although the stride was a short int initially, the stride | 
 | 	 used in the analysis has been widened to an int, and such | 
 | 	 widening will be done in the initializer as well.  */ | 
 |       else if (!incr_vec[i].initializer | 
 | 	       && TREE_CODE (first_dep->stride) != INTEGER_CST | 
 | 	       && !legal_cast_p_1 (first_dep->stride_type, | 
 | 				   TREE_TYPE (gimple_assign_lhs | 
 | 					      (first_dep->cand_stmt)))) | 
 | 	incr_vec[i].cost = COST_INFINITE; | 
 |  | 
 |       /* If we need to add an initializer, make sure we don't introduce | 
 | 	 a multiply by a pointer type, which can happen in certain cast | 
 | 	 scenarios.  */ | 
 |       else if (!incr_vec[i].initializer | 
 | 	       && TREE_CODE (first_dep->stride) != INTEGER_CST | 
 | 	       && POINTER_TYPE_P (first_dep->stride_type)) | 
 | 	incr_vec[i].cost = COST_INFINITE; | 
 |  | 
 |       /* For any other increment, if this is a multiply candidate, we | 
 | 	 must introduce a temporary T and initialize it with | 
 | 	 T_0 = stride * increment.  When optimizing for speed, walk the | 
 | 	 candidate tree to calculate the best cost reduction along any | 
 | 	 path; if it offsets the fixed cost of inserting the initializer, | 
 | 	 replacing the increment is profitable.  When optimizing for | 
 |          size, instead calculate the total cost reduction from replacing | 
 | 	 all candidates with this increment.  */ | 
 |       else if (first_dep->kind == CAND_MULT) | 
 | 	{ | 
 | 	  int cost = mult_by_coeff_cost (incr, mode, speed); | 
 | 	  int repl_savings; | 
 |  | 
 | 	  if (tree_fits_shwi_p (first_dep->stride)) | 
 | 	    { | 
 | 	      HOST_WIDE_INT hwi_stride = tree_to_shwi (first_dep->stride); | 
 | 	      repl_savings = mult_by_coeff_cost (hwi_stride, mode, speed); | 
 | 	    } | 
 | 	  else | 
 | 	    repl_savings = mul_cost (speed, mode); | 
 | 	  repl_savings -= add_cost (speed, mode); | 
 |  | 
 | 	  if (speed) | 
 | 	    cost = lowest_cost_path (cost, repl_savings, first_dep, | 
 | 				     incr_vec[i].incr, COUNT_PHIS); | 
 | 	  else | 
 | 	    cost -= total_savings (repl_savings, first_dep, incr_vec[i].incr, | 
 | 				   COUNT_PHIS); | 
 |  | 
 | 	  incr_vec[i].cost = cost; | 
 | 	} | 
 |  | 
 |       /* If this is an add candidate, the initializer may already | 
 | 	 exist, so only calculate the cost of the initializer if it | 
 | 	 doesn't.  We are replacing one add with another here, so the | 
 | 	 known replacement savings is zero.  We will account for removal | 
 | 	 of dead instructions in lowest_cost_path or total_savings.  */ | 
 |       else | 
 | 	{ | 
 | 	  int cost = 0; | 
 | 	  if (!incr_vec[i].initializer) | 
 | 	    cost = mult_by_coeff_cost (incr, mode, speed); | 
 |  | 
 | 	  if (speed) | 
 | 	    cost = lowest_cost_path (cost, 0, first_dep, incr_vec[i].incr, | 
 | 				     DONT_COUNT_PHIS); | 
 | 	  else | 
 | 	    cost -= total_savings (0, first_dep, incr_vec[i].incr, | 
 | 				   DONT_COUNT_PHIS); | 
 |  | 
 | 	  incr_vec[i].cost = cost; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Return the nearest common dominator of BB1 and BB2.  If the blocks | 
 |    are identical, return the earlier of C1 and C2 in *WHERE.  Otherwise, | 
 |    if the NCD matches BB1, return C1 in *WHERE; if the NCD matches BB2, | 
 |    return C2 in *WHERE; and if the NCD matches neither, return NULL in | 
 |    *WHERE.  Note: It is possible for one of C1 and C2 to be NULL.  */ | 
 |  | 
 | static basic_block | 
 | ncd_for_two_cands (basic_block bb1, basic_block bb2, | 
 | 		   slsr_cand_t c1, slsr_cand_t c2, slsr_cand_t *where) | 
 | { | 
 |   basic_block ncd; | 
 |  | 
 |   if (!bb1) | 
 |     { | 
 |       *where = c2; | 
 |       return bb2; | 
 |     } | 
 |  | 
 |   if (!bb2) | 
 |     { | 
 |       *where = c1; | 
 |       return bb1; | 
 |     } | 
 |  | 
 |   ncd = nearest_common_dominator (CDI_DOMINATORS, bb1, bb2); | 
 |  | 
 |   /* If both candidates are in the same block, the earlier | 
 |      candidate wins.  */ | 
 |   if (bb1 == ncd && bb2 == ncd) | 
 |     { | 
 |       if (!c1 || (c2 && c2->cand_num < c1->cand_num)) | 
 | 	*where = c2; | 
 |       else | 
 | 	*where = c1; | 
 |     } | 
 |  | 
 |   /* Otherwise, if one of them produced a candidate in the | 
 |      dominator, that one wins.  */ | 
 |   else if (bb1 == ncd) | 
 |     *where = c1; | 
 |  | 
 |   else if (bb2 == ncd) | 
 |     *where = c2; | 
 |  | 
 |   /* If neither matches the dominator, neither wins.  */ | 
 |   else | 
 |     *where = NULL; | 
 |  | 
 |   return ncd; | 
 | } | 
 |  | 
 | /* Consider all candidates that feed PHI.  Find the nearest common | 
 |    dominator of those candidates requiring the given increment INCR. | 
 |    Further find and return the nearest common dominator of this result | 
 |    with block NCD.  If the returned block contains one or more of the | 
 |    candidates, return the earliest candidate in the block in *WHERE.  */ | 
 |  | 
 | static basic_block | 
 | ncd_with_phi (slsr_cand_t c, const offset_int &incr, gphi *phi, | 
 | 	      basic_block ncd, slsr_cand_t *where) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t basis = lookup_cand (c->basis); | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |       gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 |       if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	ncd = ncd_with_phi (c, incr, as_a <gphi *> (arg_def), ncd, where); | 
 |       else | 
 | 	{ | 
 | 	  offset_int diff; | 
 |  | 
 | 	  if (operand_equal_p (arg, phi_cand->base_expr, 0)) | 
 | 	    diff = -basis->index; | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t arg_cand = base_cand_from_table (arg); | 
 | 	      diff = arg_cand->index - basis->index; | 
 | 	    } | 
 |  | 
 | 	  basic_block pred = gimple_phi_arg_edge (phi, i)->src; | 
 |  | 
 | 	  if ((incr == diff) || (!address_arithmetic_p && incr == -diff)) | 
 | 	    ncd = ncd_for_two_cands (ncd, pred, *where, NULL, where); | 
 | 	} | 
 |     } | 
 |  | 
 |   return ncd; | 
 | } | 
 |  | 
 | /* Consider the candidate C together with any candidates that feed | 
 |    C's phi dependence (if any).  Find and return the nearest common | 
 |    dominator of those candidates requiring the given increment INCR. | 
 |    If the returned block contains one or more of the candidates, | 
 |    return the earliest candidate in the block in *WHERE.  */ | 
 |  | 
 | static basic_block | 
 | ncd_of_cand_and_phis (slsr_cand_t c, const offset_int &incr, slsr_cand_t *where) | 
 | { | 
 |   basic_block ncd = NULL; | 
 |  | 
 |   if (cand_abs_increment (c) == incr) | 
 |     { | 
 |       ncd = gimple_bb (c->cand_stmt); | 
 |       *where = c; | 
 |     } | 
 |  | 
 |   if (phi_dependent_cand_p (c)) | 
 |     ncd = ncd_with_phi (c, incr, | 
 | 			as_a <gphi *> (lookup_cand (c->def_phi)->cand_stmt), | 
 | 			ncd, where); | 
 |  | 
 |   return ncd; | 
 | } | 
 |  | 
 | /* Consider all candidates in the tree rooted at C for which INCR | 
 |    represents the required increment of C relative to its basis. | 
 |    Find and return the basic block that most nearly dominates all | 
 |    such candidates.  If the returned block contains one or more of | 
 |    the candidates, return the earliest candidate in the block in | 
 |    *WHERE.  */ | 
 |  | 
 | static basic_block | 
 | nearest_common_dominator_for_cands (slsr_cand_t c, const offset_int &incr, | 
 | 				    slsr_cand_t *where) | 
 | { | 
 |   basic_block sib_ncd = NULL, dep_ncd = NULL, this_ncd = NULL, ncd; | 
 |   slsr_cand_t sib_where = NULL, dep_where = NULL, this_where = NULL, new_where; | 
 |  | 
 |   /* First find the NCD of all siblings and dependents.  */ | 
 |   if (c->sibling) | 
 |     sib_ncd = nearest_common_dominator_for_cands (lookup_cand (c->sibling), | 
 | 						  incr, &sib_where); | 
 |   if (c->dependent) | 
 |     dep_ncd = nearest_common_dominator_for_cands (lookup_cand (c->dependent), | 
 | 						  incr, &dep_where); | 
 |   if (!sib_ncd && !dep_ncd) | 
 |     { | 
 |       new_where = NULL; | 
 |       ncd = NULL; | 
 |     } | 
 |   else if (sib_ncd && !dep_ncd) | 
 |     { | 
 |       new_where = sib_where; | 
 |       ncd = sib_ncd; | 
 |     } | 
 |   else if (dep_ncd && !sib_ncd) | 
 |     { | 
 |       new_where = dep_where; | 
 |       ncd = dep_ncd; | 
 |     } | 
 |   else | 
 |     ncd = ncd_for_two_cands (sib_ncd, dep_ncd, sib_where, | 
 | 			     dep_where, &new_where); | 
 |  | 
 |   /* If the candidate's increment doesn't match the one we're interested | 
 |      in (and nor do any increments for feeding defs of a phi-dependence), | 
 |      then the result depends only on siblings and dependents.  */ | 
 |   this_ncd = ncd_of_cand_and_phis (c, incr, &this_where); | 
 |  | 
 |   if (!this_ncd || cand_already_replaced (c)) | 
 |     { | 
 |       *where = new_where; | 
 |       return ncd; | 
 |     } | 
 |  | 
 |   /* Otherwise, compare this candidate with the result from all siblings | 
 |      and dependents.  */ | 
 |   ncd = ncd_for_two_cands (ncd, this_ncd, new_where, this_where, where); | 
 |  | 
 |   return ncd; | 
 | } | 
 |  | 
 | /* Return TRUE if the increment indexed by INDEX is profitable to replace.  */ | 
 |  | 
 | static inline bool | 
 | profitable_increment_p (unsigned index) | 
 | { | 
 |   return (incr_vec[index].cost <= COST_NEUTRAL); | 
 | } | 
 |  | 
 | /* For each profitable increment in the increment vector not equal to | 
 |    0 or 1 (or -1, for non-pointer arithmetic), find the nearest common | 
 |    dominator of all statements in the candidate chain rooted at C | 
 |    that require that increment, and insert an initializer | 
 |    T_0 = stride * increment at that location.  Record T_0 with the | 
 |    increment record.  */ | 
 |  | 
 | static void | 
 | insert_initializers (slsr_cand_t c) | 
 | { | 
 |   unsigned i; | 
 |  | 
 |   for (i = 0; i < incr_vec_len; i++) | 
 |     { | 
 |       basic_block bb; | 
 |       slsr_cand_t where = NULL; | 
 |       gassign *init_stmt; | 
 |       gassign *cast_stmt = NULL; | 
 |       tree new_name, incr_tree, init_stride; | 
 |       offset_int incr = incr_vec[i].incr; | 
 |  | 
 |       if (!profitable_increment_p (i) | 
 | 	  || incr == 1 | 
 | 	  || (incr == -1 | 
 | 	      && (!POINTER_TYPE_P (lookup_cand (c->basis)->cand_type))) | 
 | 	  || incr == 0) | 
 | 	continue; | 
 |  | 
 |       /* We may have already identified an existing initializer that | 
 | 	 will suffice.  */ | 
 |       if (incr_vec[i].initializer) | 
 | 	{ | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    { | 
 | 	      fputs ("Using existing initializer: ", dump_file); | 
 | 	      print_gimple_stmt (dump_file, | 
 | 				 SSA_NAME_DEF_STMT (incr_vec[i].initializer), | 
 | 				 0, TDF_NONE); | 
 | 	    } | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       /* Find the block that most closely dominates all candidates | 
 | 	 with this increment.  If there is at least one candidate in | 
 | 	 that block, the earliest one will be returned in WHERE.  */ | 
 |       bb = nearest_common_dominator_for_cands (c, incr, &where); | 
 |  | 
 |       /* If the NCD is not dominated by the block containing the | 
 | 	 definition of the stride, we can't legally insert a | 
 | 	 single initializer.  Mark the increment as unprofitable | 
 | 	 so we don't make any replacements.  FIXME: Multiple | 
 | 	 initializers could be placed with more analysis.  */ | 
 |       gimple *stride_def = SSA_NAME_DEF_STMT (c->stride); | 
 |       basic_block stride_bb = gimple_bb (stride_def); | 
 |  | 
 |       if (stride_bb && !dominated_by_p (CDI_DOMINATORS, bb, stride_bb)) | 
 | 	{ | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    fprintf (dump_file, | 
 | 		     "Initializer #%d cannot be legally placed\n", i); | 
 | 	  incr_vec[i].cost = COST_INFINITE; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       /* If the nominal stride has a different type than the recorded | 
 | 	 stride type, build a cast from the nominal stride to that type.  */ | 
 |       if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type)) | 
 | 	{ | 
 | 	  init_stride = make_temp_ssa_name (c->stride_type, NULL, "slsr"); | 
 | 	  cast_stmt = gimple_build_assign (init_stride, NOP_EXPR, c->stride); | 
 | 	} | 
 |       else | 
 | 	init_stride = c->stride; | 
 |  | 
 |       /* Create a new SSA name to hold the initializer's value.  */ | 
 |       new_name = make_temp_ssa_name (c->stride_type, NULL, "slsr"); | 
 |       incr_vec[i].initializer = new_name; | 
 |  | 
 |       /* Create the initializer and insert it in the latest possible | 
 | 	 dominating position.  */ | 
 |       incr_tree = wide_int_to_tree (c->stride_type, incr); | 
 |       init_stmt = gimple_build_assign (new_name, MULT_EXPR, | 
 | 				       init_stride, incr_tree); | 
 |       if (where) | 
 | 	{ | 
 | 	  gimple_stmt_iterator gsi = gsi_for_stmt (where->cand_stmt); | 
 | 	  location_t loc = gimple_location (where->cand_stmt); | 
 |  | 
 | 	  if (cast_stmt) | 
 | 	    { | 
 | 	      gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT); | 
 | 	      gimple_set_location (cast_stmt, loc); | 
 | 	    } | 
 |  | 
 | 	  gsi_insert_before (&gsi, init_stmt, GSI_SAME_STMT); | 
 | 	  gimple_set_location (init_stmt, loc); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  gimple_stmt_iterator gsi = gsi_last_bb (bb); | 
 | 	  gimple *basis_stmt = lookup_cand (c->basis)->cand_stmt; | 
 | 	  location_t loc = gimple_location (basis_stmt); | 
 |  | 
 | 	  if (!gsi_end_p (gsi) && stmt_ends_bb_p (gsi_stmt (gsi))) | 
 | 	    { | 
 | 	      if (cast_stmt) | 
 | 		{ | 
 | 		  gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT); | 
 | 		  gimple_set_location (cast_stmt, loc); | 
 | 		} | 
 | 	      gsi_insert_before (&gsi, init_stmt, GSI_SAME_STMT); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      if (cast_stmt) | 
 | 		{ | 
 | 		  gsi_insert_after (&gsi, cast_stmt, GSI_NEW_STMT); | 
 | 		  gimple_set_location (cast_stmt, loc); | 
 | 		} | 
 | 	      gsi_insert_after (&gsi, init_stmt, GSI_NEW_STMT); | 
 | 	    } | 
 |  | 
 | 	  gimple_set_location (init_stmt, gimple_location (basis_stmt)); | 
 | 	} | 
 |  | 
 |       if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	{ | 
 | 	  if (cast_stmt) | 
 | 	    { | 
 | 	      fputs ("Inserting stride cast: ", dump_file); | 
 | 	      print_gimple_stmt (dump_file, cast_stmt, 0); | 
 | 	    } | 
 | 	  fputs ("Inserting initializer: ", dump_file); | 
 | 	  print_gimple_stmt (dump_file, init_stmt, 0); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Recursive helper function for all_phi_incrs_profitable.  */ | 
 |  | 
 | static bool | 
 | all_phi_incrs_profitable_1 (slsr_cand_t c, gphi *phi, int *spread) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t basis = lookup_cand (c->basis); | 
 |   slsr_cand_t phi_cand = *stmt_cand_map->get (phi); | 
 |  | 
 |   if (phi_cand->visited) | 
 |     return true; | 
 |  | 
 |   phi_cand->visited = 1; | 
 |   (*spread)++; | 
 |  | 
 |   /* If the basis doesn't dominate the PHI (including when the PHI is | 
 |      in the same block as the basis), we won't be able to create a PHI | 
 |      using the basis here.  */ | 
 |   basic_block basis_bb = gimple_bb (basis->cand_stmt); | 
 |   basic_block phi_bb = gimple_bb (phi); | 
 |  | 
 |   if (phi_bb == basis_bb | 
 |       || !dominated_by_p (CDI_DOMINATORS, phi_bb, basis_bb)) | 
 |     return false; | 
 |  | 
 |   for (i = 0; i < gimple_phi_num_args (phi); i++) | 
 |     { | 
 |       /* If the PHI arg resides in a block not dominated by the basis, | 
 | 	 we won't be able to create a PHI using the basis here.  */ | 
 |       basic_block pred_bb = gimple_phi_arg_edge (phi, i)->src; | 
 |  | 
 |       if (!dominated_by_p (CDI_DOMINATORS, pred_bb, basis_bb)) | 
 | 	return false; | 
 |  | 
 |       tree arg = gimple_phi_arg_def (phi, i); | 
 |       gimple *arg_def = SSA_NAME_DEF_STMT (arg); | 
 |  | 
 |       if (gimple_code (arg_def) == GIMPLE_PHI) | 
 | 	{ | 
 | 	  if (!all_phi_incrs_profitable_1 (c, as_a <gphi *> (arg_def), spread) | 
 | 	      || *spread > MAX_SPREAD) | 
 | 	    return false; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  int j; | 
 | 	  offset_int increment; | 
 |  | 
 | 	  if (operand_equal_p (arg, phi_cand->base_expr, 0)) | 
 | 	    increment = -basis->index; | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t arg_cand = base_cand_from_table (arg); | 
 | 	      increment = arg_cand->index - basis->index; | 
 | 	    } | 
 |  | 
 | 	  if (!address_arithmetic_p && wi::neg_p (increment)) | 
 | 	    increment = -increment; | 
 |  | 
 | 	  j = incr_vec_index (increment); | 
 |  | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    { | 
 | 	      fprintf (dump_file, "  Conditional candidate %d, phi: ", | 
 | 		       c->cand_num); | 
 | 	      print_gimple_stmt (dump_file, phi, 0); | 
 | 	      fputs ("    increment: ", dump_file); | 
 | 	      print_decs (increment, dump_file); | 
 | 	      if (j < 0) | 
 | 		fprintf (dump_file, | 
 | 			 "\n  Not replaced; incr_vec overflow.\n"); | 
 | 	      else { | 
 | 		fprintf (dump_file, "\n    cost: %d\n", incr_vec[j].cost); | 
 | 		if (profitable_increment_p (j)) | 
 | 		  fputs ("  Replacing...\n", dump_file); | 
 | 		else | 
 | 		  fputs ("  Not replaced.\n", dump_file); | 
 | 	      } | 
 | 	    } | 
 |  | 
 | 	  if (j < 0 || !profitable_increment_p (j)) | 
 | 	    return false; | 
 | 	} | 
 |     } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Return TRUE iff all required increments for candidates feeding PHI | 
 |    are profitable (and legal!) to replace on behalf of candidate C.  */ | 
 |  | 
 | static bool | 
 | all_phi_incrs_profitable (slsr_cand_t c, gphi *phi) | 
 | { | 
 |   int spread = 0; | 
 |   bool retval = all_phi_incrs_profitable_1 (c, phi, &spread); | 
 |   clear_visited (phi); | 
 |   return retval; | 
 | } | 
 |  | 
 | /* Create a NOP_EXPR that copies FROM_EXPR into a new SSA name of | 
 |    type TO_TYPE, and insert it in front of the statement represented | 
 |    by candidate C.  Use *NEW_VAR to create the new SSA name.  Return | 
 |    the new SSA name.  */ | 
 |  | 
 | static tree | 
 | introduce_cast_before_cand (slsr_cand_t c, tree to_type, tree from_expr) | 
 | { | 
 |   tree cast_lhs; | 
 |   gassign *cast_stmt; | 
 |   gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 |  | 
 |   cast_lhs = make_temp_ssa_name (to_type, NULL, "slsr"); | 
 |   cast_stmt = gimple_build_assign (cast_lhs, NOP_EXPR, from_expr); | 
 |   gimple_set_location (cast_stmt, gimple_location (c->cand_stmt)); | 
 |   gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("  Inserting: ", dump_file); | 
 |       print_gimple_stmt (dump_file, cast_stmt, 0); | 
 |     } | 
 |  | 
 |   return cast_lhs; | 
 | } | 
 |  | 
 | /* Replace the RHS of the statement represented by candidate C with | 
 |    NEW_CODE, NEW_RHS1, and NEW_RHS2, provided that to do so doesn't | 
 |    leave C unchanged or just interchange its operands.  The original | 
 |    operation and operands are in OLD_CODE, OLD_RHS1, and OLD_RHS2. | 
 |    If the replacement was made and we are doing a details dump, | 
 |    return the revised statement, else NULL.  */ | 
 |  | 
 | static gimple * | 
 | replace_rhs_if_not_dup (enum tree_code new_code, tree new_rhs1, tree new_rhs2, | 
 | 			enum tree_code old_code, tree old_rhs1, tree old_rhs2, | 
 | 			slsr_cand_t c) | 
 | { | 
 |   if (new_code != old_code | 
 |       || ((!operand_equal_p (new_rhs1, old_rhs1, 0) | 
 | 	   || !operand_equal_p (new_rhs2, old_rhs2, 0)) | 
 | 	  && (!operand_equal_p (new_rhs1, old_rhs2, 0) | 
 | 	      || !operand_equal_p (new_rhs2, old_rhs1, 0)))) | 
 |     { | 
 |       gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 |       slsr_cand_t cc = lookup_cand (c->first_interp); | 
 |       gimple_assign_set_rhs_with_ops (&gsi, new_code, new_rhs1, new_rhs2); | 
 |       update_stmt (gsi_stmt (gsi)); | 
 |       while (cc) | 
 | 	{ | 
 | 	  cc->cand_stmt = gsi_stmt (gsi); | 
 | 	  cc = lookup_cand (cc->next_interp); | 
 | 	} | 
 |  | 
 |       if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	return gsi_stmt (gsi); | 
 |     } | 
 |  | 
 |   else if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     fputs ("  (duplicate, not actually replacing)\n", dump_file); | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Strength-reduce the statement represented by candidate C by replacing | 
 |    it with an equivalent addition or subtraction.  I is the index into | 
 |    the increment vector identifying C's increment.  NEW_VAR is used to | 
 |    create a new SSA name if a cast needs to be introduced.  BASIS_NAME | 
 |    is the rhs1 to use in creating the add/subtract.  */ | 
 |  | 
 | static void | 
 | replace_one_candidate (slsr_cand_t c, unsigned i, tree basis_name, | 
 | 		       auto_bitmap &sdce_worklist) | 
 | { | 
 |   gimple *stmt_to_print = NULL; | 
 |   tree orig_rhs1, orig_rhs2; | 
 |   tree rhs2; | 
 |   enum tree_code orig_code, repl_code; | 
 |   offset_int cand_incr; | 
 |  | 
 |   orig_code = gimple_assign_rhs_code (c->cand_stmt); | 
 |   orig_rhs1 = gimple_assign_rhs1 (c->cand_stmt); | 
 |   orig_rhs2 = gimple_assign_rhs2 (c->cand_stmt); | 
 |   cand_incr = cand_increment (c); | 
 |  | 
 |   /* If orig_rhs2 is NULL, we have already replaced this in situ with | 
 |      a copy statement under another interpretation.  */ | 
 |   if (!orig_rhs2) | 
 |     return; | 
 |  | 
 |   /* Mark the 2 original rhs for maybe DCEing.  */ | 
 |   if (TREE_CODE (orig_rhs1) == SSA_NAME) | 
 |     bitmap_set_bit (sdce_worklist, SSA_NAME_VERSION (orig_rhs1)); | 
 |   if (TREE_CODE (orig_rhs2) == SSA_NAME) | 
 |    bitmap_set_bit (sdce_worklist, SSA_NAME_VERSION (orig_rhs2)); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       fputs ("Replacing: ", dump_file); | 
 |       print_gimple_stmt (dump_file, c->cand_stmt, 0); | 
 |       stmt_to_print = c->cand_stmt; | 
 |     } | 
 |  | 
 |   if (address_arithmetic_p) | 
 |     repl_code = POINTER_PLUS_EXPR; | 
 |   else | 
 |     repl_code = PLUS_EXPR; | 
 |  | 
 |   /* If the increment has an initializer T_0, replace the candidate | 
 |      statement with an add of the basis name and the initializer.  */ | 
 |   if (incr_vec[i].initializer) | 
 |     { | 
 |       tree init_type = TREE_TYPE (incr_vec[i].initializer); | 
 |       tree orig_type = TREE_TYPE (orig_rhs2); | 
 |  | 
 |       if (types_compatible_p (orig_type, init_type)) | 
 | 	rhs2 = incr_vec[i].initializer; | 
 |       else | 
 | 	rhs2 = introduce_cast_before_cand (c, orig_type, | 
 | 					   incr_vec[i].initializer); | 
 |  | 
 |       if (incr_vec[i].incr != cand_incr) | 
 | 	{ | 
 | 	  gcc_assert (repl_code == PLUS_EXPR); | 
 | 	  repl_code = MINUS_EXPR; | 
 | 	} | 
 |  | 
 |       stmt_to_print = replace_rhs_if_not_dup (repl_code, basis_name, rhs2, | 
 | 					      orig_code, orig_rhs1, orig_rhs2, | 
 | 					      c); | 
 |     } | 
 |  | 
 |   /* Otherwise, the increment is one of -1, 0, and 1.  Replace | 
 |      with a subtract of the stride from the basis name, a copy | 
 |      from the basis name, or an add of the stride to the basis | 
 |      name, respectively.  It may be necessary to introduce a | 
 |      cast (or reuse an existing cast).  */ | 
 |   else if (cand_incr == 1) | 
 |     { | 
 |       tree stride_type = TREE_TYPE (c->stride); | 
 |       tree orig_type = TREE_TYPE (orig_rhs2); | 
 |  | 
 |       if (types_compatible_p (orig_type, stride_type)) | 
 | 	rhs2 = c->stride; | 
 |       else | 
 | 	rhs2 = introduce_cast_before_cand (c, orig_type, c->stride); | 
 |  | 
 |       stmt_to_print = replace_rhs_if_not_dup (repl_code, basis_name, rhs2, | 
 | 					      orig_code, orig_rhs1, orig_rhs2, | 
 | 					      c); | 
 |     } | 
 |  | 
 |   else if (cand_incr == -1) | 
 |     { | 
 |       tree stride_type = TREE_TYPE (c->stride); | 
 |       tree orig_type = TREE_TYPE (orig_rhs2); | 
 |       gcc_assert (repl_code != POINTER_PLUS_EXPR); | 
 |  | 
 |       if (types_compatible_p (orig_type, stride_type)) | 
 | 	rhs2 = c->stride; | 
 |       else | 
 | 	rhs2 = introduce_cast_before_cand (c, orig_type, c->stride); | 
 |  | 
 |       if (orig_code != MINUS_EXPR | 
 | 	  || !operand_equal_p (basis_name, orig_rhs1, 0) | 
 | 	  || !operand_equal_p (rhs2, orig_rhs2, 0)) | 
 | 	{ | 
 | 	  gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 | 	  slsr_cand_t cc = lookup_cand (c->first_interp); | 
 | 	  gimple_assign_set_rhs_with_ops (&gsi, MINUS_EXPR, basis_name, rhs2); | 
 | 	  update_stmt (gsi_stmt (gsi)); | 
 | 	  while (cc) | 
 | 	    { | 
 | 	      cc->cand_stmt = gsi_stmt (gsi); | 
 | 	      cc = lookup_cand (cc->next_interp); | 
 | 	    } | 
 |  | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    stmt_to_print = gsi_stmt (gsi); | 
 | 	} | 
 |       else if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	fputs ("  (duplicate, not actually replacing)\n", dump_file); | 
 |     } | 
 |  | 
 |   else if (cand_incr == 0) | 
 |     { | 
 |       tree lhs = gimple_assign_lhs (c->cand_stmt); | 
 |       tree lhs_type = TREE_TYPE (lhs); | 
 |       tree basis_type = TREE_TYPE (basis_name); | 
 |  | 
 |       if (types_compatible_p (lhs_type, basis_type)) | 
 | 	{ | 
 | 	  gassign *copy_stmt = gimple_build_assign (lhs, basis_name); | 
 | 	  gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 | 	  slsr_cand_t cc = lookup_cand (c->first_interp); | 
 | 	  gimple_set_location (copy_stmt, gimple_location (c->cand_stmt)); | 
 | 	  gsi_replace (&gsi, copy_stmt, false); | 
 | 	  while (cc) | 
 | 	    { | 
 | 	      cc->cand_stmt = copy_stmt; | 
 | 	      cc = lookup_cand (cc->next_interp); | 
 | 	    } | 
 |  | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    stmt_to_print = copy_stmt; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  gimple_stmt_iterator gsi = gsi_for_stmt (c->cand_stmt); | 
 | 	  gassign *cast_stmt = gimple_build_assign (lhs, NOP_EXPR, basis_name); | 
 | 	  slsr_cand_t cc = lookup_cand (c->first_interp); | 
 | 	  gimple_set_location (cast_stmt, gimple_location (c->cand_stmt)); | 
 | 	  gsi_replace (&gsi, cast_stmt, false); | 
 | 	  while (cc) | 
 | 	    { | 
 | 	      cc->cand_stmt = cast_stmt; | 
 | 	      cc = lookup_cand (cc->next_interp); | 
 | 	    } | 
 |  | 
 | 	  if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	    stmt_to_print = cast_stmt; | 
 | 	} | 
 |     } | 
 |   else | 
 |     gcc_unreachable (); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS) && stmt_to_print) | 
 |     { | 
 |       fputs ("With: ", dump_file); | 
 |       print_gimple_stmt (dump_file, stmt_to_print, 0); | 
 |       fputs ("\n", dump_file); | 
 |     } | 
 | } | 
 |  | 
 | /* For each candidate in the tree rooted at C, replace it with | 
 |    an increment if such has been shown to be profitable.  */ | 
 |  | 
 | static void | 
 | replace_profitable_candidates (slsr_cand_t c, auto_bitmap &sdce_worklist) | 
 | { | 
 |   if (!cand_already_replaced (c)) | 
 |     { | 
 |       offset_int increment = cand_abs_increment (c); | 
 |       enum tree_code orig_code = gimple_assign_rhs_code (c->cand_stmt); | 
 |       int i; | 
 |  | 
 |       i = incr_vec_index (increment); | 
 |  | 
 |       /* Only process profitable increments.  Nothing useful can be done | 
 | 	 to a cast or copy.  */ | 
 |       if (i >= 0 | 
 | 	  && profitable_increment_p (i) | 
 | 	  && orig_code != SSA_NAME | 
 | 	  && !CONVERT_EXPR_CODE_P (orig_code)) | 
 | 	{ | 
 | 	  if (phi_dependent_cand_p (c)) | 
 | 	    { | 
 | 	      gphi *phi = as_a <gphi *> (lookup_cand (c->def_phi)->cand_stmt); | 
 |  | 
 | 	      if (all_phi_incrs_profitable (c, phi)) | 
 | 		{ | 
 | 		  /* Look up the LHS SSA name from C's basis.  This will be | 
 | 		     the RHS1 of the adds we will introduce to create new | 
 | 		     phi arguments.  */ | 
 | 		  slsr_cand_t basis = lookup_cand (c->basis); | 
 | 		  tree basis_name = gimple_assign_lhs (basis->cand_stmt); | 
 |  | 
 | 		  /* Create a new phi statement that will represent C's true | 
 | 		     basis after the transformation is complete.  */ | 
 | 		  location_t loc = gimple_location (c->cand_stmt); | 
 | 		  tree name = create_phi_basis (c, phi, basis_name, | 
 | 						loc, UNKNOWN_STRIDE); | 
 |  | 
 | 		  /* Replace C with an add of the new basis phi and the | 
 | 		     increment.  */ | 
 | 		  replace_one_candidate (c, i, name, sdce_worklist); | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      slsr_cand_t basis = lookup_cand (c->basis); | 
 | 	      tree basis_name = gimple_assign_lhs (basis->cand_stmt); | 
 | 	      replace_one_candidate (c, i, basis_name, sdce_worklist); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   if (c->sibling) | 
 |     replace_profitable_candidates (lookup_cand (c->sibling), sdce_worklist); | 
 |  | 
 |   if (c->dependent) | 
 |     replace_profitable_candidates (lookup_cand (c->dependent), sdce_worklist); | 
 | } | 
 |  | 
 | /* Analyze costs of related candidates in the candidate vector, | 
 |    and make beneficial replacements.  */ | 
 |  | 
 | static void | 
 | analyze_candidates_and_replace (void) | 
 | { | 
 |   unsigned i; | 
 |   slsr_cand_t c; | 
 |   auto_bitmap simple_dce_worklist; | 
 |  | 
 |   /* Each candidate that has a null basis and a non-null | 
 |      dependent is the root of a tree of related statements. | 
 |      Analyze each tree to determine a subset of those | 
 |      statements that can be replaced with maximum benefit. | 
 |  | 
 |      Note the first NULL element is skipped.  */ | 
 |   FOR_EACH_VEC_ELT_FROM (cand_vec, i, c, 1) | 
 |     { | 
 |       slsr_cand_t first_dep; | 
 |  | 
 |       if (c->basis != 0 || c->dependent == 0) | 
 | 	continue; | 
 |  | 
 |       if (dump_file && (dump_flags & TDF_DETAILS)) | 
 | 	fprintf (dump_file, "\nProcessing dependency tree rooted at %d.\n", | 
 | 		 c->cand_num); | 
 |  | 
 |       first_dep = lookup_cand (c->dependent); | 
 |  | 
 |       /* If this is a chain of CAND_REFs, unconditionally replace | 
 | 	 each of them with a strength-reduced data reference.  */ | 
 |       if (c->kind == CAND_REF) | 
 | 	replace_refs (c); | 
 |  | 
 |       /* If the common stride of all related candidates is a known | 
 | 	 constant, each candidate without a phi-dependence can be | 
 | 	 profitably replaced.  Each replaces a multiply by a single | 
 | 	 add, with the possibility that a feeding add also goes dead. | 
 | 	 A candidate with a phi-dependence is replaced only if the | 
 | 	 compensation code it requires is offset by the strength | 
 | 	 reduction savings.  */ | 
 |       else if (TREE_CODE (c->stride) == INTEGER_CST) | 
 | 	replace_uncond_cands_and_profitable_phis (first_dep, | 
 | 						  simple_dce_worklist); | 
 |  | 
 |       /* When the stride is an SSA name, it may still be profitable | 
 | 	 to replace some or all of the dependent candidates, depending | 
 | 	 on whether the introduced increments can be reused, or are | 
 | 	 less expensive to calculate than the replaced statements.  */ | 
 |       else | 
 | 	{ | 
 | 	  machine_mode mode; | 
 | 	  bool speed; | 
 |  | 
 | 	  /* Determine whether we'll be generating pointer arithmetic | 
 | 	     when replacing candidates.  */ | 
 | 	  address_arithmetic_p = (c->kind == CAND_ADD | 
 | 				  && POINTER_TYPE_P (c->cand_type)); | 
 |  | 
 | 	  /* If all candidates have already been replaced under other | 
 | 	     interpretations, nothing remains to be done.  */ | 
 | 	  if (!count_candidates (c)) | 
 | 	    continue; | 
 |  | 
 | 	  /* Construct an array of increments for this candidate chain.  */ | 
 | 	  incr_vec = XNEWVEC (incr_info, MAX_INCR_VEC_LEN); | 
 | 	  incr_vec_len = 0; | 
 | 	  record_increments (c); | 
 |  | 
 | 	  /* Determine which increments are profitable to replace.  */ | 
 | 	  mode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (c->cand_stmt))); | 
 | 	  speed = optimize_cands_for_speed_p (c); | 
 | 	  analyze_increments (first_dep, mode, speed); | 
 |  | 
 | 	  /* Insert initializers of the form T_0 = stride * increment | 
 | 	     for use in profitable replacements.  */ | 
 | 	  insert_initializers (first_dep); | 
 | 	  dump_incr_vec (); | 
 |  | 
 | 	  /* Perform the replacements.  */ | 
 | 	  replace_profitable_candidates (first_dep, simple_dce_worklist); | 
 | 	  free (incr_vec); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* For conditional candidates, we may have uncommitted insertions | 
 |      on edges to clean up.  */ | 
 |   gsi_commit_edge_inserts (); | 
 |  | 
 |   simple_dce_from_worklist (simple_dce_worklist); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | const pass_data pass_data_strength_reduction = | 
 | { | 
 |   GIMPLE_PASS, /* type */ | 
 |   "slsr", /* name */ | 
 |   OPTGROUP_NONE, /* optinfo_flags */ | 
 |   TV_GIMPLE_SLSR, /* tv_id */ | 
 |   ( PROP_cfg | PROP_ssa ), /* properties_required */ | 
 |   0, /* properties_provided */ | 
 |   0, /* properties_destroyed */ | 
 |   0, /* todo_flags_start */ | 
 |   0, /* todo_flags_finish */ | 
 | }; | 
 |  | 
 | class pass_strength_reduction : public gimple_opt_pass | 
 | { | 
 | public: | 
 |   pass_strength_reduction (gcc::context *ctxt) | 
 |     : gimple_opt_pass (pass_data_strength_reduction, ctxt) | 
 |   {} | 
 |  | 
 |   /* opt_pass methods: */ | 
 |   bool gate (function *) final override { return flag_tree_slsr; } | 
 |   unsigned int execute (function *) final override; | 
 |  | 
 | }; // class pass_strength_reduction | 
 |  | 
 | unsigned | 
 | pass_strength_reduction::execute (function *fun) | 
 | { | 
 |   /* Create the obstack where candidates will reside.  */ | 
 |   gcc_obstack_init (&cand_obstack); | 
 |  | 
 |   /* Allocate the candidate vector and initialize the first NULL element.  */ | 
 |   cand_vec.create (128); | 
 |   cand_vec.safe_push (NULL); | 
 |  | 
 |   /* Allocate the mapping from statements to candidate indices.  */ | 
 |   stmt_cand_map = new hash_map<gimple *, slsr_cand_t>; | 
 |  | 
 |   /* Create the obstack where candidate chains will reside.  */ | 
 |   gcc_obstack_init (&chain_obstack); | 
 |  | 
 |   /* Allocate the mapping from base expressions to candidate chains.  */ | 
 |   base_cand_map = new hash_table<cand_chain_hasher> (500); | 
 |  | 
 |   /* Allocate the mapping from bases to alternative bases.  */ | 
 |   alt_base_map = new hash_map<tree, tree>; | 
 |  | 
 |   /* Initialize the loop optimizer.  We need to detect flow across | 
 |      back edges, and this gives us dominator information as well.  */ | 
 |   loop_optimizer_init (AVOID_CFG_MODIFICATIONS); | 
 |  | 
 |   /* Walk the CFG in predominator order looking for strength reduction | 
 |      candidates.  */ | 
 |   find_candidates_dom_walker (CDI_DOMINATORS) | 
 |     .walk (fun->cfg->x_entry_block_ptr); | 
 |  | 
 |   if (dump_file && (dump_flags & TDF_DETAILS)) | 
 |     { | 
 |       dump_cand_vec (); | 
 |       dump_cand_chains (); | 
 |     } | 
 |  | 
 |   delete alt_base_map; | 
 |   free_affine_expand_cache (&name_expansions); | 
 |  | 
 |   /* Analyze costs and make appropriate replacements.  */ | 
 |   analyze_candidates_and_replace (); | 
 |  | 
 |   loop_optimizer_finalize (); | 
 |   delete base_cand_map; | 
 |   base_cand_map = NULL; | 
 |   obstack_free (&chain_obstack, NULL); | 
 |   delete stmt_cand_map; | 
 |   cand_vec.release (); | 
 |   obstack_free (&cand_obstack, NULL); | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | } // anon namespace | 
 |  | 
 | gimple_opt_pass * | 
 | make_pass_strength_reduction (gcc::context *ctxt) | 
 | { | 
 |   return new pass_strength_reduction (ctxt); | 
 | } |