lower_switch: retain debug info, some smaller cleanups
[libfirm] / ir / lower / lower_switch.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   Lowering of Switches if necessary or advantageous.
23  * @author  Moritz Kroll
24  * @version $Id$
25  */
26 #include "config.h"
27
28 #include <limits.h>
29 #include <stdbool.h>
30
31 #include "array_t.h"
32 #include "ircons.h"
33 #include "irgopt.h"
34 #include "irgwalk.h"
35 #include "irnode_t.h"
36 #include "irouts.h"
37 #include "irpass_t.h"
38 #include "lowering.h"
39 #include "error.h"
40
41 #define foreach_out_irn(irn, i, outirn) for (i = get_irn_n_outs(irn) - 1;\
42         i >= 0 && (outirn = get_irn_out(irn, i)); --i)
43
44 typedef struct walk_env {
45         unsigned         spare_size;        /**< the allowed spare size for table switches */
46         bool             changed;           /**< indicates whether a change was performed */
47 } walk_env_t;
48
49 typedef struct case_data {
50         long     value;
51         ir_node *target;
52 } case_data_t;
53
54 typedef struct ifcas_env {
55         ir_node  *sel;
56         int       defindex;
57         ir_node **defusers;           /**< the Projs pointing to the default case */
58 } ifcas_env_t;
59
60 /**
61  * Evaluate a switch and decide whether we should build a table switch.
62  *
63  * @param cond       The Cond node representing the switch.
64  * @param spare_size Allowed spare size for table switches in machine words.
65  *                   (Default in edgfe: 128)
66  */
67 static bool should_do_table_switch(ir_node *cond, unsigned spare_size)
68 {
69         long     default_pn;
70         int      i;
71         ir_node *proj;
72         long switch_min = LONG_MAX;
73         long switch_max = LONG_MIN;
74         unsigned long spare;
75         unsigned long num_cases = 0;
76
77         /* TODO: Minimum size for jump table? */
78         if (get_irn_n_outs(cond) <= 4)
79                 return false;
80
81         default_pn = get_Cond_default_proj(cond);
82
83         foreach_out_irn(cond, i, proj) {
84                 long pn = get_Proj_proj(proj);
85                 if (pn == default_pn)
86                         continue;
87
88                 if (pn < switch_min)
89                         switch_min = pn;
90                 if (pn > switch_max)
91                         switch_max = pn;
92                 ++num_cases;
93         }
94
95         /*
96          * Here we have: num_cases and [switch_min, switch_max] interval.
97          * We do an if-cascade if there are too many spare numbers.
98          */
99         spare = (unsigned long) switch_max - (unsigned long) switch_min - num_cases + 1;
100         return spare < spare_size;
101 }
102
103 static int casecmp(const void *a, const void *b)
104 {
105         const case_data_t *cda = a;
106         const case_data_t *cdb = b;
107
108         /*
109          * Enforce unsigned sorting. Signed comparison will behave differently for
110          * 32-bit values, depending on sizeof(long). This will make the resulting
111          * array deterministic.
112          */
113         return ((unsigned long)cda->value > (unsigned long)cdb->value) -
114                ((unsigned long)cda->value < (unsigned long)cdb->value);
115 }
116
117 /**
118  * Creates an if cascade realizing binary search.
119  */
120 static void create_if_cascade(ifcas_env_t *env, dbg_info *dbgi, ir_node *block,
121                               case_data_t *curcases, unsigned numcases)
122 {
123         ir_graph *irg = get_irn_irg(block);
124     ir_mode *cmp_mode;
125     ir_node *cmp_sel;
126     ir_node *sel_block;
127
128     /* Get the mode and sel node for the comparison. */
129     cmp_mode  = get_irn_mode(env->sel);
130     cmp_sel   = env->sel;
131     sel_block = get_nodes_block(cmp_sel);
132
133     /*
134      * Make sure that an unsigned comparison is used, by converting the sel
135      * node to an unsigned mode and using that mode for the constants, too.
136      * This is important, because the qsort applied to the case labels uses
137      * an unsigned comparison and both comparison methods have to match.
138      */
139     if (mode_is_signed(cmp_mode)) {
140         cmp_mode = find_unsigned_mode(cmp_mode);
141         cmp_sel  = new_r_Conv(sel_block, cmp_sel, cmp_mode);
142     }
143
144         if (numcases == 0) {
145                 /* zero cases: "goto default;" */
146                 env->defusers[env->defindex++] = new_Jmp();
147         } else if (numcases == 1) {
148                 /* only one case: "if (sel == val) goto target else goto default;" */
149                 ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
150                 ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val);
151                 ir_node *proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
152                 ir_node *cond      = new_rd_Cond(dbgi, block, proj);
153                 ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
154                 ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
155
156                 set_Block_cfgpred(curcases[0].target, 0, trueproj);
157                 env->defusers[env->defindex++] = falseproj;
158         } else if (numcases == 2) {
159                 /* only two cases: "if (sel == val[0]) goto target[0];" */
160                 ir_node *val       = new_r_Const_long(irg, cmp_mode, curcases[0].value);
161                 ir_node *cmp       = new_rd_Cmp(dbgi, block, cmp_sel, val);
162                 ir_node *proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
163                 ir_node *cond      = new_rd_Cond(dbgi, block, proj);
164                 ir_node *trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
165                 ir_node *falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
166                 ir_node *in[1];
167                 ir_node *neblock;
168
169                 set_Block_cfgpred(curcases[0].target, 0, trueproj);
170
171                 in[0] = falseproj;
172                 neblock = new_r_Block(irg, 1, in);
173
174                 /* second part: "else if (sel == val[1]) goto target[1] else goto default;" */
175                 val       = new_r_Const_long(irg, cmp_mode, curcases[1].value);
176                 cmp       = new_rd_Cmp(dbgi, neblock, cmp_sel, val);
177                 proj      = new_r_Proj(cmp, mode_b, pn_Cmp_Eq);
178                 cond      = new_rd_Cond(dbgi, neblock, proj);
179                 trueproj  = new_r_Proj(cond, mode_X, pn_Cond_true);
180                 falseproj = new_r_Proj(cond, mode_X, pn_Cond_false);
181                 set_Block_cfgpred(curcases[1].target, 0, trueproj);
182                 env->defusers[env->defindex++] = falseproj;
183         } else {
184                 /* recursive case: split cases in the middle */
185                 int midcase = numcases / 2;
186                 ir_node *val  = new_r_Const_long(irg, cmp_mode,
187                                                  curcases[midcase].value);
188                 ir_node *cmp  = new_rd_Cmp(dbgi, block, cmp_sel, val);
189                 ir_node *proj = new_r_Proj(cmp, mode_b, pn_Cmp_Lt);
190                 ir_node *cond = new_rd_Cond(dbgi, block, proj);
191                 ir_node *in[1];
192                 ir_node *ltblock;
193                 ir_node *geblock;
194
195                 in[0]   = new_r_Proj(cond, mode_X, pn_Cond_true);
196                 ltblock = new_r_Block(irg, 1, in);
197
198                 in[0]   = new_r_Proj(cond, mode_X, pn_Cond_false);
199                 geblock = new_r_Block(irg, 1, in);
200
201                 create_if_cascade(env, dbgi, ltblock, curcases, midcase);
202                 create_if_cascade(env, dbgi, geblock, curcases + midcase,
203                                   numcases - midcase);
204         }
205 }
206
207 /**
208  * Block-Walker: searches for Cond nodes with a non-boolean mode
209  */
210 static void find_cond_nodes(ir_node *block, void *ctx)
211 {
212         walk_env_t  *env = ctx;
213         ir_node     *projx;
214         ir_node     *cond;
215         ir_node     *sel;
216         ir_mode     *sel_mode;
217         long         default_pn;
218         int          i;
219         unsigned     j = 0;
220         unsigned     numcases;
221         ir_node     *proj;
222         case_data_t *cases;
223         ir_node     *condblock;
224         ir_node     *defblock = NULL;
225         dbg_info    *dbgi;
226         ifcas_env_t  ifcas_env;
227
228         /* because we split critical blocks only blocks with 1 predecessors may
229          * contain Proj->Cond nodes */
230         if (get_Block_n_cfgpreds(block) != 1)
231                 return;
232
233         projx = get_Block_cfgpred(block, 0);
234         if (!is_Proj(projx))
235                 return;
236         assert(get_irn_mode(projx) == mode_X);
237
238         cond = get_Proj_pred(projx);
239         if (!is_Cond(cond))
240                 return;
241
242         sel      = get_Cond_selector(cond);
243         sel_mode = get_irn_mode(sel);
244
245         if (sel_mode == mode_b)
246                 return;
247
248         /* the algorithms here don't work reliable for modes bigger than 32
249          * since we operate with long numbers */
250         assert(get_mode_size_bits(sel_mode) <= 32);
251
252         /* ok, we have found a switch cond */
253
254         /* no need to do anything if backend handles out-of-bounds and the switch
255          * is small enough */
256         if (should_do_table_switch(cond, env->spare_size))
257                 return;
258
259         /*
260          * Switch should be transformed into an if cascade.
261          * So first order the cases, so we can do a binary search on them.
262          */
263         env->changed = true;
264
265         numcases = get_irn_n_outs(cond) - 1; /* does not contain default case */
266         cases    = XMALLOCN(case_data_t, numcases);
267
268         default_pn         = get_Cond_default_proj(cond);
269         ifcas_env.sel      = sel;
270         ifcas_env.defindex = 0;
271         ifcas_env.defusers = XMALLOCN(ir_node*, numcases);
272
273         foreach_out_irn(cond, i, proj) {
274                 long pn = get_Proj_proj(proj);
275                 ir_node *target = get_irn_out(proj, 0);
276                 assert(get_Block_n_cfgpreds(target) == 1);
277
278                 if (pn == default_pn) {
279                         defblock = target;
280                         continue;
281                 }
282
283                 cases[j].value  = pn;
284                 cases[j].target = target;
285                 j++;
286         }
287         assert(j == numcases);
288
289         if (defblock == NULL)
290                 panic("Switch %+F has no default proj", cond);
291
292         qsort(cases, numcases, sizeof(cases[0]), casecmp);
293
294         /* Now create the if cascade */
295         condblock = get_nodes_block(cond);
296         dbgi      = get_irn_dbg_info(cond);
297         create_if_cascade(&ifcas_env, dbgi, condblock, cases, numcases);
298
299         /* Connect new default case users */
300         set_irn_in(defblock, ifcas_env.defindex, ifcas_env.defusers);
301
302         xfree(cases);
303         xfree(ifcas_env.defusers);
304 }
305
306 void lower_switch(ir_graph *irg, unsigned spare_size)
307 {
308         walk_env_t env;
309         env.changed             = false;
310         env.spare_size          = spare_size;
311
312         remove_critical_cf_edges(irg);
313         assure_irg_outs(irg);
314
315         irg_block_walk_graph(irg, find_cond_nodes, NULL, &env);
316
317         if (env.changed) {
318                 /* control flow changed */
319                 set_irg_outs_inconsistent(irg);
320                 set_irg_doms_inconsistent(irg);
321                 set_irg_extblk_inconsistent(irg);
322                 set_irg_loopinfo_inconsistent(irg);
323         }
324 }
325
326 struct pass_t {
327         ir_graph_pass_t pass;
328         unsigned        spare_size;
329 };
330
331 /**
332  * Wrapper for running lower_switch() as a pass.
333  */
334 static int pass_wrapper(ir_graph *irg, void *context)
335 {
336         struct pass_t *pass = context;
337
338         lower_switch(irg, pass->spare_size);
339         return 0;
340 }
341
342 /* creates a pass for lower_switch */
343 ir_graph_pass_t *lower_switch_pass(const char *name, unsigned spare_size)
344 {
345         struct pass_t *pass = XMALLOCZ(struct pass_t);
346
347         pass->spare_size = spare_size;
348         return def_graph_pass_constructor(
349                 &pass->pass, name ? name : "lower_switch", pass_wrapper);
350 }