diff options
Diffstat (limited to 'meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch')
-rw-r--r-- | meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch | 811 |
1 files changed, 811 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch new file mode 100644 index 000000000..cf22aaf16 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch | |||
@@ -0,0 +1,811 @@ | |||
1 | 2010-12-13 Tom de Vries <tom@codesourcery.com> | ||
2 | |||
3 | gcc/ | ||
4 | * tree-if-switch-conversion.c: New pass. | ||
5 | * tree-pass.h (pass_if_to_switch): Declare. | ||
6 | * common.opt (ftree-if-to-switch-conversion): New switch. | ||
7 | * opts.c (decode_options): Set flag_tree_if_to_switch_conversion at -O2 | ||
8 | and higher. | ||
9 | * passes.c (init_optimization_passes): Use new pass. | ||
10 | * params.def (PARAM_IF_TO_SWITCH_THRESHOLD): New param. | ||
11 | * doc/invoke.texi (-ftree-if-to-switch-conversion) | ||
12 | (if-to-switch-threshold): New item. | ||
13 | * doc/invoke.texi (Optimization Options, option -O2): Add | ||
14 | -ftree-if-to-switch-conversion. | ||
15 | * Makefile.in (OBJS-common): Add tree-if-switch-conversion.o. | ||
16 | * Makefile.in (tree-if-switch-conversion.o): New rule. | ||
17 | |||
18 | === modified file 'gcc/Makefile.in' | ||
19 | Index: gcc-4_5-branch/gcc/Makefile.in | ||
20 | =================================================================== | ||
21 | --- gcc-4_5-branch.orig/gcc/Makefile.in | ||
22 | +++ gcc-4_5-branch/gcc/Makefile.in | ||
23 | @@ -1354,6 +1354,7 @@ OBJS-common = \ | ||
24 | tree-profile.o \ | ||
25 | tree-scalar-evolution.o \ | ||
26 | tree-sra.o \ | ||
27 | + tree-if-switch-conversion.o \ | ||
28 | tree-switch-conversion.o \ | ||
29 | tree-ssa-address.o \ | ||
30 | tree-ssa-alias.o \ | ||
31 | @@ -3013,6 +3014,11 @@ tree-sra.o : tree-sra.c $(CONFIG_H) $(SY | ||
32 | $(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) $(IPA_PROP_H) \ | ||
33 | $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) $(PARAMS_H) \ | ||
34 | $(TARGET_H) $(FLAGS_H) $(EXPR_H) $(TREE_INLINE_H) | ||
35 | +tree-if-switch-conversion.o : tree-if-switch-conversion.c $(CONFIG_H) \ | ||
36 | + $(SYSTEM_H) $(TREE_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) \ | ||
37 | + $(TREE_INLINE_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ | ||
38 | + $(GIMPLE_H) $(TREE_PASS_H) $(FLAGS_H) $(EXPR_H) $(BASIC_BLOCK_H) output.h \ | ||
39 | + $(GGC_H) $(OBSTACK_H) $(PARAMS_H) $(CPPLIB_H) $(PARAMS_H) | ||
40 | tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \ | ||
41 | $(TREE_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \ | ||
42 | $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(GIMPLE_H) \ | ||
43 | Index: gcc-4_5-branch/gcc/common.opt | ||
44 | =================================================================== | ||
45 | --- gcc-4_5-branch.orig/gcc/common.opt | ||
46 | +++ gcc-4_5-branch/gcc/common.opt | ||
47 | @@ -1285,6 +1285,10 @@ ftree-switch-conversion | ||
48 | Common Report Var(flag_tree_switch_conversion) Optimization | ||
49 | Perform conversions of switch initializations. | ||
50 | |||
51 | +ftree-if-to-switch-conversion | ||
52 | +Common Report Var(flag_tree_if_to_switch_conversion) Optimization | ||
53 | +Perform conversions of chains of ifs into switches. | ||
54 | + | ||
55 | ftree-dce | ||
56 | Common Report Var(flag_tree_dce) Optimization | ||
57 | Enable SSA dead code elimination optimization on trees | ||
58 | Index: gcc-4_5-branch/gcc/doc/invoke.texi | ||
59 | =================================================================== | ||
60 | --- gcc-4_5-branch.orig/gcc/doc/invoke.texi | ||
61 | +++ gcc-4_5-branch/gcc/doc/invoke.texi | ||
62 | @@ -382,7 +382,8 @@ Objective-C and Objective-C++ Dialects}. | ||
63 | -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer @gol | ||
64 | -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-copy-prop @gol | ||
65 | -ftree-copyrename -ftree-dce @gol | ||
66 | --ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre -ftree-loop-im @gol | ||
67 | +-ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre @gol | ||
68 | +-ftree-if-to-switch-conversion -ftree-loop-im @gol | ||
69 | -ftree-phiprop -ftree-loop-distribution @gol | ||
70 | -ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize @gol | ||
71 | -ftree-parallelize-loops=@var{n} -ftree-pre -ftree-pta -ftree-reassoc @gol | ||
72 | @@ -5798,6 +5799,7 @@ also turns on the following optimization | ||
73 | -fsched-interblock -fsched-spec @gol | ||
74 | -fschedule-insns -fschedule-insns2 @gol | ||
75 | -fstrict-aliasing -fstrict-overflow @gol | ||
76 | +-ftree-if-to-switch-conversion @gol | ||
77 | -ftree-switch-conversion @gol | ||
78 | -ftree-pre @gol | ||
79 | -ftree-vrp} | ||
80 | @@ -6634,6 +6636,10 @@ Perform conversion of simple initializat | ||
81 | initializations from a scalar array. This flag is enabled by default | ||
82 | at @option{-O2} and higher. | ||
83 | |||
84 | +@item -ftree-if-to-switch-conversion | ||
85 | +Perform conversion of chains of ifs into switches. This flag is enabled by | ||
86 | +default at @option{-O2} and higher. | ||
87 | + | ||
88 | @item -ftree-dce | ||
89 | @opindex ftree-dce | ||
90 | Perform dead code elimination (DCE) on trees. This flag is enabled by | ||
91 | @@ -8577,6 +8583,12 @@ loop in the loop nest by a given number | ||
92 | length can be changed using the @option{loop-block-tile-size} | ||
93 | parameter. The default value is 51 iterations. | ||
94 | |||
95 | +@item if-to-switch-threshold | ||
96 | +If-chain to switch conversion, enabled by | ||
97 | +@option{-ftree-if-to-switch-conversion} convert chains of ifs of sufficient | ||
98 | +length into switches. The parameter @option{if-to-switch-threshold} can be | ||
99 | +used to set the minimal required length. The default value is 3. | ||
100 | + | ||
101 | @end table | ||
102 | @end table | ||
103 | |||
104 | Index: gcc-4_5-branch/gcc/opts.c | ||
105 | =================================================================== | ||
106 | --- gcc-4_5-branch.orig/gcc/opts.c | ||
107 | +++ gcc-4_5-branch/gcc/opts.c | ||
108 | @@ -905,6 +905,7 @@ decode_options (unsigned int argc, const | ||
109 | flag_tree_builtin_call_dce = opt2; | ||
110 | flag_tree_pre = opt2; | ||
111 | flag_tree_switch_conversion = opt2; | ||
112 | + flag_tree_if_to_switch_conversion = opt2; | ||
113 | flag_ipa_cp = opt2; | ||
114 | flag_ipa_sra = opt2; | ||
115 | flag_ee = opt2; | ||
116 | Index: gcc-4_5-branch/gcc/params.def | ||
117 | =================================================================== | ||
118 | --- gcc-4_5-branch.orig/gcc/params.def | ||
119 | +++ gcc-4_5-branch/gcc/params.def | ||
120 | @@ -826,6 +826,11 @@ DEFPARAM (PARAM_IPA_SRA_PTR_GROWTH_FACTO | ||
121 | "a pointer to an aggregate with", | ||
122 | 2, 0, 0) | ||
123 | |||
124 | +DEFPARAM (PARAM_IF_TO_SWITCH_THRESHOLD, | ||
125 | + "if-to-switch-threshold", | ||
126 | + "Threshold for converting an if-chain into a switch", | ||
127 | + 3, 0, 0) | ||
128 | + | ||
129 | /* | ||
130 | Local variables: | ||
131 | mode:c | ||
132 | Index: gcc-4_5-branch/gcc/passes.c | ||
133 | =================================================================== | ||
134 | --- gcc-4_5-branch.orig/gcc/passes.c | ||
135 | +++ gcc-4_5-branch/gcc/passes.c | ||
136 | @@ -788,6 +788,7 @@ init_optimization_passes (void) | ||
137 | NEXT_PASS (pass_cd_dce); | ||
138 | NEXT_PASS (pass_early_ipa_sra); | ||
139 | NEXT_PASS (pass_tail_recursion); | ||
140 | + NEXT_PASS (pass_if_to_switch); | ||
141 | NEXT_PASS (pass_convert_switch); | ||
142 | NEXT_PASS (pass_cleanup_eh); | ||
143 | NEXT_PASS (pass_profile); | ||
144 | @@ -844,6 +845,7 @@ init_optimization_passes (void) | ||
145 | NEXT_PASS (pass_phiprop); | ||
146 | NEXT_PASS (pass_fre); | ||
147 | NEXT_PASS (pass_copy_prop); | ||
148 | + NEXT_PASS (pass_if_to_switch); | ||
149 | NEXT_PASS (pass_merge_phi); | ||
150 | NEXT_PASS (pass_vrp); | ||
151 | NEXT_PASS (pass_dce); | ||
152 | Index: gcc-4_5-branch/gcc/tree-if-switch-conversion.c | ||
153 | =================================================================== | ||
154 | --- /dev/null | ||
155 | +++ gcc-4_5-branch/gcc/tree-if-switch-conversion.c | ||
156 | @@ -0,0 +1,643 @@ | ||
157 | +/* Convert a chain of ifs into a switch. | ||
158 | + Copyright (C) 2010 Free Software Foundation, Inc. | ||
159 | + Contributed by Tom de Vries <tom@codesourcery.com> | ||
160 | + | ||
161 | +This file is part of GCC. | ||
162 | + | ||
163 | +GCC is free software; you can redistribute it and/or modify it | ||
164 | +under the terms of the GNU General Public License as published by the | ||
165 | +Free Software Foundation; either version 3, or (at your option) any | ||
166 | +later version. | ||
167 | + | ||
168 | +GCC is distributed in the hope that it will be useful, but WITHOUT | ||
169 | +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
170 | +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
171 | +for more details. | ||
172 | + | ||
173 | +You should have received a copy of the GNU General Public License | ||
174 | +along with GCC; see the file COPYING3. If not, write to the Free | ||
175 | +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA | ||
176 | +02110-1301, USA. */ | ||
177 | + | ||
178 | + | ||
179 | +/* The following pass converts a chain of ifs into a switch. | ||
180 | + | ||
181 | + The if-chain has the following properties: | ||
182 | + - all bbs end in a GIMPLE_COND. | ||
183 | + - all but the first bb are empty, apart from the GIMPLE_COND. | ||
184 | + - the GIMPLE_CONDs compare the same variable against integer constants. | ||
185 | + - the true gotos all target the same bb. | ||
186 | + - the false gotos target the next in the if-chain. | ||
187 | + | ||
188 | + F.i., consider the following if-chain: | ||
189 | + ... | ||
190 | + <bb 4>: | ||
191 | + ... | ||
192 | + if (D.1993_3 == 32) | ||
193 | + goto <bb 3>; | ||
194 | + else | ||
195 | + goto <bb 5>; | ||
196 | + | ||
197 | + <bb 5>: | ||
198 | + if (D.1993_3 == 13) | ||
199 | + goto <bb 3>; | ||
200 | + else | ||
201 | + goto <bb 6>; | ||
202 | + | ||
203 | + <bb 6>: | ||
204 | + if (D.1993_3 == 10) | ||
205 | + goto <bb 3>; | ||
206 | + else | ||
207 | + goto <bb 7>; | ||
208 | + | ||
209 | + <bb 7>: | ||
210 | + if (D.1993_3 == 9) | ||
211 | + goto <bb 3>; | ||
212 | + else | ||
213 | + goto <bb 8>; | ||
214 | + ... | ||
215 | + | ||
216 | + The pass will report this if-chain like this: | ||
217 | + ... | ||
218 | + var: D.1993_3 | ||
219 | + first: <bb 4> | ||
220 | + true: <bb 3> | ||
221 | + last: <bb 7> | ||
222 | + constants: 9 10 13 32 | ||
223 | + ... | ||
224 | + | ||
225 | + and then convert the if-chain into a switch: | ||
226 | + ... | ||
227 | + <bb 4>: | ||
228 | + ... | ||
229 | + switch (D.1993_3) <default: <L8>, | ||
230 | + case 9: <L7>, | ||
231 | + case 10: <L7>, | ||
232 | + case 13: <L7>, | ||
233 | + case 32: <L7>> | ||
234 | + ... | ||
235 | + | ||
236 | + The conversion does not happen if the chain is too short. The threshold is | ||
237 | + determined by the parameter PARAM_IF_TO_SWITCH_THRESHOLD. | ||
238 | + | ||
239 | + The pass will try to construct a chain for each bb, unless the bb it is | ||
240 | + already contained in a chain. This ensures that all chains will be found, | ||
241 | + and that no chain will be constructed twice. The pass constructs and | ||
242 | + converts the chains one-by-one, rather than first calculating all the chains | ||
243 | + and then doing the conversions. | ||
244 | + | ||
245 | + The pass could detect range-checks in analyze_bb as well, and handle them. | ||
246 | + Simple ones, like 'c <= 5', and more complex ones, like | ||
247 | + '(unsigned char) c + 247 <= 1', which is generated by the C front-end from | ||
248 | + code like '(c == 9 || c == 10)' or '(9 <= c && c <= 10)'. */ | ||
249 | + | ||
250 | +#include "config.h" | ||
251 | +#include "system.h" | ||
252 | +#include "coretypes.h" | ||
253 | +#include "tm.h" | ||
254 | + | ||
255 | +#include "params.h" | ||
256 | +#include "flags.h" | ||
257 | +#include "tree.h" | ||
258 | +#include "basic-block.h" | ||
259 | +#include "tree-flow.h" | ||
260 | +#include "tree-flow-inline.h" | ||
261 | +#include "tree-ssa-operands.h" | ||
262 | +#include "diagnostic.h" | ||
263 | +#include "tree-pass.h" | ||
264 | +#include "tree-dump.h" | ||
265 | +#include "timevar.h" | ||
266 | + | ||
267 | +/* Information we've collected about a single bb. */ | ||
268 | + | ||
269 | +struct ifsc_info | ||
270 | +{ | ||
271 | + /* The variable of the bb's ending GIMPLE_COND, NULL_TREE if not present. */ | ||
272 | + tree var; | ||
273 | + /* The cond_code of the bb's ending GIMPLE_COND. */ | ||
274 | + enum tree_code cond_code; | ||
275 | + /* The constant of the bb's ending GIMPLE_COND. */ | ||
276 | + tree constant; | ||
277 | + /* Successor edge of the bb if its GIMPLE_COND is true. */ | ||
278 | + edge true_edge; | ||
279 | + /* Successor edge of the bb if its GIMPLE_COND is false. */ | ||
280 | + edge false_edge; | ||
281 | + /* Set if the bb has valid ifsc_info. */ | ||
282 | + bool valid; | ||
283 | + /* Set if the bb is part of a chain. */ | ||
284 | + bool chained; | ||
285 | +}; | ||
286 | + | ||
287 | +/* Macros to access the fields of struct ifsc_info. */ | ||
288 | + | ||
289 | +#define BB_IFSC_VAR(bb) (((struct ifsc_info *)bb->aux)->var) | ||
290 | +#define BB_IFSC_COND_CODE(bb) (((struct ifsc_info *)bb->aux)->cond_code) | ||
291 | +#define BB_IFSC_CONSTANT(bb) (((struct ifsc_info *)bb->aux)->constant) | ||
292 | +#define BB_IFSC_TRUE_EDGE(bb) (((struct ifsc_info *)bb->aux)->true_edge) | ||
293 | +#define BB_IFSC_FALSE_EDGE(bb) (((struct ifsc_info *)bb->aux)->false_edge) | ||
294 | +#define BB_IFSC_VALID(bb) (((struct ifsc_info *)bb->aux)->valid) | ||
295 | +#define BB_IFSC_CHAINED(bb) (((struct ifsc_info *)bb->aux)->chained) | ||
296 | + | ||
297 | +/* Data-type describing an if-chain. */ | ||
298 | + | ||
299 | +struct if_chain | ||
300 | +{ | ||
301 | + /* First bb in the chain. */ | ||
302 | + basic_block first; | ||
303 | + /* Last bb in the chain. */ | ||
304 | + basic_block last; | ||
305 | + /* Variable that GIMPLE_CONDs of all bbs in chain compare against. */ | ||
306 | + tree var; | ||
307 | + /* bb that all GIMPLE_CONDs jump to if comparison succeeds. */ | ||
308 | + basic_block true_dest; | ||
309 | + /* Constants that GIMPLE_CONDs of all bbs in chain compare var against. */ | ||
310 | + VEC (tree, heap) *constants; | ||
311 | + /* Same as previous, but sorted and with duplicates removed. */ | ||
312 | + VEC (tree, heap) *unique_constants; | ||
313 | +}; | ||
314 | + | ||
315 | +/* Utility macro. */ | ||
316 | + | ||
317 | +#define SWAP(T, X, Y) do { T tmp = (X); (X) = (Y); (Y) = tmp; } while (0) | ||
318 | + | ||
319 | +/* Helper function for sort_constants. */ | ||
320 | + | ||
321 | +static int | ||
322 | +compare_constants (const void *p1, const void *p2) | ||
323 | +{ | ||
324 | + const_tree const c1 = *(const_tree const*)p1; | ||
325 | + const_tree const c2 = *(const_tree const*)p2; | ||
326 | + | ||
327 | + return tree_int_cst_compare (c1, c2); | ||
328 | +} | ||
329 | + | ||
330 | +/* Sort constants in constants and copy to unique_constants, while skipping | ||
331 | + duplicates. */ | ||
332 | + | ||
333 | +static void | ||
334 | +sort_constants (VEC (tree,heap) *constants, VEC (tree,heap) **unique_constants) | ||
335 | +{ | ||
336 | + size_t len = VEC_length (tree, constants); | ||
337 | + unsigned int ix; | ||
338 | + tree prev = NULL_TREE, constant; | ||
339 | + | ||
340 | + /* Sort constants. */ | ||
341 | + qsort (VEC_address (tree, constants), len, sizeof (tree), | ||
342 | + compare_constants); | ||
343 | + | ||
344 | + /* Copy to unique_constants, while skipping duplicates. */ | ||
345 | + for (ix = 0; VEC_iterate (tree, constants, ix, constant); ix++) | ||
346 | + { | ||
347 | + if (prev != NULL_TREE && tree_int_cst_compare (prev, constant) == 0) | ||
348 | + continue; | ||
349 | + prev = constant; | ||
350 | + | ||
351 | + VEC_safe_push (tree, heap, *unique_constants, constant); | ||
352 | + } | ||
353 | +} | ||
354 | + | ||
355 | +/* Get true_edge and false_edge of a bb ending in a conditional jump. */ | ||
356 | + | ||
357 | +static void | ||
358 | +get_edges (basic_block bb, edge *true_edge, edge *false_edge) | ||
359 | +{ | ||
360 | + edge e0, e1; | ||
361 | + int e0_true; | ||
362 | + int n = EDGE_COUNT (bb->succs); | ||
363 | + gcc_assert (n == 2); | ||
364 | + | ||
365 | + e0 = EDGE_SUCC (bb, 0); | ||
366 | + e1 = EDGE_SUCC (bb, 1); | ||
367 | + | ||
368 | + e0_true = e0->flags & EDGE_TRUE_VALUE; | ||
369 | + | ||
370 | + *true_edge = e0_true ? e0 : e1; | ||
371 | + *false_edge = e0_true ? e1 : e0; | ||
372 | + | ||
373 | + gcc_assert ((*true_edge)->flags & EDGE_TRUE_VALUE); | ||
374 | + gcc_assert ((*false_edge)->flags & EDGE_FALSE_VALUE); | ||
375 | + | ||
376 | + gcc_assert (((*true_edge)->flags & EDGE_FALLTHRU) == 0); | ||
377 | + gcc_assert (((*false_edge)->flags & EDGE_FALLTHRU) == 0); | ||
378 | +} | ||
379 | + | ||
380 | +/* Analyze bb and store results in ifsc_info struct. */ | ||
381 | + | ||
382 | +static void | ||
383 | +analyze_bb (basic_block bb) | ||
384 | +{ | ||
385 | + gimple stmt = last_stmt (bb); | ||
386 | + tree lhs, rhs, var, constant; | ||
387 | + edge true_edge, false_edge; | ||
388 | + enum tree_code cond_code; | ||
389 | + | ||
390 | + /* Don't redo analysis. */ | ||
391 | + if (BB_IFSC_VALID (bb)) | ||
392 | + return; | ||
393 | + BB_IFSC_VALID (bb) = true; | ||
394 | + | ||
395 | + | ||
396 | + /* bb needs to end in GIMPLE_COND. */ | ||
397 | + if (!stmt || gimple_code (stmt) != GIMPLE_COND) | ||
398 | + return; | ||
399 | + | ||
400 | + /* bb needs to end in EQ_EXPR or NE_EXPR. */ | ||
401 | + cond_code = gimple_cond_code (stmt); | ||
402 | + if (cond_code != EQ_EXPR && cond_code != NE_EXPR) | ||
403 | + return; | ||
404 | + | ||
405 | + lhs = gimple_cond_lhs (stmt); | ||
406 | + rhs = gimple_cond_rhs (stmt); | ||
407 | + | ||
408 | + /* GIMPLE_COND needs to compare variable to constant. */ | ||
409 | + if ((TREE_CONSTANT (lhs) == 0) | ||
410 | + == (TREE_CONSTANT (rhs) == 0)) | ||
411 | + return; | ||
412 | + | ||
413 | + var = TREE_CONSTANT (lhs) ? rhs : lhs; | ||
414 | + constant = TREE_CONSTANT (lhs)? lhs : rhs; | ||
415 | + | ||
416 | + /* Switches cannot handle non-integral types. */ | ||
417 | + if (!INTEGRAL_TYPE_P(TREE_TYPE (var))) | ||
418 | + return; | ||
419 | + | ||
420 | + get_edges (bb, &true_edge, &false_edge); | ||
421 | + | ||
422 | + if (cond_code == NE_EXPR) | ||
423 | + SWAP (edge, true_edge, false_edge); | ||
424 | + | ||
425 | + /* TODO: loosen this constraint. In principle it's ok if true_edge->dest has | ||
426 | + phis, as long as for each phi all the edges coming from the chain have the | ||
427 | + same value. */ | ||
428 | + if (!gimple_seq_empty_p (phi_nodes (true_edge->dest))) | ||
429 | + return; | ||
430 | + | ||
431 | + /* Store analysis in ifsc_info struct. */ | ||
432 | + BB_IFSC_VAR (bb) = var; | ||
433 | + BB_IFSC_COND_CODE (bb) = cond_code; | ||
434 | + BB_IFSC_CONSTANT (bb) = constant; | ||
435 | + BB_IFSC_TRUE_EDGE (bb) = true_edge; | ||
436 | + BB_IFSC_FALSE_EDGE (bb) = false_edge; | ||
437 | +} | ||
438 | + | ||
439 | +/* Grow if-chain forward. */ | ||
440 | + | ||
441 | +static void | ||
442 | +grow_if_chain_forward (struct if_chain *chain) | ||
443 | +{ | ||
444 | + basic_block next_bb; | ||
445 | + | ||
446 | + while (1) | ||
447 | + { | ||
448 | + next_bb = BB_IFSC_FALSE_EDGE (chain->last)->dest; | ||
449 | + | ||
450 | + /* next_bb is already part of another chain. */ | ||
451 | + if (BB_IFSC_CHAINED (next_bb)) | ||
452 | + break; | ||
453 | + | ||
454 | + /* next_bb needs to be dominated by the last bb. */ | ||
455 | + if (!single_pred_p (next_bb)) | ||
456 | + break; | ||
457 | + | ||
458 | + analyze_bb (next_bb); | ||
459 | + | ||
460 | + /* Does next_bb fit in chain? */ | ||
461 | + if (BB_IFSC_VAR (next_bb) != chain->var | ||
462 | + || BB_IFSC_TRUE_EDGE (next_bb)->dest != chain->true_dest) | ||
463 | + break; | ||
464 | + | ||
465 | + /* We can only add empty bbs at the end of the chain. */ | ||
466 | + if (first_stmt (next_bb) != last_stmt (next_bb)) | ||
467 | + break; | ||
468 | + | ||
469 | + /* Add next_bb at end of chain. */ | ||
470 | + VEC_safe_push (tree, heap, chain->constants, BB_IFSC_CONSTANT (next_bb)); | ||
471 | + BB_IFSC_CHAINED (next_bb) = true; | ||
472 | + chain->last = next_bb; | ||
473 | + } | ||
474 | +} | ||
475 | + | ||
476 | +/* Grow if-chain backward. */ | ||
477 | + | ||
478 | +static void | ||
479 | +grow_if_chain_backward (struct if_chain *chain) | ||
480 | +{ | ||
481 | + basic_block prev_bb; | ||
482 | + | ||
483 | + while (1) | ||
484 | + { | ||
485 | + /* First bb is not empty, cannot grow backwards. */ | ||
486 | + if (first_stmt (chain->first) != last_stmt (chain->first)) | ||
487 | + break; | ||
488 | + | ||
489 | + /* First bb has no single predecessor, cannot grow backwards. */ | ||
490 | + if (!single_pred_p (chain->first)) | ||
491 | + break; | ||
492 | + | ||
493 | + prev_bb = single_pred (chain->first); | ||
494 | + | ||
495 | + /* prev_bb is already part of another chain. */ | ||
496 | + if (BB_IFSC_CHAINED (prev_bb)) | ||
497 | + break; | ||
498 | + | ||
499 | + analyze_bb (prev_bb); | ||
500 | + | ||
501 | + /* Does prev_bb fit in chain? */ | ||
502 | + if (BB_IFSC_VAR (prev_bb) != chain->var | ||
503 | + || BB_IFSC_TRUE_EDGE (prev_bb)->dest != chain->true_dest) | ||
504 | + break; | ||
505 | + | ||
506 | + /* Add prev_bb at beginning of chain. */ | ||
507 | + VEC_safe_push (tree, heap, chain->constants, BB_IFSC_CONSTANT (prev_bb)); | ||
508 | + BB_IFSC_CHAINED (prev_bb) = true; | ||
509 | + chain->first = prev_bb; | ||
510 | + } | ||
511 | +} | ||
512 | + | ||
513 | +/* Grow if-chain containing bb. */ | ||
514 | + | ||
515 | +static void | ||
516 | +grow_if_chain (basic_block bb, struct if_chain *chain) | ||
517 | +{ | ||
518 | + /* Initialize chain to empty. */ | ||
519 | + VEC_truncate (tree, chain->constants, 0); | ||
520 | + VEC_truncate (tree, chain->unique_constants, 0); | ||
521 | + | ||
522 | + /* bb is already part of another chain. */ | ||
523 | + if (BB_IFSC_CHAINED (bb)) | ||
524 | + return; | ||
525 | + | ||
526 | + analyze_bb (bb); | ||
527 | + | ||
528 | + /* bb is not fit to be part of a chain. */ | ||
529 | + if (BB_IFSC_VAR (bb) == NULL_TREE) | ||
530 | + return; | ||
531 | + | ||
532 | + /* Set bb as initial part of the chain. */ | ||
533 | + VEC_safe_push (tree, heap, chain->constants, BB_IFSC_CONSTANT (bb)); | ||
534 | + chain->first = chain->last = bb; | ||
535 | + chain->var = BB_IFSC_VAR (bb); | ||
536 | + chain->true_dest = BB_IFSC_TRUE_EDGE (bb)->dest; | ||
537 | + | ||
538 | + /* bb is part of a chain now. */ | ||
539 | + BB_IFSC_CHAINED (bb) = true; | ||
540 | + | ||
541 | + /* Grow chain to its maximum size. */ | ||
542 | + grow_if_chain_forward (chain); | ||
543 | + grow_if_chain_backward (chain); | ||
544 | + | ||
545 | + /* Sort constants and skip duplicates. */ | ||
546 | + sort_constants (chain->constants, &chain->unique_constants); | ||
547 | +} | ||
548 | + | ||
549 | +static void | ||
550 | +dump_tree_vector (VEC (tree, heap) *vec) | ||
551 | +{ | ||
552 | + unsigned int ix; | ||
553 | + tree constant; | ||
554 | + | ||
555 | + for (ix = 0; VEC_iterate (tree, vec, ix, constant); ix++) | ||
556 | + { | ||
557 | + if (ix != 0) | ||
558 | + fprintf (dump_file, " "); | ||
559 | + print_generic_expr (dump_file, constant, 0); | ||
560 | + } | ||
561 | + fprintf (dump_file, "\n"); | ||
562 | +} | ||
563 | + | ||
564 | +/* Dump if-chain to dump_file. */ | ||
565 | + | ||
566 | +static void | ||
567 | +dump_if_chain (struct if_chain *chain) | ||
568 | +{ | ||
569 | + if (!dump_file) | ||
570 | + return; | ||
571 | + | ||
572 | + fprintf (dump_file, "var: "); | ||
573 | + print_generic_expr (dump_file, chain->var, 0); | ||
574 | + fprintf (dump_file, "\n"); | ||
575 | + fprintf (dump_file, "first: <bb %d>\n", chain->first->index); | ||
576 | + fprintf (dump_file, "true: <bb %d>\n", chain->true_dest->index); | ||
577 | + fprintf (dump_file, "last: <bb %d>\n",chain->last->index); | ||
578 | + | ||
579 | + fprintf (dump_file, "constants: "); | ||
580 | + dump_tree_vector (chain->constants); | ||
581 | + | ||
582 | + if (VEC_length (tree, chain->unique_constants) | ||
583 | + != VEC_length (tree, chain->constants)) | ||
584 | + { | ||
585 | + fprintf (dump_file, "unique_constants: "); | ||
586 | + dump_tree_vector (chain->unique_constants); | ||
587 | + } | ||
588 | +} | ||
589 | + | ||
590 | +/* Remove redundant bbs and edges. */ | ||
591 | + | ||
592 | +static void | ||
593 | +remove_redundant_bbs_and_edges (struct if_chain *chain, int *false_prob) | ||
594 | +{ | ||
595 | + basic_block bb, next; | ||
596 | + edge true_edge, false_edge; | ||
597 | + | ||
598 | + for (bb = chain->first;; bb = next) | ||
599 | + { | ||
600 | + true_edge = BB_IFSC_TRUE_EDGE (bb); | ||
601 | + false_edge = BB_IFSC_FALSE_EDGE (bb); | ||
602 | + | ||
603 | + /* Determine next, before we delete false_edge. */ | ||
604 | + next = false_edge->dest; | ||
605 | + | ||
606 | + /* Accumulate probability. */ | ||
607 | + *false_prob = (*false_prob * false_edge->probability) / REG_BR_PROB_BASE; | ||
608 | + | ||
609 | + /* Don't remove the new true_edge. */ | ||
610 | + if (bb != chain->first) | ||
611 | + remove_edge (true_edge); | ||
612 | + | ||
613 | + /* Don't remove the new false_edge. */ | ||
614 | + if (bb != chain->last) | ||
615 | + remove_edge (false_edge); | ||
616 | + | ||
617 | + /* Don't remove the first bb. */ | ||
618 | + if (bb != chain->first) | ||
619 | + delete_basic_block (bb); | ||
620 | + | ||
621 | + /* Stop after last. */ | ||
622 | + if (bb == chain->last) | ||
623 | + break; | ||
624 | + } | ||
625 | +} | ||
626 | + | ||
627 | +/* Update control flow graph. */ | ||
628 | + | ||
629 | +static void | ||
630 | +update_cfg (struct if_chain *chain) | ||
631 | +{ | ||
632 | + edge true_edge, false_edge; | ||
633 | + int false_prob; | ||
634 | + int flags_mask = ~(EDGE_FALLTHRU|EDGE_TRUE_VALUE|EDGE_FALSE_VALUE); | ||
635 | + | ||
636 | + /* We keep these 2 edges, and remove the rest. We need this specific | ||
637 | + false_edge, because a phi in chain->last->dest might reference (the index | ||
638 | + of) this edge. For true_edge, we could pick any of them. */ | ||
639 | + true_edge = BB_IFSC_TRUE_EDGE (chain->first); | ||
640 | + false_edge = BB_IFSC_FALSE_EDGE (chain->last); | ||
641 | + | ||
642 | + /* Update true edge. */ | ||
643 | + true_edge->flags &= flags_mask; | ||
644 | + | ||
645 | + /* Update false edge. */ | ||
646 | + redirect_edge_pred (false_edge, chain->first); | ||
647 | + false_edge->flags &= flags_mask; | ||
648 | + | ||
649 | + false_prob = REG_BR_PROB_BASE; | ||
650 | + remove_redundant_bbs_and_edges (chain, &false_prob); | ||
651 | + | ||
652 | + /* Repair probabilities. */ | ||
653 | + true_edge->probability = REG_BR_PROB_BASE - false_prob; | ||
654 | + false_edge->probability = false_prob; | ||
655 | + | ||
656 | + /* Force recalculation of dominance info. */ | ||
657 | + free_dominance_info (CDI_DOMINATORS); | ||
658 | + free_dominance_info (CDI_POST_DOMINATORS); | ||
659 | +} | ||
660 | + | ||
661 | +/* Create switch statement. Borrows from gimplify_switch_expr. */ | ||
662 | + | ||
663 | +static void | ||
664 | +convert_if_chain_to_switch (struct if_chain *chain) | ||
665 | +{ | ||
666 | + tree label_decl_true, label_decl_false; | ||
667 | + gimple label_true, label_false, gimple_switch; | ||
668 | + gimple_stmt_iterator gsi; | ||
669 | + tree default_case, other_case, constant; | ||
670 | + unsigned int ix; | ||
671 | + VEC (tree, heap) *labels; | ||
672 | + | ||
673 | + labels = VEC_alloc (tree, heap, 8); | ||
674 | + | ||
675 | + /* Create and insert true jump label. */ | ||
676 | + label_decl_true = create_artificial_label (UNKNOWN_LOCATION); | ||
677 | + label_true = gimple_build_label (label_decl_true); | ||
678 | + gsi = gsi_start_bb (chain->true_dest); | ||
679 | + gsi_insert_before (&gsi, label_true, GSI_SAME_STMT); | ||
680 | + | ||
681 | + /* Create and insert false jump label. */ | ||
682 | + label_decl_false = create_artificial_label (UNKNOWN_LOCATION); | ||
683 | + label_false = gimple_build_label (label_decl_false); | ||
684 | + gsi = gsi_start_bb (BB_IFSC_FALSE_EDGE (chain->last)->dest); | ||
685 | + gsi_insert_before (&gsi, label_false, GSI_SAME_STMT); | ||
686 | + | ||
687 | + /* Create default case label. */ | ||
688 | + default_case = build3 (CASE_LABEL_EXPR, void_type_node, | ||
689 | + NULL_TREE, NULL_TREE, | ||
690 | + label_decl_false); | ||
691 | + | ||
692 | + /* Create case labels. */ | ||
693 | + for (ix = 0; VEC_iterate (tree, chain->unique_constants, ix, constant); ix++) | ||
694 | + { | ||
695 | + /* TODO: use ranges, as in gimplify_switch_expr. */ | ||
696 | + other_case = build3 (CASE_LABEL_EXPR, void_type_node, | ||
697 | + constant, NULL_TREE, | ||
698 | + label_decl_true); | ||
699 | + VEC_safe_push (tree, heap, labels, other_case); | ||
700 | + } | ||
701 | + | ||
702 | + /* Create and insert switch. */ | ||
703 | + gimple_switch = gimple_build_switch_vec (chain->var, default_case, labels); | ||
704 | + gsi = gsi_for_stmt (last_stmt (chain->first)); | ||
705 | + gsi_insert_before (&gsi, gimple_switch, GSI_SAME_STMT); | ||
706 | + | ||
707 | + /* Remove now obsolete if. */ | ||
708 | + gsi_remove (&gsi, true); | ||
709 | + | ||
710 | + VEC_free (tree, heap, labels); | ||
711 | +} | ||
712 | + | ||
713 | +/* Allocation and initialization. */ | ||
714 | + | ||
715 | +static void | ||
716 | +init_pass (struct if_chain *chain) | ||
717 | +{ | ||
718 | + alloc_aux_for_blocks (sizeof (struct ifsc_info)); | ||
719 | + | ||
720 | + chain->constants = VEC_alloc (tree, heap, 8); | ||
721 | + chain->unique_constants = VEC_alloc (tree, heap, 8); | ||
722 | +} | ||
723 | + | ||
724 | +/* Deallocation. */ | ||
725 | + | ||
726 | +static void | ||
727 | +finish_pass (struct if_chain *chain) | ||
728 | +{ | ||
729 | + free_aux_for_blocks (); | ||
730 | + | ||
731 | + VEC_free (tree, heap, chain->constants); | ||
732 | + VEC_free (tree, heap, chain->unique_constants); | ||
733 | +} | ||
734 | + | ||
735 | +/* Find if-chains and convert them to switches. */ | ||
736 | + | ||
737 | +static unsigned int | ||
738 | +do_if_to_switch (void) | ||
739 | +{ | ||
740 | + basic_block bb; | ||
741 | + struct if_chain chain; | ||
742 | + unsigned int convert_threshold = PARAM_VALUE (PARAM_IF_TO_SWITCH_THRESHOLD); | ||
743 | + | ||
744 | + init_pass (&chain); | ||
745 | + | ||
746 | + for (bb = cfun->cfg->x_entry_block_ptr->next_bb; | ||
747 | + bb != cfun->cfg->x_exit_block_ptr;) | ||
748 | + { | ||
749 | + grow_if_chain (bb, &chain); | ||
750 | + | ||
751 | + do | ||
752 | + bb = bb->next_bb; | ||
753 | + while (BB_IFSC_CHAINED (bb)); | ||
754 | + | ||
755 | + /* Determine if the chain is long enough. */ | ||
756 | + if (VEC_length (tree, chain.unique_constants) < convert_threshold) | ||
757 | + continue; | ||
758 | + | ||
759 | + dump_if_chain (&chain); | ||
760 | + | ||
761 | + convert_if_chain_to_switch (&chain); | ||
762 | + | ||
763 | + update_cfg (&chain); | ||
764 | + } | ||
765 | + | ||
766 | + finish_pass (&chain); | ||
767 | + | ||
768 | + return 0; | ||
769 | +} | ||
770 | + | ||
771 | +/* The pass gate. */ | ||
772 | + | ||
773 | +static bool | ||
774 | +if_to_switch_gate (void) | ||
775 | +{ | ||
776 | + return flag_tree_if_to_switch_conversion; | ||
777 | +} | ||
778 | + | ||
779 | +/* The pass definition. */ | ||
780 | + | ||
781 | +struct gimple_opt_pass pass_if_to_switch = | ||
782 | +{ | ||
783 | + { | ||
784 | + GIMPLE_PASS, | ||
785 | + "iftoswitch", /* name */ | ||
786 | + if_to_switch_gate, /* gate */ | ||
787 | + do_if_to_switch, /* execute */ | ||
788 | + NULL, /* sub */ | ||
789 | + NULL, /* next */ | ||
790 | + 0, /* static_pass_number */ | ||
791 | + TV_TREE_SWITCH_CONVERSION, /* tv_id */ | ||
792 | + PROP_cfg | PROP_ssa, /* properties_required */ | ||
793 | + 0, /* properties_provided */ | ||
794 | + 0, /* properties_destroyed */ | ||
795 | + 0, /* todo_flags_start */ | ||
796 | + TODO_update_ssa | TODO_dump_func | ||
797 | + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ | ||
798 | + } | ||
799 | +}; | ||
800 | Index: gcc-4_5-branch/gcc/tree-pass.h | ||
801 | =================================================================== | ||
802 | --- gcc-4_5-branch.orig/gcc/tree-pass.h | ||
803 | +++ gcc-4_5-branch/gcc/tree-pass.h | ||
804 | @@ -560,6 +560,7 @@ extern struct gimple_opt_pass pass_inlin | ||
805 | extern struct gimple_opt_pass pass_all_early_optimizations; | ||
806 | extern struct gimple_opt_pass pass_update_address_taken; | ||
807 | extern struct gimple_opt_pass pass_convert_switch; | ||
808 | +extern struct gimple_opt_pass pass_if_to_switch; | ||
809 | |||
810 | /* The root of the compilation pass tree, once constructed. */ | ||
811 | extern struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes, | ||