BugFix: fixed list_for_each_safe() instance.
[libfirm] / ir / opt / garbage_collect.c
1 /*
2  * Copyright (C) 2010 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    Removal of unreachable methods.
23  * @author   Matthias Braun
24  * @version  $Id$
25  */
26 #include "config.h"
27
28 #include "iroptimize.h"
29 #include "typerep.h"
30 #include "type_t.h"
31 #include "entity_t.h"
32 #include "irprog_t.h"
33 #include "irprintf.h"
34 #include "irpass.h"
35 #include "irgwalk.h"
36 #include "error.h"
37 #include "debug.h"
38
39 DEBUG_ONLY(static firm_dbg_module_t *dbg);
40
41 static void visit_entity(ir_entity *entity);
42
43 static void visit_node(ir_node *node, void *env)
44 {
45         ir_entity *entity;
46         (void) env;
47
48         if (!is_SymConst(node))
49                 return;
50         if (!SYMCONST_HAS_ENT(get_SymConst_kind(node)))
51                 return;
52
53         entity = get_SymConst_entity(node);
54         visit_entity(entity);
55 }
56
57 static void start_visit_node(ir_node *node)
58 {
59         ir_graph *irg = get_irn_irg(node);
60
61         if (get_irg_visited(irg) < get_max_irg_visited()) {
62                 set_irg_visited(irg, get_max_irg_visited());
63         }
64         current_ir_graph = irg;
65         irg_walk_2(node, visit_node, NULL, NULL);
66 }
67
68 static void visit_initializer(ir_initializer_t *initializer)
69 {
70         switch (initializer->kind) {
71         case IR_INITIALIZER_CONST:
72                 start_visit_node(initializer->consti.value);
73                 return;
74         case IR_INITIALIZER_TARVAL:
75         case IR_INITIALIZER_NULL:
76                 return;
77
78         case IR_INITIALIZER_COMPOUND: {
79                 size_t i;
80                 for(i = 0; i < initializer->compound.n_initializers; ++i) {
81                         ir_initializer_t *subinitializer
82                                 = initializer->compound.initializers[i];
83                         visit_initializer(subinitializer);
84                 }
85                 return;
86         }
87         }
88         panic("invalid initializer found");
89 }
90
91 static void visit_entity(ir_entity *entity)
92 {
93         ir_graph *irg;
94
95         if (entity_visited(entity))
96                 return;
97         mark_entity_visited(entity);
98
99         if (entity->initializer != NULL) {
100                 visit_initializer(entity->initializer);
101         }  else if (entity_has_compound_ent_values(entity)) {
102                 int i;
103                 int n_members = get_compound_ent_n_values(entity);
104                 for (i = 0; i < n_members; ++i) {
105                         ir_node *node = get_compound_ent_value(entity, i);
106                         start_visit_node(node);
107                 }
108         }
109
110         irg = get_entity_irg(entity);
111         if (irg != NULL) {
112                 start_visit_node(get_irg_end(irg));
113         }
114 }
115
116 static void visit_segment(ir_type *segment)
117 {
118         int n_entities = get_compound_n_members(segment);
119         int i;
120
121         for (i = 0; i < n_entities; ++i) {
122                 ir_entity *entity = get_compound_member(segment, i);
123                 if (get_entity_visibility(entity) != ir_visibility_default
124                                 && !(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER))
125                         continue;
126
127                 visit_entity(entity);
128         }
129 }
130
131 static void garbage_collect_in_segment(ir_type *segment)
132 {
133         int i;
134
135         for (i = get_compound_n_members(segment)-1; i >= 0; --i) {
136                 ir_entity *entity = get_compound_member(segment, i);
137
138                 if (entity_visited(entity))
139                         continue;
140
141                 DB((dbg, LEVEL_1, "  removing entity %+F\n", entity));
142
143                 /* TODO: this is O(n^2) improve our interfaces! */
144                 remove_class_member(get_entity_owner(entity), entity);
145         }
146 }
147
148 void garbage_collect_entities(void)
149 {
150         int          i;
151         ir_segment_t s;
152
153         FIRM_DBG_REGISTER(dbg, "firm.opt.garbagecollect");
154
155         /* start a type walk for all externally visible entities */
156         irp_reserve_resources(irp, IR_RESOURCE_TYPE_VISITED);
157         inc_master_type_visited();
158         inc_max_irg_visited();
159
160         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
161                 ir_type *type = get_segment_type(s);
162                 mark_type_visited(type);
163
164                 visit_segment(type);
165         }
166
167         /* remove graphs of non-visited functions
168          * (we have to count backwards so we can safely call remove_irp_irg
169          *  while iterating) */
170         for (i = get_irp_n_irgs()-1; i >= 0; --i) {
171                 ir_graph  *irg    = get_irp_irg(i);
172                 ir_entity *entity = get_irg_entity(irg);
173
174                 if (entity_visited(entity))
175                         continue;
176
177                 DB((dbg, LEVEL_1, "  freeing method %+F\n",     entity));
178                 remove_irp_irg(irg);
179         }
180
181         /* we can now remove all non-visited (global) entities */
182         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
183                 ir_type *type = get_segment_type(s);
184                 garbage_collect_in_segment(type);
185         }
186         irp_free_resources(irp, IR_RESOURCE_TYPE_VISITED);
187 }
188
189 ir_prog_pass_t *garbage_collect_entities_pass(const char *name)
190 {
191         return def_prog_pass(name ? name : "garbage_collect",
192                              garbage_collect_entities);
193 }