OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [godump.c] - Blame information for rev 694

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 684 jeremybenn
/* 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>.
4
 
5
This file is part of GCC.
6
 
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.
11
 
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.
16
 
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/>.  */
20
 
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.
26
 
27
   All global names are output with a leading underscore, so that they
28
   are all hidden in Go.  */
29
 
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"
39
 
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.  */
44
 
45
/* Our debug hooks.  This is initialized by dump_go_spec_init.  */
46
 
47
static struct gcc_debug_hooks go_debug_hooks;
48
 
49
/* The real debug hooks.  */
50
 
51
static const struct gcc_debug_hooks *real_debug_hooks;
52
 
53
/* The file where we should write information.  */
54
 
55
static FILE *go_dump_file;
56
 
57
/* A queue of decls to output.  */
58
 
59
static GTY(()) VEC(tree,gc) *queue;
60
 
61
/* A hash table of macros we have seen.  */
62
 
63
static htab_t macro_hash;
64
 
65
/* The type of a value in macro_hash.  */
66
 
67
struct macro_hash_value
68
{
69
  /* The name stored in the hash table.  */
70
  char *name;
71
  /* The value of the macro.  */
72
  char *value;
73
};
74
 
75
/* Calculate the hash value for an entry in the macro hash table.  */
76
 
77
static hashval_t
78
macro_hash_hashval (const void *val)
79
{
80
  const struct macro_hash_value *mhval = (const struct macro_hash_value *) val;
81
  return htab_hash_string (mhval->name);
82
}
83
 
84
/* Compare values in the macro hash table for equality.  */
85
 
86
static int
87
macro_hash_eq (const void *v1, const void *v2)
88
{
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;
92
}
93
 
94
/* Free values deleted from the macro hash table.  */
95
 
96
static void
97
macro_hash_del (void *v)
98
{
99
  struct macro_hash_value *mhv = (struct macro_hash_value *) v;
100
  XDELETEVEC (mhv->name);
101
  XDELETEVEC (mhv->value);
102
  XDELETE (mhv);
103
}
104
 
105
/* For the string hash tables.  */
106
 
107
static int
108
string_hash_eq (const void *y1, const void *y2)
109
{
110
  return strcmp ((const char *) y1, (const char *) y2) == 0;
111
}
112
 
113
/* A macro definition.  */
114
 
115
static void
116
go_define (unsigned int lineno, const char *buffer)
117
{
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;
129
 
130
  real_debug_hooks->define (lineno, buffer);
131
 
132
  /* Skip macro functions.  */
133
  for (p = buffer; *p != '\0' && *p != ' '; ++p)
134
    if (*p == '(')
135
      return;
136
 
137
  if (*p == '\0')
138
    return;
139
 
140
  name_end = p;
141
 
142
  ++p;
143
  if (*p == '\0')
144
    return;
145
 
146
  copy = XNEWVEC (char, name_end - buffer + 1);
147
  memcpy (copy, buffer, name_end - buffer);
148
  copy[name_end - buffer] = '\0';
149
 
150
  mhval = XNEW (struct macro_hash_value);
151
  mhval->name = copy;
152
  mhval->value = NULL;
153
 
154
  hashval = htab_hash_string (copy);
155
  slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, NO_INSERT);
