added doxygen docu
[libfirm] / ir / ana2 / pto_name.c
1 /* -*- c -*- */
2
3 /*
4   Project:     libFIRM
5   File name:   ir/ana/pto_name.c
6   Purpose:     Names for abstract objects
7   Author:      Florian
8   Modified by:
9   Created:     Sat Nov 13 19:35:27 CET 2004
10   CVS-ID:      $Id$
11   Copyright:   (c) 1999-2004 Universität Karlsruhe
12   Licence:     This file is protected by the GPL -  GNU GENERAL PUBLIC LICENSE.
13 */
14
15 # ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 # endif
18
19 /*
20   pto_name: Names for abstract objects
21 */
22
23 # include "pto.h"
24 # include "pto_name.h"
25 # include "pto_util.h"
26
27 # include <string.h>            /* for memcpy */
28 # include <obstack.h>
29 # include <errno.h>
30
31 # include "irnode.h"
32 # include "irprog.h"
33 # include "xmalloc.h"
34
35 # include "pto_debug.h"
36 # include "gnu_ext.h"
37
38 /* Local Defines: */
39 # define obstack_chunk_alloc xmalloc
40 # define obstack_chunk_free free
41
42 # define NALLOC(size)   obstack_alloc (name_obst, size)
43
44 /* Local Data Types: */
45
46 /* Local Variables: */
47 struct obstack *qset_obst = NULL;
48 struct obstack *name_obst = NULL;
49
50 static desc_t *all_descs = NULL;
51
52 static int name_id = 0;
53
54 # define PTO_COLOR
55
56 # ifdef PTO_COLOR
57 static int last_col_idx = 0;
58
59 /* Local Prototypes: */
60 static int pto_name_alloc_color (desc_t*);
61 static void pto_name_set_color (desc_t*, int);
62 # endif /* defined PTO_COLOR */
63
64 /* ===================================================
65    Local Implementation:
66    =================================================== */
67 # ifdef PTO_COLOR
68 /* set a nice color to an object descriptor */
69 static void pto_name_set_obj_color (obj_desc_t *obj_desc, int col_idx)
70 {
71   int i;
72
73   for (i = 0; i < obj_desc->n_fields; i ++) {
74     qset_t *ptos = obj_desc->values [i];
75
76     desc_t *tgt = (desc_t*) qset_start (ptos);
77
78     while (NULL != tgt) {
79       pto_name_set_color (tgt, col_idx);
80
81       tgt = (desc_t*) qset_next (ptos);
82     }
83   }
84 }
85
86 /* set a nice color to an array descriptor */
87 static void pto_name_set_arr_color (arr_desc_t *arr_desc, int col_idx)
88 {
89   qset_t *ptos = arr_desc->value;
90
91   desc_t *tgt = (desc_t*) qset_start (ptos);
92
93   while (NULL != tgt) {
94     pto_name_set_color (tgt, col_idx);
95
96     tgt = (desc_t*) qset_next (ptos);
97   }
98 }
99
100 /* set a nice color to a descriptor */
101 static void pto_name_set_color (desc_t *desc, int col_idx)
102 {
103   /* assert (0 == desc->col_idx); */
104
105   desc->col_idx = col_idx;
106
107   if (FALSE == desc->visit) {
108     desc->visit = TRUE;
109     if (object == desc->kind) {
110       pto_name_set_obj_color ((obj_desc_t*) desc, col_idx);
111     } else if (array == desc->kind) {
112       pto_name_set_arr_color ((arr_desc_t*) desc, col_idx);
113     }
114
115     desc->visit = FALSE;
116   }
117 }
118
119
120 /* allocate nice colors for an object descriptor */
121 static int pto_name_alloc_obj_color (obj_desc_t *obj_desc)
122 {
123   int i;
124   int col_idx = 0;
125
126   for (i = 0; (0 == col_idx) && (i < obj_desc->n_fields); i ++) {
127     qset_t *ptos = obj_desc->values [i];
128     desc_t *tgt = (desc_t*) qset_start (ptos);
129
130     while ((0 == col_idx) && (NULL != tgt)) {
131       col_idx = pto_name_alloc_color (tgt);
132
133       tgt = (desc_t*) qset_next (ptos);
134     }
135   }
136
137   return (col_idx);
138 }
139
140 /* allocate nice colors for an array descriptor */
141 static int pto_name_alloc_arr_color (arr_desc_t *arr_desc)
142 {
143   int col_idx = 0;
144
145   qset_t *ptos = arr_desc->value;
146
147   desc_t *tgt = (desc_t*) qset_start (ptos);
148
149   while ((NULL != tgt) && (0 == col_idx)) {
150     col_idx = pto_name_alloc_color (tgt);
151     tgt = (desc_t*) qset_next (ptos);
152   }
153
154   return (col_idx);
155 }
156
157 /* allocate nice colors for the given descriptor */
158 static int pto_name_alloc_color (desc_t *desc)
159 {
160   int col_idx = 0;
161
162   if (0 != desc->col_idx) {
163     return (desc->col_idx);
164   }
165
166   if (FALSE == desc->visit) {
167     desc->visit = TRUE;
168     if (object == desc->kind) {
169       col_idx = pto_name_alloc_obj_color ((obj_desc_t*) desc);
170     } else if (array == desc->kind) {
171       col_idx = pto_name_alloc_arr_color ((arr_desc_t*) desc);
172     }
173     desc->visit = FALSE;
174   }
175
176   if (0 == col_idx) {
177     col_idx = ++ last_col_idx;
178   }
179
180   pto_name_set_color (desc, col_idx);
181
182   return (col_idx);
183 }
184
185 /* allocate nice colors */
186 static void pto_name_alloc_colors (void)
187 {
188   desc_t *desc = all_descs;
189
190   while (NULL != desc) {
191     pto_name_alloc_color (desc);
192
193     desc = desc->prev;
194   }
195 }
196 # endif /* defined PTO_COLOR */
197
198 /* See whether the given entity is a field. */
199 static int is_field (entity *ent)
200 {
201   type *tp = get_entity_type (ent);
202
203   if (is_Primitive_type (tp) || is_Pointer_type (tp)) {
204     /* actually, we don't get by by restricting ourselves to pointer types */
205     return (TRUE);
206   } else {
207     return (FALSE);
208   }
209 }
210
211 /* Helper to collect_fields(type*): collect all fields of the given
212   clazz and its super classes into the given obstack. */
213 static void _collect_fields (type *clazz, struct obstack *obst)
214 {
215   int n_members = get_class_n_members (clazz);
216   int n_supers  = get_class_n_supertypes (clazz);
217   int i;
218
219   for (i = 0; i < n_members; i ++) {
220     entity *ent = get_class_member (clazz, i);
221
222     if (is_field (ent)) {
223       if (allocation_static != get_entity_allocation (ent)) {
224         obstack_ptr_grow (obst, ent);
225       }
226     }
227   }
228
229   for (i = 0; i < n_supers; i ++) {
230     type *s_clazz = get_class_supertype (clazz, i);
231
232     _collect_fields (s_clazz, obst);
233   }
234 }
235
236 /* Collect the fields of the given class and its super classes into an array.
237   The last entry of the array is written NULL. */
238 static entity **collect_fields (type *clazz)
239 {
240   struct obstack obst;
241   int n_fields;
242   entity ** fields;
243   void *tmp;
244
245   if (NULL != get_type_link (clazz)) {
246     DBGPRINT (3, (stdout, "%s: reusing field list for \"%s\"\n",
247                   __FUNCTION__,
248                   get_type_name (clazz)));
249
250     return ((entity **) get_type_link (clazz));
251   } else {
252     DBGPRINT (2, (stdout, "%s: new field list for \"%s\"\n",
253                   __FUNCTION__,
254                   get_type_name (clazz)));
255   }
256
257   obstack_init (&obst);
258
259   _collect_fields (clazz, &obst);
260
261   /* append terminating NULL */
262   obstack_ptr_grow (&obst, NULL);
263
264   n_fields = obstack_object_size (&obst) / sizeof (void*);
265
266   fields = NALLOC (n_fields * sizeof (entity*));
267   tmp = obstack_finish(&obst);
268
269   memcpy (fields, tmp, n_fields * sizeof (entity*));
270
271   obstack_free (&obst, NULL);
272
273   set_type_link (clazz, fields);
274
275   return (fields);
276 }
277
278 /* Write the intro text for a name dump into the given stream */
279 static void pto_name_dump_start (FILE *stream)
280 {
281 # ifdef PTO_COLOR
282   pto_name_alloc_colors ();
283 # endif /* defined PTO_COLOR */
284
285   fprintf (stream, "digraph \"Names\" {\n");
286   fprintf (stream, "\tgraph [rankdir=\"LR\", ordering=\"out\", size=\"11,7\", rotate=\"90\"];\n");
287   fprintf (stream, "\tnode [shape=\"record\", style=\"filled\"];\n");
288   fprintf (stream, "\tedge [color=\"black\"];\n");
289   fprintf (stream, "\n");
290 }
291
292 /* Write the extro text for a name dump into the given stream */
293 static void pto_name_dump_finish (FILE *stream)
294 {
295   fprintf (stream, "}\n");
296 }
297
298 /* Write a node for the given descriptor into the given stream */
299 static void pto_name_dump_desc (desc_t *desc, FILE *stream)
300 {
301   type *tp = desc->tp;
302   const char *tp_name = get_type_name (tp);
303   ir_node *nd;
304
305   fprintf (stream, "\t/* %s \"%s\" */\n",
306            object == desc->kind ? "Object" : "Array",
307            tp_name);
308
309   fprintf (stream, "\tdesc_%i [label=\"<HEAD>type \\[%i\\]",
310            desc->id, desc->id);
311
312   if (-1 != desc->ctx) {
313     fprintf (stream, ", ctx = %i", desc->ctx);
314   } else {
315     fprintf (stream, " (global)");
316   }
317
318   fprintf (stream, "\\lname=\\\"%s\\\"",
319            tp_name);
320
321   nd = desc->node;
322
323   if (NULL != nd) {
324     ir_graph *graph = get_irn_irg (nd);
325     entity *method = get_irg_entity (graph);
326     const char *ent_name = get_entity_name (method);
327     const char *own_name = get_type_name (get_entity_owner (method));
328
329     fprintf (stream, "\\lnode=%s\\[%li\\]",
330              get_op_name (get_irn_op (nd)),
331              get_irn_node_nr (nd));
332     fprintf (stream, "\\lgraph=\\\"%s.%s\\\"",
333              own_name,
334              ent_name);
335   }
336
337   if (desc->kind == object) {
338     obj_desc_t *obj_desc = (obj_desc_t*) desc;
339
340     int i;
341     for (i = 0; i < obj_desc->n_fields; i ++) {
342       entity *field = obj_desc->fields [i];
343
344       if (is_Pointer_type (get_entity_type (field))) {
345         const char *ent_name = get_entity_name (field);
346
347         fprintf (stream, "|<%i>%s", i, ent_name);
348       }
349     }
350   } else if (array == desc->kind) {
351     fprintf (stream, "|<arr>[]");
352   } else {
353     assert (0 && "invalid descriptor");
354   }
355
356   /* end label string */
357   fprintf (stream, "\"");
358
359 # ifdef PTO_COLOR
360   {
361     const char *fontcolor;
362     int col_idx = desc->col_idx;
363     float hue = (float) col_idx / (float) last_col_idx;
364     float sat = 1.000f;            /* 0.300 .. 1.000 */
365     float val = 0.800f;            /* 0.300 .. 1.000 */
366
367   # define MAX_COLORS 12
368     if (last_col_idx > MAX_COLORS) {
369       /* too many colors ... vary value too */
370       float div = (float) MAX_COLORS / (float) last_col_idx;
371
372       sat = (div * ((col_idx / MAX_COLORS)));
373       val = (div * ((col_idx / MAX_COLORS)));
374
375       col_idx = col_idx % MAX_COLORS;
376       hue = (float) col_idx / (float) MAX_COLORS;
377
378       // re-adjust sat and val
379       {
380         const float sat_min = 0.200f; /* 0.200 .. 0.400 */
381         const float val_min = 0.300f; /* 0.300 .. 0.400 */
382
383         sat = sat_min + ((1.0f - sat_min) * sat);
384         val = val_min + ((1.0f - val_min) * val);
385       }
386     }
387   # undef MAX_COLORS
388
389     fprintf (stream, ", color=\"%01.3f, %01.3f, %01.3f\"", hue, sat, val);
390
391     if ((hue > 0.3) && (sat < 0.5)) {
392       fontcolor = "white";
393     } else if (sat < 0.4) {
394       fontcolor = "white";
395     } else {
396       fontcolor = "black";
397     }
398
399     fprintf (stream, ", fontcolor=\"%s\"", fontcolor);
400   }
401 # else /* if defined PTO_COLOR */
402   fprintf (stream, ", color=\"lightgrey\"");
403 # endif /* defined PTO_COLOR */
404
405   /* end attributes */
406   fprintf (stream, "];\n");
407   fprintf (stream, "\n");
408
409   /* now the edges */
410   if (desc->kind == object) {
411     obj_desc_t *obj_desc = (obj_desc_t*) desc;
412
413     int i;
414     for (i = 0; i < obj_desc->n_fields; i ++) {
415       desc_t *tgt = (desc_t*) qset_start (obj_desc->values [i]);
416
417       while (NULL != tgt) {
418         fprintf (stream, "\tdesc_%i:%i -> desc_%i:HEAD;\n",
419                  desc->id, i, tgt->id);
420
421         tgt = (desc_t*) qset_next (obj_desc->values [i]);
422       }
423     }
424   } else if (array == desc->kind) {
425     arr_desc_t *arr_desc = (arr_desc_t*) desc;
426
427     desc_t *tgt = (desc_t*) qset_start (arr_desc->value);
428
429     while (NULL != tgt) {
430       fprintf (stream, "\tdesc_%i:arr -> desc_%i:HEAD;\n",
431                desc->id, tgt->id);
432
433       tgt = (desc_t*) qset_next (arr_desc->value);
434     }
435   }
436
437   fprintf (stream, "\n");
438 }
439
440
441 /* ===================================================
442    Exported Implementation:
443    =================================================== */
444 /* Find the given descriptor's entry for the given entity */
445 qset_t *get_entry (desc_t *desc, entity *ent)
446 {
447
448   if (desc->kind == object) {
449     obj_desc_t *obj_desc = (obj_desc_t*) desc;
450     int i;
451     const int n_fields = obj_desc->n_fields;
452
453     for (i = 0; i < n_fields; i ++) {
454       if (ent == obj_desc->fields [i]) {
455         return (obj_desc->values [i]);
456       }
457     }
458
459     assert (0 && "entry not found");
460   } else if (desc->kind == array) {
461     arr_desc_t *arr_desc = (arr_desc_t*) desc;
462
463     return (arr_desc->value);
464   } else {
465     assert (0 && "invalid descriptor");
466   }
467   return NULL;
468 }
469
470
471 /* get a new descriptor for the given type at the given node */
472 desc_t *new_name (type *tp, ir_node *node, int ctx)
473 {
474   desc_t *desc = NULL;
475
476   assert ((is_Class_type (tp) || is_Array_type (tp)) && "unsuitable type");
477
478   DBGPRINT (2, (stdout, "%s: new name for type \"%s\"\n",
479                 __FUNCTION__,
480                 get_type_name (tp)));
481   fflush (stdout);
482
483   if (is_Class_type (tp)) {
484     obj_desc_t *obj_desc = NALLOC (sizeof (obj_desc_t));
485     int i;
486     int n_fields;
487
488     obj_desc->kind = object;
489     obj_desc->fields = collect_fields (tp);
490
491     for (n_fields = 0; (NULL != obj_desc->fields [n_fields]); n_fields ++) {
492       /* nothing, just count ... */
493     }
494
495     obj_desc->n_fields = n_fields;
496     obj_desc->values = (qset_t**) NALLOC (n_fields * sizeof (qset_t*));
497
498     for (i = 0; i < n_fields; i ++) {
499       obj_desc->values [i] = qset_new (N_INITIAL_OJBS, qset_obst);
500     }
501
502     desc = (desc_t*) obj_desc;
503   } else if (is_Array_type (tp)) {
504     arr_desc_t *arr_desc = (arr_desc_t*) NALLOC (sizeof (arr_desc_t));
505
506     arr_desc->kind = array;
507     arr_desc->value = qset_new (N_INITIAL_OJBS, qset_obst);
508
509     desc = (desc_t*) arr_desc;
510   }
511
512   desc->id    = name_id ++;
513   desc->col_idx = 0;
514   desc->tp    = tp;
515   desc->visit = FALSE;
516   desc->ctx   = ctx;
517   desc->node  = node;
518
519   desc->prev  = all_descs;
520   all_descs = desc;
521
522   return (desc);
523 }
524
525 # define N_GLOB_INITIAL_FIELDS  20
526 static obj_desc_t *obj_glob = NULL;
527 static int n_glob_fields = N_GLOB_INITIAL_FIELDS;
528
529 /* get a new descriptor for the given (presumably static) entity */
530 desc_t *new_ent_name (entity *ent)
531 {
532   int i;
533   int missing = TRUE;
534   type *tp = get_entity_type (ent);
535
536   assert (is_Pointer_type (tp));
537   tp = get_pointer_points_to_type (tp);
538   assert (is_Class_type (tp));
539
540   DBGPRINT (2, (stdout, "%s: new name for entity \"%s\"\n",
541                 __FUNCTION__,
542                 get_entity_name (ent)));
543   DBGEXE (2, (fflush (stdout)));
544
545   assert (((allocation_static == get_entity_allocation (ent)) ||
546            (allocation_automatic == get_entity_allocation (ent))) &&
547           "not a static/automatic field");
548
549   if (NULL == obj_glob) {
550     obj_glob = (obj_desc_t*) NALLOC (sizeof (obj_desc_t));
551
552     obj_glob->id   = name_id ++;
553     obj_glob->ctx  = -1;
554     obj_glob->col_idx = 0;
555     obj_glob->visit = FALSE;
556     obj_glob->kind = object;
557     obj_glob->tp   = get_glob_type ();
558     obj_glob->node = NULL;
559
560     obj_glob->n_fields = 0;
561     obj_glob->fields = (entity**) NALLOC (N_GLOB_INITIAL_FIELDS * sizeof (entity*));
562     obj_glob->values = (qset_t**) NALLOC (N_GLOB_INITIAL_FIELDS * sizeof (qset_t*));
563
564     obj_glob->prev = all_descs;
565     all_descs = (desc_t*) obj_glob;
566   }
567
568   for (i = 0; missing && (i < obj_glob->n_fields); i ++) {
569     if (ent == obj_glob->fields [i]) {
570       missing = FALSE;
571     }
572   }
573
574   if (missing) {
575     if (obj_glob->n_fields == n_glob_fields) {
576       entity **fields = obj_glob->fields;
577       qset_t **values = obj_glob->values;
578
579       n_glob_fields *= 2;
580       obj_glob->fields = (entity**) NALLOC (n_glob_fields * sizeof (entity*));
581       obj_glob->values = (qset_t**) NALLOC (n_glob_fields * sizeof (qset_t*));
582
583       memcpy (obj_glob->fields, fields, obj_glob->n_fields * sizeof (entity*));
584       memcpy (obj_glob->values, values, obj_glob->n_fields * sizeof (qset_t*));
585
586       /* free (fields); */
587       /* free (values); */
588     }
589
590     obj_glob->fields [obj_glob->n_fields   ] = ent;
591     obj_glob->values [obj_glob->n_fields ++] = qset_new (N_INITIAL_OJBS, qset_obst);
592   }
593
594   return ((desc_t*) obj_glob);
595 }
596 # undef N_GLOB_INITIAL_FIELDS
597
598 /* Dump all names to a file of the given name */
599 void pto_dump_names (const char *name)
600 {
601   desc_t *desc = all_descs;
602   FILE *stream = fopen (name, "w");
603
604   errno = 0;
605   if  (NULL == stream) {
606     fprintf (stderr, "%s: unable to open %s (%s)\n",
607              __FUNCTION__, name, strerror (errno));
608     return;
609   }
610
611   pto_name_dump_start (stream);
612
613   while (NULL != desc) {
614     pto_name_dump_desc (desc, stream);
615
616     desc = desc->prev;
617   }
618
619   pto_name_dump_finish (stream);
620   fclose (stream);
621 }
622
623 /* Initialise the name module */
624 void pto_name_init (void)
625 {
626   DBGPRINT (3, (stdout, "%s\n", __FUNCTION__));
627   assert (NULL == name_obst);
628   assert (NULL == qset_obst);
629
630   name_obst = xmalloc (sizeof (struct obstack));
631   qset_obst = xmalloc (sizeof (struct obstack));
632
633   obstack_init (name_obst);
634   obstack_init (qset_obst);
635 }
636
637 /* Cleanup the name module */
638 void pto_name_cleanup (void)
639 {
640   DBGPRINT (3, (stdout, "%s\n", __FUNCTION__));
641   obstack_free (name_obst, NULL);
642   obstack_free (qset_obst, NULL);
643
644   memset (name_obst, 0x00, sizeof (struct obstack));
645   memset (qset_obst, 0x00, sizeof (struct obstack));
646
647   free (name_obst);
648   free (qset_obst);
649
650   name_obst = NULL;
651   qset_obst = NULL;
652 }
653
654 \f
655 /*
656   $Log$
657   Revision 1.15  2005/03/02 10:14:38  beck
658   placed a return on all execution pathes
659
660   Revision 1.14  2005/02/17 08:45:38  liekweg
661   Don't return a value for an invalid descriptor
662
663   Revision 1.13  2005/02/11 10:21:28  beck
664   get_entry now always returns a value
665
666   Revision 1.12  2005/01/14 14:13:56  liekweg
667   fix gnu extension, fix fprintf's, fix allocs
668
669   Revision 1.11  2005/01/05 14:25:54  beck
670   renames all is_x*_type() functions to is_X*_type() to prevent name clash with EDG fronten
671
672   Revision 1.10  2004/12/22 14:43:14  beck
673   made allocations C-like
674
675   Revision 1.9  2004/12/21 15:34:09  beck
676   removed C99 constructs
677   make const float
678   add default return
679
680   Revision 1.8  2004/12/15 13:30:30  liekweg
681   use DBGEXE correctly; print yet nicer names
682
683   Revision 1.7  2004/12/15 09:18:18  liekweg
684   pto_name.c
685
686   Revision 1.6  2004/12/06 12:52:09  liekweg
687   colorize name dump
688
689   Revision 1.4  2004/11/30 15:49:27  liekweg
690   include 'dump'
691
692   Revision 1.3  2004/11/30 14:47:54  liekweg
693   fix initialisation; do correct iteration
694
695   Revision 1.2  2004/11/24 14:53:56  liekweg
696   Bugfixes
697
698   Revision 1.1  2004/11/18 16:37:34  liekweg
699   rewritten
700
701
702 */