added license infos
[libfirm] / ir / ana / rta.c
1 /*
2  * Copyrigth (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief    Interprocedural analysis to improve the call graph estimate.
23  * @author   Florian
24  * @version  09.06.2002
25  * @version  $Id$
26  */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "rta.h"
32
33 #include <stdlib.h>
34
35 #include "irnode_t.h"
36 #include "irprog_t.h"
37 #include "irgraph_t.h"
38
39 #include "eset.h"
40 #include "irgwalk.h"
41 #include "irgmod.h"
42 #include "typewalk.h"
43 #include "irvrfy.h"
44 #include "trvrfy.h"
45
46 # ifndef TRUE
47 #  define TRUE 1
48 #  define FALSE 0
49 # endif /* not defined TRUE */
50
51 /* flags */
52 static int verbose     = 0;
53
54
55 /* base data */
56 static eset *_live_classes   = NULL;
57
58 /* cache computed results */
59 static eset *_live_graphs    = NULL;
60
61 /**
62    Given a method, find the firm graph that implements that method.
63 */
64 static ir_graph *get_implementing_graph (ir_entity *method)
65 {
66 #if 0
67   ir_graph *graph = get_entity_irg ((ir_entity*) method);
68
69   /* Search upwards in the overwrites graph. */
70   /* GL: this will not work for multiple inheritance */
71   if (NULL == graph) {
72     int i;
73     int n_over = get_entity_n_overwrites ((ir_entity*) method);
74
75     for (i = 0; (NULL == graph) && (i < n_over); i ++) {
76       ir_entity *over = get_entity_overwrites ((ir_entity*) method, i);
77       graph = get_implementing_graph (over);
78     }
79   }
80
81   /* GL   this is not valid in our remove irg algorithm ... which we removed by now ...  */
82   assert(get_entity_peculiarity(method) == peculiarity_description
83      || graph == get_entity_irg(get_SymConst_entity(get_atomic_ent_value(method))));
84
85   /* we *must* always return a graph != NULL, *except* when we're used
86      inside remove_irg or force_description */
87   /* assert (graph && "no graph"); */
88
89   return (graph);
90 #else
91   ir_graph *graph = NULL;
92
93   if (get_entity_peculiarity(method) != peculiarity_description)
94     graph = get_entity_irg(get_SymConst_entity(get_atomic_ent_value(method)));
95
96   return graph;
97 #endif
98 }
99
100 /**
101  * Add a graph to the set of live graphs.
102  *
103  * @param graph  the graph to add
104  * @return non-zero if the graph was added, zero
105  *         if it was already in the live set
106  */
107 static int add_graph (ir_graph *graph)
108 {
109   if (!eset_contains (_live_graphs, graph)) {
110     if (verbose > 1) {
111       fprintf(stdout, "RTA:        new graph of ");
112       DDMEO(get_irg_entity (graph));
113     }
114
115     eset_insert (_live_graphs, graph);
116     return (TRUE);
117   }
118
119   return (FALSE);
120 }
121
122 /**
123  * Add a class to the set of live classes.
124  *
125  * @param clazz   the class to add
126  * @return non-zero if the graph was added, zero
127  *         if it was already in the live set
128  */
129 static int add_class (ir_type *clazz)
130 {
131   if (!eset_contains (_live_classes, clazz)) {
132     if (verbose > 1) {
133       fprintf(stdout, "RTA:        new class: ");
134       DDMT(clazz);
135     }
136
137     eset_insert (_live_classes, clazz);
138     return (TRUE);
139   }
140
141   return (FALSE);
142 }
143
144 /** Given an entity, add all implementing graphs that belong to live classes
145  *  to _live_graphs.
146  *
147  *  Iff additions occurred, return TRUE, else FALSE.
148 */
149 static int add_implementing_graphs (ir_entity *method)
150 {
151   int i;
152   int n_over = get_entity_n_overwrittenby (method);
153   ir_graph *graph = get_entity_irg (method);
154   int change = FALSE;
155
156   if (NULL == graph) {
157     graph = get_implementing_graph (method);
158   }
159
160   if (verbose > 1) {
161     fprintf(stdout, "RTA:        new call to ");
162     DDMEO(method);
163   }
164
165   if (rta_is_alive_class (get_entity_owner (method))) {
166     if (NULL != graph) {
167       change = add_graph (graph);
168     }
169   }
170
171   for (i = 0; i < n_over; i ++) {
172     ir_entity *over = get_entity_overwrittenby (method, i);
173     change |= add_implementing_graphs (over);
174   }
175
176   return (change);
177 }
178
179 /** Enter all method accesses and all class allocations into
180  *  our tables.
181  *
182  *  Set *(int*)env to true iff (possibly) new graphs have been found.
183  */
184 static void rta_act (ir_node *node, void *env)
185 {
186   int *change = (int*) env;
187   ir_opcode op = get_irn_opcode (node);
188
189   if (iro_Call == op) {         /* CALL */
190     ir_entity *ent = NULL;
191
192     ir_node *ptr = get_Call_ptr (node);
193
194     /* CALL SEL */
195     if (iro_Sel == get_irn_opcode (ptr)) {
196       ent = get_Sel_entity (ptr);
197       *change |= add_implementing_graphs (ent);
198
199       /* CALL SYMCONST */
200     } else if (iro_SymConst == get_irn_opcode (ptr)) {
201       if (get_SymConst_kind(ptr) == symconst_addr_ent) {
202         ir_graph *graph;
203
204         ent = get_SymConst_entity (ptr);
205         graph = get_entity_irg (ent);
206         if (graph) {
207           *change |= add_graph (graph);
208         } else {
209           /* it's an external allocated thing. */
210         }
211       } else if (get_SymConst_kind(ptr) == symconst_addr_name) {
212             /* Entities of kind addr_name may not be allocated in this compilation unit.
213                If so, the frontend built faulty Firm.  So just ignore. */
214             /* if (get_SymConst_name(ptr) != new_id_from_str("iro_Catch"))
215         assert (ent && "couldn't determine entity of call to SymConst of kind addr_name."); */
216       } else {
217         /* other symconst. */
218         assert(0 && "This SymConst can not be an address for a method call.");
219       }
220
221       /* STRANGE */
222     } else {
223       DDMN(ptr);
224       assert(0 && "Unexpected address expression: can not analyse, therefore can not do correct rta!");
225     }
226
227   } else if (iro_Alloc == op) { /* ALLOC */
228     ir_type *type = get_Alloc_type (node);
229
230     *change |= add_class (type);
231   }
232 }
233
234 /**
235    Traverse the given graph to collect method accesses and
236    object allocations.
237 */
238 static int rta_fill_graph (ir_graph* graph)
239 {
240   int change = FALSE;
241   irg_walk_graph (graph, rta_act, NULL, &change);
242   return change;
243 }
244
245 /** Traverse all graphs to collect method accesses and object allocations.
246  */
247 static int rta_fill_incremental (void)
248 {
249   int i;
250   int n_runs = 0;
251   int rerun  = TRUE;
252   int old_ip_view = get_interprocedural_view();
253
254   set_interprocedural_view(0);     /* save this for later */
255
256   /* init_tables has added main_irg to _live_graphs */
257
258   /* Need to take care of graphs that are externally
259      visible or sticky. Pretend that they are called: */
260
261   for (i = 0; i < get_irp_n_irgs(); i++) {
262     ir_graph *graph = get_irp_irg (i);
263     ir_entity *ent = get_irg_entity (graph);
264
265     if ((visibility_external_visible == get_entity_visibility (ent)) ||
266         (stickyness_sticky == get_entity_stickyness (ent))) {
267       eset_insert (_live_graphs, graph);
268       // printf("external visible: "); DDMG(graph);
269     }
270   }
271
272   while (rerun) {
273     ir_graph *graph;
274
275     /* start off new */
276     eset *live_graphs = _live_graphs;
277     _live_graphs = eset_create ();
278
279     if (verbose > 1) {
280       fprintf(stdout, "RTA: RUN %i\n", n_runs);
281     }
282
283     /* collect what we have found previously */
284     eset_insert_all (_live_graphs, live_graphs);
285
286     rerun = FALSE;
287     for (graph = eset_first (live_graphs);
288          graph;
289          graph = eset_next (live_graphs)) {
290
291       if (verbose > 1) {
292         fprintf(stdout, "RTA: RUN %i: considering graph of ", n_runs);
293         DDMEO(get_irg_entity (graph));
294       }
295
296       rerun |= rta_fill_graph (graph);
297     }
298
299     eset_destroy (live_graphs);
300
301     n_runs ++;
302   }
303
304   set_interprocedural_view(old_ip_view); /* cover up our traces */
305
306   return (n_runs);
307 }
308
309 /**
310  * Count the number of graphs that we have found to be live.
311  */
312 static int stats (void)
313 {
314   int i;
315   int n_live_graphs = 0;
316   int n_graphs = get_irp_n_irgs();
317
318   for (i = 0; i < n_graphs; i++) {
319     ir_graph *graph = get_irp_irg(i);
320
321     if (rta_is_alive_graph (graph)) {
322       n_live_graphs ++;
323     }
324   }
325
326   return (n_live_graphs);
327 }
328
329 /* remove a graph, part I */
330 /*
331    We removed the first graph to implement the entity, so we're
332    abstract now.  Pretend that it wasn't there at all, and every
333    entity that used to inherit this entity's graph is now abstract.
334 */
335 /* Since we *know* that this entity will not be called, this is OK. */
336 static void force_description (ir_entity *ent, ir_entity *addr)
337 {
338   int i, n_over = get_entity_n_overwrittenby (ent);
339
340   set_entity_peculiarity (ent, peculiarity_description);
341
342   for (i = 0; i < n_over; i ++) {
343     ir_entity *over = get_entity_overwrittenby (ent, i);
344
345     if (peculiarity_inherited == get_entity_peculiarity (over)) {
346       /* We rely on the fact that cse is performed on the const_code_irg. */
347       ir_entity *my_addr = get_SymConst_entity(get_atomic_ent_value(over));
348
349       if (addr == my_addr) {
350         force_description (over, addr);
351       }
352     } else if (peculiarity_existent == get_entity_peculiarity (over)) {
353       /* check whether 'over' forces 'inheritance' of *our* graph: */
354       ir_node *f_addr = get_atomic_ent_value (over);
355       ir_entity *impl_ent = get_SymConst_entity (f_addr);
356
357       assert ((get_irn_op(f_addr) == op_SymConst) && "can't do complex addrs");
358       if (impl_ent == addr) {
359         assert (0 && "gibt's denn sowas");
360         force_description (over, addr);
361       }
362     }
363   }
364 }
365
366 /**
367    Initialize the static data structures.
368 */
369 static void init_tables (void)
370 {
371   ir_type *tp;
372   int i, n;
373
374   _live_classes = eset_create ();
375   _live_graphs  = eset_create ();
376
377   if (get_irp_main_irg ()) {
378     eset_insert (_live_graphs, get_irp_main_irg ());
379   }
380
381   /* Find static allocated classes */
382   tp = get_glob_type();
383   n = get_class_n_members(tp);
384   for (i = 0; i < n; ++i) {
385     ir_type *member_type = get_entity_type(get_class_member(tp, i));
386     if (is_Class_type(member_type))
387       eset_insert(_live_classes, member_type);
388   }
389
390   tp = get_tls_type();
391   n = get_struct_n_members(tp);
392   for (i = 0; i < n; ++i) {
393     ir_type *member_type = get_entity_type(get_struct_member(tp, i));
394     if (is_Class_type(member_type))
395       eset_insert(_live_classes, member_type);
396   }
397 }
398
399 /*
400  * Initialize the RTA data structures, and perform RTA.
401  * do_verbose If == 1, print statistics, if > 1, chatter about every detail
402  */
403 void rta_init (int do_verbose)
404 {
405   int n_runs = 0;
406
407   int rem_vpi = get_visit_pseudo_irgs();
408   set_visit_pseudo_irgs(1);
409
410 # ifdef DEBUG_libfirm
411   {
412     int i, n;
413     n = get_irp_n_irgs();
414     for (i = 0; i < n; i++) {
415       irg_vrfy (get_irp_irg(i));
416         }
417     tr_vrfy ();
418   }
419 # endif /* defined DEBUG_libfirm */
420
421   verbose = do_verbose;
422
423   init_tables ();
424
425   n_runs = rta_fill_incremental ();
426
427   if (verbose) {
428     int n_live_graphs = stats ();
429
430     printf ("RTA: n_graphs      = %i\n", get_irp_n_irgs ());
431     printf ("RTA: n_live_graphs = %i\n", n_live_graphs);
432     printf ("RTA: n_runs        = %i\n", n_runs);
433   }
434
435 # ifdef DEBUG_libfirm
436   {
437     int i, n;
438     n = get_irp_n_irgs();
439     for (i = 0; i < n; i++) {
440       irg_vrfy (get_irp_irg(i));
441         }
442     tr_vrfy ();
443   }
444 # endif /* defined DEBUG_libfirm */
445
446   set_visit_pseudo_irgs(rem_vpi);
447 }
448
449 /**
450  * walker for all types and entities
451  *
452  * Changes the peculiarity of entities that represents
453  * dead graphs to peculiarity_description.
454  */
455 static void make_entity_to_description(type_or_ent *tore, void *env) {
456   if (get_kind(tore) == k_entity) {
457     ir_entity *ent = (ir_entity *)tore;
458
459     if ((is_Method_type(get_entity_type(ent)))                        &&
460         (get_entity_peculiarity(ent) != peculiarity_description)      &&
461         (get_entity_visibility(ent)  != visibility_external_allocated)   ) {
462       ir_graph *irg = get_entity_irg(get_SymConst_entity(get_atomic_ent_value(ent)));
463       if (!eset_contains (_live_graphs, irg)) {
464         set_entity_peculiarity(ent, peculiarity_description);
465         set_entity_irg(ent, NULL);
466       }
467     }
468   }
469 }
470
471 /* Delete all graphs that we have found to be dead from the program
472    If verbose == 1, print statistics, if > 1, chatter about every detail
473 */
474 void rta_delete_dead_graphs (void)
475 {
476   int i;
477   int n_graphs = get_irp_n_irgs ();
478   ir_graph *graph = NULL;
479   int n_dead_graphs = 0;
480   ir_graph **dead_graphs;
481
482   int rem_vpi = get_visit_pseudo_irgs();
483   set_visit_pseudo_irgs(1);
484
485   if (!get_optimize() || !get_opt_dead_method_elimination()) return;
486
487   dead_graphs = xmalloc(sizeof(*dead_graphs) * get_irp_n_irgs());
488
489   for (i = 0; i < n_graphs; i++) {
490     graph = get_irp_irg(i);
491
492     if (rta_is_alive_graph (graph)) {
493       /* do nothing (except some debugging fprintf`s :-) */
494     } else {
495 #ifndef NDEBUG
496       ir_entity *ent = get_irg_entity (graph);
497       assert (visibility_external_visible != get_entity_visibility (ent));
498 #endif
499
500       dead_graphs[n_dead_graphs] = graph;
501       n_dead_graphs ++;
502     }
503   }
504
505   type_walk(make_entity_to_description, NULL, NULL);
506   for (i = 0; i < n_dead_graphs; ++i) {
507     remove_irp_irg (dead_graphs[i]);
508   }
509
510   if (verbose) {
511     printf ("RTA: n_dead_graphs = %i\n", n_dead_graphs);
512   }
513
514   set_visit_pseudo_irgs(rem_vpi);
515
516   free(dead_graphs);
517 }
518
519 /* Clean up the RTA data structures.  Call this after calling rta_init */
520 void rta_cleanup (void)
521 {
522 # ifdef DEBUG_libfirm
523   int i;
524     for (i = 0; i < get_irp_n_irgs(); i++) {
525       irg_vrfy (get_irp_irg(i));
526     }
527     tr_vrfy ();
528 # endif /* defined DEBUG_libfirm */
529
530   if (_live_classes) {
531     eset_destroy (_live_classes);
532     _live_classes = NULL;
533   }
534
535   if (_live_graphs) {
536     eset_destroy (_live_graphs);
537     _live_graphs = NULL;
538   }
539 }
540
541 /* Say whether this class might be instantiated at any point in the program: */
542 int  rta_is_alive_class  (ir_type   *clazz)
543 {
544   return (eset_contains (_live_classes, clazz));
545 }
546
547 /* Say whether this graph might be run at any time in the program: */
548 int  rta_is_alive_graph (ir_graph *graph)
549 {
550   return eset_contains (_live_graphs, graph);
551 }
552
553 /* dump our opinion */
554 void rta_report (void)
555 {
556   int i;
557
558   for (i = 0; i < get_irp_n_types(); ++i) {
559     ir_type *tp = get_irp_type(i);
560     if (is_Class_type(tp) && rta_is_alive_class(tp)) {
561       fprintf(stdout, "RTA: considered allocated: "); DDMT(tp);
562     }
563   }
564
565   for (i = 0; i < get_irp_n_irgs(); i++) {
566     if (rta_is_alive_graph (get_irp_irg(i))) {
567       fprintf(stdout, "RTA: considered called: graph of ");
568       DDMEO(get_irg_entity (get_irp_irg(i)));
569     }
570   }
571 }
572
573
574 /*
575  * $Log$
576  * Revision 1.41  2007/03/22 10:39:33  matze
577  * a bunch of fixes to make firm work with NDEBUG and without DEBUG_libfirm
578  *
579  * Revision 1.40  2007/01/16 15:45:15  beck
580  * renamed type opcode to ir_opcode
581  *
582  * Revision 1.39  2006/12/13 13:15:12  beck
583  * renamed entity -> ir_entity
584  *
585  * Revision 1.38  2006/12/12 16:12:05  beck
586  * Fixed missing initialization
587  *
588  * Revision 1.37  2006/12/11 15:28:48  matze
589  * - Several warning fixes
590  * - Fixes for compilation without DEBUG_libfirm
591  * - Fixed for compilation without WITH_LIBCORE (but it's still broken)
592  *
593  * Revision 1.36  2006/06/05 15:58:12  beck
594  * added support for Thread local storage
595  * added more doxygen docu
596  *
597  * Revision 1.35  2006/01/13 21:51:59  beck
598  * renamed all types 'type' to 'ir_type'
599  *
600  * Revision 1.34  2006/01/02 15:01:16  beck
601  * missing include added
602  *
603  * Revision 1.33  2005/11/17 17:26:57  beck
604  * removed bool type and depency from stdbool.h (not C89)
605  *
606  * Revision 1.32  2005/01/05 14:24:52  beck
607  * renames all is_x*_type() functions to is_X*_type() to prevent name clash with EDG frontend
608  *
609  * Revision 1.31  2004/12/21 13:45:14  beck
610  * removed C99 constructs
611  *
612  * Revision 1.30  2004/12/02 16:16:11  beck
613  * fixed config.h include
614  * used xmalloc instead of malloc
615  *
616  * Revision 1.29  2004/11/11 13:28:08  goetz
617  * made pseudo irg aware
618  *
619  * Revision 1.28  2004/11/03 14:47:18  beck
620  * removed gloval intraprocedural_view variable and replaced by get_*() set_*() functions
621  *
622  * Revision 1.27  2004/10/21 07:23:34  goetz
623  * comments
624  *
625  * Revision 1.26  2004/10/20 14:59:27  liekweg
626  * Removed ecg
627  *
628  * Revision 1.25  2004/10/18 12:47:08  liekweg
629  * avoid warning
630  *
631  * Revision 1.24  2004/09/24 13:59:04  beck
632  * fixed doxygen comments, removed initialization for description entities
633  *
634  * Revision 1.23  2004/08/19 16:51:02  goetz
635  * fixed some errors, pushed closer to inteded firm semantics
636  *
637  * Revision 1.22  2004/08/13 08:57:15  beyhan
638  * normalized names of functions, enums ...
639  * added suffix as argument to dumpers, removed global variable
640  * removed support for tarval/Const
641  *
642  * Revision 1.21  2004/07/08 15:50:56  goetz
643  * firmstat added
644  *
645  * Revision 1.20  2004/07/08 11:17:40  goetz
646  * *** empty log message ***
647  *
648  * Revision 1.19  2004/07/06 12:30:37  beyhan
649  * new SymConst semantics
650  *
651  * Revision 1.18  2004/06/27 21:17:41  liekweg
652  * Added comment
653  *
654  * Revision 1.17  2004/06/25 13:45:13  liekweg
655  * observe stickyness; minor refactoring
656  *
657  * Revision 1.16  2004/06/24 06:42:14  goetz
658  * test of firm flags
659  *
660  * Revision 1.15  2004/06/18 15:47:19  liekweg
661  * minor bug fix (go forward, not backward) --flo
662  *
663  * Revision 1.14  2004/06/18 13:12:43  liekweg
664  * final bug fix (calls via consts)
665  *
666  * Revision 1.13  2004/06/17 16:34:33  liekweg
667  * removed DD*s
668  *
669  * Revision 1.12  2004/06/17 16:33:33  liekweg
670  * minor bug fix
671  *
672  * Revision 1.11  2004/06/17 14:21:13  liekweg
673  * major bugfix
674  *
675  * Revision 1.10  2004/06/17 10:31:41  goetz
676  * irscc: bugfix, can now deal with loops not reachable from start
677  * cgana: bugfix, skip_Tuple
678  * rta: improved
679  *
680  * Revision 1.9  2004/06/17 08:56:03  liekweg
681  * Fixed typos in comments
682  *
683  * Revision 1.8  2004/06/17 08:33:01  liekweg
684  * Added comments; added remove_irg
685  *
686  * Revision 1.6  2004/06/14 13:02:03  goetz
687  * bugfixesbug
688  *
689  * Revision 1.5  2004/06/13 15:03:45  liekweg
690  * RTA auf Iterative RTA aufgebohrt --flo
691  *
692  * Revision 1.4  2004/06/12 19:35:04  liekweg
693  * Kommentare eingef"ugt --flo
694  *
695  * Revision 1.3  2004/06/12 17:09:46  liekweg
696  * RTA works, outedges breaks.  "Yay." --flo
697  *
698  * Revision 1.2  2004/06/11 18:25:39  liekweg
699  * Added todo
700  *
701  * Revision 1.1  2004/06/11 18:24:18  liekweg
702  * Added RTA --flo
703  *
704  */