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