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