summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch
diff options
context:
space:
mode:
authorKoen Kooi <koen@dominion.thruhere.net>2011-03-17 21:41:22 +0100
committerKoen Kooi <koen@dominion.thruhere.net>2011-03-17 21:41:22 +0100
commitc58cc7d3796dcee6e93885c835ed04cb566abeb2 (patch)
tree3eea4d4ef6a4ef79e0f4e025d7012c1a5cc38835 /meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99468.patch
parenteec6ab97f712e06eb52c9f7c99e19ffab3ce9d74 (diff)
downloadmeta-openembedded-c58cc7d3796dcee6e93885c835ed04cb566abeb2.tar.gz
move layer into meta-oe in preparation for future splits
As per TSC decision Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
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.patch811
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 @@
12010-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'
19Index: 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) \
43Index: 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
58Index: 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
104Index: 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;
116Index: 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
132Index: 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);
152Index: 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+};
800Index: 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,