- return;
-
- g->e = e;
-
- eliminate_build (g, B);
-
- if (elim_graph_size (g) != 0)
- {
- tree var;
-
- sbitmap_zero (g->visited);
- VEC_truncate (int, g->stack, 0);
-
- for (x = 0; VEC_iterate (tree, g->nodes, x, var); x++)
- {
- int p = var_to_partition (g->map, var);
- if (!TEST_BIT (g->visited, p))
- elim_forward (g, p);
- }
-
- sbitmap_zero (g->visited);
- while (VEC_length (int, g->stack) > 0)
- {
- x = VEC_pop (int, g->stack);
- if (!TEST_BIT (g->visited, x))
- elim_create (g, x);
- }
- }
-
- /* If there are any pending constant copies, issue them now. */
- while (VEC_length (tree, g->const_copies) > 0)
- {
- tree src, dest;
- src = VEC_pop (tree, g->const_copies);
- dest = VEC_pop (tree, g->const_copies);
- insert_copy_on_edge (e, dest, src);
- }
-}
-
-
-/* Shortcut routine to print messages to file F of the form:
- "STR1 EXPR1 STR2 EXPR2 STR3." */
-
-static void
-print_exprs (FILE *f, const char *str1, tree expr1, const char *str2,
- tree expr2, const char *str3)
-{
- fprintf (f, "%s", str1);
- print_generic_expr (f, expr1, TDF_SLIM);
- fprintf (f, "%s", str2);
- print_generic_expr (f, expr2, TDF_SLIM);
- fprintf (f, "%s", str3);
-}
-
-
-/* Shortcut routine to print abnormal edge messages to file F of the form:
- "STR1 EXPR1 STR2 EXPR2 across edge E. */
-
-static void
-print_exprs_edge (FILE *f, edge e, const char *str1, tree expr1,
- const char *str2, tree expr2)
-{
- print_exprs (f, str1, expr1, str2, expr2, " across an abnormal edge");
- fprintf (f, " from BB%d->BB%d\n", e->src->index,
- e->dest->index);
-}
-
-
-/* Coalesce partitions in MAP which are live across abnormal edges in GRAPH.
- RV is the root variable groupings of the partitions in MAP. Since code
- cannot be inserted on these edges, failure to coalesce something across
- an abnormal edge is an error. */
-
-static void
-coalesce_abnormal_edges (var_map map, conflict_graph graph, root_var_p rv)
-{
- basic_block bb;
- edge e;
- tree phi, var, tmp;
- int x, y, z;
- edge_iterator ei;
-
- /* Code cannot be inserted on abnormal edges. Look for all abnormal
- edges, and coalesce any PHI results with their arguments across
- that edge. */
-
- FOR_EACH_BB (bb)
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->dest != EXIT_BLOCK_PTR && e->flags & EDGE_ABNORMAL)
- for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
- {
- /* Visit each PHI on the destination side of this abnormal
- edge, and attempt to coalesce the argument with the result. */
- var = PHI_RESULT (phi);
- x = var_to_partition (map, var);
-
- /* Ignore results which are not relevant. */
- if (x == NO_PARTITION)
- continue;
-
- tmp = PHI_ARG_DEF (phi, e->dest_idx);
-#ifdef ENABLE_CHECKING
- if (!phi_ssa_name_p (tmp))
- {
- print_exprs_edge (stderr, e,
- "\nConstant argument in PHI. Can't insert :",
- var, " = ", tmp);
- internal_error ("SSA corruption");
- }
-#else
- gcc_assert (phi_ssa_name_p (tmp));
-#endif
- y = var_to_partition (map, tmp);
- gcc_assert (x != NO_PARTITION);
- gcc_assert (y != NO_PARTITION);
-#ifdef ENABLE_CHECKING
- if (root_var_find (rv, x) != root_var_find (rv, y))
- {
- print_exprs_edge (stderr, e, "\nDifferent root vars: ",
- root_var (rv, root_var_find (rv, x)),
- " and ",
- root_var (rv, root_var_find (rv, y)));
- internal_error ("SSA corruption");
- }
-#else
- gcc_assert (root_var_find (rv, x) == root_var_find (rv, y));
-#endif
-
- if (x != y)
- {
-#ifdef ENABLE_CHECKING
- if (conflict_graph_conflict_p (graph, x, y))
- {
- print_exprs_edge (stderr, e, "\n Conflict ",
- partition_to_var (map, x),
- " and ", partition_to_var (map, y));
- internal_error ("SSA corruption");
- }
-#else
- gcc_assert (!conflict_graph_conflict_p (graph, x, y));
-#endif
-
- /* Now map the partitions back to their real variables. */
- var = partition_to_var (map, x);
- tmp = partition_to_var (map, y);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- print_exprs_edge (dump_file, e,
- "ABNORMAL: Coalescing ",
- var, " and ", tmp);
- }
- z = var_union (map, var, tmp);
-#ifdef ENABLE_CHECKING
- if (z == NO_PARTITION)
- {
- print_exprs_edge (stderr, e, "\nUnable to coalesce",
- partition_to_var (map, x), " and ",
- partition_to_var (map, y));
- internal_error ("SSA corruption");
- }
-#else
- gcc_assert (z != NO_PARTITION);
-#endif
- gcc_assert (z == x || z == y);
- if (z == x)
- conflict_graph_merge_regs (graph, x, y);
- else
- conflict_graph_merge_regs (graph, y, x);
- }
- }
-}
-
-/* Coalesce potential copies via PHI arguments. */
-
-static void
-coalesce_phi_operands (var_map map, coalesce_list_p cl)
-{
- basic_block bb;
- tree phi;
-
- FOR_EACH_BB (bb)
- {
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- tree res = PHI_RESULT (phi);
- int p = var_to_partition (map, res);
- int x;
-
- if (p == NO_PARTITION)
- continue;
-
- for (x = 0; x < PHI_NUM_ARGS (phi); x++)
- {
- tree arg = PHI_ARG_DEF (phi, x);
- int p2;
-
- if (TREE_CODE (arg) != SSA_NAME)
- continue;
- if (SSA_NAME_VAR (res) != SSA_NAME_VAR (arg))
- continue;
- p2 = var_to_partition (map, PHI_ARG_DEF (phi, x));
- if (p2 != NO_PARTITION)
- {
- edge e = PHI_ARG_EDGE (phi, x);
- add_coalesce (cl, p, p2,
- coalesce_cost (EDGE_FREQUENCY (e),
- maybe_hot_bb_p (bb),
- EDGE_CRITICAL_P (e)));
- }
- }
- }
- }
-}
-
-/* Coalesce all the result decls together. */
-
-static void
-coalesce_result_decls (var_map map, coalesce_list_p cl)
-{
- unsigned int i, x;
- tree var = NULL;
-
- for (i = x = 0; x < num_var_partitions (map); x++)
- {
- tree p = partition_to_var (map, x);
- if (TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
- {
- if (var == NULL_TREE)
- {
- var = p;
- i = x;
- }
- else
- add_coalesce (cl, i, x,
- coalesce_cost (EXIT_BLOCK_PTR->frequency,
- maybe_hot_bb_p (EXIT_BLOCK_PTR),
- false));
- }
- }
-}
-
-/* Coalesce matching constraints in asms. */
-
-static void
-coalesce_asm_operands (var_map map, coalesce_list_p cl)
-{
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- block_stmt_iterator bsi;
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- tree stmt = bsi_stmt (bsi);
- unsigned long noutputs, i;
- tree *outputs, link;
-
- if (TREE_CODE (stmt) != ASM_EXPR)
- continue;
-
- noutputs = list_length (ASM_OUTPUTS (stmt));
- outputs = (tree *) alloca (noutputs * sizeof (tree));
- for (i = 0, link = ASM_OUTPUTS (stmt); link;
- ++i, link = TREE_CHAIN (link))
- outputs[i] = TREE_VALUE (link);
-
- for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
- {
- const char *constraint
- = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
- tree input = TREE_VALUE (link);
- char *end;
- unsigned long match;
- int p1, p2;
-
- if (TREE_CODE (input) != SSA_NAME && !DECL_P (input))
- continue;
-
- match = strtoul (constraint, &end, 10);
- if (match >= noutputs || end == constraint)
- continue;
-
- if (TREE_CODE (outputs[match]) != SSA_NAME
- && !DECL_P (outputs[match]))
- continue;
-
- p1 = var_to_partition (map, outputs[match]);
- if (p1 == NO_PARTITION)
- continue;
- p2 = var_to_partition (map, input);
- if (p2 == NO_PARTITION)
- continue;
-
- add_coalesce (cl, p1, p2, coalesce_cost (REG_BR_PROB_BASE,
- maybe_hot_bb_p (bb),
- false));
- }
- }
- }
-}
-
-/* Reduce the number of live ranges in MAP. Live range information is
- returned if FLAGS indicates that we are combining temporaries, otherwise
- NULL is returned. The only partitions which are associated with actual
- variables at this point are those which are forced to be coalesced for
- various reason. (live on entry, live across abnormal edges, etc.). */
-
-static tree_live_info_p
-coalesce_ssa_name (var_map map, int flags)
-{
- unsigned num, x;
- sbitmap live;
- root_var_p rv;
- tree_live_info_p liveinfo;
- conflict_graph graph;
- coalesce_list_p cl = NULL;
- sbitmap_iterator sbi;
-
- if (num_var_partitions (map) <= 1)
- return NULL;
-
- liveinfo = calculate_live_on_entry (map);
- calculate_live_on_exit (liveinfo);
- rv = root_var_init (map);
-
- /* Remove single element variable from the list. */
- root_var_compact (rv);
-
- cl = create_coalesce_list (map);
-
- coalesce_phi_operands (map, cl);
- coalesce_result_decls (map, cl);
- coalesce_asm_operands (map, cl);
-
- /* Build a conflict graph. */
- graph = build_tree_conflict_graph (liveinfo, rv, cl);
-
- if (cl)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Before sorting:\n");
- dump_coalesce_list (dump_file, cl);
- }
-
- sort_coalesce_list (cl);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "\nAfter sorting:\n");
- dump_coalesce_list (dump_file, cl);
- }
- }
-
- /* Put the single element variables back in. */
- root_var_decompact (rv);
-
- /* First, coalesce all live on entry variables to their root variable.
- This will ensure the first use is coming from the correct location. */
-
- num = num_var_partitions (map);
- live = sbitmap_alloc (num);
- sbitmap_zero (live);
-
- /* Set 'live' vector to indicate live on entry partitions. */
- for (x = 0 ; x < num; x++)
- {
- tree var = partition_to_var (map, x);
- if (default_def (SSA_NAME_VAR (var)) == var)
- SET_BIT (live, x);
- }
-
- if ((flags & SSANORM_COMBINE_TEMPS) == 0)
- {
- delete_tree_live_info (liveinfo);
- liveinfo = NULL;
- }
-
- /* Assign root variable as partition representative for each live on entry
- partition. */
- EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, sbi)
- {
- tree var = root_var (rv, root_var_find (rv, x));
- var_ann_t ann = var_ann (var);
- /* If these aren't already coalesced... */
- if (partition_to_var (map, x) != var)
- {
- /* This root variable should have not already been assigned
- to another partition which is not coalesced with this one. */
- gcc_assert (!ann->out_of_ssa_tag);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- print_exprs (dump_file, "Must coalesce ",
- partition_to_var (map, x),
- " with the root variable ", var, ".\n");
- }
-
- change_partition_var (map, var, x);
- }
- }
-
- sbitmap_free (live);
-
- /* Coalesce partitions live across abnormal edges. */
- coalesce_abnormal_edges (map, graph, rv);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- dump_var_map (dump_file, map);
-
- /* Coalesce partitions. */
- coalesce_tpa_members (rv, graph, map, cl,
- ((dump_flags & TDF_DETAILS) ? dump_file
- : NULL));
-
- if (flags & SSANORM_COALESCE_PARTITIONS)
- coalesce_tpa_members (rv, graph, map, NULL,
- ((dump_flags & TDF_DETAILS) ? dump_file
- : NULL));
- if (cl)
- delete_coalesce_list (cl);
- root_var_delete (rv);
- conflict_graph_delete (graph);
-
- return liveinfo;
-}
-
-
-/* Take the ssa-name var_map MAP, and assign real variables to each
- partition. */
-
-static void
-assign_vars (var_map map)
-{
- int x, i, num, rep;
- tree t, var;
- var_ann_t ann;
- root_var_p rv;
-
- rv = root_var_init (map);
- if (!rv)
- return;
-
- /* Coalescing may already have forced some partitions to their root
- variable. Find these and tag them. */
-
- num = num_var_partitions (map);
- for (x = 0; x < num; x++)
- {
- var = partition_to_var (map, x);
- if (TREE_CODE (var) != SSA_NAME)
- {
- /* Coalescing will already have verified that more than one
- partition doesn't have the same root variable. Simply marked
- the variable as assigned. */
- ann = var_ann (var);
- ann->out_of_ssa_tag = 1;
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "partition %d has variable ", x);
- print_generic_expr (dump_file, var, TDF_SLIM);
- fprintf (dump_file, " assigned to it.\n");
- }
-
- }
- }
-
- num = root_var_num (rv);
- for (x = 0; x < num; x++)
- {
- var = root_var (rv, x);
- ann = var_ann (var);
- for (i = root_var_first_partition (rv, x);
- i != ROOT_VAR_NONE;
- i = root_var_next_partition (rv, i))
- {
- t = partition_to_var (map, i);
-
- if (t == var || TREE_CODE (t) != SSA_NAME)
- continue;
-
- rep = var_to_partition (map, t);
-
- if (!ann->out_of_ssa_tag)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- print_exprs (dump_file, "", t, " --> ", var, "\n");
- change_partition_var (map, var, rep);
- continue;
- }
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- print_exprs (dump_file, "", t, " not coalesced with ", var,
- "");
-
- var = create_temp (t);
- change_partition_var (map, var, rep);
- ann = var_ann (var);
-
- 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)
- {
- edge e = PHI_ARG_EDGE (phi, x);
-
- add_coalesce (cl, p, p2,
- coalesce_cost (EDGE_FREQUENCY (e),
- maybe_hot_bb_p (bb),
- EDGE_CRITICAL_P (e)));
- }
- }
- }
- }
-
-
- /* 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;
- bitmap *expr_vars;
- 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_dependence (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 = XNEW (struct temp_expr_table_d);
- t->map = map;
-
- t->version_info = XCNEWVEC (void *, num_ssa_names + 1);
- t->expr_vars = XCNEWVEC (bitmap, num_ssa_names + 1);
- t->partition_dep_list = XCNEWVEC (value_expr_p,
- num_var_partitions (map) + 1);
-
- 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;
- unsigned i;
-
-#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);
-
- for (i = 0; i <= num_ssa_names; i++)
- if (t->expr_vars[i])
- BITMAP_FREE (t->expr_vars[i]);
- free (t->expr_vars);
-
- 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_dependence (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, basevar;
- int version;
- var_map map = tab->map;
- ssa_op_iter iter;
- tree call_expr;
- bitmap def_vars = BITMAP_ALLOC (NULL), use_vars;
-
- 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;