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