Removed mode parameter from Const and Const_type constructors (now derived from tarval)
[libfirm] / ir / opt / condeval.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   Partial condition evaluation
23  * @date    10. Sep. 2006
24  * @author  Christoph Mallon, Matthias Braun
25  * @version $Id$
26  */
27 #include "config.h"
28
29 #include "iroptimize.h"
30
31 #include <assert.h>
32 #include "array_t.h"
33 #include "debug.h"
34 #include "ircons.h"
35 #include "irgmod.h"
36 #include "irgopt.h"
37 #include "irgwalk.h"
38 #include "irnode.h"
39 #include "irnode_t.h"
40 #include "iredges.h"
41 #include "iredges_t.h"
42 #include "irtools.h"
43 #include "irgraph.h"
44 #include "tv.h"
45 #include "opt_confirms.h"
46
47 #undef AVOID_PHIB
48
49 DEBUG_ONLY(static firm_dbg_module_t *dbg);
50
51 /**
52  * Add the new predecessor x to node node, which is either a Block or a Phi
53  */
54 static void add_pred(ir_node* node, ir_node* x)
55 {
56         ir_node** ins;
57         int n;
58         int i;
59
60         assert(is_Block(node) || is_Phi(node));
61
62         n = get_irn_arity(node);
63         NEW_ARR_A(ir_node*, ins, n + 1);
64         for (i = 0; i < n; i++)
65                 ins[i] = get_irn_n(node, i);
66         ins[n] = x;
67         set_irn_in(node, n + 1, ins);
68 }
69
70 static ir_node *ssa_second_def;
71 static ir_node *ssa_second_def_block;
72
73 static ir_node *search_def_and_create_phis(ir_node *block, ir_mode *mode,
74                                            int first)
75 {
76         int i;
77         int n_cfgpreds;
78         ir_graph *irg;
79         ir_node *phi;
80         ir_node **in;
81
82         /* This is needed because we create bads sometimes */
83         if(is_Bad(block))
84                 return new_Bad();
85
86         /* the other defs can't be marked for cases where a user of the original
87          * value is in the same block as the alternative definition.
88          * In this case we mustn't use the alternative definition.
89          * So we keep a flag that indicated wether we walked at least 1 block
90          * away and may use the alternative definition */
91         if (block == ssa_second_def_block && !first) {
92                 return ssa_second_def;
93         }
94
95         /* already processed this block? */
96         if(irn_visited(block)) {
97                 ir_node *value = (ir_node*) get_irn_link(block);
98                 return value;
99         }
100
101         irg = get_irn_irg(block);
102         assert(block != get_irg_start_block(irg));
103
104         /* a Block with only 1 predecessor needs no Phi */
105         n_cfgpreds = get_Block_n_cfgpreds(block);
106         if(n_cfgpreds == 1) {
107                 ir_node *pred_block = get_Block_cfgpred_block(block, 0);
108                 ir_node *value      = search_def_and_create_phis(pred_block, mode, 0);
109
110                 set_irn_link(block, value);
111                 mark_irn_visited(block);
112                 return value;
113         }
114
115         /* create a new Phi */
116         NEW_ARR_A(ir_node*, in, n_cfgpreds);
117         for(i = 0; i < n_cfgpreds; ++i)
118                 in[i] = new_Unknown(mode);
119
120         phi = new_r_Phi(irg, block, n_cfgpreds, in, mode);
121         set_irn_link(block, phi);
122         mark_irn_visited(block);
123
124         /* set Phi predecessors */
125         for(i = 0; i < n_cfgpreds; ++i) {
126                 ir_node *pred_block = get_Block_cfgpred_block(block, i);
127                 ir_node *pred_val   = search_def_and_create_phis(pred_block, mode, 0);
128
129                 set_irn_n(phi, i, pred_val);
130         }
131
132         return phi;
133 }
134
135 /**
136  * Given a set of values this function constructs SSA-form for the users of the
137  * first value (the users are determined through the out-edges of the value).
138  * Uses the irn_visited flags. Works without using the dominance tree.
139  */
140 static void construct_ssa(ir_node *orig_block, ir_node *orig_val,
141                           ir_node *second_block, ir_node *second_val)
142 {
143         ir_graph *irg;
144         ir_mode *mode;
145         const ir_edge_t *edge;
146         const ir_edge_t *next;
147
148         /* no need to do anything */
149         if (orig_val == second_val)
150                 return;
151
152         irg = get_irn_irg(orig_val);
153         inc_irg_visited(irg);
154
155         mode = get_irn_mode(orig_val);
156         set_irn_link(orig_block, orig_val);
157         mark_irn_visited(orig_block);
158
159         ssa_second_def_block = second_block;
160         ssa_second_def       = second_val;
161
162         /* Only fix the users of the first, i.e. the original node */
163         foreach_out_edge_safe(orig_val, edge, next) {
164                 ir_node *user = get_edge_src_irn(edge);
165                 int j = get_edge_src_pos(edge);
166                 ir_node *user_block = get_nodes_block(user);
167                 ir_node *newval;
168
169                 /* ignore keeps */
170                 if (is_End(user))
171                         continue;
172
173                 DB((dbg, LEVEL_3, ">>> Fixing user %+F (pred %d == %+F)\n", user, j, get_irn_n(user, j)));
174
175                 if(is_Phi(user)) {
176                         ir_node *pred_block = get_Block_cfgpred_block(user_block, j);
177                         newval = search_def_and_create_phis(pred_block, mode, 1);
178                 } else {
179                         newval = search_def_and_create_phis(user_block, mode, 1);
180                 }
181
182                 /* don't fix newly created Phis from the SSA construction */
183                 if (newval != user) {
184                         DB((dbg, LEVEL_4, ">>>> Setting input %d of %+F to %+F\n", j, user, newval));
185                         set_irn_n(user, j, newval);
186                 }
187         }
188 }
189
190 static void split_critical_edge(ir_node *block, int pos) {
191         ir_graph *irg = get_irn_irg(block);
192         ir_node *in[1];
193         ir_node *new_block;
194         ir_node *new_jmp;
195
196         in[0] = get_Block_cfgpred(block, pos);
197         new_block = new_r_Block(irg, 1, in);
198         new_jmp = new_r_Jmp(irg, new_block);
199         set_Block_cfgpred(block, pos, new_jmp);
200 }
201
202 typedef struct condeval_env_t {
203         ir_node       *true_block;
204         ir_node       *cmp;        /**< The Compare node that might be partial evaluated */
205         pn_Cmp         pnc;        /**< The Compare mode of the Compare node. */
206         ir_node       *cnst;
207         tarval        *tv;
208         ir_visited_t   visited_nr;
209
210         ir_node       *cnst_pred;   /**< the block before the constant */
211         int            cnst_pos;    /**< the pos to the constant block (needed to
212                                           kill that edge later) */
213 } condeval_env_t;
214
215 static ir_node *copy_and_fix_node(const condeval_env_t *env, ir_node *block,
216                                   ir_node *copy_block, int j, ir_node *node) {
217         int      i, arity;
218         ir_node *copy;
219
220         /* we can evaluate Phis right now, all other nodes get copied */
221         if (is_Phi(node)) {
222                 copy = get_Phi_pred(node, j);
223                 /* we might have to evaluate a Phi-cascade */
224                 if(get_irn_visited(copy) >= env->visited_nr) {
225                         copy = get_irn_link(copy);
226                 }
227         } else {
228                 copy = exact_copy(node);
229                 set_nodes_block(copy, copy_block);
230
231                 assert(get_irn_mode(copy) != mode_X);
232
233                 arity = get_irn_arity(copy);
234                 for(i = 0; i < arity; ++i) {
235                         ir_node *pred     = get_irn_n(copy, i);
236                         ir_node *new_pred;
237
238                         if(get_nodes_block(pred) != block)
239                                 continue;
240
241                         if(get_irn_visited(pred) >= env->visited_nr) {
242                                 new_pred = get_irn_link(pred);
243                         } else {
244                                 new_pred = copy_and_fix_node(env, block, copy_block, j, pred);
245                         }
246                         DB((dbg, LEVEL_2, ">> Set Pred of %+F to %+F\n", copy, new_pred));
247                         set_irn_n(copy, i, new_pred);
248                 }
249         }
250
251         set_irn_link(node, copy);
252         set_irn_visited(node, env->visited_nr);
253
254         return copy;
255 }
256
257 static void copy_and_fix(const condeval_env_t *env, ir_node *block,
258                          ir_node *copy_block, int j) {
259         const ir_edge_t *edge;
260
261         /* Look at all nodes in the cond_block and copy them into pred */
262         foreach_out_edge(block, edge) {
263                 ir_node *node = get_edge_src_irn(edge);
264                 ir_node *copy;
265                 ir_mode *mode;
266
267                 if (is_Block(node)) {
268                         /* Block->Block edge, should be the MacroBlock edge */
269                         assert(get_Block_MacroBlock(node) == block && "Block->Block edge found");
270                         continue;
271                 }
272
273                 /* ignore control flow */
274                 mode = get_irn_mode(node);
275                 if (mode == mode_X || is_Cond(node))
276                         continue;
277 #ifdef AVOID_PHIB
278                 /* we may not copy mode_b nodes, because this could produce Phi with
279                  * mode_bs which can't be handled in all backends. Instead we duplicate
280                  * the node and move it to its users */
281                 if (mode == mode_b) {
282                         const ir_edge_t *edge, *next;
283                         ir_node *pred;
284                         int      pn;
285
286                         assert(is_Proj(node));
287
288                         pred = get_Proj_pred(node);
289                         pn   = get_Proj_proj(node);
290
291                         foreach_out_edge_safe(node, edge, next) {
292                                 ir_node *cmp_copy;
293                                 ir_node *user       = get_edge_src_irn(edge);
294                                 int pos             = get_edge_src_pos(edge);
295                                 ir_node *user_block = get_nodes_block(user);
296
297                                 if(user_block == block)
298                                         continue;
299
300                                 cmp_copy = exact_copy(pred);
301                                 set_nodes_block(cmp_copy, user_block);
302                                 copy = new_r_Proj(current_ir_graph, user_block, cmp_copy, mode_b, pn);
303                                 set_irn_n(user, pos, copy);
304                         }
305                         continue;
306                 }
307 #endif
308
309                 copy = copy_and_fix_node(env, block, copy_block, j, node);
310
311                 /* we might hit values in blocks that have already been processed by a
312                  * recursive find_phi_with_const() call */
313                 assert(get_irn_visited(copy) <= env->visited_nr);
314                 if(get_irn_visited(copy) >= env->visited_nr) {
315                         ir_node *prev_copy = get_irn_link(copy);
316                         if(prev_copy != NULL)
317                                 set_irn_link(node, prev_copy);
318                 }
319         }
320
321         /* fix data-flow (and reconstruct SSA if needed) */
322         foreach_out_edge(block, edge) {
323                 ir_node *node = get_edge_src_irn(edge);
324                 ir_node *copy_node;
325                 ir_mode *mode;
326
327                 if (is_Block(node)) {
328                         /* Block->Block edge, should be the MacroBlock edge */
329                         assert(get_Block_MacroBlock(node) == block && "Block->Block edge found");
330                         continue;
331                 }
332
333                 mode = get_irn_mode(node);
334                 if (mode == mode_X || is_Cond(node))
335                         continue;
336 #ifdef AVOID_PHIB
337                 if (mode == mode_b)
338                         continue;
339 #endif
340
341                 DB((dbg, LEVEL_2, ">> Fixing users of %+F\n", node));
342
343                 copy_node = get_irn_link(node);
344                 construct_ssa(block, node, copy_block, copy_node);
345         }
346 }
347
348 /**
349  * returns whether the cmp evaluates to true or false, or can't be evaluated!
350  * 1: true, 0: false, -1: can't evaluate
351  *
352  * @param pnc       the compare mode of the Compare
353  * @param tv_left   the left tarval
354  * @param tv_right  the right tarval
355  */
356 static int eval_cmp_tv(pn_Cmp pnc, tarval *tv_left, tarval *tv_right) {
357         pn_Cmp cmp_result = tarval_cmp(tv_left, tv_right);
358
359         /* does the compare evaluate to true? */
360         if (cmp_result == pn_Cmp_False)
361                 return -1;
362         if ((cmp_result & pnc) != cmp_result)
363                 return 0;
364
365         return 1;
366 }
367
368 /**
369  * returns whether the cmp evaluates to true or false, or can't be evaluated!
370  * 1: true, 0: false, -1: can't evaluate
371  *
372  * @param env      the environment
373  * @param cand     the candidate node, either a Const or a Confirm
374  */
375 static int eval_cmp(condeval_env_t *env, ir_node *cand) {
376         if (is_Const(cand)) {
377                 tarval *tv_cand   = get_Const_tarval(cand);
378                 tarval *tv_cmp    = get_Const_tarval(env->cnst);
379
380                 return eval_cmp_tv(env->pnc, tv_cand, tv_cmp);
381         } else { /* a Confirm */
382                 tarval *res = computed_value_Cmp_Confirm(env->cmp, cand, env->cnst, env->pnc);
383
384                 if (res == tarval_bad)
385                         return -1;
386                 return res == tarval_b_true;
387         }
388 }
389
390 /**
391  * Check for Const or Confirm with Const.
392  */
393 static int is_Const_or_Confirm(const ir_node *node) {
394         if (is_Confirm(node))
395                 node = get_Confirm_bound(node);
396         return is_Const(node);
397 }
398
399 /**
400  * get the tarval of a Const or Confirm with
401  */
402 static tarval *get_Const_or_Confirm_tarval(const ir_node *node) {
403         if (is_Confirm(node)) {
404                 if (get_Confirm_bound(node))
405                         node = get_Confirm_bound(node);
406         }
407         return get_Const_tarval(node);
408 }
409
410 static ir_node *find_const_or_confirm(condeval_env_t *env, ir_node *jump, ir_node *value)
411 {
412         ir_node *block = get_nodes_block(jump);
413
414         if (irn_visited_else_mark(value))
415                 return NULL;
416
417         if (is_Const_or_Confirm(value)) {
418                 if (eval_cmp(env, value) <= 0) {
419                         return NULL;
420                 }
421
422                 DB((
423                         dbg, LEVEL_1,
424                         "> Found condition evaluation candidate %+F->%+F\n",
425                         env->true_block, block
426                 ));
427
428                 /* adjust true_block to point directly towards our jump */
429                 add_pred(env->true_block, jump);
430
431                 split_critical_edge(env->true_block, 0);
432
433                 /* we need a bigger visited nr when going back */
434                 env->visited_nr++;
435
436                 return block;
437         }
438
439         if(is_Phi(value)) {
440                 int i, arity;
441
442                 /* the Phi has to be in the same Block as the Jmp */
443                 if(get_nodes_block(value) != block) {
444                         return NULL;
445                 }
446
447                 arity = get_irn_arity(value);
448                 for(i = 0; i < arity; ++i) {
449                         ir_node *copy_block;
450                         ir_node *phi_pred = get_Phi_pred(value, i);
451                         ir_node *cfgpred  = get_Block_cfgpred(block, i);
452
453                         copy_block = find_const_or_confirm(env, cfgpred, phi_pred);
454                         if(copy_block == NULL)
455                                 continue;
456
457                         /* copy duplicated nodes in copy_block and fix SSA */
458                         copy_and_fix(env, block, copy_block, i);
459
460                         if(copy_block == get_nodes_block(cfgpred)) {
461                                 env->cnst_pred = block;
462                                 env->cnst_pos  = i;
463                         }
464
465                         /* return now as we can't process more possibilities in 1 run */
466                         return copy_block;
467                 }
468         }
469
470         return NULL;
471 }
472
473 static ir_node *find_candidate(condeval_env_t *env, ir_node *jump,
474                                ir_node *value)
475 {
476         ir_node *block = get_nodes_block(jump);
477
478         if (irn_visited_else_mark(value)) {
479                 return NULL;
480         }
481
482         if (is_Const_or_Confirm(value)) {
483                 tarval *tv = get_Const_or_Confirm_tarval(value);
484
485                 if (tv != env->tv)
486                         return NULL;
487
488                 DB((
489                         dbg, LEVEL_1,
490                         "> Found condition evaluation candidate %+F->%+F\n",
491                         env->true_block, block
492                 ));
493
494                 /* adjust true_block to point directly towards our jump */
495                 add_pred(env->true_block, jump);
496
497                 split_critical_edge(env->true_block, 0);
498
499                 /* we need a bigger visited nr when going back */
500                 env->visited_nr++;
501
502                 return block;
503         }
504         if(is_Phi(value)) {
505                 int i, arity;
506
507                 /* the Phi has to be in the same Block as the Jmp */
508                 if(get_nodes_block(value) != block)
509                         return NULL;
510
511                 arity = get_irn_arity(value);
512                 for(i = 0; i < arity; ++i) {
513                         ir_node *copy_block;
514                         ir_node *phi_pred = get_Phi_pred(value, i);
515                         ir_node *cfgpred  = get_Block_cfgpred(block, i);
516
517                         copy_block = find_candidate(env, cfgpred, phi_pred);
518                         if(copy_block == NULL)
519                                 continue;
520
521                         /* copy duplicated nodes in copy_block and fix SSA */
522                         copy_and_fix(env, block, copy_block, i);
523
524                         if(copy_block == get_nodes_block(cfgpred)) {
525                                 env->cnst_pred = block;
526                                 env->cnst_pos  = i;
527                         }
528
529                         /* return now as we can't process more possibilities in 1 run */
530                         return copy_block;
531                 }
532         }
533         if(is_Proj(value)) {
534                 ir_node *left;
535                 ir_node *right;
536                 int      pnc;
537                 ir_node *cmp = get_Proj_pred(value);
538                 if(!is_Cmp(cmp))
539                         return NULL;
540
541                 left  = get_Cmp_left(cmp);
542                 right = get_Cmp_right(cmp);
543                 pnc   = get_Proj_proj(value);
544
545                 /* we assume that the constant is on the right side, swap left/right
546                  * if needed */
547                 if(is_Const(left)) {
548                         ir_node *t = left;
549                         left       = right;
550                         right      = t;
551
552                         pnc        = get_inversed_pnc(pnc);
553                 }
554
555                 if(!is_Const(right))
556                         return 0;
557
558                 if(get_nodes_block(left) != block) {
559                         return 0;
560                 }
561
562                 /* negate condition when we're looking for the false block */
563                 if(env->tv == tarval_b_false) {
564                         pnc = get_negated_pnc(pnc, get_irn_mode(right));
565                 }
566
567                 /* (recursively) look if a pred of a Phi is a constant or a Confirm */
568                 env->cmp  = cmp;
569                 env->pnc  = pnc;
570                 env->cnst = right;
571
572                 return find_const_or_confirm(env, jump, left);
573         }
574
575         return NULL;
576 }
577
578 /**
579  * Block-walker: searches for the following construct
580  *
581  *  Const or Phi with constants
582  *           |
583  *          Cmp
584  *           |
585  *         Cond
586  *          /
587  *       ProjX
588  *        /
589  *     Block
590  */
591 static void cond_eval(ir_node* block, void* data)
592 {
593         condeval_env_t env;
594         int *changed = data;
595         ir_node *selector;
596         ir_node *projx;
597         ir_node *cond;
598         ir_node *copy_block;
599         int      selector_evaluated;
600         const ir_edge_t *edge, *next;
601         ir_node* bad;
602         size_t   cnst_pos;
603
604         if(get_Block_n_cfgpreds(block) != 1)
605                 return;
606
607         projx = get_Block_cfgpred(block, 0);
608         if (!is_Proj(projx))
609                 return;
610         assert(get_irn_mode(projx) == mode_X);
611
612         cond = get_Proj_pred(projx);
613         if (!is_Cond(cond))
614                 return;
615
616         selector = get_Cond_selector(cond);
617         /* TODO handle switch Conds */
618         if (get_irn_mode(selector) != mode_b)
619                 return;
620
621         /* handle cases that can be immediately evaluated */
622         selector_evaluated = -1;
623         if(is_Proj(selector)) {
624                 ir_node *cmp = get_Proj_pred(selector);
625                 if(is_Cmp(cmp)) {
626                         ir_node *left  = get_Cmp_left(cmp);
627                         ir_node *right = get_Cmp_right(cmp);
628                         if(is_Const(left) && is_Const(right)) {
629                                 int     pnc      = get_Proj_proj(selector);
630                                 tarval *tv_left  = get_Const_tarval(left);
631                                 tarval *tv_right = get_Const_tarval(right);
632
633                                 selector_evaluated = eval_cmp_tv(pnc, tv_left, tv_right);
634                                 if(selector_evaluated < 0)
635                                         return;
636                         }
637                 }
638         } else if (is_Const_or_Confirm(selector)) {
639                 tarval *tv = get_Const_or_Confirm_tarval(selector);
640                 if(tv == tarval_b_true) {
641                         selector_evaluated = 1;
642                 } else {
643                         assert(tv == tarval_b_false);
644                         selector_evaluated = 0;
645                 }
646         }
647
648         env.cnst_pred = NULL;
649         if (get_Proj_proj(projx) == pn_Cond_false) {
650                 env.tv = tarval_b_false;
651                 if(selector_evaluated >= 0)
652                         selector_evaluated = !selector_evaluated;
653         } else {
654                 env.tv = tarval_b_true;
655         }
656
657         if(selector_evaluated == 0) {
658                 bad = new_Bad();
659                 exchange(projx, bad);
660                 *changed = 1;
661                 return;
662         } else if(selector_evaluated == 1) {
663                 dbg_info *dbgi = get_irn_dbg_info(selector);
664                 ir_node  *jmp  = new_rd_Jmp(dbgi, current_ir_graph, get_nodes_block(projx));
665                 exchange(projx, jmp);
666                 *changed = 1;
667                 return;
668         }
669
670         /* (recursively) look if a pred of a Phi is a constant or a Confirm */
671         env.true_block = block;
672         inc_irg_visited(current_ir_graph);
673         env.visited_nr = get_irg_visited(current_ir_graph);
674
675         copy_block = find_candidate(&env, projx, selector);
676         if (copy_block == NULL)
677                 return;
678
679         /* we have to remove the edge towards the pred as the pred now
680          * jumps into the true_block. We also have to shorten Phis
681          * in our block because of this */
682         bad      = new_Bad();
683         cnst_pos = env.cnst_pos;
684
685         /* shorten Phis */
686         foreach_out_edge_safe(env.cnst_pred, edge, next) {
687                 ir_node *node = get_edge_src_irn(edge);
688
689                 if(is_Phi(node))
690                         set_Phi_pred(node, cnst_pos, bad);
691         }
692
693         set_Block_cfgpred(env.cnst_pred, cnst_pos, bad);
694
695         /* the graph is changed now */
696         *changed = 1;
697 }
698
699 void opt_cond_eval(ir_graph* irg)
700 {
701         int changed, rerun;
702
703         FIRM_DBG_REGISTER(dbg, "firm.opt.condeval");
704
705         DB((dbg, LEVEL_1, "===> Performing condition evaluation on %+F\n", irg));
706
707         remove_critical_cf_edges(irg);
708         normalize_proj_nodes(irg);
709
710         edges_assure(irg);
711         ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED);
712
713         changed = 0;
714         do {
715                 rerun = 0;
716                 irg_block_walk_graph(irg, cond_eval, NULL, &rerun);
717                 changed |= rerun;
718         } while (rerun);
719
720         ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED);
721
722         if (changed) {
723                 /* control flow changed, some blocks may become dead */
724                 set_irg_outs_inconsistent(irg);
725                 set_irg_doms_inconsistent(irg);
726                 set_irg_extblk_inconsistent(irg);
727                 set_irg_loopinfo_inconsistent(irg);
728
729                 /* Dead code might be created. Optimize it away as it is dangerous
730                  * to call optimize_df() an dead code. */
731                 optimize_cf(irg);
732         }
733 }