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

Diego Novillo dnovillo@google.com
Fri Aug 10 15:07:00 GMT 2012


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.

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);
+}



More information about the Gcc-patches mailing list