This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] gc-improv merge (2/n): make gengtype output typed allocators


This contains the gengtype changes:
1) To accept a new GTY option "variable_size" for types where knowing
the type is not enough to know the number of bytes that needto be
allocated
2) To output all kinds of typed allocators.

The sample output for a simple type, from gtype-desc.h:

#define ggc_alloc_string_descriptor() ((struct string_descriptor
*)(ggc_internal_alloc_stat (sizeof (struct string_descriptor)
MEM_STAT_INFO)))
#define ggc_alloc_cleared_string_descriptor() ((struct
string_descriptor *)(ggc_internal_cleared_alloc_stat (sizeof (struct
string_descriptor) MEM_STAT_INFO)))
#define ggc_alloc_vec_string_descriptor(n) ((struct string_descriptor
*)(ggc_internal_vec_alloc_stat (sizeof (struct string_descriptor), n
MEM_STAT_INFO)))
#define ggc_alloc_cleared_vec_string_descriptor(n) ((struct
string_descriptor *)(ggc_internal_cleared_vec_alloc_stat (sizeof
(struct string_descriptor), n MEM_STAT_INFO)))
#define ggc_alloc_zone_string_descriptor(z) ((struct string_descriptor
*)(ggc_internal_zone_alloc_stat (z, sizeof (struct string_descriptor)
MEM_STAT_INFO)))
#define ggc_alloc_zone_cleared_string_descriptor(z) ((struct
string_descriptor *)(ggc_internal_zone_cleared_alloc_stat (z, sizeof
(struct string_descriptor) MEM_STAT_INFO)))
#define ggc_alloc_zone_vec_string_descriptor(n, z) ((struct
string_descriptor *)(ggc_internal_zone_vec_alloc_stat (z, sizeof
(struct string_descriptor), n MEM_STAT_INFO)))
#define ggc_alloc_zone_cleared_vec_string_descriptor(n, z) ((struct
string_descriptor *)(ggc_internal_zone_cleared_vec_alloc_stat (z,
sizeof (struct string_descriptor), n MEM_STAT_INFO)))

This output shows the following types of allocators:
1) ggc_alloc_foo () - simple allocator
2) ggc_alloc_cleared_foo () - additionally clears the allocated memory
3) ggc_alloc_vec_foo (n) - allocates array for n instances of foo
4) ggc_alloc_cleared_vec_foo (n) - additionally clears the allocated memory
5) ggc_alloc_zone_foo (z) - allocates in the specified zone
6) to 8) - correspond to 2) to 5) with zone allocation.

The types that are annotated with variable_size GTY annotation receive
allocators that take an extra size parameter.

The types that are to be referenced from hash tables or splay trees
additionally get callback allocators:
gtype-desc.h:
extern void * ggc_alloc_splay_tree_scalar_scalar_splay_tree_node_s
(int, void *);
gtype-desc.c:
void * ggc_alloc_splay_tree_scalar_scalar_splay_tree_node_s (int sz, void * nl)
{
  return ggc_splay_alloc (gt_e_II17splay_tree_node_s, sz, nl);
}

with automatically-generated names that try to include the names of
types in question but be more readable than the other gengtype
automatically-generated names such as
gt_pch_p_P16var_loc_list_def4htab. The reason for this is that these
callbacks will have to be specified manually:

superset_entry->children
        = splay_tree_new_ggc (splay_tree_compare_ints,
                              ggc_alloc_splay_tree_scalar_scalar_splay_tree_s,

ggc_alloc_splay_tree_scalar_scalar_splay_tree_node_s);

Such names as ggc_alloc_splay_tree_scalar_scalar_splay_tree_node_s
will not win beauty contests, but I don't have a better idea how to
name callbacks automatically.

The implementations of these generated macros and functions depend on
the other patches in the merge.

Tested on x86_64/linux and many others.

