From patchwork Wed Nov 3 22:09:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 70077 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id BC2B6B70A5 for ; Thu, 4 Nov 2010 09:09:47 +1100 (EST) Received: (qmail 32506 invoked by alias); 3 Nov 2010 22:09:46 -0000 Received: (qmail 32495 invoked by uid 22791); 3 Nov 2010 22:09:43 -0000 X-SWARE-Spam-Status: No, hits=-2.1 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CP, TW_FN, TW_GD, TW_GV, TW_GX, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Nov 2010 22:09:35 +0000 Received: from hpaq3.eem.corp.google.com (hpaq3.eem.corp.google.com [172.25.149.3]) by smtp-out.google.com with ESMTP id oA3M9WAh020010 for ; Wed, 3 Nov 2010 15:09:32 -0700 Received: from pzk7 (pzk7.prod.google.com [10.243.19.135]) by hpaq3.eem.corp.google.com with ESMTP id oA3M9TDT018722 for ; Wed, 3 Nov 2010 15:09:30 -0700 Received: by pzk7 with SMTP id 7so81184pzk.15 for ; Wed, 03 Nov 2010 15:09:29 -0700 (PDT) Received: by 10.142.164.4 with SMTP id m4mr7464255wfe.184.1288822169529; Wed, 03 Nov 2010 15:09:29 -0700 (PDT) Received: from coign.google.com (dhcp-172-22-125-232.mtv.corp.google.com [172.22.125.232]) by mx.google.com with ESMTPS id y42sm14304486wfd.10.2010.11.03.15.09.27 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 03 Nov 2010 15:09:27 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org Subject: PATCH RFA: Add -ggo option Date: Wed, 03 Nov 2010 15:09:26 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch adds a -ggo option to gcc. This option is used when building the Go library. The Go library calls libc functions directly, which means that it needs to know the layout of structures like stat and the size of types like uid_t. I implemented this by adding a -ggo option to gcc which generates debugging information as Go language comments in the assembler file. The shell script mksysinfo.sh in the libgo library uses that like this: ${CC} -D_GNU_SOURCE -ggo -S -o sysinfo.s sysinfo.c where sysinfo.c is just a list of #include statements. The script then greps the sysinfo.s file to extract the generated Go language comments. This is certainly the most intrusive Go-specific patch to the rest of the compiler, and it's not really all that intrusive. It's almost all middle-end, so I don't necessarily require approval for it, but I would like people to take a look. I may technically require approval for the changes to the C frontend and the Java frontend, although they are very minor. Ian gcc/ChangeLog: 2010-11-03 Ian Lance Taylor * goout.c: New file. * common.opt (ggo): New option. * flag-types.h (enum debug_info_type): Add GO_DEBUG. * opts.c (common_handle_option): Handle OPT_ggo. * toplev.c (debug_type_names): Add "go". (process_options): Handle write_symbols == GO_DEBUG. * debug.h (go_debug_hooks): Declare. * doc/invoke.texi (Option Summary): Mention -ggo. (Debugging Options): Document -ggo. * Makefile.in (OBJS-common): Add goout.o. (goout.o): New target. (GTFILES): Add $(srcdir)/goout.c. gcc/c-family/ChangeLog: 2010-11-03 Ian Lance Taylor * c-lex.c (init_c_lex): Handle write_symbols == GO_DEBUG. gcc/java/ChangeLog: 2010-11-03 Ian Lance Taylor * jvspec.c (lang_specific_driver): Handle OPT_ggo. Index: goout.c =================================================================== --- goout.c (revision 0) +++ goout.c (revision 0) @@ -0,0 +1,773 @@ +/* Output Go language descriptions of types. + Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +/* This file is used during the build process to emit Go language + descriptions of declarations from C header files. It uses the + debug info hooks to emit the descriptions. The Go language + descriptions then become part of the Go runtime support + library. + + All global names are output with a leading underscore, so that they + are all hidden in Go. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "ggc.h" +#include "pointer-set.h" +#include "output.h" +#include "debug.h" + +/* A queue of decls to output. */ + +static GTY(()) tree queue; + +/* A hash table of macros we have seen. Using macro_hash_node is + awkward but I don't know how to avoid it for the GTY machinery. */ + +struct GTY(()) macro_hash_node +{ + char *name; +}; + +struct GTY(()) goout_container +{ + /* DECLs that we have already seen. */ + struct pointer_set_t *decls_seen; + + /* Types which may potentially have to be defined as dummy + types. */ + struct pointer_set_t *pot_dummy_types; + + /* Go keywords. */ + htab_t keyword_hash; + + /* Global type definitions. */ + htab_t type_hash; +}; + +static GTY ((param_is (struct macro_hash_node))) htab_t macro_hash; + +#ifdef GO_DEBUGGING_INFO + +/* For the macro hash table. */ + +static hashval_t +macro_hash_hash (const void *x) +{ + return htab_hash_string (((const struct macro_hash_node *) x)->name); +} + +static int +macro_hash_eq (const void *x1, const void *x2) +{ + return strcmp ((((const struct macro_hash_node *) x1)->name), + (const char *) x2) == 0; +} + +/* Initialize. */ + +static void +go_init (const char *filename ATTRIBUTE_UNUSED) +{ + macro_hash = htab_create (100, macro_hash_hash, macro_hash_eq, NULL); +} + +/* A macro definition. */ + +static void +go_define (unsigned int lineno ATTRIBUTE_UNUSED, const char *buffer) +{ + const char *p; + const char *name_end; + char *out_buffer; + char *q; + char *copy; + void **slot; + + /* Skip macro functions. */ + for (p = buffer; *p != '\0' && *p != ' '; ++p) + if (*p == '(') + return; + + if (*p == '\0') + return; + + name_end = p; + + ++p; + if (*p == '\0') + return; + + copy = XNEWVEC (char, name_end - buffer + 1); + memcpy (copy, buffer, name_end - buffer); + copy[name_end - buffer] = '\0'; + + slot = htab_find_slot_with_hash (macro_hash, copy, htab_hash_string (copy), + NO_INSERT); + if (slot != NULL) + { + XDELETEVEC (copy); + return; + } + + /* For simplicity, we force all names to be hidden by adding an + initial underscore, and let the user undo this as needed. */ + out_buffer = XNEWVEC (char, strlen (p) * 2 + 1); + q = out_buffer; + while (*p != '\0') + { + if (ISALPHA (*p) || *p == '_') + { + const char *start; + char *n; + + start = p; + while (ISALNUM (*p) || *p == '_') + ++p; + n = (char *) alloca (p - start + 1); + memcpy (n, start, p - start); + n[p - start] = '\0'; + slot = htab_find_slot_with_hash (macro_hash, n, + htab_hash_string (n), + NO_INSERT); + if (slot == NULL + || ((struct macro_hash_node *) *slot)->name == NULL) + { + /* This is a reference to a name which was not defined + as a macro. */ + fprintf (asm_out_file, "#GO unknowndefine %s\n", buffer); + return; + } + + *q++ = '_'; + memcpy (q, start, p - start); + q += p - start; + } + else if (ISDIGIT (*p) + || (*p == '.' && ISDIGIT (p[1]))) + { + const char *start; + bool is_hex; + + start = p; + is_hex = false; + if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + is_hex = true; + } + while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E' + || (is_hex + && ((*p >= 'a' && *p <= 'f') + || (*p >= 'A' && *p <= 'F')))) + ++p; + memcpy (q, start, p - start); + q += p - start; + while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L' + || *p == 'f' || *p == 'F' + || *p == 'd' || *p == 'D') + { + /* Go doesn't use any of these trailing type + modifiers. */ + ++p; + } + } + else if (ISSPACE (*p) + || *p == '+' || *p == '-' + || *p == '*' || *p == '/' || *p == '%' + || *p == '|' || *p == '&' + || *p == '>' || *p == '<' + || *p == '!' + || *p == '(' || *p == ')' + || *p == '"' || *p == '\'') + *q++ = *p++; + else + { + /* Something we don't recognize. */ + fprintf (asm_out_file, "#GO unknowndefine %s\n", buffer); + return; + } + } + *q = '\0'; + + slot = htab_find_slot_with_hash (macro_hash, copy, htab_hash_string (copy), + INSERT); + *slot = XNEW (struct macro_hash_node); + ((struct macro_hash_node *) *slot)->name = copy; + + fprintf (asm_out_file, "#GO const _%s = %s\n", copy, out_buffer); + + XDELETEVEC (out_buffer); +} + +/* A macro undef. */ + +static void +go_undef (unsigned int lineno ATTRIBUTE_UNUSED, + const char *buffer ATTRIBUTE_UNUSED) +{ + void **slot; + + slot = htab_find_slot_with_hash (macro_hash, buffer, + htab_hash_string (buffer), + NO_INSERT); + if (slot == NULL) + return; + fprintf (asm_out_file, "#GO undef _%s\n", buffer); + /* We don't delete the slot from the hash table because that will + cause a duplicate const definition. */ +} + +/* A function or variable decl. */ + +static void +go_decl (tree decl) +{ + if (!TREE_PUBLIC (decl) + || DECL_IS_BUILTIN (decl) + || DECL_NAME (decl) == NULL_TREE) + return; + queue = tree_cons (NULL_TREE, decl, queue); +} + +/* A type declaration. */ + +static void +go_type_decl (tree decl, int local) +{ + if (local || DECL_IS_BUILTIN (decl)) + return; + if (DECL_NAME (decl) == NULL_TREE + && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE + || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE) + && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE) + return; + queue = tree_cons (NULL_TREE, decl, queue); +} + +/* Output a type. */ + +static void +go_output_type (struct goout_container *container, tree type, + bool in_struct_or_func) +{ + if (TYPE_NAME (type) != NULL_TREE + && (pointer_set_contains (container->decls_seen, type) + || pointer_set_contains (container->decls_seen, TYPE_NAME (type))) + && (AGGREGATE_TYPE_P (type) + || POINTER_TYPE_P (type) + || TREE_CODE (type) == FUNCTION_TYPE)) + { + tree name; + + name = TYPE_NAME (type); + if (TREE_CODE (name) == IDENTIFIER_NODE) + { + fprintf (asm_out_file, "_%s", IDENTIFIER_POINTER (name)); + return; + } + else if (TREE_CODE (name) == TYPE_DECL) + { + fprintf (asm_out_file, "_%s", + IDENTIFIER_POINTER (DECL_NAME (name))); + return; + } + } + + pointer_set_insert (container->decls_seen, type); + + switch (TREE_CODE (type)) + { + case ENUMERAL_TYPE: + fprintf (asm_out_file, "int"); + break; + + case TYPE_DECL: + fprintf (asm_out_file, "_%s", + IDENTIFIER_POINTER (DECL_NAME (type))); + break; + + case INTEGER_TYPE: + { + const char *s; + char buf[100]; + + switch (TYPE_PRECISION (type)) + { + case 8: + s = TYPE_UNSIGNED (type) ? "uint8" : "int8"; + break; + case 16: + s = TYPE_UNSIGNED (type) ? "uint16" : "int16"; + break; + case 32: + s = TYPE_UNSIGNED (type) ? "uint32" : "int32"; + break; + case 64: + s = TYPE_UNSIGNED (type) ? "uint64" : "int64"; + break; + default: + snprintf (buf, sizeof buf, "INVALID-int-%u%s", + TYPE_PRECISION (type), + TYPE_UNSIGNED (type) ? "u" : ""); + s = buf; + break; + } + fprintf (asm_out_file, "%s", s); + } + break; + + case REAL_TYPE: + { + const char *s; + char buf[100]; + + switch (TYPE_PRECISION (type)) + { + case 32: + s = "float32"; + break; + case 64: + s = "float64"; + break; + case 80: + s = "float80"; + break; + default: + snprintf (buf, sizeof buf, "INVALID-float-%u", + TYPE_PRECISION (type)); + s = buf; + break; + } + fprintf (asm_out_file, "%s", s); + } + break; + + case BOOLEAN_TYPE: + fprintf (asm_out_file, "bool"); + break; + + case POINTER_TYPE: + if (in_struct_or_func + && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE + && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)) + || (POINTER_TYPE_P (TREE_TYPE (type)) + && (TREE_CODE (TREE_TYPE (TREE_TYPE (type))) + == FUNCTION_TYPE)))) + { + tree name; + name = TYPE_NAME (TREE_TYPE (type)); + if (TREE_CODE (name) == IDENTIFIER_NODE) + { + fprintf (asm_out_file, "*_%s", IDENTIFIER_POINTER (name)); + /* If pointing to a struct or union, then the pointer + here can be used without the struct or union definition. + So this struct or union is a can be a potential dummy + type. */ + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) + pointer_set_insert (container->pot_dummy_types, + IDENTIFIER_POINTER (name)); + return; + } + else if (TREE_CODE (name) == TYPE_DECL) + { + fprintf (asm_out_file, "*_%s", + IDENTIFIER_POINTER (DECL_NAME (name))); + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) + pointer_set_insert (container->pot_dummy_types, + IDENTIFIER_POINTER (DECL_NAME (name))); + return; + } + } + if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + fprintf (asm_out_file, "func"); + else + fprintf (asm_out_file, "*"); + if (VOID_TYPE_P (TREE_TYPE (type))) + fprintf (asm_out_file, "byte"); + else + go_output_type (container, TREE_TYPE (type), in_struct_or_func); + break; + + case ARRAY_TYPE: + fprintf (asm_out_file, "["); + if (TYPE_DOMAIN (type) != NULL_TREE + && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE + && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE + && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST + && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0 + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE + && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST + && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0)) + fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC "+1", + tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0)); + fprintf (asm_out_file, "]"); + go_output_type (container, TREE_TYPE (type), in_struct_or_func); + break; + + case UNION_TYPE: + case RECORD_TYPE: + { + tree field; + int i; + + fprintf (asm_out_file, "struct { "); + i = 0; + for (field = TYPE_FIELDS (type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL) + { + fprintf (asm_out_file, "_f%d ", i); + i++; + } + else + { + const char *var_name; + void **slot; + + /* Start variable name with an underscore if a keyword. */ + var_name = IDENTIFIER_POINTER (DECL_NAME (field)); + slot = htab_find_slot (container->keyword_hash, var_name, + NO_INSERT); + if (slot == NULL) + fprintf (asm_out_file, "%s ", var_name); + else + fprintf (asm_out_file, "_%s ", var_name); + } + if (DECL_BIT_FIELD (field)) + fprintf (asm_out_file, "INVALID-bit-field"); + else + { + /* Do not expand type if a record or union type or a + function pointer. */ + if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) + || (POINTER_TYPE_P (TREE_TYPE (field)) + && (TREE_CODE (TREE_TYPE (TREE_TYPE (field))) + == FUNCTION_TYPE)))) + { + tree name = TYPE_NAME (TREE_TYPE (field)); + if (TREE_CODE (name) == IDENTIFIER_NODE) + fprintf (asm_out_file, "_%s", IDENTIFIER_POINTER (name)); + else if (TREE_CODE (name) == TYPE_DECL) + fprintf (asm_out_file, "_%s", + IDENTIFIER_POINTER (DECL_NAME (name))); + } + else + go_output_type (container, TREE_TYPE (field), true); + } + fprintf (asm_out_file, "; "); + + /* Only output the first field of a union, and hope for + the best. */ + if (TREE_CODE (type) == UNION_TYPE) + break; + } + fprintf (asm_out_file, "}"); + } + break; + + case FUNCTION_TYPE: + { + tree args; + bool is_varargs; + tree result; + + fprintf (asm_out_file, "("); + is_varargs = true; + for (args = TYPE_ARG_TYPES (type); + args != NULL_TREE; + args = TREE_CHAIN (args)) + { + if (VOID_TYPE_P (TREE_VALUE (args))) + { + gcc_assert (TREE_CHAIN (args) == NULL); + is_varargs = false; + break; + } + if (args != TYPE_ARG_TYPES (type)) + fprintf (asm_out_file, ", "); + go_output_type (container, TREE_VALUE (args), true); + } + if (is_varargs) + { + if (TYPE_ARG_TYPES (type) != NULL_TREE) + fprintf (asm_out_file, ", "); + fprintf (asm_out_file, "..."); + } + fprintf (asm_out_file, ")"); + + result = TREE_TYPE (type); + if (!VOID_TYPE_P (result)) + { + fprintf (asm_out_file, " "); + go_output_type (container, result, in_struct_or_func); + } + } + break; + + default: + fprintf (asm_out_file, "INVALID-type"); + break; + } +} + +/* Output a function declaration. */ + +static void +go_output_fndecl (struct goout_container *container, tree decl) +{ + fprintf (asm_out_file, "#GO func _%s ", + IDENTIFIER_POINTER (DECL_NAME (decl))); + go_output_type (container, TREE_TYPE (decl), false); + fprintf (asm_out_file, " __asm__(\"%s\")\n", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); +} + +/* Output a typedef or something like a struct definition. */ + +static void +go_output_typedef (struct goout_container *container, tree decl) +{ + /* If we have an enum type, output the enum constants + separately. */ + if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE + && TYPE_SIZE (TREE_TYPE (decl)) != 0 + && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl)) + && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE + || !pointer_set_contains (container->decls_seen, + TYPE_CANONICAL (TREE_TYPE (decl))))) + { + tree element; + + for (element = TYPE_VALUES (TREE_TYPE (decl)); + element != NULL_TREE; + element = TREE_CHAIN (element)) + fprintf (asm_out_file, "#GO const _%s = " HOST_WIDE_INT_PRINT_DEC "\n", + IDENTIFIER_POINTER (TREE_PURPOSE (element)), + tree_low_cst (TREE_VALUE (element), 0)); + pointer_set_insert (container->decls_seen, TREE_TYPE (decl)); + if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE) + pointer_set_insert (container->decls_seen, TYPE_CANONICAL (TREE_TYPE (decl))); + } + + if (DECL_NAME (decl) != NULL_TREE) + { + void **slot; + const char *type; + + type = IDENTIFIER_POINTER (DECL_NAME (decl)); + /* If type defined already, skip. */ + slot = htab_find_slot (container->type_hash, type, INSERT); + if (*slot != NULL) + return; + *slot = CONST_CAST (void *, (const void *) type); + + fprintf (asm_out_file, "#GO type _%s ", + IDENTIFIER_POINTER (DECL_NAME (decl))); + go_output_type (container, TREE_TYPE (decl), false); + pointer_set_insert (container->decls_seen, decl); + } + else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))) + { + void **slot; + const char *type; + + type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl)))); + /* If type defined already, skip. */ + slot = htab_find_slot (container->type_hash, type, INSERT); + if (*slot != NULL) + return; + *slot = CONST_CAST (void *, (const void *) type); + + fprintf (asm_out_file, "#GO type _%s ", + IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl)))); + go_output_type (container, TREE_TYPE (decl), false); + } + else + return; + + fprintf (asm_out_file, "\n"); +} + +/* Output a variable. */ + +static void +go_output_var (struct goout_container *container, tree decl) +{ + if (pointer_set_contains (container->decls_seen, decl) + || pointer_set_contains (container->decls_seen, DECL_NAME (decl))) + return; + pointer_set_insert (container->decls_seen, decl); + pointer_set_insert (container->decls_seen, DECL_NAME (decl)); + fprintf (asm_out_file, "#GO var _%s ", + IDENTIFIER_POINTER (DECL_NAME (decl))); + go_output_type (container, TREE_TYPE (decl), false); + fprintf (asm_out_file, "\n"); +} + +/* For the type and keywords hash tables. */ + +static int +string_hash_eq (const void *y1, const void *y2) +{ + return strcmp ((const char *) y1, (const char *) y2) == 0; +} + +/* Build a hash table with the Go keywords. */ + +static const char * const keywords[] = { + "__asm__", "break", "case", "chan", "const", "continue", "default", + "defer", "else", "fallthrough", "for", "func", "go", "goto", "if", + "import", "interface", "map", "package", "range", "return", "select", + "struct", "switch", "type", "var" +}; + +static void +keyword_hash_init (struct goout_container *container) +{ + size_t i; + size_t count = sizeof (keywords) / sizeof (keywords[0]); + void **slot; + + for (i = 0; i < count; i++) + { + slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT); + *slot = CONST_CAST (void *, (const void *) keywords[i]); + } +} + +/* Traversing the pot_dummy_types and seeing which types are present in the + global types hash table and creating dummy definitions if not found. + This function is invoked by pointer_set_traverse. */ + +static bool +find_dummy_types (const void *ptr, void *adata) +{ + struct goout_container *data = (struct goout_container *) adata; + void **slot; + const char *type = (const char *) ptr; + + slot = htab_find_slot (data->type_hash, type, NO_INSERT); + if (slot == NULL) + fprintf (asm_out_file, "#GO type _%s struct {};\n", type); + return true; +} + +/* Output symbols. */ + +static void +go_finish (const char *filename ATTRIBUTE_UNUSED) +{ + struct goout_container container; + + tree q; + + container.decls_seen = pointer_set_create (); + container.pot_dummy_types = pointer_set_create (); + container.type_hash = htab_create (100, htab_hash_string, + string_hash_eq, NULL); + container.keyword_hash = htab_create (50, htab_hash_string, + string_hash_eq, NULL); + + keyword_hash_init (&container); + + q = nreverse (queue); + queue = NULL_TREE; + for (; q != NULL_TREE; q = TREE_CHAIN (q)) + { + tree decl; + + decl = TREE_VALUE (q); + switch (TREE_CODE (decl)) + { + case FUNCTION_DECL: + go_output_fndecl (&container, decl); + break; + + case TYPE_DECL: + go_output_typedef (&container, decl); + break; + + case VAR_DECL: + go_output_var (&container, decl); + break; + + default: + gcc_unreachable(); + } + } + /* To emit dummy definitions. */ + pointer_set_traverse (container.pot_dummy_types, find_dummy_types, + (void *) &container); + + pointer_set_destroy (container.decls_seen); + pointer_set_destroy (container.pot_dummy_types); + htab_delete (container.type_hash); + htab_delete (container.keyword_hash); +} + +/* The debug hooks structure. */ + +const struct gcc_debug_hooks go_debug_hooks = +{ + go_init, /* init */ + go_finish, /* finish */ + debug_nothing_void, /* assembly_start */ + go_define, /* define */ + go_undef, /* undef */ + debug_nothing_int_charstar, /* start_source_file */ + debug_nothing_int, /* end_source_file */ + debug_nothing_int_int, /* begin_block */ + debug_nothing_int_int, /* end_block */ + debug_true_const_tree, /* ignore_block */ + debug_nothing_int_charstar_int_bool, /* source_line */ + debug_nothing_int_charstar, /* begin_prologue */ + debug_nothing_int_charstar, /* end_prologue */ + debug_nothing_int_charstar, /* begin_epilogue */ + debug_nothing_int_charstar, /* end_epilogue */ + debug_nothing_tree, /* begin_function */ + debug_nothing_int, /* end_function */ + go_decl, /* function_decl */ + go_decl, /* global_decl */ + go_type_decl, /* type_decl */ + debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */ + debug_nothing_tree, /* deferred_inline_function */ + debug_nothing_tree, /* outlining_inline_function */ + debug_nothing_rtx, /* label */ + debug_nothing_int, /* handle_pch */ + debug_nothing_rtx, /* var_location */ + debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_rtx_rtx, /* copy_call_info */ + debug_nothing_uid, /* virtual_call */ + debug_nothing_tree_tree, /* set_name */ + 0 /* start_end_main_source_file */ +}; + +#endif /* defined(GO_DEBUG_INFO) */ + +#include "gt-goout.h" Index: flag-types.h =================================================================== --- flag-types.h (revision 166249) +++ flag-types.h (working copy) @@ -30,8 +30,9 @@ enum debug_info_type DWARF2_DEBUG, /* Write Dwarf v2 debug info (using dwarf2out.c). */ XCOFF_DEBUG, /* Write IBM/Xcoff debug info (using dbxout.c). */ VMS_DEBUG, /* Write VMS debug info (using vmsdbgout.c). */ - VMS_AND_DWARF2_DEBUG /* Write VMS debug info (using vmsdbgout.c). - and DWARF v2 debug info (using dwarf2out.c). */ + VMS_AND_DWARF2_DEBUG, /* Write VMS debug info (using vmsdbgout.c). + and DWARF v2 debug info (using dwarf2out.c). */ + GO_DEBUG /* Write Go language information (using goout.c). */ }; enum debug_info_level Index: debug.h =================================================================== --- debug.h (revision 166249) +++ debug.h (working copy) @@ -193,6 +193,7 @@ extern const struct gcc_debug_hooks sdb_ extern const struct gcc_debug_hooks xcoff_debug_hooks; extern const struct gcc_debug_hooks dwarf2_debug_hooks; extern const struct gcc_debug_hooks vmsdbg_debug_hooks; +extern const struct gcc_debug_hooks go_debug_hooks; /* Dwarf2 frame information. */ Index: common.opt =================================================================== --- common.opt (revision 166249) +++ common.opt (working copy) @@ -1868,6 +1868,10 @@ ggdb Common JoinedOrMissing Generate debug information in default extended format +ggo +Common +Generate Go language type information + gstabs Common JoinedOrMissing Negative(gstabs+) Generate debug information in STABS format Index: opts.c =================================================================== --- opts.c (revision 166249) +++ opts.c (working copy) @@ -2170,6 +2170,10 @@ common_handle_option (struct gcc_options set_debug_level (NO_DEBUG, 2, arg); break; + case OPT_ggo: + set_debug_level (GO_DEBUG, 1, "3"); + break; + case OPT_gstabs: case OPT_gstabs_: set_debug_level (DBX_DEBUG, code == OPT_gstabs_, arg); Index: toplev.c =================================================================== --- toplev.c (revision 166249) +++ toplev.c (working copy) @@ -1064,7 +1064,7 @@ decode_d_option (const char *arg) /* Indexed by enum debug_info_type. */ const char *const debug_type_names[] = { - "none", "stabs", "coff", "dwarf-2", "xcoff", "vms" + "none", "stabs", "coff", "dwarf-2", "xcoff", "vms", "go" }; /* Print version information to FILE. @@ -1939,6 +1939,10 @@ process_options (void) else if (write_symbols == VMS_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG) debug_hooks = &vmsdbg_debug_hooks; #endif +#ifdef GO_DEBUGGING_INFO + else if (write_symbols == GO_DEBUG) + debug_hooks = &go_debug_hooks; +#endif else error ("target system does not support the \"%s\" debug format", debug_type_names[write_symbols]); Index: c-family/c-lex.c =================================================================== --- c-family/c-lex.c (revision 166249) +++ c-family/c-lex.c (working copy) @@ -89,7 +89,8 @@ init_c_lex (void) /* Set the debug callbacks if we can use them. */ if (debug_info_level == DINFO_LEVEL_VERBOSE && (write_symbols == DWARF2_DEBUG - || write_symbols == VMS_AND_DWARF2_DEBUG)) + || write_symbols == VMS_AND_DWARF2_DEBUG + || write_symbols == GO_DEBUG)) { cb->define = cb_define; cb->undef = cb_undef; Index: java/jvspec.c =================================================================== --- java/jvspec.c (revision 166249) +++ java/jvspec.c (working copy) @@ -281,6 +281,7 @@ lang_specific_driver (struct cl_decoded_ case OPT_gcoff: case OPT_gdwarf_: case OPT_ggdb: + case OPT_ggo: case OPT_gstabs: case OPT_gstabs_: case OPT_gvms: Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 166249) +++ doc/invoke.texi (working copy) @@ -318,7 +318,7 @@ Objective-C and Objective-C++ Dialects}. -fvar-tracking-assignments -fvar-tracking-assignments-toggle @gol -g -g@var{level} -gtoggle -gcoff -gdwarf-@var{version} @gol -ggdb -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol --gvms -gxcoff -gxcoff+ @gol +-gvms -gxcoff -gxcoff+ -ggo @gol -fno-merge-debug-strings -fno-dwarf2-cfi-asm @gol -fdebug-prefix-map=@var{old}=@var{new} @gol -femit-struct-debug-baseonly -femit-struct-debug-reduced @gol @@ -4591,6 +4591,12 @@ Allow using extensions of later DWARF st Produce debugging information in VMS debug format (if that is supported). This is the format used by DEBUG on VMS systems. +@item -ggo +Produce debugging information as Go language comments in the generated +assembly code. This is only available if the Go frontend was enabled +when the compiler was built. This is used internally when building +the Go runtime library. + @item -g@var{level} @itemx -ggdb@var{level} @itemx -gstabs@var{level} Index: Makefile.in =================================================================== --- Makefile.in (revision 166249) +++ Makefile.in (working copy) @@ -1233,6 +1237,7 @@ OBJS-common = \ gimple-low.o \ gimple-pretty-print.o \ gimplify.o \ + goout.o \ graph.o \ graphds.o \ graphite.o \ @@ -2964,6 +2969,8 @@ vmsdbgout.o : vmsdbgout.c $(CONFIG_H) $( xcoffout.o : xcoffout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(RTL_H) xcoffout.h $(FLAGS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) output.h dbxout.h \ $(GGC_H) $(TARGET_H) debug.h $(GSTAB_H) xcoff.h +goout.o : goout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + $(GGC_H) pointer-set.h output.h debug.h emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \ $(GGC_H) $(EXPR_H) hard-reg-set.h $(BITMAP_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(BASIC_BLOCK_H) \ @@ -3736,7 +3743,8 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp $(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \ $(srcdir)/expr.h \ $(srcdir)/function.c $(srcdir)/except.c \ - $(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \ + $(srcdir)/gcse.c $(srcdir)/goout.c \ + $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \ $(srcdir)/profile.c $(srcdir)/mcf.c \ $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/cfglayout.h \ $(srcdir)/sdbout.c $(srcdir)/stor-layout.c \