Remove the first if-conversion implementation.
[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                                         /* only exchange if we have a Psi */
345                                         if (arity == 2) {
346                                                 exchange(phi, psi);
347                                         } else {
348                                                 rewire(phi, i, j, psi);
349                                         }
350
351                                         phi = get_irn_link(phi);
352                                 } while (phi != NULL);
353
354                                 exchange(get_nodes_block(get_irn_n(block, i)), psi_block);
355                                 exchange(get_nodes_block(get_irn_n(block, j)), psi_block);
356
357                                 if (arity == 2) {
358 #if 1
359                                         DB((dbg, LEVEL_1,  "Welding block %+F and %+F\n", block, psi_block));
360                                         /* copy the block-info from the Psi-block to the block before merging */
361                                         get_block_blockinfo(psi_block)->has_pinned |= get_block_blockinfo(block)->has_pinned;
362                                         set_irn_link(block, get_irn_link(psi_block));
363
364                                         set_irn_in(block, get_irn_arity(psi_block), get_irn_in(psi_block) + 1);
365                                         exchange_cdep(psi_block, block);
366                                         exchange(psi_block, block);
367 #else
368                                         DB((dbg, LEVEL_1,  "Welding block %+F to %+F\n", block, psi_block));
369                                         get_block_blockinfo(psi_block)->has_pinned |=   get_block_blockinfo(block)->has_pinned;
370                                         exchange(block, psi_block);
371 #endif
372                                         return;
373                                 } else {
374                                         rewire(block, i, j, new_r_Jmp(current_ir_graph, psi_block));
375                                         goto restart;
376                                 }
377                         }
378                 }
379         }
380 }
381
382 /**
383  * Block walker: add additional data
384  */
385 static void init_block_link(ir_node *block, void *env)
386 {
387         struct obstack *obst = env;
388         block_info *bi = obstack_alloc(obst, sizeof(*bi));
389
390         bi->phi = NULL;
391         bi->has_pinned = 0;
392         set_irn_link(block, bi);
393 }
394
395
396 /**
397  * Daisy-chain all phis in a block
398  * If a non-movable node is encountered set the has_pinned flag
399  */
400 static void collect_phis(ir_node *node, void *env)
401 {
402         if (is_Phi(node)) {
403                 ir_node *block = get_nodes_block(node);
404                 block_info *bi = get_block_blockinfo(block);
405
406                 set_irn_link(node, bi->phi);
407                 bi->phi = node;
408         }
409         else {
410                 if (is_no_Block(node) && get_irn_pinned(node) == op_pin_state_pinned) {
411                         /*
412                          * Ignore control flow nodes, these will be removed.
413                          * This ignores Raise. That is surely bad. FIXME.
414                          */
415                         if (! is_cfop(node)) {
416                                 ir_node *block = get_nodes_block(node);
417                                 block_info *bi = get_block_blockinfo(block);
418
419                                 DB((dbg, LEVEL_2, "Node %+F in block %+F is unmovable\n", node, block));
420                                 bi->has_pinned = 1;
421                         }
422                 }
423         }
424 }
425
426
427 /*
428  * Transform multiple cascaded Psis into one Psi
429  */
430 static ir_node* fold_psi(ir_node* psi)
431 {
432         int arity = get_Psi_n_conds(psi);
433         int new_arity = 0;
434         int i;
435         ir_node* n;
436         ir_node** conds;
437         ir_node** vals;
438         int j;
439         int k;
440         int a;
441         ir_node* new_psi;
442
443         for (i = 0; i < arity; ++i) {
444                 n = get_Psi_val(psi, i);
445                 if (get_irn_op(n) == op_Psi) {
446                         new_arity += get_Psi_n_conds(n) + 1;
447                 } else {
448                         ++new_arity;
449                 }
450         }
451         n = get_Psi_default(psi);
452         if (get_irn_op(n) == op_Psi) {
453                 new_arity += get_Psi_n_conds(n);
454         }
455
456         if (arity == new_arity) return psi; // no attached Psis found
457         DB((dbg, LEVEL_1, "Folding %+F from %d to %d conds\n", psi, arity, new_arity));
458
459         NEW_ARR_A(ir_node *, conds, new_arity);
460         NEW_ARR_A(ir_node *, vals, new_arity + 1);
461         j = 0;
462         for (i = 0; i < arity; ++i) {
463                 ir_node* c = get_Psi_cond(psi, i);
464
465                 n = get_Psi_val(psi, i);
466                 if (get_irn_op(n) == op_Psi) {
467                         a = get_Psi_n_conds(n);
468                         for (k = 0; k < a; ++k) {
469                                 conds[j] = new_r_And(
470                                         current_ir_graph, get_nodes_block(psi),
471                                         c, get_Psi_cond(n, k), mode_b
472                                 );
473                                 vals[j] = get_Psi_val(n, k);
474                                 ++j;
475                         }
476                         conds[j] = c;
477                         vals[j] = get_Psi_default(n);
478                 } else {
479                         conds[j] = c;
480                         vals[j] = n;
481                 }
482                 ++j;
483         }
484         n = get_Psi_default(psi);
485         if (get_irn_op(n) == op_Psi) {
486                 a = get_Psi_n_conds(n);
487                 for (k = 0; k < a; ++k) {
488                         conds[j] = get_Psi_cond(n, k);
489                         vals[j] = get_Psi_val(n, k);
490                         ++j;
491                 }
492                 vals[j] = get_Psi_default(n);
493         } else {
494                 vals[j] = n;
495         }
496         assert(j == new_arity);
497         new_psi = new_r_Psi(
498                 current_ir_graph, get_nodes_block(psi),
499                 new_arity, conds, vals, get_irn_mode(psi)
500         );
501         DB((dbg, LEVEL_1, "Folded %+F into new %+F\n", psi, new_psi));
502         exchange(psi, new_psi);
503         return new_psi;
504 }
505
506
507 /*
508  * Merge consecutive psi inputs if the data inputs are the same
509  */
510 static ir_node* meld_psi(ir_node* psi)
511 {
512         int arity = get_Psi_n_conds(psi);
513         int new_arity;
514         ir_node** conds;
515         ir_node** vals;
516         ir_node* cond;
517         ir_node* val;
518         int i;
519         int j;
520         ir_node* new_psi;
521
522         new_arity = 1;
523         val = get_Psi_val(psi, 0);
524         DB((dbg, LEVEL_1, "Pred  0 of %+F is %+F\n", psi, val));
525         for (i = 1; i < arity; ++i) {
526                 ir_node* v = get_Psi_val(psi, i);
527                 DB((dbg, LEVEL_1, "Pred %2d of %+F is %+F\n", i, psi, v));
528                 if (val != v) {
529                         val = v;
530                         ++new_arity;
531                 }
532         }
533         DB((dbg, LEVEL_1, "Default of %+F is %+F\n", psi, get_Psi_default(psi)));
534         if (val == get_Psi_default(psi)) --new_arity;
535
536         DB((dbg, LEVEL_1, "Melding Psi %+F from %d conds to %d\n", psi, arity, new_arity));
537
538         if (new_arity == arity) return psi;
539
540         /* If all data inputs of the Psi are equal, exchange the Psi with that value */
541         if (new_arity == 0) {
542                 exchange(psi, val);
543                 return val;
544         }
545
546         NEW_ARR_A(ir_node *, conds, new_arity);
547         NEW_ARR_A(ir_node *, vals, new_arity + 1);
548         cond = get_Psi_cond(psi, 0);
549         val = get_Psi_val(psi, 0);
550         j = 0;
551         for (i = 1; i < arity; ++i) {
552                 ir_node* v = get_Psi_val(psi, i);
553
554                 if (v == val) {
555                         cond = new_r_Or(
556                                 current_ir_graph, get_nodes_block(psi),
557                                 cond, get_Psi_cond(psi, i), mode_b
558                         );
559                 } else {
560                         conds[j] = cond;
561                         vals[j] = val;
562                         ++j;
563                         val = v;
564                 }
565         }
566         if (val != get_Psi_default(psi)) {
567                 conds[j] = cond;
568                 vals[j] = val;
569                 ++j;
570         }
571         vals[j] = get_Psi_default(psi);
572         assert(j == new_arity);
573         new_psi = new_r_Psi(
574                 current_ir_graph, get_nodes_block(psi),
575                 new_arity, conds, vals, get_irn_mode(psi)
576         );
577         DB((dbg, LEVEL_1, "Molded %+F into %+F\n", psi, new_psi));
578         exchange(psi, new_psi);
579         return new_psi;
580 }
581
582
583 /**
584  * Split a Psi with multiple conditions into multiple Psis with one condtition
585  * each
586  */
587 static ir_node* split_psi(ir_node* psi)
588 {
589         int arity = get_Psi_n_conds(psi);
590         ir_mode* mode;
591         ir_node* block;
592         ir_node* rval;
593         int i;
594
595         if (arity == 1) return psi;
596
597         mode = get_irn_mode(psi);
598         block = get_nodes_block(psi);
599         rval = get_Psi_default(psi);
600         for (i = arity - 1; i >= 0; --i) {
601                 ir_node* conds[1];
602                 ir_node* vals[2];
603
604                 conds[0] = get_Psi_cond(psi, i);
605                 vals[0] = get_Psi_val(psi, i);
606                 vals[1] = rval;
607                 rval = new_r_Psi(
608                         current_ir_graph, block, 1, conds, vals, mode
609                 );
610         }
611         exchange(psi, rval);
612         return rval;
613 }
614
615
616 static void optimise_psis(ir_node* node, void* env)
617 {
618         if (get_irn_op(node) != op_Psi) return;
619 #if 1
620         node = fold_psi(node);
621 #endif
622 #if 1
623         node = meld_psi(node);
624 #endif
625 #if 1
626         node = split_psi(node);
627 #endif
628 }
629
630
631 void opt_if_conv(ir_graph *irg, const opt_if_conv_info_t *params)
632 {
633         struct obstack obst;
634         opt_if_conv_info_t p;
635
636         if (! get_opt_if_conversion())
637                 return;
638
639         /* get the parameters */
640         if (params)
641                 memcpy(&p, params, sizeof(p));
642         else
643                 memcpy(&p, &default_info, sizeof(p));
644
645         FIRM_DBG_REGISTER(dbg, "firm.opt.ifconv");
646
647         DB((dbg, LEVEL_1, "Running if-conversion on %+F\n", irg));
648
649         normalize_one_return(irg);
650         remove_critical_cf_edges(irg);
651
652         compute_cdep(irg);
653         assure_doms(irg);
654
655         obstack_init(&obst);
656         irg_block_walk_graph(irg, init_block_link, NULL, &obst);
657         irg_walk_graph(irg, collect_phis, NULL, NULL);
658         irg_block_walk_graph(irg, NULL, if_conv_walker, &p);
659
660         local_optimize_graph(irg);
661
662         irg_walk_graph(irg, NULL, optimise_psis, NULL);
663
664         obstack_free(&obst, NULL);
665
666         free_dom(irg);
667         free_cdep(irg);
668 }