2010-05-06  Laurynas Biveinis  <laurynas.biveinis@gmail.com>

	* gentype.c: Update copyright year.
	(walk_type): Accept variable_size GTY option.
	(USED_BY_TYPED_GC_P): New macro.
	(write_enum_defn): Use USED_BY_TYPED_GC_P.  Do not output
	whitespace at the end of strings.
	(get_type_specifier, variable_size_p): New functions.
	(alloc_quantity, alloc_zone): New enums.
	(write_typed_alloc_def): New function.
	(write_typed_struct_alloc_def): Likewise.
	(write_typed_typed_typedef_alloc_def): Likewise.
	(write_typed_alloc_defns): Likewise.
	(output_typename, write_splay_tree_allocator_def): Likewise.
	(write_splay_tree_allocators): Likewise.
	(main): Call write_typed_alloc_defns and
	write_splay_tree_allocators.

-- 
Laurynas
diff -r -u -x .svn gcc-trunk/gcc/gcc/gengtype.c gcc-gc-improv/gcc/gcc/gengtype.c
--- gcc-trunk/gcc/gcc/gengtype.c	2010-05-05 11:58:30.000000000 +0200
+++ gcc-gc-improv/gcc/gcc/gengtype.c	2010-05-06 13:12:47.000000000 +0200
@@ -2084,6 +2083,8 @@
       ;
     else if (strcmp (oo->name, "reorder") == 0)
       ;
+    else if (strcmp (oo->name, "variable_size") == 0)
+      ;
     else
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
 
@@ -3022,6 +3023,20 @@
       }
 }
 
+/* Nonzero if S is a type for which typed GC allocators should be output.  */
+
+#define USED_BY_TYPED_GC_P(s)						\
+  (((s->kind == TYPE_POINTER)						\
+    && ((s->u.p->gc_used == GC_POINTED_TO)				\
+	|| (s->u.p->gc_used == GC_USED)))				\
+   || (UNION_OR_STRUCT_P (s) &&						\
+       (((s)->gc_used == GC_POINTED_TO)					\
+	|| ((s)->gc_used == GC_MAYBE_POINTED_TO				\
+	    && s->u.s.line.file != NULL)				\
+	|| ((s)->gc_used == GC_USED					\
+	    && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))))))
+
+
 /* Write out the 'enum' definition for gt_types_enum.  */
 
 static void
@@ -3034,23 +3049,18 @@
   oprintf (header_file, "\n/* Enumeration of types known.  */\n");
   oprintf (header_file, "enum gt_types_enum {\n");
   for (s = structures; s; s = s->next)
-    if (s->gc_used == GC_POINTED_TO
-	|| s->gc_used == GC_MAYBE_POINTED_TO)
+    if (USED_BY_TYPED_GC_P (s))
       {
-	if (s->gc_used == GC_MAYBE_POINTED_TO
-	    && s->u.s.line.file == NULL)
-	  continue;
-
 	oprintf (header_file, " gt_ggc_e_");
 	output_mangled_typename (header_file, s);
-	oprintf (header_file, ", \n");
+	oprintf (header_file, ",\n");
       }
   for (s = param_structs; s; s = s->next)
     if (s->gc_used == GC_POINTED_TO)
       {
 	oprintf (header_file, " gt_e_");
 	output_mangled_typename (header_file, s);
-	oprintf (header_file, ", \n");
+	oprintf (header_file, ",\n");
       }
   oprintf (header_file, " gt_types_enum_last\n");
   oprintf (header_file, "};\n");
@@ -3697,14 +3707,219 @@
   do_typedef (astratname, new_structure (astratname, 0, pos, field, 0), pos);
 }
 
