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

Reply via email to