156
 
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')
165
    {
166
      switch (*p)
167
        {
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 '_':
179
          {
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;
187
 
188
            if (saw_operand)
189
              goto unknown;
190
 
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)
200
              {
201
                /* This is a reference to a name which was not defined
202
                   as a macro.  */
203
                goto unknown;
204
              }
205
 
206
            *q++ = '_';
207
            memcpy (q, start, p - start);
208
            q += p - start;
209
 
210
            saw_operand = true;
211
            need_operand = false;
212
          }
213
          break;
214
 
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':
221
          {
222
            const char *start;
223
            bool is_hex;
224
 
225
            start = p;
226
            is_hex = false;
227
            if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
228
              {
229
                p += 2;
230
                is_hex = true;
231
              }
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')
242
              {
243
                /* Go doesn't use any of these trailing type
244
                   modifiers.  */
245
                ++p;
246
              }
247
 
248
            /* We'll pick up the exponent, if any, as an
249
               expression.  */
250
 
251
            saw_operand = true;
252
            need_operand = false;
253
          }
254
          break;
255
 
256
        case ' ': case '\t':
257
          *q++ = *p++;
258
          break;
259
 
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;
267
 
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;
276
 
277
        case '+': case '-':
278
          /* Always OK, but not part of an operand.  */
279
          *q++ = *p++;
280
          saw_operand = false;
281
          break;
282
 
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;
291
 
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;
303
 
304
        case '!':
305
          *q++ = *p++;
306
          if (*p == '=')
307
            {
308
              /* Must be a binary operator.  */
309
              if (!saw_operand)
310
                goto unknown;
311
              *q++ = *p++;
312
              saw_operand = false;
313
              need_operand = true;
314
            }
315
          else
316
            {
317
              /* Must be a unary operator.  */
318
              if (saw_operand)
319
                goto unknown;
320
              need_operand = true;
321
            }
322
          break;
323
 
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;
334
 
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;
343
 
344
        case '"':
345
        case '\'':
346
          {
347
            char quote;
348
            int count;
349
 
350
            if (saw_operand)
351
              goto unknown;
352
            quote = *p;
353
            *q++ = *p++;
354
            count = 0;
355
            while (*p != quote)
356
              {
357
                int c;
358
 
359
                if (*p == '\0')
360
                  goto unknown;
361
 
362
                ++count;
363
 
364
                if (*p != '\\')
365
                  {
366
                    *q++ = *p++;
367
                    continue;
368
                  }
369
 
370
                *q++ = *p++;
371
                switch (*p)
372
                  {
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')
377
                      {
378
                        *q++ = *p++;
379
                        ++c;
380
                      }
381
                    /* Go octal characters are always 3
382
                       digits.  */
383
                    if (c != 3)
384
                      goto unknown;
385
                    break;
386
 
387
                  case 'x':
388
                    *q++ = *p++;
389
                    c = 0;
390
                    while (ISXDIGIT (*p))
391
                      {
392
                        *q++ = *p++;
393
                        ++c;
394
                      }
395
                    /* Go hex characters are always 2 digits.  */
396
                    if (c != 2)
397
                      goto unknown;
398
                    break;
399
 
400
                  case 'a': case 'b': case 'f': case 'n': case 'r':
401
                  case 't': case 'v': case '\\': case '\'': case '"':
402
                    *q++ = *p++;
403
                    break;
404
 
405
                  default:
406
                    goto unknown;
407
                  }
408
              }
409
 
410
            *q++ = *p++;
411
 
412
            if (quote == '\'' && count != 1)
413
              goto unknown;
414
 
415
            saw_operand = true;
416
            need_operand = false;
417
 
418
            break;
419
          }
420
 
421
        default:
422
          goto unknown;
423
        }
424
    }
425
 
426
  if (need_operand)
427
    goto unknown;
428
 
429
  gcc_assert ((size_t) (q - out_buffer) < out_len);
430
  *q = '\0';
431
 
432
  mhval->value = out_buffer;
433
 
434
  if (slot == NULL)
435
    {
436
      slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, INSERT);
437
      gcc_assert (slot != NULL && *slot == NULL);
438
    }
439
  else
440
    {
441
      if (*slot != NULL)
442
        macro_hash_del (*slot);
443
    }
444
 
445
  *slot = mhval;
446
 
447
  return;
448
 
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);
455
}
456
 
457
/* A macro undef.  */
458
 
459
static void
460
go_undef (unsigned int lineno, const char *buffer)
461
{
462
  struct macro_hash_value mhval;
463
  void **slot;
464
 
465
  real_debug_hooks->undef (lineno, buffer);
466
 
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);
472
}
473
 
474
/* A function or variable decl.  */
475
 
