Beginning of implementation of partial condition evaluation
[libfirm] / ir / opt / condeval.c
1 #include <assert.h>
2 #include <alloca.h>
3 #include "array.h"
4 #include "debug.h"
5 #include "ircons.h"
6 #include "irgwalk.h"
7 #include "irnode.h"
8 #include "tv.h"
9
10 DEBUG_ONLY(static firm_dbg_module_t *dbg);
11
12 static void cond_eval(ir_node* block, void* env)
13 {
14         int n_block = get_Block_n_cfgpreds(block);
15         int i;
16
17         for (i = 0; i < n_block; i++) {
18                 ir_node* pred;
19                 ir_node* projx;
20                 ir_node* cond;
21                 ir_node* cmp;
22                 ir_node* left;
23                 ir_node* right;
24                 ir_node* cond_block;
25                 ir_node* phi;
26                 ir_node* cnst;
27                 pn_Cmp pnc;
28                 int n_phi;
29                 int j;
30
31                 pred = get_Block_cfgpred(block, i);
32                 if (!is_Proj(pred)) continue;
33                 projx = pred;
34
35                 pred = get_Proj_pred(projx);
36                 if (!is_Cond(pred)) continue;
37                 cond = pred;
38
39                 pred = get_Cond_selector(cond);
40                 assert(is_Proj(pred));
41                 // TODO handle switches
42                 if (get_irn_mode(pred) != mode_b) continue;
43                 pnc = get_Proj_proj(pred);
44
45                 cmp = get_Proj_pred(pred);
46                 assert(is_Cmp(cmp));
47
48                 left  = get_Cmp_left(cmp);
49                 right = get_Cmp_right(cmp);
50
51                 // TODO handle Const-Const and Phi-Phi
52                 if (is_Phi(left)) {
53                         if (!is_Const(right)) continue;
54                         phi  = left;
55                         cnst = right;
56                 } else if (is_Phi(right)) {
57                         if (!is_Const(left)) continue;
58                         phi  = right;
59                         cnst = left;
60                         pnc = get_inversed_pnc(pnc);
61                 } else {
62                         continue;
63                 }
64
65                 cond_block = get_nodes_block(cond);
66                 if (get_nodes_block(phi) != cond_block) continue;
67
68                 if (get_Proj_proj(projx) == 0) pnc = get_negated_pnc(pnc, get_irn_mode(cnst));
69
70                 n_phi = get_Phi_n_preds(phi);
71                 for (j = 0; j < n_phi; j++) {
72                         tarval* tv_phi;
73                         tarval* tv_cnst;
74                         ir_node** ins;
75                         int k;
76
77                         pred = get_Phi_pred(phi, j);
78                         // TODO handle Phi cascades
79                         if (!is_Const(pred)) continue;
80
81                         tv_phi  = get_Const_tarval(pred);
82                         tv_cnst = get_Const_tarval(cnst);
83
84                         switch (tarval_cmp(tv_phi, tv_cnst)) {
85                                 case pn_Cmp_Lt:
86                                         if (pnc != pn_Cmp_Lt &&
87                                                         pnc != pn_Cmp_Le &&
88                                                         pnc != pn_Cmp_Lg) {
89                                                 continue;
90                                         }
91                                         break;
92
93                                 case pn_Cmp_Eq:
94                                         if (pnc != pn_Cmp_Le &&
95                                                         pnc != pn_Cmp_Ge &&
96                                                         pnc != pn_Cmp_Eq) {
97                                                 continue;
98                                         }
99                                         break;
100
101                                 case pn_Cmp_Gt:
102                                         if (pnc != pn_Cmp_Gt &&
103                                                         pnc != pn_Cmp_Ge &&
104                                                         pnc != pn_Cmp_Lg) {
105                                                 continue;
106                                         }
107                                         break;
108
109                                 default: continue;
110                         }
111
112                         DB((
113                                 dbg, LEVEL_1,
114                                 "> Found condition evaluation candidate %+F->%+F predecessor %d\n",
115                                 block, cond_block, j
116                         ));
117
118 #if 0 // TODO repair data flow and dominance
119                         NEW_ARR_A(ir_node*, ins, n_block + 1);
120                         for (k = 0; k < n_block; k++) ins[k] = get_Block_cfgpred(block, k);
121                         ins[k] = get_Block_cfgpred(cond_block, j);
122                         set_irn_in(block, n_block + 1, ins);
123
124                         set_Block_cfgpred(cond_block, j, new_Bad());
125                         set_Phi_pred(phi, j, new_Bad());
126 #endif
127                 }
128         }
129 }
130
131
132 void opt_cond_eval(ir_graph* irg)
133 {
134         FIRM_DBG_REGISTER(dbg, "firm.opt.condeval");
135
136         DB((dbg, LEVEL_1, "===> Performing condition evaluation on %+F\n", irg));
137
138         irg_block_walk_graph(irg, NULL, cond_eval, NULL);
139 }