-dA enhancement
[official-gcc.git] / gcc / godump.c
blob7ee7af0e861ab23b8c5faa3a5e106aad312c65a9
1 /* Output Go language descriptions of types.
2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor <iant@google.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* This file is used during the build process to emit Go language
22 descriptions of declarations from C header files. It uses the
23 debug info hooks to emit the descriptions. The Go language
24 descriptions then become part of the Go runtime support
25 library.
27 All global names are output with a leading underscore, so that they
28 are all hidden in Go. */
30 #include "config.h"
31 #include "system.h"
32 #include "coretypes.h"
33 #include "diagnostic-core.h"
34 #include "tree.h"
35 #include "ggc.h"
36 #include "pointer-set.h"
37 #include "obstack.h"
38 #include "debug.h"
40 /* We dump this information from the debug hooks. This gives us a
41 stable and maintainable API to hook into. In order to work
42 correctly when -g is used, we build our own hooks structure which
43 wraps the hooks we need to change. */
45 /* Our debug hooks. This is initialized by dump_go_spec_init. */
47 static struct gcc_debug_hooks go_debug_hooks;
49 /* The real debug hooks. */
51 static const struct gcc_debug_hooks *real_debug_hooks;
53 /* The file where we should write information. */
55 static FILE *go_dump_file;
57 /* A queue of decls to output. */
59 static GTY(()) VEC(tree,gc) *queue;
61 /* A hash table of macros we have seen. */
63 static htab_t macro_hash;
65 /* For the hash tables. */
67 static int
68 string_hash_eq (const void *y1, const void *y2)
70 return strcmp ((const char *) y1, (const char *) y2) == 0;
73 /* A macro definition. */
75 static void
76 go_define (unsigned int lineno, const char *buffer)
78 const char *p;
79 const char *name_end;
80 char *out_buffer;
81 char *q;
82 bool saw_operand;
83 bool need_operand;
84 char *copy;
85 hashval_t hashval;
86 void **slot;
88 real_debug_hooks->define (lineno, buffer);
90 /* Skip macro functions. */
91 for (p = buffer; *p != '\0' && *p != ' '; ++p)
92 if (*p == '(')
93 return;
95 if (*p == '\0')
96 return;
98 name_end = p;
100 ++p;
101 if (*p == '\0')
102 return;
104 copy = XNEWVEC (char, name_end - buffer + 1);
105 memcpy (copy, buffer, name_end - buffer);
106 copy[name_end - buffer] = '\0';
108 hashval = htab_hash_string (copy);
109 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
110 if (slot != NULL)
112 XDELETEVEC (copy);
113 return;
116 /* For simplicity, we force all names to be hidden by adding an
117 initial underscore, and let the user undo this as needed. */
118 out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
119 q = out_buffer;
120 saw_operand = false;
121 need_operand = false;
122 while (*p != '\0')
124 switch (*p)
126 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
127 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
128 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
129 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
130 case 'Y': case 'Z':
131 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
132 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
133 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
134 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
135 case 'y': case 'z':
136 case '_':
138 /* The start of an identifier. Technically we should also
139 worry about UTF-8 identifiers, but they are not a
140 problem for practical uses of -fdump-go-spec so we
141 don't worry about them. */
142 const char *start;
143 char *n;
145 if (saw_operand)
146 goto unknown;
148 start = p;
149 while (ISALNUM (*p) || *p == '_')
150 ++p;
151 n = XALLOCAVEC (char, p - start + 1);
152 memcpy (n, start, p - start);
153 n[p - start] = '\0';
154 slot = htab_find_slot (macro_hash, n, NO_INSERT);
155 if (slot == NULL || *slot == NULL)
157 /* This is a reference to a name which was not defined
158 as a macro. */
159 goto unknown;
162 *q++ = '_';
163 memcpy (q, start, p - start);
164 q += p - start;
166 saw_operand = true;
167 need_operand = false;
169 break;
171 case '.':
172 if (!ISDIGIT (p[1]))
173 goto unknown;
174 /* Fall through. */
175 case '0': case '1': case '2': case '3': case '4':
176 case '5': case '6': case '7': case '8': case '9':
178 const char *start;
179 bool is_hex;
181 start = p;
182 is_hex = false;
183 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
185 p += 2;
186 is_hex = true;
188 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
189 || (is_hex
190 && ((*p >= 'a' && *p <= 'f')
191 || (*p >= 'A' && *p <= 'F'))))
192 ++p;
193 memcpy (q, start, p - start);
194 q += p - start;
195 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
196 || *p == 'f' || *p == 'F'
197 || *p == 'd' || *p == 'D')
199 /* Go doesn't use any of these trailing type
200 modifiers. */
201 ++p;
204 /* We'll pick up the exponent, if any, as an
205 expression. */
207 saw_operand = true;
208 need_operand = false;
210 break;
212 case ' ': case '\t':
213 *q++ = *p++;
214 break;
216 case '(':
217 /* Always OK, not part of an operand, presumed to start an
218 operand. */
219 *q++ = *p++;
220 saw_operand = false;
221 need_operand = false;
222 break;
224 case ')':
225 /* OK if we don't need an operand, and presumed to indicate
226 an operand. */
227 if (need_operand)
228 goto unknown;
229 *q++ = *p++;
230 saw_operand = true;
231 break;
233 case '+': case '-':
234 /* Always OK, but not part of an operand. */
235 *q++ = *p++;
236 saw_operand = false;
237 break;
239 case '*': case '/': case '%': case '|': case '&': case '^':
240 /* Must be a binary operator. */
241 if (!saw_operand)
242 goto unknown;
243 *q++ = *p++;
244 saw_operand = false;
245 need_operand = true;
246 break;
248 case '=':
249 *q++ = *p++;
250 if (*p != '=')
251 goto unknown;
252 /* Must be a binary operator. */
253 if (!saw_operand)
254 goto unknown;
255 *q++ = *p++;
256 saw_operand = false;
257 need_operand = true;
258 break;
260 case '!':
261 *q++ = *p++;
262 if (*p == '=')
264 /* Must be a binary operator. */
265 if (!saw_operand)
266 goto unknown;
267 *q++ = *p++;
268 saw_operand = false;
269 need_operand = true;
271 else
273 /* Must be a unary operator. */
274 if (saw_operand)
275 goto unknown;
276 need_operand = true;
278 break;
280 case '<': case '>':
281 /* Must be a binary operand, may be << or >> or <= or >=. */
282 if (!saw_operand)
283 goto unknown;
284 *q++ = *p++;
285 if (*p == *(p - 1) || *p == '=')
286 *q++ = *p++;
287 saw_operand = false;
288 need_operand = true;
289 break;
291 case '~':
292 /* Must be a unary operand, must be translated for Go. */
293 if (saw_operand)
294 goto unknown;
295 *q++ = '^';
296 p++;
297 need_operand = true;
298 break;
300 case '"':
301 case '\'':
303 char quote = *p;
304 *q++ = *p++;
305 while (*p != quote)
307 int c;
309 if (*p == '\0')
310 goto unknown;
312 if (*p != '\\')
314 *q++ = *p++;
315 continue;
318 *q++ = *p++;
319 switch (*p)
321 case '0': case '1': case '2': case '3':
322 case '4': case '5': case '6': case '7':
323 c = 0;
324 while (*p >= '0' && *p <= '7')
326 *q++ = *p++;
327 ++c;
329 /* Go octal characters are always 3
330 digits. */
331 if (c != 3)
332 goto unknown;
333 break;
335 case 'x':
336 *q++ = *p++;
337 c = 0;
338 while (ISXDIGIT (*p))
340 *q++ = *p++;
341 ++c;
343 /* Go hex characters are always 2 digits. */
344 if (c != 2)
345 goto unknown;
346 break;
348 case 'a': case 'b': case 'f': case 'n': case 'r':
349 case 't': case 'v': case '\\': case '\'': case '"':
350 *q++ = *p++;
351 break;
353 default:
354 goto unknown;
357 *q++ = *p++;
358 break;
361 default:
362 goto unknown;
366 if (need_operand)
367 goto unknown;
369 *q = '\0';
371 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
372 *slot = copy;
374 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
376 XDELETEVEC (out_buffer);
377 return;
379 unknown:
380 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
381 XDELETEVEC (out_buffer);
382 XDELETEVEC (copy);
385 /* A macro undef. */
387 static void
388 go_undef (unsigned int lineno, const char *buffer)
390 void **slot;
392 real_debug_hooks->undef (lineno, buffer);
394 slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
395 if (slot == NULL)
396 return;
397 fprintf (go_dump_file, "// undef _%s\n", buffer);
398 /* We don't delete the slot from the hash table because that will
399 cause a duplicate const definition. */
402 /* A function or variable decl. */
404 static void
405 go_decl (tree decl)
407 if (!TREE_PUBLIC (decl)
408 || DECL_IS_BUILTIN (decl)
409 || DECL_NAME (decl) == NULL_TREE)
410 return;
411 VEC_safe_push (tree, gc, queue, decl);
414 /* A function decl. */
416 static void
417 go_function_decl (tree decl)
419 real_debug_hooks->function_decl (decl);
420 go_decl (decl);
423 /* A global variable decl. */
425 static void
426 go_global_decl (tree decl)
428 real_debug_hooks->global_decl (decl);
429 go_decl (decl);
432 /* A type declaration. */
434 static void
435 go_type_decl (tree decl, int local)
437 real_debug_hooks->type_decl (decl, local);
439 if (local || DECL_IS_BUILTIN (decl))
440 return;
441 if (DECL_NAME (decl) == NULL_TREE
442 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
443 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
444 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
445 return;
446 VEC_safe_push (tree, gc, queue, decl);
449 /* A container for the data we pass around when generating information
450 at the end of the compilation. */
452 struct godump_container
454 /* DECLs that we have already seen. */
455 struct pointer_set_t *decls_seen;
457 /* Types which may potentially have to be defined as dummy
458 types. */
459 struct pointer_set_t *pot_dummy_types;
461 /* Go keywords. */
462 htab_t keyword_hash;
464 /* Global type definitions. */
465 htab_t type_hash;
467 /* Obstack used to write out a type definition. */
468 struct obstack type_obstack;
471 /* Append an IDENTIFIER_NODE to OB. */
473 static void
474 go_append_string (struct obstack *ob, tree id)
476 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
479 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
480 USE_TYPE_NAME is true if we can simply use a type name here without
481 needing to define it. IS_FUNC_OK is true if we can output a func
482 type here; the "func" keyword will already have been added. Return
483 true if the type can be represented in Go, false otherwise. */
485 static bool
486 go_format_type (struct godump_container *container, tree type,
487 bool use_type_name, bool is_func_ok)
489 bool ret;
490 struct obstack *ob;
492 ret = true;
493 ob = &container->type_obstack;
495 if (TYPE_NAME (type) != NULL_TREE
496 && (pointer_set_contains (container->decls_seen, type)
497 || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
498 && (AGGREGATE_TYPE_P (type)
499 || POINTER_TYPE_P (type)
500 || TREE_CODE (type) == FUNCTION_TYPE))
502 tree name;
504 name = TYPE_NAME (type);
505 if (TREE_CODE (name) == IDENTIFIER_NODE)
507 obstack_1grow (ob, '_');
508 go_append_string (ob, name);
509 return ret;
511 else if (TREE_CODE (name) == TYPE_DECL)
513 obstack_1grow (ob, '_');
514 go_append_string (ob, DECL_NAME (name));
515 return ret;
519 pointer_set_insert (container->decls_seen, type);
521 switch (TREE_CODE (type))
523 case ENUMERAL_TYPE:
524 obstack_grow (ob, "int", 3);
525 break;
527 case TYPE_DECL:
528 obstack_1grow (ob, '_');
529 go_append_string (ob, DECL_NAME (type));
530 break;
532 case INTEGER_TYPE:
534 const char *s;
535 char buf[100];
537 switch (TYPE_PRECISION (type))
539 case 8:
540 s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
541 break;
542 case 16:
543 s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
544 break;
545 case 32:
546 s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
547 break;
548 case 64:
549 s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
550 break;
551 default:
552 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
553 TYPE_PRECISION (type),
554 TYPE_UNSIGNED (type) ? "u" : "");
555 s = buf;
556 ret = false;
557 break;
559 obstack_grow (ob, s, strlen (s));
561 break;
563 case REAL_TYPE:
565 const char *s;
566 char buf[100];
568 switch (TYPE_PRECISION (type))
570 case 32:
571 s = "float32";
572 break;
573 case 64:
574 s = "float64";
575 break;
576 default:
577 snprintf (buf, sizeof buf, "INVALID-float-%u",
578 TYPE_PRECISION (type));
579 s = buf;
580 ret = false;
581 break;
583 obstack_grow (ob, s, strlen (s));
585 break;
587 case BOOLEAN_TYPE:
588 obstack_grow (ob, "bool", 4);
589 break;
591 case POINTER_TYPE:
592 if (use_type_name
593 && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
594 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
595 || (POINTER_TYPE_P (TREE_TYPE (type))
596 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
597 == FUNCTION_TYPE))))
599 tree name;
601 name = TYPE_NAME (TREE_TYPE (type));
602 if (TREE_CODE (name) == IDENTIFIER_NODE)
604 obstack_grow (ob, "*_", 2);
605 go_append_string (ob, name);
607 /* The pointer here can be used without the struct or
608 union definition. So this struct or union is a a
609 potential dummy type. */
610 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
611 pointer_set_insert (container->pot_dummy_types,
612 IDENTIFIER_POINTER (name));
614 return ret;
616 else if (TREE_CODE (name) == TYPE_DECL)
618 obstack_grow (ob, "*_", 2);
619 go_append_string (ob, DECL_NAME (name));
620 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
621 pointer_set_insert (container->pot_dummy_types,
622 IDENTIFIER_POINTER (DECL_NAME (name)));
623 return ret;
626 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
627 obstack_grow (ob, "func", 4);
628 else
629 obstack_1grow (ob, '*');
630 if (VOID_TYPE_P (TREE_TYPE (type)))
631 obstack_grow (ob, "byte", 4);
632 else
634 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
635 true))
636 ret = false;
638 break;
640 case ARRAY_TYPE:
641 obstack_1grow (ob, '[');
642 if (TYPE_DOMAIN (type) != NULL_TREE
643 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
644 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
645 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
646 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
647 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
648 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
649 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
651 char buf[100];
653 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
654 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
655 obstack_grow (ob, buf, strlen (buf));
657 obstack_1grow (ob, ']');
658 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
659 ret = false;
660 break;
662 case UNION_TYPE:
663 case RECORD_TYPE:
665 tree field;
666 int i;
668 obstack_grow (ob, "struct { ", 9);
669 i = 0;
670 for (field = TYPE_FIELDS (type);
671 field != NULL_TREE;
672 field = TREE_CHAIN (field))
674 if (DECL_NAME (field) == NULL)
676 char buf[100];
678 obstack_grow (ob, "_f", 2);
679 snprintf (buf, sizeof buf, "%d", i);
680 obstack_grow (ob, buf, strlen (buf));
681 i++;
683 else
685 const char *var_name;
686 void **slot;
688 /* Start variable name with an underscore if a keyword. */
689 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
690 slot = htab_find_slot (container->keyword_hash, var_name,
691 NO_INSERT);
692 if (slot != NULL)
693 obstack_1grow (ob, '_');
694 go_append_string (ob, DECL_NAME (field));
696 obstack_1grow (ob, ' ');
697 if (DECL_BIT_FIELD (field))
699 obstack_grow (ob, "INVALID-bit-field", 17);
700 ret = false;
702 else
704 /* Do not expand type if a record or union type or a
705 function pointer. */
706 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
707 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
708 || (POINTER_TYPE_P (TREE_TYPE (field))
709 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
710 == FUNCTION_TYPE))))
712 tree name = TYPE_NAME (TREE_TYPE (field));
713 if (TREE_CODE (name) == IDENTIFIER_NODE)
715 obstack_1grow (ob, '_');
716 go_append_string (ob, name);
718 else if (TREE_CODE (name) == TYPE_DECL)
720 obstack_1grow (ob, '_');
721 go_append_string (ob, DECL_NAME (name));
724 else
726 if (!go_format_type (container, TREE_TYPE (field), true,
727 false))
728 ret = false;
731 obstack_grow (ob, "; ", 2);
733 /* Only output the first field of a union, and hope for
734 the best. */
735 if (TREE_CODE (type) == UNION_TYPE)
736 break;
738 obstack_1grow (ob, '}');
740 break;
742 case FUNCTION_TYPE:
744 tree args;
745 bool is_varargs;
746 tree result;
748 /* Go has no way to write a type which is a function but not a
749 pointer to a function. */
750 if (!is_func_ok)
752 obstack_grow (ob, "func*", 5);
753 ret = false;
756 obstack_1grow (ob, '(');
757 is_varargs = true;
758 for (args = TYPE_ARG_TYPES (type);
759 args != NULL_TREE;
760 args = TREE_CHAIN (args))
762 if (VOID_TYPE_P (TREE_VALUE (args)))
764 gcc_assert (TREE_CHAIN (args) == NULL);
765 is_varargs = false;
766 break;
768 if (args != TYPE_ARG_TYPES (type))
769 obstack_grow (ob, ", ", 2);
770 if (!go_format_type (container, TREE_VALUE (args), true, false))
771 ret = false;
773 if (is_varargs)
775 if (TYPE_ARG_TYPES (type) != NULL_TREE)
776 obstack_grow (ob, ", ", 2);
777 obstack_grow (ob, "...interface{}", 14);
779 obstack_1grow (ob, ')');
781 result = TREE_TYPE (type);
782 if (!VOID_TYPE_P (result))
784 obstack_1grow (ob, ' ');
785 if (!go_format_type (container, result, use_type_name, false))
786 ret = false;
789 break;
791 default:
792 obstack_grow (ob, "INVALID-type", 12);
793 ret = false;
794 break;
797 return ret;
800 /* Output the type which was built on the type obstack, and then free
801 it. */
803 static void
804 go_output_type (struct godump_container *container)
806 struct obstack *ob;
808 ob = &container->type_obstack;
809 obstack_1grow (ob, '\0');
810 fputs (obstack_base (ob), go_dump_file);
811 obstack_free (ob, obstack_base (ob));
814 /* Output a function declaration. */
816 static void
817 go_output_fndecl (struct godump_container *container, tree decl)
819 if (!go_format_type (container, TREE_TYPE (decl), false, true))
820 fprintf (go_dump_file, "// ");
821 fprintf (go_dump_file, "func _%s ",
822 IDENTIFIER_POINTER (DECL_NAME (decl)));
823 go_output_type (container);
824 fprintf (go_dump_file, " __asm__(\"%s\")\n",
825 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
828 /* Output a typedef or something like a struct definition. */
830 static void
831 go_output_typedef (struct godump_container *container, tree decl)
833 /* If we have an enum type, output the enum constants
834 separately. */
835 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
836 && TYPE_SIZE (TREE_TYPE (decl)) != 0
837 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
838 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
839 || !pointer_set_contains (container->decls_seen,
840 TYPE_CANONICAL (TREE_TYPE (decl)))))
842 tree element;
844 for (element = TYPE_VALUES (TREE_TYPE (decl));
845 element != NULL_TREE;
846 element = TREE_CHAIN (element))
847 fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
848 IDENTIFIER_POINTER (TREE_PURPOSE (element)),
849 tree_low_cst (TREE_VALUE (element), 0));
850 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
851 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
852 pointer_set_insert (container->decls_seen,
853 TYPE_CANONICAL (TREE_TYPE (decl)));
856 if (DECL_NAME (decl) != NULL_TREE)
858 void **slot;
859 const char *type;
861 type = IDENTIFIER_POINTER (DECL_NAME (decl));
862 /* If type defined already, skip. */
863 slot = htab_find_slot (container->type_hash, type, INSERT);
864 if (*slot != NULL)
865 return;
866 *slot = CONST_CAST (void *, (const void *) type);
868 if (!go_format_type (container, TREE_TYPE (decl), false, false))
869 fprintf (go_dump_file, "// ");
870 fprintf (go_dump_file, "type _%s ",
871 IDENTIFIER_POINTER (DECL_NAME (decl)));
872 go_output_type (container);
873 pointer_set_insert (container->decls_seen, decl);
875 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
877 void **slot;
878 const char *type;
880 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
881 /* If type defined already, skip. */
882 slot = htab_find_slot (container->type_hash, type, INSERT);
883 if (*slot != NULL)
884 return;
885 *slot = CONST_CAST (void *, (const void *) type);
887 if (!go_format_type (container, TREE_TYPE (decl), false, false))
888 fprintf (go_dump_file, "// ");
889 fprintf (go_dump_file, "type _%s ",
890 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
891 go_output_type (container);
893 else
894 return;
896 fprintf (go_dump_file, "\n");
899 /* Output a variable. */
901 static void
902 go_output_var (struct godump_container *container, tree decl)
904 bool is_valid;
906 if (pointer_set_contains (container->decls_seen, decl)
907 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
908 return;
909 pointer_set_insert (container->decls_seen, decl);
910 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
912 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
913 if (is_valid
914 && htab_find_slot (container->type_hash,
915 IDENTIFIER_POINTER (DECL_NAME (decl)),
916 NO_INSERT) != NULL)
918 /* There is already a type with this name, probably from a
919 struct tag. Prefer the type to the variable. */
920 is_valid = false;
922 if (!is_valid)
923 fprintf (go_dump_file, "// ");
925 fprintf (go_dump_file, "var _%s ",
926 IDENTIFIER_POINTER (DECL_NAME (decl)));
927 go_output_type (container);
928 fprintf (go_dump_file, "\n");
930 /* Sometimes an extern variable is declared with an unknown struct
931 type. */
932 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
933 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
935 tree type_name = TYPE_NAME (TREE_TYPE (decl));
936 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
937 pointer_set_insert (container->pot_dummy_types,
938 IDENTIFIER_POINTER (type_name));
939 else if (TREE_CODE (type_name) == TYPE_DECL)
940 pointer_set_insert (container->pot_dummy_types,
941 IDENTIFIER_POINTER (DECL_NAME (type_name)));
945 /* Build a hash table with the Go keywords. */
947 static const char * const keywords[] = {
948 "__asm__", "break", "case", "chan", "const", "continue", "default",
949 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
950 "import", "interface", "map", "package", "range", "return", "select",
951 "struct", "switch", "type", "var"
954 static void
955 keyword_hash_init (struct godump_container *container)
957 size_t i;
958 size_t count = sizeof (keywords) / sizeof (keywords[0]);
959 void **slot;
961 for (i = 0; i < count; i++)
963 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
964 *slot = CONST_CAST (void *, (const void *) keywords[i]);
968 /* Traversing the pot_dummy_types and seeing which types are present
969 in the global types hash table and creating dummy definitions if
970 not found. This function is invoked by pointer_set_traverse. */
972 static bool
973 find_dummy_types (const void *ptr, void *adata)
975 struct godump_container *data = (struct godump_container *) adata;
976 const char *type = (const char *) ptr;
977 void **slot;
979 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
980 if (slot == NULL)
981 fprintf (go_dump_file, "type _%s struct {}\n", type);
982 return true;
985 /* Output symbols. */
987 static void
988 go_finish (const char *filename)
990 struct godump_container container;
991 unsigned int ix;
992 tree decl;
994 real_debug_hooks->finish (filename);
996 container.decls_seen = pointer_set_create ();
997 container.pot_dummy_types = pointer_set_create ();
998 container.type_hash = htab_create (100, htab_hash_string,
999 string_hash_eq, NULL);
1000 container.keyword_hash = htab_create (50, htab_hash_string,
1001 string_hash_eq, NULL);
1002 obstack_init (&container.type_obstack);
1004 keyword_hash_init (&container);
1006 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1008 switch (TREE_CODE (decl))
1010 case FUNCTION_DECL:
1011 go_output_fndecl (&container, decl);
1012 break;
1014 case TYPE_DECL:
1015 go_output_typedef (&container, decl);
1016 break;
1018 case VAR_DECL:
1019 go_output_var (&container, decl);
1020 break;
1022 default:
1023 gcc_unreachable();
1027 /* To emit dummy definitions. */
1028 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1029 (void *) &container);
1031 pointer_set_destroy (container.decls_seen);
1032 pointer_set_destroy (container.pot_dummy_types);
1033 htab_delete (container.type_hash);
1034 htab_delete (container.keyword_hash);
1035 obstack_free (&container.type_obstack, NULL);
1037 queue = NULL;
1039 if (fclose (go_dump_file) != 0)
1040 error ("could not close Go dump file: %m");
1041 go_dump_file = NULL;
1044 /* Set up our hooks. */
1046 const struct gcc_debug_hooks *
1047 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1049 go_dump_file = fopen (filename, "w");
1050 if (go_dump_file == NULL)
1052 error ("could not open Go dump file %qs: %m", filename);
1053 return hooks;
1056 go_debug_hooks = *hooks;
1057 real_debug_hooks = hooks;
1059 go_debug_hooks.finish = go_finish;
1060 go_debug_hooks.define = go_define;
1061 go_debug_hooks.undef = go_undef;
1062 go_debug_hooks.function_decl = go_function_decl;
1063 go_debug_hooks.global_decl = go_global_decl;
1064 go_debug_hooks.type_decl = go_type_decl;
1066 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1068 return &go_debug_hooks;
1071 #include "gt-godump.h"