diff options
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/tree-ssa-pre.c')
-rw-r--r-- | gcc-4.2.1-5666.3/gcc/tree-ssa-pre.c | 4000 |
1 files changed, 0 insertions, 4000 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/tree-ssa-pre.c b/gcc-4.2.1-5666.3/gcc/tree-ssa-pre.c deleted file mode 100644 index 9c7b89faa..000000000 --- a/gcc-4.2.1-5666.3/gcc/tree-ssa-pre.c +++ /dev/null @@ -1,4000 +0,0 @@ -/* 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 */ -}; |