476
static void
477
go_decl (tree decl)
478
{
479
  if (!TREE_PUBLIC (decl)
480
      || DECL_IS_BUILTIN (decl)
481
      || DECL_NAME (decl) == NULL_TREE)
482
    return;
483
  VEC_safe_push (tree, gc, queue, decl);
484
}
485
 
486
/* A function decl.  */
487
 
488
static void
489
go_function_decl (tree decl)
490
{
491
  real_debug_hooks->function_decl (decl);
492
  go_decl (decl);
493
}
494
 
495
/* A global variable decl.  */
496
 
497
static void
498
go_global_decl (tree decl)
499
{
500
  real_debug_hooks->global_decl (decl);
501
  go_decl (decl);
502
}
503
 
504
/* A type declaration.  */
505
 
506
static void
507
go_type_decl (tree decl, int local)
508
{
509
  real_debug_hooks->type_decl (decl, local);
510
 
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 (tree, gc, queue, decl);
519
}
520
 
521
/* A container for the data we pass around when generating information
522
   at the end of the compilation.  */
523
 
524
struct godump_container
525
{
526
  /* DECLs that we have already seen.  */
527
  struct pointer_set_t *decls_seen;
528
 
529
  /* Types which may potentially have to be defined as dummy
530
     types.  */
531
  struct pointer_set_t *pot_dummy_types;
532
 
533
  /* Go keywords.  */
534
  htab_t keyword_hash;
535
 
536
  /* Global type definitions.  */
537
  htab_t type_hash;
538
 
539
  /* Invalid types.  */
540
  htab_t invalid_hash;
541
 
542
  /* Obstack used to write out a type definition.  */
543
  struct obstack type_obstack;
544
};
545
 
546
/* Append an IDENTIFIER_NODE to OB.  */
547
 
548
static void
549
go_append_string (struct obstack *ob, tree id)
550
{
551
  obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
552
}
553
 
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.  */
559
 
560
static bool
561
go_format_type (struct godump_container *container, tree type,
562
                bool use_type_name, bool is_func_ok)
563
{
564
  bool ret;
565
  struct obstack *ob;
566
 
567
  ret = true;
568
  ob = &container->type_obstack;
569
 
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))
576
    {
577
      tree name;
578
      void **slot;
579
 
580
      name = TYPE_NAME (type);
581
      if (TREE_CODE (name) == TYPE_DECL)
582
        name = DECL_NAME (name);
583
 
584
      slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
585
                             NO_INSERT);
586
      if (slot != NULL)
587
        ret = false;
588
 
589
      obstack_1grow (ob, '_');
590
      go_append_string (ob, name);
591
      return ret;
592
    }
593
 
594
  pointer_set_insert (container->decls_seen, type);
595
 
596
  switch (TREE_CODE (type))
597
    {
598
    case ENUMERAL_TYPE:
599
      obstack_grow (ob, "int", 3);
600
      break;
601
 
602
    case TYPE_DECL:
603
      {
604
        void **slot;
605
 
606
        slot = htab_find_slot (container->invalid_hash,
607
                               IDENTIFIER_POINTER (DECL_NAME (type)),
608
                               NO_INSERT);
609
        if (slot != NULL)
610
          ret = false;
611
 
612
        obstack_1grow (ob, '_');
613
        go_append_string (ob, DECL_NAME (type));
614
      }
615
      break;
616
 
617
    case INTEGER_TYPE:
618
      {
619
        const char *s;
620
        char buf[100];
621
 
622
        switch (TYPE_PRECISION (type))
623
          {
624
          case 8:
625
            s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
626
            break;
627
          case 16:
628
            s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
629
            break;
630
          case 32:
631
            s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
632
            break;
633
          case 64:
634
            s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
635
            break;
636
          default:
637
            snprintf (buf, sizeof buf, "INVALID-int-%u%s",
638
                      TYPE_PRECISION (type),
639
                      TYPE_UNSIGNED (type) ? "u" : "");
640
            s = buf;
641
            ret = false;
642
            break;
643
          }
644
        obstack_grow (ob, s, strlen (s));
645
      }
646
      break;
647
 
648
    case REAL_TYPE:
649
      {
650
        const char *s;
651
        char buf[100];
652
 
653
        switch (TYPE_PRECISION (type))
654
          {
655
          case 32:
656
            s = "float32";
657
            break;
658
          case 64:
659
            s = "float64";
660
            break;
661
          default:
662
            snprintf (buf, sizeof buf, "INVALID-float-%u",
663
                      TYPE_PRECISION (type));
664
            s = buf;
665
            ret = false;
666
            break;
667
          }
668
        obstack_grow (ob, s, strlen (s));
669
      }
670
      break;
671
 
672
    case BOOLEAN_TYPE:
673
      obstack_grow (ob, "bool", 4);
674
      break;
675
 
676
    case POINTER_TYPE:
677
      if (use_type_name
678
          && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
679
          && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
680
              || (POINTER_TYPE_P (TREE_TYPE (type))
681
                  && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
682
                      == FUNCTION_TYPE))))
