* gcc.dg/tree-ssa/alias-30.c (dg-options): Dump only fre1 details.
[official-gcc.git] / gcc / godump.c
blob6d6b819bea3140a9773a399263aaa51086d12a04
1 /* Output Go language descriptions of types.
2 Copyright (C) 2008-2014 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, va_gc> *queue;
61 /* A hash table of macros we have seen. */
63 static htab_t macro_hash;
65 /* The type of a value in macro_hash. */
67 struct macro_hash_value
69 /* The name stored in the hash table. */
70 char *name;
71 /* The value of the macro. */
72 char *value;
75 /* Calculate the hash value for an entry in the macro hash table. */
77 static hashval_t
78 macro_hash_hashval (const void *val)
80 const struct macro_hash_value *mhval = (const struct macro_hash_value *) val;
81 return htab_hash_string (mhval->name);
84 /* Compare values in the macro hash table for equality. */
86 static int
87 macro_hash_eq (const void *v1, const void *v2)
89 const struct macro_hash_value *mhv1 = (const struct macro_hash_value *) v1;
90 const struct macro_hash_value *mhv2 = (const struct macro_hash_value *) v2;
91 return strcmp (mhv1->name, mhv2->name) == 0;
94 /* Free values deleted from the macro hash table. */
96 static void
97 macro_hash_del (void *v)
99 struct macro_hash_value *mhv = (struct macro_hash_value *) v;
100 XDELETEVEC (mhv->name);
101 XDELETEVEC (mhv->value);
102 XDELETE (mhv);
105 /* For the string hash tables. */
107 static int
108 string_hash_eq (const void *y1, const void *y2)
110 return strcmp ((const char *) y1, (const char *) y2) == 0;
113 /* A macro definition. */
115 static void
116 go_define (unsigned int lineno, const char *buffer)
118 const char *p;
119 const char *name_end;
120 size_t out_len;
121 char *out_buffer;
122 char *q;
123 bool saw_operand;
124 bool need_operand;
125 struct macro_hash_value *mhval;
126 char *copy;
127 hashval_t hashval;
128 void **slot;
130 real_debug_hooks->define (lineno, buffer);
132 /* Skip macro functions. */
133 for (p = buffer; *p != '\0' && *p != ' '; ++p)
134 if (*p == '(')
135 return;
137 if (*p == '\0')
138 return;
140 name_end = p;
142 ++p;
143 if (*p == '\0')
144 return;
146 copy = XNEWVEC (char, name_end - buffer + 1);
147 memcpy (copy, buffer, name_end - buffer);
148 copy[name_end - buffer] = '\0';
150 mhval = XNEW (struct macro_hash_value);
151 mhval->name = copy;
152 mhval->value = NULL;
154 hashval = htab_hash_string (copy);
155 slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, NO_INSERT);
157 /* For simplicity, we force all names to be hidden by adding an
158 initial underscore, and let the user undo this as needed. */
159 out_len = strlen (p) * 2 + 1;
160 out_buffer = XNEWVEC (char, out_len);
161 q = out_buffer;
162 saw_operand = false;
163 need_operand = false;
164 while (*p != '\0')
166 switch (*p)
168 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
169 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
170 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
171 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
172 case 'Y': case 'Z':
173 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
174 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
175 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
176 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
177 case 'y': case 'z':
178 case '_':
180 /* The start of an identifier. Technically we should also
181 worry about UTF-8 identifiers, but they are not a
182 problem for practical uses of -fdump-go-spec so we
183 don't worry about them. */
184 const char *start;
185 char *n;
186 struct macro_hash_value idval;
188 if (saw_operand)
189 goto unknown;
191 start = p;
192 while (ISALNUM (*p) || *p == '_')
193 ++p;
194 n = XALLOCAVEC (char, p - start + 1);
195 memcpy (n, start, p - start);
196 n[p - start] = '\0';
197 idval.name = n;
198 idval.value = NULL;
199 if (htab_find (macro_hash, &idval) == NULL)
201 /* This is a reference to a name which was not defined
202 as a macro. */
203 goto unknown;
206 *q++ = '_';
207 memcpy (q, start, p - start);
208 q += p - start;
210 saw_operand = true;
211 need_operand = false;
213 break;
215 case '.':
216 if (!ISDIGIT (p[1]))
217 goto unknown;
218 /* Fall through. */
219 case '0': case '1': case '2': case '3': case '4':
220 case '5': case '6': case '7': case '8': case '9':
222 const char *start;
223 bool is_hex;
225 start = p;
226 is_hex = false;
227 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
229 p += 2;
230 is_hex = true;
232 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
233 || (is_hex
234 && ((*p >= 'a' && *p <= 'f')
235 || (*p >= 'A' && *p <= 'F'))))
236 ++p;
237 memcpy (q, start, p - start);
238 q += p - start;
239 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
240 || *p == 'f' || *p == 'F'
241 || *p == 'd' || *p == 'D')
243 /* Go doesn't use any of these trailing type
244 modifiers. */
245 ++p;
248 /* We'll pick up the exponent, if any, as an
249 expression. */
251 saw_operand = true;
252 need_operand = false;
254 break;
256 case ' ': case '\t':
257 *q++ = *p++;
258 break;
260 case '(':
261 /* Always OK, not part of an operand, presumed to start an
262 operand. */
263 *q++ = *p++;
264 saw_operand = false;
265 need_operand = false;
266 break;
268 case ')':
269 /* OK if we don't need an operand, and presumed to indicate
270 an operand. */
271 if (need_operand)
272 goto unknown;
273 *q++ = *p++;
274 saw_operand = true;
275 break;
277 case '+': case '-':
278 /* Always OK, but not part of an operand. */
279 *q++ = *p++;
280 saw_operand = false;
281 break;
283 case '*': case '/': case '%': case '|': case '&': case '^':
284 /* Must be a binary operator. */
285 if (!saw_operand)
286 goto unknown;
287 *q++ = *p++;
288 saw_operand = false;
289 need_operand = true;
290 break;
292 case '=':
293 *q++ = *p++;
294 if (*p != '=')
295 goto unknown;
296 /* Must be a binary operator. */
297 if (!saw_operand)
298 goto unknown;
299 *q++ = *p++;
300 saw_operand = false;
301 need_operand = true;
302 break;
304 case '!':
305 *q++ = *p++;
306 if (*p == '=')
308 /* Must be a binary operator. */
309 if (!saw_operand)
310 goto unknown;
311 *q++ = *p++;
312 saw_operand = false;
313 need_operand = true;
315 else
317 /* Must be a unary operator. */
318 if (saw_operand)
319 goto unknown;
320 need_operand = true;
322 break;
324 case '<': case '>':
325 /* Must be a binary operand, may be << or >> or <= or >=. */
326 if (!saw_operand)
327 goto unknown;
328 *q++ = *p++;
329 if (*p == *(p - 1) || *p == '=')
330 *q++ = *p++;
331 saw_operand = false;
332 need_operand = true;
333 break;
335 case '~':
336 /* Must be a unary operand, must be translated for Go. */
337 if (saw_operand)
338 goto unknown;
339 *q++ = '^';
340 p++;
341 need_operand = true;
342 break;
344 case '"':
345 case '\'':
347 char quote;
348 int count;
350 if (saw_operand)
351 goto unknown;
352 quote = *p;
353 *q++ = *p++;
354 count = 0;
355 while (*p != quote)
357 int c;
359 if (*p == '\0')
360 goto unknown;
362 ++count;
364 if (*p != '\\')
366 *q++ = *p++;
367 continue;
370 *q++ = *p++;
371 switch (*p)
373 case '0': case '1': case '2': case '3':
374 case '4': case '5': case '6': case '7':
375 c = 0;
376 while (*p >= '0' && *p <= '7')
378 *q++ = *p++;
379 ++c;
381 /* Go octal characters are always 3
382 digits. */
383 if (c != 3)
384 goto unknown;
385 break;
387 case 'x':
388 *q++ = *p++;
389 c = 0;
390 while (ISXDIGIT (*p))
392 *q++ = *p++;
393 ++c;
395 /* Go hex characters are always 2 digits. */
396 if (c != 2)
397 goto unknown;
398 break;
400 case 'a': case 'b': case 'f': case 'n': case 'r':
401 case 't': case 'v': case '\\': case '\'': case '"':
402 *q++ = *p++;
403 break;
405 default:
406 goto unknown;
410 *q++ = *p++;
412 if (quote == '\'' && count != 1)
413 goto unknown;
415 saw_operand = true;
416 need_operand = false;
418 break;
421 default:
422 goto unknown;
426 if (need_operand)
427 goto unknown;
429 gcc_assert ((size_t) (q - out_buffer) < out_len);
430 *q = '\0';
432 mhval->value = out_buffer;
434 if (slot == NULL)
436 slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, INSERT);
437 gcc_assert (slot != NULL && *slot == NULL);
439 else
441 if (*slot != NULL)
442 macro_hash_del (*slot);
445 *slot = mhval;
447 return;
449 unknown:
450 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
451 if (slot != NULL)
452 htab_clear_slot (macro_hash, slot);
453 XDELETEVEC (out_buffer);
454 XDELETEVEC (copy);
457 /* A macro undef. */
459 static void
460 go_undef (unsigned int lineno, const char *buffer)
462 struct macro_hash_value mhval;
463 void **slot;
465 real_debug_hooks->undef (lineno, buffer);
467 mhval.name = CONST_CAST (char *, buffer);
468 mhval.value = NULL;
469 slot = htab_find_slot (macro_hash, &mhval, NO_INSERT);
470 if (slot != NULL)
471 htab_clear_slot (macro_hash, slot);
474 /* A function or variable decl. */
476 static void
477 go_decl (tree decl)
479 if (!TREE_PUBLIC (decl)
480 || DECL_IS_BUILTIN (decl)
481 || DECL_NAME (decl) == NULL_TREE)
482 return;
483 vec_safe_push (queue, decl);
486 /* A function decl. */
488 static void
489 go_function_decl (tree decl)
491 real_debug_hooks->function_decl (decl);
492 go_decl (decl);
495 /* A global variable decl. */
497 static void
498 go_global_decl (tree decl)
500 real_debug_hooks->global_decl (decl);
501 go_decl (decl);
504 /* A type declaration. */
506 static void
507 go_type_decl (tree decl, int local)
509 real_debug_hooks->type_decl (decl, local);
511 if (local || DECL_IS_BUILTIN (decl))
512 return;
513 if (DECL_NAME (decl) == NULL_TREE
514 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
515 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
516 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
517 return;
518 vec_safe_push (queue, decl);
521 /* A container for the data we pass around when generating information
522 at the end of the compilation. */
524 struct godump_container
526 /* DECLs that we have already seen. */
527 struct pointer_set_t *decls_seen;
529 /* Types which may potentially have to be defined as dummy
530 types. */
531 struct pointer_set_t *pot_dummy_types;
533 /* Go keywords. */
534 htab_t keyword_hash;
536 /* Global type definitions. */
537 htab_t type_hash;
539 /* Invalid types. */
540 htab_t invalid_hash;
542 /* Obstack used to write out a type definition. */
543 struct obstack type_obstack;
546 /* Append an IDENTIFIER_NODE to OB. */
548 static void
549 go_append_string (struct obstack *ob, tree id)
551 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
554 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
555 USE_TYPE_NAME is true if we can simply use a type name here without
556 needing to define it. IS_FUNC_OK is true if we can output a func
557 type here; the "func" keyword will already have been added. Return
558 true if the type can be represented in Go, false otherwise. */
560 static bool
561 go_format_type (struct godump_container *container, tree type,
562 bool use_type_name, bool is_func_ok)
564 bool ret;
565 struct obstack *ob;
567 ret = true;
568 ob = &container->type_obstack;
570 if (TYPE_NAME (type) != NULL_TREE
571 && (pointer_set_contains (container->decls_seen, type)
572 || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
573 && (AGGREGATE_TYPE_P (type)
574 || POINTER_TYPE_P (type)
575 || TREE_CODE (type) == FUNCTION_TYPE))
577 tree name;
578 void **slot;
580 name = TYPE_IDENTIFIER (type);
582 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
583 NO_INSERT);
584 if (slot != NULL)
585 ret = false;
587 obstack_1grow (ob, '_');
588 go_append_string (ob, name);
589 return ret;
592 pointer_set_insert (container->decls_seen, type);
594 switch (TREE_CODE (type))
596 case ENUMERAL_TYPE:
597 obstack_grow (ob, "int", 3);
598 break;
600 case TYPE_DECL:
602 void **slot;
604 slot = htab_find_slot (container->invalid_hash,
605 IDENTIFIER_POINTER (DECL_NAME (type)),
606 NO_INSERT);
607 if (slot != NULL)
608 ret = false;
610 obstack_1grow (ob, '_');
611 go_append_string (ob, DECL_NAME (type));
613 break;
615 case INTEGER_TYPE:
617 const char *s;
618 char buf[100];
620 switch (TYPE_PRECISION (type))
622 case 8:
623 s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
624 break;
625 case 16:
626 s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
627 break;
628 case 32:
629 s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
630 break;
631 case 64:
632 s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
633 break;
634 default:
635 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
636 TYPE_PRECISION (type),
637 TYPE_UNSIGNED (type) ? "u" : "");
638 s = buf;
639 ret = false;
640 break;
642 obstack_grow (ob, s, strlen (s));
644 break;
646 case REAL_TYPE:
648 const char *s;
649 char buf[100];
651 switch (TYPE_PRECISION (type))
653 case 32:
654 s = "float32";
655 break;
656 case 64:
657 s = "float64";
658 break;
659 default:
660 snprintf (buf, sizeof buf, "INVALID-float-%u",
661 TYPE_PRECISION (type));
662 s = buf;
663 ret = false;
664 break;
666 obstack_grow (ob, s, strlen (s));
668 break;
670 case BOOLEAN_TYPE:
671 obstack_grow (ob, "bool", 4);
672 break;
674 case POINTER_TYPE:
675 if (use_type_name
676 && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
677 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
678 || (POINTER_TYPE_P (TREE_TYPE (type))
679 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
680 == FUNCTION_TYPE))))
682 tree name;
683 void **slot;
685 name = TYPE_IDENTIFIER (TREE_TYPE (type));
687 slot = htab_find_slot (container->invalid_hash,
688 IDENTIFIER_POINTER (name), NO_INSERT);
689 if (slot != NULL)
690 ret = false;
692 obstack_grow (ob, "*_", 2);
693 go_append_string (ob, name);
695 /* The pointer here can be used without the struct or union
696 definition. So this struct or union is a potential dummy
697 type. */
698 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
699 pointer_set_insert (container->pot_dummy_types,
700 IDENTIFIER_POINTER (name));
702 return ret;
704 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
705 obstack_grow (ob, "func", 4);
706 else
707 obstack_1grow (ob, '*');
708 if (VOID_TYPE_P (TREE_TYPE (type)))
709 obstack_grow (ob, "byte", 4);
710 else
712 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
713 true))
714 ret = false;
716 break;
718 case ARRAY_TYPE:
719 obstack_1grow (ob, '[');
720 if (TYPE_DOMAIN (type) != NULL_TREE
721 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
722 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
723 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
724 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
725 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
726 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
727 && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
729 char buf[100];
731 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
732 tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
733 obstack_grow (ob, buf, strlen (buf));
735 obstack_1grow (ob, ']');
736 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
737 ret = false;
738 break;
740 case UNION_TYPE:
741 case RECORD_TYPE:
743 tree field;
744 int i;
746 obstack_grow (ob, "struct { ", 9);
747 i = 0;
748 for (field = TYPE_FIELDS (type);
749 field != NULL_TREE;
750 field = TREE_CHAIN (field))
752 struct obstack hold_type_obstack;
753 bool field_ok;
755 if (TREE_CODE (type) == UNION_TYPE)
757 hold_type_obstack = container->type_obstack;
758 obstack_init (&container->type_obstack);
761 field_ok = true;
763 if (DECL_NAME (field) == NULL)
765 char buf[100];
767 obstack_grow (ob, "Godump_", 7);
768 snprintf (buf, sizeof buf, "%d", i);
769 obstack_grow (ob, buf, strlen (buf));
770 i++;
772 else
774 const char *var_name;
775 void **slot;
777 /* Start variable name with an underscore if a keyword. */
778 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
779 slot = htab_find_slot (container->keyword_hash, var_name,
780 NO_INSERT);
781 if (slot != NULL)
782 obstack_1grow (ob, '_');
783 go_append_string (ob, DECL_NAME (field));
785 obstack_1grow (ob, ' ');
786 if (DECL_BIT_FIELD (field))
788 obstack_grow (ob, "INVALID-bit-field", 17);
789 field_ok = false;
791 else
793 /* Do not expand type if a record or union type or a
794 function pointer. */
795 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
796 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
797 || (POINTER_TYPE_P (TREE_TYPE (field))
798 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
799 == FUNCTION_TYPE))))
801 tree name;
802 void **slot;
804 name = TYPE_IDENTIFIER (TREE_TYPE (field));
806 slot = htab_find_slot (container->invalid_hash,
807 IDENTIFIER_POINTER (name),
808 NO_INSERT);
809 if (slot != NULL)
810 field_ok = false;
812 obstack_1grow (ob, '_');
813 go_append_string (ob, name);
815 else
817 if (!go_format_type (container, TREE_TYPE (field), true,
818 false))
819 field_ok = false;
822 obstack_grow (ob, "; ", 2);
824 /* Only output the first successful field of a union, and
825 hope for the best. */
826 if (TREE_CODE (type) == UNION_TYPE)
828 if (!field_ok && TREE_CHAIN (field) == NULL_TREE)
830 field_ok = true;
831 ret = false;
833 if (field_ok)
835 unsigned int sz;
837 sz = obstack_object_size (&container->type_obstack);
838 obstack_grow (&hold_type_obstack,
839 obstack_base (&container->type_obstack),
840 sz);
842 obstack_free (&container->type_obstack, NULL);
843 container->type_obstack = hold_type_obstack;
844 if (field_ok)
845 break;
847 else
849 if (!field_ok)
850 ret = false;
853 obstack_1grow (ob, '}');
855 break;
857 case FUNCTION_TYPE:
859 tree arg_type;
860 bool is_varargs;
861 tree result;
862 function_args_iterator iter;
863 bool seen_arg;
865 /* Go has no way to write a type which is a function but not a
866 pointer to a function. */
867 if (!is_func_ok)
869 obstack_grow (ob, "func*", 5);
870 ret = false;
873 obstack_1grow (ob, '(');
874 is_varargs = stdarg_p (type);
875 seen_arg = false;
876 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
878 if (VOID_TYPE_P (arg_type))
879 break;
880 if (seen_arg)
881 obstack_grow (ob, ", ", 2);
882 if (!go_format_type (container, arg_type, true, false))
883 ret = false;
884 seen_arg = true;
886 if (is_varargs)
888 if (prototype_p (type))
889 obstack_grow (ob, ", ", 2);
890 obstack_grow (ob, "...interface{}", 14);
892 obstack_1grow (ob, ')');
894 result = TREE_TYPE (type);
895 if (!VOID_TYPE_P (result))
897 obstack_1grow (ob, ' ');
898 if (!go_format_type (container, result, use_type_name, false))
899 ret = false;
902 break;
904 default:
905 obstack_grow (ob, "INVALID-type", 12);
906 ret = false;
907 break;
910 return ret;
913 /* Output the type which was built on the type obstack, and then free
914 it. */
916 static void
917 go_output_type (struct godump_container *container)
919 struct obstack *ob;
921 ob = &container->type_obstack;
922 obstack_1grow (ob, '\0');
923 fputs (obstack_base (ob), go_dump_file);
924 obstack_free (ob, obstack_base (ob));
927 /* Output a function declaration. */
929 static void
930 go_output_fndecl (struct godump_container *container, tree decl)
932 if (!go_format_type (container, TREE_TYPE (decl), false, true))
933 fprintf (go_dump_file, "// ");
934 fprintf (go_dump_file, "func _%s ",
935 IDENTIFIER_POINTER (DECL_NAME (decl)));
936 go_output_type (container);
937 fprintf (go_dump_file, " __asm__(\"%s\")\n",
938 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
941 /* Output a typedef or something like a struct definition. */
943 static void
944 go_output_typedef (struct godump_container *container, tree decl)
946 /* If we have an enum type, output the enum constants
947 separately. */
948 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
949 && TYPE_SIZE (TREE_TYPE (decl)) != 0
950 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
951 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
952 || !pointer_set_contains (container->decls_seen,
953 TYPE_CANONICAL (TREE_TYPE (decl)))))
955 tree element;
957 for (element = TYPE_VALUES (TREE_TYPE (decl));
958 element != NULL_TREE;
959 element = TREE_CHAIN (element))
961 const char *name;
962 struct macro_hash_value *mhval;
963 void **slot;
964 char buf[100];
966 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
968 /* Sometimes a name will be defined as both an enum constant
969 and a macro. Avoid duplicate definition errors by
970 treating enum constants as macros. */
971 mhval = XNEW (struct macro_hash_value);
972 mhval->name = xstrdup (name);
973 mhval->value = NULL;
974 slot = htab_find_slot (macro_hash, mhval, INSERT);
975 if (*slot != NULL)
976 macro_hash_del (*slot);
978 if (tree_fits_shwi_p (TREE_VALUE (element)))
979 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
980 tree_to_shwi (TREE_VALUE (element)));
981 else if (tree_fits_uhwi_p (TREE_VALUE (element)))
982 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
983 tree_to_uhwi (TREE_VALUE (element)));
984 else
985 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
986 ((unsigned HOST_WIDE_INT)
987 TREE_INT_CST_HIGH (TREE_VALUE (element))),
988 TREE_INT_CST_LOW (TREE_VALUE (element)));
990 mhval->value = xstrdup (buf);
991 *slot = mhval;
993 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
994 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
995 pointer_set_insert (container->decls_seen,
996 TYPE_CANONICAL (TREE_TYPE (decl)));
999 if (DECL_NAME (decl) != NULL_TREE)
1001 void **slot;
1002 const char *type;
1004 type = IDENTIFIER_POINTER (DECL_NAME (decl));
1005 /* If type defined already, skip. */
1006 slot = htab_find_slot (container->type_hash, type, INSERT);
1007 if (*slot != NULL)
1008 return;
1009 *slot = CONST_CAST (void *, (const void *) type);
1011 if (!go_format_type (container, TREE_TYPE (decl), false, false))
1013 fprintf (go_dump_file, "// ");
1014 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1015 *slot = CONST_CAST (void *, (const void *) type);
1017 fprintf (go_dump_file, "type _%s ",
1018 IDENTIFIER_POINTER (DECL_NAME (decl)));
1019 go_output_type (container);
1021 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1023 HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1025 if (size > 0)
1026 fprintf (go_dump_file,
1027 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1028 IDENTIFIER_POINTER (DECL_NAME (decl)),
1029 size);
1032 pointer_set_insert (container->decls_seen, decl);
1034 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1036 void **slot;
1037 const char *type;
1038 HOST_WIDE_INT size;
1040 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1041 /* If type defined already, skip. */
1042 slot = htab_find_slot (container->type_hash, type, INSERT);
1043 if (*slot != NULL)
1044 return;
1045 *slot = CONST_CAST (void *, (const void *) type);
1047 if (!go_format_type (container, TREE_TYPE (decl), false, false))
1049 fprintf (go_dump_file, "// ");
1050 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1051 *slot = CONST_CAST (void *, (const void *) type);
1053 fprintf (go_dump_file, "type _%s ",
1054 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1055 go_output_type (container);
1057 size = int_size_in_bytes (TREE_TYPE (decl));
1058 if (size > 0)
1059 fprintf (go_dump_file,
1060 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1061 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1062 size);
1064 else
1065 return;
1067 fprintf (go_dump_file, "\n");
1070 /* Output a variable. */
1072 static void
1073 go_output_var (struct godump_container *container, tree decl)
1075 bool is_valid;
1077 if (pointer_set_contains (container->decls_seen, decl)
1078 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
1079 return;
1080 pointer_set_insert (container->decls_seen, decl);
1081 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
1083 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
1084 if (is_valid
1085 && htab_find_slot (container->type_hash,
1086 IDENTIFIER_POINTER (DECL_NAME (decl)),
1087 NO_INSERT) != NULL)
1089 /* There is already a type with this name, probably from a
1090 struct tag. Prefer the type to the variable. */
1091 is_valid = false;
1093 if (!is_valid)
1094 fprintf (go_dump_file, "// ");
1096 fprintf (go_dump_file, "var _%s ",
1097 IDENTIFIER_POINTER (DECL_NAME (decl)));
1098 go_output_type (container);
1099 fprintf (go_dump_file, "\n");
1101 /* Sometimes an extern variable is declared with an unknown struct
1102 type. */
1103 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1104 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1106 tree type_name = TYPE_NAME (TREE_TYPE (decl));
1107 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1108 pointer_set_insert (container->pot_dummy_types,
1109 IDENTIFIER_POINTER (type_name));
1110 else if (TREE_CODE (type_name) == TYPE_DECL)
1111 pointer_set_insert (container->pot_dummy_types,
1112 IDENTIFIER_POINTER (DECL_NAME (type_name)));
1116 /* Output the final value of a preprocessor macro or enum constant.
1117 This is called via htab_traverse_noresize. */
1119 static int
1120 go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1122 struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1123 fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1124 return 1;
1127 /* Build a hash table with the Go keywords. */
1129 static const char * const keywords[] = {
1130 "__asm__", "break", "case", "chan", "const", "continue", "default",
1131 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1132 "import", "interface", "map", "package", "range", "return", "select",
1133 "struct", "switch", "type", "var"
1136 static void
1137 keyword_hash_init (struct godump_container *container)
1139 size_t i;
1140 size_t count = sizeof (keywords) / sizeof (keywords[0]);
1141 void **slot;
1143 for (i = 0; i < count; i++)
1145 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1146 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1150 /* Traversing the pot_dummy_types and seeing which types are present
1151 in the global types hash table and creating dummy definitions if
1152 not found. This function is invoked by pointer_set_traverse. */
1154 static bool
1155 find_dummy_types (const void *ptr, void *adata)
1157 struct godump_container *data = (struct godump_container *) adata;
1158 const char *type = (const char *) ptr;
1159 void **slot;
1160 void **islot;
1162 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1163 islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1164 if (slot == NULL || islot != NULL)
1165 fprintf (go_dump_file, "type _%s struct {}\n", type);
1166 return true;
1169 /* Output symbols. */
1171 static void
1172 go_finish (const char *filename)
1174 struct godump_container container;
1175 unsigned int ix;
1176 tree decl;
1178 real_debug_hooks->finish (filename);
1180 container.decls_seen = pointer_set_create ();
1181 container.pot_dummy_types = pointer_set_create ();
1182 container.type_hash = htab_create (100, htab_hash_string,
1183 string_hash_eq, NULL);
1184 container.invalid_hash = htab_create (10, htab_hash_string,
1185 string_hash_eq, NULL);
1186 container.keyword_hash = htab_create (50, htab_hash_string,
1187 string_hash_eq, NULL);
1188 obstack_init (&container.type_obstack);
1190 keyword_hash_init (&container);
1192 FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
1194 switch (TREE_CODE (decl))
1196 case FUNCTION_DECL:
1197 go_output_fndecl (&container, decl);
1198 break;
1200 case TYPE_DECL:
1201 go_output_typedef (&container, decl);
1202 break;
1204 case VAR_DECL:
1205 go_output_var (&container, decl);
1206 break;
1208 default:
1209 gcc_unreachable ();
1213 htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1215 /* To emit dummy definitions. */
1216 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1217 (void *) &container);
1219 pointer_set_destroy (container.decls_seen);
1220 pointer_set_destroy (container.pot_dummy_types);
1221 htab_delete (container.type_hash);
1222 htab_delete (container.invalid_hash);
1223 htab_delete (container.keyword_hash);
1224 obstack_free (&container.type_obstack, NULL);
1226 vec_free (queue);
1228 if (fclose (go_dump_file) != 0)
1229 error ("could not close Go dump file: %m");
1230 go_dump_file = NULL;
1233 /* Set up our hooks. */
1235 const struct gcc_debug_hooks *
1236 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1238 go_dump_file = fopen (filename, "w");
1239 if (go_dump_file == NULL)
1241 error ("could not open Go dump file %qs: %m", filename);
1242 return hooks;
1245 go_debug_hooks = *hooks;
1246 real_debug_hooks = hooks;
1248 go_debug_hooks.finish = go_finish;
1249 go_debug_hooks.define = go_define;
1250 go_debug_hooks.undef = go_undef;
1251 go_debug_hooks.function_decl = go_function_decl;
1252 go_debug_hooks.global_decl = go_global_decl;
1253 go_debug_hooks.type_decl = go_type_decl;
1255 macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1256 macro_hash_del);
1258 return &go_debug_hooks;
1261 #include "gt-godump.h"