+/* Returns the specifier keyword for a string or union type S, empty string
+   otherwise.  */
+
+static const char *
+get_type_specifier (const type_p s)
+{
+  if (s->kind == TYPE_STRUCT || s->kind == TYPE_LANG_STRUCT)
+    return "struct ";
+  if (s->kind == TYPE_UNION)
+    return "union ";
+  return "";
+}
+
+/* TRUE if type S has the GTY variable_size annotation.  */
+
+static bool
+variable_size_p (const type_p s)
+{
+  options_p o;
+  for (o = s->u.s.opt; o; o = o->next)
+    if (strcmp (o->name, "variable_size") == 0)
+      return true;
+  return false;
+}
+
+enum alloc_quantity { single, vector };
+enum alloc_zone { any_zone, specific_zone };
+
+/* Writes one typed allocator definition for type identifier TYPE_NAME with
+   optional type specifier TYPE_SPECIFIER.  The allocator name will contain
+   ALLOCATOR_TYPE.  If VARIABLE_SIZE is true, the allocator will have an extra
+   parameter specifying number of bytes to allocate.  If QUANTITY is set to
+   VECTOR, a vector allocator will be output, if ZONE is set to SPECIFIC_ZONE,
+   the allocator will be zone-specific.  */
+
+static void
+write_typed_alloc_def (bool variable_size, const char * type_specifier,
+		       const char * type_name, const char * allocator_type,
+		       enum alloc_quantity quantity, enum alloc_zone zone)
+{
+  bool two_args = variable_size && (quantity == vector);
+  bool third_arg = (zone == specific_zone) && (variable_size
+					       || (quantity == vector));
+
+  oprintf (header_file, "#define ggc_alloc_%s%s",allocator_type, type_name);
+  oprintf (header_file, "(%s%s%s%s%s) ",
+	   (variable_size ? "SIZE" : ""),
+	   (two_args ? ", " : ""),
+	   (quantity == vector) ? "n" : "",
+	   (third_arg ? ", " : ""), (zone == specific_zone) ? "z" : "");
+  oprintf (header_file, "((%s%s *)", type_specifier, type_name);
+  oprintf (header_file, "(ggc_internal_%salloc_stat (", allocator_type);
+  if (zone == specific_zone)
+    oprintf (header_file, "z, ");
+  if (variable_size)
+    oprintf (header_file, "SIZE");
+  else
+    oprintf (header_file, "sizeof (%s%s)", type_specifier, type_name);
+  if (quantity == vector)
+    oprintf (header_file, ", n");
+  oprintf (header_file, " MEM_STAT_INFO)))\n");
+}
+
+/* Writes a typed allocator definition for a struct or union S.  */
+
+static void
+write_typed_struct_alloc_def (const type_p s, const char * allocator_type,
+			      enum alloc_quantity quantity,
+			      enum alloc_zone zone)
+{
+  write_typed_alloc_def (variable_size_p (s), get_type_specifier (s),
+			 s->u.s.tag, allocator_type, quantity, zone);
+}
+
+/* Writes a typed allocator definition for a typedef P.  */
+
+static void
+write_typed_typedef_alloc_def (const pair_p p, const char * allocator_type,
+			       enum alloc_quantity quantity,
+			       enum alloc_zone zone)
+{
+  write_typed_alloc_def (variable_size_p (p->type), "", p->name,
+			 allocator_type, quantity, zone);
+}
+
+/* Writes typed allocator definitions for the types in STRUCTURES and
+   TYPEDEFS that are used by GC.  */
+
+static void
+write_typed_alloc_defns (const type_p structures, const pair_p typedefs)
+{
+  type_p s;
+  pair_p p;
+
+  oprintf (header_file,
+	   "\n/* Allocators for known structs and unions.  */\n\n");
+  for (s = structures; s; s = s->next)
+    {
+      if (!USED_BY_TYPED_GC_P (s))
+	continue;
+      write_typed_struct_alloc_def (s, "", single, any_zone);
+      write_typed_struct_alloc_def (s, "cleared_", single, any_zone);
+      write_typed_struct_alloc_def (s, "vec_", vector, any_zone);
+      write_typed_struct_alloc_def (s, "cleared_vec_", vector, any_zone);
+      write_typed_struct_alloc_def (s, "zone_", single, specific_zone);
+      write_typed_struct_alloc_def (s, "zone_cleared_", single,
+				    specific_zone);
+      write_typed_struct_alloc_def (s, "zone_vec_", vector, specific_zone);
+      write_typed_struct_alloc_def (s, "zone_cleared_vec_", vector,
+				    specific_zone);
+    }
+
+  oprintf (header_file, "\n/* Allocators for known typedefs.  */\n");
+  for (p = typedefs; p; p = p->next)
+    {
+      s = p->type;
+      if (!USED_BY_TYPED_GC_P (s) || (strcmp (p->name, s->u.s.tag) == 0))
+	continue;
+      write_typed_typedef_alloc_def (p, "", single, any_zone);
+      write_typed_typedef_alloc_def (p, "cleared_", single, any_zone);
+      write_typed_typedef_alloc_def (p, "vec_", vector, any_zone);
+      write_typed_typedef_alloc_def (p, "cleared_vec_", vector, any_zone);
+      write_typed_typedef_alloc_def (p, "zone_", single, specific_zone);
+      write_typed_typedef_alloc_def (p, "zone_cleared_", single,
+				     specific_zone);
+      write_typed_typedef_alloc_def (p, "zone_cleared_vec_", vector,
+				     specific_zone);
+    }
+}
+
+/* Prints not-as-ugly version of a typename of T to OF.  Trades the uniquness
+   guaranteee for somewhat increased readability.  If name conflicts do happen,
+   this funcion will have to be adjusted to be more like
+   output_mangled_typename.  */
+
+static void
+output_typename (outf_p of, const_type_p t)
+{
+  switch (t->kind)
+    {
+    case TYPE_STRING:
+      oprintf (of, "str");
+      break;
+    case TYPE_SCALAR:
+      oprintf (of, "scalar");
+      break;
+    case TYPE_POINTER:
+      output_typename (of, t->u.p);
+      break;
+    case TYPE_STRUCT:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
+      oprintf (of, "%s", t->u.s.tag);
+      break;
+    case TYPE_PARAM_STRUCT:
+      {
+	int i;
+	for (i = 0; i < NUM_PARAM; i++)
+	  if (t->u.param_struct.param[i] != NULL) {
+	    output_typename (of, t->u.param_struct.param[i]);
+	    oprintf (of, "_");
+	  }
+	output_typename (of, t->u.param_struct.stru);
+	break;
+      }
+    default:
+      gcc_unreachable();
+    }
+}
+
+/*  Writes a typed GC allocator for type S that is suitable as a callback for
+    the splay tree implementation in libiberty.  */
+
+static void
+write_splay_tree_allocator_def (const_type_p s)
+{
+  outf_p of = get_output_file_for_structure(s, NULL);
+  oprintf (of, "void * ggc_alloc_splay_tree_");
+  output_typename (of, s);
+  oprintf (of, " (int sz, void * nl)\n");
+  oprintf (of, "{\n");
+  oprintf (of, "  return ggc_splay_alloc (");
+  oprintf (of, "gt_e_");
+  output_mangled_typename (of, s);
+  oprintf (of, ", sz, nl);\n");
+  oprintf (of, "}\n\n");
+}
+
+/* Writes typed GC allocators for PARAM_STRUCTS that are suitable as callbacks
+   for the splay tree implementation in libiberty.  */
+
+static void
+write_splay_tree_allocators (const_type_p param_structs)
+{
+  const_type_p s;
+
+  oprintf (header_file, "\n/* Splay tree callback allocators.  */\n");
+  for (s = param_structs; s; s = s->next)
+    if (s->gc_used == GC_POINTED_TO)
+      {
+	oprintf (header_file, "extern void * ggc_alloc_splay_tree_");
+	output_typename (header_file, s);
+	oprintf (header_file, " (int, void *);\n");
+	write_splay_tree_allocator_def (s);
+      }
+}
+
 static void dump_pair (int indent, pair_p p);
 static void dump_type (int indent, type_p p);
 static void dump_type_list (int indent, type_p p);
@@ -4017,6 +4213,7 @@
 
   open_base_files ();
   write_enum_defn (structures, param_structs);
+  write_typed_alloc_defns (structures, typedefs);
   output_header = plugin_output ? plugin_output : header_file;
   write_types (output_header, structures, param_structs, &ggc_wtd);
   if (plugin_files == NULL)
@@ -4024,6 +4221,7 @@
       write_types (header_file, structures, param_structs, &pch_wtd);
       write_local (header_file, structures, param_structs);
     }
+  write_splay_tree_allocators (param_structs);
   write_roots (variables, plugin_files == NULL);
   write_rtx_next ();
   close_output_files ();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]