fix trailing whitespaces and tabulators in the middle of a line
[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                 if (!SYMCONST_HAS_ENT(get_SymConst_kind(node)))
50                         return;
51                 entity = get_SymConst_entity(node);
52         } else if (is_Sel(node)) {
53                 entity = get_Sel_entity(node);
54         } else {
55                 return;
56         }
57
58         visit_entity(entity);
59 }
60
61 static void start_visit_node(ir_node *node)
62 {
63         ir_graph *irg = get_irn_irg(node);
64
65         if (get_irg_visited(irg) < get_max_irg_visited()) {
66                 set_irg_visited(irg, get_max_irg_visited());
67         }
68         current_ir_graph = irg;
69         irg_walk_2(node, visit_node, NULL, NULL);
70 }
71
72 static void visit_initializer(ir_initializer_t *initializer)
73 {
74         switch (initializer->kind) {
75         case IR_INITIALIZER_CONST:
76                 start_visit_node(initializer->consti.value);
77                 return;
78         case IR_INITIALIZER_TARVAL:
79         case IR_INITIALIZER_NULL:
80                 return;
81
82         case IR_INITIALIZER_COMPOUND: {
83                 size_t i;
84                 for (i = 0; i < initializer->compound.n_initializers; ++i) {
85                         ir_initializer_t *subinitializer
86                                 = initializer->compound.initializers[i];
87                         visit_initializer(subinitializer);
88                 }
89                 return;
90         }
91         }
92         panic("invalid initializer found");
93 }
94
95 static void visit_entity(ir_entity *entity)
96 {
97         ir_graph *irg;
98
99         if (entity_visited(entity))
100                 return;
101         mark_entity_visited(entity);
102
103         if (entity->initializer != NULL) {
104                 visit_initializer(entity->initializer);
105         }  else if (entity_has_compound_ent_values(entity)) {
106                 int i;
107                 int n_members = get_compound_ent_n_values(entity);
108                 for (i = 0; i < n_members; ++i) {
109                         ir_node *node = get_compound_ent_value(entity, i);
110                         start_visit_node(node);
111                 }
112         }
113
114         irg = get_entity_irg(entity);
115         if (irg != NULL) {
116                 start_visit_node(get_irg_end(irg));
117         }
118 }
119
120 static void visit_segment(ir_type *segment)
121 {
122         int n_entities = get_compound_n_members(segment);
123         int i;
124
125         for (i = 0; i < n_entities; ++i) {
126                 ir_entity *entity = get_compound_member(segment, i);
127                 if (get_entity_visibility(entity) != ir_visibility_default
128                                 && !(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER))
129                         continue;
130
131                 visit_entity(entity);
132         }
133 }
134
135 static void garbage_collect_in_segment(ir_type *segment)
136 {
137         int i;
138
139         for (i = get_compound_n_members(segment)-1; i >= 0; --i) {
140                 ir_entity *entity = get_compound_member(segment, i);
141
142                 if (entity_visited(entity))
143                         continue;
144
145                 DB((dbg, LEVEL_1, "  removing entity %+F\n", entity));
146
147                 free_entity(entity);
148         }
149 }
150
151 void garbage_collect_entities(void)
152 {
153         int          i;
154         ir_segment_t s;
155
156         FIRM_DBG_REGISTER(dbg, "firm.opt.garbagecollect");
157
158         /* start a type walk for all externally visible entities */
159         irp_reserve_resources(irp, IR_RESOURCE_TYPE_VISITED);
160         inc_master_type_visited();
161         inc_max_irg_visited();
162
163         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
164                 ir_type *type = get_segment_type(s);
165                 mark_type_visited(type);
166
167                 visit_segment(type);
168         }
169
170         /* remove graphs of non-visited functions
171          * (we have to count backwards so we can safely call remove_irp_irg
172          *  while iterating) */
173         for (i = get_irp_n_irgs()-1; i >= 0; --i) {
174                 ir_graph  *irg    = get_irp_irg(i);
175                 ir_entity *entity = get_irg_entity(irg);
176
177                 if (entity_visited(entity))
178                         continue;
179
180                 DB((dbg, LEVEL_1, "  freeing method %+F\n", entity));
181                 remove_irp_irg(irg);
182         }
183
184         /* we can now remove all non-visited (global) entities */
185         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
186                 ir_type *type = get_segment_type(s);
187                 garbage_collect_in_segment(type);
188         }
189         irp_free_resources(irp, IR_RESOURCE_TYPE_VISITED);
190 }
191
192 ir_prog_pass_t *garbage_collect_entities_pass(const char *name)
193 {
194         return def_prog_pass(name ? name : "garbage_collect",
195                              garbage_collect_entities);
196 }