+/* Record the definition of the vec_prefix structure, as defined in vec.h:
+
+ struct vec_prefix GTY(()) {
+ unsigned num;
+ unsigned alloc;
+ }; */
+static type_p
+vec_prefix_type (void)
+{
+ static type_p prefix_type = NULL;
+ if (prefix_type == NULL)
+ {
+ pair_p fields;
+ static struct fileloc pos = { NULL, 0 };
+ type_p len_ty = create_scalar_type ("unsigned");
+ pos.file = input_file_by_name (__FILE__); pos.line = __LINE__;
+ fields = create_field_at (0, len_ty, "alloc", 0, &pos);
+ fields = create_field_at (fields, len_ty, "num", 0, &pos);
+ prefix_type = new_structure ("vec_prefix", 0, &pos, fields, 0);
+ prefix_type->u.s.bitmap = -1;
+ }
+ return prefix_type;
+}
+
+/* Record the definition of a generic VEC structure, as if we had expanded
+ the macros in vec.h:
+
+ typedef struct VEC_<type>_base GTY(()) {
+ struct vec_prefix prefix;
+ <type> GTY((length ("%h.prefix.num"))) vec[1];
+ } VEC_<type>_base
+
+ where the GTY(()) tags are only present if is_scalar is _false_. */
+
+void
+note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos)
+{
+ pair_p fields;
+ type_p t;
+ options_p o;
+ const char *name = concat ("VEC_", type_name, "_base", (char *) 0);
+
+ if (is_scalar)
+ {
+ t = create_scalar_type (type_name);
+ o = 0;
+ }
+ else
+ {
+ t = resolve_typedef (type_name, pos);
+ o = create_string_option (0, "length", "%h.prefix.num");
+ }
+ /* We assemble the field list in reverse order. */
+ fields = create_field_at (0, create_array (t, "1"), "vec", o, pos);
+ fields = create_field_at (fields, vec_prefix_type (), "prefix", 0, pos);
+
+ do_typedef (name, new_structure (name, 0, pos, fields, 0), pos);
+}
+
+/* Record the definition of an allocation-specific VEC structure, as if
+ we had expanded the macros in vec.h:
+
+ typedef struct VEC_<type>_<astrat> {
+ VEC_<type>_base base;
+ } VEC_<type>_<astrat>;
+*/
+void
+note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos)
+{
+ const char *astratname = concat ("VEC_", type, "_", astrat, (char *) 0);
+ const char *basename = concat ("VEC_", type, "_base", (char *) 0);
+
+ pair_p field = create_field_at (0, resolve_typedef (basename, pos),
+ "base", 0, pos);
+
+ 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 into output F 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 (outf_p f,
+ 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)));
+ gcc_assert (f != NULL);
+ oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name);
+ oprintf (f, "(%s%s%s%s%s) ",
+ (variable_size ? "SIZE" : ""),
+ (two_args ? ", " : ""),
+ (quantity == vector) ? "n" : "",
+ (third_arg ? ", " : ""), (zone == specific_zone) ? "z" : "");
+ oprintf (f, "((%s%s *)", type_specifier, type_name);
+ oprintf (f, "(ggc_internal_%salloc_stat (", allocator_type);
+ if (zone == specific_zone)
+ oprintf (f, "z, ");
+ if (variable_size)
+ oprintf (f, "SIZE");
+ else
+ oprintf (f, "sizeof (%s%s)", type_specifier, type_name);
+ if (quantity == vector)
+ oprintf (f, ", n");
+ oprintf (f, " MEM_STAT_INFO)))\n");
+}
+
+/* Writes a typed allocator definition into output F for a struct or
+ union S, with a given ALLOCATOR_TYPE and QUANTITY for ZONE. */
+
+static void
+write_typed_struct_alloc_def (outf_p f,
+ const type_p s, const char *allocator_type,
+ enum alloc_quantity quantity,
+ enum alloc_zone zone)
+{
+ gcc_assert (UNION_OR_STRUCT_P (s));
+ write_typed_alloc_def (f, variable_size_p (s), get_type_specifier (s),
+ s->u.s.tag, allocator_type, quantity, zone);
+}
+
+/* Writes a typed allocator definition into output F for a typedef P,
+ with a given ALLOCATOR_TYPE and QUANTITY for ZONE. */
+
+static void
+write_typed_typedef_alloc_def (outf_p f,
+ const pair_p p, const char *allocator_type,
+ enum alloc_quantity quantity,
+ enum alloc_zone zone)
+{
+ write_typed_alloc_def (f, variable_size_p (p->type), "", p->name,
+ allocator_type, quantity, zone);
+}
+
+/* Writes typed allocator definitions into output F for the types in
+ STRUCTURES and TYPEDEFS that are used by GC. */
+
+static void
+write_typed_alloc_defns (outf_p f,
+ const type_p structures, const pair_p typedefs)
+{
+ type_p s;
+ pair_p p;
+
+ gcc_assert (f != NULL);
+ oprintf (f,
+ "\n/* Allocators for known structs and unions. */\n\n");
+ for (s = structures; s; s = s->next)
+ {
+ if (!USED_BY_TYPED_GC_P (s))
+ continue;
+ gcc_assert (UNION_OR_STRUCT_P (s));
+ /* In plugin mode onput output ggc_alloc macro definitions
+ relevant to plugin input files. */
+ if (nb_plugin_files > 0
+ && ((s->u.s.line.file == NULL) || !s->u.s.line.file->inpisplugin))
+ continue;
+ write_typed_struct_alloc_def (f, s, "", single, any_zone);
+ write_typed_struct_alloc_def (f, s, "cleared_", single, any_zone);
+ write_typed_struct_alloc_def (f, s, "vec_", vector, any_zone);
+ write_typed_struct_alloc_def (f, s, "cleared_vec_", vector, any_zone);
+ write_typed_struct_alloc_def (f, s, "zone_", single, specific_zone);
+ write_typed_struct_alloc_def (f, s, "zone_cleared_", single,
+ specific_zone);
+ write_typed_struct_alloc_def (f, s, "zone_vec_", vector, specific_zone);
+ write_typed_struct_alloc_def (f, s, "zone_cleared_vec_", vector,
+ specific_zone);
+ }
+
+ oprintf (f, "\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;
+ /* In plugin mode onput output ggc_alloc macro definitions
+ relevant to plugin input files. */
+ if (nb_plugin_files > 0)
+ {
+ struct fileloc* filoc = type_fileloc(s);
+ if (!filoc || !filoc->file->inpisplugin)
+ continue;
+ };
+ write_typed_typedef_alloc_def (f, p, "", single, any_zone);
+ write_typed_typedef_alloc_def (f, p, "cleared_", single, any_zone);
+ write_typed_typedef_alloc_def (f, p, "vec_", vector, any_zone);
+ write_typed_typedef_alloc_def (f, p, "cleared_vec_", vector, any_zone);
+ write_typed_typedef_alloc_def (f, p, "zone_", single, specific_zone);
+ write_typed_typedef_alloc_def (f, p, "zone_cleared_", single,
+ specific_zone);
+ write_typed_typedef_alloc_def (f, 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_with_visibility (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);
+
+#define INDENT 2
+
+/* Dumps the value of typekind KIND. */
+
+static void
+dump_typekind (int indent, enum typekind kind)
+{
+ printf ("%*ckind = ", indent, ' ');
+ switch (kind)
+ {
+ case TYPE_SCALAR:
+ printf ("TYPE_SCALAR");
+ break;
+ case TYPE_STRING:
+ printf ("TYPE_STRING");
+ break;
+ case TYPE_STRUCT:
+ printf ("TYPE_STRUCT");
+ break;
+ case TYPE_UNION:
+ printf ("TYPE_UNION");
+ break;
+ case TYPE_POINTER:
+ printf ("TYPE_POINTER");
+ break;
+ case TYPE_ARRAY:
+ printf ("TYPE_ARRAY");
+ break;
+ case TYPE_LANG_STRUCT:
+ printf ("TYPE_LANG_STRUCT");
+ break;
+ case TYPE_PARAM_STRUCT:
+ printf ("TYPE_PARAM_STRUCT");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ printf ("\n");
+}
+
+/* Dumps the value of GC_USED flag. */
+
+static void
+dump_gc_used (int indent, enum gc_used_enum gc_used)
+{
+ printf ("%*cgc_used = ", indent, ' ');
+ switch (gc_used)
+ {
+ case GC_UNUSED:
+ printf ("GC_UNUSED");
+ break;
+ case GC_USED:
+ printf ("GC_USED");
+ break;
+ case GC_MAYBE_POINTED_TO:
+ printf ("GC_MAYBE_POINTED_TO");
+ break;
+ case GC_POINTED_TO:
+ printf ("GC_POINTED_TO");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ printf ("\n");
+}
+
+/* Dumps the type options OPT. */
+
+static void
+dump_options (int indent, options_p opt)
+{
+ options_p o;
+ printf ("%*coptions = ", indent, ' ');
+ o = opt;
+ while (o)
+ {
+ switch (o->kind)
+ {
+ case OPTION_STRING:
+ printf ("%s:string %s ", o->name, o->info.string);
+ break;
+ case OPTION_TYPE:
+ printf ("%s:type ", o->name);
+ dump_type (indent+1, o->info.type);
+ break;
+ case OPTION_NESTED:
+ printf ("%s:nested ", o->name);
+ break;
+ case OPTION_NONE:
+ gcc_unreachable ();
+ }
+ o = o->next;
+ }
+ printf ("\n");
+}
+
+/* Dumps the source file location in LINE. */
+
+static void
+dump_fileloc (int indent, struct fileloc line)
+{
+ printf ("%*cfileloc: file = %s, line = %d\n", indent, ' ',
+ get_input_file_name (line.file),
+ line.line);
+}
+
+/* Recursively dumps the struct, union, or a language-specific
+ struct T. */
+
+static void
+dump_type_u_s (int indent, type_p t)
+{
+ pair_p fields;
+
+ gcc_assert (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION
+ || t->kind == TYPE_LANG_STRUCT);
+ printf ("%*cu.s.tag = %s\n", indent, ' ', t->u.s.tag);
+ dump_fileloc (indent, t->u.s.line);
+ printf ("%*cu.s.fields =\n", indent, ' ');
+ fields = t->u.s.fields;
+ while (fields)
+ {
+ dump_pair (indent + INDENT, fields);
+ fields = fields->next;
+ }
+ printf ("%*cend of fields of type %p\n", indent, ' ', (void *) t);
+ dump_options (indent, t->u.s.opt);
+ printf ("%*cu.s.bitmap = %X\n", indent, ' ', t->u.s.bitmap);
+ if (t->kind == TYPE_LANG_STRUCT)
+ {
+ printf ("%*cu.s.lang_struct:\n", indent, ' ');
+ dump_type_list (indent + INDENT, t->u.s.lang_struct);
+ }
+}
+
+/* Recursively dumps the array T. */
+
+static void
+dump_type_u_a (int indent, type_p t)
+{
+ gcc_assert (t->kind == TYPE_ARRAY);
+ printf ("%*clen = %s, u.a.p:\n", indent, ' ', t->u.a.len);
+ dump_type_list (indent + INDENT, t->u.a.p);
+}
+
+/* Recursively dumps the parameterized struct T. */
+
+static void
+dump_type_u_param_struct (int indent, type_p t)
+{
+ int i;
+ gcc_assert (t->kind == TYPE_PARAM_STRUCT);
+ printf ("%*cu.param_struct.stru:\n", indent, ' ');
+ dump_type_list (indent, t->u.param_struct.stru);
+ dump_fileloc (indent, t->u.param_struct.line);
+ for (i = 0; i < NUM_PARAM; i++)
+ {
+ if (t->u.param_struct.param[i] == NULL)
+ continue;
+ printf ("%*cu.param_struct.param[%d]:\n", indent, ' ', i);
+ dump_type (indent + INDENT, t->u.param_struct.param[i]);
+ }
+}
+
+/* Recursively dumps the type list T. */
+
+static void
+dump_type_list (int indent, type_p t)
+{
+ type_p p = t;
+ while (p)
+ {
+ dump_type (indent, p);
+ p = p->next;
+ }
+}
+
+static htab_t seen_types;
+
+/* Recursively dumps the type T if it was not dumped previously. */
+
+static void
+dump_type (int indent, type_p t)
+{
+ PTR *slot;
+
+ printf ("%*cType at %p: ", indent, ' ', (void *) t);
+ slot = htab_find_slot (seen_types, t, INSERT);
+ if (*slot != NULL)
+ {
+ printf ("already seen.\n");
+ return;
+ }
+ *slot = t;
+ printf ("\n");
+
+ dump_typekind (indent, t->kind);
+ printf ("%*cpointer_to = %p\n", indent + INDENT, ' ',
+ (void *) t->pointer_to);
+ dump_gc_used (indent + INDENT, t->gc_used);
+ switch (t->kind)
+ {
+ case TYPE_SCALAR:
+ printf ("%*cscalar_is_char = %s\n", indent + INDENT, ' ',
+ t->u.scalar_is_char ? "true" : "false");
+ break;
+ case TYPE_STRING:
+ break;
+ case TYPE_STRUCT:
+ case TYPE_UNION:
+ case TYPE_LANG_STRUCT:
+ dump_type_u_s (indent + INDENT, t);
+ break;
+ case TYPE_POINTER:
+ printf ("%*cp:\n", indent + INDENT, ' ');
+ dump_type (indent + INDENT, t->u.p);
+ break;
+ case TYPE_ARRAY:
+ dump_type_u_a (indent + INDENT, t);
+ break;
+ case TYPE_PARAM_STRUCT:
+ dump_type_u_param_struct (indent + INDENT, t);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ printf ("%*cEnd of type at %p\n", indent, ' ', (void *) t);
+}
+
+/* Dumps the pair P. */
+
+static void
+dump_pair (int indent, pair_p p)
+{
+ printf ("%*cpair: name = %s\n", indent, ' ', p->name);
+ dump_type (indent, p->type);
+ dump_fileloc (indent, p->line);
+ dump_options (indent, p->opt);
+ printf ("%*cEnd of pair %s\n", indent, ' ', p->name);
+}
+
+/* Dumps the list of pairs PP. */
+
+static void
+dump_pair_list (const char *name, pair_p pp)
+{
+ pair_p p;
+ printf ("%s:\n", name);
+ for (p = pp; p != NULL; p = p->next)
+ dump_pair (0, p);
+ printf ("End of %s\n\n", name);
+}
+
+/* Dumps the STRUCTURES. */
+
+static void
+dump_structures (const char *name, type_p structures)
+{
+ printf ("%s:\n", name);
+ dump_type_list (0, structures);
+ printf ("End of %s\n\n", name);
+}
+
+/* Dumps the internal structures of gengtype. This is useful to debug
+ gengtype itself, or to understand what it does, e.g. for plugin
+ developers. */
+
+static void
+dump_everything (void)
+{
+ seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL);
+ dump_pair_list ("typedefs", typedefs);
+ dump_structures ("structures", structures);
+ dump_structures ("param_structs", param_structs);
+ dump_pair_list ("variables", variables);
+ htab_delete (seen_types);
+}
+\f
+
+
+/* Option specification for getopt_long. */
+static const struct option gengtype_long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"dump", no_argument, NULL, 'd'},
+ {"debug", no_argument, NULL, 'D'},
+ {"plugin", required_argument, NULL, 'P'},
+ {"srcdir", required_argument, NULL, 'S'},
+ {"backupdir", required_argument, NULL, 'B'},
+ {"inputs", required_argument, NULL, 'I'},
+ {"read-state", required_argument, NULL, 'r'},
+ {"write-state", required_argument, NULL, 'w'},
+ /* Terminating NULL placeholder. */
+ {NULL, no_argument, NULL, 0},
+};
+
+
+static void
+print_usage (void)
+{
+ printf ("Usage: %s\n", progname);
+ printf ("\t -h | --help " " \t# Give this help.\n");
+ printf ("\t -D | --debug "
+ " \t# Give debug output to debug %s itself.\n", progname);
+ printf ("\t -V | --version " " \t# Give version information.\n");
+ printf ("\t -v | --verbose \t# Increase verbosity. Can be given several times.\n");
+ printf ("\t -d | --dump " " \t# Dump state for debugging.\n");
+ printf ("\t -P | --plugin <output-file> <plugin-src> ... "
+ " \t# Generate for plugin.\n");
+ printf ("\t -S | --srcdir <GCC-directory> "
+ " \t# Specify the GCC source directory.\n");
+ printf ("\t -B | --backupdir <directory> "
+ " \t# Specify the backup directory for updated files.\n");
+ printf ("\t -I | --inputs <input-list> "
+ " \t# Specify the file with source files list.\n");
+ printf ("\t -w | --write-state <state-file> " " \t# Write a state file.\n");
+ printf ("\t -r | --read-state <state-file> " " \t# Read a state file.\n");
+}
+
+static void
+print_version (void)
+{
+ printf ("%s %s%s\n", progname, pkgversion_string, version_string);
+ printf ("Report bugs: %s\n", bug_report_url);
+}
+
+/* Parse the program options using getopt_long... */
+static void
+parse_program_options (int argc, char **argv)
+{
+ int opt = -1;
+ while ((opt = getopt_long (argc, argv, "hVvdP:S:B:I:w:r:D",
+ gengtype_long_options, NULL)) >= 0)
+ {
+ switch (opt)
+ {
+ case 'h': /* --help */
+ print_usage ();
+ break;
+ case 'V': /* --version */
+ print_version ();
+ break;
+ case 'd': /* --dump */
+ do_dump = 1;
+ break;
+ case 'D': /* --debug */
+ do_debug = 1;
+ break;
+ case 'v': /* --verbose */
+ verbosity_level++;
+ break;
+ case 'P': /* --plugin */
+ if (optarg)
+ plugin_output_filename = optarg;
+ else
+ fatal ("missing plugin output file name");
+ break;
+ case 'S': /* --srcdir */
+ if (optarg)
+ srcdir = optarg;
+ else
+ fatal ("missing source directory");
+ srcdir_len = strlen (srcdir);
+ break;
+ case 'B': /* --backupdir */
+ if (optarg)
+ backup_dir = optarg;
+ else
+ fatal ("missing backup directory");
+ break;
+ case 'I': /* --inputs */
+ if (optarg)
+ inputlist = optarg;
+ else
+ fatal ("missing input list");
+ break;
+ case 'r': /* --read-state */
+ if (optarg)
+ read_state_filename = optarg;
+ else
+ fatal ("missing read state file");
+ DBGPRINTF ("read state %s\n", optarg);
+ break;
+ case 'w': /* --write-state */
+ DBGPRINTF ("write state %s\n", optarg);
+ if (optarg)
+ write_state_filename = optarg;
+ else
+ fatal ("missing write state file");
+ break;
+ default:
+ fprintf (stderr, "%s: unknown flag '%c'\n", progname, opt);
+ print_usage ();
+ fatal ("unexpected flag");
+ }
+ };
+ if (plugin_output_filename)
+ {
+ /* In plugin mode we require some input files. */
+ int i = 0;
+ if (optind >= argc)
+ fatal ("no source files given in plugin mode");
+ nb_plugin_files = argc - optind;
+ plugin_files = XNEWVEC (input_file*, nb_plugin_files);
+ for (i = 0; i < (int) nb_plugin_files; i++)
+ {
+ char *name = argv[i + optind];
+ plugin_files[i] = input_file_by_name (name);
+ }
+ }
+}
+