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