- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, " --> New temp: '");
- print_generic_expr (dump_file, var, TDF_SLIM);
- fprintf (dump_file, "'\n");
- }
- }
- }
-
- root_var_delete (rv);
-}
-
-
-/* Replace use operand P with whatever variable it has been rewritten to based
- on the partitions in MAP. EXPR is an optional expression vector over SSA
- versions which is used to replace P with an expression instead of a variable.
- If the stmt is changed, return true. */
-
-static inline bool
-replace_use_variable (var_map map, use_operand_p p, tree *expr)
-{
- tree new_var;
- tree var = USE_FROM_PTR (p);
-
- /* Check if we are replacing this variable with an expression. */
- if (expr)
- {
- int version = SSA_NAME_VERSION (var);
- if (expr[version])
- {
- tree new_expr = TREE_OPERAND (expr[version], 1);
- SET_USE (p, new_expr);
- /* Clear the stmt's RHS, or GC might bite us. */
- TREE_OPERAND (expr[version], 1) = NULL_TREE;
- return true;
- }
- }
-
- new_var = var_to_partition_to_var (map, var);
- if (new_var)
- {
- SET_USE (p, new_var);
- set_is_used (new_var);
- return true;
- }
- return false;
-}
-
-
-/* Replace def operand DEF_P with whatever variable it has been rewritten to
- based on the partitions in MAP. EXPR is an optional expression vector over
- SSA versions which is used to replace DEF_P with an expression instead of a
- variable. If the stmt is changed, return true. */
-
-static inline bool
-replace_def_variable (var_map map, def_operand_p def_p, tree *expr)
-{
- tree new_var;
- tree var = DEF_FROM_PTR (def_p);
-
- /* Check if we are replacing this variable with an expression. */
- if (expr)
- {
- int version = SSA_NAME_VERSION (var);
- if (expr[version])
- {
- tree new_expr = TREE_OPERAND (expr[version], 1);
- SET_DEF (def_p, new_expr);
- /* Clear the stmt's RHS, or GC might bite us. */
- TREE_OPERAND (expr[version], 1) = NULL_TREE;
- return true;
- }
- }
-
- new_var = var_to_partition_to_var (map, var);
- if (new_var)
- {
- SET_DEF (def_p, new_var);
- set_is_used (new_var);
- return true;
- }
- return false;
-}
-
-
-/* Remove any PHI node which is a virtual PHI. */
-
-static void
-eliminate_virtual_phis (void)
-{
- basic_block bb;
- tree phi, next;
-
- FOR_EACH_BB (bb)
- {
- for (phi = phi_nodes (bb); phi; phi = next)
- {
- next = PHI_CHAIN (phi);
- if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
- {
-#ifdef ENABLE_CHECKING
- int i;
- /* There should be no arguments of this PHI which are in
- the partition list, or we get incorrect results. */
- for (i = 0; i < PHI_NUM_ARGS (phi); i++)
- {
- tree arg = PHI_ARG_DEF (phi, i);
- if (TREE_CODE (arg) == SSA_NAME
- && is_gimple_reg (SSA_NAME_VAR (arg)))
- {
- fprintf (stderr, "Argument of PHI is not virtual (");
- print_generic_expr (stderr, arg, TDF_SLIM);
- fprintf (stderr, "), but the result is :");
- print_generic_stmt (stderr, phi, TDF_SLIM);
- internal_error ("SSA corruption");
- }
- }
-#endif
- remove_phi_node (phi, NULL_TREE);
- }
- }
- }
-}
-
-
-/* This routine will coalesce variables in MAP of the same type which do not
- interfere with each other. LIVEINFO is the live range info for variables
- of interest. This will both reduce the memory footprint of the stack, and
- allow us to coalesce together local copies of globals and scalarized
- component refs. */
-
-static void
-coalesce_vars (var_map map, tree_live_info_p liveinfo)
-{
- basic_block bb;
- type_var_p tv;
- tree var;
- unsigned x, p, p2;
- coalesce_list_p cl;
- conflict_graph graph;
-
- cl = create_coalesce_list (map);
-
- /* Merge all the live on entry vectors for coalesced partitions. */
- for (x = 0; x < num_var_partitions (map); x++)
- {
- var = partition_to_var (map, x);
- p = var_to_partition (map, var);
- if (p != x)
- live_merge_and_clear (liveinfo, p, x);
- }
-
- /* When PHI nodes are turned into copies, the result of each PHI node
- becomes live on entry to the block. Mark these now. */
- FOR_EACH_BB (bb)
- {
- tree phi, arg;
- unsigned p;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- p = var_to_partition (map, PHI_RESULT (phi));
-
- /* Skip virtual PHI nodes. */
- if (p == (unsigned)NO_PARTITION)
- continue;
-
- make_live_on_entry (liveinfo, bb, p);
-
- /* Each argument is a potential copy operation. Add any arguments
- which are not coalesced to the result to the coalesce list. */
- for (x = 0; x < (unsigned)PHI_NUM_ARGS (phi); x++)
- {
- arg = PHI_ARG_DEF (phi, x);
- if (!phi_ssa_name_p (arg))
- continue;
- p2 = var_to_partition (map, arg);
- if (p2 == (unsigned)NO_PARTITION)
- continue;
- if (p != p2)
- add_coalesce (cl, p, p2, 1);
- }
- }
- }
-
-
- /* Re-calculate live on exit info. */
- calculate_live_on_exit (liveinfo);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Live range info for variable memory coalescing.\n");
- dump_live_info (dump_file, liveinfo, LIVEDUMP_ALL);
-
- fprintf (dump_file, "Coalesce list from phi nodes:\n");
- dump_coalesce_list (dump_file, cl);
- }
-
-
- tv = type_var_init (map);
- if (dump_file)
- type_var_dump (dump_file, tv);
- type_var_compact (tv);
- if (dump_file)
- type_var_dump (dump_file, tv);
-
- graph = build_tree_conflict_graph (liveinfo, tv, cl);
-
- type_var_decompact (tv);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "type var list now looks like:n");
- type_var_dump (dump_file, tv);
-
- fprintf (dump_file, "Coalesce list after conflict graph build:\n");
- dump_coalesce_list (dump_file, cl);
- }
-
- sort_coalesce_list (cl);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Coalesce list after sorting:\n");
- dump_coalesce_list (dump_file, cl);
- }
-
- coalesce_tpa_members (tv, graph, map, cl,
- ((dump_flags & TDF_DETAILS) ? dump_file : NULL));
-
- type_var_delete (tv);
- delete_coalesce_list (cl);
-}
-
-
-/* Temporary Expression Replacement (TER)
-
- Replace SSA version variables during out-of-ssa with their defining
- expression if there is only one use of the variable.
-
- A pass is made through the function, one block at a time. No cross block
- information is tracked.
-
- Variables which only have one use, and whose defining stmt is considered
- a replaceable expression (see check_replaceable) are entered into
- consideration by adding a list of dependent partitions to the version_info
- vector for that ssa_name_version. This information comes from the partition
- mapping for each USE. At the same time, the partition_dep_list vector for
- these partitions have this version number entered into their lists.
-
- When the use of a replaceable ssa_variable is encountered, the dependence
- list in version_info[] is moved to the "pending_dependence" list in case
- the current expression is also replaceable. (To be determined later in
- processing this stmt.) version_info[] for the version is then updated to
- point to the defining stmt and the 'replaceable' bit is set.
-
- Any partition which is defined by a statement 'kills' any expression which
- is dependent on this partition. Every ssa version in the partitions'
- dependence list is removed from future consideration.
-
- All virtual references are lumped together. Any expression which is
- dependent on any virtual variable (via a VUSE) has a dependence added
- to the special partition defined by VIRTUAL_PARTITION.
-
- Whenever a V_MAY_DEF is seen, all expressions dependent this
- VIRTUAL_PARTITION are removed from consideration.
-
- At the end of a basic block, all expression are removed from consideration
- in preparation for the next block.
-
- The end result is a vector over SSA_NAME_VERSION which is passed back to
- rewrite_out_of_ssa. As the SSA variables are being rewritten, instead of
- replacing the SSA_NAME tree element with the partition it was assigned,
- it is replaced with the RHS of the defining expression. */
-
-
-/* Dependency list element. This can contain either a partition index or a
- version number, depending on which list it is in. */
-
-typedef struct value_expr_d
-{
- int value;
- struct value_expr_d *next;
-} *value_expr_p;
-
-
-/* Temporary Expression Replacement (TER) table information. */
-
-typedef struct temp_expr_table_d
-{
- var_map map;
- void **version_info;
- value_expr_p *partition_dep_list;
- bitmap replaceable;
- bool saw_replaceable;
- int virtual_partition;
- bitmap partition_in_use;
- value_expr_p free_list;
- value_expr_p pending_dependence;
-} *temp_expr_table_p;
-
-/* Used to indicate a dependency on V_MAY_DEFs. */
-#define VIRTUAL_PARTITION(table) (table->virtual_partition)
-
-static temp_expr_table_p new_temp_expr_table (var_map);
-static tree *free_temp_expr_table (temp_expr_table_p);
-static inline value_expr_p new_value_expr (temp_expr_table_p);
-static inline void free_value_expr (temp_expr_table_p, value_expr_p);
-static inline value_expr_p find_value_in_list (value_expr_p, int,
- value_expr_p *);
-static inline void add_value_to_list (temp_expr_table_p, value_expr_p *, int);
-static inline void add_info_to_list (temp_expr_table_p, value_expr_p *,
- value_expr_p);
-static value_expr_p remove_value_from_list (value_expr_p *, int);
-static void add_dependance (temp_expr_table_p, int, tree);
-static bool check_replaceable (temp_expr_table_p, tree);
-static void finish_expr (temp_expr_table_p, int, bool);
-static void mark_replaceable (temp_expr_table_p, tree);
-static inline void kill_expr (temp_expr_table_p, int, bool);
-static inline void kill_virtual_exprs (temp_expr_table_p, bool);
-static void find_replaceable_in_bb (temp_expr_table_p, basic_block);
-static tree *find_replaceable_exprs (var_map);
-static void dump_replaceable_exprs (FILE *, tree *);
-
-
-/* Create a new TER table for MAP. */
-
-static temp_expr_table_p
-new_temp_expr_table (var_map map)
-{
- temp_expr_table_p t;
-
- t = (temp_expr_table_p) xmalloc (sizeof (struct temp_expr_table_d));
- t->map = map;
-
- t->version_info = xcalloc (num_ssa_names + 1, sizeof (void *));
- t->partition_dep_list = xcalloc (num_var_partitions (map) + 1,
- sizeof (value_expr_p));
-
- t->replaceable = BITMAP_ALLOC (NULL);
- t->partition_in_use = BITMAP_ALLOC (NULL);
-
- t->saw_replaceable = false;
- t->virtual_partition = num_var_partitions (map);
- t->free_list = NULL;
- t->pending_dependence = NULL;
-
- return t;
-}
-
-
-/* Free TER table T. If there are valid replacements, return the expression
- vector. */
-
-static tree *
-free_temp_expr_table (temp_expr_table_p t)
-{
- value_expr_p p;
- tree *ret = NULL;
-
-#ifdef ENABLE_CHECKING
- unsigned x;
- for (x = 0; x <= num_var_partitions (t->map); x++)
- gcc_assert (!t->partition_dep_list[x]);
-#endif
-
- while ((p = t->free_list))
- {
- t->free_list = p->next;
- free (p);
- }
-
- BITMAP_FREE (t->partition_in_use);
- BITMAP_FREE (t->replaceable);
-
- free (t->partition_dep_list);
- if (t->saw_replaceable)
- ret = (tree *)t->version_info;
- else
- free (t->version_info);
-
- free (t);
- return ret;
-}
-
-
-/* Allocate a new value list node. Take it from the free list in TABLE if
- possible. */
-
-static inline value_expr_p
-new_value_expr (temp_expr_table_p table)
-{
- value_expr_p p;
- if (table->free_list)
- {
- p = table->free_list;
- table->free_list = p->next;
- }
- else
- p = (value_expr_p) xmalloc (sizeof (struct value_expr_d));
-
- return p;
-}
-
-
-/* Add value list node P to the free list in TABLE. */
-
-static inline void
-free_value_expr (temp_expr_table_p table, value_expr_p p)
-{
- p->next = table->free_list;
- table->free_list = p;
-}
-
-
-/* Find VALUE if it's in LIST. Return a pointer to the list object if found,
- else return NULL. If LAST_PTR is provided, it will point to the previous
- item upon return, or NULL if this is the first item in the list. */
-
-static inline value_expr_p
-find_value_in_list (value_expr_p list, int value, value_expr_p *last_ptr)
-{
- value_expr_p curr;
- value_expr_p last = NULL;
-
- for (curr = list; curr; last = curr, curr = curr->next)
- {
- if (curr->value == value)
- break;
- }
- if (last_ptr)
- *last_ptr = last;
- return curr;
-}
-
-
-/* Add VALUE to LIST, if it isn't already present. TAB is the expression
- table */
-
-static inline void
-add_value_to_list (temp_expr_table_p tab, value_expr_p *list, int value)
-{
- value_expr_p info;
-
- if (!find_value_in_list (*list, value, NULL))
- {
- info = new_value_expr (tab);
- info->value = value;
- info->next = *list;
- *list = info;
- }
-}
-
-
-/* Add value node INFO if it's value isn't already in LIST. Free INFO if
- it is already in the list. TAB is the expression table. */
-
-static inline void
-add_info_to_list (temp_expr_table_p tab, value_expr_p *list, value_expr_p info)
-{
- if (find_value_in_list (*list, info->value, NULL))
- free_value_expr (tab, info);
- else
- {
- info->next = *list;
- *list = info;
- }
-}
-
-
-/* Look for VALUE in LIST. If found, remove it from the list and return it's
- pointer. */
-
-static value_expr_p
-remove_value_from_list (value_expr_p *list, int value)
-{
- value_expr_p info, last;
-
- info = find_value_in_list (*list, value, &last);
- if (!info)
- return NULL;
- if (!last)
- *list = info->next;
- else
- last->next = info->next;
-
- return info;
-}
-
-
-/* Add a dependency between the def of ssa VERSION and VAR. If VAR is
- replaceable by an expression, add a dependence each of the elements of the
- expression. These are contained in the pending list. TAB is the
- expression table. */
-
-static void
-add_dependance (temp_expr_table_p tab, int version, tree var)
-{
- int i, x;
- value_expr_p info;
-
- i = SSA_NAME_VERSION (var);
- if (bitmap_bit_p (tab->replaceable, i))
- {
- /* This variable is being substituted, so use whatever dependences
- were queued up when we marked this as replaceable earlier. */
- while ((info = tab->pending_dependence))
- {
- tab->pending_dependence = info->next;
- /* Get the partition this variable was dependent on. Reuse this
- object to represent the current expression instead. */
- x = info->value;
- info->value = version;
- add_info_to_list (tab, &(tab->partition_dep_list[x]), info);
- add_value_to_list (tab,
- (value_expr_p *)&(tab->version_info[version]), x);
- bitmap_set_bit (tab->partition_in_use, x);
- }
- }
- else
- {
- i = var_to_partition (tab->map, var);
- gcc_assert (i != NO_PARTITION);
- add_value_to_list (tab, &(tab->partition_dep_list[i]), version);
- add_value_to_list (tab,
- (value_expr_p *)&(tab->version_info[version]), i);
- bitmap_set_bit (tab->partition_in_use, i);
- }
-}
-
-
-/* Check if expression STMT is suitable for replacement in table TAB. If so,
- create an expression entry. Return true if this stmt is replaceable. */
-
-static bool
-check_replaceable (temp_expr_table_p tab, tree stmt)
-{
- tree var, def;
- int version;
- var_map map = tab->map;
- ssa_op_iter iter;
- tree call_expr;
-
- if (TREE_CODE (stmt) != MODIFY_EXPR)
- return false;
-
- /* Punt if there is more than 1 def, or more than 1 use. */
- def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF);
- if (!def)
- return false;
-
- if (version_ref_count (map, def) != 1)
- return false;
-
- /* There must be no V_MAY_DEFS or V_MUST_DEFS. */
- if (!(ZERO_SSA_OPERANDS (stmt, (SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF))))
- return false;
-
- /* Float expressions must go through memory if float-store is on. */
- if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1))))
- return false;
-
- /* Calls to functions with side-effects cannot be replaced. */
- if ((call_expr = get_call_expr_in (stmt)) != NULL_TREE)
- {
- int call_flags = call_expr_flags (call_expr);
- if (TREE_SIDE_EFFECTS (call_expr)
- && !(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
- return false;
- }
-
- version = SSA_NAME_VERSION (def);
-
- /* Add this expression to the dependency list for each use partition. */
- FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
- {
- add_dependance (tab, version, var);
- }
-
- /* If there are VUSES, add a dependence on virtual defs. */
- if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE))
- {
- add_value_to_list (tab, (value_expr_p *)&(tab->version_info[version]),
- VIRTUAL_PARTITION (tab));
- add_value_to_list (tab,
- &(tab->partition_dep_list[VIRTUAL_PARTITION (tab)]),
- version);
- bitmap_set_bit (tab->partition_in_use, VIRTUAL_PARTITION (tab));
- }
-
- return true;
-}
-
-
-/* This function will remove the expression for VERSION from replacement
- consideration.n table TAB If 'replace' is true, it is marked as
- replaceable, otherwise not. */
-
-static void
-finish_expr (temp_expr_table_p tab, int version, bool replace)
-{
- value_expr_p info, tmp;
- int partition;
-
- /* Remove this expression from its dependent lists. The partition dependence
- list is retained and transfered later to whomever uses this version. */
- for (info = (value_expr_p) tab->version_info[version]; info; info = tmp)
- {
- partition = info->value;
- gcc_assert (tab->partition_dep_list[partition]);
- tmp = remove_value_from_list (&(tab->partition_dep_list[partition]),
- version);
- gcc_assert (tmp);
- free_value_expr (tab, tmp);
- /* Only clear the bit when the dependency list is emptied via
- a replacement. Otherwise kill_expr will take care of it. */
- if (!(tab->partition_dep_list[partition]) && replace)
- bitmap_clear_bit (tab->partition_in_use, partition);
- tmp = info->next;
- if (!replace)
- free_value_expr (tab, info);
- }
-
- if (replace)
- {
- tab->saw_replaceable = true;
- bitmap_set_bit (tab->replaceable, version);
- }
- else
- {
- gcc_assert (!bitmap_bit_p (tab->replaceable, version));
- tab->version_info[version] = NULL;
- }
-}
-
-
-/* Mark the expression associated with VAR as replaceable, and enter
- the defining stmt into the version_info table TAB. */
-
-static void
-mark_replaceable (temp_expr_table_p tab, tree var)
-{
- value_expr_p info;
- int version = SSA_NAME_VERSION (var);
- finish_expr (tab, version, true);
-
- /* Move the dependence list to the pending list. */
- if (tab->version_info[version])
- {
- info = (value_expr_p) tab->version_info[version];
- for ( ; info->next; info = info->next)
- continue;
- info->next = tab->pending_dependence;
- tab->pending_dependence = (value_expr_p)tab->version_info[version];
- }
-
- tab->version_info[version] = SSA_NAME_DEF_STMT (var);
-}
-
-
-/* This function marks any expression in TAB which is dependent on PARTITION
- as NOT replaceable. CLEAR_BIT is used to determine whether partition_in_use
- should have its bit cleared. Since this routine can be called within an
- EXECUTE_IF_SET_IN_BITMAP, the bit can't always be cleared. */
-
-static inline void
-kill_expr (temp_expr_table_p tab, int partition, bool clear_bit)
-{
- value_expr_p ptr;
-
- /* Mark every active expr dependent on this var as not replaceable. */
- while ((ptr = tab->partition_dep_list[partition]) != NULL)
- finish_expr (tab, ptr->value, false);
-
- if (clear_bit)
- bitmap_clear_bit (tab->partition_in_use, partition);
-}
-
-
-/* This function kills all expressions in TAB which are dependent on virtual
- DEFs. CLEAR_BIT determines whether partition_in_use gets cleared. */
-
-static inline void
-kill_virtual_exprs (temp_expr_table_p tab, bool clear_bit)
-{
- kill_expr (tab, VIRTUAL_PARTITION (tab), clear_bit);
-}
-
-
-/* This function processes basic block BB, and looks for variables which can
- be replaced by their expressions. Results are stored in TAB. */
-
-static void
-find_replaceable_in_bb (temp_expr_table_p tab, basic_block bb)
-{
- block_stmt_iterator bsi;
- tree stmt, def;
- stmt_ann_t ann;
- int partition;
- var_map map = tab->map;
- value_expr_p p;
- ssa_op_iter iter;
-
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- stmt = bsi_stmt (bsi);
- ann = stmt_ann (stmt);
-
- /* Determine if this stmt finishes an existing expression. */
- FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_USE)
- {
- if (tab->version_info[SSA_NAME_VERSION (def)])
- {
- bool same_root_var = false;
- tree def2;
- ssa_op_iter iter2;
-
- /* See if the root variables are the same. If they are, we
- do not want to do the replacement to avoid problems with
- code size, see PR tree-optimization/17549. */
- FOR_EACH_SSA_TREE_OPERAND (def2, stmt, iter2, SSA_OP_DEF)
- if (SSA_NAME_VAR (def) == SSA_NAME_VAR (def2))
- {
- same_root_var = true;
- break;
- }
-
- /* Mark expression as replaceable unless stmt is volatile
- or DEF sets the same root variable as STMT. */
- if (!ann->has_volatile_ops && !same_root_var)
- mark_replaceable (tab, def);
- else
- finish_expr (tab, SSA_NAME_VERSION (def), false);
- }
- }
-
- /* Next, see if this stmt kills off an active expression. */
- FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
- {
- partition = var_to_partition (map, def);
- if (partition != NO_PARTITION && tab->partition_dep_list[partition])
- kill_expr (tab, partition, true);
- }
-
- /* Now see if we are creating a new expression or not. */
- if (!ann->has_volatile_ops)
- check_replaceable (tab, stmt);
-
- /* Free any unused dependency lists. */
- while ((p = tab->pending_dependence))
- {
- tab->pending_dependence = p->next;
- free_value_expr (tab, p);
- }
-
- /* A V_{MAY,MUST}_DEF kills any expression using a virtual operand. */
- if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS))
- kill_virtual_exprs (tab, true);
- }
-}
-
-
-/* This function is the driver routine for replacement of temporary expressions
- in the SSA->normal phase, operating on MAP. If there are replaceable
- expressions, a table is returned which maps SSA versions to the
- expressions they should be replaced with. A NULL_TREE indicates no
- replacement should take place. If there are no replacements at all,
- NULL is returned by the function, otherwise an expression vector indexed
- by SSA_NAME version numbers. */
-
-static tree *
-find_replaceable_exprs (var_map map)
-{
- basic_block bb;
- unsigned i;
- temp_expr_table_p table;
- tree *ret;
-
- table = new_temp_expr_table (map);
- FOR_EACH_BB (bb)
- {
- bitmap_iterator bi;
-
- find_replaceable_in_bb (table, bb);
- EXECUTE_IF_SET_IN_BITMAP ((table->partition_in_use), 0, i, bi)
- {
- kill_expr (table, i, false);
- }
- }
-
- ret = free_temp_expr_table (table);
- return ret;
-}
-
-
-/* Dump TER expression table EXPR to file F. */
-
-static void
-dump_replaceable_exprs (FILE *f, tree *expr)
-{
- tree stmt, var;
- int x;
- fprintf (f, "\nReplacing Expressions\n");
- for (x = 0; x < (int)num_ssa_names + 1; x++)
- if (expr[x])
- {
- stmt = expr[x];
- var = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF);
- gcc_assert (var != NULL_TREE);
- print_generic_expr (f, var, TDF_SLIM);
- fprintf (f, " replace with --> ");
- print_generic_expr (f, TREE_OPERAND (stmt, 1), TDF_SLIM);
- fprintf (f, "\n");
- }
- fprintf (f, "\n");
-}
-
-
-/* Helper function for discover_nonconstant_array_refs.
- Look for ARRAY_REF nodes with non-constant indexes and mark them
- addressable. */
-
-static tree
-discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees,
- void *data ATTRIBUTE_UNUSED)
-{
- tree t = *tp;
-
- if (IS_TYPE_OR_DECL_P (t))
- *walk_subtrees = 0;
- else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
- {
- while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
- && is_gimple_min_invariant (TREE_OPERAND (t, 1))
- && (!TREE_OPERAND (t, 2)
- || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
- || (TREE_CODE (t) == COMPONENT_REF
- && (!TREE_OPERAND (t,2)
- || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
- || TREE_CODE (t) == BIT_FIELD_REF
- || TREE_CODE (t) == REALPART_EXPR
- || TREE_CODE (t) == IMAGPART_EXPR
- || TREE_CODE (t) == VIEW_CONVERT_EXPR
- || TREE_CODE (t) == NOP_EXPR
- || TREE_CODE (t) == CONVERT_EXPR)
- t = TREE_OPERAND (t, 0);
-
- if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
- {
- t = get_base_address (t);
- if (t && DECL_P (t))
- TREE_ADDRESSABLE (t) = 1;
- }
-
- *walk_subtrees = 0;
- }
-
- return NULL_TREE;
-}
-
-
-/* RTL expansion is not able to compile array references with variable
- offsets for arrays stored in single register. Discover such
- expressions and mark variables as addressable to avoid this
- scenario. */
-
-static void
-discover_nonconstant_array_refs (void)
-{
- basic_block bb;
- block_stmt_iterator bsi;
-
- FOR_EACH_BB (bb)
- {
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r,
- NULL , NULL);
- }
-}
-
-
-/* This function will rewrite the current program using the variable mapping
- found in MAP. If the replacement vector VALUES is provided, any
- occurrences of partitions with non-null entries in the vector will be
- replaced with the expression in the vector instead of its mapped
- variable. */
-
-static void
-rewrite_trees (var_map map, tree *values)
-{
- elim_graph g;
- basic_block bb;
- block_stmt_iterator si;
- edge e;
- tree phi;
- bool changed;
-
-#ifdef ENABLE_CHECKING
- /* Search for PHIs where the destination has no partition, but one
- or more arguments has a partition. This should not happen and can
- create incorrect code. */
- FOR_EACH_BB (bb)
- {
- tree phi;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- tree T0 = var_to_partition_to_var (map, PHI_RESULT (phi));
-
- if (T0 == NULL_TREE)
- {
- int i;
-
- for (i = 0; i < PHI_NUM_ARGS (phi); i++)
- {
- tree arg = PHI_ARG_DEF (phi, i);
-
- if (TREE_CODE (arg) == SSA_NAME
- && var_to_partition (map, arg) != NO_PARTITION)
- {
- fprintf (stderr, "Argument of PHI is in a partition :(");
- print_generic_expr (stderr, arg, TDF_SLIM);
- fprintf (stderr, "), but the result is not :");
- print_generic_stmt (stderr, phi, TDF_SLIM);
- internal_error ("SSA corruption");
- }
- }
- }
- }
- }
-#endif
-
- /* Replace PHI nodes with any required copies. */
- g = new_elim_graph (map->num_partitions);
- g->map = map;
- FOR_EACH_BB (bb)
- {
- for (si = bsi_start (bb); !bsi_end_p (si); )
- {
- tree stmt = bsi_stmt (si);
- use_operand_p use_p, copy_use_p;
- def_operand_p def_p;
- bool remove = false, is_copy = false;
- int num_uses = 0;
- stmt_ann_t ann;
- ssa_op_iter iter;
-
- ann = stmt_ann (stmt);
- changed = false;
-
- if (TREE_CODE (stmt) == MODIFY_EXPR
- && (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME))
- is_copy = true;
-
- copy_use_p = NULL_USE_OPERAND_P;
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
- {
- if (replace_use_variable (map, use_p, values))
- changed = true;
- copy_use_p = use_p;
- num_uses++;
- }
-
- if (num_uses != 1)
- is_copy = false;
-
- def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
-
- if (def_p != NULL)
- {
- /* Mark this stmt for removal if it is the list of replaceable
- expressions. */
- if (values && values[SSA_NAME_VERSION (DEF_FROM_PTR (def_p))])
- remove = true;
- else
- {
- if (replace_def_variable (map, def_p, NULL))
- changed = true;
- /* If both SSA_NAMEs coalesce to the same variable,
- mark the now redundant copy for removal. */
- if (is_copy)
- {
- gcc_assert (copy_use_p != NULL_USE_OPERAND_P);
- if (DEF_FROM_PTR (def_p) == USE_FROM_PTR (copy_use_p))
- remove = true;
- }
- }
- }
- else
- FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
- if (replace_def_variable (map, def_p, NULL))
- changed = true;
-
- /* Remove any stmts marked for removal. */
- if (remove)
- bsi_remove (&si);
- else
- bsi_next (&si);
- }
-
- phi = phi_nodes (bb);
- if (phi)
- {
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, bb->preds)
- eliminate_phi (e, g);
- }
- }
-
- delete_elim_graph (g);
-}
-
-
-DEF_VEC_ALLOC_P(edge,heap);
-
-/* These are the local work structures used to determine the best place to
- insert the copies that were placed on edges by the SSA->normal pass.. */
-static VEC(edge,heap) *edge_leader;
-static VEC(tree,heap) *stmt_list;
-static bitmap leader_has_match = NULL;
-static edge leader_match = NULL;
-
-
-/* Pass this function to make_forwarder_block so that all the edges with
- matching PENDING_STMT lists to 'curr_stmt_list' get redirected. */
-static bool
-same_stmt_list_p (edge e)
-{
- return (e->aux == (PTR) leader_match) ? true : false;
-}
-
-
-/* Return TRUE if S1 and S2 are equivalent copies. */
-static inline bool
-identical_copies_p (tree s1, tree s2)
-{
-#ifdef ENABLE_CHECKING
- gcc_assert (TREE_CODE (s1) == MODIFY_EXPR);
- gcc_assert (TREE_CODE (s2) == MODIFY_EXPR);
- gcc_assert (DECL_P (TREE_OPERAND (s1, 0)));
- gcc_assert (DECL_P (TREE_OPERAND (s2, 0)));
-#endif
-
- if (TREE_OPERAND (s1, 0) != TREE_OPERAND (s2, 0))
- return false;
-
- s1 = TREE_OPERAND (s1, 1);
- s2 = TREE_OPERAND (s2, 1);
-
- if (s1 != s2)
- return false;
-
- return true;
-}
-
-
-/* Compare the PENDING_STMT list for two edges, and return true if the lists
- contain the same sequence of copies. */
-
-static inline bool
-identical_stmt_lists_p (edge e1, edge e2)
-{
- tree t1 = PENDING_STMT (e1);
- tree t2 = PENDING_STMT (e2);
- tree_stmt_iterator tsi1, tsi2;
-
- gcc_assert (TREE_CODE (t1) == STATEMENT_LIST);
- gcc_assert (TREE_CODE (t2) == STATEMENT_LIST);
-
- for (tsi1 = tsi_start (t1), tsi2 = tsi_start (t2);
- !tsi_end_p (tsi1) && !tsi_end_p (tsi2);
- tsi_next (&tsi1), tsi_next (&tsi2))
- {
- if (!identical_copies_p (tsi_stmt (tsi1), tsi_stmt (tsi2)))
- break;
- }
-
- if (!tsi_end_p (tsi1) || ! tsi_end_p (tsi2))
- return false;
-
- return true;
-}
-
-
-/* Allocate data structures used in analyze_edges_for_bb. */
-
-static void
-init_analyze_edges_for_bb (void)
-{
- edge_leader = VEC_alloc (edge, heap, 25);
- stmt_list = VEC_alloc (tree, heap, 25);
- leader_has_match = BITMAP_ALLOC (NULL);
-}
-
-
-/* Free data structures used in analyze_edges_for_bb. */
-
-static void
-fini_analyze_edges_for_bb (void)
-{
- VEC_free (edge, heap, edge_leader);
- VEC_free (tree, heap, stmt_list);
- BITMAP_FREE (leader_has_match);
-}
-
-
-/* Look at all the incoming edges to block BB, and decide where the best place
- to insert the stmts on each edge are, and perform those insertions. Output
- any debug information to DEBUG_FILE. */
-
-static void
-analyze_edges_for_bb (basic_block bb, FILE *debug_file)
-{
- edge e;
- edge_iterator ei;
- int count;
- unsigned int x;
- bool have_opportunity;
- block_stmt_iterator bsi;
- tree stmt;
- edge single_edge = NULL;
- bool is_label;
- edge leader;
-
- count = 0;
-
- /* Blocks which contain at least one abnormal edge cannot use
- make_forwarder_block. Look for these blocks, and commit any PENDING_STMTs
- found on edges in these block. */
- have_opportunity = true;
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (e->flags & EDGE_ABNORMAL)
- {
- have_opportunity = false;
- break;
- }
-
- if (!have_opportunity)
- {
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (PENDING_STMT (e))
- bsi_commit_one_edge_insert (e, NULL);
- return;
- }
- /* Find out how many edges there are with interesting pending stmts on them.
- Commit the stmts on edges we are not interested in. */
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- if (PENDING_STMT (e))
- {
- gcc_assert (!(e->flags & EDGE_ABNORMAL));
- if (e->flags & EDGE_FALLTHRU)
- {
- bsi = bsi_start (e->src);
- if (!bsi_end_p (bsi))
- {
- stmt = bsi_stmt (bsi);
- bsi_next (&bsi);
- gcc_assert (stmt != NULL_TREE);
- is_label = (TREE_CODE (stmt) == LABEL_EXPR);
- /* Punt if it has non-label stmts, or isn't local. */
- if (!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0))
- || !bsi_end_p (bsi))
- {
- bsi_commit_one_edge_insert (e, NULL);
- continue;
- }
- }
- }
- single_edge = e;
- count++;
- }
- }
-
- /* If there aren't at least 2 edges, no sharing will happen. */
- if (count < 2)
- {
- if (single_edge)
- bsi_commit_one_edge_insert (single_edge, NULL);
- return;
- }
-
- /* Ensure that we have empty worklists. */
-#ifdef ENABLE_CHECKING
- gcc_assert (VEC_length (edge, edge_leader) == 0);
- gcc_assert (VEC_length (tree, stmt_list) == 0);
- gcc_assert (bitmap_empty_p (leader_has_match));
-#endif
-
- /* Find the "leader" block for each set of unique stmt lists. Preference is
- given to FALLTHRU blocks since they would need a GOTO to arrive at another
- block. The leader edge destination is the block which all the other edges
- with the same stmt list will be redirected to. */
- have_opportunity = false;
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- if (PENDING_STMT (e))
- {
- bool found = false;
-
- /* Look for the same stmt list in edge leaders list. */
- for (x = 0; VEC_iterate (edge, edge_leader, x, leader); x++)
- {
- if (identical_stmt_lists_p (leader, e))
- {
- /* Give this edge the same stmt list pointer. */
- PENDING_STMT (e) = NULL;
- e->aux = leader;
- bitmap_set_bit (leader_has_match, x);
- have_opportunity = found = true;
- break;
- }
- }
-
- /* If no similar stmt list, add this edge to the leader list. */
- if (!found)
- {
- VEC_safe_push (edge, heap, edge_leader, e);
- VEC_safe_push (tree, heap, stmt_list, PENDING_STMT (e));
- }
- }
- }
-
- /* If there are no similar lists, just issue the stmts. */
- if (!have_opportunity)
- {
- for (x = 0; VEC_iterate (edge, edge_leader, x, leader); x++)
- bsi_commit_one_edge_insert (leader, NULL);
- VEC_truncate (edge, edge_leader, 0);
- VEC_truncate (tree, stmt_list, 0);
- bitmap_clear (leader_has_match);
- return;
- }
-
-
- if (debug_file)
- fprintf (debug_file, "\nOpportunities in BB %d for stmt/block reduction:\n",
- bb->index);
-
-
- /* For each common list, create a forwarding block and issue the stmt's
- in that block. */
- for (x = 0; VEC_iterate (edge, edge_leader, x, leader); x++)
- if (bitmap_bit_p (leader_has_match, x))
- {
- edge new_edge;
- block_stmt_iterator bsi;
- tree curr_stmt_list;
-
- leader_match = leader;
-
- /* The tree_* cfg manipulation routines use the PENDING_EDGE field
- for various PHI manipulations, so it gets cleared whhen calls are
- made to make_forwarder_block(). So make sure the edge is clear,
- and use the saved stmt list. */
- PENDING_STMT (leader) = NULL;
- leader->aux = leader;
- curr_stmt_list = VEC_index (tree, stmt_list, x);
-
- new_edge = make_forwarder_block (leader->dest, same_stmt_list_p,
- NULL);
- bb = new_edge->dest;
- if (debug_file)
- {
- fprintf (debug_file, "Splitting BB %d for Common stmt list. ",
- leader->dest->index);
- fprintf (debug_file, "Original block is now BB%d.\n", bb->index);
- print_generic_stmt (debug_file, curr_stmt_list, TDF_VOPS);
- }
-
- FOR_EACH_EDGE (e, ei, new_edge->src->preds)
- {
- e->aux = NULL;
- if (debug_file)
- fprintf (debug_file, " Edge (%d->%d) lands here.\n",
- e->src->index, e->dest->index);
- }
-
- bsi = bsi_last (leader->dest);
- bsi_insert_after (&bsi, curr_stmt_list, BSI_NEW_STMT);
-
- leader_match = NULL;
- /* We should never get a new block now. */
- }
- else
- {
- PENDING_STMT (leader) = VEC_index (tree, stmt_list, x);
- bsi_commit_one_edge_insert (leader, NULL);
- }
-
-
- /* Clear the working data structures. */
- VEC_truncate (edge, edge_leader, 0);
- VEC_truncate (tree, stmt_list, 0);
- bitmap_clear (leader_has_match);
-}
-
-
-/* This function will analyze the insertions which were performed on edges,
- and decide whether they should be left on that edge, or whether it is more
- efficient to emit some subset of them in a single block. All stmts are
- inserted somewhere, and if non-NULL, debug information is printed via
- DUMP_FILE. */
-
-static void
-perform_edge_inserts (FILE *dump_file)
-{
- basic_block bb;
-
- if (dump_file)
- fprintf(dump_file, "Analyzing Edge Insertions.\n");
-
- /* analyze_edges_for_bb calls make_forwarder_block, which tries to
- incrementally update the dominator information. Since we don't
- need dominator information after this pass, go ahead and free the
- dominator information. */
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
-
- /* Allocate data structures used in analyze_edges_for_bb. */
- init_analyze_edges_for_bb ();
-
- FOR_EACH_BB (bb)
- analyze_edges_for_bb (bb, dump_file);
-
- analyze_edges_for_bb (EXIT_BLOCK_PTR, dump_file);
-
- /* Free data structures used in analyze_edges_for_bb. */
- fini_analyze_edges_for_bb ();
-
-#ifdef ENABLE_CHECKING
- {
- edge_iterator ei;
- edge e;
- FOR_EACH_BB (bb)
- {
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- if (PENDING_STMT (e))
- error (" Pending stmts not issued on PRED edge (%d, %d)\n",
- e->src->index, e->dest->index);
- }
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (PENDING_STMT (e))
- error (" Pending stmts not issued on SUCC edge (%d, %d)\n",
- e->src->index, e->dest->index);
- }
- }
- FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
- {
- if (PENDING_STMT (e))
- error (" Pending stmts not issued on ENTRY edge (%d, %d)\n",
- e->src->index, e->dest->index);
- }
- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
- {
- if (PENDING_STMT (e))
- error (" Pending stmts not issued on EXIT edge (%d, %d)\n",
- e->src->index, e->dest->index);
- }
- }
-#endif