becopyilp: Inline struct size_red_t into struct ilp_env_t.
[libfirm] / ir / opt / garbage_collect.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief    Removal of unreachable methods.
9  * @author   Matthias Braun
10  */
11 #include "config.h"
12
13 #include "iroptimize.h"
14 #include "typerep.h"
15 #include "type_t.h"
16 #include "entity_t.h"
17 #include "irprog_t.h"
18 #include "irprintf.h"
19 #include "irpass.h"
20 #include "irgwalk.h"
21 #include "error.h"
22 #include "debug.h"
23
24 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
25
26 static void visit_entity(ir_entity *entity);
27
28 static void visit_node(ir_node *node, void *env)
29 {
30         ir_entity *entity;
31         (void) env;
32
33         if (is_SymConst(node)) {
34                 if (!SYMCONST_HAS_ENT(get_SymConst_kind(node)))
35                         return;
36                 entity = get_SymConst_entity(node);
37         } else if (is_Sel(node)) {
38                 entity = get_Sel_entity(node);
39         } else {
40                 return;
41         }
42
43         visit_entity(entity);
44 }
45
46 static void start_visit_node(ir_node *node)
47 {
48         ir_graph *irg = get_irn_irg(node);
49
50         if (get_irg_visited(irg) < get_max_irg_visited()) {
51                 set_irg_visited(irg, get_max_irg_visited());
52         }
53         irg_walk_2(node, visit_node, NULL, NULL);
54 }
55
56 static void visit_initializer(ir_initializer_t *initializer)
57 {
58         switch (initializer->kind) {
59         case IR_INITIALIZER_CONST:
60                 start_visit_node(initializer->consti.value);
61                 return;
62         case IR_INITIALIZER_TARVAL:
63         case IR_INITIALIZER_NULL:
64                 return;
65
66         case IR_INITIALIZER_COMPOUND: {
67                 size_t i;
68                 for (i = 0; i < initializer->compound.n_initializers; ++i) {
69                         ir_initializer_t *subinitializer
70                                 = initializer->compound.initializers[i];
71                         visit_initializer(subinitializer);
72                 }
73                 return;
74         }
75         }
76         panic("invalid initializer found");
77 }
78
79 static void visit_entity(ir_entity *entity)
80 {
81         ir_graph *irg;
82
83         if (entity_visited(entity))
84                 return;
85         mark_entity_visited(entity);
86
87         if (entity->initializer != NULL) {
88                 visit_initializer(entity->initializer);
89         }
90
91         irg = get_entity_irg(entity);
92         if (irg != NULL) {
93                 start_visit_node(get_irg_end(irg));
94         }
95 }
96
97 static void visit_segment(ir_type *segment)
98 {
99         int n_entities = get_compound_n_members(segment);
100         int i;
101
102         for (i = 0; i < n_entities; ++i) {
103                 ir_entity *entity = get_compound_member(segment, i);
104                 if (get_entity_visibility(entity) != ir_visibility_external
105                                 && !(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER)
106                                 && !(get_entity_linkage(entity) & IR_LINKAGE_NO_CODEGEN))
107                         continue;
108
109                 visit_entity(entity);
110         }
111 }
112
113 static void garbage_collect_in_segment(ir_type *segment)
114 {
115         int i;
116
117         for (i = get_compound_n_members(segment)-1; i >= 0; --i) {
118                 ir_entity *entity = get_compound_member(segment, i);
119
120                 if (entity_visited(entity))
121                         continue;
122
123                 DB((dbg, LEVEL_1, "  removing entity %+F\n", entity));
124
125                 free_entity(entity);
126         }
127 }
128
129 void garbage_collect_entities(void)
130 {
131         size_t       i;
132         ir_segment_t s;
133
134         FIRM_DBG_REGISTER(dbg, "firm.opt.garbagecollect");
135
136         /* start a type walk for all externally visible entities */
137         irp_reserve_resources(irp, IRP_RESOURCE_TYPE_VISITED);
138         inc_master_type_visited();
139         inc_max_irg_visited();
140
141         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
142                 ir_type *type = get_segment_type(s);
143                 mark_type_visited(type);
144
145                 visit_segment(type);
146         }
147
148         /* remove graphs of non-visited functions
149          * (we have to count backwards, because freeing the graph moves the last
150          *  graph in the list to the free position) */
151         for (i = get_irp_n_irgs(); i > 0;) {
152                 ir_graph  *irg    = get_irp_irg(--i);
153                 ir_entity *entity = get_irg_entity(irg);
154
155                 if (entity_visited(entity))
156                         continue;
157
158                 DB((dbg, LEVEL_1, "  freeing method %+F\n", entity));
159                 free_ir_graph(irg);
160         }
161
162         /* we can now remove all non-visited (global) entities */
163         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
164                 ir_type *type = get_segment_type(s);
165                 garbage_collect_in_segment(type);
166         }
167         irp_free_resources(irp, IRP_RESOURCE_TYPE_VISITED);
168 }
169
170 ir_prog_pass_t *garbage_collect_entities_pass(const char *name)
171 {
172         return def_prog_pass(name ? name : "garbage_collect",
173                              garbage_collect_entities);
174 }