683
        {
684
          tree name;
685
          void **slot;
686
 
687
          name = TYPE_NAME (TREE_TYPE (type));
688
          if (TREE_CODE (name) == TYPE_DECL)
689
            name = DECL_NAME (name);
690
 
691
          slot = htab_find_slot (container->invalid_hash,
692
                                 IDENTIFIER_POINTER (name), NO_INSERT);
693
          if (slot != NULL)
694
            ret = false;
695
 
696
          obstack_grow (ob, "*_", 2);
697
          go_append_string (ob, name);
698
 
699
          /* The pointer here can be used without the struct or union
700
             definition.  So this struct or union is a potential dummy
701
             type.  */
702
          if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
703
            pointer_set_insert (container->pot_dummy_types,
704
                                IDENTIFIER_POINTER (name));
705
 
706
          return ret;
707
        }
708
      if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
709
        obstack_grow (ob, "func", 4);
710
      else
711
        obstack_1grow (ob, '*');
712
      if (VOID_TYPE_P (TREE_TYPE (type)))
713
        obstack_grow (ob, "byte", 4);
714
      else
715
        {
716
          if (!go_format_type (container, TREE_TYPE (type), use_type_name,
717
                               true))
718
            ret = false;
719
        }
720
      break;
721
 
722
    case ARRAY_TYPE:
723
      obstack_1grow (ob, '[');
724
      if (TYPE_DOMAIN (type) != NULL_TREE
725
          && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
726
          && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
727
          && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
728
          && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
729
          && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
730
          && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
731
          && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
732
        {
733
          char buf[100];
734
 
735
          snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
736
                    tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
737
          obstack_grow (ob, buf, strlen (buf));
738
        }
739
      obstack_1grow (ob, ']');
740
      if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
741
        ret = false;
742
      break;
743
 
744
    case UNION_TYPE:
745
    case RECORD_TYPE:
746
      {
747
        tree field;
748
        int i;
749
 
750
        obstack_grow (ob, "struct { ", 9);
751
        i = 0;
752
        for (field = TYPE_FIELDS (type);
753
             field != NULL_TREE;
754
             field = TREE_CHAIN (field))
755
          {
756
            struct obstack hold_type_obstack;
757
            bool field_ok;
758
 
759
            if (TREE_CODE (type) == UNION_TYPE)
760
              {
761
                hold_type_obstack = container->type_obstack;
762
                obstack_init (&container->type_obstack);
763
              }
764
 
765
            field_ok = true;
766
 
767
            if (DECL_NAME (field) == NULL)
768
              {
769
                char buf[100];
770
 
771
                obstack_grow (ob, "Godump_", 7);
772
                snprintf (buf, sizeof buf, "%d", i);
773
                obstack_grow (ob, buf, strlen (buf));
774
                i++;
775
              }
776
            else
777
              {
778
                const char *var_name;
779
                void **slot;
780
 
781
                /* Start variable name with an underscore if a keyword.  */
782
                var_name = IDENTIFIER_POINTER (DECL_NAME (field));
783
                slot = htab_find_slot (container->keyword_hash, var_name,
784
                                       NO_INSERT);
785
                if (slot != NULL)
786
                  obstack_1grow (ob, '_');
787
                go_append_string (ob, DECL_NAME (field));
788
              }
789
            obstack_1grow (ob, ' ');
790
            if (DECL_BIT_FIELD (field))
791
              {
792
                obstack_grow (ob, "INVALID-bit-field", 17);
793
                field_ok = false;
794
              }
795
            else
796
              {
797
                /* Do not expand type if a record or union type or a
798
                   function pointer.  */
799
                if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
800
                    && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
801
                        || (POINTER_TYPE_P (TREE_TYPE (field))
802
                            && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
803
                                == FUNCTION_TYPE))))
804
                  {
805
                    tree name;
806
                    void **slot;
807
 
808
                    name = TYPE_NAME (TREE_TYPE (field));
809
                    if (TREE_CODE (name) == TYPE_DECL)
810
                      name = DECL_NAME (name);
811
 
812
                    slot = htab_find_slot (container->invalid_hash,
813
                                           IDENTIFIER_POINTER (name),
814
                                           NO_INSERT);
815
                    if (slot != NULL)
816
                      field_ok = false;
817
 
818
                    obstack_1grow (ob, '_');
819
                    go_append_string (ob, name);
820
                  }
821
                else
822
                  {
823
                    if (!go_format_type (container, TREE_TYPE (field), true,
824
                                         false))
825
                      field_ok = false;
826
                  }
827
              }
