diff mbox

[cxx-conversion] Support garbage-collected C++ templates

Message ID 50252386.8000505@google.com
State New
Headers show

Commit Message

Diego Novillo Aug. 10, 2012, 3:06 p.m. UTC
On 12-08-09 09:05 , Richard Guenther wrote:

> What I do not understand is why you need a GTY(()) annotation on
> C++ types with user-defined gc routines.  gengtype should treat all
> types not marked with GTY(()) as having user-defined gc routines, no?

Ideally, yes.  But currently gengtype makes it hard to do because of the 
way it's designed.  When it finds a struct with no GTY() hooks, it 
completely ignores it.  If that struct is later reached from a ggc root, 
it is too late to say 'ah, it must be a user type'.

That's why if we add a keyword to indicate that this struct is 
user-handled, things start working (with some limitations).

In this patch, I implement this notion.  As an example, I modified 
struct edge_def.

The good:

- No GTY markers are needed for the fields of the structure.
- The user provides gt_ggc_mx and gt_pch_nx (2 variants).  These are 
implemented in terms of calls to gt_ggc_mx and gt_pch_nx (see tree-cfg.c).
- gengtype generates the generic glue that calls these functions.

The ugly:

- The structure needs to be marked 'GTY((user))' for the gty parser to 
put it in the list of interesting structures (most notably, it gives it 
a source location, which is the indicator used in the rest of gengtype 
to decide whether a structure is interesting).

- The user-provided markers need to declare the prototypes for the 
gt_ggc_mx and gt_pch_nx for the type fields.  This is due to the lack of 
prototypes generated in gtype-desc.h (or some other header).

These two warts are the ones I was referring to.  I need to fix these in 
trunk because they will require quite a bit of file reorganization.

The end point should be that the only thing we really need to tell 
gengtype about are the variable roots.  Everything else would rely on 
user-provided markings.  I suppose we could still keep the automatic 
option for really simple stuff, though.


Diego.


2012-08-10  Diego Novillo  <dnovillo@google.com>

         * basic-block.h (struct edge_def): Mark GTY((user)).
         Remove all GTY markers from fields.
         (gt_ggc_mx): Declare.
         (gt_pch_nx): Declare.
         * tree-cfg.c (gt_ggc_mx): New.
         (gt_pch_nx): New.

         * gengtype-lex.l (USER_GTY): Add pattern for "user".
         * gengtype-parse.c (option): Handle USER_GTY.
         (opts_have): New.
         (type): Call it.
         If the keyword 'user' is used, do not walk the fields
         of the structure.
         * gengtype.h (USER_GTY): Add.

Comments

Richard Henderson Aug. 10, 2012, 8:14 p.m. UTC | #1
On 2012-08-10 08:06, Diego Novillo wrote:
> The end point should be that the only thing we really need to tell
> gengtype about are the variable roots.  Everything else would rely on
> user-provided markings.  I suppose we could still keep the automatic
> option for really simple stuff, though.

Yes please.  Markup may be awkward, but I think can be less awkward
than generating those three cookie-cutter functions.


r~
Diego Novillo Aug. 10, 2012, 8:41 p.m. UTC | #2
On 12-08-10 16:14 , Richard Henderson wrote:
> On 2012-08-10 08:06, Diego Novillo wrote:
>> The end point should be that the only thing we really need to tell
>> gengtype about are the variable roots.  Everything else would rely on
>> user-provided markings.  I suppose we could still keep the automatic
>> option for really simple stuff, though.
>
> Yes please.  Markup may be awkward, but I think can be less awkward
> than generating those three cookie-cutter functions.

Yeah. Another thing I suppose we want to keep is the whole 'prev' and 
'next' markings. These generate harness that would be cumbersome to 
implement from user code.


Diego.
Lawrence Crowl Aug. 11, 2012, 1:27 a.m. UTC | #3
On 8/10/12, Diego Novillo <dnovillo@google.com> wrote:
> On 12-08-10 16:14 , Richard Henderson wrote:
> > On 2012-08-10 08:06, Diego Novillo wrote:
> > > The end point should be that the only thing we really need to
> > > tell gengtype about are the variable roots.  Everything else
> > > would rely on user-provided markings.  I suppose we could still
> > > keep the automatic option for really simple stuff, though.
> >
> > Yes please.  Markup may be awkward, but I think can be less
> > awkward than generating those three cookie-cutter functions.
>
> Yeah. Another thing I suppose we want to keep is the whole
> 'prev' and 'next' markings. These generate harness that would be
> cumbersome to implement from user code.

