Directly use pmap_get() instead of pmap_contains() + pmap_get().
[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         const ir_edge_t *edge;
114         const ir_edge_t *next;
115
116         /* we can't do usefull things with the default label */
117         if (pn == pn_Switch_default)
118                 return;
119
120         foreach_out_edge_safe(selector, edge, next) {
121                 ir_node *succ = get_edge_src_irn(edge);
122                 int     pos   = get_edge_src_pos(edge);
123                 ir_node *blk  = get_effective_use_block(succ, pos);
124
125                 if (block_dominates(block, blk)) {
126                         /*
127                          * Ok, we found a user of irn that is placed
128                          * in a block dominated by the branch block.
129                          * We can replace the input with the Constant
130                          * branch label.
131                          */
132                         if (c == NULL)
133                                 c = get_case_value(switchn, pn);
134
135                         set_irn_n(succ, pos, c);
136                         DBG_OPT_CONFIRM_C(selector, c);
137                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
138
139                         env->num_consts += 1;
140                 }
141         }
142 }
143
144 /**
145  * Handle a mode_b input of Cond nodes.
146  *
147  * @param block     the block which is entered by the branch
148  * @param selector  the mode_b node expressing the branch condition
149  * @param pnc       the true/false condition branch
150  * @param env       statistical environment
151  */
152 static void handle_modeb(ir_node *block, ir_node *selector, pn_Cond pnc, env_t *env)
153 {
154         ir_node *cond, *old, *other_blk = NULL, *con = NULL;
155         ir_node *c_b = NULL, *c_o = NULL;
156         const ir_edge_t *edge, *next;
157
158         for (edge = get_irn_out_edge_first(selector); edge; edge = next) {
159                 ir_node *user     = get_edge_src_irn(edge);
160                 int     pos       = get_edge_src_pos(edge);
161                 ir_node *user_blk = get_effective_use_block(user, pos);
162
163                 next = get_irn_out_edge_next(selector, edge);
164                 if (block_dominates(block, user_blk)) {
165                         /*
166                          * Ok, we found a usage of selector in a block
167                          * dominated by the branch block.
168                          * We can replace the input with true/false.
169                          */
170                         if (con == NULL) {
171                                 ir_graph *irg = get_irn_irg(block);
172                                 con = new_r_Const(irg, pnc == pn_Cond_true ? tarval_b_true : tarval_b_false);
173                         }
174                         old = get_irn_n(user, pos);
175                         set_irn_n(user, pos, con);
176                         DBG_OPT_CONFIRM_C(old, con);
177
178                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, user, con));
179
180                         env->num_consts += 1;
181                 } else {
182                         int i, n;
183
184                         /* get the other block */
185                         if (other_blk == NULL) {
186                                 /* we have already tested, that block has only ONE Cond predecessor */
187                                 cond = get_Proj_pred(get_Block_cfgpred(block, 0));
188                                 foreach_out_edge(cond, edge) {
189                                         ir_node *proj = get_edge_src_irn(edge);
190                                         if (get_Proj_proj(proj) == (long)pnc)
191                                                 continue;
192                                         edge = get_irn_out_edge_first(proj);
193                                         other_blk = get_edge_src_irn(edge);
194                                         break;
195                                 }
196                                 assert(other_blk);
197
198                                 /*
199                                  * Note the special case here: if block is a then, there might be no else
200                                  * block. In that case the other_block is the user_blk itself and pred_block
201                                  * is the cond_block ...
202                                  *
203                                  * Best would be to introduce a block here, removing this critical edge.
204                                  * For some reasons I cannot repair dominance here, so I have to remove
205                                  * ALL critical edges...
206                                  * FIXME: This should not be needed if we could repair dominance ...
207                                  */
208                         }
209
210                         n = get_Block_n_cfgpreds(user_blk);
211
212                         /*
213                          * We have found a user in a non-dominated block:
214                          * check, if all its block predecessors are dominated.
215                          * If yes, place a Phi.
216                          */
217                         for (i = n - 1; i >= 0; --i) {
218                                 ir_node *pred_blk = get_Block_cfgpred_block(user_blk, i);
219
220                                 if (!block_dominates(block, pred_blk) &&
221                                     !block_dominates(other_blk, pred_blk)) {
222                                         /* can't do anything */
223                                         break;
224                                 }
225                         }
226                         if (i < 0) {
227                                 ir_node *phi, **in;
228
229                                 NEW_ARR_A(ir_node *, in, n);
230                                 /* ok, ALL predecessors are either dominated by block OR other block */
231                                 if (c_b == NULL) {
232                                         ir_graph *irg    = get_irn_irg(block);
233                                         ir_node *c_true  = new_r_Const(irg, tarval_b_true);
234                                         ir_node *c_false = new_r_Const(irg, tarval_b_false);
235                                         env->num_consts += 2;
236                                         if (pnc == pn_Cond_true) {
237                                                 c_b = c_true;
238                                                 c_o = c_false;
239                                         } else {
240                                                 c_b = c_false;
241                                                 c_o = c_true;
242                                         }
243                                 }
244                                 for (i = n - 1; i >= 0; --i) {
245                                         ir_node *pred_blk = get_Block_cfgpred_block(user_blk, i);
246
247                                         if (block_dominates(block, pred_blk))
248                                                 in[i] = c_b;
249                                         else
250                                                 in[i] = c_o;
251                                 }
252                                 phi = new_r_Phi(user_blk, n, in, mode_b);
253                                 set_irn_n(user, pos, phi);
254                                 env->num_eq += 1;
255                         }
256                 }
257         }
258 }
259
260 /**
261  * Handle an IF-branch.
262  *
263  * @param block   the block which is entered by the branch
264  * @param cmp     the Cmp node expressing the branch condition
265  * @param rel     the Compare relation for taking this branch
266  * @param env     statistical environment
267  */
268 static void handle_if(ir_node *block, ir_node *cmp, ir_relation rel, env_t *env)
269 {
270         ir_node *left  = get_Cmp_left(cmp);
271         ir_node *right = get_Cmp_right(cmp);
272         ir_node *cond_block;
273         ir_op *op;
274         const ir_edge_t *edge, *next;
275
276         /* Beware of Bads */
277         if (is_Bad(left) || is_Bad(right))
278                 return;
279
280         op = get_irn_op(left);
281
282         /* Do not create Confirm nodes for Cmp(Const, Const) constructs.
283            These are removed anyway */
284         if (op == op_Const && is_Const(right))
285                 return;
286
287         /* try to place the constant on the right side for a Confirm */
288         if (op == op_Const || op == op_SymConst) {
289                 ir_node *t = left;
290
291                 left  = right;
292                 right = t;
293
294                 rel = get_inversed_relation(rel);
295         }
296
297         /*
298          * First case: both values are identical.
299          * replace the left one by the right (potentially const) one.
300          */
301         if (rel == ir_relation_equal) {
302                 cond_block = get_Block_cfgpred_block(block, 0);
303                 for (edge = get_irn_out_edge_first(left); edge; edge = next) {
304                         ir_node *user = get_edge_src_irn(edge);
305                         int     pos   = get_edge_src_pos(edge);
306                         ir_node *blk  = get_effective_use_block(user, pos);
307
308                         next = get_irn_out_edge_next(left, edge);
309                         if (block_dominates(block, blk)) {
310                                 /*
311                                  * Ok, we found a usage of left in a block
312                                  * dominated by the branch block.
313                                  * We can replace the input with right.
314                                  */
315                                 set_irn_n(user, pos, right);
316                                 DBG_OPT_CONFIRM(left, right);
317
318                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, user, right));
319
320                                 env->num_eq += 1;
321                         } else if (block_dominates(blk, cond_block)
322                                         && is_Const(right)
323                                         && get_irn_pinned(user) == op_pin_state_floats) {
324                                 /*
325                                  * left == Const and we found a movable user of left in a
326                                  * dominator of the Cond block
327                                  */
328                                 const ir_edge_t *user_edge;
329                                 const ir_edge_t *user_next;
330                                 foreach_out_edge_safe(user, user_edge, user_next) {
331                                         ir_node *usr_of_usr = get_edge_src_irn(user_edge);
332                                         int      npos       = get_edge_src_pos(user_edge);
333                                         ir_node *user_blk   = get_effective_use_block(usr_of_usr, npos);
334
335                                         if (block_dominates(block, user_blk)) {
336                                                 /*
337                                                  * The user of the user is dominated by our true/false
338                                                  * block. So, create a copy of user WITH the constant
339                                                  * replacing its pos'th input.
340                                                  *
341                                                  * This is always good for unop's and might be good
342                                                  * for binops.
343                                                  *
344                                                  * If user has other user in the false/true block, code
345                                                  * placement will move it down.
346                                                  * If there are users in cond block or upper, we create
347                                                  * "redundant ops", because one will have a const op,
348                                                  * the other no const ...
349                                                  */
350                                                 ir_node *new_op = exact_copy(user);
351                                                 set_nodes_block(new_op, block);
352                                                 set_irn_n(new_op, pos, right);
353                                                 set_irn_n(usr_of_usr, npos, new_op);
354                                                 env->num_eq += 1;
355                                         }
356                                 }
357                         }
358                 }
359         } else { /* not ir_relation_equal cases */
360                 ir_node *c = NULL;
361
362                 foreach_out_edge_safe(left, edge, next) {
363                         ir_node *succ = get_edge_src_irn(edge);
364                         int     pos   = get_edge_src_pos(edge);
365                         ir_node *blk  = get_effective_use_block(succ, pos);
366
367                         if (block_dominates(block, blk)) {
368                                 /*
369                                  * Ok, we found a usage of left in a block
370                                  * dominated by the branch block.
371                                  * We can replace the input with a Confirm(left, pnc, right).
372                                  */
373                                 if (! c)
374                                         c = new_r_Confirm(block, left, right, rel);
375
376                                 pos = get_edge_src_pos(edge);
377                                 set_irn_n(succ, pos, c);
378                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
379
380                                 env->num_confirms += 1;
381                         }
382                 }
383
384                 if (! is_Const(right)) {
385                         /* also construct inverse Confirms */
386                         ir_node *rc = NULL;
387
388                         rel = get_inversed_relation(rel);
389                         foreach_out_edge_safe(right, edge, next) {
390                                 ir_node *succ = get_edge_src_irn(edge);
391                                 int     pos;
392                                 ir_node *blk;
393
394                                 if (succ == c)
395                                         continue;
396
397                                 pos  = get_edge_src_pos(edge);
398                                 blk  = get_effective_use_block(succ, pos);
399
400                                 if (block_dominates(block, blk)) {
401                                         /*
402                                          * Ok, we found a usage of right in a block
403                                          * dominated by the branch block.
404                                          * We can replace the input with a Confirm(right, rel^-1, left).
405                                          */
406                                         if (! rc)
407                                                 rc = new_r_Confirm(block, right, left, rel);
408
409                                         pos = get_edge_src_pos(edge);
410                                         set_irn_n(succ, pos, rc);
411                                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, rc));
412
413                                         env->num_confirms += 1;
414                                 }
415                         }
416                 }
417         }
418 }
419
420 /**
421  * Pre-block-walker: Called for every block to insert Confirm nodes
422  */
423 static void insert_Confirm_in_block(ir_node *block, void *data)
424 {
425         env_t   *env = (env_t*) data;
426         ir_node *cond;
427         ir_node *proj;
428
429         /*
430          * we can only handle blocks with only ONE control flow
431          * predecessor yet.
432          */
433         if (get_Block_n_cfgpreds(block) != 1)
434                 return;
435
436         proj = get_Block_cfgpred(block, 0);
437         if (! is_Proj(proj))
438                 return;
439
440         cond = get_Proj_pred(proj);
441         if (is_Switch(cond)) {
442                 long proj_nr = get_Proj_proj(proj);
443                 handle_case(block, cond, proj_nr, env);
444         } else if (is_Cond(cond)) {
445                 ir_node *selector = get_Cond_selector(cond);
446                 ir_relation rel;
447
448                 handle_modeb(block, selector, (pn_Cond) get_Proj_proj(proj), env);
449
450                 if (! is_Cmp(selector))
451                         return;
452
453                 rel = get_Cmp_relation(selector);
454
455                 if (get_Proj_proj(proj) != pn_Cond_true) {
456                         /* it's the false branch */
457                         rel = get_negated_relation(rel);
458                 }
459                 DB((dbg, LEVEL_2, "At %+F using %+F Confirm %=\n", block, selector, rel));
460
461                 handle_if(block, selector, rel, env);
462         }
463 }
464
465 /**
466  * Checks if a node is a non-null Confirm.
467  */
468 static int is_non_null_Confirm(const ir_node *ptr)
469 {
470         for (;;) {
471                 if (! is_Confirm(ptr))
472                         break;
473                 if (get_Confirm_relation(ptr) == ir_relation_less_greater) {
474                         ir_node *bound = get_Confirm_bound(ptr);
475
476                         if (is_Const(bound) && is_Const_null(bound))
477                                 return 1;
478                 }
479                 ptr = get_Confirm_value(ptr);
480         }
481         /*
482          * While a SymConst is not a Confirm, it is non-null
483          * anyway. This helps to reduce the number of
484          * constructed Confirms.
485          */
486         if (is_SymConst_addr_ent(ptr))
487                 return 1;
488         return 0;
489 }
490
491 /**
492  * The given pointer will be dereferenced, add non-null Confirms.
493  *
494  * @param ptr    a node representing an address
495  * @param block  the block of the dereferencing instruction
496  * @param env    environment
497  */
498 static void insert_non_null(ir_node *ptr, ir_node *block, env_t *env)
499 {
500         const ir_edge_t *edge, *next;
501         ir_node         *c = NULL;
502
503         foreach_out_edge_safe(ptr, edge, next) {
504                 ir_node *succ = get_edge_src_irn(edge);
505                 int     pos;
506                 ir_node *blk;
507
508
509                 /* for now, we place a Confirm only in front of a Cmp */
510                 if (! is_Cmp(succ))
511                         continue;
512
513                 pos = get_edge_src_pos(edge);
514                 blk = get_effective_use_block(succ, pos);
515
516                 if (block_dominates(block, blk)) {
517                         /*
518                          * Ok, we found a usage of ptr in a block
519                          * dominated by the Load/Store block.
520                          * We can replace the input with a Confirm(ptr, !=, NULL).
521                          */
522                         if (c == NULL) {
523                                 ir_mode  *mode = get_irn_mode(ptr);
524                                 ir_graph *irg  = get_irn_irg(block);
525                                 c = new_r_Const(irg, get_mode_null(mode));
526                                 c = new_r_Confirm(block, ptr, c, ir_relation_less_greater);
527                         }
528
529                         set_irn_n(succ, pos, c);
530                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
531
532                         env->num_non_null += 1;
533                         env->num_confirms += 1;
534                 }
535         }
536 }
537
538 /**
539  * Pre-walker: Called for every node to insert Confirm nodes
540  */
541 static void insert_Confirm(ir_node *node, void *data)
542 {
543         ir_node *ptr;
544         env_t   *env = (env_t*) data;
545
546         switch (get_irn_opcode(node)) {
547         case iro_Block:
548                 insert_Confirm_in_block(node, env);
549                 break;
550         case iro_Load:
551                 ptr = get_Load_ptr(node);
552                 if (! is_non_null_Confirm(ptr))
553                         insert_non_null(ptr, get_nodes_block(node), env);
554                 break;
555         case iro_Store:
556                 ptr = get_Store_ptr(node);
557                 if (! is_non_null_Confirm(ptr))
558                         insert_non_null(ptr, get_nodes_block(node), env);
559                 break;
560         default:
561                 break;
562         }
563 }
564
565 void construct_confirms(ir_graph *irg)
566 {
567         env_t env;
568         FIRM_DBG_REGISTER(dbg, "firm.ana.confirm");
569
570         assure_irg_properties(irg,
571               IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES
572                 | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE
573                 | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES);
574
575         assert(get_irg_pinned(irg) == op_pin_state_pinned &&
576                "Nodes must be placed to insert Confirms");
577
578         env.num_confirms = 0;
579         env.num_consts   = 0;
580         env.num_eq       = 0;
581         env.num_non_null = 0;
582
583         if (get_opt_global_null_ptr_elimination()) {
584                 /* do global NULL test elimination */
585                 irg_walk_graph(irg, insert_Confirm, NULL, &env);
586         } else {
587                 /* now, visit all blocks and add Confirms where possible */
588                 irg_block_walk_graph(irg, insert_Confirm_in_block, NULL, &env);
589         }
590
591         DB((dbg, LEVEL_1, "# Confirms inserted : %u\n", env.num_confirms));
592         DB((dbg, LEVEL_1, "# Const replacements: %u\n", env.num_consts));
593         DB((dbg, LEVEL_1, "# node equalities   : %u\n", env.num_eq));
594         DB((dbg, LEVEL_1, "# non-null Confirms : %u\n", env.num_non_null));
595
596         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
597 }
598
599 ir_graph_pass_t *construct_confirms_pass(const char *name)
600 {
601         return def_graph_pass(name ? name : "confirm", construct_confirms);
602 }
603
604 static void remove_confirm(ir_node *n, void *env)
605 {
606         ir_node *value;
607
608         (void) env;
609         if (!is_Confirm(n))
610                 return;
611
612         value = get_Confirm_value(n);
613         exchange(n, value);
614 }
615
616 void remove_confirms(ir_graph *irg)
617 {
618         irg_walk_graph(irg, NULL, remove_confirm, NULL);
619         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
620 }
621
622 ir_graph_pass_t *remove_confirms_pass(const char *name)
623 {
624         return def_graph_pass(name ? name : "rem_confirm", remove_confirms);
625 }