828
            obstack_grow (ob, "; ", 2);
829
 
830
            /* Only output the first successful field of a union, and
831
               hope for the best.  */
832
            if (TREE_CODE (type) == UNION_TYPE)
833
              {
834
                if (!field_ok && TREE_CHAIN (field) == NULL_TREE)
835
                  {
836
                    field_ok = true;
837
                    ret = false;
838
                  }
839
                if (field_ok)
840
                  {
841
                    unsigned int sz;
842
 
843
                    sz = obstack_object_size (&container->type_obstack);
844
                    obstack_grow (&hold_type_obstack,
845
                                  obstack_base (&container->type_obstack),
846
                                  sz);
847
                  }
848
                obstack_free (&container->type_obstack, NULL);
849
                container->type_obstack = hold_type_obstack;
850
                if (field_ok)
851
                  break;
852
              }
853
            else
854
              {
855
                if (!field_ok)
856
                  ret = false;
857
              }
858
          }
859
        obstack_1grow (ob, '}');
860
      }
861
      break;
862
 
863
    case FUNCTION_TYPE:
864
      {
865
        tree arg_type;
866
        bool is_varargs;
867
        tree result;
868
        function_args_iterator iter;
869
        bool seen_arg;
870
 
871
        /* Go has no way to write a type which is a function but not a
872
           pointer to a function.  */
873
        if (!is_func_ok)
874
          {
875
            obstack_grow (ob, "func*", 5);
876
            ret = false;
877
          }
878
 
879
        obstack_1grow (ob, '(');
880
        is_varargs = stdarg_p (type);
881
        seen_arg = false;
882
        FOREACH_FUNCTION_ARGS (type, arg_type, iter)
883
          {
884
            if (VOID_TYPE_P (arg_type))
885
              break;
886
            if (seen_arg)
887
              obstack_grow (ob, ", ", 2);
888
            if (!go_format_type (container, arg_type, true, false))
889
              ret = false;
890
            seen_arg = true;
891
          }
892
        if (is_varargs)
893
          {
894
            if (prototype_p (type))
895
              obstack_grow (ob, ", ", 2);
896
            obstack_grow (ob, "...interface{}", 14);
897
          }
898
        obstack_1grow (ob, ')');
899
 
900
        result = TREE_TYPE (type);
901
        if (!VOID_TYPE_P (result))
902
          {
903
            obstack_1grow (ob, ' ');
904
            if (!go_format_type (container, result, use_type_name, false))
905
              ret = false;
906
          }
907
      }
