diff options
author | Jeff Law <law@gcc.gnu.org> | 2013-06-14 12:52:32 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2013-06-14 12:52:32 -0600 |
commit | e91d0adbc165ca56844bc0f0c8c92782739d75f4 (patch) | |
tree | 885f6be93528b5d127ff4ebdfff5e4d673b7ab15 | |
parent | 51b08adabf40a7922771ff4e0c36c8680c082825 (diff) | |
download | gcc-e91d0adbc165ca56844bc0f0c8c92782739d75f4.zip gcc-e91d0adbc165ca56844bc0f0c8c92782739d75f4.tar.gz gcc-e91d0adbc165ca56844bc0f0c8c92782739d75f4.tar.bz2 |
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
-rw-r--r-- | gcc/gimple.h | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/coalesce-1.c | 195 | ||||
-rw-r--r-- | gcc/tree-ssa-coalesce.c | 50 | ||||
-rw-r--r-- | gcc/tree-ssa-live.c | 8 | ||||
-rw-r--r-- | gcc/tree-ssa-uncprop.c | 14 |
5 files changed, 250 insertions, 20 deletions
diff --git a/gcc/gimple.h b/gcc/gimple.h index b4de403..8ae07c9 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1101,6 +1101,9 @@ extern tree tree_ssa_strip_useless_type_conversions (tree); extern bool useless_type_conversion_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. */ static inline gimple_seq_node diff --git a/gcc/testsuite/gcc.dg/tree-ssa/coalesce-1.c b/gcc/testsuite/gcc.dg/tree-ssa/coalesce-1.c new file mode 100644 index 0000000..5cae9ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/coalesce-1.c @@ -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" } } */ + diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c index 354b5f1..d647191 100644 --- a/gcc/tree-ssa-coalesce.c +++ b/gcc/tree-ssa-coalesce.c @@ -943,8 +943,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy) continue; register_ssa_partition (map, arg); - if ((SSA_NAME_VAR (arg) == SSA_NAME_VAR (res) - && TREE_TYPE (arg) == TREE_TYPE (res)) + if (gimple_can_coalesce_p (arg, res) || (e->flags & EDGE_ABNORMAL)) { 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) && TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == SSA_NAME - && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (rhs1) - && TREE_TYPE (lhs) == TREE_TYPE (rhs1)) + && gimple_can_coalesce_p (lhs, rhs1)) { v1 = SSA_NAME_VERSION (lhs); 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]); v2 = SSA_NAME_VERSION (input); - if (SSA_NAME_VAR (outputs[match]) == SSA_NAME_VAR (input) - && TREE_TYPE (outputs[match]) == TREE_TYPE (input)) + if (gimple_can_coalesce_p (outputs[match], input)) { cost = coalesce_cost (REG_BR_PROB_BASE, optimize_bb_for_size_p (bb)); @@ -1072,8 +1069,7 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy) first = var; else { - gcc_assert (SSA_NAME_VAR (var) == SSA_NAME_VAR (first) - && TREE_TYPE (var) == TREE_TYPE (first)); + gcc_assert (gimple_can_coalesce_p (var, first)); v1 = SSA_NAME_VERSION (first); v2 = SSA_NAME_VERSION (var); 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); /* Assert the coalesces have the same base variable. */ - gcc_assert (SSA_NAME_VAR (var1) == SSA_NAME_VAR (var2) - && TREE_TYPE (var1) == TREE_TYPE (var2)); + gcc_assert (gimple_can_coalesce_p (var1, var2)); if (debug) fprintf (debug, "Coalesce list: "); @@ -1341,3 +1336,38 @@ coalesce_ssa_name (void) 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; +} diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 83a52a0..a624d00 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -111,8 +111,12 @@ var_map_base_init (var_map map) as it restricts the sets we compute conflicts for. Using TREE_TYPE to generate sets is the easies as type equivalency also holds for SSA names with the same - underlying decl. */ - m->base.from = TREE_TYPE (var); + underlying decl. + + 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. */ slot = tree_to_index.find_slot (m, INSERT); if (!*slot) diff --git a/gcc/tree-ssa-uncprop.c b/gcc/tree-ssa-uncprop.c index 1fbc524..555485a 100644 --- a/gcc/tree-ssa-uncprop.c +++ b/gcc/tree-ssa-uncprop.c @@ -474,12 +474,11 @@ uncprop_into_successor_phis (basic_block bb) equiv_hash_elt an_equiv_elt; equiv_hash_elt **slot; - /* If the argument is not an invariant, and refers to the same - underlying variable as the PHI result, then there's no - point in un-propagating the argument. */ + /* If the argument is not an invariant and can be potentially + coalesced with the result, then there's no point in + un-propagating the argument. */ if (!is_gimple_min_invariant (arg) - && (SSA_NAME_VAR (arg) == SSA_NAME_VAR (res) - && TREE_TYPE (arg) == TREE_TYPE (res))) + && gimple_can_coalesce_p (arg, res)) continue; /* Lookup this argument's value in the hash table. */ @@ -493,7 +492,7 @@ uncprop_into_successor_phis (basic_block bb) int j; /* 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 SSA_NAME. Use the most recent equivalence as hopefully that results in shortest lifetimes. */ @@ -501,8 +500,7 @@ uncprop_into_successor_phis (basic_block bb) { tree equiv = elt->equivalences[j]; - if (SSA_NAME_VAR (equiv) == SSA_NAME_VAR (res) - && TREE_TYPE (equiv) == TREE_TYPE (res)) + if (gimple_can_coalesce_p (equiv, res)) { SET_PHI_ARG_DEF (phi, e->dest_idx, equiv); break; |