simplify confusing entity/owner interfaces. There is no public way anymore to add...
[libfirm] / ir / opt / dead_code_elimination.c
1 /*
2  * Copyright (C) 1995-2008 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    Dead node elimination
23  * @author   Michael Beck, Goetz Lindenmaier
24  * @version  $Id: opt_inline.c 27265 2010-03-07 15:13:00Z matze $
25  *
26  * Strictly speaking dead node elimination is unnecessary in firm - everthying
27  * which is not used can't be found by any walker.
28  * The only drawback is that the nodes still take up memory. This phase fixes
29  * this by copying all (reachable) nodes to a new obstack and throwing away
30  * the old one.
31  */
32 #include "config.h"
33
34 #include "iroptimize.h"
35 #include "irnode_t.h"
36 #include "irgraph_t.h"
37 #include "irphase_t.h"
38 #include "iredges_t.h"
39 #include "irhooks.h"
40 #include "irtools.h"
41 #include "irgwalk.h"
42 #include "cgana.h"
43 #include "irouts.h"
44 #include "trouts.h"
45 #include "iropt_t.h"
46 #include "irpass.h"
47 #include "pmap.h"
48
49 /** a pointer to the new phases */
50 static ir_phase *new_phases[PHASE_LAST + 1];
51
52 /**
53  * Reroute the inputs of a node from nodes in the old graph to copied nodes in
54  * the new graph
55  */
56 static void rewire_inputs(ir_node *node, void *env)
57 {
58         (void) env;
59         irn_rewire_inputs(node);
60 }
61
62 static void copy_node_dce(ir_node *node, void *env)
63 {
64         int       i;
65         ir_node  *new_node = exact_copy(node);
66         ir_graph *irg      = get_irn_irg(new_node);
67         (void) env;
68
69         /* preserve the node numbers for easier debugging */
70         new_node->node_nr = node->node_nr;
71
72         /* copy phase information for this node */
73         for (i = 0; i <= PHASE_LAST; i++) {
74                 ir_phase *phase = irg_get_phase(irg, i);
75                 if (phase == NULL)
76                         continue;
77                 if (!phase_get_irn_data(phase, node))
78                         continue;
79                 phase_set_irn_data(new_phases[i], new_node,
80                                    phase_get_irn_data(phase, node));
81         }
82
83         set_irn_link(node, new_node);
84         hook_dead_node_elim_subst(irg, node, new_node);
85 }
86
87 /**
88  * Copies the graph reachable from current_ir_graph->end to the obstack
89  * in current_ir_graph and fixes the environment.
90  * Then fixes the fields in current_ir_graph containing nodes of the
91  * graph.
92  *
93  * @param copy_node_nr  If non-zero, the node number will be copied
94  */
95 static void copy_graph_env(ir_graph *irg)
96 {
97         ir_node *new_anchor;
98         int i;
99
100         /* init the new_phases array */
101         /* TODO: this is wrong, it should only allocate a new data_ptr inside
102          * the phase! */
103         for (i = 0; i <= PHASE_LAST; i++) {
104                 ir_phase *old_ph = irg_get_phase(irg, i);
105                 if (old_ph == NULL) {
106                         new_phases[i] = NULL;
107                 } else {
108                         new_phases[i] = new_phase(irg, old_ph->data_init);
109                         new_phases[i]->priv = old_ph->priv;
110                 }
111         }
112
113         /* copy nodes */
114         irg_walk_anchors(irg, copy_node_dce, rewire_inputs, NULL);
115
116         /* fix the anchor */
117         new_anchor = get_irn_link(irg->anchor);
118         assert(new_anchor != NULL);
119         irg->anchor = new_anchor;
120
121         /* copy the new phases into the irg */
122         for (i = 0; i <= PHASE_LAST; i++) {
123                 ir_phase *old_ph = irg_get_phase(irg, i);
124                 if (old_ph == NULL)
125                         continue;
126
127                 /* Matze: commented out for now: This is a memory leak, but for a real
128                  * fix we must not create new phases here, but reuse the old phases
129                  * and just create a new data array */
130                 /* phase_free(old_ph); */
131                 irg->phases[i] = new_phases[i];
132         }
133 }
134
135 /**
136  * Copies all reachable nodes to a new obstack.  Removes bad inputs
137  * from block nodes and the corresponding inputs from Phi nodes.
138  * Merges single exit blocks with single entry blocks and removes
139  * 1-input Phis.
140  * Adds all new nodes to a new hash table for CSE.  Does not
141  * perform CSE, so the hash table might contain common subexpressions.
142  */
143 void dead_node_elimination(ir_graph *irg)
144 {
145         ir_graph *rem;
146 #ifdef INTERPROCEDURAL_VIEW
147         int rem_ipview = get_interprocedural_view();
148 #endif
149         struct obstack *graveyard_obst = NULL;
150         struct obstack *rebirth_obst   = NULL;
151
152         edges_deactivate(irg);
153
154         /* inform statistics that we started a dead-node elimination run */
155         hook_dead_node_elim(irg, 1);
156
157         /* Remember external state of current_ir_graph. */
158         rem = current_ir_graph;
159         current_ir_graph = irg;
160 #ifdef INTERPROCEDURAL_VIEW
161         set_interprocedural_view(0);
162 #endif
163
164         assert(get_irg_phase_state(irg) != phase_building);
165
166         /* Handle graph state */
167         free_callee_info(irg);
168         free_irg_outs(irg);
169         free_trouts();
170         free_loop_information(irg);
171         set_irg_doms_inconsistent(irg);
172
173         /* A quiet place, where the old obstack can rest in peace,
174            until it will be cremated. */
175         graveyard_obst = irg->obst;
176
177         /* A new obstack, where the reachable nodes will be copied to. */
178         rebirth_obst = XMALLOC(struct obstack);
179         irg->obst = rebirth_obst;
180         obstack_init(irg->obst);
181         irg->last_node_idx = 0;
182
183         /* We also need a new value table for CSE */
184         del_identities(irg->value_table);
185         irg->value_table = new_identities();
186
187         /* Copy the graph from the old to the new obstack */
188         copy_graph_env(irg);
189
190         /* Free memory from old unoptimized obstack */
191         obstack_free(graveyard_obst, 0);  /* First empty the obstack ... */
192         xfree(graveyard_obst);            /* ... then free it.           */
193
194         /* inform statistics that the run is over */
195         hook_dead_node_elim(irg, 0);
196
197         current_ir_graph = rem;
198 #ifdef INTERPROCEDURAL_VIEW
199         set_interprocedural_view(rem_ipview);
200 #endif
201 }
202
203 ir_graph_pass_t *dead_node_elimination_pass(const char *name)
204 {
205         return def_graph_pass(name ? name : "dce", dead_node_elimination);
206 }
207
208
209 /*
210    __                      _  __ __
211   (_     __    o     _    | \/  |_
212   __)|_| | \_/ | \_/(/_   |_/\__|__
213
214   The following stuff implements a facility that automatically patches
215   registered ir_node pointers to the new node when a dead node elimination occurs.
216
217
218   Warning: This is considered a hack - try hard to avoid this!
219 */
220
221 struct _survive_dce_t {
222         struct obstack obst;
223         pmap *places;
224         pmap *new_places;
225         hook_entry_t dead_node_elim;
226         hook_entry_t dead_node_elim_subst;
227 };
228
229 typedef struct _survive_dce_list_t {
230         struct _survive_dce_list_t *next;
231         ir_node **place;
232 } survive_dce_list_t;
233
234 static void dead_node_hook(void *context, ir_graph *irg, int start)
235 {
236         survive_dce_t *sd = context;
237         (void) irg;
238
239         /* Create a new map before the dead node elimination is performed. */
240         if (start) {
241                 sd->new_places = pmap_create_ex(pmap_count(sd->places));
242         } else {
243                 /* Patch back all nodes if dead node elimination is over and something is to be done. */
244                 pmap_destroy(sd->places);
245                 sd->places     = sd->new_places;
246                 sd->new_places = NULL;
247         }
248 }
249
250 /**
251  * Hook called when dead node elimination replaces old by nw.
252  */
253 static void dead_node_subst_hook(void *context, ir_graph *irg, ir_node *old, ir_node *nw)
254 {
255         survive_dce_t *sd = context;
256         survive_dce_list_t *list = pmap_get(sd->places, old);
257         (void) irg;
258
259         /* If the node is to be patched back, write the new address to all registered locations. */
260         if (list) {
261                 survive_dce_list_t *p;
262
263                 for (p = list; p; p = p->next)
264                         *(p->place) = nw;
265
266                 pmap_insert(sd->new_places, nw, list);
267         }
268 }
269
270 /**
271  * Make a new Survive DCE environment.
272  */
273 survive_dce_t *new_survive_dce(void)
274 {
275         survive_dce_t *res = XMALLOC(survive_dce_t);
276         obstack_init(&res->obst);
277         res->places     = pmap_create();
278         res->new_places = NULL;
279
280         res->dead_node_elim.hook._hook_dead_node_elim = dead_node_hook;
281         res->dead_node_elim.context                   = res;
282         res->dead_node_elim.next                      = NULL;
283
284         res->dead_node_elim_subst.hook._hook_dead_node_elim_subst = dead_node_subst_hook;
285         res->dead_node_elim_subst.context = res;
286         res->dead_node_elim_subst.next    = NULL;
287
288         register_hook(hook_dead_node_elim, &res->dead_node_elim);
289         register_hook(hook_dead_node_elim_subst, &res->dead_node_elim_subst);
290         return res;
291 }
292
293 /**
294  * Free a Survive DCE environment.
295  */
296 void free_survive_dce(survive_dce_t *sd)
297 {
298         obstack_free(&sd->obst, NULL);
299         pmap_destroy(sd->places);
300         unregister_hook(hook_dead_node_elim, &sd->dead_node_elim);
301         unregister_hook(hook_dead_node_elim_subst, &sd->dead_node_elim_subst);
302         xfree(sd);
303 }
304
305 /**
306  * Register a node pointer to be patched upon DCE.
307  * When DCE occurs, the node pointer specified by @p place will be
308  * patched to the new address of the node it is pointing to.
309  *
310  * @param sd    The Survive DCE environment.
311  * @param place The address of the node pointer.
312  */
313 void survive_dce_register_irn(survive_dce_t *sd, ir_node **place)
314 {
315         if (*place != NULL) {
316                 ir_node *irn      = *place;
317                 survive_dce_list_t *curr = pmap_get(sd->places, irn);
318                 survive_dce_list_t *nw   = OALLOC(&sd->obst, survive_dce_list_t);
319
320                 nw->next  = curr;
321                 nw->place = place;
322
323                 pmap_insert(sd->places, irn, nw);
324         }
325 }