908
      break;
909
 
910
    default:
911
      obstack_grow (ob, "INVALID-type", 12);
912
      ret = false;
913
      break;
914
    }
915
 
916
  return ret;
917
}
918
 
919
/* Output the type which was built on the type obstack, and then free
920
   it.  */
921
 
922
static void
923
go_output_type (struct godump_container *container)
924
{
925
  struct obstack *ob;
926
 
927
  ob = &container->type_obstack;
928
  obstack_1grow (ob, '\0');
929
  fputs (obstack_base (ob), go_dump_file);
930
  obstack_free (ob, obstack_base (ob));
931
}
932
 
933
/* Output a function declaration.  */
934
 
935
static void
936
go_output_fndecl (struct godump_container *container, tree decl)
937
{
938
  if (!go_format_type (container, TREE_TYPE (decl), false, true))
939
    fprintf (go_dump_file, "// ");
940
  fprintf (go_dump_file, "func _%s ",
941
           IDENTIFIER_POINTER (DECL_NAME (decl)));
942
  go_output_type (container);
943
  fprintf (go_dump_file, " __asm__(\"%s\")\n",
944
           IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
945
}
946
 
947
/* Output a typedef or something like a struct definition.  */
948
 
949
static void
950
go_output_typedef (struct godump_container *container, tree decl)
951
{
952
  /* If we have an enum type, output the enum constants
953
     separately.  */
954
  if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
955
      && TYPE_SIZE (TREE_TYPE (decl)) != 0
956
      && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
957
      && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
958
          || !pointer_set_contains (container->decls_seen,
959
                                    TYPE_CANONICAL (TREE_TYPE (decl)))))
960
    {
961
      tree element;
962
 
963
      for (element = TYPE_VALUES (TREE_TYPE (decl));
964
           element != NULL_TREE;
965
           element = TREE_CHAIN (element))
966
        {
967
          const char *name;
968
          struct macro_hash_value *mhval;
969
          void **slot;
970
          char buf[100];
971
 
972
          name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
973
 
974
          /* Sometimes a name will be defined as both an enum constant
975
             and a macro.  Avoid duplicate definition errors by
976
             treating enum constants as macros.  */
977
          mhval = XNEW (struct macro_hash_value);
978
          mhval->name = xstrdup (name);
979
          mhval->value = NULL;
980
          slot = htab_find_slot (macro_hash, mhval, INSERT);
981
          if (*slot != NULL)
982
            macro_hash_del (*slot);
983
 
984
          if (host_integerp (TREE_VALUE (element), 0))
985
            snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
986
                     tree_low_cst (TREE_VALUE (element), 0));
987
          else if (host_integerp (TREE_VALUE (element), 1))
988
            snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
989
                     ((unsigned HOST_WIDE_INT)
990
                      tree_low_cst (TREE_VALUE (element), 1)));
991
          else
992
            snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
993
                     ((unsigned HOST_WIDE_INT)
994
                      TREE_INT_CST_HIGH (TREE_VALUE (element))),
995
                     TREE_INT_CST_LOW (TREE_VALUE (element)));
996
 
997
          mhval->value = xstrdup (buf);
998
          *slot = mhval;
999
        }
1000
      pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
1001
      if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
1002
        pointer_set_insert (container->decls_seen,
1003
                            TYPE_CANONICAL (TREE_TYPE (decl)));
1004
    }
1005
 
1006
  if (DECL_NAME (decl) != NULL_TREE)
