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