1 /* If-elseif-else to switch conversion pass
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* Algorithm of the pass runs in the following steps:
21 a) We walk basic blocks in DOMINATOR order so that we first reach
22 a first condition of a future switch.
23 b) We follow false edges of a if-else-chain and we record chain
24 of GIMPLE conditions. These blocks are only used for comparison
25 of a common SSA_NAME and we do not allow any side effect.
26 c) We remove all basic blocks (except first) of such chain and
27 GIMPLE switch replaces the condition in the first basic block.
28 d) We move all GIMPLE statements in the removed blocks into the
33 #include "coretypes.h"
38 #include "tree-pass.h"
40 #include "gimple-pretty-print.h"
41 #include "fold-const.h"
42 #include "gimple-iterator.h"
45 #include "tree-cfgcleanup.h"
47 #include "tree-ssa-loop.h"
48 #include "diagnostic.h"
50 #include "tree-into-ssa.h"
54 #include "alloc-pool.h"
55 #include "tree-switch-conversion.h"
56 #include "tree-ssa-reassoc.h"
59 using namespace tree_switch_conversion
;
63 typedef auto_vec
<std::pair
<gphi
*, tree
>> mapping_vec
;
65 condition_info (gcond
*cond
, bool has_side_effect
): m_cond (cond
),
66 m_bb (gimple_bb (cond
)), m_forwarder_bb (NULL
), m_ranges (),
67 m_true_edge (NULL
), m_false_edge (NULL
),
68 m_true_edge_phi_mapping (), m_false_edge_phi_mapping (),
69 m_has_side_effect (has_side_effect
)
74 /* Recond PHI mapping for an original edge E and save these into
76 void record_phi_mapping (edge e
, mapping_vec
*vec
);
80 basic_block m_forwarder_bb
;
81 auto_vec
<range_entry
> m_ranges
;
84 mapping_vec m_true_edge_phi_mapping
;
85 mapping_vec m_false_edge_phi_mapping
;
86 bool m_has_side_effect
;
89 /* Recond PHI mapping for an original edge E and save these into vector VEC. */
92 condition_info::record_phi_mapping (edge e
, mapping_vec
*vec
)
94 for (gphi_iterator gsi
= gsi_start_phis (e
->dest
); !gsi_end_p (gsi
);
97 gphi
*phi
= gsi
.phi ();
98 tree arg
= PHI_ARG_DEF_FROM_EDGE (phi
, e
);
99 vec
->safe_push (std::make_pair (phi
, arg
));
103 /* Master structure for one if to switch conversion candidate. */
107 /* Default constructor. */
108 if_chain (): m_entries ()
110 m_entries
.create (2);
113 /* Default destructor. */
116 m_entries
.release ();
119 /* Verify that all case ranges do not overlap. */
120 bool check_non_overlapping_cases ();
122 /* Return true when the switch can be expanded with a jump table or
123 a bit test (at least partially). */
124 bool is_beneficial ();
126 /* If chain entries. */
127 vec
<condition_info
*> m_entries
;
130 /* Compare two case ranges by minimum value. */
133 range_cmp (const void *a
, const void *b
)
135 const range_entry
*re1
= *(const range_entry
* const *) a
;
136 const range_entry
*re2
= *(const range_entry
* const *) b
;
138 return tree_int_cst_compare (re1
->low
, re2
->low
);
141 /* Verify that all case ranges do not overlap. */
144 if_chain::check_non_overlapping_cases ()
146 auto_vec
<range_entry
*> all_ranges
;
147 for (unsigned i
= 0; i
< m_entries
.length (); i
++)
148 for (unsigned j
= 0; j
< m_entries
[i
]->m_ranges
.length (); j
++)
149 all_ranges
.safe_push (&m_entries
[i
]->m_ranges
[j
]);
151 all_ranges
.qsort (range_cmp
);
153 for (unsigned i
= 0; i
< all_ranges
.length () - 1; i
++)
155 range_entry
*left
= all_ranges
[i
];
156 range_entry
*right
= all_ranges
[i
+ 1];
157 if (tree_int_cst_le (left
->low
, right
->low
)
158 && tree_int_cst_le (right
->low
, left
->high
))
165 /* Compare clusters by minimum value. */
168 cluster_cmp (const void *a
, const void *b
)
170 simple_cluster
*sc1
= *(simple_cluster
* const *) a
;
171 simple_cluster
*sc2
= *(simple_cluster
* const *) b
;
173 return tree_int_cst_compare (sc1
->get_low (), sc2
->get_high ());
176 /* Dump constructed CLUSTERS with prefix MESSAGE. */
179 dump_clusters (vec
<cluster
*> *clusters
, const char *message
)
183 fprintf (dump_file
, ";; %s: ", message
);
184 for (unsigned i
= 0; i
< clusters
->length (); i
++)
185 (*clusters
)[i
]->dump (dump_file
, dump_flags
& TDF_DETAILS
);
186 fprintf (dump_file
, "\n");
190 /* Return true when the switch can be expanded with a jump table or
191 a bit test (at least partially). */
194 if_chain::is_beneficial ()
196 profile_probability prob
= profile_probability::uninitialized ();
198 auto_vec
<cluster
*> clusters
;
199 clusters
.create (m_entries
.length ());
201 for (unsigned i
= 0; i
< m_entries
.length (); i
++)
203 condition_info
*info
= m_entries
[i
];
204 for (unsigned j
= 0; j
< info
->m_ranges
.length (); j
++)
206 range_entry
*range
= &info
->m_ranges
[j
];
207 basic_block bb
= info
->m_true_edge
->dest
;
208 bool has_forwarder
= !info
->m_true_edge_phi_mapping
.is_empty ();
209 clusters
.safe_push (new simple_cluster (range
->low
, range
->high
,
215 /* Sort clusters and merge them. */
216 auto_vec
<cluster
*> filtered_clusters
;
217 filtered_clusters
.create (16);
218 clusters
.qsort (cluster_cmp
);
219 simple_cluster
*left
= static_cast<simple_cluster
*> (clusters
[0]);
220 filtered_clusters
.safe_push (left
);
222 for (unsigned i
= 1; i
< clusters
.length (); i
++)
224 simple_cluster
*right
= static_cast<simple_cluster
*> (clusters
[i
]);
225 tree type
= TREE_TYPE (left
->get_low ());
226 if (!left
->m_has_forward_bb
227 && !right
->m_has_forward_bb
228 && left
->m_case_bb
== right
->m_case_bb
)
230 if (wi::eq_p (wi::to_wide (right
->get_low ()) - wi::to_wide
231 (left
->get_high ()), wi::one (TYPE_PRECISION (type
))))
233 left
->set_high (right
->get_high ());
239 left
= static_cast<simple_cluster
*> (clusters
[i
]);
240 filtered_clusters
.safe_push (left
);
243 dump_clusters (&filtered_clusters
, "Canonical GIMPLE case clusters");
245 vec
<cluster
*> output
246 = jump_table_cluster::find_jump_tables (filtered_clusters
);
247 bool r
= output
.length () < filtered_clusters
.length ();
250 dump_clusters (&output
, "JT can be built");
251 release_clusters (output
);
257 output
= bit_test_cluster::find_bit_tests (filtered_clusters
);
258 r
= output
.length () < filtered_clusters
.length ();
260 dump_clusters (&output
, "BT can be built");
262 release_clusters (output
);
266 /* Build case label with MIN and MAX values of a given basic block DEST. */
269 build_case_label (tree index_type
, tree min
, tree max
, basic_block dest
)
271 if (min
!= NULL_TREE
&& index_type
!= TREE_TYPE (min
))
272 min
= fold_convert (index_type
, min
);
273 if (max
!= NULL_TREE
&& index_type
!= TREE_TYPE (max
))
274 max
= fold_convert (index_type
, max
);
276 tree label
= gimple_block_label (dest
);
277 return build_case_label (min
, min
== max
? NULL_TREE
: max
, label
);
280 /* Compare two integer constants. */
283 label_cmp (const void *a
, const void *b
)
285 const_tree l1
= *(const const_tree
*) a
;
286 const_tree l2
= *(const const_tree
*) b
;
288 return tree_int_cst_compare (CASE_LOW (l1
), CASE_LOW (l2
));
291 /* Convert a given if CHAIN into a switch GIMPLE statement. */
294 convert_if_conditions_to_switch (if_chain
*chain
)
296 if (!dbg_cnt (if_to_switch
))
299 auto_vec
<tree
> labels
;
300 unsigned entries
= chain
->m_entries
.length ();
301 condition_info
*first_cond
= chain
->m_entries
[0];
302 condition_info
*last_cond
= chain
->m_entries
[entries
- 1];
304 edge default_edge
= last_cond
->m_false_edge
;
305 basic_block default_bb
= default_edge
->dest
;
307 gimple_stmt_iterator gsi
= gsi_for_stmt (first_cond
->m_cond
);
308 tree index_type
= TREE_TYPE (first_cond
->m_ranges
[0].exp
);
309 for (unsigned i
= 0; i
< entries
; i
++)
311 condition_info
*info
= chain
->m_entries
[i
];
312 basic_block case_bb
= info
->m_true_edge
->dest
;
314 /* Create a forwarder block if needed. */
315 if (!info
->m_true_edge_phi_mapping
.is_empty ())
317 info
->m_forwarder_bb
= split_edge (info
->m_true_edge
);
318 case_bb
= info
->m_forwarder_bb
;
321 for (unsigned j
= 0; j
< info
->m_ranges
.length (); j
++)
322 labels
.safe_push (build_case_label (index_type
,
323 info
->m_ranges
[j
].low
,
324 info
->m_ranges
[j
].high
,
326 default_bb
= info
->m_false_edge
->dest
;
330 remove_edge (first_cond
->m_true_edge
);
331 remove_edge (first_cond
->m_false_edge
);
334 delete_basic_block (info
->m_bb
);
336 make_edge (first_cond
->m_bb
, case_bb
, 0);
339 labels
.qsort (label_cmp
);
341 edge e
= find_edge (first_cond
->m_bb
, default_bb
);
343 e
= make_edge (first_cond
->m_bb
, default_bb
, 0);
345 = gimple_build_switch (first_cond
->m_ranges
[0].exp
,
346 build_case_label (index_type
, NULL_TREE
,
347 NULL_TREE
, default_bb
),
350 gsi_remove (&gsi
, true);
351 gsi_insert_before (&gsi
, s
, GSI_NEW_STMT
);
355 fprintf (dump_file
, "Expanded into a new gimple STMT: ");
356 print_gimple_stmt (dump_file
, s
, 0, TDF_SLIM
);
357 putc ('\n', dump_file
);
360 /* Fill up missing PHI node arguments. */
361 for (unsigned i
= 0; i
< chain
->m_entries
.length (); ++i
)
363 condition_info
*info
= chain
->m_entries
[i
];
364 for (unsigned j
= 0; j
< info
->m_true_edge_phi_mapping
.length (); ++j
)
366 std::pair
<gphi
*, tree
> item
= info
->m_true_edge_phi_mapping
[j
];
367 add_phi_arg (item
.first
, item
.second
,
368 single_succ_edge (info
->m_forwarder_bb
),
373 /* Fill up missing PHI nodes for the default BB. */
374 for (unsigned j
= 0; j
< last_cond
->m_false_edge_phi_mapping
.length (); ++j
)
376 std::pair
<gphi
*, tree
> item
= last_cond
->m_false_edge_phi_mapping
[j
];
377 add_phi_arg (item
.first
, item
.second
, e
, UNKNOWN_LOCATION
);
381 /* Identify an index variable used in BB in a GIMPLE condition.
382 Save information about the condition into CONDITIONS_IN_BBS. */
385 find_conditions (basic_block bb
,
386 hash_map
<basic_block
, condition_info
*> *conditions_in_bbs
)
388 gimple_stmt_iterator gsi
= gsi_last_nondebug_bb (bb
);
392 gcond
*cond
= dyn_cast
<gcond
*> (gsi_stmt (gsi
));
396 tree lhs
= gimple_cond_lhs (cond
);
397 tree rhs
= gimple_cond_rhs (cond
);
398 tree_code code
= gimple_cond_code (cond
);
400 condition_info
*info
= new condition_info (cond
, !no_side_effect_bb (bb
));
404 && TREE_CODE (lhs
) == SSA_NAME
405 && (def
= dyn_cast
<gassign
*> (SSA_NAME_DEF_STMT (lhs
))) != NULL
406 && integer_zerop (rhs
))
408 enum tree_code rhs_code
= gimple_assign_rhs_code (def
);
409 if (rhs_code
== BIT_IOR_EXPR
)
411 info
->m_ranges
.safe_grow (2, true);
412 init_range_entry (&info
->m_ranges
[0], gimple_assign_rhs1 (def
), NULL
);
413 init_range_entry (&info
->m_ranges
[1], gimple_assign_rhs2 (def
), NULL
);
418 info
->m_ranges
.safe_grow (1, true);
419 init_range_entry (&info
->m_ranges
[0], NULL_TREE
, cond
);
422 /* All identified ranges must have equal expression and IN_P flag. */
423 if (!info
->m_ranges
.is_empty ())
425 edge true_edge
, false_edge
;
426 tree expr
= info
->m_ranges
[0].exp
;
427 bool in_p
= info
->m_ranges
[0].in_p
;
429 extract_true_false_edges_from_block (bb
, &true_edge
, &false_edge
);
430 info
->m_true_edge
= in_p
? true_edge
: false_edge
;
431 info
->m_false_edge
= in_p
? false_edge
: true_edge
;
433 for (unsigned i
= 0; i
< info
->m_ranges
.length (); ++i
)
434 if (info
->m_ranges
[i
].exp
== NULL_TREE
435 || !INTEGRAL_TYPE_P (TREE_TYPE (info
->m_ranges
[i
].exp
))
436 || info
->m_ranges
[i
].low
== NULL_TREE
437 || info
->m_ranges
[i
].high
== NULL_TREE
438 || (TYPE_PRECISION (TREE_TYPE (info
->m_ranges
[i
].low
))
439 != TYPE_PRECISION (TREE_TYPE (info
->m_ranges
[i
].high
))))
442 for (unsigned i
= 1; i
< info
->m_ranges
.length (); ++i
)
443 if (info
->m_ranges
[i
].exp
!= expr
444 || info
->m_ranges
[i
].in_p
!= in_p
)
447 info
->record_phi_mapping (info
->m_true_edge
,
448 &info
->m_true_edge_phi_mapping
);
449 info
->record_phi_mapping (info
->m_false_edge
,
450 &info
->m_false_edge_phi_mapping
);
451 conditions_in_bbs
->put (bb
, info
);
461 const pass_data pass_data_if_to_switch
=
463 GIMPLE_PASS
, /* type */
464 "iftoswitch", /* name */
465 OPTGROUP_NONE
, /* optinfo_flags */
466 TV_TREE_IF_TO_SWITCH
, /* tv_id */
467 ( PROP_cfg
| PROP_ssa
), /* properties_required */
468 0, /* properties_provided */
469 0, /* properties_destroyed */
470 0, /* todo_flags_start */
471 TODO_update_ssa
/* todo_flags_finish */
474 class pass_if_to_switch
: public gimple_opt_pass
477 pass_if_to_switch (gcc::context
*ctxt
)
478 : gimple_opt_pass (pass_data_if_to_switch
, ctxt
)
481 /* opt_pass methods: */
482 bool gate (function
*) final override
484 return (jump_table_cluster::is_enabled ()
485 || bit_test_cluster::is_enabled ());
488 unsigned int execute (function
*) final override
;
490 }; // class pass_if_to_switch
493 pass_if_to_switch::execute (function
*fun
)
495 auto_vec
<if_chain
*> all_candidates
;
496 hash_map
<basic_block
, condition_info
*> conditions_in_bbs
;
498 mark_ssa_maybe_undefs ();
501 FOR_EACH_BB_FN (bb
, fun
)
502 find_conditions (bb
, &conditions_in_bbs
);
504 if (conditions_in_bbs
.is_empty ())
507 int *rpo
= XNEWVEC (int, n_basic_blocks_for_fn (fun
));
508 unsigned n
= pre_and_rev_post_order_compute_fn (fun
, NULL
, rpo
, false);
510 auto_bitmap seen_bbs
;
511 for (int i
= n
- 1; i
>= 0; --i
)
513 basic_block bb
= BASIC_BLOCK_FOR_FN (fun
, rpo
[i
]);
514 if (bitmap_bit_p (seen_bbs
, bb
->index
))
517 bitmap_set_bit (seen_bbs
, bb
->index
);
518 condition_info
**slot
= conditions_in_bbs
.get (bb
);
521 condition_info
*info
= *slot
;
522 if_chain
*chain
= new if_chain ();
523 chain
->m_entries
.safe_push (info
);
524 /* Try to find a chain starting in this BB. */
527 if (!single_pred_p (gimple_bb (info
->m_cond
)))
529 edge e
= single_pred_edge (gimple_bb (info
->m_cond
));
530 condition_info
**info2
= conditions_in_bbs
.get (e
->src
);
531 if (!info2
|| info
->m_ranges
[0].exp
!= (*info2
)->m_ranges
[0].exp
)
534 /* It is important that the blocks are linked through FALSE_EDGE.
535 For an expression of index != VALUE, true and false edges
537 if ((*info2
)->m_false_edge
!= e
)
540 /* Only the first BB in a chain can have a side effect. */
541 if (info
->m_has_side_effect
)
544 chain
->m_entries
.safe_push (*info2
);
545 bitmap_set_bit (seen_bbs
, e
->src
->index
);
549 chain
->m_entries
.reverse ();
550 if (chain
->m_entries
.length () >= 2
551 && chain
->check_non_overlapping_cases ()
552 && chain
->is_beneficial ())
554 gcond
*cond
= chain
->m_entries
[0]->m_cond
;
555 if (dump_enabled_p ())
556 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS
, cond
,
557 "Condition chain with %d BBs "
558 "transformed into a switch statement.\n",
559 chain
->m_entries
.length ());
560 all_candidates
.safe_push (chain
);
567 for (unsigned i
= 0; i
< all_candidates
.length (); i
++)
569 convert_if_conditions_to_switch (all_candidates
[i
]);
570 delete all_candidates
[i
];
575 for (hash_map
<basic_block
, condition_info
*>::iterator it
576 = conditions_in_bbs
.begin (); it
!= conditions_in_bbs
.end (); ++it
)
579 if (!all_candidates
.is_empty ())
581 free_dominance_info (CDI_DOMINATORS
);
582 return TODO_cleanup_cfg
;
591 make_pass_if_to_switch (gcc::context
*ctxt
)
593 return new pass_if_to_switch (ctxt
);