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