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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
-#include "errors.h"
#include "expr.h"
#include "function.h"
#include "diagnostic.h"
#include "tree-dump.h"
#include "tree-ssa-live.h"
#include "tree-pass.h"
+#include "toplev.h"
/* Flags to pass to remove_ssa_form. */
#define SSANORM_COMBINE_TEMPS 0x2
#define SSANORM_COALESCE_PARTITIONS 0x4
+DEF_VEC_I(int);
+DEF_VEC_ALLOC_I(int,heap);
+
/* Used to hold all the components required to do SSA PHI elimination.
The node and pred/succ list is a simple linear list of nodes and
edges represented as pairs of nodes.
VEC(tree,heap) *nodes;
/* The predecessor and successor edge list. */
- varray_type edge_list;
+ VEC(int,heap) *edge_list;
/* Visited vector. */
sbitmap visited;
name = "temp";
tmp = create_tmp_var (type, name);
- if (DECL_DEBUG_EXPR (t) && DECL_DEBUG_EXPR_IS_FROM (t))
+ if (DECL_DEBUG_EXPR_IS_FROM (t) && DECL_DEBUG_EXPR (t))
{
- DECL_DEBUG_EXPR (tmp) = DECL_DEBUG_EXPR (t);
+ SET_DECL_DEBUG_EXPR (tmp, DECL_DEBUG_EXPR (t));
DECL_DEBUG_EXPR_IS_FROM (tmp) = 1;
}
else if (!DECL_IGNORED_P (t))
{
- DECL_DEBUG_EXPR (tmp) = t;
+ SET_DECL_DEBUG_EXPR (tmp, t);
DECL_DEBUG_EXPR_IS_FROM (tmp) = 1;
}
DECL_ARTIFICIAL (tmp) = DECL_ARTIFICIAL (t);
g->nodes = VEC_alloc (tree, heap, 30);
g->const_copies = VEC_alloc (tree, heap, 20);
- VARRAY_INT_INIT (g->edge_list, 20, "Elimination Edge List");
+ g->edge_list = VEC_alloc (int, heap, 20);
VARRAY_INT_INIT (g->stack, 30, " Elimination Stack");
g->visited = sbitmap_alloc (size);
clear_elim_graph (elim_graph g)
{
VEC_truncate (tree, g->nodes, 0);
- VARRAY_POP_ALL (g->edge_list);
+ VEC_truncate (int, g->edge_list, 0);
}
delete_elim_graph (elim_graph g)
{
sbitmap_free (g->visited);
+ VEC_free (int, heap, g->edge_list);
VEC_free (tree, heap, g->const_copies);
VEC_free (tree, heap, g->nodes);
free (g);
static inline void
elim_graph_add_edge (elim_graph g, int pred, int succ)
{
- VARRAY_PUSH_INT (g->edge_list, pred);
- VARRAY_PUSH_INT (g->edge_list, succ);
+ VEC_safe_push (int, heap, g->edge_list, pred);
+ VEC_safe_push (int, heap, g->edge_list, succ);
}
{
int y;
unsigned x;
- for (x = 0; x < VARRAY_ACTIVE_SIZE (g->edge_list); x += 2)
- if (VARRAY_INT (g->edge_list, x) == node)
+ for (x = 0; x < VEC_length (int, g->edge_list); x += 2)
+ if (VEC_index (int, g->edge_list, x) == node)
{
- VARRAY_INT (g->edge_list, x) = -1;
- y = VARRAY_INT (g->edge_list, x + 1);
- VARRAY_INT (g->edge_list, x + 1) = -1;
+ VEC_replace (int, g->edge_list, x, -1);
+ y = VEC_index (int, g->edge_list, x + 1);
+ VEC_replace (int, g->edge_list, x + 1, -1);
return y;
}
return -1;
do { \
unsigned x_; \
int y_; \
- for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2) \
+ for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2) \
{ \
- y_ = VARRAY_INT ((GRAPH)->edge_list, x_); \
+ y_ = VEC_index (int, (GRAPH)->edge_list, x_); \
if (y_ != (NODE)) \
continue; \
- (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_ + 1); \
+ (VAR) = VEC_index (int, (GRAPH)->edge_list, x_ + 1); \
CODE; \
} \
} while (0)
do { \
unsigned x_; \
int y_; \
- for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2) \
+ for (x_ = 0; x_ < VEC_length (int, (GRAPH)->edge_list); x_ += 2) \
{ \
- y_ = VARRAY_INT ((GRAPH)->edge_list, x_ + 1); \
+ y_ = VEC_index (int, (GRAPH)->edge_list, x_ + 1); \
if (y_ != (NODE)) \
continue; \
- (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_); \
+ (VAR) = VEC_index (int, (GRAPH)->edge_list, x_); \
CODE; \
} \
} while (0)
}
}
+/* Coalesce potential copies via PHI arguments. */
-/* 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)
+static void
+coalesce_phi_operands (var_map map, coalesce_list_p cl)
{
- unsigned num, x, i;
- sbitmap live;
- tree var, phi;
- root_var_p rv;
- tree_live_info_p liveinfo;
- var_ann_t ann;
- conflict_graph graph;
basic_block bb;
- coalesce_list_p cl = NULL;
-
- 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);
+ tree phi;
- /* Add all potential copies via PHI arguments to the list. */
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 < (unsigned)PHI_NUM_ARGS (phi); x++)
+
+ for (x = 0; x < PHI_NUM_ARGS (phi); x++)
{
tree arg = PHI_ARG_DEF (phi, x);
int p2;
continue;
p2 = var_to_partition (map, PHI_ARG_DEF (phi, x));
if (p2 != NO_PARTITION)
- add_coalesce (cl, p, p2, 1);
+ {
+ 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. */
- var = NULL_TREE;
- i = 0;
- for (x = 0; x < num_var_partitions (map); x++)
+/* 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 (TREE_CODE (SSA_NAME_VAR (p)) == RESULT_DECL)
{
if (var == NULL_TREE)
{
i = x;
}
else
- add_coalesce (cl, i, x, 1);
+ 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);
/* First, coalesce all live on entry variables to their root variable.
This will ensure the first use is coming from the correct location. */
- live = sbitmap_alloc (num_var_partitions (map));
+ num = num_var_partitions (map);
+ live = sbitmap_alloc (num);
sbitmap_zero (live);
/* Set 'live' vector to indicate live on entry partitions. */
- num = num_var_partitions (map);
for (x = 0 ; x < num; x++)
{
- var = partition_to_var (map, x);
+ tree var = partition_to_var (map, x);
if (default_def (SSA_NAME_VAR (var)) == var)
SET_BIT (live, x);
}
/* Assign root variable as partition representative for each live on entry
partition. */
- EXECUTE_IF_SET_IN_SBITMAP (live, 0, x,
+ EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, sbi)
{
- var = root_var (rv, root_var_find (rv, x));
- ann = var_ann (var);
+ 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)
{
change_partition_var (map, var, x);
}
- });
+ }
sbitmap_free (live);
if (p2 == (unsigned)NO_PARTITION)
continue;
if (p != p2)
- add_coalesce (cl, p, p2, 1);
+ {
+ 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)));
+ }
}
}
}