Diego and I talked about this issue.  What follows is sort of a
brain dump.  Corrections welcome.

There are several principles we can apply to the work.

   Data types that change frequently should be handled automatically.
   Otherwise, the purpose of precise garbage collection is somewhat
   defeated.  If we get to that situation, we should simply figure
   out how to convert the collector to something else.

   GTY markings that change frequently, or are hard to understand
   and get right, are a burden as well.

   The complexity of gengtype's implementation can be substantially
   reduced if it does not try to solve all problems.

   We are compiler engineers, and we can do complex manual work
   when appropriate.  Not everything needs to be automatic.

Applying those principles, we can reach some conclusions about
approach.

   We can rely on GTY((user)) for template class types.  By and large
   these types implement general data structures, like hash tables.
   The won't change much once built, and so maintenance of the manual
   marking routines will not be a large burden.  Taking this approach
   means that gengtype will not have to understand templates.
   We really do not want gengtype trying to understand templates.
   Diego has already implemented this part.

   Some types generic via void* and use param_is/use_param.  As we
   migrate to templates, much of these uses can go away.  Perhaps,
   eventually, we might be able to remove that complexity from
   gengtype.  As this possibility is closer to wishful thinking,
   it has really low priority.

   We cannot rely on GTY((user)) for class hierarchies that hold
   program structures.  For example, cgraph and tree nodes are too
   volatile to rely on manually synchronizing the marker function
   with the data fields.  So, we need to get gengtype to work with
   class hierarchies.

   We probably do not need to handle multiple inheritance.  First,
   existing structures do not use it.  Second, it probably would not
   be used much anyway.

   Polymorphic class hierarchies may require the user to add a
   couple of method declarations for gengtype.  Gengtype would then
   provide the method definitions.  We do not have any polymorphic
   classes yet, so this issue has a low priority.

   We will likely borrow the descriminator/tag structure of
   unions for the marking of non-polymorphic class hierarchies.
   Gengtype will split the marking of fields and the identification
   of the dynamic type into separate functions.  We have several
   non-polymorphic class hierarchies now, though represented with
   unions and embedding, so this issue has a high priority.

   Some current classes with nested unions, e.g. tree_type_symtab
   within tree_type_common within tree_node, might be convertable
   to a class hierarchy that eliminates all unions.  If so, they
   will likely need more than one descriminator. Given that such
   structures can persist with nested unions for some time, this
   issue has low priority.

Given all that, it seems that the highest priority for
gengtype modifications is direct support for non-polymorphic
single-inheritance class hierarchies that are discriminated by tags.
diff mbox

Patch

diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index bf18bae..23cec6b 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -33,19 +33,19 @@  along with GCC; see the file COPYING3.  If not see
  typedef HOST_WIDEST_INT gcov_type;

  /* Control flow edge information.  */
