cleanup: Remove pointless assert(is_${NODE}(x)) just before get_${NODE}_${FOO}(x...
[libfirm] / ir / ana / irconsconfirm.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief    Construction of Confirm nodes
23  * @author   Michael Beck
24  * @date     6.2005
25  */
26 #include "config.h"
27
28 #include "irconsconfirm.h"
29
30 #include "irgraph_t.h"
31 #include "irnode_t.h"
32 #include "ircons_t.h"
33 #include "irgmod.h"
34 #include "iropt_dbg.h"
35 #include "iredges_t.h"
36 #include "irgwalk.h"
37 #include "irprintf.h"
38 #include "irgopt.h"
39 #include "irpass.h"
40 #include "irtools.h"
41 #include "array_t.h"
42 #include "debug.h"
43 #include "error.h"
44 #include "irflag.h"
45
46 /**
47  * Walker environment.
48  */
49 typedef struct env_t {
50         unsigned num_confirms;  /**< Number of inserted Confirm nodes. */
51         unsigned num_consts;    /**< Number of constants placed. */
52         unsigned num_eq;        /**< Number of equalities placed. */
53         unsigned num_non_null;  /**< Number of non-null Confirms. */
54 } env_t;
55
56 /** The debug handle. */
57 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
58
59 /**
60  * Return the effective use block of a node and its predecessor on
61  * position pos.
62  *
63  * @param node  the node
64  * @param pos   the position of the used input
65  *
66  * This handles correctly Phi nodes.
67  */
68 static ir_node *get_effective_use_block(ir_node *node, int pos)
69 {
70         if (is_Phi(node)) {
71                 /* the effective use of a Phi argument is in its predecessor block */
72                 node = get_nodes_block(node);
73                 return get_Block_cfgpred_block(node, pos);
74         }
75         return get_nodes_block(node);
76 }
77
78 static ir_node *get_case_value(ir_node *switchn, long pn)
79 {
80         ir_graph              *irg       = get_irn_irg(switchn);
81         const ir_switch_table *table     = get_Switch_table(switchn);
82         size_t                 n_entries = ir_switch_table_get_n_entries(table);
83         ir_tarval             *val       = NULL;
84         size_t                 e;
85         for (e = 0; e < n_entries; ++e) {
86                 const ir_switch_table_entry *entry
87                         = ir_switch_table_get_entry_const(table, e);
88                 if (entry->pn != pn)
89                         continue;
90                 /* multiple matching entries gets too complicated for a single
91                  * Confirm */
92                 if (val != NULL)
93                         return NULL;
94                 /* case ranges are too complicated too */
95                 if (entry->min != entry->max)
96                         return NULL;
97                 val = entry->min;
98         }
99         assert(val != NULL);
100         return new_r_Const(irg, val);
101 }
102
103 /**
104  * Handle a CASE-branch.
105  *
106  * Branch labels are a simple case. We can replace the value
107  * by a Const with the branch label.
108  */
109 static void handle_case(ir_node *block, ir_node *switchn, long pn, env_t *env)
110 {
111         ir_node *c = NULL;
112         ir_node *selector = get_Switch_selector(switchn);
113
114         /* we can't do usefull things with the default label */
115         if (pn == pn_Switch_default)
116                 return;
117
118         foreach_out_edge_safe(selector, edge) {
119                 ir_node *succ = get_edge_src_irn(edge);
120                 int     pos   = get_edge_src_pos(edge);
121                 ir_node *blk  = get_effective_use_block(succ, pos);
122
123                 if (block_dominates(block, blk)) {
124                         /*
125                          * Ok, we found a user of irn that is placed
126                          * in a block dominated by the branch block.
127                          * We can replace the input with the Constant
128                          * branch label.
129                          */
130                         if (c == NULL)
131                                 c = get_case_value(switchn, pn);
132
133                         set_irn_n(succ, pos, c);
134                         DBG_OPT_CONFIRM_C(selector, c);
135                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
136
137                         env->num_consts += 1;
138                 }
139         }
140 }
141
142 /**
143  * Handle a mode_b input of Cond nodes.
144  *
145  * @param block     the block which is entered by the branch
146  * @param selector  the mode_b node expressing the branch condition
147  * @param pnc       the true/false condition branch
148  * @param env       statistical environment
149  */
150 static void handle_modeb(ir_node *block, ir_node *selector, pn_Cond pnc, env_t *env)
151 {
152         ir_node *cond, *old, *other_blk = NULL, *con = NULL;
153         ir_node *c_b = NULL, *c_o = NULL;
154
155         foreach_out_edge_safe(selector, edge) {
156                 ir_node *user     = get_edge_src_irn(edge);
157                 int     pos       = get_edge_src_pos(edge);
158                 ir_node *user_blk = get_effective_use_block(user, pos);
159
160                 if (block_dominates(block, user_blk)) {
161                         /*
162                          * Ok, we found a usage of selector in a block
163                          * dominated by the branch block.
164                          * We can replace the input with true/false.
165                          */
166                         if (con == NULL) {
167                                 ir_graph *irg = get_irn_irg(block);
168                                 con = new_r_Const(irg, pnc == pn_Cond_true ? tarval_b_true : tarval_b_false);
169                         }
170                         old = get_irn_n(user, pos);
171                         set_irn_n(user, pos, con);
172                         DBG_OPT_CONFIRM_C(old, con);
173
174                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, user, con));
175
176                         env->num_consts += 1;
177                 } else {
178                         int i, n;
179
180                         /* get the other block */
181                         if (other_blk == NULL) {
182                                 /* we have already tested, that block has only ONE Cond predecessor */
183                                 cond = get_Proj_pred(get_Block_cfgpred(block, 0));
184                                 foreach_out_edge(cond, edge) {
185                                         ir_node *proj = get_edge_src_irn(edge);
186                                         if (get_Proj_proj(proj) == (long)pnc)
187                                                 continue;
188                                         edge = get_irn_out_edge_first(proj);
189                                         other_blk = get_edge_src_irn(edge);
190                                         break;
191                                 }
192                                 assert(other_blk);
193
194                                 /*
195                                  * Note the special case here: if block is a then, there might be no else
196                                  * block. In that case the other_block is the user_blk itself and pred_block
197                                  * is the cond_block ...
198                                  *
199                                  * Best would be to introduce a block here, removing this critical edge.
200                                  * For some reasons I cannot repair dominance here, so I have to remove
201                                  * ALL critical edges...
202                                  * FIXME: This should not be needed if we could repair dominance ...
203                                  */
204                         }
205
206                         n = get_Block_n_cfgpreds(user_blk);
207
208                         /*
209                          * We have found a user in a non-dominated block:
210                          * check, if all its block predecessors are dominated.
211                          * If yes, place a Phi.
212                          */
213                         for (i = n - 1; i >= 0; --i) {
214                                 ir_node *pred_blk = get_Block_cfgpred_block(user_blk, i);
215
216                                 if (!block_dominates(block, pred_blk) &&
217                                     !block_dominates(other_blk, pred_blk)) {
218                                         /* can't do anything */
219                                         break;
220                                 }
221                         }
222                         if (i < 0) {
223                                 ir_node *phi, **in;
224
225                                 NEW_ARR_A(ir_node *, in, n);
226                                 /* ok, ALL predecessors are either dominated by block OR other block */
227                                 if (c_b == NULL) {
228                                         ir_graph *irg    = get_irn_irg(block);
229                                         ir_node *c_true  = new_r_Const(irg, tarval_b_true);
230                                         ir_node *c_false = new_r_Const(irg, tarval_b_false);
231                                         env->num_consts += 2;
232                                         if (pnc == pn_Cond_true) {
233                                                 c_b = c_true;
234                                                 c_o = c_false;
235                                         } else {
236                                                 c_b = c_false;
237                                                 c_o = c_true;
238                                         }
239                                 }
240                                 for (i = n - 1; i >= 0; --i) {
241                                         ir_node *pred_blk = get_Block_cfgpred_block(user_blk, i);
242
243                                         if (block_dominates(block, pred_blk))
244                                                 in[i] = c_b;
245                                         else
246                                                 in[i] = c_o;
247                                 }
248                                 phi = new_r_Phi(user_blk, n, in, mode_b);
249                                 set_irn_n(user, pos, phi);
250                                 env->num_eq += 1;
251                         }
252                 }
253         }
254 }
255
256 /**
257  * Handle an IF-branch.
258  *
259  * @param block   the block which is entered by the branch
260  * @param cmp     the Cmp node expressing the branch condition
261  * @param rel     the Compare relation for taking this branch
262  * @param env     statistical environment
263  */
264 static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
265 {
266         ir_node *left  = get_Cmp_left(cmp);
267         ir_node *right = get_Cmp_right(cmp);
268         ir_node *cond_block;
269
270         /* Beware of Bads */
271         if (is_Bad(left) || is_Bad(right))
272                 return;
273
274         /* Do not create Confirm nodes for Cmp(Const, Const) constructs.
275            These are removed anyway */
276         if (is_Const(left) && is_Const(right))
277                 return;
278
279         /* try to place the constant on the right side for a Confirm */
280         if (is_Const(left) || is_SymConst(left)) {
281                 ir_node *t = left;
282
283                 left  = right;
284                 right = t;
285
286                 rel = get_inversed_relation(rel);
287         }
288
289         /*
290          * First case: both values are identical.
291          * replace the left one by the right (potentially const) one.
292          */
293         if (rel == ir_relation_equal) {
294                 cond_block = get_Block_cfgpred_block(block, 0);
295                 foreach_out_edge_safe(left, edge) {
296                         ir_node *user = get_edge_src_irn(edge);
297                         int     pos   = get_edge_src_pos(edge);
298                         ir_node *blk  = get_effective_use_block(user, pos);
299
300                         if (block_dominates(block, blk)) {
301                                 /*
302                                  * Ok, we found a usage of left in a block
303                                  * dominated by the branch block.
304                                  * We can replace the input with right.
305                                  */
306                                 set_irn_n(user, pos, right);
307                                 DBG_OPT_CONFIRM(left, right);
308
309                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, user, right));
310
311                                 env->num_eq += 1;
312                         } else if (block_dominates(blk, cond_block)
313                                         && is_Const(right)
314                                         && get_irn_pinned(user) == op_pin_state_floats) {
315                                 /*
316                                  * left == Const and we found a movable user of left in a
317                                  * dominator of the Cond block
318                                  */
319                                 foreach_out_edge_safe(user, user_edge) {
320                                         ir_node *usr_of_usr = get_edge_src_irn(user_edge);
321                                         int      npos       = get_edge_src_pos(user_edge);
322                                         ir_node *user_blk   = get_effective_use_block(usr_of_usr, npos);
323
324                                         if (block_dominates(block, user_blk)) {
325                                                 /*
326                                                  * The user of the user is dominated by our true/false
327                                                  * block. So, create a copy of user WITH the constant
328                                                  * replacing its pos'th input.
329                                                  *
330                                                  * This is always good for unop's and might be good
331                                                  * for binops.
332                                                  *
333                                                  * If user has other user in the false/true block, code
334                                                  * placement will move it down.
335                                                  * If there are users in cond block or upper, we create
336                                                  * "redundant ops", because one will have a const op,
337                                                  * the other no const ...
338                                                  */
339                                                 ir_node *new_op = exact_copy(user);
340                                                 set_nodes_block(new_op, block);
341                                                 set_irn_n(new_op, pos, right);
342                                                 set_irn_n(usr_of_usr, npos, new_op);
343                                                 env->num_eq += 1;
344                                         }
345                                 }
346                         }
347                 }
348         } else { /* not ir_relation_equal cases */
349                 ir_node *c = NULL;
350
351                 foreach_out_edge_safe(left, edge) {
352                         ir_node *succ = get_edge_src_irn(edge);
353                         int     pos   = get_edge_src_pos(edge);
354                         ir_node *blk  = get_effective_use_block(succ, pos);
355
356                         if (block_dominates(block, blk)) {
357                                 /*
358                                  * Ok, we found a usage of left in a block
359                                  * dominated by the branch block.
360                                  * We can replace the input with a Confirm(left, pnc, right).
361                                  */
362                                 if (! c)
363                                         c = new_r_Confirm(block, left, right, rel);
364
365                                 pos = get_edge_src_pos(edge);
366                                 set_irn_n(succ, pos, c);
367                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
368
369                                 env->num_confirms += 1;
370                         }
371                 }
372
373                 if (! is_Const(right)) {
374                         /* also construct inverse Confirms */
375                         ir_node *rc = NULL;
376
377                         rel = get_inversed_relation(rel);
378                         foreach_out_edge_safe(right, edge) {
379                                 ir_node *succ = get_edge_src_irn(edge);
380                                 int     pos;
381                                 ir_node *blk;
382
383                                 if (succ == c)
384                                         continue;
385
386                                 pos  = get_edge_src_pos(edge);
387                                 blk  = get_effective_use_block(succ, pos);
388
389                                 if (block_dominates(block, blk)) {
390                                         /*
391                                          * Ok, we found a usage of right in a block
392                                          * dominated by the branch block.
393                                          * We can replace the input with a Confirm(right, rel^-1, left).
394                                          */
395                                         if (! rc)
396                                                 rc = new_r_Confirm(block, right, left, rel);
397
398                                         pos = get_edge_src_pos(edge);
399                                         set_irn_n(succ, pos, rc);
400                                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, rc));
401
402                                         env->num_confirms += 1;
403                                 }
404                         }
405                 }
406         }
407 }
408
409 /**
410  * Pre-block-walker: Called for every block to insert Confirm nodes
411  */
412 static void insert_Confirm_in_block(ir_node *block, void *data)
413 {
414         env_t   *env = (env_t*) data;
415         ir_node *cond;
416         ir_node *proj;
417
418         /*
419          * we can only handle blocks with only ONE control flow
420          * predecessor yet.
421          */
422         if (get_Block_n_cfgpreds(block) != 1)
423                 return;
424
425         proj = get_Block_cfgpred(block, 0);
426         if (! is_Proj(proj))
427                 return;
428
429         cond = get_Proj_pred(proj);
430         if (is_Switch(cond)) {
431                 long proj_nr = get_Proj_proj(proj);
432                 handle_case(block, cond, proj_nr, env);
433         } else if (is_Cond(cond)) {
434                 ir_node *selector = get_Cond_selector(cond);
435                 ir_relation rel;
436
437                 handle_modeb(block, selector, (pn_Cond) get_Proj_proj(proj), env);
438
439                 if (! is_Cmp(selector))
440                         return;
441
442                 rel = get_Cmp_relation(selector);
443
444                 if (get_Proj_proj(proj) != pn_Cond_true) {
445                         /* it's the false branch */
446                         rel = get_negated_relation(rel);
447                 }
448                 DB((dbg, LEVEL_2, "At %+F using %+F Confirm %=\n", block, selector, rel));
449
450                 handle_if(block, selector, rel, env);
451         }
452 }
453
454 /**
455  * Checks if a node is a non-null Confirm.
456  */
457 static int is_non_null_Confirm(const ir_node *ptr)
458 {
459         for (;;) {
460                 if (! is_Confirm(ptr))
461                         break;
462                 if (get_Confirm_relation(ptr) == ir_relation_less_greater) {
463                         ir_node *bound = get_Confirm_bound(ptr);
464
465                         if (is_Const(bound) && is_Const_null(bound))
466                                 return 1;
467                 }
468                 ptr = get_Confirm_value(ptr);
469         }
470         /*
471          * While a SymConst is not a Confirm, it is non-null
472          * anyway. This helps to reduce the number of
473          * constructed Confirms.
474          */
475         if (is_SymConst_addr_ent(ptr))
476                 return 1;
477         return 0;
478 }
479
480 /**
481  * The given pointer will be dereferenced, add non-null Confirms.
482  *
483  * @param ptr    a node representing an address
484  * @param block  the block of the dereferencing instruction
485  * @param env    environment
486  */
487 static void insert_non_null(ir_node *ptr, ir_node *block, env_t *env)
488 {
489         ir_node *c = NULL;
490
491         foreach_out_edge_safe(ptr, edge) {
492                 ir_node *succ = get_edge_src_irn(edge);
493                 int     pos;
494                 ir_node *blk;
495
496
497                 /* for now, we place a Confirm only in front of a Cmp */
498                 if (! is_Cmp(succ))
499                         continue;
500
501                 pos = get_edge_src_pos(edge);
502                 blk = get_effective_use_block(succ, pos);
503
504                 if (block_dominates(block, blk)) {
505                         /*
506                          * Ok, we found a usage of ptr in a block
507                          * dominated by the Load/Store block.
508                          * We can replace the input with a Confirm(ptr, !=, NULL).
509                          */
510                         if (c == NULL) {
511                                 ir_mode  *mode = get_irn_mode(ptr);
512                                 ir_graph *irg  = get_irn_irg(block);
513                                 c = new_r_Const(irg, get_mode_null(mode));
514                                 c = new_r_Confirm(block, ptr, c, ir_relation_less_greater);
515                         }
516
517                         set_irn_n(succ, pos, c);
518                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
519
520                         env->num_non_null += 1;
521                         env->num_confirms += 1;
522                 }
523         }
524 }
525
526 /**
527  * Pre-walker: Called for every node to insert Confirm nodes
528  */
529 static void insert_Confirm(ir_node *node, void *data)
530 {
531         ir_node *ptr;
532         env_t   *env = (env_t*) data;
533
534         switch (get_irn_opcode(node)) {
535         case iro_Block:
536                 insert_Confirm_in_block(node, env);
537                 break;
538         case iro_Load:
539                 ptr = get_Load_ptr(node);
540                 if (! is_non_null_Confirm(ptr))
541                         insert_non_null(ptr, get_nodes_block(node), env);
542                 break;
543         case iro_Store:
544                 ptr = get_Store_ptr(node);
545                 if (! is_non_null_Confirm(ptr))
546                         insert_non_null(ptr, get_nodes_block(node), env);
547                 break;
548         default:
549                 break;
550         }
551 }
552
553 void construct_confirms(ir_graph *irg)
554 {
555         env_t env;
556         FIRM_DBG_REGISTER(dbg, "firm.ana.confirm");
557
558         assure_irg_properties(irg,
559               IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES
560                 | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE
561                 | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES);
562
563         assert(get_irg_pinned(irg) == op_pin_state_pinned &&
564                "Nodes must be placed to insert Confirms");
565
566         env.num_confirms = 0;
567         env.num_consts   = 0;
568         env.num_eq       = 0;
569         env.num_non_null = 0;
570
571         if (get_opt_global_null_ptr_elimination()) {
572                 /* do global NULL test elimination */
573                 irg_walk_graph(irg, insert_Confirm, NULL, &env);
574         } else {
575                 /* now, visit all blocks and add Confirms where possible */
576                 irg_block_walk_graph(irg, insert_Confirm_in_block, NULL, &env);
577         }
578
579         DB((dbg, LEVEL_1, "# Confirms inserted : %u\n", env.num_confirms));
580         DB((dbg, LEVEL_1, "# Const replacements: %u\n", env.num_consts));
581         DB((dbg, LEVEL_1, "# node equalities   : %u\n", env.num_eq));
582         DB((dbg, LEVEL_1, "# non-null Confirms : %u\n", env.num_non_null));
583
584         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
585 }
586
587 ir_graph_pass_t *construct_confirms_pass(const char *name)
588 {
589         return def_graph_pass(name ? name : "confirm", construct_confirms);
590 }
591
592 static void remove_confirm(ir_node *n, void *env)
593 {
594         ir_node *value;
595
596         (void) env;
597         if (!is_Confirm(n))
598                 return;
599
600         value = get_Confirm_value(n);
601         exchange(n, value);
602 }
603
604 void remove_confirms(ir_graph *irg)
605 {
606         irg_walk_graph(irg, NULL, remove_confirm, NULL);
607         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
608 }
609
610 ir_graph_pass_t *remove_confirms_pass(const char *name)
611 {
612         return def_graph_pass(name ? name : "rem_confirm", remove_confirms);
613 }