1007
    {
1008
      void **slot;
1009
      const char *type;
1010
 
1011
      type = IDENTIFIER_POINTER (DECL_NAME (decl));
1012
      /* If type defined already, skip.  */
1013
      slot = htab_find_slot (container->type_hash, type, INSERT);
1014
      if (*slot != NULL)
1015
        return;
1016
      *slot = CONST_CAST (void *, (const void *) type);
1017
 
1018
      if (!go_format_type (container, TREE_TYPE (decl), false, false))
1019
        {
1020
          fprintf (go_dump_file, "// ");
1021
          slot = htab_find_slot (container->invalid_hash, type, INSERT);
1022
          *slot = CONST_CAST (void *, (const void *) type);
1023
        }
1024
      fprintf (go_dump_file, "type _%s ",
1025
               IDENTIFIER_POINTER (DECL_NAME (decl)));
1026
      go_output_type (container);
1027
      pointer_set_insert (container->decls_seen, decl);
1028
    }
1029
  else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1030
    {
1031
       void **slot;
1032
       const char *type;
1033
 
1034
       type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1035
       /* If type defined already, skip.  */
1036
       slot = htab_find_slot (container->type_hash, type, INSERT);
1037
       if (*slot != NULL)
1038
         return;
1039
       *slot = CONST_CAST (void *, (const void *) type);
1040
 
1041
       if (!go_format_type (container, TREE_TYPE (decl), false, false))
1042
         {
1043
           fprintf (go_dump_file, "// ");
1044
           slot = htab_find_slot (container->invalid_hash, type, INSERT);
1045
           *slot = CONST_CAST (void *, (const void *) type);
1046
         }
1047
       fprintf (go_dump_file, "type _%s ",
1048
               IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1049
       go_output_type (container);
1050
    }
1051
  else
1052
    return;
1053
 
1054
  fprintf (go_dump_file, "\n");
1055
}
1056
 
1057
/* Output a variable.  */
1058
 
