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