becopyilp: Do not advertise the switch to dump the solution, because this is not...
[libfirm] / ir / lower / lower_switch.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief   Lowering of Switches if necessary or advantageous.
9  * @author  Moritz Kroll
10  */
11 #include "config.h"
12
13 #include <limits.h>
14 #include <stdbool.h>
15
16 #include "array_t.h"
17 #include "ircons.h"
18 #include "irgopt.h"
19 #include "irgwalk.h"
20 #include "irnode_t.h"
21 #include "irouts.h"
22 #include "irpass_t.h"
23 #include "lowering.h"
24 #include "error.h"
25 #include "irnodeset.h"
26
27 #define foreach_out_irn(irn, i, outirn) for (i = get_irn_n_outs(irn) - 1;\
28         i >= 0 && (outirn = get_irn_out(irn, i)); --i)
29
30 typedef struct walk_env_t {
31         ir_nodeset_t  processed;
32         ir_mode      *selector_mode;
33         unsigned      spare_size; /**< the allowed spare size for table switches */
34         unsigned      small_switch;
35         bool          changed;    /**< indicates whether a change was performed */
36 } walk_env_t;
37
38 typedef struct case_data_t {
39         const ir_switch_table_entry *entry;
40         ir_node                     *target;
41 } case_data_t;
42
43 typedef struct switch_info_t {
44         ir_node     *switchn;
45         ir_tarval   *switch_min;
46         ir_tarval   *switch_max;
47         ir_node     *default_block;
48         unsigned     num_cases;
49         case_data_t *cases;
50         ir_node    **defusers;    /**< the Projs pointing to the default case */
51 } switch_info_t;
52
53 /**
54  * analyze enough to decide if we should lower the switch
55  */
56 static void analyse_switch0(switch_info_t *info, ir_node *switchn)
57 {
58         const ir_switch_table *table      = get_Switch_table(switchn);
59         size_t                 n_entries  = ir_switch_table_get_n_entries(table);
60         ir_mode               *mode       = get_irn_mode(get_Switch_selector(switchn));
61         ir_tarval             *switch_min = get_mode_max(mode);
62         ir_tarval             *switch_max = get_mode_min(mode);
63         unsigned               num_cases  = 0;
64
65         for (size_t e = 0; e < n_entries; ++e) {
66                 const ir_switch_table_entry *entry
67                         = ir_switch_table_get_entry_const(table, e);
68                 if (entry->pn == 0)
69                         continue;
70
71                 if (tarval_cmp(entry->min, switch_min) == ir_relation_less)
72                         switch_min = entry->min;
73                 if (tarval_cmp(entry->max, switch_max) == ir_relation_greater)
74                         switch_max = entry->max;
75
76                 ++num_cases;
77         }
78
79         info->switchn    = switchn;
80         info->switch_min = switch_min;
81         info->switch_max = switch_max;
82         info->num_cases  = num_cases;
83 }
84
85 static int casecmp(const void *a, const void *b)
86 {
87         const case_data_t           *cda = (const case_data_t*)a;
88         const case_data_t           *cdb = (const case_data_t*)b;
89         const ir_switch_table_entry *ea  = cda->entry;
90         const ir_switch_table_entry *eb  = cdb->entry;
91
92         if (ea == eb)
93                 return 0;
94
95         if (tarval_cmp(ea->max, eb->min) == ir_relation_less)
96                 return -1;
97         /* cases must be non overlapping, so the only remaining case is greater */
98         assert(tarval_cmp(ea->min, eb->max) == ir_relation_greater);
99         return 1;
100 }
101
102 /**
103  * Analyse the stuff that anayse_switch0() left out
104  */
105 static void analyse_switch1(switch_info_t *info)
106 {
107         const ir_node         *switchn   = info->switchn;
108         const ir_switch_table *table     = get_Switch_table(switchn);
109         size_t                 n_entries = ir_switch_table_get_n_entries(table);
110         unsigned               n_outs    = get_Switch_n_outs(switchn);
111         ir_node              **targets   = XMALLOCNZ(ir_node*, n_outs);
112         unsigned               num_cases = info->num_cases;
113         case_data_t           *cases     = XMALLOCN(case_data_t, num_cases);
114         unsigned               c         = 0;
115         size_t                 e;
116         int                    i;
117         ir_node               *proj;
118
119         foreach_out_irn(switchn, i, proj) {
120                 long     pn     = get_Proj_proj(proj);
121                 ir_node *target = get_irn_out(proj, 0);
122
123                 assert((unsigned)pn < n_outs);
124                 assert(targets[(unsigned)pn] == NULL);
125                 targets[(unsigned)pn] = target;
126         }
127
128         for (e = 0; e < n_entries; ++e) {
129                 const ir_switch_table_entry *entry
130                         = ir_switch_table_get_entry_const(table, e);
131                 if (entry->pn == 0)
132                         continue;
133
134                 cases[c].entry  = entry;
135                 cases[c].target = targets[entry->pn];
136                 ++c;
137         }
138         assert(c == num_cases);
139
140         /*
141          * Switch should be transformed into an if cascade.
142          * So first order the cases, so we can do a binary search on them.
143          */
144         qsort(cases, num_cases, sizeof(cases[0]), casecmp);
145
146         info->default_block = targets[pn_Switch_default];
147         info->cases         = cases;
148         free(targets);
149 }
150
151 static void normalize_table(ir_node *switchn, ir_mode *new_mode,
152                             ir_tarval *delta)
153 {
154         ir_switch_table *table     = get_Switch_table(switchn);
155         size_t           n_entries = ir_switch_table_get_n_entries(table);
156         size_t           e;
157         /* adapt switch_table */
158         for (e = 0; e < n_entries; ++e) {
159                 ir_switch_table_entry *entry = ir_switch_table_get_entry(table, e);
160                 ir_tarval *min = entry->min;
161
162                 if (entry->pn == 0)
163                         continue;
164
165                 min = tarval_convert_to(min, new_mode);
166                 if (delta != NULL)
167                         min = tarval_sub(min, delta, NULL);
168
169                 if (entry->min == entry->max) {
170                         entry->min = min;
171                         entry->max = min;
172                 } else {
173                         ir_tarval *max = entry->max;
174                         max = tarval_convert_to(max, new_mode);
175                         if (delta != NULL)
176                                 max = tarval_sub(max, delta, NULL);
177                         entry->min = min;
178                         entry->max = max;
179                 }
180         }
181 }
182
183 static void create_out_of_bounds_check(switch_info_t *info)
184 {
185         ir_node    *switchn       = info->switchn;
186         ir_graph   *irg           = get_irn_irg(switchn);
187         dbg_info   *dbgi          = get_irn_dbg_info(switchn);
188         ir_node    *selector      = get_Switch_selector(switchn);
189         ir_node    *block         = get_nodes_block(switchn);
190         ir_node   **default_preds = NEW_ARR_F(ir_node*, 0);
191         ir_node    *default_block = NULL;
192         ir_node    *max_const;
193         ir_node    *proj_true;
194         ir_node    *proj_false;
195         ir_node    *cmp;
196         ir_node    *oob_cond;
197         ir_node    *in[1];
198         ir_node    *new_block;
199         int         i;
200         ir_node    *proj;
201         size_t      n_default_preds;
202
203         assert(tarval_is_null(info->switch_min));
204
205         /* check for out-of-bounds */
206         max_const  = new_r_Const(irg, info->switch_max);
207         cmp        = new_rd_Cmp(dbgi, block, selector, max_const, ir_relation_less_equal);
208         oob_cond   = new_rd_Cond(dbgi, block, cmp);
209         proj_true  = new_r_Proj(oob_cond, mode_X, pn_Cond_true);
210         proj_false = new_r_Proj(oob_cond, mode_X, pn_Cond_false);
211
212         ARR_APP1(ir_node*, default_preds, proj_false);
213
214         /* create new block containing the switch */
215         in[0] = proj_true;
216         new_block = new_r_Block(irg, 1, in);
217         set_nodes_block(switchn, new_block);
218
219         /* adjust projs */
220         foreach_out_irn(switchn, i, proj) {
221                 long pn = get_Proj_proj(proj);
222                 if (pn == pn_Switch_default) {
223                         assert(default_block == NULL);
224                         default_block = get_irn_out(proj, 0);
225                         ARR_APP1(ir_node*, default_preds, proj);
226                 }
227                 set_nodes_block(proj, new_block);
228         }
229
230         /* adapt default block */
231         n_default_preds = ARR_LEN(default_preds);
232         if (n_default_preds > 1) {
233                 /* create new intermediate blocks so we don't have critical edges */
234                 size_t p;
235                 for (p = 0; p < n_default_preds; ++p) {
236                         ir_node *pred = default_preds[p];
237                         ir_node *split_block;
238                         ir_node *block_in[1];
239
240                         block_in[0] = pred;
241                         split_block = new_r_Block(irg, 1, block_in);
242
243                         default_preds[p] = new_r_Jmp(split_block);
244                 }
245         }
246         set_irn_in(default_block, n_default_preds, default_preds);
247
248         DEL_ARR_F(default_preds);
249
250         clear_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
251 }
252
253 /**
254  * normalize switch to work on an unsigned input with the first case at 0
255  */
256 static void normalize_switch(switch_info_t *info, ir_mode *selector_mode)
257 {
258         ir_node   *switchn         = info->switchn;
259         ir_graph  *irg             = get_irn_irg(switchn);
260         ir_node   *block           = get_nodes_block(switchn);
261         ir_node   *selector        = get_Switch_selector(switchn);
262         ir_mode   *mode            = get_irn_mode(selector);
263         ir_tarval *delta           = NULL;
264         bool       needs_normalize = false;
265
266         ir_tarval *min = info->switch_min;
267         if (mode_is_signed(mode)) {
268                 mode             = find_unsigned_mode(mode);
269                 selector         = new_r_Conv(block, selector, mode);
270                 min              = tarval_convert_to(min, mode);
271                 info->switch_min = min;
272                 info->switch_max = tarval_convert_to(info->switch_max, mode);
273                 needs_normalize  = true;
274         }
275
276         /* normalize so switch_min is at 0 */
277         if (min != get_mode_null(mode)) {
278                 ir_node  *min_const = new_r_Const(irg, min);
279                 dbg_info *dbgi      = get_irn_dbg_info(switchn);
280                 selector = new_rd_Sub(dbgi, block, selector, min_const, mode);
281
282                 info->switch_max = tarval_sub(info->switch_max, min, mode);
283                 info->switch_min = get_mode_null(mode);
284                 delta            = min;
285
286                 needs_normalize = true;
287         }
288
289         /* if we have a selector_mode set, then the we will have a switch node,
290          * we have to construct an out-of-bounds check then and after that convert
291          * the switch/selector to the backends desired switch mode */
292         if (selector_mode != NULL) {
293                 set_Switch_selector(switchn, selector);
294                 create_out_of_bounds_check(info);
295
296                 selector = new_r_Conv(block, selector, selector_mode);
297                 mode     = selector_mode;
298                 info->switch_min = tarval_convert_to(info->switch_min, mode);
299                 info->switch_max = tarval_convert_to(info->switch_max, mode);
300                 if (delta != NULL)
301                         delta = tarval_convert_to(delta, mode);
302                 needs_normalize = true;
303         }
304
305         if (needs_normalize) {
306                 set_Switch_selector(switchn, selector);
307                 normalize_table(switchn, mode, delta);
308         }
309 }
310
311 /**
312  * Create an if (selector == caseval) Cond node (and handle the special case
313  * of ranged cases)
314  */
315 static ir_node *create_case_cond(const ir_switch_table_entry *entry,
316                                  dbg_info *dbgi, ir_node *block,
317                                  ir_node *selector)
318 {
319         ir_graph *irg      = get_irn_irg(block);
320         ir_node  *minconst = new_r_Const(irg, entry->min);
321         ir_node  *cmp;
322
323         if (entry->min == entry->max) {
324                 cmp = new_rd_Cmp(dbgi, block, selector, minconst, ir_relation_equal);
325         } else {
326                 ir_tarval *adjusted_max = tarval_sub(entry->max, entry->min, NULL);
327                 ir_node   *sub          = new_rd_Sub(dbgi, block, selector, minconst,
328                                                      get_tarval_mode(adjusted_max));
329                 ir_node   *maxconst     = new_r_Const(irg, adjusted_max);
330                 cmp = new_rd_Cmp(dbgi, block, sub, maxconst, ir_relation_less_equal);
331         }
332
333         return new_rd_Cond(dbgi, block, cmp);
334 }
335
336 /**
337  * Creates an if cascade realizing binary search.
338  */
339 static void create_if_cascade(switch_info_t *info, ir_node *block,
340                               case_data_t *curcases, unsigned numcases)
341 {
342         ir_graph      *irg      = get_irn_irg(block);
343         const ir_node *switchn  = info->switchn;
344         dbg_info      *dbgi     = get_irn_dbg_info(switchn);
345         ir_node       *selector = get_Switch_selector(switchn);
346
347         if (numcases == 0) {
348                 /* zero cases: "goto default;" */
349                 ARR_APP1(ir_node*, info->defusers, new_r_Jmp(block));
350         } else if (numcases == 1) {
351                 /*only one case: "if (sel == val) goto target else goto default;"*/
352                 const ir_switch_table_entry *entry = curcases[0].entry;
353                 ir_node *cond      = create_case_cond(entry, dbgi, block, selector);
354                 ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
355                 ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
356
357                 set_Block_cfgpred(curcases[0].target, 0, trueproj);
358                 ARR_APP1(ir_node*, info->defusers, falseproj);
359         } else if (numcases == 2) {
360                 /* only two cases: "if (sel == val[0]) goto target[0];" */
361                 const ir_switch_table_entry *entry0 = curcases[0].entry;
362                 const ir_switch_table_entry *entry1 = curcases[1].entry;
363                 ir_node *cond      = create_case_cond(entry0, dbgi, block, selector);
364                 ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
365                 ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
366                 ir_node *in[1];
367                 ir_node *neblock;
368
369                 set_Block_cfgpred(curcases[0].target, 0, trueproj);
370
371                 in[0] = falseproj;
372                 neblock = new_r_Block(irg, 1, in);
373
374                 /* second part: "else if (sel == val[1]) goto target[1] else goto default;" */
375                 cond      = create_case_cond(entry1, dbgi, neblock, selector);
376                 trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
377                 falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
378                 set_Block_cfgpred(curcases[1].target, 0, trueproj);
379                 ARR_APP1(ir_node*, info->defusers, falseproj);
380         } else {
381                 /* recursive case: split cases in the middle */
382                 unsigned midcase = numcases / 2;
383                 const ir_switch_table_entry *entry = curcases[midcase].entry;
384                 ir_node *val = new_r_Const(irg, entry->min);
385                 ir_node *cmp = new_rd_Cmp(dbgi, block, selector, val, ir_relation_less);
386                 ir_node *cond = new_rd_Cond(dbgi, block, cmp);
387                 ir_node *in[1];
388                 ir_node *ltblock;
389                 ir_node *geblock;
390
391                 in[0]   = new_r_Proj(cond, mode_X, pn_Cond_true);
392                 ltblock = new_r_Block(irg, 1, in);
393
394                 in[0]   = new_r_Proj(cond, mode_X, pn_Cond_false);
395                 geblock = new_r_Block(irg, 1, in);
396
397                 create_if_cascade(info, ltblock, curcases, midcase);
398                 create_if_cascade(info, geblock, curcases + midcase, numcases - midcase);
399         }
400 }
401
402 /**
403  * Block-Walker: searches for Switch nodes
404  */
405 static void find_switch_nodes(ir_node *block, void *ctx)
406 {
407         walk_env_t   *env = (walk_env_t *)ctx;
408         ir_node      *projx;
409         ir_node      *switchn;
410         switch_info_t info;
411
412         /* because we split critical blocks only blocks with 1 predecessors may
413          * contain Proj->Cond nodes */
414         if (get_Block_n_cfgpreds(block) != 1)
415                 return;
416
417         projx = get_Block_cfgpred(block, 0);
418         if (!is_Proj(projx))
419                 return;
420         assert(get_irn_mode(projx) == mode_X);
421
422         switchn = get_Proj_pred(projx);
423         if (!is_Switch(switchn))
424                 return;
425
426         if (!ir_nodeset_insert(&env->processed, switchn))
427                 return;
428
429         analyse_switch0(&info, switchn);
430
431         /*
432          * Here we have: num_cases and [switch_min, switch_max] interval.
433          * We do an if-cascade if there are too many spare numbers.
434          */
435         ir_mode   *mode  = get_irn_mode(get_Switch_selector(switchn));
436         ir_tarval *spare = tarval_sub(info.switch_max, info.switch_min, mode);
437         mode  = find_unsigned_mode(mode);
438         spare = tarval_convert_to(spare, mode);
439         ir_tarval *num_cases_minus_one
440                 = new_tarval_from_long(info.num_cases-1, mode);
441         spare = tarval_sub(spare, num_cases_minus_one, mode);
442         ir_tarval *spare_size = new_tarval_from_long(env->spare_size, mode);
443         bool lower_switch = (info.num_cases <= env->small_switch
444          || (tarval_cmp(spare, spare_size) & ir_relation_greater_equal));
445
446         if (!lower_switch) {
447                 /* we won't decompose the switch. But we must add an out-of-bounds
448                  * check */
449                 normalize_switch(&info, env->selector_mode);
450                 return;
451         }
452
453         normalize_switch(&info, NULL);
454         analyse_switch1(&info);
455
456         /* Now create the if cascade */
457         env->changed  = true;
458         info.defusers = NEW_ARR_F(ir_node*, 0);
459         block         = get_nodes_block(switchn);
460         create_if_cascade(&info, block, info.cases, info.num_cases);
461
462         /* Connect new default case users */
463         set_irn_in(info.default_block, ARR_LEN(info.defusers), info.defusers);
464
465         DEL_ARR_F(info.defusers);
466         xfree(info.cases);
467         clear_irg_properties(get_irn_irg(block), IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES
468                                           | IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
469 }
470
471 void lower_switch(ir_graph *irg, unsigned small_switch, unsigned spare_size,
472                   ir_mode *selector_mode)
473 {
474         if (mode_is_signed(selector_mode))
475                 panic("expected unsigned mode for switch selector");
476
477         walk_env_t env;
478         env.selector_mode       = selector_mode;
479         env.spare_size          = spare_size;
480         env.small_switch        = small_switch;
481         env.changed             = false;
482         ir_nodeset_init(&env.processed);
483
484         remove_critical_cf_edges(irg);
485         assure_irg_outs(irg);
486
487         irg_block_walk_graph(irg, find_switch_nodes, NULL, &env);
488         ir_nodeset_destroy(&env.processed);
489 }