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