The following moves the two virtual operands into the gimple_ops array, thereby allowing those to be allocated on-demand. In particular the patch goes the simple route never allocating those for GIMPLE_UNARY_RHS, GIMPLE_BINARY_RHS or GIMPLE_TERNARY_RHS.
I did not clean up the class hierarchy, I did not look for adjustments needed for gcall or gasm, gimple_size is now wrong for those and I didn't quickly find a "nice" solution here. Various passes need adjustment to where they do gimple_assign_set_rhs_* and not handle the (previously impossible) case where the stmt gets re-allocated. For example _1 = _2 + 1 requires 3 ops but _1 = _3 requires 4 as it is GIMPLE_SINGLE_RHS. I didn't try to optimize further by changing allocation based on subcode (we also have those GENERIC tcc_reference non-memory operations like REALPART_EXPR or VIEW_CONVERT_EXPR). Having the virtual operands in ops[] is following the use_operands where the use operand for the VUSE is prepended to use_ops[]. Only very lightly tested (it ICEs, for calls, still on few testcases). I'm mostly looking for general comments and implementation ideas to make it less ugly. * gimple.h ... --- gcc/gimple-ssa.h | 16 ++-- gcc/gimple.cc | 35 ++++++--- gcc/gimple.h | 162 ++++++++++++++++++++------------------- gcc/tree-if-conv.cc | 3 +- gcc/tree-ssa-forwprop.cc | 2 +- gcc/tree-ssa-reassoc.cc | 1 + gcc/tree-vect-generic.cc | 2 +- 7 files changed, 121 insertions(+), 100 deletions(-) diff --git a/gcc/gimple-ssa.h b/gcc/gimple-ssa.h index 6193d46985c..7bf09a91648 100644 --- a/gcc/gimple-ssa.h +++ b/gcc/gimple-ssa.h @@ -141,13 +141,13 @@ inline use_operand_p gimple_vuse_op (const gimple *g) { struct use_optype_d *ops; - const gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <const gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) + const gimple_statement_with_ops_base *mem_ops_stmt = + dyn_cast <const gimple_statement_with_ops_base *> (g); + if (!gimple_has_mem_ops (g)) return NULL_USE_OPERAND_P; ops = mem_ops_stmt->use_ops; if (ops - && USE_OP_PTR (ops)->use == &mem_ops_stmt->vuse) + && USE_OP_PTR (ops)->use == gimple_vuse_ptr (CONST_CAST_GIMPLE (g))) return USE_OP_PTR (ops); return NULL_USE_OPERAND_P; } @@ -157,12 +157,10 @@ gimple_vuse_op (const gimple *g) inline def_operand_p gimple_vdef_op (gimple *g) { - gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) + if (!gimple_has_mem_ops (g)) return NULL_DEF_OPERAND_P; - if (mem_ops_stmt->vdef) - return &mem_ops_stmt->vdef; + if (auto def_p = gimple_vdef_ptr (g)) + return def_p; return NULL_DEF_OPERAND_P; } diff --git a/gcc/gimple.cc b/gcc/gimple.cc index f7b313be40e..ff54a7d19d3 100644 --- a/gcc/gimple.cc +++ b/gcc/gimple.cc @@ -142,12 +142,18 @@ gimple_init (gimple *g, enum gimple_code code, unsigned num_ops) operands. */ gimple * -gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL) +gimple_alloc (enum gimple_code code, unsigned num_ops, + int num_mem_ops MEM_STAT_DECL) { size_t size; gimple *stmt; - size = gimple_size (code, num_ops); + /* Optimize non-SINGLE assign, pass in optional mem_ops override + argument. */ + unsigned mem_ops = (code >= GIMPLE_ASSIGN && code <= GIMPLE_RETURN) ? 2 : 0; + if (num_mem_ops != -1) + mem_ops = num_mem_ops; + size = gimple_size (code, num_ops + mem_ops); if (GATHER_STATISTICS) { enum gimple_alloc_kind kind = gimple_alloc_kind (code); @@ -182,9 +188,10 @@ gimple_set_subcode (gimple *g, unsigned subcode) static gimple * gimple_build_with_ops_stat (enum gimple_code code, unsigned subcode, - unsigned num_ops MEM_STAT_DECL) + unsigned num_ops, + int num_mem_ops = -1 MEM_STAT_DECL) { - gimple *s = gimple_alloc (code, num_ops PASS_MEM_STAT); + gimple *s = gimple_alloc (code, num_ops, num_mem_ops PASS_MEM_STAT); gimple_set_subcode (s, subcode); return s; @@ -471,9 +478,11 @@ gimple_build_assign_1 (tree lhs, enum tree_code subcode, tree op1, code). */ num_ops = get_gimple_rhs_num_ops (subcode) + 1; + int num_mem_ops + = get_gimple_rhs_class (subcode) == GIMPLE_SINGLE_RHS ? 2 : 0; p = as_a <gassign *> ( - gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops - PASS_MEM_STAT)); + gimple_build_with_ops_stat (GIMPLE_ASSIGN, (unsigned)subcode, num_ops, + num_mem_ops PASS_MEM_STAT)); gimple_assign_set_lhs (p, lhs); /* For COND_EXPR, op1 should not be a comparison. */ if (op1 && subcode == COND_EXPR) @@ -1909,11 +1918,18 @@ gimple_assign_set_rhs_with_ops (gimple_stmt_iterator *gsi, enum tree_code code, gimple *old_stmt = stmt; /* If the new CODE needs more operands, allocate a new statement. */ - if (gimple_num_ops (stmt) < new_rhs_ops + 1) + if (gimple_num_ops (stmt) + (gimple_has_mem_ops (old_stmt) ? 2 : 0) + < new_rhs_ops + 1 + (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS ? 2 : 0)) { tree lhs = gimple_assign_lhs (old_stmt); - stmt = gimple_alloc (gimple_code (old_stmt), new_rhs_ops + 1); + stmt = gimple_alloc (gimple_code (old_stmt), new_rhs_ops + 1, + get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS ? 2 : 0); memcpy (stmt, old_stmt, gimple_size (gimple_code (old_stmt))); + /* We didn't adjust a virtual definition SSA_NAME_DEF_STMT so assert + we never re-allocate for stmts with those. */ + gcc_assert (!gimple_vdef (old_stmt)); + if (gimple_vuse (old_stmt) && gimple_has_mem_ops (stmt)) + gimple_set_vuse (stmt, gimple_vuse (old_stmt)); gimple_init_singleton (stmt); /* The LHS needs to be reset as this also changes the SSA name @@ -1981,7 +1997,8 @@ gimple_copy (gimple *stmt) { enum gimple_code code = gimple_code (stmt); unsigned num_ops = gimple_num_ops (stmt); - gimple *copy = gimple_alloc (code, num_ops); + gimple *copy = gimple_alloc (code, num_ops, + gimple_has_mem_ops (stmt) ? 2 : 0); unsigned i; /* Shallow copy all the fields from STMT. */ diff --git a/gcc/gimple.h b/gcc/gimple.h index 4a6e0e97d1e..c2e7f493de1 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -325,11 +325,13 @@ struct GTY((tag("GSS_WITH_MEM_OPS_BASE"))) { /* [ WORD 1-7 ] : base class */ +#if 0 /* [ WORD 8-9 ] Virtual operands for this statement. The GC will pick them up via the ssa_names array. */ tree GTY((skip (""))) vdef; tree GTY((skip (""))) vuse; +#endif }; @@ -1543,7 +1545,7 @@ extern gimple *currently_expanding_gimple_stmt; size_t gimple_size (enum gimple_code code, unsigned num_ops = 0); void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops); -gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO); +gimple *gimple_alloc (enum gimple_code, unsigned, int = -1 CXX_MEM_STAT_INFO); greturn *gimple_build_return (tree); void gimple_call_reset_alias_info (gcall *); gcall *gimple_build_call_vec (tree, const vec<tree> &); @@ -2164,12 +2166,24 @@ is_a_helper <gimple_statement_with_ops *>::test (gimple *gs) return gimple_has_ops (gs); } +inline enum gimple_rhs_class gimple_assign_rhs_class (const gimple *gs); + /* Return true if GIMPLE statement G has memory operands. */ inline bool gimple_has_mem_ops (const gimple *g) { - return gimple_code (g) >= GIMPLE_ASSIGN && gimple_code (g) <= GIMPLE_RETURN; + return ((gimple_code (g) >= GIMPLE_ASSIGN && gimple_code (g) <= GIMPLE_RETURN) + && (gimple_code (g) != GIMPLE_ASSIGN + || gimple_assign_rhs_class (g) == GIMPLE_SINGLE_RHS)); +} + +template <> +template <> +inline bool +is_a_helper <const gimple_statement_with_ops_base *>::test (const gimple *gs) +{ + return gimple_has_ops (gs); } template <> @@ -2212,75 +2226,6 @@ gimple_set_use_ops (gimple *g, struct use_optype_d *use) } -/* Return the single VUSE operand of the statement G. */ - -inline tree -gimple_vuse (const gimple *g) -{ - const gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <const gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) - return NULL_TREE; - return mem_ops_stmt->vuse; -} - -/* Return the single VDEF operand of the statement G. */ - -inline tree -gimple_vdef (const gimple *g) -{ - const gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <const gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) - return NULL_TREE; - return mem_ops_stmt->vdef; -} - -/* Return the single VUSE operand of the statement G. */ - -inline tree * -gimple_vuse_ptr (gimple *g) -{ - gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) - return NULL; - return &mem_ops_stmt->vuse; -} - -/* Return the single VDEF operand of the statement G. */ - -inline tree * -gimple_vdef_ptr (gimple *g) -{ - gimple_statement_with_memory_ops *mem_ops_stmt = - dyn_cast <gimple_statement_with_memory_ops *> (g); - if (!mem_ops_stmt) - return NULL; - return &mem_ops_stmt->vdef; -} - -/* Set the single VUSE operand of the statement G. */ - -inline void -gimple_set_vuse (gimple *g, tree vuse) -{ - gimple_statement_with_memory_ops *mem_ops_stmt = - as_a <gimple_statement_with_memory_ops *> (g); - mem_ops_stmt->vuse = vuse; -} - -/* Set the single VDEF operand of the statement G. */ - -inline void -gimple_set_vdef (gimple *g, tree vdef) -{ - gimple_statement_with_memory_ops *mem_ops_stmt = - as_a <gimple_statement_with_memory_ops *> (g); - mem_ops_stmt->vdef = vdef; -} - - /* Return true if statement G has operands and the modified field has been set. */ @@ -2331,14 +2276,6 @@ gimple_in_transaction (const gimple *stmt) return bb_in_transaction (gimple_bb (stmt)); } -/* Return true if statement STMT may access memory. */ - -inline bool -gimple_references_memory_p (gimple *stmt) -{ - return gimple_has_mem_ops (stmt) && gimple_vuse (stmt); -} - /* Return the subcode for OMP statement S. */ @@ -2629,6 +2566,73 @@ gimple_set_op (gimple *gs, unsigned i, tree op) gimple_ops (gs)[i] = op; } +/* Return the single VUSE operand of the statement G. */ + +inline tree +gimple_vuse (const gimple *g) +{ + if (!gimple_has_mem_ops (g)) + return NULL_TREE; + return gimple_ops (CONST_CAST_GIMPLE (g))[gimple_num_ops (g)]; +} + +/* Return the single VDEF operand of the statement G. */ + +inline tree +gimple_vdef (const gimple *g) +{ + if (!gimple_has_mem_ops (g)) + return NULL_TREE; + return gimple_ops (CONST_CAST_GIMPLE (g))[gimple_num_ops (g) + 1]; +} + +/* Return the single VUSE operand of the statement G. */ + +inline tree * +gimple_vuse_ptr (gimple *g) +{ + if (!gimple_has_mem_ops (g)) + return NULL; + return &gimple_ops (g)[gimple_num_ops (g)]; +} + +/* Return the single VDEF operand of the statement G. */ + +inline tree * +gimple_vdef_ptr (gimple *g) +{ + if (!gimple_has_mem_ops (g)) + return NULL; + return &gimple_ops (g)[gimple_num_ops (g) + 1]; +} + +/* Set the single VUSE operand of the statement G. */ + +inline void +gimple_set_vuse (gimple *g, tree vuse) +{ + gcc_assert (gimple_has_mem_ops (g)); + gimple_ops (g)[gimple_num_ops (g)] = vuse; +} + +/* Set the single VDEF operand of the statement G. */ + +inline void +gimple_set_vdef (gimple *g, tree vdef) +{ + gcc_assert (gimple_has_mem_ops (g)); + gimple_ops (g)[gimple_num_ops (g) + 1] = vdef; +} + +/* Return true if statement STMT may access memory. */ + +inline bool +gimple_references_memory_p (gimple *stmt) +{ + return gimple_vuse (stmt); +} + + /* Return true if GS is a GIMPLE_ASSIGN. */ inline bool diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc index eb981642bae..0e03596a37e 100644 --- a/gcc/tree-if-conv.cc +++ b/gcc/tree-if-conv.cc @@ -393,7 +393,8 @@ ifc_temp_var (tree type, tree expr, gimple_stmt_iterator *gsi) { tree new_name = make_temp_ssa_name (type, NULL, "_ifc_"); gimple *stmt = gimple_build_assign (new_name, expr); - gimple_set_vuse (stmt, gimple_vuse (gsi_stmt (*gsi))); + if (gimple_has_mem_ops (stmt)) + gimple_set_vuse (stmt, gimple_vuse (gsi_stmt (*gsi))); gsi_insert_before (gsi, stmt, GSI_SAME_STMT); return new_name; } diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index cb1e86c6912..27e735555db 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -692,7 +692,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs, gimple_assign_set_rhs_with_ops (use_stmt_gsi, NOP_EXPR, new_def_rhs); else return false; - gcc_assert (gsi_stmt (*use_stmt_gsi) == use_stmt); + use_stmt = gsi_stmt (*use_stmt_gsi); update_stmt (use_stmt); return true; } diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc index ba2a1804052..ac1b2ad5998 100644 --- a/gcc/tree-ssa-reassoc.cc +++ b/gcc/tree-ssa-reassoc.cc @@ -6876,6 +6876,7 @@ transform_stmt_to_copy (gimple_stmt_iterator *gsi, gimple *stmt, tree new_rhs) rhs1 = gimple_assign_rhs1 (stmt); gimple_assign_set_rhs_from_tree (gsi, new_rhs); + stmt = gsi_stmt (*gsi); update_stmt (stmt); remove_visited_stmt_chain (rhs1); diff --git a/gcc/tree-vect-generic.cc b/gcc/tree-vect-generic.cc index 21d906e9c55..07947bfc8f6 100644 --- a/gcc/tree-vect-generic.cc +++ b/gcc/tree-vect-generic.cc @@ -2211,7 +2211,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi, : gimplify_build1 (gsi, code, stype, srhs1); gimple_assign_set_rhs_from_tree (gsi, build_vector_from_val (type, slhs)); - update_stmt (stmt); + update_stmt (gsi_stmt (*gsi)); return; } } -- 2.43.0