group High-Level exception support ops together
[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   /* try to place the constant on the right side for a Confirm */
111   if (op == op_Const || op == op_SymConst) {
112     ir_node *t = left;
113
114     left  = right;
115     right = t;
116
117     pnc = get_inversed_pnc(pnc);
118   }
119
120   /*
121    * First case: both values are identical.
122    * replace the right one by the left one.
123    */
124   if (pnc == pn_Cmp_Eq) {
125     int pos;
126
127     for (edge = get_irn_out_edge_first(left); edge; edge = next) {
128       ir_node *succ = get_edge_src_irn(edge);
129       ir_node *blk = get_nodes_block(succ);
130
131       next = get_irn_out_edge_next(left, edge);
132       if (block_dominates(block, blk)) {
133         /*
134          * Ok, we found a user of right that is placed
135          * in a block dominated by the branch block.
136          * We can replace the input with right.
137          */
138         pos = get_edge_src_pos(edge);
139         set_irn_n(succ, pos, right);
140         DBG_OPT_CONFIRM(left, right);
141
142 //        ir_printf("2 Replacing input %d of node %n with %n\n", pos, succ, right);
143
144         env->num_eq += 1;
145       }
146     }
147   }
148   else { /* not == cases */
149     int pos;
150     ir_node *c = NULL;
151
152     for (edge = get_irn_out_edge_first(left); edge; edge = next) {
153       ir_node *succ = get_edge_src_irn(edge);
154       ir_node *blk = get_nodes_block(succ);
155
156       next = get_irn_out_edge_next(left, edge);
157       if (block_dominates(block, blk)) {
158         /*
159          * Ok, we found a user of right that is placed
160          * in a block dominated by the branch block.
161          * We can replace the input with a Confirm(left, pnc, right).
162          */
163         if (! c)
164           c = new_r_Confirm(current_ir_graph, block, left, right, pnc);
165
166         pos = get_edge_src_pos(edge);
167         set_irn_n(succ, pos, c);
168 //        ir_printf("3 Replacing input %d of node %n with %n\n", pos, succ, c);
169
170         env->num_confirms += 1;
171       }
172     }
173   }
174 }
175
176 /**
177  * Pre-walker: Called for every block to insert Confirm nodes
178  */
179 static void insert_Confirm(ir_node *block, void *env)
180 {
181   ir_node *cond, *proj, *selector;
182   ir_mode *mode;
183
184   /*
185    * we can only handle blocks with only ONE control flow
186    * predecessor
187    */
188   if (get_Block_n_cfgpreds(block) != 1)
189     return;
190
191   proj = get_Block_cfgpred(block, 0);
192   if (get_irn_op(proj) != op_Proj)
193     return;
194
195   cond = get_Proj_pred(proj);
196   if (get_irn_op(cond) != op_Cond)
197     return;
198
199   selector = get_Cond_selector(cond);
200   mode = get_irn_mode(selector);
201
202   if (mode == mode_b) {
203     ir_node *cmp;
204     pn_Cmp pnc;
205
206     /* this should be an IF, check this */
207     if (get_irn_op(selector) != op_Proj)
208       return;
209
210     cmp = get_Proj_pred(selector);
211     if (get_irn_op(cmp) != op_Cmp)
212       return;
213
214     pnc = get_Proj_proj(selector);
215
216     if (get_Proj_proj(proj) != pn_Cond_true) {
217       /* it's the false branch */
218       pnc = get_negated_pnc(pnc, mode);
219     }
220 //    ir_printf("At %n using %n Confirm %=\n", block, cmp, pnc);
221
222     handle_if(block, cmp, pnc, env);
223   }
224   else if (mode_is_int(mode)) {
225     long proj_nr = get_Proj_proj(proj);
226
227     /* this is a CASE, but we cannot handle the default case */
228     if (proj_nr == get_Cond_defaultProj(cond))
229       return;
230
231     handle_case(block, get_Cond_selector(cond), proj_nr, env);
232   }
233 }
234
235 /*
236  * Construct Confirm nodes
237  */
238 void construct_confirms(ir_graph *irg)
239 {
240   env_t env;
241   int edges_active = edges_activated(irg);
242
243   if (get_irg_dom_state(irg) != dom_consistent) {
244     /* we need dominance info */
245     compute_doms(irg);
246   }
247
248   assert(get_irg_pinned(irg) == op_pin_state_pinned &&
249     "Nodes must be placed to insert Confirms");
250
251   if (! edges_active) {
252     /* We need edges */
253     edges_activate(irg);
254   }
255
256   env.num_confirms = 0;
257   env.num_consts   = 0;
258   env.num_eq       = 0;
259
260   /* now, visit all blocks and add Confirms where possible */
261   irg_block_walk_graph(irg, insert_Confirm, NULL, &env);
262
263   if (env.num_confirms | env.num_consts | env.num_eq) {
264     /* we have add nodes or changed DF edges */
265     set_irg_outs_inconsistent(irg);
266
267     /* the new nodes are not in the loop info */
268     set_irg_loopinfo_inconsistent(irg);
269   }
270
271 #if 0
272   printf("# Confirms inserted : %u\n", env.num_confirms);
273   printf("# Const replacements: %u\n", env.num_consts);
274   printf("# node equalities   : %u\n", env.num_eq);
275 #endif
276
277   /* deactivate edges if they where off */
278   if (! edges_active)
279     edges_deactivate(irg);
280 }
281
282 /**
283  * Post-walker: Remove Confirm nodes
284  */
285 static void rem_Confirm(ir_node *n, void *env) {
286   if (get_irn_op(n) == op_Confirm) {
287     ir_node *value = get_Confirm_value(n);
288     if (value != n)
289       exchange(n, value);
290     else {
291       /*
292        * Strange: a Confirm is it's own bound. This can happen
293        * in dead blocks when Phi nodes are already removed.
294        */
295       exchange(n, new_Bad());
296     }
297   }
298 }
299
300 /*
301  * Remove all Confirm nodes from a graph.
302  */
303 void remove_confirms(ir_graph *irg) {
304   irg_walk_graph(irg, NULL, rem_Confirm, NULL);
305 }