-struct GTY(()) edge_def {
+struct GTY((user)) edge_def {
    /* The two blocks at the ends of the edge.  */
    basic_block src;
    basic_block dest;

    /* Instructions queued on the edge.  */
    union edge_def_insns {
-    gimple_seq GTY ((tag ("true"))) g;
-    rtx GTY ((tag ("false"))) r;
-  } GTY ((desc ("current_ir_type () == IR_GIMPLE"))) insns;
+    gimple_seq g;
+    rtx r;
+  } insns;

    /* Auxiliary info specific to a pass.  */
-  PTR GTY ((skip (""))) aux;
+  PTR aux;

    /* Location of any goto implicit in the edge and associated BLOCK.  */
    tree goto_block;
@@ -65,6 +65,11 @@  DEF_VEC_P(edge);
  DEF_VEC_ALLOC_P(edge,gc);
  DEF_VEC_ALLOC_P(edge,heap);

+/* Garbage collection and PCH support for edge_def.  */
+extern void gt_ggc_mx (edge_def *e);
+extern void gt_pch_nx (edge_def *e);
+extern void gt_pch_nx (edge_def *e, gt_pointer_operator, void *);
+
  /* Masks for edge.flags.  */
  #define DEF_EDGE_FLAG(NAME,IDX) EDGE_##NAME = 1 << IDX ,
  enum cfg_edge_flags {
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index 537acf6..5788a6a 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -108,6 +108,7 @@  EOID	[^[:alnum:]_]
  "enum"/{EOID}			{ return ENUM; }
  "ptr_alias"/{EOID}	  	{ return PTR_ALIAS; }
  "nested_ptr"/{EOID}		{ return NESTED_PTR; }
+"user"/{EOID}			{ return USER_GTY; }
  [0-9]+				{ return NUM; }
  "param"[0-9]*"_is"/{EOID}		{
    *yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1);
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index b213585..03ee781 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -499,6 +499,10 @@  option (options_p prev)
        advance ();
        return nestedptr_optvalue (prev);

+    case USER_GTY:
+      advance ();
+      return create_string_option (prev, "user", "");
+
      default:
        parse_error ("expected an option keyword, have %s", 
print_cur_token ());
        advance ();
@@ -733,6 +737,18 @@  struct_field_seq (void)
    return nreverse_pairs (f);
  }

+/* Return true if OPTS contain the option named STR.  */
+
+static bool
+opts_have (options_p opts, const char *str)
+{
+  for (options_p opt = opts; opt; opt = opt->next)
+    if (strcmp (opt->name, str) == 0)
+      return true;
+  return false;
+}
+
+
  /* This is called type(), but what it parses (sort of) is what C calls
     declaration-specifiers and specifier-qualifier-list:

@@ -805,6 +821,7 @@  type (options_p *optsp, bool nested)

  	if (is_gty)
  	  {
+	    bool is_user_gty = opts_have (opts, "user");
  	    if (token () == '{')
  	      {
  		pair_p fields;
@@ -812,9 +829,20 @@  type (options_p *optsp, bool nested)
  		if (is_gty == GTY_AFTER_ID)
  		  parse_error ("GTY must be specified before identifier");

-		advance ();
-		fields = struct_field_seq ();
-		require ('}');
+		if (!is_user_gty)
+		  {
+		    advance ();
+		    fields = struct_field_seq ();
+		    require ('}');
+		  }
+		else
+		  {
+		    /* Do not look inside user defined structures.  */
+		    fields = NULL;
+		    kind = TYPE_USER_STRUCT;
+		    consume_balanced ('{', '}');
+		  }
+
  		return new_structure (s, kind, &lexer_line, fields, opts);
  	      }
  	  }
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 2ca0e4e..4a178ec 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -463,6 +463,7 @@  enum
      ELLIPSIS,
      PTR_ALIAS,
      NESTED_PTR,
+    USER_GTY,
      PARAM_IS,
      NUM,
      SCALAR,
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e4cf076..b734781 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -7836,3 +7836,54 @@  struct gimple_opt_pass pass_warn_unused_result =
      0,					/* todo_flags_finish */
    }
  };
+
+
+/* Garbage collection support for edge_def.  */
+
+extern void gt_ggc_mx (tree&);
+extern void gt_ggc_mx (gimple&);
+extern void gt_ggc_mx (rtx&);
+extern void gt_ggc_mx (basic_block&);
+
+void
+gt_ggc_mx (edge_def *e)
+{
+  gt_ggc_mx (e->src);
+  gt_ggc_mx (e->dest);
+  if (current_ir_type () == IR_GIMPLE)
+    gt_ggc_mx (e->insns.g);
+  else
+    gt_ggc_mx (e->insns.r);
+  gt_ggc_mx (e->goto_block);
+}
+
+/* PCH support for edge_def.  */
+
+extern void gt_pch_nx (tree&);
+extern void gt_pch_nx (gimple&);
+extern void gt_pch_nx (rtx&);
+extern void gt_pch_nx (basic_block&);
+
+void
+gt_pch_nx (edge_def *e)
+{
+  gt_pch_nx (e->src);
+  gt_pch_nx (e->dest);
+  if (current_ir_type () == IR_GIMPLE)
+    gt_pch_nx (e->insns.g);
+  else
+    gt_pch_nx (e->insns.r);
+  gt_pch_nx (e->goto_block);
+}
+
+void
+gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
+{
+  op (&(e->src), cookie);
+  op (&(e->dest), cookie);
+  if (current_ir_type () == IR_GIMPLE)
+    op (&(e->insns.g), cookie);
+  else
+    op (&(e->insns.r), cookie);
+  op (&(e->goto_block), cookie);
+}