92aff145d3377897f1e9c3ada71afdcac6d747e4
[libfirm] / ir / ir / irgopt.c
1 /* Copyright (C) 1998 - 2000 by Universitaet Karlsruhe
2 ** All rights reserved.
3 **
4 ** Author: Christian Schaefer
5 **
6 ** Optimizations for a whole ir graph, i.e., a procedure.
7 */
8
9 # include <assert.h>
10
11 # include "irgopt.h"
12 # include "irnode_t.h"
13 # include "irgraph_t.h"
14 # include "iropt.h"
15 # include "irgwalk.h"
16 # include "ircons.h"
17 # include "misc.h"
18 # include "irgmod.h"
19
20 # include "pset.h"
21 pset *new_identities (void);
22 void  del_identities (pset *value_table);
23
24 /********************************************************************/
25 /* apply optimizations of iropt to all nodes.                       */
26 /********************************************************************/
27
28 void
29 optimize_in_place_wrapper (ir_node *n, void *env) {
30   int i;
31   ir_node *optimized;
32
33   /* optimize all sons after recursion, i.e., the sons' sons are
34      optimized already. */
35   for (i = -1; i < get_irn_arity(n); i++) {
36     optimized = optimize_in_place(get_irn_n(n, i));
37     set_irn_n(n, i, optimized);
38   }
39 }
40
41 void
42 local_optimize_graph (ir_graph *irg) {
43   ir_graph *rem = current_ir_graph;
44   current_ir_graph = irg;
45
46   /* Should we clean the value_table in irg for the cse? Better do so... */
47   del_identities(irg->value_table);
48   irg->value_table = new_identities();
49
50   /* walk over the graph */
51   irg_walk(irg->end, NULL, optimize_in_place_wrapper, NULL);
52
53   current_ir_graph = rem;
54 }
55
56 /********************************************************************/
57 /* Routines for dead node elimination / copying garbage collection  */
58 /* of the obstack.                                                  */
59 /********************************************************************/
60
61 /* Remeber the new node in the old node by using a field all nodes have. */
62 inline void
63 set_new_node (ir_node *old, ir_node *new)
64 {
65   old->link = new;
66 }
67
68 /* Get this new node, before the old node is forgotton.*/
69 inline ir_node *
70 get_new_node (ir_node * n)
71 {
72   return n->link;
73 }
74
75
76 /* We use the block_visited flag to mark that we have computed the
77    number of useful predecessors for this block.
78    Further we encode the new arity in this flag.  Remembering the arity is
79    useful, as it saves a lot of pointer accesses.  This function is called
80    for all Phi and Block nodes in a Block. */
81 inline int
82 compute_new_arity(ir_node *b) {
83   int i, res;
84   int irg_v, block_v;
85
86   irg_v = get_irg_block_visited(current_ir_graph);
87   block_v = get_Block_block_visited(b);
88   if (block_v >= irg_v) {
89     /* we computed the number of preds for this block and saved it in the
90        block_v flag */
91     return block_v - irg_v;
92   } else {
93     /* compute the number of good predecessors */
94     res = get_irn_arity(b);
95     for (i = 0; i < get_irn_arity(b); i++)
96       if (get_irn_opcode(get_irn_n(b, i)) == iro_Bad) res--;
97     /* save it in the flag. */
98     set_Block_block_visited(b, irg_v + res);
99     return res;
100   }
101 }
102
103 /* Copies the node to the new obstack. The Ins of the new node point to
104    the predecessors on the old obstack.  n->link points to the new node.
105    For Phi and Block nodes the function allocates in-arrays with an arity
106    only for useful predecessors.  The arity is determined by counting
107    the non-bad predecessors of the block. */
108 inline void
109 copy_node (ir_node *n, void *env) {
110   ir_node *nn, *block;
111   int new_arity;
112
113   if (get_irn_opcode(n) == iro_Block) {
114     block = NULL;
115     new_arity = compute_new_arity(n);
116   } else {
117     block = get_nodes_Block(n);
118     if (get_irn_opcode(n) == iro_Phi) {
119       new_arity = compute_new_arity(block);
120     } else {
121       new_arity = get_irn_arity(n);
122     }
123   }
124   nn = new_ir_node(current_ir_graph,
125                    block,
126                    get_irn_op(n),
127                    get_irn_mode(n),
128                    new_arity,
129                    get_irn_in(n));
130   /* Copy the attributes.  These might point to additional data.  If this
131      was allocated on the old obstack the pointers now are dangling.  This
132      frees e.g. the memory of the graph_arr allocated in new_immBlock. */
133   copy_attrs(n, nn);
134   set_new_node(n, nn);
135 }
136
137 /* Copies new predecessors of old node to new node remembered in link.
138    Spare the Bad predecessors of Phi and Block nodes. */
139 inline void
140 copy_preds (ir_node *n, void *env) {
141   ir_node *nn, *block, *on;
142   int i, j;
143
144   nn = get_new_node(n);
145
146   if (get_irn_opcode(n) == iro_Block) {
147     /* Don't copy Bad nodes. */
148     j = 0;
149     for (i = 0; i < get_irn_arity(n); i++)
150       if (get_irn_opcode(get_irn_n(n, i)) != iro_Bad) {
151         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
152         j++;
153       }
154     /* repair the block visited flag from above misuse */
155     set_Block_block_visited(nn, 0);
156     /* Local optimization could not merge two subsequent blocks if
157        in array contained Bads.  Now it's possible.  */
158     on = optimize_in_place(nn);
159     if (nn != on) exchange(nn, on);
160   } else if (get_irn_opcode(n) == iro_Phi) {
161     /* Don't copy node if corresponding predecessor in block is Bad.
162        The Block itself should not be Bad. */
163     block = get_nodes_Block(n);
164     set_irn_n (nn, -1, get_new_node(block));
165     j = 0;
166     for (i = 0; i < get_irn_arity(n); i++)
167       if (get_irn_opcode(get_irn_n(block, i)) != iro_Bad) {
168         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
169         j++;
170       }
171     /* Compacting the Phi's ins might generate Phis with only one
172        predecessor. */
173     if (get_irn_arity(n) == 1)
174     exchange(n, get_irn_n(n, 0));
175   } else {
176     for (i = -1; i < get_irn_arity(n); i++)
177       set_irn_n (nn, i, get_new_node(get_irn_n(n, i)));
178   }
179 }
180
181 /* Copies the graph reachable from current_ir_graph->end to the obstack
182    in current_ir_graph.
183    Then fixes the fields in current_ir_graph containing nodes of the
184    graph.  */
185 void
186 copy_graph () {
187   /* Not all nodes remembered in current_ir_graph might be reachable
188      from the end node.  Assure their link is set to NULL so that
189      we can test whether new nodes have been computed. */
190   set_irn_link(get_irg_frame  (current_ir_graph), NULL);
191   set_irn_link(get_irg_globals(current_ir_graph), NULL);
192   set_irn_link(get_irg_args   (current_ir_graph), NULL);
193
194   /* we use the block walk flag for removing Bads from Blocks ins. */
195   inc_irg_block_visited(current_ir_graph);
196
197   /* copy the graph */
198   irg_walk(get_irg_end(current_ir_graph), copy_node, copy_preds, NULL);
199
200   /* fix the fields in current_ir_graph */
201   set_irg_end        (current_ir_graph, get_new_node(get_irg_end(current_ir_graph)));
202   set_irg_end_block  (current_ir_graph, get_new_node(get_irg_end_block(current_ir_graph)));
203   if (get_irn_link(get_irg_frame(current_ir_graph)) == NULL)
204     irg_walk(get_irg_frame(current_ir_graph), copy_node, copy_preds, NULL);
205   if (get_irn_link(get_irg_globals(current_ir_graph)) == NULL)
206     irg_walk(get_irg_globals(current_ir_graph), copy_node, copy_preds, NULL);
207   if (get_irn_link(get_irg_args(current_ir_graph)) == NULL)
208     irg_walk(get_irg_args(current_ir_graph), copy_node, copy_preds, NULL);
209   set_irg_start  (current_ir_graph, get_new_node(get_irg_start(current_ir_graph)));
210   set_irg_start_block(current_ir_graph,
211                       get_new_node(get_irg_start_block(current_ir_graph)));
212   set_irg_frame  (current_ir_graph, get_new_node(get_irg_frame(current_ir_graph)));
213   set_irg_globals(current_ir_graph, get_new_node(get_irg_globals(current_ir_graph)));
214   set_irg_args   (current_ir_graph, get_new_node(get_irg_args(current_ir_graph)));
215   if (get_irn_link(get_irg_bad(current_ir_graph)) == NULL) {
216     copy_node(get_irg_bad(current_ir_graph), NULL);
217     copy_preds(get_irg_bad(current_ir_graph), NULL);
218   }
219   set_irg_bad(current_ir_graph, get_new_node(get_irg_bad(current_ir_graph)));
220 }
221
222
223 /* Amroq call this emigrate() */
224 void
225 dead_node_elimination(ir_graph *irg) {
226   ir_graph *rem;
227   struct obstack *graveyard_obst = NULL;
228   struct obstack *rebirth_obst   = NULL;
229
230   /* Remember external state of current_ir_graph. */
231   rem = current_ir_graph;
232   current_ir_graph = irg;
233
234   if (get_optimize() && get_opt_dead_node_elimination()) {
235
236     /* A quiet place, where the old obstack can rest in peace,
237        until it will be cremated. */
238     graveyard_obst = irg->obst;
239
240     /* A new obstack, where the reachable nodes will be copied to. */
241     rebirth_obst = (struct obstack *) xmalloc (sizeof (struct obstack));
242     current_ir_graph->obst = rebirth_obst;
243     obstack_init (current_ir_graph->obst);
244
245     /* Copy the graph from the old to the new obstack */
246     copy_graph();
247
248     /* Free memory from old unoptimized obstack */
249     obstack_free(graveyard_obst, 0);  /* First empty the obstack ... */
250     xfree (graveyard_obst);           /* ... then free it.           */
251   }
252
253   current_ir_graph = rem;
254 }