doxygen docu fixed
[libfirm] / ir / ana / irconsconfirm.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ana/irconsconfirm.c
4  * Purpose:     Construction of Confirm nodes
5  * Author:      Michael Beck
6  * Modified by:
7  * Created:     6.2005
8  * CVS-ID:      $Id$
9  * Copyright:   (C) 2002-2005 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 /**
14  * @file irconsconfirm.c
15  *
16  * Construction of Confirm nodes
17  *
18  * @author Michael Beck
19  */
20 #include "irgraph_t.h"
21 #include "irnode_t.h"
22 #include "ircons_t.h"
23 #include "irgmod.h"
24 #include "iropt_dbg.h"
25 #include "iredges_t.h"
26 #include "irprintf.h"
27
28 /**
29  * Walker environment.
30  */
31 typedef struct _env_t {
32   unsigned num_confirms;  /**< number of inserted Confirm nodes */
33   unsigned num_consts;    /**< number of constants placed */
34   unsigned num_eq;        /**< number of equalities placed */
35 } env_t;
36
37 /**
38  * Handle a CASE-branch.
39  *
40  * @param block   the block which is entered by the branch
41  * @param irn     the node expressing the switch value
42  * @param nr      the branch label
43  * @param env     statistical environment
44  *
45  * Branch labels are a simple case. We can replace the value
46  * by a Const with the branch label.
47  */
48 static void handle_case(ir_node *block, ir_node *irn, long nr, env_t *env)
49 {
50   int pos;
51   const ir_edge_t *edge, *next;
52   ir_node *c = NULL;
53
54   if (is_Bad(irn))
55     return;
56
57   for (edge = get_irn_out_edge_first(irn); edge; edge = next) {
58     ir_node *succ = get_edge_src_irn(edge);
59     ir_node *blk = get_nodes_block(succ);
60
61     next = get_irn_out_edge_next(irn, edge);
62
63     if (block_dominates(block, blk)) {
64       /*
65        * Ok, we found a user of irn that is placed
66        * in a block dominated by the branch block.
67        * We can replace the input with the Constant
68        * branch label.
69        */
70
71       if (! c) {
72         ir_mode *mode = get_irn_mode(irn);
73         type *tp      = get_irn_type(irn);
74         tarval *tv    = new_tarval_from_long(nr, mode);
75         c = new_r_Const_type(current_ir_graph, block, mode, tv, tp);
76       }
77
78       pos = get_edge_src_pos(edge);
79       set_irn_n(succ, pos, c);
80       DBG_OPT_CONFIRM_C(irn, c);
81 //      ir_printf("1 Replacing input %d of node %n with %n\n", pos, succ, c);
82
83       env->num_consts += 1;
84     }
85   }
86 }
87
88 /**
89  * Handle an IF-branch.
90  *
91  * @param block   the block which is entered by the branch
92  * @param cmp     the Cmp node expressing the branch condition
93  * @param pnc     the Compare relation for taking this branch
94  * @param env     statistical environment
95  */
96 static void handle_if(ir_node *block, ir_node *cmp, pn_Cmp pnc, env_t *env)
97 {
98   ir_node *left  = get_Cmp_left(cmp);
99   ir_node *right = get_Cmp_right(cmp);
100         ir_op *op;
101   const ir_edge_t *edge, *next;
102
103   /* Beware of Bads */
104   if (is_Bad(left) ||is_Bad(right))
105     return;
106
107   op = get_irn_op(left);
108
109   /* try to place the constant on the right side for a Confirm */
110   if (op == op_Const || op == op_SymConst) {
111     ir_node *t = left;
112
113     left  = right;
114     right = t;
115
116     pnc = get_inversed_pnc(pnc);
117   }
118
119   /*
120    * First case: both values are identical.
121    * replace the right one by the left one.
122    */
123   if (pnc == pn_Cmp_Eq) {
124     int pos;
125
126     for (edge = get_irn_out_edge_first(left); edge; edge = next) {
127       ir_node *succ = get_edge_src_irn(edge);
128       ir_node *blk = get_nodes_block(succ);
129
130       next = get_irn_out_edge_next(left, edge);
131       if (block_dominates(block, blk)) {
132         /*
133          * Ok, we found a user of right that is placed
134          * in a block dominated by the branch block.
135          * We can replace the input with right.
136          */
137         pos = get_edge_src_pos(edge);
138         set_irn_n(succ, pos, right);
139         DBG_OPT_CONFIRM(left, right);
140
141 //        ir_printf("2 Replacing input %d of node %n with %n\n", pos, succ, right);
142
143         env->num_eq += 1;
144       }
145     }
146   }
147   else { /* not == cases */
148     int pos;
149     ir_node *c = NULL;
150
151     for (edge = get_irn_out_edge_first(left); edge; edge = next) {
152       ir_node *succ = get_edge_src_irn(edge);
153       ir_node *blk = get_nodes_block(succ);
154
155       next = get_irn_out_edge_next(left, edge);
156       if (block_dominates(block, blk)) {
157         /*
158          * Ok, we found a user of right that is placed
159          * in a block dominated by the branch block.
160          * We can replace the input with a Confirm(left, pnc, right).
161          */
162         if (! c)
163           c = new_r_Confirm(current_ir_graph, block, left, right, pnc);
164
165         pos = get_edge_src_pos(edge);
166         set_irn_n(succ, pos, c);
167 //        ir_printf("3 Replacing input %d of node %n with %n\n", pos, succ, c);
168
169         env->num_confirms += 1;
170       }
171     }
172   }
173 }
174
175 /**
176  * Pre-walker: Called for every block to insert Confirm nodes
177  */
178 static void insert_Confirm(ir_node *block, void *env)
179 {
180   ir_node *cond, *proj, *selector;
181   ir_mode *mode;
182
183   /*
184    * we can only handle blocks with only ONE control flow
185    * predecessor
186    */
187   if (get_Block_n_cfgpreds(block) != 1)
188     return;
189
190   proj = get_Block_cfgpred(block, 0);
191   if (get_irn_op(proj) != op_Proj)
192     return;
193
194   cond = get_Proj_pred(proj);
195   if (get_irn_op(cond) != op_Cond)
196     return;
197
198   selector = get_Cond_selector(cond);
199   mode = get_irn_mode(selector);
200
201   if (mode == mode_b) {
202     ir_node *cmp;
203     pn_Cmp pnc;
204
205     /* this should be an IF, check this */
206     if (get_irn_op(selector) != op_Proj)
207       return;
208
209     cmp = get_Proj_pred(selector);
210     if (get_irn_op(cmp) != op_Cmp)
211       return;
212
213     pnc = get_Proj_proj(selector);
214
215     if (get_Proj_proj(proj) != pn_Cond_true) {
216       /* it's the false branch */
217       pnc = get_negated_pnc(pnc, mode);
218     }
219 //    ir_printf("At %n using %n Confirm %=\n", block, cmp, pnc);
220
221     handle_if(block, cmp, pnc, env);
222   }
223   else if (mode_is_int(mode)) {
224     long proj_nr = get_Proj_proj(proj);
225
226     /* this is a CASE, but we cannot handle the default case */
227     if (proj_nr == get_Cond_defaultProj(cond))
228       return;
229
230     handle_case(block, get_Cond_selector(cond), proj_nr, env);
231   }
232 }
233
234 /*
235  * Construct Confirm nodes
236  */
237 void construct_confirms(ir_graph *irg)
238 {
239   env_t env;
240   int edges_active = edges_activated(irg);
241
242   if (get_irg_dom_state(irg) != dom_consistent) {
243     /* we need dominance info */
244     compute_doms(irg);
245   }
246
247   assert(get_irg_pinned(irg) == op_pin_state_pinned &&
248     "Nodes must be placed to insert Confirms");
249
250   if (! edges_active) {
251     /* We need edges */
252     edges_activate(irg);
253   }
254
255   env.num_confirms = 0;
256   env.num_consts   = 0;
257   env.num_eq       = 0;
258
259   /* now, visit all blocks and add Confirms where possible */
260   irg_block_walk_graph(irg, insert_Confirm, NULL, &env);
261
262   if (env.num_confirms | env.num_consts | env.num_eq) {
263     /* we have add nodes or changed DF edges */
264     set_irg_outs_inconsistent(irg);
265
266     /* the new nodes are not in the loop info */
267     set_irg_loopinfo_inconsistent(irg);
268   }
269
270 #if 0
271   printf("# Confirms inserted : %u\n", env.num_confirms);
272   printf("# Const replacements: %u\n", env.num_consts);
273   printf("# node equalities   : %u\n", env.num_eq);
274 #endif
275
276   /* deactivate edges if they where off */
277   if (! edges_active)
278     edges_deactivate(irg);
279 }
280
281 /**
282  * Post-walker: Remove Confirm nodes
283  */
284 static void rem_Confirm(ir_node *n, void *env) {
285   if (get_irn_op(n) == op_Confirm) {
286     ir_node *value = get_Confirm_value(n);
287     if (value != n)
288       exchange(n, value);
289     else {
290       /*
291        * Strange: a Confirm is it's own bound. This can happen
292        * in dead blocks when Phi nodes are already removed.
293        */
294       exchange(n, new_Bad());
295     }
296   }
297 }
298
299 /*
300  * Remove all Confirm nodes from a graph.
301  */
302 void remove_confirms(ir_graph *irg) {
303   irg_walk_graph(irg, NULL, rem_Confirm, NULL);
304 }