simplify and cleanup execfreq API
[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         ir_op *op;
270
271         /* Beware of Bads */
272         if (is_Bad(left) || is_Bad(right))
273                 return;
274
275         op = get_irn_op(left);
276
277         /* Do not create Confirm nodes for Cmp(Const, Const) constructs.
278            These are removed anyway */
279         if (op == op_Const && is_Const(right))
280                 return;
281
282         /* try to place the constant on the right side for a Confirm */
283         if (op == op_Const || op == op_SymConst) {
284                 ir_node *t = left;
285
286                 left  = right;
287                 right = t;
288
289                 rel = get_inversed_relation(rel);
290         }
291
292         /*
293          * First case: both values are identical.
294          * replace the left one by the right (potentially const) one.
295          */
296         if (rel == ir_relation_equal) {
297                 cond_block = get_Block_cfgpred_block(block, 0);
298                 foreach_out_edge_safe(left, edge) {
299                         ir_node *user = get_edge_src_irn(edge);
300                         int     pos   = get_edge_src_pos(edge);
301                         ir_node *blk  = get_effective_use_block(user, pos);
302
303                         if (block_dominates(block, blk)) {
304                                 /*
305                                  * Ok, we found a usage of left in a block
306                                  * dominated by the branch block.
307                                  * We can replace the input with right.
308                                  */
309                                 set_irn_n(user, pos, right);
310                                 DBG_OPT_CONFIRM(left, right);
311
312                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, user, right));
313
314                                 env->num_eq += 1;
315                         } else if (block_dominates(blk, cond_block)
316                                         && is_Const(right)
317                                         && get_irn_pinned(user) == op_pin_state_floats) {
318                                 /*
319                                  * left == Const and we found a movable user of left in a
320                                  * dominator of the Cond block
321                                  */
322                                 foreach_out_edge_safe(user, user_edge) {
323                                         ir_node *usr_of_usr = get_edge_src_irn(user_edge);
324                                         int      npos       = get_edge_src_pos(user_edge);
325                                         ir_node *user_blk   = get_effective_use_block(usr_of_usr, npos);
326
327                                         if (block_dominates(block, user_blk)) {
328                                                 /*
329                                                  * The user of the user is dominated by our true/false
330                                                  * block. So, create a copy of user WITH the constant
331                                                  * replacing its pos'th input.
332                                                  *
333                                                  * This is always good for unop's and might be good
334                                                  * for binops.
335                                                  *
336                                                  * If user has other user in the false/true block, code
337                                                  * placement will move it down.
338                                                  * If there are users in cond block or upper, we create
339                                                  * "redundant ops", because one will have a const op,
340                                                  * the other no const ...
341                                                  */
342                                                 ir_node *new_op = exact_copy(user);
343                                                 set_nodes_block(new_op, block);
344                                                 set_irn_n(new_op, pos, right);
345                                                 set_irn_n(usr_of_usr, npos, new_op);
346                                                 env->num_eq += 1;
347                                         }
348                                 }
349                         }
350                 }
351         } else { /* not ir_relation_equal cases */
352                 ir_node *c = NULL;
353
354                 foreach_out_edge_safe(left, edge) {
355                         ir_node *succ = get_edge_src_irn(edge);
356                         int     pos   = get_edge_src_pos(edge);
357                         ir_node *blk  = get_effective_use_block(succ, pos);
358
359                         if (block_dominates(block, blk)) {
360                                 /*
361                                  * Ok, we found a usage of left in a block
362                                  * dominated by the branch block.
363                                  * We can replace the input with a Confirm(left, pnc, right).
364                                  */
365                                 if (! c)
366                                         c = new_r_Confirm(block, left, right, rel);
367
368                                 pos = get_edge_src_pos(edge);
369                                 set_irn_n(succ, pos, c);
370                                 DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
371
372                                 env->num_confirms += 1;
373                         }
374                 }
375
376                 if (! is_Const(right)) {
377                         /* also construct inverse Confirms */
378                         ir_node *rc = NULL;
379
380                         rel = get_inversed_relation(rel);
381                         foreach_out_edge_safe(right, edge) {
382                                 ir_node *succ = get_edge_src_irn(edge);
383                                 int     pos;
384                                 ir_node *blk;
385
386                                 if (succ == c)
387                                         continue;
388
389                                 pos  = get_edge_src_pos(edge);
390                                 blk  = get_effective_use_block(succ, pos);
391
392                                 if (block_dominates(block, blk)) {
393                                         /*
394                                          * Ok, we found a usage of right in a block
395                                          * dominated by the branch block.
396                                          * We can replace the input with a Confirm(right, rel^-1, left).
397                                          */
398                                         if (! rc)
399                                                 rc = new_r_Confirm(block, right, left, rel);
400
401                                         pos = get_edge_src_pos(edge);
402                                         set_irn_n(succ, pos, rc);
403                                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, rc));
404
405                                         env->num_confirms += 1;
406                                 }
407                         }
408                 }
409         }
410 }
411
412 /**
413  * Pre-block-walker: Called for every block to insert Confirm nodes
414  */
415 static void insert_Confirm_in_block(ir_node *block, void *data)
416 {
417         env_t   *env = (env_t*) data;
418         ir_node *cond;
419         ir_node *proj;
420
421         /*
422          * we can only handle blocks with only ONE control flow
423          * predecessor yet.
424          */
425         if (get_Block_n_cfgpreds(block) != 1)
426                 return;
427
428         proj = get_Block_cfgpred(block, 0);
429         if (! is_Proj(proj))
430                 return;
431
432         cond = get_Proj_pred(proj);
433         if (is_Switch(cond)) {
434                 long proj_nr = get_Proj_proj(proj);
435                 handle_case(block, cond, proj_nr, env);
436         } else if (is_Cond(cond)) {
437                 ir_node *selector = get_Cond_selector(cond);
438                 ir_relation rel;
439
440                 handle_modeb(block, selector, (pn_Cond) get_Proj_proj(proj), env);
441
442                 if (! is_Cmp(selector))
443                         return;
444
445                 rel = get_Cmp_relation(selector);
446
447                 if (get_Proj_proj(proj) != pn_Cond_true) {
448                         /* it's the false branch */
449                         rel = get_negated_relation(rel);
450                 }
451                 DB((dbg, LEVEL_2, "At %+F using %+F Confirm %=\n", block, selector, rel));
452
453                 handle_if(block, selector, rel, env);
454         }
455 }
456
457 /**
458  * Checks if a node is a non-null Confirm.
459  */
460 static int is_non_null_Confirm(const ir_node *ptr)
461 {
462         for (;;) {
463                 if (! is_Confirm(ptr))
464                         break;
465                 if (get_Confirm_relation(ptr) == ir_relation_less_greater) {
466                         ir_node *bound = get_Confirm_bound(ptr);
467
468                         if (is_Const(bound) && is_Const_null(bound))
469                                 return 1;
470                 }
471                 ptr = get_Confirm_value(ptr);
472         }
473         /*
474          * While a SymConst is not a Confirm, it is non-null
475          * anyway. This helps to reduce the number of
476          * constructed Confirms.
477          */
478         if (is_SymConst_addr_ent(ptr))
479                 return 1;
480         return 0;
481 }
482
483 /**
484  * The given pointer will be dereferenced, add non-null Confirms.
485  *
486  * @param ptr    a node representing an address
487  * @param block  the block of the dereferencing instruction
488  * @param env    environment
489  */
490 static void insert_non_null(ir_node *ptr, ir_node *block, env_t *env)
491 {
492         ir_node *c = NULL;
493
494         foreach_out_edge_safe(ptr, edge) {
495                 ir_node *succ = get_edge_src_irn(edge);
496                 int     pos;
497                 ir_node *blk;
498
499
500                 /* for now, we place a Confirm only in front of a Cmp */
501                 if (! is_Cmp(succ))
502                         continue;
503
504                 pos = get_edge_src_pos(edge);
505                 blk = get_effective_use_block(succ, pos);
506
507                 if (block_dominates(block, blk)) {
508                         /*
509                          * Ok, we found a usage of ptr in a block
510                          * dominated by the Load/Store block.
511                          * We can replace the input with a Confirm(ptr, !=, NULL).
512                          */
513                         if (c == NULL) {
514                                 ir_mode  *mode = get_irn_mode(ptr);
515                                 ir_graph *irg  = get_irn_irg(block);
516                                 c = new_r_Const(irg, get_mode_null(mode));
517                                 c = new_r_Confirm(block, ptr, c, ir_relation_less_greater);
518                         }
519
520                         set_irn_n(succ, pos, c);
521                         DB((dbg, LEVEL_2, "Replacing input %d of node %+F with %+F\n", pos, succ, c));
522
523                         env->num_non_null += 1;
524                         env->num_confirms += 1;
525                 }
526         }
527 }
528
529 /**
530  * Pre-walker: Called for every node to insert Confirm nodes
531  */
532 static void insert_Confirm(ir_node *node, void *data)
533 {
534         ir_node *ptr;
535         env_t   *env = (env_t*) data;
536
537         switch (get_irn_opcode(node)) {
538         case iro_Block:
539                 insert_Confirm_in_block(node, env);
540                 break;
541         case iro_Load:
542                 ptr = get_Load_ptr(node);
543                 if (! is_non_null_Confirm(ptr))
544                         insert_non_null(ptr, get_nodes_block(node), env);
545                 break;
546         case iro_Store:
547                 ptr = get_Store_ptr(node);
548                 if (! is_non_null_Confirm(ptr))
549                         insert_non_null(ptr, get_nodes_block(node), env);
550                 break;
551         default:
552                 break;
553         }
554 }
555
556 void construct_confirms(ir_graph *irg)
557 {
558         env_t env;
559         FIRM_DBG_REGISTER(dbg, "firm.ana.confirm");
560
561         assure_irg_properties(irg,
562               IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES
563                 | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE
564                 | IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES);
565
566         assert(get_irg_pinned(irg) == op_pin_state_pinned &&
567                "Nodes must be placed to insert Confirms");
568
569         env.num_confirms = 0;
570         env.num_consts   = 0;
571         env.num_eq       = 0;
572         env.num_non_null = 0;
573
574         if (get_opt_global_null_ptr_elimination()) {
575                 /* do global NULL test elimination */
576                 irg_walk_graph(irg, insert_Confirm, NULL, &env);
577         } else {
578                 /* now, visit all blocks and add Confirms where possible */
579                 irg_block_walk_graph(irg, insert_Confirm_in_block, NULL, &env);
580         }
581
582         DB((dbg, LEVEL_1, "# Confirms inserted : %u\n", env.num_confirms));
583         DB((dbg, LEVEL_1, "# Const replacements: %u\n", env.num_consts));
584         DB((dbg, LEVEL_1, "# node equalities   : %u\n", env.num_eq));
585         DB((dbg, LEVEL_1, "# non-null Confirms : %u\n", env.num_non_null));
586
587         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
588 }
589
590 ir_graph_pass_t *construct_confirms_pass(const char *name)
591 {
592         return def_graph_pass(name ? name : "confirm", construct_confirms);
593 }
594
595 static void remove_confirm(ir_node *n, void *env)
596 {
597         ir_node *value;
598
599         (void) env;
600         if (!is_Confirm(n))
601                 return;
602
603         value = get_Confirm_value(n);
604         exchange(n, value);
605 }
606
607 void remove_confirms(ir_graph *irg)
608 {
609         irg_walk_graph(irg, NULL, remove_confirm, NULL);
610         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_CONTROL_FLOW);
611 }
612
613 ir_graph_pass_t *remove_confirms_pass(const char *name)
614 {
615         return def_graph_pass(name ? name : "rem_confirm", remove_confirms);
616 }