- Remove incorrect comment
[libfirm] / ir / opt / ifconv.c
1 /*
2  * Copyright (C) 1995-2007 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    ir/opt/ifconv.c
22  * @brief   If conversion
23  * @author  Christoph Mallon
24  * @version $Id$
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include "obst.h"
34 #include "irnode_t.h"
35 #include "cdep.h"
36 #include "ircons.h"
37 #include "ifconv.h"
38 #include "irdom.h"
39 #include "irgmod.h"
40 #include "irgopt.h"
41 #include "irgwalk.h"
42 #include "irtools.h"
43 #include "return.h"
44 #include "array.h"
45 #include "xmalloc.h"
46
47 // debug
48 #include "irdump.h"
49 #include "debug.h"
50
51 DEBUG_ONLY(firm_dbg_module_t *dbg);
52
53 /** allow every Psi to be created. */
54 static int default_allow_ifconv(ir_node *sel, ir_node* phi_list, int i, int j)
55 {
56         return 1;
57 }
58
59 /**
60  * Default options.
61  */
62 static const opt_if_conv_info_t default_info = {
63         0,    /* doesn't matter for Psi */
64         default_allow_ifconv
65 };
66
67 /**
68  * Additional block info.
69  */
70 typedef struct block_info {
71         ir_node *phi;   /**< head of the Phi list */
72         int has_pinned; /**< set if the block contains instructions that cannot be moved */
73 } block_info;
74
75 #define get_block_blockinfo(block) ((block_info *)get_irn_link(block))
76
77 /**
78  * Returns non-zero if a Block can be emptied.
79  */
80 static int can_empty_block(ir_node *block)
81 {
82         return !get_block_blockinfo(block)->has_pinned;
83 }
84
85
86 static ir_node* walk_to_projx(ir_node* start, const ir_node* dependency)
87 {
88         int arity;
89         int i;
90
91         /* No need to find the conditional block if this block cannot be emptied and
92          * therefore not moved
93          */
94         if (!can_empty_block(start)) return NULL;
95
96         arity = get_irn_arity(start);
97         for (i = 0; i < arity; ++i) {
98                 ir_node* pred = get_irn_n(start, i);
99                 ir_node* pred_block = get_nodes_block(pred);
100
101                 if (pred_block == dependency) {
102                         if (is_Proj(pred)) {
103                                 assert(get_irn_mode(pred) == mode_X);
104                                 return pred;
105                         }
106                         return NULL;
107                 }
108
109                 if (is_Proj(pred)) {
110                         assert(get_irn_mode(pred) == mode_X);
111                         return NULL;
112                 }
113
114                 if (is_cdep_on(pred_block, dependency)) {
115                         return walk_to_projx(pred_block, dependency);
116                 }
117         }
118         return NULL;
119 }
120
121
122 /**
123  * Copies the DAG starting at node to the ith predecessor block of src_block
124  * -if the node isn't in the src_block, this is a nop and the node is returned
125  * -if the node is a phi in the src_block, the ith predecessor of the phi is
126  *   returned
127  * otherwise returns the copy of the passed node
128  */
129 static ir_node* copy_to(ir_node* node, ir_node* src_block, int i)
130 {
131         ir_node* dst_block;
132         ir_node* copy;
133         int arity;
134         int j;
135
136         if (get_nodes_block(node) != src_block) return node;
137         if (get_irn_op(node) == op_Phi) return get_irn_n(node, i);
138
139         copy = exact_copy(node);
140         dst_block = get_nodes_block(get_irn_n(src_block, i));
141         set_nodes_block(copy, dst_block);
142
143         DB((dbg, LEVEL_1, "Copying node %+F to block %+F, copy is %+F\n",
144                 node, dst_block, copy));
145
146         arity = get_irn_arity(node);
147         for (j = 0; j < arity; ++j) {
148                 set_irn_n(copy, j, copy_to(get_irn_n(node, j), src_block, i));
149                 DB((dbg, LEVEL_2, "-- pred %d is %+F\n", j, get_irn_n(copy, j)));
150         }
151         return copy;
152 }
153
154
155 /**
156  * Remove predecessors i and j from node and add predecessor new_pred
157  */
158 static void rewire(ir_node* node, int i, int j, ir_node* new_pred)
159 {
160         int arity = get_irn_arity(node);
161         ir_node **ins;
162         int k;
163         int l;
164
165         NEW_ARR_A(ir_node *, ins, arity - 1);
166
167         l = 0;
168         for (k = 0; k < i; ++k) ins[l++] = get_irn_n(node, k);
169         for (++k; k < j; ++k) ins[l++] = get_irn_n(node, k);
170         for (++k; k < arity; ++k) ins[l++] = get_irn_n(node, k);
171         ins[l++] = new_pred;
172         assert(l == arity - 1);
173         set_irn_in(node, l, ins);
174 }
175
176
177 /**
178  * Remove the jth predecessors from the ith predecessor of block and add it to block
179  */
180 static void split_block(ir_node* block, int i, int j)
181 {
182         ir_node* pred_block = get_nodes_block(get_irn_n(block, i));
183         int arity = get_irn_arity(block);
184         int new_pred_arity;
185         ir_node* phi;
186         ir_node **ins;
187         ir_node **pred_ins;
188         int k;
189
190         DB((dbg, LEVEL_1, "Splitting predecessor %d of predecessor %d of %+F\n", j, i, block));
191
192         NEW_ARR_A(ir_node*, ins, arity + 1);
193
194         for (phi = get_block_blockinfo(block)->phi; phi != NULL; phi = get_irn_link(phi)) {
195                 ir_node* copy = copy_to(get_irn_n(phi, i), pred_block, j);
196
197                 for (k = 0; k < i; ++k) ins[k] = get_irn_n(phi, k);
198                 ins[k++] = copy;
199                 for (; k < arity; ++k) ins[k] = get_irn_n(phi, k);
200                 ins[k] = get_irn_n(phi, i);
201                 assert(k == arity);
202                 set_irn_in(phi, arity + 1, ins);
203         }
204
205         for (k = 0; k < i; ++k) ins[k] = get_irn_n(block, k);
206         ins[k++] = get_irn_n(pred_block, j);
207         for (; k < arity; ++k) ins[k] = get_irn_n(block, k);
208         ins[k] = get_irn_n(block, i);
209         assert(k == arity);
210         set_irn_in(block, arity + 1, ins);
211
212         new_pred_arity = get_irn_arity(pred_block) - 1;
213         NEW_ARR_A(ir_node*, pred_ins, new_pred_arity);
214
215         for (phi = get_block_blockinfo(pred_block)->phi; phi != NULL; phi = get_irn_link(phi)) {
216                 for (k = 0; k < j; ++k) pred_ins[k] = get_irn_n(phi, k);
217                 for (; k < new_pred_arity; ++k) pred_ins[k] = get_irn_n(phi, k + 1);
218                 assert(k == new_pred_arity);
219                 if (new_pred_arity > 1) {
220                         set_irn_in(phi, new_pred_arity, pred_ins);
221                 } else {
222                         exchange(phi, pred_ins[0]);
223                 }
224         }
225
226         for (k = 0; k < j; ++k) pred_ins[k] = get_irn_n(pred_block, k);
227         for (; k < new_pred_arity; ++k) pred_ins[k] = get_irn_n(pred_block, k + 1);
228         assert(k == new_pred_arity);
229         if (new_pred_arity > 1) {
230                 set_irn_in(pred_block, new_pred_arity, pred_ins);
231         } else {
232                 exchange(pred_block, get_nodes_block(pred_ins[0]));
233         }
234 }
235
236
237 static void prepare_path(ir_node* block, int i, const ir_node* dependency)
238 {
239         ir_node* pred = get_nodes_block(get_irn_n(block, i));
240         int pred_arity;
241         int j;
242
243         DB((dbg, LEVEL_1, "Preparing predecessor %d of %+F\n", i, block));
244
245         pred_arity = get_irn_arity(pred);
246         for (j = 0; j < pred_arity; ++j) {
247                 ir_node* pred_pred = get_nodes_block(get_irn_n(pred, j));
248
249                 if (is_cdep_on(pred_pred, dependency)) {
250                         prepare_path(pred, j, dependency);
251                         split_block(block, i, j);
252                         break;
253                 }
254         }
255 }
256
257
258 static void if_conv_walker(ir_node* block, void* env)
259 {
260         int arity;
261         int i;
262         opt_if_conv_info_t *opt_info = env;
263
264         /* Bail out, if there are no Phis at all */
265         if (get_block_blockinfo(block)->phi == NULL) return;
266
267 restart:
268         arity = get_irn_arity(block);
269         for (i = 0; i < arity; ++i) {
270                 ir_node* pred;
271                 cdep* cdep;
272
273                 pred = get_nodes_block(get_irn_n(block, i));
274                 for (cdep = find_cdep(pred); cdep != NULL; cdep = cdep->next) {
275                         const ir_node* dependency = cdep->node;
276                         ir_node* projx0 = walk_to_projx(pred, dependency);
277                         ir_node* cond;
278                         int j;
279
280                         if (projx0 == NULL) continue;
281
282                         cond = get_Proj_pred(projx0);
283                         if (get_irn_op(cond) != op_Cond) continue;
284
285                         /* We only handle boolean decisions, no switches */
286                         if (get_irn_mode(get_Cond_selector(cond)) != mode_b) continue;
287
288                         for (j = i + 1; j < arity; ++j) {
289                                 ir_node* projx1;
290                                 ir_node* conds[1];
291                                 ir_node* vals[2];
292                                 ir_node* psi = NULL;
293                                 ir_node* psi_block;
294                                 ir_node* phi;
295
296                                 pred = get_nodes_block(get_irn_n(block, j));
297
298                                 if (!is_cdep_on(pred, dependency)) continue;
299
300                                 projx1 = walk_to_projx(pred, dependency);
301
302                                 if (projx1 == NULL) continue;
303
304                                 phi = get_block_blockinfo(block)->phi;
305                                 if (!opt_info->allow_ifconv(get_Cond_selector(cond), phi, i, j)) continue;
306
307                                 DB((dbg, LEVEL_1, "Found Cond %+F with proj %+F and %+F\n",
308                                         cond, projx0, projx1
309                                 ));
310
311                                 prepare_path(block, i, dependency);
312                                 prepare_path(block, j, dependency);
313                                 arity = get_irn_arity(block);
314
315                                 conds[0] = get_Cond_selector(cond);
316
317                                 psi_block = get_nodes_block(cond);
318                                 do {
319                                         ir_node* val_i = get_irn_n(phi, i);
320                                         ir_node* val_j = get_irn_n(phi, j);
321
322                                         if (val_i == val_j) {
323                                                 psi = val_i;
324                                                 DB((dbg, LEVEL_2,  "Generating no psi, because both values are equal\n"));
325                                         } else {
326                                                 /* Something is very fishy if two predecessors of a PhiM point into
327                                                  * one block, but not at the same memory node
328                                                  */
329                                                 assert(get_irn_mode(phi) != mode_M);
330                                                 if (get_Proj_proj(projx0) == pn_Cond_true) {
331                                                         vals[0] = val_i;
332                                                         vals[1] = val_j;
333                                                 } else {
334                                                         vals[0] = val_j;
335                                                         vals[1] = val_i;
336                                                 }
337
338                                                 psi = new_r_Psi(
339                                                         current_ir_graph, psi_block, 1, conds, vals, get_irn_mode(phi)
340                                                 );
341                                                 DB((dbg, LEVEL_2, "Generating %+F for %+F\n", psi, phi));
342                                         }
343
344                                         if (arity == 2) {
345                                                 exchange(phi, psi);
346                                         } else {
347                                                 rewire(phi, i, j, psi);
348                                         }
349
350                                         phi = get_irn_link(phi);
351                                 } while (phi != NULL);
352
353                                 exchange(get_nodes_block(get_irn_n(block, i)), psi_block);
354                                 exchange(get_nodes_block(get_irn_n(block, j)), psi_block);
355
356                                 if (arity == 2) {
357 #if 1
358                                         DB((dbg, LEVEL_1,  "Welding block %+F and %+F\n", block, psi_block));
359                                         /* copy the block-info from the Psi-block to the block before merging */
360                                         get_block_blockinfo(psi_block)->has_pinned |= get_block_blockinfo(block)->has_pinned;
361                                         set_irn_link(block, get_irn_link(psi_block));
362
363                                         set_irn_in(block, get_irn_arity(psi_block), get_irn_in(psi_block) + 1);
364                                         exchange_cdep(psi_block, block);
365                                         exchange(psi_block, block);
366 #else
367                                         DB((dbg, LEVEL_1,  "Welding block %+F to %+F\n", block, psi_block));
368                                         get_block_blockinfo(psi_block)->has_pinned |=   get_block_blockinfo(block)->has_pinned;
369                                         exchange(block, psi_block);
370 #endif
371                                         return;
372                                 } else {
373                                         rewire(block, i, j, new_r_Jmp(current_ir_graph, psi_block));
374                                         goto restart;
375                                 }
376                         }
377                 }
378         }
379 }
380
381 /**
382  * Block walker: add additional data
383  */
384 static void init_block_link(ir_node *block, void *env)
385 {
386         struct obstack *obst = env;
387         block_info *bi = obstack_alloc(obst, sizeof(*bi));
388
389         bi->phi = NULL;
390         bi->has_pinned = 0;
391         set_irn_link(block, bi);
392 }
393
394
395 /**
396  * Daisy-chain all phis in a block
397  * If a non-movable node is encountered set the has_pinned flag
398  */
399 static void collect_phis(ir_node *node, void *env)
400 {
401         if (is_Phi(node)) {
402                 ir_node *block = get_nodes_block(node);
403                 block_info *bi = get_block_blockinfo(block);
404
405                 set_irn_link(node, bi->phi);
406                 bi->phi = node;
407         }
408         else {
409                 if (is_no_Block(node) && get_irn_pinned(node) == op_pin_state_pinned) {
410                         /*
411                          * Ignore control flow nodes, these will be removed.
412                          * This ignores Raise. That is surely bad. FIXME.
413                          */
414                         if (! is_cfop(node)) {
415                                 ir_node *block = get_nodes_block(node);
416                                 block_info *bi = get_block_blockinfo(block);
417
418                                 DB((dbg, LEVEL_2, "Node %+F in block %+F is unmovable\n", node, block));
419                                 bi->has_pinned = 1;
420                         }
421                 }
422         }
423 }
424
425
426 /*
427  * Transform multiple cascaded Psis into one Psi
428  */
429 static ir_node* fold_psi(ir_node* psi)
430 {
431         int arity = get_Psi_n_conds(psi);
432         int new_arity = 0;
433         int i;
434         ir_node* n;
435         ir_node** conds;
436         ir_node** vals;
437         int j;
438         int k;
439         int a;
440         ir_node* new_psi;
441
442         for (i = 0; i < arity; ++i) {
443                 n = get_Psi_val(psi, i);
444                 if (get_irn_op(n) == op_Psi) {
445                         new_arity += get_Psi_n_conds(n) + 1;
446                 } else {
447                         ++new_arity;
448                 }
449         }
450         n = get_Psi_default(psi);
451         if (get_irn_op(n) == op_Psi) {
452                 new_arity += get_Psi_n_conds(n);
453         }
454
455         if (arity == new_arity) return psi; // no attached Psis found
456         DB((dbg, LEVEL_1, "Folding %+F from %d to %d conds\n", psi, arity, new_arity));
457
458         NEW_ARR_A(ir_node *, conds, new_arity);
459         NEW_ARR_A(ir_node *, vals, new_arity + 1);
460         j = 0;
461         for (i = 0; i < arity; ++i) {
462                 ir_node* c = get_Psi_cond(psi, i);
463
464                 n = get_Psi_val(psi, i);
465                 if (get_irn_op(n) == op_Psi) {
466                         a = get_Psi_n_conds(n);
467                         for (k = 0; k < a; ++k) {
468                                 conds[j] = new_r_And(
469                                         current_ir_graph, get_nodes_block(psi),
470                                         c, get_Psi_cond(n, k), mode_b
471                                 );
472                                 vals[j] = get_Psi_val(n, k);
473                                 ++j;
474                         }
475                         conds[j] = c;
476                         vals[j] = get_Psi_default(n);
477                 } else {
478                         conds[j] = c;
479                         vals[j] = n;
480                 }
481                 ++j;
482         }
483         n = get_Psi_default(psi);
484         if (get_irn_op(n) == op_Psi) {
485                 a = get_Psi_n_conds(n);
486                 for (k = 0; k < a; ++k) {
487                         conds[j] = get_Psi_cond(n, k);
488                         vals[j] = get_Psi_val(n, k);
489                         ++j;
490                 }
491                 vals[j] = get_Psi_default(n);
492         } else {
493                 vals[j] = n;
494         }
495         assert(j == new_arity);
496         new_psi = new_r_Psi(
497                 current_ir_graph, get_nodes_block(psi),
498                 new_arity, conds, vals, get_irn_mode(psi)
499         );
500         DB((dbg, LEVEL_1, "Folded %+F into new %+F\n", psi, new_psi));
501         exchange(psi, new_psi);
502         return new_psi;
503 }
504
505
506 /*
507  * Merge consecutive psi inputs if the data inputs are the same
508  */
509 static ir_node* meld_psi(ir_node* psi)
510 {
511         int arity = get_Psi_n_conds(psi);
512         int new_arity;
513         ir_node** conds;
514         ir_node** vals;
515         ir_node* cond;
516         ir_node* val;
517         int i;
518         int j;
519         ir_node* new_psi;
520
521         new_arity = 1;
522         val = get_Psi_val(psi, 0);
523         DB((dbg, LEVEL_1, "Pred  0 of %+F is %+F\n", psi, val));
524         for (i = 1; i < arity; ++i) {
525                 ir_node* v = get_Psi_val(psi, i);
526                 DB((dbg, LEVEL_1, "Pred %2d of %+F is %+F\n", i, psi, v));
527                 if (val != v) {
528                         val = v;
529                         ++new_arity;
530                 }
531         }
532         DB((dbg, LEVEL_1, "Default of %+F is %+F\n", psi, get_Psi_default(psi)));
533         if (val == get_Psi_default(psi)) --new_arity;
534
535         DB((dbg, LEVEL_1, "Melding Psi %+F from %d conds to %d\n", psi, arity, new_arity));
536
537         if (new_arity == arity) return psi;
538
539         /* If all data inputs of the Psi are equal, exchange the Psi with that value */
540         if (new_arity == 0) {
541                 exchange(psi, val);
542                 return val;
543         }
544
545         NEW_ARR_A(ir_node *, conds, new_arity);
546         NEW_ARR_A(ir_node *, vals, new_arity + 1);
547         cond = get_Psi_cond(psi, 0);
548         val = get_Psi_val(psi, 0);
549         j = 0;
550         for (i = 1; i < arity; ++i) {
551                 ir_node* v = get_Psi_val(psi, i);
552
553                 if (v == val) {
554                         cond = new_r_Or(
555                                 current_ir_graph, get_nodes_block(psi),
556                                 cond, get_Psi_cond(psi, i), mode_b
557                         );
558                 } else {
559                         conds[j] = cond;
560                         vals[j] = val;
561                         ++j;
562                         val = v;
563                 }
564         }
565         if (val != get_Psi_default(psi)) {
566                 conds[j] = cond;
567                 vals[j] = val;
568                 ++j;
569         }
570         vals[j] = get_Psi_default(psi);
571         assert(j == new_arity);
572         new_psi = new_r_Psi(
573                 current_ir_graph, get_nodes_block(psi),
574                 new_arity, conds, vals, get_irn_mode(psi)
575         );
576         DB((dbg, LEVEL_1, "Molded %+F into %+F\n", psi, new_psi));
577         exchange(psi, new_psi);
578         return new_psi;
579 }
580
581
582 /**
583  * Split a Psi with multiple conditions into multiple Psis with one condtition
584  * each
585  */
586 static ir_node* split_psi(ir_node* psi)
587 {
588         int arity = get_Psi_n_conds(psi);
589         ir_mode* mode;
590         ir_node* block;
591         ir_node* rval;
592         int i;
593
594         if (arity == 1) return psi;
595
596         mode = get_irn_mode(psi);
597         block = get_nodes_block(psi);
598         rval = get_Psi_default(psi);
599         for (i = arity - 1; i >= 0; --i) {
600                 ir_node* conds[1];
601                 ir_node* vals[2];
602
603                 conds[0] = get_Psi_cond(psi, i);
604                 vals[0] = get_Psi_val(psi, i);
605                 vals[1] = rval;
606                 rval = new_r_Psi(
607                         current_ir_graph, block, 1, conds, vals, mode
608                 );
609         }
610         exchange(psi, rval);
611         return rval;
612 }
613
614
615 static void optimise_psis(ir_node* node, void* env)
616 {
617         if (get_irn_op(node) != op_Psi) return;
618 #if 1
619         node = fold_psi(node);
620 #endif
621 #if 1
622         node = meld_psi(node);
623 #endif
624 #if 1
625         node = split_psi(node);
626 #endif
627 }
628
629
630 void opt_if_conv(ir_graph *irg, const opt_if_conv_info_t *params)
631 {
632         struct obstack obst;
633         opt_if_conv_info_t p;
634
635         if (! get_opt_if_conversion())
636                 return;
637
638         /* get the parameters */
639         p = (params != NULL ? *params : default_info);
640
641         FIRM_DBG_REGISTER(dbg, "firm.opt.ifconv");
642
643         DB((dbg, LEVEL_1, "Running if-conversion on %+F\n", irg));
644
645         normalize_one_return(irg);
646         remove_critical_cf_edges(irg);
647
648         compute_cdep(irg);
649         assure_doms(irg);
650
651         obstack_init(&obst);
652         irg_block_walk_graph(irg, init_block_link, NULL, &obst);
653         irg_walk_graph(irg, collect_phis, NULL, NULL);
654         irg_block_walk_graph(irg, NULL, if_conv_walker, &p);
655
656         local_optimize_graph(irg);
657
658         irg_walk_graph(irg, NULL, optimise_psis, NULL);
659
660         obstack_free(&obst, NULL);
661
662         free_dom(irg);
663         free_cdep(irg);
664 }