|  | /* SSA-PRE for trees. | 
|  | Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. | 
|  | Contributed by Daniel Berlin <dan@dberlin.org> and Steven Bosscher | 
|  | <stevenb@suse.de> | 
|  |  | 
|  | 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 2, 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 COPYING.  If not, write to | 
|  | the Free Software Foundation, 51 Franklin Street, Fifth Floor, | 
|  | Boston, MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "system.h" | 
|  | #include "coretypes.h" | 
|  | #include "tm.h" | 
|  | #include "ggc.h" | 
|  | #include "tree.h" | 
|  | #include "basic-block.h" | 
|  | #include "diagnostic.h" | 
|  | #include "tree-inline.h" | 
|  | #include "tree-flow.h" | 
|  | #include "tree-gimple.h" | 
|  | #include "tree-dump.h" | 
|  | #include "timevar.h" | 
|  | #include "fibheap.h" | 
|  | #include "hashtab.h" | 
|  | #include "tree-iterator.h" | 
|  | #include "real.h" | 
|  | #include "alloc-pool.h" | 
|  | #include "tree-pass.h" | 
|  | #include "flags.h" | 
|  | #include "bitmap.h" | 
|  | #include "langhooks.h" | 
|  | #include "cfgloop.h" | 
|  |  | 
|  | /* TODO: | 
|  |  | 
|  | 1. Avail sets can be shared by making an avail_find_leader that | 
|  | walks up the dominator tree and looks in those avail sets. | 
|  | This might affect code optimality, it's unclear right now. | 
|  | 2. Strength reduction can be performed by anticipating expressions | 
|  | we can repair later on. | 
|  | 3. We can do back-substitution or smarter value numbering to catch | 
|  | commutative expressions split up over multiple statements. | 
|  | 4. ANTIC_SAFE_LOADS could be a lot smarter than it is now. | 
|  | Right now, it is simply calculating loads that occur before | 
|  | any store in a block, instead of loads that occur before | 
|  | stores that affect them.  This is relatively more expensive, and | 
|  | it's not clear how much more it will buy us. | 
|  | */ | 
|  |  | 
|  | /* For ease of terminology, "expression node" in the below refers to | 
|  | every expression node but MODIFY_EXPR, because MODIFY_EXPR's represent | 
|  | the actual statement containing the expressions we care about, and | 
|  | we cache the value number by putting it in the expression.  */ | 
|  |  | 
|  | /* Basic algorithm | 
|  |  | 
|  | First we walk the statements to generate the AVAIL sets, the | 
|  | EXP_GEN sets, and the tmp_gen sets.  EXP_GEN sets represent the | 
|  | generation of values/expressions by a given block.  We use them | 
|  | when computing the ANTIC sets.  The AVAIL sets consist of | 
|  | SSA_NAME's that represent values, so we know what values are | 
|  | available in what blocks.  AVAIL is a forward dataflow problem.  In | 
|  | SSA, values are never killed, so we don't need a kill set, or a | 
|  | fixpoint iteration, in order to calculate the AVAIL sets.  In | 
|  | traditional parlance, AVAIL sets tell us the downsafety of the | 
|  | expressions/values. | 
|  |  | 
|  | Next, we generate the ANTIC sets.  These sets represent the | 
|  | anticipatable expressions.  ANTIC is a backwards dataflow | 
|  | problem.An expression is anticipatable in a given block if it could | 
|  | be generated in that block.  This means that if we had to perform | 
|  | an insertion in that block, of the value of that expression, we | 
|  | could.  Calculating the ANTIC sets requires phi translation of | 
|  | expressions, because the flow goes backwards through phis.  We must | 
|  | iterate to a fixpoint of the ANTIC sets, because we have a kill | 
|  | set.  Even in SSA form, values are not live over the entire | 
|  | function, only from their definition point onwards.  So we have to | 
|  | remove values from the ANTIC set once we go past the definition | 
|  | point of the leaders that make them up. | 
|  | compute_antic/compute_antic_aux performs this computation. | 
|  |  | 
|  | Third, we perform insertions to make partially redundant | 
|  | expressions fully redundant. | 
|  |  | 
|  | An expression is partially redundant (excluding partial | 
|  | anticipation) if: | 
|  |  | 
|  | 1. It is AVAIL in some, but not all, of the predecessors of a | 
|  | given block. | 
|  | 2. It is ANTIC in all the predecessors. | 
|  |  | 
|  | In order to make it fully redundant, we insert the expression into | 
|  | the predecessors where it is not available, but is ANTIC. | 
|  | insert/insert_aux performs this insertion. | 
|  |  | 
|  | Fourth, we eliminate fully redundant expressions. | 
|  | This is a simple statement walk that replaces redundant | 
|  | calculations  with the now available values.  */ | 
|  |  | 
|  | /* Representations of value numbers: | 
|  |  | 
|  | Value numbers are represented using the "value handle" approach. | 
|  | This means that each SSA_NAME (and for other reasons to be | 
|  | disclosed in a moment, expression nodes) has a value handle that | 
|  | can be retrieved through get_value_handle.  This value handle, *is* | 
|  | the value number of the SSA_NAME.  You can pointer compare the | 
|  | value handles for equivalence purposes. | 
|  |  | 
|  | For debugging reasons, the value handle is internally more than | 
|  | just a number, it is a VAR_DECL named "value.x", where x is a | 
|  | unique number for each value number in use.  This allows | 
|  | expressions with SSA_NAMES replaced by value handles to still be | 
|  | pretty printed in a sane way.  They simply print as "value.3 * | 
|  | value.5", etc. | 
|  |  | 
|  | Expression nodes have value handles associated with them as a | 
|  | cache.  Otherwise, we'd have to look them up again in the hash | 
|  | table This makes significant difference (factor of two or more) on | 
|  | some test cases.  They can be thrown away after the pass is | 
|  | finished.  */ | 
|  |  | 
|  | /* Representation of expressions on value numbers: | 
|  |  | 
|  | In some portions of this code, you will notice we allocate "fake" | 
|  | analogues to the expression we are value numbering, and replace the | 
|  | operands with the values of the expression.  Since we work on | 
|  | values, and not just names, we canonicalize expressions to value | 
|  | expressions for use in the ANTIC sets, the EXP_GEN set, etc. | 
|  |  | 
|  | This is theoretically unnecessary, it just saves a bunch of | 
|  | repeated get_value_handle and find_leader calls in the remainder of | 
|  | the code, trading off temporary memory usage for speed.  The tree | 
|  | nodes aren't actually creating more garbage, since they are | 
|  | allocated in a special pools which are thrown away at the end of | 
|  | this pass. | 
|  |  | 
|  | All of this also means that if you print the EXP_GEN or ANTIC sets, | 
|  | you will see "value.5 + value.7" in the set, instead of "a_55 + | 
|  | b_66" or something.  The only thing that actually cares about | 
|  | seeing the value leaders is phi translation, and it needs to be | 
|  | able to find the leader for a value in an arbitrary block, so this | 
|  | "value expression" form is perfect for it (otherwise you'd do | 
|  | get_value_handle->find_leader->translate->get_value_handle->find_leader).*/ | 
|  |  | 
|  |  | 
|  | /* Representation of sets: | 
|  |  | 
|  | There are currently two types of sets used, hopefully to be unified soon. | 
|  | The AVAIL sets do not need to be sorted in any particular order, | 
|  | and thus, are simply represented as two bitmaps, one that keeps | 
|  | track of values present in the set, and one that keeps track of | 
|  | expressions present in the set. | 
|  |  | 
|  | The other sets are represented as doubly linked lists kept in topological | 
|  | order, with an optional supporting bitmap of values present in the | 
|  | set.  The sets represent values, and the elements can be values or | 
|  | expressions.  The elements can appear in different sets, but each | 
|  | element can only appear once in each set. | 
|  |  | 
|  | Since each node in the set represents a value, we also want to be | 
|  | able to map expression, set pairs to something that tells us | 
|  | whether the value is present is a set.  We use a per-set bitmap for | 
|  | that.  The value handles also point to a linked list of the | 
|  | expressions they represent via a tree annotation.  This is mainly | 
|  | useful only for debugging, since we don't do identity lookups.  */ | 
|  |  | 
|  |  | 
|  | static bool in_fre = false; | 
|  |  | 
|  | /* A value set element.  Basically a single linked list of | 
|  | expressions/values.  */ | 
|  | typedef struct value_set_node | 
|  | { | 
|  | /* An expression.  */ | 
|  | tree expr; | 
|  |  | 
|  | /* A pointer to the next element of the value set.  */ | 
|  | struct value_set_node *next; | 
|  | } *value_set_node_t; | 
|  |  | 
|  |  | 
|  | /* A value set.  This is a singly linked list of value_set_node | 
|  | elements with a possible bitmap that tells us what values exist in | 
|  | the set.  This set must be kept in topologically sorted order.  */ | 
|  | typedef struct value_set | 
|  | { | 
|  | /* The head of the list.  Used for iterating over the list in | 
|  | order.  */ | 
|  | value_set_node_t head; | 
|  |  | 
|  | /* The tail of the list.  Used for tail insertions, which are | 
|  | necessary to keep the set in topologically sorted order because | 
|  | of how the set is built.  */ | 
|  | value_set_node_t tail; | 
|  |  | 
|  | /* The length of the list.  */ | 
|  | size_t length; | 
|  |  | 
|  | /* True if the set is indexed, which means it contains a backing | 
|  | bitmap for quick determination of whether certain values exist in the | 
|  | set.  */ | 
|  | bool indexed; | 
|  |  | 
|  | /* The bitmap of values that exist in the set.  May be NULL in an | 
|  | empty or non-indexed set.  */ | 
|  | bitmap values; | 
|  |  | 
|  | } *value_set_t; | 
|  |  | 
|  |  | 
|  | /* An unordered bitmap set.  One bitmap tracks values, the other, | 
|  | expressions.  */ | 
|  | typedef struct bitmap_set | 
|  | { | 
|  | bitmap expressions; | 
|  | bitmap values; | 
|  | } *bitmap_set_t; | 
|  |  | 
|  | /* Sets that we need to keep track of.  */ | 
|  | typedef struct bb_value_sets | 
|  | { | 
|  | /* The EXP_GEN set, which represents expressions/values generated in | 
|  | a basic block.  */ | 
|  | value_set_t exp_gen; | 
|  |  | 
|  | /* The PHI_GEN set, which represents PHI results generated in a | 
|  | basic block.  */ | 
|  | bitmap_set_t phi_gen; | 
|  |  | 
|  | /* The TMP_GEN set, which represents results/temporaries generated | 
|  | in a basic block. IE the LHS of an expression.  */ | 
|  | bitmap_set_t tmp_gen; | 
|  |  | 
|  | /* The AVAIL_OUT set, which represents which values are available in | 
|  | a given basic block.  */ | 
|  | bitmap_set_t avail_out; | 
|  |  | 
|  | /* The ANTIC_IN set, which represents which values are anticipatable | 
|  | in a given basic block.  */ | 
|  | value_set_t antic_in; | 
|  |  | 
|  | /* The NEW_SETS set, which is used during insertion to augment the | 
|  | AVAIL_OUT set of blocks with the new insertions performed during | 
|  | the current iteration.  */ | 
|  | bitmap_set_t new_sets; | 
|  |  | 
|  | /* The RVUSE sets, which are used during ANTIC computation to ensure | 
|  | that we don't mark loads ANTIC once they have died.  */ | 
|  | bitmap rvuse_in; | 
|  | bitmap rvuse_out; | 
|  | bitmap rvuse_gen; | 
|  | bitmap rvuse_kill; | 
|  |  | 
|  | /* For actually occurring loads, as long as they occur before all the | 
|  | other stores in the block, we know they are antic at the top of | 
|  | the block, regardless of RVUSE_KILL.  */ | 
|  | value_set_t antic_safe_loads; | 
|  | } *bb_value_sets_t; | 
|  |  | 
|  | #define EXP_GEN(BB)	((bb_value_sets_t) ((BB)->aux))->exp_gen | 
|  | #define PHI_GEN(BB)	((bb_value_sets_t) ((BB)->aux))->phi_gen | 
|  | #define TMP_GEN(BB)	((bb_value_sets_t) ((BB)->aux))->tmp_gen | 
|  | #define AVAIL_OUT(BB)	((bb_value_sets_t) ((BB)->aux))->avail_out | 
|  | #define ANTIC_IN(BB)	((bb_value_sets_t) ((BB)->aux))->antic_in | 
|  | #define RVUSE_IN(BB)    ((bb_value_sets_t) ((BB)->aux))->rvuse_in | 
|  | #define RVUSE_GEN(BB)   ((bb_value_sets_t) ((BB)->aux))->rvuse_gen | 
|  | #define RVUSE_KILL(BB)   ((bb_value_sets_t) ((BB)->aux))->rvuse_kill | 
|  | #define RVUSE_OUT(BB)    ((bb_value_sets_t) ((BB)->aux))->rvuse_out | 
|  | #define NEW_SETS(BB)	((bb_value_sets_t) ((BB)->aux))->new_sets | 
|  | #define ANTIC_SAFE_LOADS(BB) ((bb_value_sets_t) ((BB)->aux))->antic_safe_loads | 
|  |  | 
|  | /* This structure is used to keep track of statistics on what | 
|  | optimization PRE was able to perform.  */ | 
|  | static struct | 
|  | { | 
|  | /* The number of RHS computations eliminated by PRE.  */ | 
|  | int eliminations; | 
|  |  | 
|  | /* The number of new expressions/temporaries generated by PRE.  */ | 
|  | int insertions; | 
|  |  | 
|  | /* The number of new PHI nodes added by PRE.  */ | 
|  | int phis; | 
|  |  | 
|  | /* The number of values found constant.  */ | 
|  | int constified; | 
|  |  | 
|  | } pre_stats; | 
|  |  | 
|  |  | 
|  | static tree bitmap_find_leader (bitmap_set_t, tree); | 
|  | static tree find_leader (value_set_t, tree); | 
|  | static void value_insert_into_set (value_set_t, tree); | 
|  | static void bitmap_value_insert_into_set (bitmap_set_t, tree); | 
|  | static void bitmap_value_replace_in_set (bitmap_set_t, tree); | 
|  | static void insert_into_set (value_set_t, tree); | 
|  | static void bitmap_set_copy (bitmap_set_t, bitmap_set_t); | 
|  | static bool bitmap_set_contains_value (bitmap_set_t, tree); | 
|  | static bitmap_set_t bitmap_set_new (void); | 
|  | static value_set_t set_new  (bool); | 
|  | static bool is_undefined_value (tree); | 
|  | static tree create_expression_by_pieces (basic_block, tree, tree); | 
|  | static tree find_or_generate_expression (basic_block, tree, tree); | 
|  |  | 
|  |  | 
|  | /* We can add and remove elements and entries to and from sets | 
|  | and hash tables, so we use alloc pools for them.  */ | 
|  |  | 
|  | static alloc_pool value_set_pool; | 
|  | static alloc_pool bitmap_set_pool; | 
|  | static alloc_pool value_set_node_pool; | 
|  | static alloc_pool binary_node_pool; | 
|  | static alloc_pool unary_node_pool; | 
|  | static alloc_pool reference_node_pool; | 
|  | static alloc_pool comparison_node_pool; | 
|  | static alloc_pool expression_node_pool; | 
|  | static alloc_pool list_node_pool; | 
|  | static alloc_pool modify_expr_node_pool; | 
|  | static bitmap_obstack grand_bitmap_obstack; | 
|  |  | 
|  | /* To avoid adding 300 temporary variables when we only need one, we | 
|  | only create one temporary variable, on demand, and build ssa names | 
|  | off that.  We do have to change the variable if the types don't | 
|  | match the current variable's type.  */ | 
|  | static tree pretemp; | 
|  | static tree storetemp; | 
|  | static tree mergephitemp; | 
|  | static tree prephitemp; | 
|  |  | 
|  | /* Set of blocks with statements that have had its EH information | 
|  | cleaned up.  */ | 
|  | static bitmap need_eh_cleanup; | 
|  |  | 
|  | /* The phi_translate_table caches phi translations for a given | 
|  | expression and predecessor.  */ | 
|  |  | 
|  | static htab_t phi_translate_table; | 
|  |  | 
|  | /* A three tuple {e, pred, v} used to cache phi translations in the | 
|  | phi_translate_table.  */ | 
|  |  | 
|  | typedef struct expr_pred_trans_d | 
|  | { | 
|  | /* The expression.  */ | 
|  | tree e; | 
|  |  | 
|  | /* The predecessor block along which we translated the expression.  */ | 
|  | basic_block pred; | 
|  |  | 
|  | /* vuses associated with the expression.  */ | 
|  | VEC (tree, gc) *vuses; | 
|  |  | 
|  | /* The value that resulted from the translation.  */ | 
|  | tree v; | 
|  |  | 
|  |  | 
|  | /* The hashcode for the expression, pred pair. This is cached for | 
|  | speed reasons.  */ | 
|  | hashval_t hashcode; | 
|  | } *expr_pred_trans_t; | 
|  |  | 
|  | /* Return the hash value for a phi translation table entry.  */ | 
|  |  | 
|  | static hashval_t | 
|  | expr_pred_trans_hash (const void *p) | 
|  | { | 
|  | const expr_pred_trans_t ve = (expr_pred_trans_t) p; | 
|  | return ve->hashcode; | 
|  | } | 
|  |  | 
|  | /* Return true if two phi translation table entries are the same. | 
|  | P1 and P2 should point to the expr_pred_trans_t's to be compared.*/ | 
|  |  | 
|  | static int | 
|  | expr_pred_trans_eq (const void *p1, const void *p2) | 
|  | { | 
|  | const expr_pred_trans_t ve1 = (expr_pred_trans_t) p1; | 
|  | const expr_pred_trans_t ve2 = (expr_pred_trans_t) p2; | 
|  | basic_block b1 = ve1->pred; | 
|  | basic_block b2 = ve2->pred; | 
|  | int i; | 
|  | tree vuse1; | 
|  |  | 
|  | /* If they are not translations for the same basic block, they can't | 
|  | be equal.  */ | 
|  | if (b1 != b2) | 
|  | return false; | 
|  |  | 
|  |  | 
|  | /* If they are for the same basic block, determine if the | 
|  | expressions are equal.  */ | 
|  | if (!expressions_equal_p (ve1->e, ve2->e)) | 
|  | return false; | 
|  |  | 
|  | /* Make sure the vuses are equivalent.  */ | 
|  | if (ve1->vuses == ve2->vuses) | 
|  | return true; | 
|  |  | 
|  | if (VEC_length (tree, ve1->vuses) != VEC_length (tree, ve2->vuses)) | 
|  | return false; | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, ve1->vuses, i, vuse1); i++) | 
|  | { | 
|  | if (VEC_index (tree, ve2->vuses, i) != vuse1) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Search in the phi translation table for the translation of | 
|  | expression E in basic block PRED with vuses VUSES. | 
|  | Return the translated value, if found, NULL otherwise.  */ | 
|  |  | 
|  | static inline tree | 
|  | phi_trans_lookup (tree e, basic_block pred, VEC (tree, gc) *vuses) | 
|  | { | 
|  | void **slot; | 
|  | struct expr_pred_trans_d ept; | 
|  |  | 
|  | ept.e = e; | 
|  | ept.pred = pred; | 
|  | ept.vuses = vuses; | 
|  | ept.hashcode = vn_compute (e, (unsigned long) pred); | 
|  | slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode, | 
|  | NO_INSERT); | 
|  | if (!slot) | 
|  | return NULL; | 
|  | else | 
|  | return ((expr_pred_trans_t) *slot)->v; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Add the tuple mapping from {expression E, basic block PRED, vuses VUSES} to | 
|  | value V, to the phi translation table.  */ | 
|  |  | 
|  | static inline void | 
|  | phi_trans_add (tree e, tree v, basic_block pred, VEC (tree, gc) *vuses) | 
|  | { | 
|  | void **slot; | 
|  | expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d); | 
|  | new_pair->e = e; | 
|  | new_pair->pred = pred; | 
|  | new_pair->vuses = vuses; | 
|  | new_pair->v = v; | 
|  | new_pair->hashcode = vn_compute (e, (unsigned long) pred); | 
|  | slot = htab_find_slot_with_hash (phi_translate_table, new_pair, | 
|  | new_pair->hashcode, INSERT); | 
|  | if (*slot) | 
|  | free (*slot); | 
|  | *slot = (void *) new_pair; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Add expression E to the expression set of value V.  */ | 
|  |  | 
|  | void | 
|  | add_to_value (tree v, tree e) | 
|  | { | 
|  | /* Constants have no expression sets.  */ | 
|  | if (is_gimple_min_invariant (v)) | 
|  | return; | 
|  |  | 
|  | if (VALUE_HANDLE_EXPR_SET (v) == NULL) | 
|  | VALUE_HANDLE_EXPR_SET (v) = set_new (false); | 
|  |  | 
|  | insert_into_set (VALUE_HANDLE_EXPR_SET (v), e); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Return true if value V exists in the bitmap for SET.  */ | 
|  |  | 
|  | static inline bool | 
|  | value_exists_in_set_bitmap (value_set_t set, tree v) | 
|  | { | 
|  | if (!set->values) | 
|  | return false; | 
|  |  | 
|  | return bitmap_bit_p (set->values, VALUE_HANDLE_ID (v)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Remove value V from the bitmap for SET.  */ | 
|  |  | 
|  | static void | 
|  | value_remove_from_set_bitmap (value_set_t set, tree v) | 
|  | { | 
|  | gcc_assert (set->indexed); | 
|  |  | 
|  | if (!set->values) | 
|  | return; | 
|  |  | 
|  | bitmap_clear_bit (set->values, VALUE_HANDLE_ID (v)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Insert the value number V into the bitmap of values existing in | 
|  | SET.  */ | 
|  |  | 
|  | static inline void | 
|  | value_insert_into_set_bitmap (value_set_t set, tree v) | 
|  | { | 
|  | gcc_assert (set->indexed); | 
|  |  | 
|  | if (set->values == NULL) | 
|  | set->values = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  |  | 
|  | bitmap_set_bit (set->values, VALUE_HANDLE_ID (v)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Create a new bitmap set and return it.  */ | 
|  |  | 
|  | static bitmap_set_t | 
|  | bitmap_set_new (void) | 
|  | { | 
|  | bitmap_set_t ret = (bitmap_set_t) pool_alloc (bitmap_set_pool); | 
|  | ret->expressions = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | ret->values = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Create a new set.  */ | 
|  |  | 
|  | static value_set_t | 
|  | set_new  (bool indexed) | 
|  | { | 
|  | value_set_t ret; | 
|  | ret = (value_set_t) pool_alloc (value_set_pool); | 
|  | ret->head = ret->tail = NULL; | 
|  | ret->length = 0; | 
|  | ret->indexed = indexed; | 
|  | ret->values = NULL; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Insert an expression EXPR into a bitmapped set.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_insert_into_set (bitmap_set_t set, tree expr) | 
|  | { | 
|  | tree val; | 
|  | /* XXX: For now, we only let SSA_NAMES into the bitmap sets.  */ | 
|  | gcc_assert (TREE_CODE (expr) == SSA_NAME); | 
|  | val = get_value_handle (expr); | 
|  |  | 
|  | gcc_assert (val); | 
|  | if (!is_gimple_min_invariant (val)) | 
|  | { | 
|  | bitmap_set_bit (set->values, VALUE_HANDLE_ID (val)); | 
|  | bitmap_set_bit (set->expressions, SSA_NAME_VERSION (expr)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Insert EXPR into SET.  */ | 
|  |  | 
|  | static void | 
|  | insert_into_set (value_set_t set, tree expr) | 
|  | { | 
|  | value_set_node_t newnode = (value_set_node_t) pool_alloc (value_set_node_pool); | 
|  | tree val = get_value_handle (expr); | 
|  | gcc_assert (val); | 
|  |  | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return; | 
|  |  | 
|  | /* For indexed sets, insert the value into the set value bitmap. | 
|  | For all sets, add it to the linked list and increment the list | 
|  | length.  */ | 
|  | if (set->indexed) | 
|  | value_insert_into_set_bitmap (set, val); | 
|  |  | 
|  | newnode->next = NULL; | 
|  | newnode->expr = expr; | 
|  | set->length ++; | 
|  | if (set->head == NULL) | 
|  | { | 
|  | set->head = set->tail = newnode; | 
|  | } | 
|  | else | 
|  | { | 
|  | set->tail->next = newnode; | 
|  | set->tail = newnode; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Copy a bitmapped set ORIG, into bitmapped set DEST.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_set_copy (bitmap_set_t dest, bitmap_set_t orig) | 
|  | { | 
|  | bitmap_copy (dest->expressions, orig->expressions); | 
|  | bitmap_copy (dest->values, orig->values); | 
|  | } | 
|  |  | 
|  | /* Perform bitmapped set operation DEST &= ORIG.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_set_and (bitmap_set_t dest, bitmap_set_t orig) | 
|  | { | 
|  | bitmap_iterator bi; | 
|  | unsigned int i; | 
|  | bitmap temp = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  |  | 
|  | bitmap_and_into (dest->values, orig->values); | 
|  | bitmap_copy (temp, dest->expressions); | 
|  | EXECUTE_IF_SET_IN_BITMAP (temp, 0, i, bi) | 
|  | { | 
|  | tree name = ssa_name (i); | 
|  | tree val = get_value_handle (name); | 
|  | if (!bitmap_bit_p (dest->values, VALUE_HANDLE_ID (val))) | 
|  | bitmap_clear_bit (dest->expressions, i); | 
|  | } | 
|  | BITMAP_FREE (temp); | 
|  | } | 
|  |  | 
|  | /* Perform bitmapped value set operation DEST = DEST & ~ORIG.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_set_and_compl (bitmap_set_t dest, bitmap_set_t orig) | 
|  | { | 
|  | bitmap_iterator bi; | 
|  | unsigned int i; | 
|  | bitmap temp = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  |  | 
|  | bitmap_and_compl_into (dest->values, orig->values); | 
|  | bitmap_copy (temp, dest->expressions); | 
|  | EXECUTE_IF_SET_IN_BITMAP (temp, 0, i, bi) | 
|  | { | 
|  | tree name = ssa_name (i); | 
|  | tree val = get_value_handle (name); | 
|  | if (!bitmap_bit_p (dest->values, VALUE_HANDLE_ID (val))) | 
|  | bitmap_clear_bit (dest->expressions, i); | 
|  | } | 
|  | BITMAP_FREE (temp); | 
|  | } | 
|  |  | 
|  | /* Return true if the bitmap set SET is empty.  */ | 
|  |  | 
|  | static bool | 
|  | bitmap_set_empty_p (bitmap_set_t set) | 
|  | { | 
|  | return bitmap_empty_p (set->values); | 
|  | } | 
|  |  | 
|  | /* Copy the set ORIG to the set DEST.  */ | 
|  |  | 
|  | static void | 
|  | set_copy (value_set_t dest, value_set_t orig) | 
|  | { | 
|  | value_set_node_t node; | 
|  |  | 
|  | if (!orig || !orig->head) | 
|  | return; | 
|  |  | 
|  | for (node = orig->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | insert_into_set (dest, node->expr); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Remove EXPR from SET.  */ | 
|  |  | 
|  | static void | 
|  | set_remove (value_set_t set, tree expr) | 
|  | { | 
|  | value_set_node_t node, prev; | 
|  |  | 
|  | /* Remove the value of EXPR from the bitmap, decrement the set | 
|  | length, and remove it from the actual double linked list.  */ | 
|  | value_remove_from_set_bitmap (set, get_value_handle (expr)); | 
|  | set->length--; | 
|  | prev = NULL; | 
|  | for (node = set->head; | 
|  | node != NULL; | 
|  | prev = node, node = node->next) | 
|  | { | 
|  | if (node->expr == expr) | 
|  | { | 
|  | if (prev == NULL) | 
|  | set->head = node->next; | 
|  | else | 
|  | prev->next= node->next; | 
|  |  | 
|  | if (node == set->tail) | 
|  | set->tail = prev; | 
|  | pool_free (value_set_node_pool, node); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Return true if SET contains the value VAL.  */ | 
|  |  | 
|  | static bool | 
|  | set_contains_value (value_set_t set, tree val) | 
|  | { | 
|  | /* All constants are in every set.  */ | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return true; | 
|  |  | 
|  | if (!set || set->length == 0) | 
|  | return false; | 
|  |  | 
|  | return value_exists_in_set_bitmap (set, val); | 
|  | } | 
|  |  | 
|  | /* Return true if bitmapped set SET contains the expression EXPR.  */ | 
|  | static bool | 
|  | bitmap_set_contains (bitmap_set_t set, tree expr) | 
|  | { | 
|  | /* All constants are in every set.  */ | 
|  | if (is_gimple_min_invariant (get_value_handle (expr))) | 
|  | return true; | 
|  |  | 
|  | /* XXX: Bitmapped sets only contain SSA_NAME's for now.  */ | 
|  | if (TREE_CODE (expr) != SSA_NAME) | 
|  | return false; | 
|  | return bitmap_bit_p (set->expressions, SSA_NAME_VERSION (expr)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Return true if bitmapped set SET contains the value VAL.  */ | 
|  |  | 
|  | static bool | 
|  | bitmap_set_contains_value (bitmap_set_t set, tree val) | 
|  | { | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return true; | 
|  | return bitmap_bit_p (set->values, VALUE_HANDLE_ID (val)); | 
|  | } | 
|  |  | 
|  | /* Replace an instance of value LOOKFOR with expression EXPR in SET.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_set_replace_value (bitmap_set_t set, tree lookfor, tree expr) | 
|  | { | 
|  | value_set_t exprset; | 
|  | value_set_node_t node; | 
|  | if (is_gimple_min_invariant (lookfor)) | 
|  | return; | 
|  | if (!bitmap_set_contains_value (set, lookfor)) | 
|  | return; | 
|  |  | 
|  | /* The number of expressions having a given value is usually | 
|  | significantly less than the total number of expressions in SET. | 
|  | Thus, rather than check, for each expression in SET, whether it | 
|  | has the value LOOKFOR, we walk the reverse mapping that tells us | 
|  | what expressions have a given value, and see if any of those | 
|  | expressions are in our set.  For large testcases, this is about | 
|  | 5-10x faster than walking the bitmap.  If this is somehow a | 
|  | significant lose for some cases, we can choose which set to walk | 
|  | based on the set size.  */ | 
|  | exprset = VALUE_HANDLE_EXPR_SET (lookfor); | 
|  | for (node = exprset->head; node; node = node->next) | 
|  | { | 
|  | if (TREE_CODE (node->expr) == SSA_NAME) | 
|  | { | 
|  | if (bitmap_bit_p (set->expressions, SSA_NAME_VERSION (node->expr))) | 
|  | { | 
|  | bitmap_clear_bit (set->expressions, SSA_NAME_VERSION (node->expr)); | 
|  | bitmap_set_bit (set->expressions, SSA_NAME_VERSION (expr)); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Subtract bitmapped set B from value set A, and return the new set.  */ | 
|  |  | 
|  | static value_set_t | 
|  | bitmap_set_subtract_from_value_set (value_set_t a, bitmap_set_t b, | 
|  | bool indexed) | 
|  | { | 
|  | value_set_t ret = set_new (indexed); | 
|  | value_set_node_t node; | 
|  | for (node = a->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | if (!bitmap_set_contains (b, node->expr)) | 
|  | insert_into_set (ret, node->expr); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Return true if two sets are equal.  */ | 
|  |  | 
|  | static bool | 
|  | set_equal (value_set_t a, value_set_t b) | 
|  | { | 
|  | value_set_node_t node; | 
|  |  | 
|  | if (a->length != b->length) | 
|  | return false; | 
|  | for (node = a->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | if (!set_contains_value (b, get_value_handle (node->expr))) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Replace an instance of EXPR's VALUE with EXPR in SET if it exists, | 
|  | and add it otherwise.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_value_replace_in_set (bitmap_set_t set, tree expr) | 
|  | { | 
|  | tree val = get_value_handle (expr); | 
|  | if (bitmap_set_contains_value (set, val)) | 
|  | bitmap_set_replace_value (set, val, expr); | 
|  | else | 
|  | bitmap_insert_into_set (set, expr); | 
|  | } | 
|  |  | 
|  | /* Insert EXPR into SET if EXPR's value is not already present in | 
|  | SET.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_value_insert_into_set (bitmap_set_t set, tree expr) | 
|  | { | 
|  | tree val = get_value_handle (expr); | 
|  |  | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return; | 
|  |  | 
|  | if (!bitmap_set_contains_value (set, val)) | 
|  | bitmap_insert_into_set (set, expr); | 
|  | } | 
|  |  | 
|  | /* Insert the value for EXPR into SET, if it doesn't exist already.  */ | 
|  |  | 
|  | static void | 
|  | value_insert_into_set (value_set_t set, tree expr) | 
|  | { | 
|  | tree val = get_value_handle (expr); | 
|  |  | 
|  | /* Constant and invariant values exist everywhere, and thus, | 
|  | actually keeping them in the sets is pointless.  */ | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return; | 
|  |  | 
|  | if (!set_contains_value (set, val)) | 
|  | insert_into_set (set, expr); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Print out SET to OUTFILE.  */ | 
|  |  | 
|  | static void | 
|  | bitmap_print_value_set (FILE *outfile, bitmap_set_t set, | 
|  | const char *setname, int blockindex) | 
|  | { | 
|  | fprintf (outfile, "%s[%d] := { ", setname, blockindex); | 
|  | if (set) | 
|  | { | 
|  | bool first = true; | 
|  | unsigned i; | 
|  | bitmap_iterator bi; | 
|  |  | 
|  | EXECUTE_IF_SET_IN_BITMAP (set->expressions, 0, i, bi) | 
|  | { | 
|  | if (!first) | 
|  | fprintf (outfile, ", "); | 
|  | first = false; | 
|  | print_generic_expr (outfile, ssa_name (i), 0); | 
|  |  | 
|  | fprintf (outfile, " ("); | 
|  | print_generic_expr (outfile, get_value_handle (ssa_name (i)), 0); | 
|  | fprintf (outfile, ") "); | 
|  | } | 
|  | } | 
|  | fprintf (outfile, " }\n"); | 
|  | } | 
|  | /* Print out the value_set SET to OUTFILE.  */ | 
|  |  | 
|  | static void | 
|  | print_value_set (FILE *outfile, value_set_t set, | 
|  | const char *setname, int blockindex) | 
|  | { | 
|  | value_set_node_t node; | 
|  | fprintf (outfile, "%s[%d] := { ", setname, blockindex); | 
|  | if (set) | 
|  | { | 
|  | for (node = set->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | print_generic_expr (outfile, node->expr, 0); | 
|  |  | 
|  | fprintf (outfile, " ("); | 
|  | print_generic_expr (outfile, get_value_handle (node->expr), 0); | 
|  | fprintf (outfile, ") "); | 
|  |  | 
|  | if (node->next) | 
|  | fprintf (outfile, ", "); | 
|  | } | 
|  | } | 
|  |  | 
|  | fprintf (outfile, " }\n"); | 
|  | } | 
|  |  | 
|  | /* Print out the expressions that have VAL to OUTFILE.  */ | 
|  |  | 
|  | void | 
|  | print_value_expressions (FILE *outfile, tree val) | 
|  | { | 
|  | if (VALUE_HANDLE_EXPR_SET (val)) | 
|  | { | 
|  | char s[10]; | 
|  | sprintf (s, "VH.%04d", VALUE_HANDLE_ID (val)); | 
|  | print_value_set (outfile, VALUE_HANDLE_EXPR_SET (val), s, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | debug_value_expressions (tree val) | 
|  | { | 
|  | print_value_expressions (stderr, val); | 
|  | } | 
|  |  | 
|  |  | 
|  | void debug_value_set (value_set_t, const char *, int); | 
|  |  | 
|  | void | 
|  | debug_value_set (value_set_t set, const char *setname, int blockindex) | 
|  | { | 
|  | print_value_set (stderr, set, setname, blockindex); | 
|  | } | 
|  |  | 
|  | /* Return the folded version of T if T, when folded, is a gimple | 
|  | min_invariant.  Otherwise, return T.  */ | 
|  |  | 
|  | static tree | 
|  | fully_constant_expression (tree t) | 
|  | { | 
|  | tree folded; | 
|  | folded = fold (t); | 
|  | if (folded && is_gimple_min_invariant (folded)) | 
|  | return folded; | 
|  | return t; | 
|  | } | 
|  |  | 
|  | /* Return a copy of a chain of nodes, chained through the TREE_CHAIN field. | 
|  | For example, this can copy a list made of TREE_LIST nodes. | 
|  | Allocates the nodes in list_node_pool*/ | 
|  |  | 
|  | static tree | 
|  | pool_copy_list (tree list) | 
|  | { | 
|  | tree head; | 
|  | tree prev, next; | 
|  |  | 
|  | if (list == 0) | 
|  | return 0; | 
|  | head = (tree) pool_alloc (list_node_pool); | 
|  |  | 
|  | memcpy (head, list, tree_size (list)); | 
|  | prev = head; | 
|  |  | 
|  | next = TREE_CHAIN (list); | 
|  | while (next) | 
|  | { | 
|  | TREE_CHAIN (prev) = (tree) pool_alloc (list_node_pool); | 
|  | memcpy (TREE_CHAIN (prev), next, tree_size (next)); | 
|  | prev = TREE_CHAIN (prev); | 
|  | next = TREE_CHAIN (next); | 
|  | } | 
|  | return head; | 
|  | } | 
|  |  | 
|  | /* Translate the vuses in the VUSES vector backwards through phi | 
|  | nodes, so that they have the value they would have in BLOCK. */ | 
|  |  | 
|  | static VEC(tree, gc) * | 
|  | translate_vuses_through_block (VEC (tree, gc) *vuses, basic_block block) | 
|  | { | 
|  | tree oldvuse; | 
|  | VEC(tree, gc) *result = NULL; | 
|  | int i; | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++) | 
|  | { | 
|  | tree phi = SSA_NAME_DEF_STMT (oldvuse); | 
|  | if (TREE_CODE (phi) == PHI_NODE) | 
|  | { | 
|  | edge e = find_edge (block, bb_for_stmt (phi)); | 
|  | if (e) | 
|  | { | 
|  | tree def = PHI_ARG_DEF (phi, e->dest_idx); | 
|  | if (def != oldvuse) | 
|  | { | 
|  | if (!result) | 
|  | result = VEC_copy (tree, gc, vuses); | 
|  | VEC_replace (tree, result, i, def); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | if (result) | 
|  | { | 
|  | sort_vuses (result); | 
|  | return result; | 
|  | } | 
|  | return vuses; | 
|  |  | 
|  | } | 
|  | /* Translate EXPR using phis in PHIBLOCK, so that it has the values of | 
|  | the phis in PRED.  Return NULL if we can't find a leader for each | 
|  | part of the translated expression.  */ | 
|  |  | 
|  | static tree | 
|  | phi_translate (tree expr, value_set_t set, basic_block pred, | 
|  | basic_block phiblock) | 
|  | { | 
|  | tree phitrans = NULL; | 
|  | tree oldexpr = expr; | 
|  | if (expr == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (is_gimple_min_invariant (expr)) | 
|  | return expr; | 
|  |  | 
|  | /* Phi translations of a given expression don't change.  */ | 
|  | if (EXPR_P (expr)) | 
|  | { | 
|  | tree vh; | 
|  |  | 
|  | vh = get_value_handle (expr); | 
|  | if (vh && TREE_CODE (vh) == VALUE_HANDLE) | 
|  | phitrans = phi_trans_lookup (expr, pred, VALUE_HANDLE_VUSES (vh)); | 
|  | else | 
|  | phitrans = phi_trans_lookup (expr, pred, NULL); | 
|  | } | 
|  | else | 
|  | phitrans = phi_trans_lookup (expr, pred, NULL); | 
|  |  | 
|  | if (phitrans) | 
|  | return phitrans; | 
|  |  | 
|  | switch (TREE_CODE_CLASS (TREE_CODE (expr))) | 
|  | { | 
|  | case tcc_expression: | 
|  | { | 
|  | if (TREE_CODE (expr) != CALL_EXPR) | 
|  | return NULL; | 
|  | else | 
|  | { | 
|  | tree oldop0 = TREE_OPERAND (expr, 0); | 
|  | tree oldarglist = TREE_OPERAND (expr, 1); | 
|  | tree oldop2 = TREE_OPERAND (expr, 2); | 
|  | tree newop0; | 
|  | tree newarglist; | 
|  | tree newop2 = NULL; | 
|  | tree oldwalker; | 
|  | tree newwalker; | 
|  | tree newexpr; | 
|  | tree vh = get_value_handle (expr); | 
|  | bool listchanged = false; | 
|  | VEC (tree, gc) *vuses = VALUE_HANDLE_VUSES (vh); | 
|  | VEC (tree, gc) *tvuses; | 
|  |  | 
|  | /* Call expressions are kind of weird because they have an | 
|  | argument list.  We don't want to value number the list | 
|  | as one value number, because that doesn't make much | 
|  | sense, and just breaks the support functions we call, | 
|  | which expect TREE_OPERAND (call_expr, 2) to be a | 
|  | TREE_LIST. */ | 
|  |  | 
|  | newop0 = phi_translate (find_leader (set, oldop0), | 
|  | set, pred, phiblock); | 
|  | if (newop0 == NULL) | 
|  | return NULL; | 
|  | if (oldop2) | 
|  | { | 
|  | newop2 = phi_translate (find_leader (set, oldop2), | 
|  | set, pred, phiblock); | 
|  | if (newop2 == NULL) | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* phi translate the argument list piece by piece. | 
|  |  | 
|  | We could actually build the list piece by piece here, | 
|  | but it's likely to not be worth the memory we will save, | 
|  | unless you have millions of call arguments.  */ | 
|  |  | 
|  | newarglist = pool_copy_list (oldarglist); | 
|  | for (oldwalker = oldarglist, newwalker = newarglist; | 
|  | oldwalker && newwalker; | 
|  | oldwalker = TREE_CHAIN (oldwalker), | 
|  | newwalker = TREE_CHAIN (newwalker)) | 
|  | { | 
|  |  | 
|  | tree oldval = TREE_VALUE (oldwalker); | 
|  | tree newval; | 
|  | if (oldval) | 
|  | { | 
|  | /* This may seem like a weird place for this | 
|  | check, but it's actually the easiest place to | 
|  | do it.  We can't do it lower on in the | 
|  | recursion because it's valid for pieces of a | 
|  | component ref to be of AGGREGATE_TYPE, as long | 
|  | as the outermost one is not. | 
|  | To avoid *that* case, we have a check for | 
|  | AGGREGATE_TYPE_P in insert_aux.  However, that | 
|  | check will *not* catch this case because here | 
|  | it occurs in the argument list.  */ | 
|  | if (AGGREGATE_TYPE_P (TREE_TYPE (oldval))) | 
|  | return NULL; | 
|  | newval = phi_translate (find_leader (set, oldval), | 
|  | set, pred, phiblock); | 
|  | if (newval == NULL) | 
|  | return NULL; | 
|  | if (newval != oldval) | 
|  | { | 
|  | listchanged = true; | 
|  | TREE_VALUE (newwalker) = get_value_handle (newval); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (listchanged) | 
|  | vn_lookup_or_add (newarglist, NULL); | 
|  |  | 
|  | tvuses = translate_vuses_through_block (vuses, pred); | 
|  |  | 
|  | if (listchanged || (newop0 != oldop0) || (oldop2 != newop2) | 
|  | || vuses != tvuses) | 
|  | { | 
|  | newexpr = (tree) pool_alloc (expression_node_pool); | 
|  | memcpy (newexpr, expr, tree_size (expr)); | 
|  | TREE_OPERAND (newexpr, 0) = newop0 == oldop0 ? oldop0 : get_value_handle (newop0); | 
|  | TREE_OPERAND (newexpr, 1) = listchanged ? newarglist : oldarglist; | 
|  | TREE_OPERAND (newexpr, 2) = newop2 == oldop2 ? oldop2 : get_value_handle (newop2); | 
|  | newexpr->common.ann = NULL; | 
|  | vn_lookup_or_add_with_vuses (newexpr, tvuses); | 
|  | expr = newexpr; | 
|  | phi_trans_add (oldexpr, newexpr, pred, tvuses); | 
|  | } | 
|  | } | 
|  | } | 
|  | return expr; | 
|  |  | 
|  | case tcc_declaration: | 
|  | { | 
|  | VEC (tree, gc) * oldvuses = NULL; | 
|  | VEC (tree, gc) * newvuses = NULL; | 
|  |  | 
|  | oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr)); | 
|  | if (oldvuses) | 
|  | newvuses = translate_vuses_through_block (oldvuses, pred); | 
|  |  | 
|  | if (oldvuses != newvuses) | 
|  | vn_lookup_or_add_with_vuses (expr, newvuses); | 
|  |  | 
|  | phi_trans_add (oldexpr, expr, pred, newvuses); | 
|  | } | 
|  | return expr; | 
|  |  | 
|  | case tcc_reference: | 
|  | { | 
|  | tree oldop0 = TREE_OPERAND (expr, 0); | 
|  | tree oldop1 = NULL; | 
|  | tree newop0; | 
|  | tree newop1 = NULL; | 
|  | tree oldop2 = NULL; | 
|  | tree newop2 = NULL; | 
|  | tree oldop3 = NULL; | 
|  | tree newop3 = NULL; | 
|  | tree newexpr; | 
|  | VEC (tree, gc) * oldvuses = NULL; | 
|  | VEC (tree, gc) * newvuses = NULL; | 
|  |  | 
|  | if (TREE_CODE (expr) != INDIRECT_REF | 
|  | && TREE_CODE (expr) != COMPONENT_REF | 
|  | && TREE_CODE (expr) != ARRAY_REF) | 
|  | return NULL; | 
|  |  | 
|  | newop0 = phi_translate (find_leader (set, oldop0), | 
|  | set, pred, phiblock); | 
|  | if (newop0 == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (TREE_CODE (expr) == ARRAY_REF) | 
|  | { | 
|  | oldop1 = TREE_OPERAND (expr, 1); | 
|  | newop1 = phi_translate (find_leader (set, oldop1), | 
|  | set, pred, phiblock); | 
|  |  | 
|  | if (newop1 == NULL) | 
|  | return NULL; | 
|  | oldop2 = TREE_OPERAND (expr, 2); | 
|  | if (oldop2) | 
|  | { | 
|  | newop2 = phi_translate (find_leader (set, oldop2), | 
|  | set, pred, phiblock); | 
|  |  | 
|  | if (newop2 == NULL) | 
|  | return NULL; | 
|  | } | 
|  | oldop3 = TREE_OPERAND (expr, 3); | 
|  | if (oldop3) | 
|  | { | 
|  | newop3 = phi_translate (find_leader (set, oldop3), | 
|  | set, pred, phiblock); | 
|  |  | 
|  | if (newop3 == NULL) | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr)); | 
|  | if (oldvuses) | 
|  | newvuses = translate_vuses_through_block (oldvuses, pred); | 
|  |  | 
|  | if (newop0 != oldop0 || newvuses != oldvuses | 
|  | || newop1 != oldop1 | 
|  | || newop2 != oldop2 | 
|  | || newop3 != oldop3) | 
|  | { | 
|  | tree t; | 
|  |  | 
|  | newexpr = pool_alloc (reference_node_pool); | 
|  | memcpy (newexpr, expr, tree_size (expr)); | 
|  | TREE_OPERAND (newexpr, 0) = get_value_handle (newop0); | 
|  | if (TREE_CODE (expr) == ARRAY_REF) | 
|  | { | 
|  | TREE_OPERAND (newexpr, 1) = get_value_handle (newop1); | 
|  | if (newop2) | 
|  | TREE_OPERAND (newexpr, 2) = get_value_handle (newop2); | 
|  | if (newop3) | 
|  | TREE_OPERAND (newexpr, 3) = get_value_handle (newop3); | 
|  | } | 
|  |  | 
|  | t = fully_constant_expression (newexpr); | 
|  |  | 
|  | if (t != newexpr) | 
|  | { | 
|  | pool_free (reference_node_pool, newexpr); | 
|  | newexpr = t; | 
|  | } | 
|  | else | 
|  | { | 
|  | newexpr->common.ann = NULL; | 
|  | vn_lookup_or_add_with_vuses (newexpr, newvuses); | 
|  | } | 
|  | expr = newexpr; | 
|  | phi_trans_add (oldexpr, newexpr, pred, newvuses); | 
|  | } | 
|  | } | 
|  | return expr; | 
|  | break; | 
|  |  | 
|  | case tcc_binary: | 
|  | case tcc_comparison: | 
|  | { | 
|  | tree oldop1 = TREE_OPERAND (expr, 0); | 
|  | tree oldop2 = TREE_OPERAND (expr, 1); | 
|  | tree newop1; | 
|  | tree newop2; | 
|  | tree newexpr; | 
|  |  | 
|  | newop1 = phi_translate (find_leader (set, oldop1), | 
|  | set, pred, phiblock); | 
|  | if (newop1 == NULL) | 
|  | return NULL; | 
|  | newop2 = phi_translate (find_leader (set, oldop2), | 
|  | set, pred, phiblock); | 
|  | if (newop2 == NULL) | 
|  | return NULL; | 
|  | if (newop1 != oldop1 || newop2 != oldop2) | 
|  | { | 
|  | tree t; | 
|  | newexpr = (tree) pool_alloc (binary_node_pool); | 
|  | memcpy (newexpr, expr, tree_size (expr)); | 
|  | TREE_OPERAND (newexpr, 0) = newop1 == oldop1 ? oldop1 : get_value_handle (newop1); | 
|  | TREE_OPERAND (newexpr, 1) = newop2 == oldop2 ? oldop2 : get_value_handle (newop2); | 
|  | t = fully_constant_expression (newexpr); | 
|  | if (t != newexpr) | 
|  | { | 
|  | pool_free (binary_node_pool, newexpr); | 
|  | newexpr = t; | 
|  | } | 
|  | else | 
|  | { | 
|  | newexpr->common.ann = NULL; | 
|  | vn_lookup_or_add (newexpr, NULL); | 
|  | } | 
|  | expr = newexpr; | 
|  | phi_trans_add (oldexpr, newexpr, pred, NULL); | 
|  | } | 
|  | } | 
|  | return expr; | 
|  |  | 
|  | case tcc_unary: | 
|  | { | 
|  | tree oldop1 = TREE_OPERAND (expr, 0); | 
|  | tree newop1; | 
|  | tree newexpr; | 
|  |  | 
|  | newop1 = phi_translate (find_leader (set, oldop1), | 
|  | set, pred, phiblock); | 
|  | if (newop1 == NULL) | 
|  | return NULL; | 
|  | if (newop1 != oldop1) | 
|  | { | 
|  | tree t; | 
|  | newexpr = (tree) pool_alloc (unary_node_pool); | 
|  | memcpy (newexpr, expr, tree_size (expr)); | 
|  | TREE_OPERAND (newexpr, 0) = get_value_handle (newop1); | 
|  | t = fully_constant_expression (newexpr); | 
|  | if (t != newexpr) | 
|  | { | 
|  | pool_free (unary_node_pool, newexpr); | 
|  | newexpr = t; | 
|  | } | 
|  | else | 
|  | { | 
|  | newexpr->common.ann = NULL; | 
|  | vn_lookup_or_add (newexpr, NULL); | 
|  | } | 
|  | expr = newexpr; | 
|  | phi_trans_add (oldexpr, newexpr, pred, NULL); | 
|  | } | 
|  | } | 
|  | return expr; | 
|  |  | 
|  | case tcc_exceptional: | 
|  | { | 
|  | tree phi = NULL; | 
|  | edge e; | 
|  | gcc_assert (TREE_CODE (expr) == SSA_NAME); | 
|  | if (TREE_CODE (SSA_NAME_DEF_STMT (expr)) == PHI_NODE) | 
|  | phi = SSA_NAME_DEF_STMT (expr); | 
|  | else | 
|  | return expr; | 
|  |  | 
|  | e = find_edge (pred, bb_for_stmt (phi)); | 
|  | if (e) | 
|  | { | 
|  | if (is_undefined_value (PHI_ARG_DEF (phi, e->dest_idx))) | 
|  | return NULL; | 
|  | vn_lookup_or_add (PHI_ARG_DEF (phi, e->dest_idx), NULL); | 
|  | return PHI_ARG_DEF (phi, e->dest_idx); | 
|  | } | 
|  | } | 
|  | return expr; | 
|  |  | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* For each expression in SET, translate the value handles through phi nodes | 
|  | in PHIBLOCK using edge PHIBLOCK->PRED, and store the resulting | 
|  | expressions in DEST.  */ | 
|  |  | 
|  | static void | 
|  | phi_translate_set (value_set_t dest, value_set_t set, basic_block pred, | 
|  | basic_block phiblock) | 
|  | { | 
|  | value_set_node_t node; | 
|  | for (node = set->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | tree translated; | 
|  |  | 
|  | translated = phi_translate (node->expr, set, pred, phiblock); | 
|  |  | 
|  | /* Don't add constants or empty translations to the cache, since | 
|  | we won't look them up that way, or use the result, anyway.  */ | 
|  | if (translated && !is_gimple_min_invariant (translated)) | 
|  | { | 
|  | tree vh = get_value_handle (translated); | 
|  | VEC (tree, gc) *vuses; | 
|  |  | 
|  | /* The value handle itself may also be an invariant, in | 
|  | which case, it has no vuses.  */ | 
|  | vuses = !is_gimple_min_invariant (vh) | 
|  | ? VALUE_HANDLE_VUSES (vh) : NULL; | 
|  | phi_trans_add (node->expr, translated, pred, vuses); | 
|  | } | 
|  |  | 
|  | if (translated != NULL) | 
|  | value_insert_into_set (dest, translated); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Find the leader for a value (i.e., the name representing that | 
|  | value) in a given set, and return it.  Return NULL if no leader is | 
|  | found.  */ | 
|  |  | 
|  | static tree | 
|  | bitmap_find_leader (bitmap_set_t set, tree val) | 
|  | { | 
|  | if (val == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return val; | 
|  | if (bitmap_set_contains_value (set, val)) | 
|  | { | 
|  | /* Rather than walk the entire bitmap of expressions, and see | 
|  | whether any of them has the value we are looking for, we look | 
|  | at the reverse mapping, which tells us the set of expressions | 
|  | that have a given value (IE value->expressions with that | 
|  | value) and see if any of those expressions are in our set. | 
|  | The number of expressions per value is usually significantly | 
|  | less than the number of expressions in the set.  In fact, for | 
|  | large testcases, doing it this way is roughly 5-10x faster | 
|  | than walking the bitmap. | 
|  | If this is somehow a significant lose for some cases, we can | 
|  | choose which set to walk based on which set is smaller.  */ | 
|  | value_set_t exprset; | 
|  | value_set_node_t node; | 
|  | exprset = VALUE_HANDLE_EXPR_SET (val); | 
|  | for (node = exprset->head; node; node = node->next) | 
|  | { | 
|  | if (TREE_CODE (node->expr) == SSA_NAME) | 
|  | { | 
|  | if (bitmap_bit_p (set->expressions, | 
|  | SSA_NAME_VERSION (node->expr))) | 
|  | return node->expr; | 
|  | } | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Find the leader for a value (i.e., the name representing that | 
|  | value) in a given set, and return it.  Return NULL if no leader is | 
|  | found.  */ | 
|  |  | 
|  | static tree | 
|  | find_leader (value_set_t set, tree val) | 
|  | { | 
|  | value_set_node_t node; | 
|  |  | 
|  | if (val == NULL) | 
|  | return NULL; | 
|  |  | 
|  | /* Constants represent themselves.  */ | 
|  | if (is_gimple_min_invariant (val)) | 
|  | return val; | 
|  |  | 
|  | if (set->length == 0) | 
|  | return NULL; | 
|  |  | 
|  | if (value_exists_in_set_bitmap (set, val)) | 
|  | { | 
|  | for (node = set->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | if (get_value_handle (node->expr) == val) | 
|  | return node->expr; | 
|  | } | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Given the vuse representative map, MAP, and an SSA version number, | 
|  | ID, return the bitmap of names ID represents, or NULL, if none | 
|  | exists.  */ | 
|  |  | 
|  | static bitmap | 
|  | get_representative (bitmap *map, int id) | 
|  | { | 
|  | if (map[id] != NULL) | 
|  | return map[id]; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* A vuse is anticipable at the top of block x, from the bottom of the | 
|  | block, if it reaches the top of the block, and is not killed in the | 
|  | block.  In effect, we are trying to see if the vuse is transparent | 
|  | backwards in the block.  */ | 
|  |  | 
|  | static bool | 
|  | vuses_dies_in_block_x (VEC (tree, gc) *vuses, basic_block block) | 
|  | { | 
|  | int i; | 
|  | tree vuse; | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++) | 
|  | { | 
|  | /* Any places where this is too conservative, are places | 
|  | where we created a new version and shouldn't have.  */ | 
|  |  | 
|  | if (!bitmap_bit_p (RVUSE_IN (block), SSA_NAME_VERSION (vuse)) | 
|  | || bitmap_bit_p (RVUSE_KILL (block), SSA_NAME_VERSION (vuse))) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Determine if the expression EXPR is valid in SET.  This means that | 
|  | we have a leader for each part of the expression (if it consists of | 
|  | values), or the expression is an SSA_NAME. | 
|  |  | 
|  | NB: We never should run into a case where we have SSA_NAME + | 
|  | SSA_NAME or SSA_NAME + value.  The sets valid_in_set is called on, | 
|  | the ANTIC sets, will only ever have SSA_NAME's or value expressions | 
|  | (IE VALUE1 + VALUE2, *VALUE1, VALUE1 < VALUE2)  */ | 
|  |  | 
|  | static bool | 
|  | valid_in_set (value_set_t set, tree expr, basic_block block) | 
|  | { | 
|  | tree vh = get_value_handle (expr); | 
|  | switch (TREE_CODE_CLASS (TREE_CODE (expr))) | 
|  | { | 
|  | case tcc_binary: | 
|  | case tcc_comparison: | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 0); | 
|  | tree op2 = TREE_OPERAND (expr, 1); | 
|  | return set_contains_value (set, op1) && set_contains_value (set, op2); | 
|  | } | 
|  |  | 
|  | case tcc_unary: | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 0); | 
|  | return set_contains_value (set, op1); | 
|  | } | 
|  |  | 
|  | case tcc_expression: | 
|  | { | 
|  | if (TREE_CODE (expr) == CALL_EXPR) | 
|  | { | 
|  | tree op0 = TREE_OPERAND (expr, 0); | 
|  | tree arglist = TREE_OPERAND (expr, 1); | 
|  | tree op2 = TREE_OPERAND (expr, 2); | 
|  |  | 
|  | /* Check the non-list operands first.  */ | 
|  | if (!set_contains_value (set, op0) | 
|  | || (op2 && !set_contains_value (set, op2))) | 
|  | return false; | 
|  |  | 
|  | /* Now check the operands.  */ | 
|  | for (; arglist; arglist = TREE_CHAIN (arglist)) | 
|  | { | 
|  | if (!set_contains_value (set, TREE_VALUE (arglist))) | 
|  | return false; | 
|  | } | 
|  | return !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), block); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | case tcc_reference: | 
|  | { | 
|  | if (TREE_CODE (expr) == INDIRECT_REF | 
|  | || TREE_CODE (expr) == COMPONENT_REF | 
|  | || TREE_CODE (expr) == ARRAY_REF) | 
|  | { | 
|  | tree op0 = TREE_OPERAND (expr, 0); | 
|  | gcc_assert (is_gimple_min_invariant (op0) | 
|  | || TREE_CODE (op0) == VALUE_HANDLE); | 
|  | if (!set_contains_value (set, op0)) | 
|  | return false; | 
|  | if (TREE_CODE (expr) == ARRAY_REF) | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 1); | 
|  | tree op2 = TREE_OPERAND (expr, 2); | 
|  | tree op3 = TREE_OPERAND (expr, 3); | 
|  | gcc_assert (is_gimple_min_invariant (op1) | 
|  | || TREE_CODE (op1) == VALUE_HANDLE); | 
|  | if (!set_contains_value (set, op1)) | 
|  | return false; | 
|  | gcc_assert (!op2 || is_gimple_min_invariant (op2) | 
|  | || TREE_CODE (op2) == VALUE_HANDLE); | 
|  | if (op2 | 
|  | && !set_contains_value (set, op2)) | 
|  | return false; | 
|  | gcc_assert (!op3 || is_gimple_min_invariant (op3) | 
|  | || TREE_CODE (op3) == VALUE_HANDLE); | 
|  | if (op3 | 
|  | && !set_contains_value (set, op3)) | 
|  | return false; | 
|  | } | 
|  | return set_contains_value (ANTIC_SAFE_LOADS (block), | 
|  | vh) | 
|  | || !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), | 
|  | block); | 
|  | } | 
|  | } | 
|  | return false; | 
|  |  | 
|  | case tcc_exceptional: | 
|  | gcc_assert (TREE_CODE (expr) == SSA_NAME); | 
|  | return true; | 
|  |  | 
|  | case tcc_declaration: | 
|  | return !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), block); | 
|  |  | 
|  | default: | 
|  | /* No other cases should be encountered.  */ | 
|  | gcc_unreachable (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Clean the set of expressions that are no longer valid in SET.  This | 
|  | means expressions that are made up of values we have no leaders for | 
|  | in SET.  */ | 
|  |  | 
|  | static void | 
|  | clean (value_set_t set, basic_block block) | 
|  | { | 
|  | value_set_node_t node; | 
|  | value_set_node_t next; | 
|  | node = set->head; | 
|  | while (node) | 
|  | { | 
|  | next = node->next; | 
|  | if (!valid_in_set (set, node->expr, block)) | 
|  | set_remove (set, node->expr); | 
|  | node = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | static sbitmap has_abnormal_preds; | 
|  |  | 
|  | /* Compute the ANTIC set for BLOCK. | 
|  |  | 
|  | If succs(BLOCK) > 1 then | 
|  | ANTIC_OUT[BLOCK] = intersection of ANTIC_IN[b] for all succ(BLOCK) | 
|  | else if succs(BLOCK) == 1 then | 
|  | ANTIC_OUT[BLOCK] = phi_translate (ANTIC_IN[succ(BLOCK)]) | 
|  |  | 
|  | ANTIC_IN[BLOCK] = clean(ANTIC_OUT[BLOCK] U EXP_GEN[BLOCK] - TMP_GEN[BLOCK]) | 
|  |  | 
|  | XXX: It would be nice to either write a set_clear, and use it for | 
|  | ANTIC_OUT, or to mark the antic_out set as deleted at the end | 
|  | of this routine, so that the pool can hand the same memory back out | 
|  | again for the next ANTIC_OUT.  */ | 
|  |  | 
|  | static bool | 
|  | compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge) | 
|  | { | 
|  | basic_block son; | 
|  | bool changed = false; | 
|  | value_set_t S, old, ANTIC_OUT; | 
|  | value_set_node_t node; | 
|  |  | 
|  | ANTIC_OUT = S = NULL; | 
|  |  | 
|  | /* If any edges from predecessors are abnormal, antic_in is empty, | 
|  | so do nothing.  */ | 
|  | if (block_has_abnormal_pred_edge) | 
|  | goto maybe_dump_sets; | 
|  |  | 
|  | old = set_new (false); | 
|  | set_copy (old, ANTIC_IN (block)); | 
|  | ANTIC_OUT = set_new (true); | 
|  |  | 
|  | /* If the block has no successors, ANTIC_OUT is empty.  */ | 
|  | if (EDGE_COUNT (block->succs) == 0) | 
|  | ; | 
|  | /* If we have one successor, we could have some phi nodes to | 
|  | translate through.  */ | 
|  | else if (single_succ_p (block)) | 
|  | { | 
|  | phi_translate_set (ANTIC_OUT, ANTIC_IN (single_succ (block)), | 
|  | block, single_succ (block)); | 
|  | } | 
|  | /* If we have multiple successors, we take the intersection of all of | 
|  | them.  */ | 
|  | else | 
|  | { | 
|  | VEC(basic_block, heap) * worklist; | 
|  | edge e; | 
|  | size_t i; | 
|  | basic_block bprime, first; | 
|  | edge_iterator ei; | 
|  |  | 
|  | worklist = VEC_alloc (basic_block, heap, EDGE_COUNT (block->succs)); | 
|  | FOR_EACH_EDGE (e, ei, block->succs) | 
|  | VEC_quick_push (basic_block, worklist, e->dest); | 
|  | first = VEC_index (basic_block, worklist, 0); | 
|  | set_copy (ANTIC_OUT, ANTIC_IN (first)); | 
|  |  | 
|  | for (i = 1; VEC_iterate (basic_block, worklist, i, bprime); i++) | 
|  | { | 
|  | node = ANTIC_OUT->head; | 
|  | while (node) | 
|  | { | 
|  | tree val; | 
|  | value_set_node_t next = node->next; | 
|  |  | 
|  | val = get_value_handle (node->expr); | 
|  | if (!set_contains_value (ANTIC_IN (bprime), val)) | 
|  | set_remove (ANTIC_OUT, node->expr); | 
|  | node = next; | 
|  | } | 
|  | } | 
|  | VEC_free (basic_block, heap, worklist); | 
|  | } | 
|  |  | 
|  | /* Generate ANTIC_OUT - TMP_GEN.  */ | 
|  | S = bitmap_set_subtract_from_value_set (ANTIC_OUT, TMP_GEN (block), false); | 
|  |  | 
|  | /* Start ANTIC_IN with EXP_GEN - TMP_GEN */ | 
|  | ANTIC_IN (block) = bitmap_set_subtract_from_value_set (EXP_GEN (block), | 
|  | TMP_GEN (block), | 
|  | true); | 
|  |  | 
|  | /* Then union in the ANTIC_OUT - TMP_GEN values, | 
|  | to get ANTIC_OUT U EXP_GEN - TMP_GEN */ | 
|  | for (node = S->head; node; node = node->next) | 
|  | value_insert_into_set (ANTIC_IN (block), node->expr); | 
|  |  | 
|  | clean (ANTIC_IN (block), block); | 
|  | if (!set_equal (old, ANTIC_IN (block))) | 
|  | changed = true; | 
|  |  | 
|  | maybe_dump_sets: | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | if (ANTIC_OUT) | 
|  | print_value_set (dump_file, ANTIC_OUT, "ANTIC_OUT", block->index); | 
|  |  | 
|  | if (ANTIC_SAFE_LOADS (block)) | 
|  | print_value_set (dump_file, ANTIC_SAFE_LOADS (block), | 
|  | "ANTIC_SAFE_LOADS", block->index); | 
|  | print_value_set (dump_file, ANTIC_IN (block), "ANTIC_IN", block->index); | 
|  |  | 
|  | if (S) | 
|  | print_value_set (dump_file, S, "S", block->index); | 
|  | } | 
|  |  | 
|  | for (son = first_dom_son (CDI_POST_DOMINATORS, block); | 
|  | son; | 
|  | son = next_dom_son (CDI_POST_DOMINATORS, son)) | 
|  | { | 
|  | changed |= compute_antic_aux (son, | 
|  | TEST_BIT (has_abnormal_preds, son->index)); | 
|  | } | 
|  | return changed; | 
|  | } | 
|  |  | 
|  | /* Compute ANTIC sets.  */ | 
|  |  | 
|  | static void | 
|  | compute_antic (void) | 
|  | { | 
|  | bool changed = true; | 
|  | int num_iterations = 0; | 
|  | basic_block block; | 
|  |  | 
|  | /* If any predecessor edges are abnormal, we punt, so antic_in is empty. | 
|  | We pre-build the map of blocks with incoming abnormal edges here.  */ | 
|  | has_abnormal_preds = sbitmap_alloc (last_basic_block); | 
|  | sbitmap_zero (has_abnormal_preds); | 
|  | FOR_EACH_BB (block) | 
|  | { | 
|  | edge_iterator ei; | 
|  | edge e; | 
|  |  | 
|  | FOR_EACH_EDGE (e, ei, block->preds) | 
|  | if (e->flags & EDGE_ABNORMAL) | 
|  | { | 
|  | SET_BIT (has_abnormal_preds, block->index); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* While we are here, give empty ANTIC_IN sets to each block.  */ | 
|  | ANTIC_IN (block) = set_new (true); | 
|  | } | 
|  | /* At the exit block we anticipate nothing.  */ | 
|  | ANTIC_IN (EXIT_BLOCK_PTR) = set_new (true); | 
|  |  | 
|  | while (changed) | 
|  | { | 
|  | num_iterations++; | 
|  | changed = false; | 
|  | changed = compute_antic_aux (EXIT_BLOCK_PTR, false); | 
|  | } | 
|  |  | 
|  | sbitmap_free (has_abnormal_preds); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_STATS)) | 
|  | fprintf (dump_file, "compute_antic required %d iterations\n", num_iterations); | 
|  | } | 
|  |  | 
|  | /* Print the names represented by the bitmap NAMES, to the file OUT.  */ | 
|  | static void | 
|  | dump_bitmap_of_names (FILE *out, bitmap names) | 
|  | { | 
|  | bitmap_iterator bi; | 
|  | unsigned int i; | 
|  |  | 
|  | fprintf (out, " { "); | 
|  | EXECUTE_IF_SET_IN_BITMAP (names, 0, i, bi) | 
|  | { | 
|  | print_generic_expr (out, ssa_name (i), 0); | 
|  | fprintf (out, " "); | 
|  | } | 
|  | fprintf (out, "}\n"); | 
|  | } | 
|  |  | 
|  | /* Compute a set of representative vuse versions for each phi.  This | 
|  | is so we can compute conservative kill sets in terms of all vuses | 
|  | that are killed, instead of continually walking chains. | 
|  |  | 
|  | We also have to be able kill all names associated with a phi when | 
|  | the phi dies in order to ensure we don't generate overlapping | 
|  | live ranges, which are not allowed in virtual SSA.  */ | 
|  |  | 
|  | static bitmap *vuse_names; | 
|  | static void | 
|  | compute_vuse_representatives (void) | 
|  | { | 
|  | tree phi; | 
|  | basic_block bb; | 
|  | VEC (tree, heap) *phis = NULL; | 
|  | bool changed = true; | 
|  | size_t i; | 
|  |  | 
|  | FOR_EACH_BB (bb) | 
|  | { | 
|  | for (phi = phi_nodes (bb); | 
|  | phi; | 
|  | phi = PHI_CHAIN (phi)) | 
|  | if (!is_gimple_reg (PHI_RESULT (phi))) | 
|  | VEC_safe_push (tree, heap, phis, phi); | 
|  | } | 
|  |  | 
|  | while (changed) | 
|  | { | 
|  | changed = false; | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, phis, i, phi); i++) | 
|  | { | 
|  | size_t ver = SSA_NAME_VERSION (PHI_RESULT (phi)); | 
|  | use_operand_p usep; | 
|  | ssa_op_iter iter; | 
|  |  | 
|  | if (vuse_names[ver] == NULL) | 
|  | { | 
|  | vuse_names[ver] = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | bitmap_set_bit (vuse_names[ver], ver); | 
|  | } | 
|  | FOR_EACH_PHI_ARG (usep, phi, iter, SSA_OP_ALL_USES) | 
|  | { | 
|  | tree use = USE_FROM_PTR (usep); | 
|  | bitmap usebitmap = get_representative (vuse_names, | 
|  | SSA_NAME_VERSION (use)); | 
|  | if (usebitmap != NULL) | 
|  | { | 
|  | changed |= bitmap_ior_into (vuse_names[ver], | 
|  | usebitmap); | 
|  | } | 
|  | else | 
|  | { | 
|  | changed |= !bitmap_bit_p (vuse_names[ver], | 
|  | SSA_NAME_VERSION (use)); | 
|  | if (changed) | 
|  | bitmap_set_bit (vuse_names[ver], | 
|  | SSA_NAME_VERSION (use)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | for (i = 0; VEC_iterate (tree, phis, i, phi); i++) | 
|  | { | 
|  | bitmap reps = get_representative (vuse_names, | 
|  | SSA_NAME_VERSION (PHI_RESULT (phi))); | 
|  | if (reps) | 
|  | { | 
|  | print_generic_expr (dump_file, PHI_RESULT (phi), 0); | 
|  | fprintf (dump_file, " represents "); | 
|  | dump_bitmap_of_names (dump_file, reps); | 
|  | } | 
|  | } | 
|  | VEC_free (tree, heap, phis); | 
|  | } | 
|  |  | 
|  | /* Compute reaching vuses and antic safe loads.  RVUSE computation is | 
|  | is a small bit of iterative dataflow to determine what virtual uses | 
|  | reach what blocks.  Because we can't generate overlapping virtual | 
|  | uses, and virtual uses *do* actually die, this ends up being faster | 
|  | in most cases than continually walking the virtual use/def chains | 
|  | to determine whether we are inside a block where a given virtual is | 
|  | still available to be used. | 
|  |  | 
|  | ANTIC_SAFE_LOADS are those loads that actually occur before any kill to | 
|  | their vuses in the block,and thus, are safe at the top of the | 
|  | block. | 
|  |  | 
|  | An example: | 
|  |  | 
|  | <block begin> | 
|  | b = *a | 
|  | *a = 9 | 
|  | <block end> | 
|  |  | 
|  | b = *a is an antic safe load because it still safe to consider it | 
|  | ANTIC at the top of the block. | 
|  |  | 
|  | We currently compute a conservative approximation to | 
|  | ANTIC_SAFE_LOADS.  We compute those loads that occur before *any* | 
|  | stores in the block.  This is not because it is difficult to | 
|  | compute the precise answer, but because it is expensive.  More | 
|  | testing is necessary to determine whether it is worth computing the | 
|  | precise answer.  */ | 
|  |  | 
|  | static void | 
|  | compute_rvuse_and_antic_safe (void) | 
|  | { | 
|  |  | 
|  | size_t i; | 
|  | tree phi; | 
|  | basic_block bb; | 
|  | int *postorder; | 
|  | bool changed = true; | 
|  | unsigned int *first_store_uid; | 
|  |  | 
|  | first_store_uid = xcalloc (n_basic_blocks, sizeof (unsigned int)); | 
|  |  | 
|  | compute_vuse_representatives (); | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | { | 
|  | RVUSE_IN (bb) = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | RVUSE_GEN (bb) = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | RVUSE_KILL (bb) = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | RVUSE_OUT (bb) = BITMAP_ALLOC (&grand_bitmap_obstack); | 
|  | ANTIC_SAFE_LOADS (bb) = NULL; | 
|  | } | 
|  |  | 
|  | /* Mark live on entry */ | 
|  | for (i = 0; i < num_ssa_names; i++) | 
|  | { | 
|  | tree name = ssa_name (i); | 
|  | if (name && !is_gimple_reg (name) | 
|  | && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name))) | 
|  | bitmap_set_bit (RVUSE_OUT (ENTRY_BLOCK_PTR), | 
|  | SSA_NAME_VERSION (name)); | 
|  | } | 
|  |  | 
|  | /* Compute local sets for reaching vuses. | 
|  | GEN(block) = generated in block and not locally killed. | 
|  | KILL(block) = set of vuses killed in block. | 
|  | */ | 
|  |  | 
|  | FOR_EACH_BB (bb) | 
|  | { | 
|  | block_stmt_iterator bsi; | 
|  | ssa_op_iter iter; | 
|  | def_operand_p defp; | 
|  | use_operand_p usep; | 
|  |  | 
|  | for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) | 
|  | { | 
|  | tree stmt = bsi_stmt (bsi); | 
|  |  | 
|  | if (first_store_uid[bb->index] == 0 | 
|  | && !ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYUSE | SSA_OP_VMAYDEF | 
|  | | SSA_OP_VMUSTDEF | SSA_OP_VMUSTKILL)) | 
|  | { | 
|  | first_store_uid[bb->index] = stmt_ann (stmt)->uid; | 
|  | } | 
|  |  | 
|  |  | 
|  | FOR_EACH_SSA_USE_OPERAND (usep, stmt, iter, SSA_OP_VIRTUAL_KILLS | 
|  | | SSA_OP_VMAYUSE) | 
|  | { | 
|  | tree use = USE_FROM_PTR (usep); | 
|  | bitmap repbit = get_representative (vuse_names, | 
|  | SSA_NAME_VERSION (use)); | 
|  | if (repbit != NULL) | 
|  | { | 
|  | bitmap_and_compl_into (RVUSE_GEN (bb), repbit); | 
|  | bitmap_ior_into (RVUSE_KILL (bb), repbit); | 
|  | } | 
|  | else | 
|  | { | 
|  | bitmap_set_bit (RVUSE_KILL (bb), SSA_NAME_VERSION (use)); | 
|  | bitmap_clear_bit (RVUSE_GEN (bb), SSA_NAME_VERSION (use)); | 
|  | } | 
|  | } | 
|  | FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_VIRTUAL_DEFS) | 
|  | { | 
|  | tree def = DEF_FROM_PTR (defp); | 
|  | bitmap_set_bit (RVUSE_GEN (bb), SSA_NAME_VERSION (def)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | FOR_EACH_BB (bb) | 
|  | { | 
|  | for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) | 
|  | { | 
|  | if (!is_gimple_reg (PHI_RESULT (phi))) | 
|  | { | 
|  | edge e; | 
|  | edge_iterator ei; | 
|  |  | 
|  | tree def = PHI_RESULT (phi); | 
|  | /* In reality, the PHI result is generated at the end of | 
|  | each predecessor block.  This will make the value | 
|  | LVUSE_IN for the bb containing the PHI, which is | 
|  | correct.  */ | 
|  | FOR_EACH_EDGE (e, ei, bb->preds) | 
|  | bitmap_set_bit (RVUSE_GEN (e->src), SSA_NAME_VERSION (def)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Solve reaching vuses. | 
|  |  | 
|  | RVUSE_IN[BB] = Union of RVUSE_OUT of predecessors. | 
|  | RVUSE_OUT[BB] = RVUSE_GEN[BB] U (RVUSE_IN[BB] - RVUSE_KILL[BB]) | 
|  | */ | 
|  | postorder = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS); | 
|  | pre_and_rev_post_order_compute (NULL, postorder, false); | 
|  |  | 
|  | changed = true; | 
|  | while (changed) | 
|  | { | 
|  | int j; | 
|  | changed = false; | 
|  | for (j = 0; j < n_basic_blocks - NUM_FIXED_BLOCKS; j++) | 
|  | { | 
|  | edge e; | 
|  | edge_iterator ei; | 
|  | bb = BASIC_BLOCK (postorder[j]); | 
|  |  | 
|  | FOR_EACH_EDGE (e, ei, bb->preds) | 
|  | bitmap_ior_into (RVUSE_IN (bb), RVUSE_OUT (e->src)); | 
|  |  | 
|  | changed |= bitmap_ior_and_compl (RVUSE_OUT (bb), | 
|  | RVUSE_GEN (bb), | 
|  | RVUSE_IN (bb), | 
|  | RVUSE_KILL (bb)); | 
|  | } | 
|  | } | 
|  | free (postorder); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | FOR_ALL_BB (bb) | 
|  | { | 
|  | fprintf (dump_file, "RVUSE_IN (%d) =", bb->index); | 
|  | dump_bitmap_of_names (dump_file, RVUSE_IN (bb)); | 
|  |  | 
|  | fprintf (dump_file, "RVUSE_KILL (%d) =", bb->index); | 
|  | dump_bitmap_of_names (dump_file, RVUSE_KILL (bb)); | 
|  |  | 
|  | fprintf (dump_file, "RVUSE_GEN (%d) =", bb->index); | 
|  | dump_bitmap_of_names (dump_file, RVUSE_GEN (bb)); | 
|  |  | 
|  | fprintf (dump_file, "RVUSE_OUT (%d) =", bb->index); | 
|  | dump_bitmap_of_names (dump_file, RVUSE_OUT (bb)); | 
|  | } | 
|  | } | 
|  |  | 
|  | FOR_EACH_BB (bb) | 
|  | { | 
|  | value_set_node_t node; | 
|  | if (bitmap_empty_p (RVUSE_KILL (bb))) | 
|  | continue; | 
|  |  | 
|  | for (node = EXP_GEN (bb)->head; node; node = node->next) | 
|  | { | 
|  | if (REFERENCE_CLASS_P (node->expr)) | 
|  | { | 
|  | tree vh = get_value_handle (node->expr); | 
|  | tree maybe = bitmap_find_leader (AVAIL_OUT (bb), vh); | 
|  |  | 
|  | if (maybe) | 
|  | { | 
|  | tree def = SSA_NAME_DEF_STMT (maybe); | 
|  |  | 
|  | if (bb_for_stmt (def) != bb) | 
|  | continue; | 
|  |  | 
|  | if (TREE_CODE (def) == PHI_NODE | 
|  | || stmt_ann (def)->uid < first_store_uid[bb->index]) | 
|  | { | 
|  | if (ANTIC_SAFE_LOADS (bb) == NULL) | 
|  | ANTIC_SAFE_LOADS (bb) = set_new (true); | 
|  | value_insert_into_set (ANTIC_SAFE_LOADS (bb), | 
|  | node->expr); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | free (first_store_uid); | 
|  | } | 
|  |  | 
|  | /* Return true if we can value number the call in STMT.  This is true | 
|  | if we have a pure or constant call.  */ | 
|  |  | 
|  | static bool | 
|  | can_value_number_call (tree stmt) | 
|  | { | 
|  | tree call = get_call_expr_in (stmt); | 
|  |  | 
|  | if (call_expr_flags (call)  & (ECF_PURE | ECF_CONST)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Return true if OP is a tree which we can perform value numbering | 
|  | on.  */ | 
|  |  | 
|  | static bool | 
|  | can_value_number_operation (tree op) | 
|  | { | 
|  | return UNARY_CLASS_P (op) | 
|  | || BINARY_CLASS_P (op) | 
|  | || COMPARISON_CLASS_P (op) | 
|  | || REFERENCE_CLASS_P (op) | 
|  | || (TREE_CODE (op) == CALL_EXPR | 
|  | && can_value_number_call (op)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Return true if OP is a tree which we can perform PRE on | 
|  | on.  This may not match the operations we can value number, but in | 
|  | a perfect world would.  */ | 
|  |  | 
|  | static bool | 
|  | can_PRE_operation (tree op) | 
|  | { | 
|  | return UNARY_CLASS_P (op) | 
|  | || BINARY_CLASS_P (op) | 
|  | || COMPARISON_CLASS_P (op) | 
|  | || TREE_CODE (op) == INDIRECT_REF | 
|  | || TREE_CODE (op) == COMPONENT_REF | 
|  | || TREE_CODE (op) == CALL_EXPR | 
|  | || TREE_CODE (op) == ARRAY_REF; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Inserted expressions are placed onto this worklist, which is used | 
|  | for performing quick dead code elimination of insertions we made | 
|  | that didn't turn out to be necessary.   */ | 
|  | static VEC(tree,heap) *inserted_exprs; | 
|  |  | 
|  | /* Pool allocated fake store expressions are placed onto this | 
|  | worklist, which, after performing dead code elimination, is walked | 
|  | to see which expressions need to be put into GC'able memory  */ | 
|  | static VEC(tree, heap) *need_creation; | 
|  |  | 
|  | /* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the | 
|  | COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with | 
|  | trying to rename aggregates into ssa form directly, which is a no | 
|  | no. | 
|  |  | 
|  | Thus, this routine doesn't create temporaries, it just builds a | 
|  | single access expression for the array, calling | 
|  | find_or_generate_expression to build the innermost pieces. | 
|  |  | 
|  | This function is a subroutine of create_expression_by_pieces, and | 
|  | should not be called on it's own unless you really know what you | 
|  | are doing. | 
|  | */ | 
|  | static tree | 
|  | create_component_ref_by_pieces (basic_block block, tree expr, tree stmts) | 
|  | { | 
|  | tree genop = expr; | 
|  | tree folded; | 
|  |  | 
|  | if (TREE_CODE (genop) == VALUE_HANDLE) | 
|  | { | 
|  | tree found = bitmap_find_leader (AVAIL_OUT (block), expr); | 
|  | if (found) | 
|  | return found; | 
|  | } | 
|  |  | 
|  | if (TREE_CODE (genop) == VALUE_HANDLE) | 
|  | genop = VALUE_HANDLE_EXPR_SET (expr)->head->expr; | 
|  |  | 
|  | switch TREE_CODE (genop) | 
|  | { | 
|  | case ARRAY_REF: | 
|  | { | 
|  | tree op0; | 
|  | tree op1, op2, op3; | 
|  | op0 = create_component_ref_by_pieces (block, | 
|  | TREE_OPERAND (genop, 0), | 
|  | stmts); | 
|  | op1 = TREE_OPERAND (genop, 1); | 
|  | if (TREE_CODE (op1) == VALUE_HANDLE) | 
|  | op1 = find_or_generate_expression (block, op1, stmts); | 
|  | op2 = TREE_OPERAND (genop, 2); | 
|  | if (op2 && TREE_CODE (op2) == VALUE_HANDLE) | 
|  | op2 = find_or_generate_expression (block, op2, stmts); | 
|  | op3 = TREE_OPERAND (genop, 3); | 
|  | if (op3 && TREE_CODE (op3) == VALUE_HANDLE) | 
|  | op3 = find_or_generate_expression (block, op3, stmts); | 
|  | folded = build4 (ARRAY_REF, TREE_TYPE (genop), op0, op1, | 
|  | op2, op3); | 
|  | return folded; | 
|  | } | 
|  | case COMPONENT_REF: | 
|  | { | 
|  | tree op0; | 
|  | tree op1; | 
|  | op0 = create_component_ref_by_pieces (block, | 
|  | TREE_OPERAND (genop, 0), | 
|  | stmts); | 
|  | op1 = VALUE_HANDLE_EXPR_SET (TREE_OPERAND (genop, 1))->head->expr; | 
|  | folded = fold_build3 (COMPONENT_REF, TREE_TYPE (genop), op0, op1, | 
|  | NULL_TREE); | 
|  | return folded; | 
|  | } | 
|  | break; | 
|  | case INDIRECT_REF: | 
|  | { | 
|  | tree op1 = TREE_OPERAND (genop, 0); | 
|  | tree genop1 = find_or_generate_expression (block, op1, stmts); | 
|  |  | 
|  | folded = fold_build1 (TREE_CODE (genop), TREE_TYPE (genop), | 
|  | genop1); | 
|  | return folded; | 
|  | } | 
|  | break; | 
|  | case VAR_DECL: | 
|  | case PARM_DECL: | 
|  | case RESULT_DECL: | 
|  | case SSA_NAME: | 
|  | case STRING_CST: | 
|  | return genop; | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  |  | 
|  | return NULL_TREE; | 
|  | } | 
|  |  | 
|  | /* Find a leader for an expression, or generate one using | 
|  | create_expression_by_pieces if it's ANTIC but | 
|  | complex. | 
|  | BLOCK is the basic_block we are looking for leaders in. | 
|  | EXPR is the expression to find a leader or generate for. | 
|  | STMTS is the statement list to put the inserted expressions on. | 
|  | Returns the SSA_NAME of the LHS of the generated expression or the | 
|  | leader.  */ | 
|  |  | 
|  | static tree | 
|  | find_or_generate_expression (basic_block block, tree expr, tree stmts) | 
|  | { | 
|  | tree genop = bitmap_find_leader (AVAIL_OUT (block), expr); | 
|  |  | 
|  | /* If it's still NULL, it must be a complex expression, so generate | 
|  | it recursively.  */ | 
|  | if (genop == NULL) | 
|  | { | 
|  | genop = VALUE_HANDLE_EXPR_SET (expr)->head->expr; | 
|  |  | 
|  | gcc_assert (can_PRE_operation (genop)); | 
|  | genop = create_expression_by_pieces (block, genop, stmts); | 
|  | } | 
|  | return genop; | 
|  | } | 
|  |  | 
|  | #define NECESSARY(stmt)		stmt->common.asm_written_flag | 
|  | /* Create an expression in pieces, so that we can handle very complex | 
|  | expressions that may be ANTIC, but not necessary GIMPLE. | 
|  | BLOCK is the basic block the expression will be inserted into, | 
|  | EXPR is the expression to insert (in value form) | 
|  | STMTS is a statement list to append the necessary insertions into. | 
|  |  | 
|  | This function will die if we hit some value that shouldn't be | 
|  | ANTIC but is (IE there is no leader for it, or its components). | 
|  | This function may also generate expressions that are themselves | 
|  | partially or fully redundant.  Those that are will be either made | 
|  | fully redundant during the next iteration of insert (for partially | 
|  | redundant ones), or eliminated by eliminate (for fully redundant | 
|  | ones).  */ | 
|  |  | 
|  | static tree | 
|  | create_expression_by_pieces (basic_block block, tree expr, tree stmts) | 
|  | { | 
|  | tree temp, name; | 
|  | tree folded, forced_stmts, newexpr; | 
|  | tree v; | 
|  | tree_stmt_iterator tsi; | 
|  |  | 
|  | switch (TREE_CODE_CLASS (TREE_CODE (expr))) | 
|  | { | 
|  | case tcc_expression: | 
|  | { | 
|  | tree op0, op2; | 
|  | tree arglist; | 
|  | tree genop0, genop2; | 
|  | tree genarglist; | 
|  | tree walker, genwalker; | 
|  |  | 
|  | gcc_assert (TREE_CODE (expr) == CALL_EXPR); | 
|  | genop2 = NULL; | 
|  |  | 
|  | op0 = TREE_OPERAND (expr, 0); | 
|  | arglist = TREE_OPERAND (expr, 1); | 
|  | op2 = TREE_OPERAND (expr, 2); | 
|  |  | 
|  | genop0 = find_or_generate_expression (block, op0, stmts); | 
|  | genarglist = copy_list (arglist); | 
|  | for (walker = arglist, genwalker = genarglist; | 
|  | genwalker && walker; | 
|  | genwalker = TREE_CHAIN (genwalker), walker = TREE_CHAIN (walker)) | 
|  | { | 
|  | TREE_VALUE (genwalker) | 
|  | = find_or_generate_expression (block, TREE_VALUE (walker), | 
|  | stmts); | 
|  | } | 
|  |  | 
|  | if (op2) | 
|  | genop2 = find_or_generate_expression (block, op2, stmts); | 
|  | folded = fold_build3 (TREE_CODE (expr), TREE_TYPE (expr), | 
|  | genop0, genarglist, genop2); | 
|  | break; | 
|  |  | 
|  |  | 
|  | } | 
|  | break; | 
|  | case tcc_reference: | 
|  | { | 
|  | if (TREE_CODE (expr) == COMPONENT_REF | 
|  | || TREE_CODE (expr) == ARRAY_REF) | 
|  | { | 
|  | folded = create_component_ref_by_pieces (block, expr, stmts); | 
|  | } | 
|  | else | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 0); | 
|  | tree genop1 = find_or_generate_expression (block, op1, stmts); | 
|  |  | 
|  | folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), | 
|  | genop1); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case tcc_binary: | 
|  | case tcc_comparison: | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 0); | 
|  | tree op2 = TREE_OPERAND (expr, 1); | 
|  | tree genop1 = find_or_generate_expression (block, op1, stmts); | 
|  | tree genop2 = find_or_generate_expression (block, op2, stmts); | 
|  | folded = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr), | 
|  | genop1, genop2); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case tcc_unary: | 
|  | { | 
|  | tree op1 = TREE_OPERAND (expr, 0); | 
|  | tree genop1 = find_or_generate_expression (block, op1, stmts); | 
|  | folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), | 
|  | genop1); | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  |  | 
|  | /* Force the generated expression to be a sequence of GIMPLE | 
|  | statements. | 
|  | We have to call unshare_expr because force_gimple_operand may | 
|  | modify the tree we pass to it.  */ | 
|  | newexpr = force_gimple_operand (unshare_expr (folded), &forced_stmts, | 
|  | false, NULL); | 
|  |  | 
|  | /* If we have any intermediate expressions to the value sets, add them | 
|  | to the value sets and chain them on in the instruction stream.  */ | 
|  | if (forced_stmts) | 
|  | { | 
|  | tsi = tsi_start (forced_stmts); | 
|  | for (; !tsi_end_p (tsi); tsi_next (&tsi)) | 
|  | { | 
|  | tree stmt = tsi_stmt (tsi); | 
|  | tree forcedname = TREE_OPERAND (stmt, 0); | 
|  | tree forcedexpr = TREE_OPERAND (stmt, 1); | 
|  | tree val = vn_lookup_or_add (forcedexpr, NULL); | 
|  |  | 
|  | VEC_safe_push (tree, heap, inserted_exprs, stmt); | 
|  | vn_add (forcedname, val); | 
|  | bitmap_value_replace_in_set (NEW_SETS (block), forcedname); | 
|  | bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname); | 
|  | mark_new_vars_to_rename (stmt); | 
|  | } | 
|  | tsi = tsi_last (stmts); | 
|  | tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING); | 
|  | } | 
|  |  | 
|  | /* Build and insert the assignment of the end result to the temporary | 
|  | that we will return.  */ | 
|  | if (!pretemp || TREE_TYPE (expr) != TREE_TYPE (pretemp)) | 
|  | { | 
|  | pretemp = create_tmp_var (TREE_TYPE (expr), "pretmp"); | 
|  | get_var_ann (pretemp); | 
|  | } | 
|  |  | 
|  | temp = pretemp; | 
|  | add_referenced_var (temp); | 
|  |  | 
|  | if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) | 
|  | DECL_COMPLEX_GIMPLE_REG_P (temp) = 1; | 
|  |  | 
|  | newexpr = build2 (MODIFY_EXPR, TREE_TYPE (expr), temp, newexpr); | 
|  | name = make_ssa_name (temp, newexpr); | 
|  | TREE_OPERAND (newexpr, 0) = name; | 
|  | NECESSARY (newexpr) = 0; | 
|  |  | 
|  | tsi = tsi_last (stmts); | 
|  | tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING); | 
|  | VEC_safe_push (tree, heap, inserted_exprs, newexpr); | 
|  | mark_new_vars_to_rename (newexpr); | 
|  |  | 
|  | /* Add a value handle to the temporary. | 
|  | The value may already exist in either NEW_SETS, or AVAIL_OUT, because | 
|  | we are creating the expression by pieces, and this particular piece of | 
|  | the expression may have been represented.  There is no harm in replacing | 
|  | here.  */ | 
|  | v = get_value_handle (expr); | 
|  | vn_add (name, v); | 
|  | bitmap_value_replace_in_set (NEW_SETS (block), name); | 
|  | bitmap_value_replace_in_set (AVAIL_OUT (block), name); | 
|  |  | 
|  | pre_stats.insertions++; | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Inserted "); | 
|  | print_generic_expr (dump_file, newexpr, 0); | 
|  | fprintf (dump_file, " in predecessor %d\n", block->index); | 
|  | } | 
|  |  | 
|  | return name; | 
|  | } | 
|  |  | 
|  | /* Insert the to-be-made-available values of NODE for each | 
|  | predecessor, stored in AVAIL, into the predecessors of BLOCK, and | 
|  | merge the result with a phi node, given the same value handle as | 
|  | NODE.  Return true if we have inserted new stuff.  */ | 
|  |  | 
|  | static bool | 
|  | insert_into_preds_of_block (basic_block block, value_set_node_t node, | 
|  | tree *avail) | 
|  | { | 
|  | tree val = get_value_handle (node->expr); | 
|  | edge pred; | 
|  | bool insertions = false; | 
|  | bool nophi = false; | 
|  | basic_block bprime; | 
|  | tree eprime; | 
|  | edge_iterator ei; | 
|  | tree type = TREE_TYPE (avail[EDGE_PRED (block, 0)->src->index]); | 
|  | tree temp; | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Found partial redundancy for expression "); | 
|  | print_generic_expr (dump_file, node->expr, 0); | 
|  | fprintf (dump_file, " ("); | 
|  | print_generic_expr (dump_file, val, 0); | 
|  | fprintf (dump_file, ")"); | 
|  | fprintf (dump_file, "\n"); | 
|  | } | 
|  |  | 
|  | /* Make sure we aren't creating an induction variable.  */ | 
|  | if (block->loop_depth > 0 && EDGE_COUNT (block->preds) == 2 | 
|  | && TREE_CODE_CLASS (TREE_CODE (node->expr)) != tcc_reference ) | 
|  | { | 
|  | bool firstinsideloop = false; | 
|  | bool secondinsideloop = false; | 
|  | firstinsideloop = flow_bb_inside_loop_p (block->loop_father, | 
|  | EDGE_PRED (block, 0)->src); | 
|  | secondinsideloop = flow_bb_inside_loop_p (block->loop_father, | 
|  | EDGE_PRED (block, 1)->src); | 
|  | /* Induction variables only have one edge inside the loop.  */ | 
|  | if (firstinsideloop ^ secondinsideloop) | 
|  | { | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | fprintf (dump_file, "Skipping insertion of phi for partial redundancy: Looks like an induction variable\n"); | 
|  | nophi = true; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Make the necessary insertions.  */ | 
|  | FOR_EACH_EDGE (pred, ei, block->preds) | 
|  | { | 
|  | tree stmts = alloc_stmt_list (); | 
|  | tree builtexpr; | 
|  | bprime = pred->src; | 
|  | eprime = avail[bprime->index]; | 
|  |  | 
|  | if (can_PRE_operation (eprime)) | 
|  | { | 
|  | #ifdef ENABLE_CHECKING | 
|  | tree vh; | 
|  |  | 
|  | /* eprime may be an invariant.  */ | 
|  | vh = TREE_CODE (eprime) == VALUE_HANDLE | 
|  | ? eprime | 
|  | : get_value_handle (eprime); | 
|  |  | 
|  | /* ensure that the virtual uses we need reach our block.  */ | 
|  | if (TREE_CODE (vh) == VALUE_HANDLE) | 
|  | { | 
|  | int i; | 
|  | tree vuse; | 
|  | for (i = 0; | 
|  | VEC_iterate (tree, VALUE_HANDLE_VUSES (vh), i, vuse); | 
|  | i++) | 
|  | { | 
|  | size_t id = SSA_NAME_VERSION (vuse); | 
|  | gcc_assert (bitmap_bit_p (RVUSE_OUT (bprime), id) | 
|  | || IS_EMPTY_STMT (SSA_NAME_DEF_STMT (vuse))); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | builtexpr = create_expression_by_pieces (bprime, | 
|  | eprime, | 
|  | stmts); | 
|  | bsi_insert_on_edge (pred, stmts); | 
|  | avail[bprime->index] = builtexpr; | 
|  | insertions = true; | 
|  | } | 
|  | } | 
|  | /* If we didn't want a phi node, and we made insertions, we still have | 
|  | inserted new stuff, and thus return true.  If we didn't want a phi node, | 
|  | and didn't make insertions, we haven't added anything new, so return | 
|  | false.  */ | 
|  | if (nophi && insertions) | 
|  | return true; | 
|  | else if (nophi && !insertions) | 
|  | return false; | 
|  |  | 
|  | /* Now build a phi for the new variable.  */ | 
|  | if (!prephitemp || TREE_TYPE (prephitemp) != type) | 
|  | { | 
|  | prephitemp = create_tmp_var (type, "prephitmp"); | 
|  | get_var_ann (prephitemp); | 
|  | } | 
|  |  | 
|  | temp = prephitemp; | 
|  | add_referenced_var (temp); | 
|  |  | 
|  | if (TREE_CODE (type) == COMPLEX_TYPE) | 
|  | DECL_COMPLEX_GIMPLE_REG_P (temp) = 1; | 
|  | temp = create_phi_node (temp, block); | 
|  |  | 
|  | NECESSARY (temp) = 0; | 
|  | VEC_safe_push (tree, heap, inserted_exprs, temp); | 
|  | FOR_EACH_EDGE (pred, ei, block->preds) | 
|  | add_phi_arg (temp, avail[pred->src->index], pred); | 
|  |  | 
|  | vn_add (PHI_RESULT (temp), val); | 
|  |  | 
|  | /* The value should *not* exist in PHI_GEN, or else we wouldn't be doing | 
|  | this insertion, since we test for the existence of this value in PHI_GEN | 
|  | before proceeding with the partial redundancy checks in insert_aux. | 
|  |  | 
|  | The value may exist in AVAIL_OUT, in particular, it could be represented | 
|  | by the expression we are trying to eliminate, in which case we want the | 
|  | replacement to occur.  If it's not existing in AVAIL_OUT, we want it | 
|  | inserted there. | 
|  |  | 
|  | Similarly, to the PHI_GEN case, the value should not exist in NEW_SETS of | 
|  | this block, because if it did, it would have existed in our dominator's | 
|  | AVAIL_OUT, and would have been skipped due to the full redundancy check. | 
|  | */ | 
|  |  | 
|  | bitmap_insert_into_set (PHI_GEN (block), | 
|  | PHI_RESULT (temp)); | 
|  | bitmap_value_replace_in_set (AVAIL_OUT (block), | 
|  | PHI_RESULT (temp)); | 
|  | bitmap_insert_into_set (NEW_SETS (block), | 
|  | PHI_RESULT (temp)); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Created phi "); | 
|  | print_generic_expr (dump_file, temp, 0); | 
|  | fprintf (dump_file, " in block %d\n", block->index); | 
|  | } | 
|  | pre_stats.phis++; | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Perform insertion of partially redundant values. | 
|  | For BLOCK, do the following: | 
|  | 1.  Propagate the NEW_SETS of the dominator into the current block. | 
|  | If the block has multiple predecessors, | 
|  | 2a. Iterate over the ANTIC expressions for the block to see if | 
|  | any of them are partially redundant. | 
|  | 2b. If so, insert them into the necessary predecessors to make | 
|  | the expression fully redundant. | 
|  | 2c. Insert a new PHI merging the values of the predecessors. | 
|  | 2d. Insert the new PHI, and the new expressions, into the | 
|  | NEW_SETS set. | 
|  | 3. Recursively call ourselves on the dominator children of BLOCK. | 
|  |  | 
|  | */ | 
|  |  | 
|  | static bool | 
|  | insert_aux (basic_block block) | 
|  | { | 
|  | basic_block son; | 
|  | bool new_stuff = false; | 
|  |  | 
|  | if (block) | 
|  | { | 
|  | basic_block dom; | 
|  | dom = get_immediate_dominator (CDI_DOMINATORS, block); | 
|  | if (dom) | 
|  | { | 
|  | unsigned i; | 
|  | bitmap_iterator bi; | 
|  | bitmap_set_t newset = NEW_SETS (dom); | 
|  | if (newset) | 
|  | { | 
|  | /* Note that we need to value_replace both NEW_SETS, and | 
|  | AVAIL_OUT. For both the case of NEW_SETS, the value may be | 
|  | represented by some non-simple expression here that we want | 
|  | to replace it with.  */ | 
|  | EXECUTE_IF_SET_IN_BITMAP (newset->expressions, 0, i, bi) | 
|  | { | 
|  | bitmap_value_replace_in_set (NEW_SETS (block), ssa_name (i)); | 
|  | bitmap_value_replace_in_set (AVAIL_OUT (block), ssa_name (i)); | 
|  | } | 
|  | } | 
|  | if (!single_pred_p (block)) | 
|  | { | 
|  | value_set_node_t node; | 
|  | for (node = ANTIC_IN (block)->head; | 
|  | node; | 
|  | node = node->next) | 
|  | { | 
|  | if (can_PRE_operation (node->expr) | 
|  | && !AGGREGATE_TYPE_P (TREE_TYPE (node->expr))) | 
|  | { | 
|  | tree *avail; | 
|  | tree val; | 
|  | bool by_some = false; | 
|  | bool cant_insert = false; | 
|  | bool all_same = true; | 
|  | tree first_s = NULL; | 
|  | edge pred; | 
|  | basic_block bprime; | 
|  | tree eprime = NULL_TREE; | 
|  | edge_iterator ei; | 
|  |  | 
|  | val = get_value_handle (node->expr); | 
|  | if (bitmap_set_contains_value (PHI_GEN (block), val)) | 
|  | continue; | 
|  | if (bitmap_set_contains_value (AVAIL_OUT (dom), val)) | 
|  | { | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | fprintf (dump_file, "Found fully redundant value\n"); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | avail = XCNEWVEC (tree, last_basic_block); | 
|  | FOR_EACH_EDGE (pred, ei, block->preds) | 
|  | { | 
|  | tree vprime; | 
|  | tree edoubleprime; | 
|  |  | 
|  | /* This can happen in the very weird case | 
|  | that our fake infinite loop edges have caused a | 
|  | critical edge to appear.  */ | 
|  | if (EDGE_CRITICAL_P (pred)) | 
|  | { | 
|  | cant_insert = true; | 
|  | break; | 
|  | } | 
|  | bprime = pred->src; | 
|  | eprime = phi_translate (node->expr, | 
|  | ANTIC_IN (block), | 
|  | bprime, block); | 
|  |  | 
|  | /* eprime will generally only be NULL if the | 
|  | value of the expression, translated | 
|  | through the PHI for this predecessor, is | 
|  | undefined.  If that is the case, we can't | 
|  | make the expression fully redundant, | 
|  | because its value is undefined along a | 
|  | predecessor path.  We can thus break out | 
|  | early because it doesn't matter what the | 
|  | rest of the results are.  */ | 
|  | if (eprime == NULL) | 
|  | { | 
|  | cant_insert = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | eprime = fully_constant_expression (eprime); | 
|  | vprime = get_value_handle (eprime); | 
|  | gcc_assert (vprime); | 
|  | edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime), | 
|  | vprime); | 
|  | if (edoubleprime == NULL) | 
|  | { | 
|  | avail[bprime->index] = eprime; | 
|  | all_same = false; | 
|  | } | 
|  | else | 
|  | { | 
|  | avail[bprime->index] = edoubleprime; | 
|  | by_some = true; | 
|  | if (first_s == NULL) | 
|  | first_s = edoubleprime; | 
|  | else if (!operand_equal_p (first_s, edoubleprime, | 
|  | 0)) | 
|  | all_same = false; | 
|  | } | 
|  | } | 
|  | /* If we can insert it, it's not the same value | 
|  | already existing along every predecessor, and | 
|  | it's defined by some predecessor, it is | 
|  | partially redundant.  */ | 
|  | if (!cant_insert && !all_same && by_some) | 
|  | { | 
|  | if (insert_into_preds_of_block (block, node, avail)) | 
|  | new_stuff = true; | 
|  | } | 
|  | /* If all edges produce the same value and that value is | 
|  | an invariant, then the PHI has the same value on all | 
|  | edges.  Note this.  */ | 
|  | else if (!cant_insert && all_same && eprime | 
|  | && is_gimple_min_invariant (eprime) | 
|  | && !is_gimple_min_invariant (val)) | 
|  | { | 
|  | value_set_t exprset = VALUE_HANDLE_EXPR_SET (val); | 
|  | value_set_node_t node; | 
|  |  | 
|  | for (node = exprset->head; node; node = node->next) | 
|  | { | 
|  | if (TREE_CODE (node->expr) == SSA_NAME) | 
|  | { | 
|  | vn_add (node->expr, eprime); | 
|  | pre_stats.constified++; | 
|  | } | 
|  | } | 
|  | } | 
|  | free (avail); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | for (son = first_dom_son (CDI_DOMINATORS, block); | 
|  | son; | 
|  | son = next_dom_son (CDI_DOMINATORS, son)) | 
|  | { | 
|  | new_stuff |= insert_aux (son); | 
|  | } | 
|  |  | 
|  | return new_stuff; | 
|  | } | 
|  |  | 
|  | /* Perform insertion of partially redundant values.  */ | 
|  |  | 
|  | static void | 
|  | insert (void) | 
|  | { | 
|  | bool new_stuff = true; | 
|  | basic_block bb; | 
|  | int num_iterations = 0; | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | NEW_SETS (bb) = bitmap_set_new (); | 
|  |  | 
|  | while (new_stuff) | 
|  | { | 
|  | num_iterations++; | 
|  | new_stuff = false; | 
|  | new_stuff = insert_aux (ENTRY_BLOCK_PTR); | 
|  | } | 
|  | if (num_iterations > 2 && dump_file && (dump_flags & TDF_STATS)) | 
|  | fprintf (dump_file, "insert required %d iterations\n", num_iterations); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Return true if VAR is an SSA variable with no defining statement in | 
|  | this procedure, *AND* isn't a live-on-entry parameter.  */ | 
|  |  | 
|  | static bool | 
|  | is_undefined_value (tree expr) | 
|  | { | 
|  | return (TREE_CODE (expr) == SSA_NAME | 
|  | && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (expr)) | 
|  | /* PARM_DECLs and hard registers are always defined.  */ | 
|  | && TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Given an SSA variable VAR and an expression EXPR, compute the value | 
|  | number for EXPR and create a value handle (VAL) for it.  If VAR and | 
|  | EXPR are not the same, associate VAL with VAR.  Finally, add VAR to | 
|  | S1 and its value handle to S2. | 
|  |  | 
|  | VUSES represent the virtual use operands associated with EXPR (if | 
|  | any).  */ | 
|  |  | 
|  | static inline void | 
|  | add_to_sets (tree var, tree expr, tree stmt, bitmap_set_t s1, | 
|  | bitmap_set_t s2) | 
|  | { | 
|  | tree val = vn_lookup_or_add (expr, stmt); | 
|  |  | 
|  | /* VAR and EXPR may be the same when processing statements for which | 
|  | we are not computing value numbers (e.g., non-assignments, or | 
|  | statements that make aliased stores).  In those cases, we are | 
|  | only interested in making VAR available as its own value.  */ | 
|  | if (var != expr) | 
|  | vn_add (var, val); | 
|  |  | 
|  | if (s1) | 
|  | bitmap_insert_into_set (s1, var); | 
|  | bitmap_value_insert_into_set (s2, var); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Given a unary or binary expression EXPR, create and return a new | 
|  | expression with the same structure as EXPR but with its operands | 
|  | replaced with the value handles of each of the operands of EXPR. | 
|  |  | 
|  | VUSES represent the virtual use operands associated with EXPR (if | 
|  | any). Insert EXPR's operands into the EXP_GEN set for BLOCK. */ | 
|  |  | 
|  | static inline tree | 
|  | create_value_expr_from (tree expr, basic_block block, tree stmt) | 
|  | { | 
|  | int i; | 
|  | enum tree_code code = TREE_CODE (expr); | 
|  | tree vexpr; | 
|  | alloc_pool pool; | 
|  |  | 
|  | gcc_assert (TREE_CODE_CLASS (code) == tcc_unary | 
|  | || TREE_CODE_CLASS (code) == tcc_binary | 
|  | || TREE_CODE_CLASS (code) == tcc_comparison | 
|  | || TREE_CODE_CLASS (code) == tcc_reference | 
|  | || TREE_CODE_CLASS (code) == tcc_expression | 
|  | || TREE_CODE_CLASS (code) == tcc_exceptional | 
|  | || TREE_CODE_CLASS (code) == tcc_declaration); | 
|  |  | 
|  | if (TREE_CODE_CLASS (code) == tcc_unary) | 
|  | pool = unary_node_pool; | 
|  | else if (TREE_CODE_CLASS (code) == tcc_reference) | 
|  | pool = reference_node_pool; | 
|  | else if (TREE_CODE_CLASS (code) == tcc_binary) | 
|  | pool = binary_node_pool; | 
|  | else if (TREE_CODE_CLASS (code) == tcc_comparison) | 
|  | pool = comparison_node_pool; | 
|  | else if (TREE_CODE_CLASS (code) == tcc_exceptional) | 
|  | { | 
|  | gcc_assert (code == TREE_LIST); | 
|  | pool = list_node_pool; | 
|  | } | 
|  | else | 
|  | { | 
|  | gcc_assert (code == CALL_EXPR); | 
|  | pool = expression_node_pool; | 
|  | } | 
|  |  | 
|  | vexpr = (tree) pool_alloc (pool); | 
|  | memcpy (vexpr, expr, tree_size (expr)); | 
|  |  | 
|  | /* This case is only for TREE_LIST's that appear as part of | 
|  | CALL_EXPR's.  Anything else is a bug, but we can't easily verify | 
|  | this, hence this comment.  TREE_LIST is not handled by the | 
|  | general case below is because they don't have a fixed length, or | 
|  | operands, so you can't access purpose/value/chain through | 
|  | TREE_OPERAND macros.  */ | 
|  |  | 
|  | if (code == TREE_LIST) | 
|  | { | 
|  | tree op = NULL_TREE; | 
|  | tree temp = NULL_TREE; | 
|  | if (TREE_CHAIN (vexpr)) | 
|  | temp = create_value_expr_from (TREE_CHAIN (vexpr), block, stmt); | 
|  | TREE_CHAIN (vexpr) = temp ? temp : TREE_CHAIN (vexpr); | 
|  |  | 
|  |  | 
|  | /* Recursively value-numberize reference ops.  */ | 
|  | if (REFERENCE_CLASS_P (TREE_VALUE (vexpr))) | 
|  | { | 
|  | tree tempop; | 
|  | op = TREE_VALUE (vexpr); | 
|  | tempop = create_value_expr_from (op, block, stmt); | 
|  | op = tempop ? tempop : op; | 
|  |  | 
|  | TREE_VALUE (vexpr)  = vn_lookup_or_add (op, stmt); | 
|  | } | 
|  | else | 
|  | { | 
|  | op = TREE_VALUE (vexpr); | 
|  | TREE_VALUE (vexpr) = vn_lookup_or_add (TREE_VALUE (vexpr), NULL); | 
|  | } | 
|  | /* This is the equivalent of inserting op into EXP_GEN like we | 
|  | do below */ | 
|  | if (!is_undefined_value (op)) | 
|  | value_insert_into_set (EXP_GEN (block), op); | 
|  |  | 
|  | return vexpr; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < TREE_CODE_LENGTH (code); i++) | 
|  | { | 
|  | tree val, op; | 
|  |  | 
|  | op = TREE_OPERAND (expr, i); | 
|  | if (op == NULL_TREE) | 
|  | continue; | 
|  |  | 
|  | /* Recursively value-numberize reference ops and tree lists.  */ | 
|  | if (REFERENCE_CLASS_P (op)) | 
|  | { | 
|  | tree tempop = create_value_expr_from (op, block, stmt); | 
|  | op = tempop ? tempop : op; | 
|  | val = vn_lookup_or_add (op, stmt); | 
|  | } | 
|  | else if (TREE_CODE (op) == TREE_LIST) | 
|  | { | 
|  | tree tempop; | 
|  |  | 
|  | gcc_assert (TREE_CODE (expr) == CALL_EXPR); | 
|  | tempop = create_value_expr_from (op, block, stmt); | 
|  |  | 
|  | op = tempop ? tempop : op; | 
|  | vn_lookup_or_add (op, NULL); | 
|  | /* Unlike everywhere else, we do *not* want to replace the | 
|  | TREE_LIST itself with a value number, because support | 
|  | functions we call will blow up.  */ | 
|  | val = op; | 
|  | } | 
|  | else | 
|  | /* Create a value handle for OP and add it to VEXPR.  */ | 
|  | val = vn_lookup_or_add (op, NULL); | 
|  |  | 
|  | if (!is_undefined_value (op) && TREE_CODE (op) != TREE_LIST) | 
|  | value_insert_into_set (EXP_GEN (block), op); | 
|  |  | 
|  | if (TREE_CODE (val) == VALUE_HANDLE) | 
|  | TREE_TYPE (val) = TREE_TYPE (TREE_OPERAND (vexpr, i)); | 
|  |  | 
|  | TREE_OPERAND (vexpr, i) = val; | 
|  | } | 
|  |  | 
|  | return vexpr; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Insert extra phis to merge values that are fully available from | 
|  | preds of BLOCK, but have no dominating representative coming from | 
|  | block DOM.   */ | 
|  |  | 
|  | static void | 
|  | insert_extra_phis (basic_block block, basic_block dom) | 
|  | { | 
|  |  | 
|  | if (!single_pred_p (block)) | 
|  | { | 
|  | edge e; | 
|  | edge_iterator ei; | 
|  | bool first = true; | 
|  | bitmap_set_t tempset = bitmap_set_new (); | 
|  |  | 
|  | FOR_EACH_EDGE (e, ei, block->preds) | 
|  | { | 
|  | /* We cannot handle abnormal incoming edges correctly.  */ | 
|  | if (e->flags & EDGE_ABNORMAL) | 
|  | return; | 
|  |  | 
|  | if (first) | 
|  | { | 
|  | bitmap_set_copy (tempset, AVAIL_OUT (e->src)); | 
|  | first = false; | 
|  | } | 
|  | else | 
|  | bitmap_set_and (tempset, AVAIL_OUT (e->src)); | 
|  | } | 
|  |  | 
|  | if (dom) | 
|  | bitmap_set_and_compl (tempset, AVAIL_OUT (dom)); | 
|  |  | 
|  | if (!bitmap_set_empty_p (tempset)) | 
|  | { | 
|  | unsigned int i; | 
|  | bitmap_iterator bi; | 
|  |  | 
|  | EXECUTE_IF_SET_IN_BITMAP (tempset->expressions, 0, i, bi) | 
|  | { | 
|  | tree name = ssa_name (i); | 
|  | tree val = get_value_handle (name); | 
|  | tree temp; | 
|  |  | 
|  | if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)) | 
|  | continue; | 
|  |  | 
|  | if (!mergephitemp | 
|  | || TREE_TYPE (name) != TREE_TYPE (mergephitemp)) | 
|  | { | 
|  | mergephitemp = create_tmp_var (TREE_TYPE (name), | 
|  | "mergephitmp"); | 
|  | get_var_ann (mergephitemp); | 
|  | } | 
|  | temp = mergephitemp; | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Creating phi "); | 
|  | print_generic_expr (dump_file, temp, 0); | 
|  | fprintf (dump_file, " to merge available but not dominating values "); | 
|  | } | 
|  |  | 
|  | add_referenced_var (temp); | 
|  | temp = create_phi_node (temp, block); | 
|  | NECESSARY (temp) = 0; | 
|  | VEC_safe_push (tree, heap, inserted_exprs, temp); | 
|  |  | 
|  | FOR_EACH_EDGE (e, ei, block->preds) | 
|  | { | 
|  | tree leader = bitmap_find_leader (AVAIL_OUT (e->src), val); | 
|  |  | 
|  | gcc_assert (leader); | 
|  | add_phi_arg (temp, leader, e); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | print_generic_expr (dump_file, leader, 0); | 
|  | fprintf (dump_file, " in block %d,", e->src->index); | 
|  | } | 
|  | } | 
|  |  | 
|  | vn_add (PHI_RESULT (temp), val); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | fprintf (dump_file, "\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Given a statement STMT and its right hand side which is a load, try | 
|  | to look for the expression stored in the location for the load, and | 
|  | return true if a useful equivalence was recorded for LHS.  */ | 
|  |  | 
|  | static bool | 
|  | try_look_through_load (tree lhs, tree mem_ref, tree stmt, basic_block block) | 
|  | { | 
|  | tree store_stmt = NULL; | 
|  | tree rhs; | 
|  | ssa_op_iter i; | 
|  | tree vuse; | 
|  |  | 
|  | FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, i, SSA_OP_VIRTUAL_USES) | 
|  | { | 
|  | tree def_stmt; | 
|  |  | 
|  | gcc_assert (TREE_CODE (vuse) == SSA_NAME); | 
|  | def_stmt = SSA_NAME_DEF_STMT (vuse); | 
|  |  | 
|  | /* If there is no useful statement for this VUSE, we'll not find a | 
|  | useful expression to return either.  Likewise, if there is a | 
|  | statement but it is not a simple assignment or it has virtual | 
|  | uses, we can stop right here.  Note that this means we do | 
|  | not look through PHI nodes, which is intentional.  */ | 
|  | if (!def_stmt | 
|  | || TREE_CODE (def_stmt) != MODIFY_EXPR | 
|  | || !ZERO_SSA_OPERANDS (def_stmt, SSA_OP_VIRTUAL_USES)) | 
|  | return false; | 
|  |  | 
|  | /* If this is not the same statement as one we have looked at for | 
|  | another VUSE of STMT already, we have two statements producing | 
|  | something that reaches our STMT.  */ | 
|  | if (store_stmt && store_stmt != def_stmt) | 
|  | return false; | 
|  | else | 
|  | { | 
|  | /* Is this a store to the exact same location as the one we are | 
|  | loading from in STMT?  */ | 
|  | if (!operand_equal_p (TREE_OPERAND (def_stmt, 0), mem_ref, 0)) | 
|  | return false; | 
|  |  | 
|  | /* Otherwise remember this statement and see if all other VUSEs | 
|  | come from the same statement.  */ | 
|  | store_stmt = def_stmt; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Alright then, we have visited all VUSEs of STMT and we've determined | 
|  | that all of them come from the same statement STORE_STMT.  See if there | 
|  | is a useful expression we can deduce from STORE_STMT.  */ | 
|  | rhs = TREE_OPERAND (store_stmt, 1); | 
|  | if ((TREE_CODE (rhs) == SSA_NAME | 
|  | && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs)) | 
|  | || is_gimple_min_invariant (rhs) | 
|  | || TREE_CODE (rhs) == ADDR_EXPR | 
|  | || TREE_INVARIANT (rhs)) | 
|  | { | 
|  |  | 
|  | /* Yay!  Compute a value number for the RHS of the statement and | 
|  | add its value to the AVAIL_OUT set for the block.  Add the LHS | 
|  | to TMP_GEN.  */ | 
|  | add_to_sets (lhs, rhs, store_stmt, TMP_GEN (block), AVAIL_OUT (block)); | 
|  | if (TREE_CODE (rhs) == SSA_NAME | 
|  | && !is_undefined_value (rhs)) | 
|  | value_insert_into_set (EXP_GEN (block), rhs); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Return a copy of NODE that is stored in the temporary alloc_pool's. | 
|  | This is made recursively true, so that the operands are stored in | 
|  | the pool as well.  */ | 
|  |  | 
|  | static tree | 
|  | poolify_tree (tree node) | 
|  | { | 
|  | switch  (TREE_CODE (node)) | 
|  | { | 
|  | case INDIRECT_REF: | 
|  | { | 
|  | tree temp = pool_alloc (reference_node_pool); | 
|  | memcpy (temp, node, tree_size (node)); | 
|  | TREE_OPERAND (temp, 0) = poolify_tree (TREE_OPERAND (temp, 0)); | 
|  | return temp; | 
|  | } | 
|  | break; | 
|  | case MODIFY_EXPR: | 
|  | { | 
|  | tree temp = pool_alloc (modify_expr_node_pool); | 
|  | memcpy (temp, node, tree_size (node)); | 
|  | TREE_OPERAND (temp, 0) = poolify_tree (TREE_OPERAND (temp, 0)); | 
|  | TREE_OPERAND (temp, 1) = poolify_tree (TREE_OPERAND (temp, 1)); | 
|  | return temp; | 
|  | } | 
|  | break; | 
|  | case SSA_NAME: | 
|  | case INTEGER_CST: | 
|  | case STRING_CST: | 
|  | case REAL_CST: | 
|  | case PARM_DECL: | 
|  | case VAR_DECL: | 
|  | case RESULT_DECL: | 
|  | return node; | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  | } | 
|  |  | 
|  | static tree modify_expr_template; | 
|  |  | 
|  | /* Allocate a MODIFY_EXPR with TYPE, and operands OP1, OP2 in the | 
|  | alloc pools and return it.  */ | 
|  | static tree | 
|  | poolify_modify_expr (tree type, tree op1, tree op2) | 
|  | { | 
|  | if (modify_expr_template == NULL) | 
|  | modify_expr_template = build2 (MODIFY_EXPR, type, op1, op2); | 
|  |  | 
|  | TREE_OPERAND (modify_expr_template, 0) = op1; | 
|  | TREE_OPERAND (modify_expr_template, 1) = op2; | 
|  | TREE_TYPE (modify_expr_template) = type; | 
|  |  | 
|  | return poolify_tree (modify_expr_template); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* For each real store operation of the form | 
|  | *a = <value> that we see, create a corresponding fake store of the | 
|  | form storetmp_<version> = *a. | 
|  |  | 
|  | This enables AVAIL computation to mark the results of stores as | 
|  | available.  Without this, you'd need to do some computation to | 
|  | mark the result of stores as ANTIC and AVAIL at all the right | 
|  | points. | 
|  | To save memory, we keep the store | 
|  | statements pool allocated until we decide whether they are | 
|  | necessary or not.  */ | 
|  |  | 
|  | static void | 
|  | insert_fake_stores (void) | 
|  | { | 
|  | basic_block block; | 
|  |  | 
|  | FOR_ALL_BB (block) | 
|  | { | 
|  | block_stmt_iterator bsi; | 
|  | for (bsi = bsi_start (block); !bsi_end_p (bsi); bsi_next (&bsi)) | 
|  | { | 
|  | tree stmt = bsi_stmt (bsi); | 
|  |  | 
|  | /* We can't generate SSA names for stores that are complex | 
|  | or aggregate.  We also want to ignore things whose | 
|  | virtual uses occur in abnormal phis.  */ | 
|  |  | 
|  | if (TREE_CODE (stmt) == MODIFY_EXPR | 
|  | && TREE_CODE (TREE_OPERAND (stmt, 0)) == INDIRECT_REF | 
|  | && !AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0))) | 
|  | && TREE_CODE (TREE_TYPE (TREE_OPERAND (stmt, 0))) != COMPLEX_TYPE) | 
|  | { | 
|  | ssa_op_iter iter; | 
|  | def_operand_p defp; | 
|  | tree lhs = TREE_OPERAND (stmt, 0); | 
|  | tree rhs = TREE_OPERAND (stmt, 1); | 
|  | tree new; | 
|  | bool notokay = false; | 
|  |  | 
|  | FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_VIRTUAL_DEFS) | 
|  | { | 
|  | tree defvar = DEF_FROM_PTR (defp); | 
|  | if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (defvar)) | 
|  | { | 
|  | notokay = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (notokay) | 
|  | continue; | 
|  |  | 
|  | if (!storetemp || TREE_TYPE (rhs) != TREE_TYPE (storetemp)) | 
|  | { | 
|  | storetemp = create_tmp_var (TREE_TYPE (rhs), "storetmp"); | 
|  | get_var_ann (storetemp); | 
|  | } | 
|  |  | 
|  | new = poolify_modify_expr (TREE_TYPE (stmt), storetemp, lhs); | 
|  |  | 
|  | lhs = make_ssa_name (storetemp, new); | 
|  | TREE_OPERAND (new, 0) = lhs; | 
|  | create_ssa_artficial_load_stmt (new, stmt); | 
|  |  | 
|  | NECESSARY (new) = 0; | 
|  | VEC_safe_push (tree, heap, inserted_exprs, new); | 
|  | VEC_safe_push (tree, heap, need_creation, new); | 
|  | bsi_insert_after (&bsi, new, BSI_NEW_STMT); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Turn the pool allocated fake stores that we created back into real | 
|  | GC allocated ones if they turned out to be necessary to PRE some | 
|  | expressions.  */ | 
|  |  | 
|  | static void | 
|  | realify_fake_stores (void) | 
|  | { | 
|  | unsigned int i; | 
|  | tree stmt; | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, need_creation, i, stmt); i++) | 
|  | { | 
|  | if (NECESSARY (stmt)) | 
|  | { | 
|  | block_stmt_iterator bsi; | 
|  | tree newstmt; | 
|  |  | 
|  | /* Mark the temp variable as referenced */ | 
|  | add_referenced_var (SSA_NAME_VAR (TREE_OPERAND (stmt, 0))); | 
|  |  | 
|  | /* Put the new statement in GC memory, fix up the | 
|  | SSA_NAME_DEF_STMT on it, and then put it in place of | 
|  | the old statement before the store in the IR stream | 
|  | as a plain ssa name copy.  */ | 
|  | bsi = bsi_for_stmt (stmt); | 
|  | bsi_prev (&bsi); | 
|  | newstmt = build2 (MODIFY_EXPR, void_type_node, | 
|  | TREE_OPERAND (stmt, 0), | 
|  | TREE_OPERAND (bsi_stmt (bsi), 1)); | 
|  | SSA_NAME_DEF_STMT (TREE_OPERAND (newstmt, 0)) = newstmt; | 
|  | bsi_insert_before (&bsi, newstmt, BSI_SAME_STMT); | 
|  | bsi = bsi_for_stmt (stmt); | 
|  | bsi_remove (&bsi, true); | 
|  | } | 
|  | else | 
|  | release_defs (stmt); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Tree-combine a value number expression *EXPR_P that does a type | 
|  | conversion with the value number expression of its operand. | 
|  | Returns true, if *EXPR_P simplifies to a value number or | 
|  | gimple min-invariant expression different from EXPR_P and | 
|  | sets *EXPR_P to the simplified expression value number. | 
|  | Otherwise returns false and does not change *EXPR_P.  */ | 
|  |  | 
|  | static bool | 
|  | try_combine_conversion (tree *expr_p) | 
|  | { | 
|  | tree expr = *expr_p; | 
|  | tree t; | 
|  |  | 
|  | if (!((TREE_CODE (expr) == NOP_EXPR | 
|  | || TREE_CODE (expr) == CONVERT_EXPR) | 
|  | && TREE_CODE (TREE_OPERAND (expr, 0)) == VALUE_HANDLE | 
|  | && !VALUE_HANDLE_VUSES (TREE_OPERAND (expr, 0)))) | 
|  | return false; | 
|  |  | 
|  | t = fold_unary (TREE_CODE (expr), TREE_TYPE (expr), | 
|  | VALUE_HANDLE_EXPR_SET (TREE_OPERAND (expr, 0))->head->expr); | 
|  | if (!t) | 
|  | return false; | 
|  |  | 
|  | /* Strip useless type conversions, which is safe in the optimizers but | 
|  | not generally in fold.  */ | 
|  | STRIP_USELESS_TYPE_CONVERSION (t); | 
|  |  | 
|  | /* Disallow value expressions we have no value number for already, as | 
|  | we would miss a leader for it here.  */ | 
|  | if (!(TREE_CODE (t) == VALUE_HANDLE | 
|  | || is_gimple_min_invariant (t))) | 
|  | t = vn_lookup (t, NULL); | 
|  |  | 
|  | if (t && t != expr) | 
|  | { | 
|  | *expr_p = t; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /* Compute the AVAIL set for all basic blocks. | 
|  |  | 
|  | This function performs value numbering of the statements in each basic | 
|  | block.  The AVAIL sets are built from information we glean while doing | 
|  | this value numbering, since the AVAIL sets contain only one entry per | 
|  | value. | 
|  |  | 
|  | AVAIL_IN[BLOCK] = AVAIL_OUT[dom(BLOCK)]. | 
|  | AVAIL_OUT[BLOCK] = AVAIL_IN[BLOCK] U PHI_GEN[BLOCK] U TMP_GEN[BLOCK].  */ | 
|  |  | 
|  | static void | 
|  | compute_avail (void) | 
|  | { | 
|  | basic_block block, son; | 
|  | basic_block *worklist; | 
|  | size_t sp = 0; | 
|  | tree param; | 
|  | /* For arguments with default definitions, we pretend they are | 
|  | defined in the entry block.  */ | 
|  | for (param = DECL_ARGUMENTS (current_function_decl); | 
|  | param; | 
|  | param = TREE_CHAIN (param)) | 
|  | { | 
|  | if (default_def (param) != NULL) | 
|  | { | 
|  | tree def = default_def (param); | 
|  | vn_lookup_or_add (def, NULL); | 
|  | bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), def); | 
|  | bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), def); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Likewise for the static chain decl. */ | 
|  | if (cfun->static_chain_decl) | 
|  | { | 
|  | param = cfun->static_chain_decl; | 
|  | if (default_def (param) != NULL) | 
|  | { | 
|  | tree def = default_def (param); | 
|  | vn_lookup_or_add (def, NULL); | 
|  | bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), def); | 
|  | bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), def); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Allocate the worklist.  */ | 
|  | worklist = XNEWVEC (basic_block, n_basic_blocks); | 
|  |  | 
|  | /* Seed the algorithm by putting the dominator children of the entry | 
|  | block on the worklist.  */ | 
|  | for (son = first_dom_son (CDI_DOMINATORS, ENTRY_BLOCK_PTR); | 
|  | son; | 
|  | son = next_dom_son (CDI_DOMINATORS, son)) | 
|  | worklist[sp++] = son; | 
|  |  | 
|  | /* Loop until the worklist is empty.  */ | 
|  | while (sp) | 
|  | { | 
|  | block_stmt_iterator bsi; | 
|  | tree stmt, phi; | 
|  | basic_block dom; | 
|  | unsigned int stmt_uid = 1; | 
|  |  | 
|  | /* Pick a block from the worklist.  */ | 
|  | block = worklist[--sp]; | 
|  |  | 
|  | /* Initially, the set of available values in BLOCK is that of | 
|  | its immediate dominator.  */ | 
|  | dom = get_immediate_dominator (CDI_DOMINATORS, block); | 
|  | if (dom) | 
|  | bitmap_set_copy (AVAIL_OUT (block), AVAIL_OUT (dom)); | 
|  |  | 
|  | if (!in_fre) | 
|  | insert_extra_phis (block, dom); | 
|  |  | 
|  | /* Generate values for PHI nodes.  */ | 
|  | for (phi = phi_nodes (block); phi; phi = PHI_CHAIN (phi)) | 
|  | /* We have no need for virtual phis, as they don't represent | 
|  | actual computations.  */ | 
|  | if (is_gimple_reg (PHI_RESULT (phi))) | 
|  | add_to_sets (PHI_RESULT (phi), PHI_RESULT (phi), NULL, | 
|  | PHI_GEN (block), AVAIL_OUT (block)); | 
|  |  | 
|  | /* Now compute value numbers and populate value sets with all | 
|  | the expressions computed in BLOCK.  */ | 
|  | for (bsi = bsi_start (block); !bsi_end_p (bsi); bsi_next (&bsi)) | 
|  | { | 
|  | stmt_ann_t ann; | 
|  | ssa_op_iter iter; | 
|  | tree op; | 
|  |  | 
|  | stmt = bsi_stmt (bsi); | 
|  | ann = stmt_ann (stmt); | 
|  |  | 
|  | ann->uid = stmt_uid++; | 
|  |  | 
|  | /* For regular value numbering, we are only interested in | 
|  | assignments of the form X_i = EXPR, where EXPR represents | 
|  | an "interesting" computation, it has no volatile operands | 
|  | and X_i doesn't flow through an abnormal edge.  */ | 
|  | if (TREE_CODE (stmt) == MODIFY_EXPR | 
|  | && !ann->has_volatile_ops | 
|  | && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME | 
|  | && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (stmt, 0))) | 
|  | { | 
|  | tree lhs = TREE_OPERAND (stmt, 0); | 
|  | tree rhs = TREE_OPERAND (stmt, 1); | 
|  |  | 
|  | /* Try to look through loads.  */ | 
|  | if (TREE_CODE (lhs) == SSA_NAME | 
|  | && !ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_USES) | 
|  | && try_look_through_load (lhs, rhs, stmt, block)) | 
|  | continue; | 
|  |  | 
|  | STRIP_USELESS_TYPE_CONVERSION (rhs); | 
|  | if (can_value_number_operation (rhs)) | 
|  | { | 
|  | /* For value numberable operation, create a | 
|  | duplicate expression with the operands replaced | 
|  | with the value handles of the original RHS.  */ | 
|  | tree newt = create_value_expr_from (rhs, block, stmt); | 
|  | if (newt) | 
|  | { | 
|  | /* If we can combine a conversion expression | 
|  | with the expression for its operand just | 
|  | record the value number for it.  */ | 
|  | if (try_combine_conversion (&newt)) | 
|  | vn_add (lhs, newt); | 
|  | else | 
|  | { | 
|  | tree val = vn_lookup_or_add (newt, stmt); | 
|  | vn_add (lhs, val); | 
|  | value_insert_into_set (EXP_GEN (block), newt); | 
|  | } | 
|  | bitmap_insert_into_set (TMP_GEN (block), lhs); | 
|  | bitmap_value_insert_into_set (AVAIL_OUT (block), lhs); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | else if ((TREE_CODE (rhs) == SSA_NAME | 
|  | && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs)) | 
|  | || is_gimple_min_invariant (rhs) | 
|  | || TREE_CODE (rhs) == ADDR_EXPR | 
|  | || TREE_INVARIANT (rhs) | 
|  | || DECL_P (rhs)) | 
|  | { | 
|  | /* Compute a value number for the RHS of the statement | 
|  | and add its value to the AVAIL_OUT set for the block. | 
|  | Add the LHS to TMP_GEN.  */ | 
|  | add_to_sets (lhs, rhs, stmt, TMP_GEN (block), | 
|  | AVAIL_OUT (block)); | 
|  |  | 
|  | if (TREE_CODE (rhs) == SSA_NAME | 
|  | && !is_undefined_value (rhs)) | 
|  | value_insert_into_set (EXP_GEN (block), rhs); | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* For any other statement that we don't recognize, simply | 
|  | make the names generated by the statement available in | 
|  | AVAIL_OUT and TMP_GEN.  */ | 
|  | FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF) | 
|  | add_to_sets (op, op, NULL, TMP_GEN (block), AVAIL_OUT (block)); | 
|  |  | 
|  | FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) | 
|  | add_to_sets (op, op, NULL, NULL , AVAIL_OUT (block)); | 
|  | } | 
|  |  | 
|  | /* Put the dominator children of BLOCK on the worklist of blocks | 
|  | to compute available sets for.  */ | 
|  | for (son = first_dom_son (CDI_DOMINATORS, block); | 
|  | son; | 
|  | son = next_dom_son (CDI_DOMINATORS, son)) | 
|  | worklist[sp++] = son; | 
|  | } | 
|  |  | 
|  | free (worklist); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Eliminate fully redundant computations.  */ | 
|  |  | 
|  | static void | 
|  | eliminate (void) | 
|  | { | 
|  | basic_block b; | 
|  |  | 
|  | FOR_EACH_BB (b) | 
|  | { | 
|  | block_stmt_iterator i; | 
|  |  | 
|  | for (i = bsi_start (b); !bsi_end_p (i); bsi_next (&i)) | 
|  | { | 
|  | tree stmt = bsi_stmt (i); | 
|  |  | 
|  | /* Lookup the RHS of the expression, see if we have an | 
|  | available computation for it.  If so, replace the RHS with | 
|  | the available computation.  */ | 
|  | if (TREE_CODE (stmt) == MODIFY_EXPR | 
|  | && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME | 
|  | && TREE_CODE (TREE_OPERAND (stmt ,1)) != SSA_NAME | 
|  | && !is_gimple_min_invariant (TREE_OPERAND (stmt, 1)) | 
|  | && !stmt_ann (stmt)->has_volatile_ops) | 
|  | { | 
|  | tree lhs = TREE_OPERAND (stmt, 0); | 
|  | tree *rhs_p = &TREE_OPERAND (stmt, 1); | 
|  | tree sprime; | 
|  |  | 
|  | sprime = bitmap_find_leader (AVAIL_OUT (b), | 
|  | vn_lookup (lhs, NULL)); | 
|  | if (sprime | 
|  | && sprime != lhs | 
|  | && (TREE_CODE (*rhs_p) != SSA_NAME | 
|  | || may_propagate_copy (*rhs_p, sprime))) | 
|  | { | 
|  | gcc_assert (sprime != *rhs_p); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Replaced "); | 
|  | print_generic_expr (dump_file, *rhs_p, 0); | 
|  | fprintf (dump_file, " with "); | 
|  | print_generic_expr (dump_file, sprime, 0); | 
|  | fprintf (dump_file, " in "); | 
|  | print_generic_stmt (dump_file, stmt, 0); | 
|  | } | 
|  |  | 
|  | if (TREE_CODE (sprime) == SSA_NAME) | 
|  | NECESSARY (SSA_NAME_DEF_STMT (sprime)) = 1; | 
|  | /* We need to make sure the new and old types actually match, | 
|  | which may require adding a simple cast, which fold_convert | 
|  | will do for us.  */ | 
|  | if (TREE_CODE (*rhs_p) != SSA_NAME | 
|  | && !tree_ssa_useless_type_conversion_1 (TREE_TYPE (*rhs_p), | 
|  | TREE_TYPE (sprime))) | 
|  | sprime = fold_convert (TREE_TYPE (*rhs_p), sprime); | 
|  |  | 
|  | pre_stats.eliminations++; | 
|  | propagate_tree_value (rhs_p, sprime); | 
|  | update_stmt (stmt); | 
|  |  | 
|  | /* If we removed EH side effects from the statement, clean | 
|  | its EH information.  */ | 
|  | if (maybe_clean_or_replace_eh_stmt (stmt, stmt)) | 
|  | { | 
|  | bitmap_set_bit (need_eh_cleanup, | 
|  | bb_for_stmt (stmt)->index); | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | fprintf (dump_file, "  Removed EH side effects.\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Borrow a bit of tree-ssa-dce.c for the moment. | 
|  | XXX: In 4.1, we should be able to just run a DCE pass after PRE, though | 
|  | this may be a bit faster, and we may want critical edges kept split.  */ | 
|  |  | 
|  | /* If OP's defining statement has not already been determined to be necessary, | 
|  | mark that statement necessary. Return the stmt, if it is newly | 
|  | necessary.  */ | 
|  |  | 
|  | static inline tree | 
|  | mark_operand_necessary (tree op) | 
|  | { | 
|  | tree stmt; | 
|  |  | 
|  | gcc_assert (op); | 
|  |  | 
|  | if (TREE_CODE (op) != SSA_NAME) | 
|  | return NULL; | 
|  |  | 
|  | stmt = SSA_NAME_DEF_STMT (op); | 
|  | gcc_assert (stmt); | 
|  |  | 
|  | if (NECESSARY (stmt) | 
|  | || IS_EMPTY_STMT (stmt)) | 
|  | return NULL; | 
|  |  | 
|  | NECESSARY (stmt) = 1; | 
|  | return stmt; | 
|  | } | 
|  |  | 
|  | /* Because we don't follow exactly the standard PRE algorithm, and decide not | 
|  | to insert PHI nodes sometimes, and because value numbering of casts isn't | 
|  | perfect, we sometimes end up inserting dead code.   This simple DCE-like | 
|  | pass removes any insertions we made that weren't actually used.  */ | 
|  |  | 
|  | static void | 
|  | remove_dead_inserted_code (void) | 
|  | { | 
|  | VEC(tree,heap) *worklist = NULL; | 
|  | int i; | 
|  | tree t; | 
|  |  | 
|  | worklist = VEC_alloc (tree, heap, VEC_length (tree, inserted_exprs)); | 
|  | for (i = 0; VEC_iterate (tree, inserted_exprs, i, t); i++) | 
|  | { | 
|  | if (NECESSARY (t)) | 
|  | VEC_quick_push (tree, worklist, t); | 
|  | } | 
|  | while (VEC_length (tree, worklist) > 0) | 
|  | { | 
|  | t = VEC_pop (tree, worklist); | 
|  |  | 
|  | /* PHI nodes are somewhat special in that each PHI alternative has | 
|  | data and control dependencies.  All the statements feeding the | 
|  | PHI node's arguments are always necessary. */ | 
|  | if (TREE_CODE (t) == PHI_NODE) | 
|  | { | 
|  | int k; | 
|  |  | 
|  | VEC_reserve (tree, heap, worklist, PHI_NUM_ARGS (t)); | 
|  | for (k = 0; k < PHI_NUM_ARGS (t); k++) | 
|  | { | 
|  | tree arg = PHI_ARG_DEF (t, k); | 
|  | if (TREE_CODE (arg) == SSA_NAME) | 
|  | { | 
|  | arg = mark_operand_necessary (arg); | 
|  | if (arg) | 
|  | VEC_quick_push (tree, worklist, arg); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Propagate through the operands.  Examine all the USE, VUSE and | 
|  | V_MAY_DEF operands in this statement.  Mark all the statements | 
|  | which feed this statement's uses as necessary.  */ | 
|  | ssa_op_iter iter; | 
|  | tree use; | 
|  |  | 
|  | /* The operands of V_MAY_DEF expressions are also needed as they | 
|  | represent potential definitions that may reach this | 
|  | statement (V_MAY_DEF operands allow us to follow def-def | 
|  | links).  */ | 
|  |  | 
|  | FOR_EACH_SSA_TREE_OPERAND (use, t, iter, SSA_OP_ALL_USES) | 
|  | { | 
|  | tree n = mark_operand_necessary (use); | 
|  | if (n) | 
|  | VEC_safe_push (tree, heap, worklist, n); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = 0; VEC_iterate (tree, inserted_exprs, i, t); i++) | 
|  | { | 
|  | if (!NECESSARY (t)) | 
|  | { | 
|  | block_stmt_iterator bsi; | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | fprintf (dump_file, "Removing unnecessary insertion:"); | 
|  | print_generic_stmt (dump_file, t, 0); | 
|  | } | 
|  |  | 
|  | if (TREE_CODE (t) == PHI_NODE) | 
|  | { | 
|  | remove_phi_node (t, NULL); | 
|  | } | 
|  | else | 
|  | { | 
|  | bsi = bsi_for_stmt (t); | 
|  | bsi_remove (&bsi, true); | 
|  | release_defs (t); | 
|  | } | 
|  | } | 
|  | } | 
|  | VEC_free (tree, heap, worklist); | 
|  | } | 
|  |  | 
|  | /* Initialize data structures used by PRE.  */ | 
|  |  | 
|  | static void | 
|  | init_pre (bool do_fre) | 
|  | { | 
|  | basic_block bb; | 
|  |  | 
|  | in_fre = do_fre; | 
|  |  | 
|  | inserted_exprs = NULL; | 
|  | need_creation = NULL; | 
|  | pretemp = NULL_TREE; | 
|  | storetemp = NULL_TREE; | 
|  | mergephitemp = NULL_TREE; | 
|  | prephitemp = NULL_TREE; | 
|  |  | 
|  | vn_init (); | 
|  | if (!do_fre) | 
|  | current_loops = loop_optimizer_init (LOOPS_NORMAL); | 
|  |  | 
|  | connect_infinite_loops_to_exit (); | 
|  | memset (&pre_stats, 0, sizeof (pre_stats)); | 
|  |  | 
|  | /* If block 0 has more than one predecessor, it means that its PHI | 
|  | nodes will have arguments coming from block -1.  This creates | 
|  | problems for several places in PRE that keep local arrays indexed | 
|  | by block number.  To prevent this, we split the edge coming from | 
|  | ENTRY_BLOCK_PTR (FIXME, if ENTRY_BLOCK_PTR had an index number | 
|  | different than -1 we wouldn't have to hack this.  tree-ssa-dce.c | 
|  | needs a similar change).  */ | 
|  | if (!single_pred_p (single_succ (ENTRY_BLOCK_PTR))) | 
|  | if (!(single_succ_edge (ENTRY_BLOCK_PTR)->flags & EDGE_ABNORMAL)) | 
|  | split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | bb->aux = xcalloc (1, sizeof (struct bb_value_sets)); | 
|  |  | 
|  | bitmap_obstack_initialize (&grand_bitmap_obstack); | 
|  | phi_translate_table = htab_create (511, expr_pred_trans_hash, | 
|  | expr_pred_trans_eq, free); | 
|  | value_set_pool = create_alloc_pool ("Value sets", | 
|  | sizeof (struct value_set), 30); | 
|  | bitmap_set_pool = create_alloc_pool ("Bitmap sets", | 
|  | sizeof (struct bitmap_set), 30); | 
|  | value_set_node_pool = create_alloc_pool ("Value set nodes", | 
|  | sizeof (struct value_set_node), 30); | 
|  | calculate_dominance_info (CDI_POST_DOMINATORS); | 
|  | calculate_dominance_info (CDI_DOMINATORS); | 
|  | binary_node_pool = create_alloc_pool ("Binary tree nodes", | 
|  | tree_code_size (PLUS_EXPR), 30); | 
|  | unary_node_pool = create_alloc_pool ("Unary tree nodes", | 
|  | tree_code_size (NEGATE_EXPR), 30); | 
|  | reference_node_pool = create_alloc_pool ("Reference tree nodes", | 
|  | tree_code_size (ARRAY_REF), 30); | 
|  | expression_node_pool = create_alloc_pool ("Expression tree nodes", | 
|  | tree_code_size (CALL_EXPR), 30); | 
|  | list_node_pool = create_alloc_pool ("List tree nodes", | 
|  | tree_code_size (TREE_LIST), 30); | 
|  | comparison_node_pool = create_alloc_pool ("Comparison tree nodes", | 
|  | tree_code_size (EQ_EXPR), 30); | 
|  | modify_expr_node_pool = create_alloc_pool ("MODIFY_EXPR nodes", | 
|  | tree_code_size (MODIFY_EXPR), | 
|  | 30); | 
|  | modify_expr_template = NULL; | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | { | 
|  | EXP_GEN (bb) = set_new (true); | 
|  | PHI_GEN (bb) = bitmap_set_new (); | 
|  | TMP_GEN (bb) = bitmap_set_new (); | 
|  | AVAIL_OUT (bb) = bitmap_set_new (); | 
|  | } | 
|  |  | 
|  | need_eh_cleanup = BITMAP_ALLOC (NULL); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Deallocate data structures used by PRE.  */ | 
|  |  | 
|  | static void | 
|  | fini_pre (bool do_fre) | 
|  | { | 
|  | basic_block bb; | 
|  | unsigned int i; | 
|  |  | 
|  | VEC_free (tree, heap, inserted_exprs); | 
|  | VEC_free (tree, heap, need_creation); | 
|  | bitmap_obstack_release (&grand_bitmap_obstack); | 
|  | free_alloc_pool (value_set_pool); | 
|  | free_alloc_pool (bitmap_set_pool); | 
|  | free_alloc_pool (value_set_node_pool); | 
|  | free_alloc_pool (binary_node_pool); | 
|  | free_alloc_pool (reference_node_pool); | 
|  | free_alloc_pool (unary_node_pool); | 
|  | free_alloc_pool (list_node_pool); | 
|  | free_alloc_pool (expression_node_pool); | 
|  | free_alloc_pool (comparison_node_pool); | 
|  | free_alloc_pool (modify_expr_node_pool); | 
|  | htab_delete (phi_translate_table); | 
|  | remove_fake_exit_edges (); | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | { | 
|  | free (bb->aux); | 
|  | bb->aux = NULL; | 
|  | } | 
|  |  | 
|  | free_dominance_info (CDI_POST_DOMINATORS); | 
|  | vn_delete (); | 
|  |  | 
|  | if (!bitmap_empty_p (need_eh_cleanup)) | 
|  | { | 
|  | tree_purge_all_dead_eh_edges (need_eh_cleanup); | 
|  | cleanup_tree_cfg (); | 
|  | } | 
|  |  | 
|  | BITMAP_FREE (need_eh_cleanup); | 
|  |  | 
|  | /* Wipe out pointers to VALUE_HANDLEs.  In the not terribly distant | 
|  | future we will want them to be persistent though.  */ | 
|  | for (i = 0; i < num_ssa_names; i++) | 
|  | { | 
|  | tree name = ssa_name (i); | 
|  |  | 
|  | if (!name) | 
|  | continue; | 
|  |  | 
|  | if (SSA_NAME_VALUE (name) | 
|  | && TREE_CODE (SSA_NAME_VALUE (name)) == VALUE_HANDLE) | 
|  | SSA_NAME_VALUE (name) = NULL; | 
|  | } | 
|  | if (!do_fre && current_loops) | 
|  | { | 
|  | loop_optimizer_finalize (current_loops); | 
|  | current_loops = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Main entry point to the SSA-PRE pass.  DO_FRE is true if the caller | 
|  | only wants to do full redundancy elimination.  */ | 
|  |  | 
|  | static void | 
|  | execute_pre (bool do_fre) | 
|  | { | 
|  | init_pre (do_fre); | 
|  |  | 
|  | if (!do_fre) | 
|  | insert_fake_stores (); | 
|  |  | 
|  | /* Collect and value number expressions computed in each basic block.  */ | 
|  | compute_avail (); | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_DETAILS)) | 
|  | { | 
|  | basic_block bb; | 
|  |  | 
|  | FOR_ALL_BB (bb) | 
|  | { | 
|  | print_value_set (dump_file, EXP_GEN (bb), "exp_gen", bb->index); | 
|  | bitmap_print_value_set (dump_file, TMP_GEN (bb), "tmp_gen", | 
|  | bb->index); | 
|  | bitmap_print_value_set (dump_file, AVAIL_OUT (bb), "avail_out", | 
|  | bb->index); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Insert can get quite slow on an incredibly large number of basic | 
|  | blocks due to some quadratic behavior.  Until this behavior is | 
|  | fixed, don't run it when he have an incredibly large number of | 
|  | bb's.  If we aren't going to run insert, there is no point in | 
|  | computing ANTIC, either, even though it's plenty fast.  */ | 
|  | if (!do_fre && n_basic_blocks < 4000) | 
|  | { | 
|  | vuse_names = XCNEWVEC (bitmap, num_ssa_names); | 
|  | compute_rvuse_and_antic_safe (); | 
|  | compute_antic (); | 
|  | insert (); | 
|  | free (vuse_names); | 
|  | } | 
|  |  | 
|  | /* Remove all the redundant expressions.  */ | 
|  | eliminate (); | 
|  |  | 
|  |  | 
|  | if (dump_file && (dump_flags & TDF_STATS)) | 
|  | { | 
|  | fprintf (dump_file, "Insertions: %d\n", pre_stats.insertions); | 
|  | fprintf (dump_file, "New PHIs: %d\n", pre_stats.phis); | 
|  | fprintf (dump_file, "Eliminated: %d\n", pre_stats.eliminations); | 
|  | fprintf (dump_file, "Constified: %d\n", pre_stats.constified); | 
|  | } | 
|  |  | 
|  | bsi_commit_edge_inserts (); | 
|  |  | 
|  | if (!do_fre) | 
|  | { | 
|  | remove_dead_inserted_code (); | 
|  | realify_fake_stores (); | 
|  | } | 
|  |  | 
|  | fini_pre (do_fre); | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Gate and execute functions for PRE.  */ | 
|  |  | 
|  | static unsigned int | 
|  | do_pre (void) | 
|  | { | 
|  | execute_pre (false); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | gate_pre (void) | 
|  | { | 
|  | return flag_tree_pre != 0; | 
|  | } | 
|  |  | 
|  | struct tree_opt_pass pass_pre = | 
|  | { | 
|  | "pre",				/* name */ | 
|  | gate_pre,				/* gate */ | 
|  | do_pre,				/* execute */ | 
|  | NULL,					/* sub */ | 
|  | NULL,					/* next */ | 
|  | 0,					/* static_pass_number */ | 
|  | TV_TREE_PRE,				/* tv_id */ | 
|  | PROP_no_crit_edges | PROP_cfg | 
|  | | PROP_ssa | PROP_alias,		/* properties_required */ | 
|  | 0,					/* properties_provided */ | 
|  | 0,					/* properties_destroyed */ | 
|  | 0,					/* todo_flags_start */ | 
|  | TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect | 
|  | | TODO_verify_ssa, /* todo_flags_finish */ | 
|  | 0					/* letter */ | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Gate and execute functions for FRE.  */ | 
|  |  | 
|  | static unsigned int | 
|  | execute_fre (void) | 
|  | { | 
|  | execute_pre (true); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | gate_fre (void) | 
|  | { | 
|  | return flag_tree_fre != 0; | 
|  | } | 
|  |  | 
|  | struct tree_opt_pass pass_fre = | 
|  | { | 
|  | "fre",				/* name */ | 
|  | gate_fre,				/* gate */ | 
|  | execute_fre,				/* execute */ | 
|  | NULL,					/* sub */ | 
|  | NULL,					/* next */ | 
|  | 0,					/* static_pass_number */ | 
|  | TV_TREE_FRE,				/* tv_id */ | 
|  | PROP_cfg | PROP_ssa | PROP_alias,	/* properties_required */ | 
|  | 0,					/* properties_provided */ | 
|  | 0,					/* properties_destroyed */ | 
|  | 0,					/* todo_flags_start */ | 
|  | TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */ | 
|  | 0					/* letter */ | 
|  | }; |