1059
static void
1060
go_output_var (struct godump_container *container, tree decl)
1061
{
1062
  bool is_valid;
1063
 
1064
  if (pointer_set_contains (container->decls_seen, decl)
1065
      || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
1066
    return;
1067
  pointer_set_insert (container->decls_seen, decl);
1068
  pointer_set_insert (container->decls_seen, DECL_NAME (decl));
1069
 
1070
  is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
1071
  if (is_valid
1072
      && htab_find_slot (container->type_hash,
1073
                         IDENTIFIER_POINTER (DECL_NAME (decl)),
1074
                         NO_INSERT) != NULL)
1075
    {
1076
      /* There is already a type with this name, probably from a
1077
         struct tag.  Prefer the type to the variable.  */
1078
      is_valid = false;
1079
    }
1080
  if (!is_valid)
1081
    fprintf (go_dump_file, "// ");
1082
 
1083
  fprintf (go_dump_file, "var _%s ",
1084
           IDENTIFIER_POINTER (DECL_NAME (decl)));
1085
  go_output_type (container);
1086
  fprintf (go_dump_file, "\n");
1087
 
1088
  /* Sometimes an extern variable is declared with an unknown struct
1089
     type.  */
1090
  if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1091
      && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1092
    {
1093
      tree type_name = TYPE_NAME (TREE_TYPE (decl));
1094
      if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1095
        pointer_set_insert (container->pot_dummy_types,
1096
                            IDENTIFIER_POINTER (type_name));
1097
      else if (TREE_CODE (type_name) == TYPE_DECL)
1098
        pointer_set_insert (container->pot_dummy_types,
1099
                            IDENTIFIER_POINTER (DECL_NAME (type_name)));
1100
    }
1101
}
1102
 
1103
/* Output the final value of a preprocessor macro or enum constant.
1104
   This is called via htab_traverse_noresize.  */
1105
 
1106
static int
1107
go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1108
{
1109
  struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1110
  fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1111
  return 1;
1112
}
1113
 
1114
/* Build a hash table with the Go keywords.  */
1115
 
1116
static const char * const keywords[] = {
1117
  "__asm__", "break", "case", "chan", "const", "continue", "default",
1118
  "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1119
  "import", "interface", "map", "package", "range", "return", "select",
1120
  "struct", "switch", "type", "var"
1121
};
1122
 
1123
static void
1124
keyword_hash_init (struct godump_container *container)
1125
{
1126
  size_t i;
1127
  size_t count = sizeof (keywords) / sizeof (keywords[0]);
1128
  void **slot;
1129
 
1130
  for (i = 0; i < count; i++)
1131
    {
1132
      slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1133
      *slot = CONST_CAST (void *, (const void *) keywords[i]);
1134
    }
1135
}
1136
 
1137
/* Traversing the pot_dummy_types and seeing which types are present
1138
   in the global types hash table and creating dummy definitions if
1139
   not found.  This function is invoked by pointer_set_traverse.  */
1140
 
1141
static bool
1142
find_dummy_types (const void *ptr, void *adata)
1143
{
1144
  struct godump_container *data = (struct godump_container *) adata;
1145
  const char *type = (const char *) ptr;
1146
  void **slot;
1147
 
1148
  slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1149
  if (slot == NULL)
1150
    fprintf (go_dump_file, "type _%s struct {}\n", type);
1151
  return true;
1152
}
1153
 
1154
/* Output symbols.  */
1155
 
1156
static void
1157
go_finish (const char *filename)
1158
{
1159
  struct godump_container container;
1160
  unsigned int ix;
1161
  tree decl;
1162
 
1163
  real_debug_hooks->finish (filename);
1164
 
1165
  container.decls_seen = pointer_set_create ();
1166
  container.pot_dummy_types = pointer_set_create ();
1167
  container.type_hash = htab_create (100, htab_hash_string,
1168
                                     string_hash_eq, NULL);
1169
  container.invalid_hash = htab_create (10, htab_hash_string,
1170
                                        string_hash_eq, NULL);
1171
  container.keyword_hash = htab_create (50, htab_hash_string,
1172
                                        string_hash_eq, NULL);
1173
  obstack_init (&container.type_obstack);
1174
 
1175
  keyword_hash_init (&container);
1176
 
1177
  FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1178
    {
1179
      switch (TREE_CODE (decl))
1180
        {
1181
        case FUNCTION_DECL:
1182
          go_output_fndecl (&container, decl);
1183
          break;
1184
 
1185
        case TYPE_DECL:
1186
          go_output_typedef (&container, decl);
1187
          break;
1188
 
1189
        case VAR_DECL:
1190
          go_output_var (&container, decl);
1191
          break;
1192
 
1193
        default:
1194
          gcc_unreachable();
1195
        }
1196
    }
1197
 
1198
  htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1199
 
1200
  /* To emit dummy definitions.  */
1201
  pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1202
                        (void *) &container);
1203
 
1204
  pointer_set_destroy (container.decls_seen);
1205
  pointer_set_destroy (container.pot_dummy_types);
1206
  htab_delete (container.type_hash);
1207
  htab_delete (container.invalid_hash);
1208
  htab_delete (container.keyword_hash);
1209
  obstack_free (&container.type_obstack, NULL);
1210
 
1211
  queue = NULL;
1212
 
1213
  if (fclose (go_dump_file) != 0)
1214
    error ("could not close Go dump file: %m");
1215
  go_dump_file = NULL;
1216
}
1217
 
1218
/* Set up our hooks.  */
1219
 
1220
const struct gcc_debug_hooks *
1221
dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1222
{
1223
  go_dump_file = fopen (filename, "w");
1224
  if (go_dump_file == NULL)
1225
    {
1226
      error ("could not open Go dump file %qs: %m", filename);
1227
      return hooks;
1228
    }
1229
 
1230
  go_debug_hooks = *hooks;
1231
  real_debug_hooks = hooks;
1232
 
1233
  go_debug_hooks.finish = go_finish;
1234
  go_debug_hooks.define = go_define;
1235
  go_debug_hooks.undef = go_undef;
1236
  go_debug_hooks.function_decl = go_function_decl;
1237
  go_debug_hooks.global_decl = go_global_decl;
1238
  go_debug_hooks.type_decl = go_type_decl;
1239
 
1240
  macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1241
                            macro_hash_del);
1242
 
1243
  return &go_debug_hooks;
1244
}
1245
 
1246
#include "gt-godump.h"

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.