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