mirror of git://gcc.gnu.org/git/gcc.git
gimple.h (gimple_can_coalesce_p): Prototype.
* gimple.h (gimple_can_coalesce_p): Prototype. * tree-ssa-coalesce.c (gimple_can_coalesce_p): New function. (create_outofssa_var_map, coalesce_partitions): Use it. * tree-ssa-uncprop.c (uncprop_into_successor_phis): Similarly. * tree-ssa-live.c (var_map_base_init): Use TYPE_CANONICAL if it's available. * gcc.dg/tree-ssa/coalesce-1.c: New test. From-SVN: r200103
This commit is contained in:
parent
51b08adabf
commit
e91d0adbc1
|
|
@ -1101,6 +1101,9 @@ extern tree tree_ssa_strip_useless_type_conversions (tree);
|
||||||
extern bool useless_type_conversion_p (tree, tree);
|
extern bool useless_type_conversion_p (tree, tree);
|
||||||
extern bool types_compatible_p (tree, tree);
|
extern bool types_compatible_p (tree, tree);
|
||||||
|
|
||||||
|
/* In tree-ssa-coalesce.c */
|
||||||
|
extern bool gimple_can_coalesce_p (tree, tree);
|
||||||
|
|
||||||
/* Return the first node in GIMPLE sequence S. */
|
/* Return the first node in GIMPLE sequence S. */
|
||||||
|
|
||||||
static inline gimple_seq_node
|
static inline gimple_seq_node
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* { dg-options "-O2 -fdump-rtl-expand-details" } */
|
||||||
|
|
||||||
|
typedef long unsigned int size_t;
|
||||||
|
union tree_node;
|
||||||
|
typedef union tree_node *tree;
|
||||||
|
union gimple_statement_d;
|
||||||
|
typedef union gimple_statement_d *gimple;
|
||||||
|
typedef const union tree_node *const_tree;
|
||||||
|
typedef const union gimple_statement_d *const_gimple;
|
||||||
|
struct gimple_seq_d;
|
||||||
|
typedef struct gimple_seq_d *gimple_seq;
|
||||||
|
struct edge_def;
|
||||||
|
typedef struct edge_def *edge;
|
||||||
|
struct basic_block_def;
|
||||||
|
typedef struct basic_block_def *basic_block;
|
||||||
|
typedef const struct basic_block_def *const_basic_block;
|
||||||
|
struct tree_exp
|
||||||
|
{
|
||||||
|
tree operands[1];
|
||||||
|
};
|
||||||
|
typedef struct ssa_use_operand_d
|
||||||
|
{
|
||||||
|
tree *use;
|
||||||
|
} ssa_use_operand_t;
|
||||||
|
struct phi_arg_d
|
||||||
|
{
|
||||||
|
struct ssa_use_operand_d imm_use;
|
||||||
|
};
|
||||||
|
union tree_node
|
||||||
|
{
|
||||||
|
struct tree_exp exp;
|
||||||
|
};
|
||||||
|
struct function
|
||||||
|
{
|
||||||
|
};
|
||||||
|
extern struct function *cfun;
|
||||||
|
struct edge_def
|
||||||
|
{
|
||||||
|
unsigned int dest_idx;
|
||||||
|
};
|
||||||
|
static __inline__ void
|
||||||
|
VEC_edge_must_be_pointer_type (void)
|
||||||
|
{
|
||||||
|
(void) ((edge) 1 == (void *) 1);
|
||||||
|
} typedef struct VEC_edge_base
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned num;
|
||||||
|
unsigned alloc;
|
||||||
|
edge vec[1];
|
||||||
|
} VEC_edge_base;
|
||||||
|
typedef struct VEC_edge_none
|
||||||
|
{
|
||||||
|
VEC_edge_base base;
|
||||||
|
} VEC_edge_none;
|
||||||
|
|
||||||
|
static __inline__ edge
|
||||||
|
VEC_edge_base_index (const VEC_edge_base * vec_, unsigned ix_,
|
||||||
|
const char *file_, unsigned line_, const char *function_)
|
||||||
|
{
|
||||||
|
return vec_->vec[ix_];
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct VEC_edge_gc
|
||||||
|
{
|
||||||
|
VEC_edge_base base;
|
||||||
|
} VEC_edge_gc;
|
||||||
|
struct basic_block_def
|
||||||
|
{
|
||||||
|
VEC_edge_gc *succs;
|
||||||
|
};
|
||||||
|
static __inline__ edge
|
||||||
|
single_succ_edge (const_basic_block bb)
|
||||||
|
{
|
||||||
|
return (VEC_edge_base_index
|
||||||
|
((((bb)->succs) ? &((bb)->succs)->base : 0), (0),
|
||||||
|
"/home/gcc/virgin-gcc/gcc/basic-block.h", 563, __FUNCTION__));
|
||||||
|
}
|
||||||
|
|
||||||
|
edge find_edge (basic_block, basic_block);
|
||||||
|
typedef tree *def_operand_p;
|
||||||
|
typedef ssa_use_operand_t *use_operand_p;
|
||||||
|
struct gimple_seq_node_d;
|
||||||
|
typedef struct gimple_seq_node_d *gimple_seq_node;
|
||||||
|
struct gimple_seq_node_d
|
||||||
|
{
|
||||||
|
gimple stmt;
|
||||||
|
};
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gimple_seq_node ptr;
|
||||||
|
gimple_seq seq;
|
||||||
|
basic_block bb;
|
||||||
|
} gimple_stmt_iterator;
|
||||||
|
struct gimple_statement_phi
|
||||||
|
{
|
||||||
|
struct phi_arg_d args[1];
|
||||||
|
};
|
||||||
|
union gimple_statement_d
|
||||||
|
{
|
||||||
|
struct gimple_statement_phi gimple_phi;
|
||||||
|
};
|
||||||
|
extern size_t const gimple_ops_offset_[];
|
||||||
|
static __inline__ tree *
|
||||||
|
gimple_ops (gimple gs)
|
||||||
|
{
|
||||||
|
size_t off;
|
||||||
|
off = gimple_ops_offset_[gimple_statement_structure (gs)];
|
||||||
|
return (tree *) ((char *) gs + off);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ tree
|
||||||
|
gimple_op (const_gimple gs, unsigned i)
|
||||||
|
{
|
||||||
|
return gimple_ops ((((union
|
||||||
|
{
|
||||||
|
const union gimple_statement_d * _q;
|
||||||
|
union gimple_statement_d * _nq;}) (((gs))))._nq))[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ struct phi_arg_d *
|
||||||
|
gimple_phi_arg (gimple gs, unsigned index)
|
||||||
|
{
|
||||||
|
return &(gs->gimple_phi.args[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ tree
|
||||||
|
gimple_switch_label (const_gimple gs, unsigned index)
|
||||||
|
{
|
||||||
|
return gimple_op (gs, index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimple_stmt_iterator gsi_start_phis (basic_block);
|
||||||
|
extern basic_block label_to_block_fn (struct function *, tree);
|
||||||
|
|
||||||
|
static __inline__ tree
|
||||||
|
get_use_from_ptr (use_operand_p use)
|
||||||
|
{
|
||||||
|
return *(use->use);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ use_operand_p
|
||||||
|
gimple_phi_arg_imm_use_ptr (gimple gs, int i)
|
||||||
|
{
|
||||||
|
return &gimple_phi_arg (gs, i)->imm_use;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct switch_conv_info
|
||||||
|
{
|
||||||
|
basic_block final_bb;
|
||||||
|
basic_block switch_bb;
|
||||||
|
const char *reason;
|
||||||
|
tree *default_values;
|
||||||
|
};
|
||||||
|
static struct switch_conv_info info;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gather_default_values (tree default_case)
|
||||||
|
{
|
||||||
|
gimple_stmt_iterator gsi;
|
||||||
|
basic_block bb =
|
||||||
|
(label_to_block_fn ((cfun + 0), default_case->exp.operands[2]));
|
||||||
|
edge e;
|
||||||
|
int i = 0;
|
||||||
|
if (bb == info.final_bb)
|
||||||
|
e = find_edge (info.switch_bb, bb);
|
||||||
|
else
|
||||||
|
e = single_succ_edge (bb);
|
||||||
|
for (gsi = gsi_start_phis (info.final_bb);
|
||||||
|
gsi_gsi_start_phis (info.final_bb); gsi_next (&gsi))
|
||||||
|
{
|
||||||
|
gimple phi = gsi.ptr->stmt;
|
||||||
|
tree val = get_use_from_ptr (gimple_phi_arg_imm_use_ptr
|
||||||
|
((((phi))), (((e)->dest_idx))));
|
||||||
|
info.default_values[i++] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
process_switch (gimple swtch)
|
||||||
|
{
|
||||||
|
unsigned int i, branch_num = gimple_switch_num_labels (swtch);
|
||||||
|
tree index_type;
|
||||||
|
info.reason = "switch has no labels\n";
|
||||||
|
gather_default_values (gimple_switch_label (swtch, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that out-of-ssa coalescing did its job by verifying there are not
|
||||||
|
any partition copies inserted. */
|
||||||
|
|
||||||
|
/* { dg-final { scan-rtl-dump-not "partition copy" "expand"} } */
|
||||||
|
/* { dg-final { cleanup-rtl-dump "expand" } } */
|
||||||
|
|
||||||
|
|
@ -943,8 +943,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
register_ssa_partition (map, arg);
|
register_ssa_partition (map, arg);
|
||||||
if ((SSA_NAME_VAR (arg) == SSA_NAME_VAR (res)
|
if (gimple_can_coalesce_p (arg, res)
|
||||||
&& TREE_TYPE (arg) == TREE_TYPE (res))
|
|
||||||
|| (e->flags & EDGE_ABNORMAL))
|
|| (e->flags & EDGE_ABNORMAL))
|
||||||
{
|
{
|
||||||
saw_copy = true;
|
saw_copy = true;
|
||||||
|
|
@ -985,8 +984,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
|
||||||
if (gimple_assign_copy_p (stmt)
|
if (gimple_assign_copy_p (stmt)
|
||||||
&& TREE_CODE (lhs) == SSA_NAME
|
&& TREE_CODE (lhs) == SSA_NAME
|
||||||
&& TREE_CODE (rhs1) == SSA_NAME
|
&& TREE_CODE (rhs1) == SSA_NAME
|
||||||
&& SSA_NAME_VAR (lhs) == SSA_NAME_VAR (rhs1)
|
&& gimple_can_coalesce_p (lhs, rhs1))
|
||||||
&& TREE_TYPE (lhs) == TREE_TYPE (rhs1))
|
|
||||||
{
|
{
|
||||||
v1 = SSA_NAME_VERSION (lhs);
|
v1 = SSA_NAME_VERSION (lhs);
|
||||||
v2 = SSA_NAME_VERSION (rhs1);
|
v2 = SSA_NAME_VERSION (rhs1);
|
||||||
|
|
@ -1037,8 +1035,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
|
||||||
v1 = SSA_NAME_VERSION (outputs[match]);
|
v1 = SSA_NAME_VERSION (outputs[match]);
|
||||||
v2 = SSA_NAME_VERSION (input);
|
v2 = SSA_NAME_VERSION (input);
|
||||||
|
|
||||||
if (SSA_NAME_VAR (outputs[match]) == SSA_NAME_VAR (input)
|
if (gimple_can_coalesce_p (outputs[match], input))
|
||||||
&& TREE_TYPE (outputs[match]) == TREE_TYPE (input))
|
|
||||||
{
|
{
|
||||||
cost = coalesce_cost (REG_BR_PROB_BASE,
|
cost = coalesce_cost (REG_BR_PROB_BASE,
|
||||||
optimize_bb_for_size_p (bb));
|
optimize_bb_for_size_p (bb));
|
||||||
|
|
@ -1072,8 +1069,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy)
|
||||||
first = var;
|
first = var;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gcc_assert (SSA_NAME_VAR (var) == SSA_NAME_VAR (first)
|
gcc_assert (gimple_can_coalesce_p (var, first));
|
||||||
&& TREE_TYPE (var) == TREE_TYPE (first));
|
|
||||||
v1 = SSA_NAME_VERSION (first);
|
v1 = SSA_NAME_VERSION (first);
|
||||||
v2 = SSA_NAME_VERSION (var);
|
v2 = SSA_NAME_VERSION (var);
|
||||||
bitmap_set_bit (used_in_copy, v1);
|
bitmap_set_bit (used_in_copy, v1);
|
||||||
|
|
@ -1210,8 +1206,7 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
|
||||||
var2 = ssa_name (y);
|
var2 = ssa_name (y);
|
||||||
|
|
||||||
/* Assert the coalesces have the same base variable. */
|
/* Assert the coalesces have the same base variable. */
|
||||||
gcc_assert (SSA_NAME_VAR (var1) == SSA_NAME_VAR (var2)
|
gcc_assert (gimple_can_coalesce_p (var1, var2));
|
||||||
&& TREE_TYPE (var1) == TREE_TYPE (var2));
|
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf (debug, "Coalesce list: ");
|
fprintf (debug, "Coalesce list: ");
|
||||||
|
|
@ -1341,3 +1336,38 @@ coalesce_ssa_name (void)
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Given SSA_NAMEs NAME1 and NAME2, return true if they are candidates for
|
||||||
|
coalescing together, false otherwise.
|
||||||
|
|
||||||
|
This must stay consistent with var_map_base_init in tree-ssa-live.c. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
gimple_can_coalesce_p (tree name1, tree name2)
|
||||||
|
{
|
||||||
|
/* First check the SSA_NAME's associated DECL. We only want to
|
||||||
|
coalesce if they have the same DECL or both have no associated DECL. */
|
||||||
|
if (SSA_NAME_VAR (name1) != SSA_NAME_VAR (name2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Now check the types. If the types are the same, then we should
|
||||||
|
try to coalesce V1 and V2. */
|
||||||
|
tree t1 = TREE_TYPE (name1);
|
||||||
|
tree t2 = TREE_TYPE (name2);
|
||||||
|
if (t1 == t2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If the types are not the same, check for a canonical type match. This
|
||||||
|
(for example) allows coalescing when the types are fundamentally the
|
||||||
|
same, but just have different names.
|
||||||
|
|
||||||
|
Note pointer types with different address spaces may have the same
|
||||||
|
canonical type. Those are rejected for coalescing by the
|
||||||
|
types_compatible_p check. */
|
||||||
|
if (TYPE_CANONICAL (t1)
|
||||||
|
&& TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2)
|
||||||
|
&& types_compatible_p (t1, t2))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,12 @@ var_map_base_init (var_map map)
|
||||||
as it restricts the sets we compute conflicts for.
|
as it restricts the sets we compute conflicts for.
|
||||||
Using TREE_TYPE to generate sets is the easies as
|
Using TREE_TYPE to generate sets is the easies as
|
||||||
type equivalency also holds for SSA names with the same
|
type equivalency also holds for SSA names with the same
|
||||||
underlying decl. */
|
underlying decl.
|
||||||
m->base.from = TREE_TYPE (var);
|
|
||||||
|
Check gimple_can_coalesce_p when changing this code. */
|
||||||
|
m->base.from = (TYPE_CANONICAL (TREE_TYPE (var))
|
||||||
|
? TYPE_CANONICAL (TREE_TYPE (var))
|
||||||
|
: TREE_TYPE (var));
|
||||||
/* If base variable hasn't been seen, set it up. */
|
/* If base variable hasn't been seen, set it up. */
|
||||||
slot = tree_to_index.find_slot (m, INSERT);
|
slot = tree_to_index.find_slot (m, INSERT);
|
||||||
if (!*slot)
|
if (!*slot)
|
||||||
|
|
|
||||||
|
|
@ -474,12 +474,11 @@ uncprop_into_successor_phis (basic_block bb)
|
||||||
equiv_hash_elt an_equiv_elt;
|
equiv_hash_elt an_equiv_elt;
|
||||||
equiv_hash_elt **slot;
|
equiv_hash_elt **slot;
|
||||||
|
|
||||||
/* If the argument is not an invariant, and refers to the same
|
/* If the argument is not an invariant and can be potentially
|
||||||
underlying variable as the PHI result, then there's no
|
coalesced with the result, then there's no point in
|
||||||
point in un-propagating the argument. */
|
un-propagating the argument. */
|
||||||
if (!is_gimple_min_invariant (arg)
|
if (!is_gimple_min_invariant (arg)
|
||||||
&& (SSA_NAME_VAR (arg) == SSA_NAME_VAR (res)
|
&& gimple_can_coalesce_p (arg, res))
|
||||||
&& TREE_TYPE (arg) == TREE_TYPE (res)))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Lookup this argument's value in the hash table. */
|
/* Lookup this argument's value in the hash table. */
|
||||||
|
|
@ -493,7 +492,7 @@ uncprop_into_successor_phis (basic_block bb)
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/* Walk every equivalence with the same value. If we find
|
/* Walk every equivalence with the same value. If we find
|
||||||
one with the same underlying variable as the PHI result,
|
one that can potentially coalesce with the PHI rsult,
|
||||||
then replace the value in the argument with its equivalent
|
then replace the value in the argument with its equivalent
|
||||||
SSA_NAME. Use the most recent equivalence as hopefully
|
SSA_NAME. Use the most recent equivalence as hopefully
|
||||||
that results in shortest lifetimes. */
|
that results in shortest lifetimes. */
|
||||||
|
|
@ -501,8 +500,7 @@ uncprop_into_successor_phis (basic_block bb)
|
||||||
{
|
{
|
||||||
tree equiv = elt->equivalences[j];
|
tree equiv = elt->equivalences[j];
|
||||||
|
|
||||||
if (SSA_NAME_VAR (equiv) == SSA_NAME_VAR (res)
|
if (gimple_can_coalesce_p (equiv, res))
|
||||||
&& TREE_TYPE (equiv) == TREE_TYPE (res))
|
|
||||||
{
|
{
|
||||||
SET_PHI_ARG_DEF (phi, e->dest_idx, equiv);
|
SET_PHI_ARG_DEF (phi, e->dest_idx, equiv);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue