]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gimple-if-to-switch.cc
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / gimple-if-to-switch.cc
CommitLineData
03eb0929 1/* If-elseif-else to switch conversion pass
99dee823 2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
03eb0929
ML
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
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
29 first one. */
30
31#include "config.h"
32#include "system.h"
33#include "coretypes.h"
34#include "backend.h"
35#include "rtl.h"
36#include "tree.h"
37#include "gimple.h"
38#include "tree-pass.h"
39#include "ssa.h"
40#include "gimple-pretty-print.h"
41#include "fold-const.h"
42#include "gimple-iterator.h"
43#include "tree-cfg.h"
44#include "tree-dfa.h"
45#include "tree-cfgcleanup.h"
46#include "alias.h"
47#include "tree-ssa-loop.h"
48#include "diagnostic.h"
49#include "cfghooks.h"
50#include "tree-into-ssa.h"
51#include "cfganal.h"
52#include "dbgcnt.h"
53#include "target.h"
54#include "alloc-pool.h"
55#include "tree-switch-conversion.h"
56#include "tree-ssa-reassoc.h"
57
58using namespace tree_switch_conversion;
59
60struct condition_info
61{
fa4586d8 62 typedef auto_vec<std::pair<gphi *, tree>> mapping_vec;
03eb0929
ML
63
64 condition_info (gcond *cond): m_cond (cond), m_bb (gimple_bb (cond)),
65 m_forwarder_bb (NULL), m_ranges (), m_true_edge (NULL), m_false_edge (NULL),
66 m_true_edge_phi_mapping (), m_false_edge_phi_mapping ()
67 {
68 m_ranges.create (0);
69 }
70
71 /* Recond PHI mapping for an original edge E and save these into
72 vector VEC. */
73 void record_phi_mapping (edge e, mapping_vec *vec);
74
75 gcond *m_cond;
76 basic_block m_bb;
77 basic_block m_forwarder_bb;
fa4586d8 78 auto_vec<range_entry> m_ranges;
03eb0929
ML
79 edge m_true_edge;
80 edge m_false_edge;
81 mapping_vec m_true_edge_phi_mapping;
82 mapping_vec m_false_edge_phi_mapping;
83};
84
85/* Recond PHI mapping for an original edge E and save these into vector VEC. */
86
87void
88condition_info::record_phi_mapping (edge e, mapping_vec *vec)
89{
90 for (gphi_iterator gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi);
91 gsi_next (&gsi))
92 {
93 gphi *phi = gsi.phi ();
7875e8dc
ML
94 tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
95 vec->safe_push (std::make_pair (phi, arg));
03eb0929
ML
96 }
97}
98
99/* Master structure for one if to switch conversion candidate. */
100
101struct if_chain
102{
103 /* Default constructor. */
104 if_chain (): m_entries ()
105 {
106 m_entries.create (2);
107 }
108
109 /* Default destructor. */
110 ~if_chain ()
111 {
112 m_entries.release ();
113 }
114
115 /* Verify that all case ranges do not overlap. */
116 bool check_non_overlapping_cases ();
117
118 /* Return true when the switch can be expanded with a jump table or
119 a bit test (at least partially). */
120 bool is_beneficial ();
121
122 /* If chain entries. */
123 vec<condition_info *> m_entries;
124};
125
126/* Compare two case ranges by minimum value. */
127
128static int
129range_cmp (const void *a, const void *b)
130{
131 const range_entry *re1 = *(const range_entry * const *) a;
132 const range_entry *re2 = *(const range_entry * const *) b;
133
134 return tree_int_cst_compare (re1->low, re2->low);
135}
136
137/* Verify that all case ranges do not overlap. */
138
139bool
140if_chain::check_non_overlapping_cases ()
141{
142 auto_vec<range_entry *> all_ranges;
143 for (unsigned i = 0; i < m_entries.length (); i++)
144 for (unsigned j = 0; j < m_entries[i]->m_ranges.length (); j++)
145 all_ranges.safe_push (&m_entries[i]->m_ranges[j]);
146
147 all_ranges.qsort (range_cmp);
148
149 for (unsigned i = 0; i < all_ranges.length () - 1; i++)
150 {
151 range_entry *left = all_ranges[i];
152 range_entry *right = all_ranges[i + 1];
153 if (tree_int_cst_le (left->low, right->low)
154 && tree_int_cst_le (right->low, left->high))
155 return false;
156 }
157
158 return true;
159}
160
161/* Compare clusters by minimum value. */
162
163static int
164cluster_cmp (const void *a, const void *b)
165{
166 simple_cluster *sc1 = *(simple_cluster * const *) a;
167 simple_cluster *sc2 = *(simple_cluster * const *) b;
168
169 return tree_int_cst_compare (sc1->get_low (), sc2->get_high ());
170}
171
172/* Dump constructed CLUSTERS with prefix MESSAGE. */
173
174static void
175dump_clusters (vec<cluster *> *clusters, const char *message)
176{
177 if (dump_file)
178 {
179 fprintf (dump_file, ";; %s: ", message);
180 for (unsigned i = 0; i < clusters->length (); i++)
181 (*clusters)[i]->dump (dump_file, dump_flags & TDF_DETAILS);
182 fprintf (dump_file, "\n");
183 }
184}
185
186/* Return true when the switch can be expanded with a jump table or
187 a bit test (at least partially). */
188
189bool
190if_chain::is_beneficial ()
191{
192 profile_probability prob = profile_probability::uninitialized ();
193
194 auto_vec<cluster *> clusters;
195 clusters.create (m_entries.length ());
196
197 for (unsigned i = 0; i < m_entries.length (); i++)
198 {
199 condition_info *info = m_entries[i];
200 for (unsigned j = 0; j < info->m_ranges.length (); j++)
201 {
202 range_entry *range = &info->m_ranges[j];
203 basic_block bb = info->m_true_edge->dest;
204 bool has_forwarder = !info->m_true_edge_phi_mapping.is_empty ();
205 clusters.safe_push (new simple_cluster (range->low, range->high,
206 NULL_TREE, bb, prob,
207 has_forwarder));
208 }
209 }
210
211 /* Sort clusters and merge them. */
212 auto_vec<cluster *> filtered_clusters;
213 filtered_clusters.create (16);
214 clusters.qsort (cluster_cmp);
215 simple_cluster *left = static_cast<simple_cluster *> (clusters[0]);
216 filtered_clusters.safe_push (left);
217
218 for (unsigned i = 1; i < clusters.length (); i++)
219 {
220 simple_cluster *right = static_cast<simple_cluster *> (clusters[i]);
221 tree type = TREE_TYPE (left->get_low ());
222 if (!left->m_has_forward_bb
223 && !right->m_has_forward_bb
224 && left->m_case_bb == right->m_case_bb)
225 {
226 if (wi::eq_p (wi::to_wide (right->get_low ()) - wi::to_wide
227 (left->get_high ()), wi::one (TYPE_PRECISION (type))))
228 {
229 left->set_high (right->get_high ());
57d1b68d 230 delete right;
03eb0929
ML
231 continue;
232 }
233 }
234
235 left = static_cast<simple_cluster *> (clusters[i]);
236 filtered_clusters.safe_push (left);
237 }
238
239 dump_clusters (&filtered_clusters, "Canonical GIMPLE case clusters");
240
241 vec<cluster *> output
242 = jump_table_cluster::find_jump_tables (filtered_clusters);
243 bool r = output.length () < filtered_clusters.length ();
244 if (r)
57d1b68d
ML
245 {
246 dump_clusters (&output, "JT can be built");
247 release_clusters (output);
248 return true;
249 }
250 else
251 output.release ();
03eb0929
ML
252
253 output = bit_test_cluster::find_bit_tests (filtered_clusters);
254 r = output.length () < filtered_clusters.length ();
255 if (r)
256 dump_clusters (&output, "BT can be built");
fa4586d8 257
57d1b68d 258 release_clusters (output);
03eb0929
ML
259 return r;
260}
261
262/* Build case label with MIN and MAX values of a given basic block DEST. */
263
264static tree
265build_case_label (tree index_type, tree min, tree max, basic_block dest)
266{
267 if (min != NULL_TREE && index_type != TREE_TYPE (min))
268 min = fold_convert (index_type, min);
269 if (max != NULL_TREE && index_type != TREE_TYPE (max))
270 max = fold_convert (index_type, max);
271
272 tree label = gimple_block_label (dest);
273 return build_case_label (min, min == max ? NULL_TREE : max, label);
274}
275
276/* Compare two integer constants. */
277
278static int
279label_cmp (const void *a, const void *b)
280{
281 const_tree l1 = *(const const_tree *) a;
282 const_tree l2 = *(const const_tree *) b;
283
284 return tree_int_cst_compare (CASE_LOW (l1), CASE_LOW (l2));
285}
286
287/* Convert a given if CHAIN into a switch GIMPLE statement. */
288
289static void
290convert_if_conditions_to_switch (if_chain *chain)
291{
292 if (!dbg_cnt (if_to_switch))
293 return;
294
295 auto_vec<tree> labels;
296 unsigned entries = chain->m_entries.length ();
297 condition_info *first_cond = chain->m_entries[0];
298 condition_info *last_cond = chain->m_entries[entries - 1];
299
300 edge default_edge = last_cond->m_false_edge;
301 basic_block default_bb = default_edge->dest;
302
303 gimple_stmt_iterator gsi = gsi_for_stmt (first_cond->m_cond);
304 tree index_type = TREE_TYPE (first_cond->m_ranges[0].exp);
305 for (unsigned i = 0; i < entries; i++)
306 {
307 condition_info *info = chain->m_entries[i];
308 basic_block case_bb = info->m_true_edge->dest;
309
310 /* Create a forwarder block if needed. */
311 if (!info->m_true_edge_phi_mapping.is_empty ())
312 {
313 info->m_forwarder_bb = split_edge (info->m_true_edge);
314 case_bb = info->m_forwarder_bb;
315 }
316
317 for (unsigned j = 0; j < info->m_ranges.length (); j++)
318 labels.safe_push (build_case_label (index_type,
319 info->m_ranges[j].low,
320 info->m_ranges[j].high,
321 case_bb));
322 default_bb = info->m_false_edge->dest;
323
324 if (i == 0)
325 {
326 remove_edge (first_cond->m_true_edge);
327 remove_edge (first_cond->m_false_edge);
328 }
329 else
330 delete_basic_block (info->m_bb);
331
332 make_edge (first_cond->m_bb, case_bb, 0);
333 }
334
335 labels.qsort (label_cmp);
336
337 edge e = find_edge (first_cond->m_bb, default_bb);
338 if (e == NULL)
339 e = make_edge (first_cond->m_bb, default_bb, 0);
340 gswitch *s
341 = gimple_build_switch (first_cond->m_ranges[0].exp,
342 build_case_label (index_type, NULL_TREE,
343 NULL_TREE, default_bb),
344 labels);
345
346 gsi_remove (&gsi, true);
347 gsi_insert_before (&gsi, s, GSI_NEW_STMT);
348
349 if (dump_file)
350 {
351 fprintf (dump_file, "Expanded into a new gimple STMT: ");
352 print_gimple_stmt (dump_file, s, 0, TDF_SLIM);
353 putc ('\n', dump_file);
354 }
355
356 /* Fill up missing PHI node arguments. */
357 for (unsigned i = 0; i < chain->m_entries.length (); ++i)
358 {
359 condition_info *info = chain->m_entries[i];
360 for (unsigned j = 0; j < info->m_true_edge_phi_mapping.length (); ++j)
361 {
362 std::pair<gphi *, tree> item = info->m_true_edge_phi_mapping[j];
363 add_phi_arg (item.first, item.second,
364 single_succ_edge (info->m_forwarder_bb),
365 UNKNOWN_LOCATION);
366 }
367 }
368
369 /* Fill up missing PHI nodes for the default BB. */
370 for (unsigned j = 0; j < last_cond->m_false_edge_phi_mapping.length (); ++j)
371 {
372 std::pair<gphi *, tree> item = last_cond->m_false_edge_phi_mapping[j];
373 add_phi_arg (item.first, item.second, e, UNKNOWN_LOCATION);
374 }
375}
376
377/* Identify an index variable used in BB in a GIMPLE condition.
378 Save information about the condition into CONDITIONS_IN_BBS. */
379
380static void
381find_conditions (basic_block bb,
fa4586d8 382 hash_map<basic_block, condition_info *> *conditions_in_bbs)
03eb0929
ML
383{
384 gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
385 if (gsi_end_p (gsi))
386 return;
387
388 gcond *cond = dyn_cast<gcond *> (gsi_stmt (gsi));
389 if (cond == NULL)
390 return;
391
392 if (!no_side_effect_bb (bb))
393 return;
394
395 tree lhs = gimple_cond_lhs (cond);
396 tree rhs = gimple_cond_rhs (cond);
397 tree_code code = gimple_cond_code (cond);
398
fa4586d8 399 condition_info *info = new condition_info (cond);
03eb0929
ML
400
401 gassign *def;
402 if (code == NE_EXPR
403 && TREE_CODE (lhs) == SSA_NAME
404 && (def = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (lhs))) != NULL
405 && integer_zerop (rhs))
406 {
407 enum tree_code rhs_code = gimple_assign_rhs_code (def);
408 if (rhs_code == BIT_IOR_EXPR)
409 {
fa4586d8
ML
410 info->m_ranges.safe_grow (2, true);
411 init_range_entry (&info->m_ranges[0], gimple_assign_rhs1 (def), NULL);
412 init_range_entry (&info->m_ranges[1], gimple_assign_rhs2 (def), NULL);
03eb0929
ML
413 }
414 }
415 else
416 {
fa4586d8
ML
417 info->m_ranges.safe_grow (1, true);
418 init_range_entry (&info->m_ranges[0], NULL_TREE, cond);
03eb0929
ML
419 }
420
421 /* All identified ranges must have equal expression and IN_P flag. */
fa4586d8 422 if (!info->m_ranges.is_empty ())
03eb0929
ML
423 {
424 edge true_edge, false_edge;
fa4586d8
ML
425 tree expr = info->m_ranges[0].exp;
426 bool in_p = info->m_ranges[0].in_p;
03eb0929
ML
427
428 extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
fa4586d8
ML
429 info->m_true_edge = in_p ? true_edge : false_edge;
430 info->m_false_edge = in_p ? false_edge : true_edge;
431
432 for (unsigned i = 0; i < info->m_ranges.length (); ++i)
433 if (info->m_ranges[i].exp == NULL_TREE
434 || !INTEGRAL_TYPE_P (TREE_TYPE (info->m_ranges[i].exp))
435 || info->m_ranges[i].low == NULL_TREE
436 || info->m_ranges[i].high == NULL_TREE
437 || (TYPE_PRECISION (TREE_TYPE (info->m_ranges[i].low))
438 != TYPE_PRECISION (TREE_TYPE (info->m_ranges[i].high))))
439 goto exit;
440
441 for (unsigned i = 1; i < info->m_ranges.length (); ++i)
442 if (info->m_ranges[i].exp != expr
443 || info->m_ranges[i].in_p != in_p)
444 goto exit;
445
446 info->record_phi_mapping (info->m_true_edge,
447 &info->m_true_edge_phi_mapping);
448 info->record_phi_mapping (info->m_false_edge,
449 &info->m_false_edge_phi_mapping);
03eb0929 450 conditions_in_bbs->put (bb, info);
5da5d8a0 451 return;
03eb0929
ML
452 }
453
fa4586d8
ML
454exit:
455 delete info;
03eb0929
ML
456}
457
458namespace {
459
460const pass_data pass_data_if_to_switch =
461{
462 GIMPLE_PASS, /* type */
463 "iftoswitch", /* name */
464 OPTGROUP_NONE, /* optinfo_flags */
465 TV_TREE_IF_TO_SWITCH, /* tv_id */
466 ( PROP_cfg | PROP_ssa ), /* properties_required */
467 0, /* properties_provided */
468 0, /* properties_destroyed */
469 0, /* todo_flags_start */
7875e8dc 470 TODO_update_ssa /* todo_flags_finish */
03eb0929
ML
471};
472
473class pass_if_to_switch : public gimple_opt_pass
474{
475public:
476 pass_if_to_switch (gcc::context *ctxt)
477 : gimple_opt_pass (pass_data_if_to_switch, ctxt)
478 {}
479
480 /* opt_pass methods: */
481 virtual bool gate (function *)
482 {
483 return (jump_table_cluster::is_enabled ()
484 || bit_test_cluster::is_enabled ());
485 }
486
487 virtual unsigned int execute (function *);
488
489}; // class pass_if_to_switch
490
491unsigned int
492pass_if_to_switch::execute (function *fun)
493{
494 auto_vec<if_chain *> all_candidates;
fa4586d8 495 hash_map<basic_block, condition_info *> conditions_in_bbs;
03eb0929
ML
496
497 basic_block bb;
498 FOR_EACH_BB_FN (bb, fun)
499 find_conditions (bb, &conditions_in_bbs);
500
501 if (conditions_in_bbs.is_empty ())
502 return 0;
503
504 int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
505 unsigned n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, false);
506
507 auto_bitmap seen_bbs;
508 for (int i = n - 1; i >= 0; --i)
509 {
510 basic_block bb = BASIC_BLOCK_FOR_FN (fun, rpo[i]);
511 if (bitmap_bit_p (seen_bbs, bb->index))
512 continue;
513
514 bitmap_set_bit (seen_bbs, bb->index);
fa4586d8
ML
515 condition_info **slot = conditions_in_bbs.get (bb);
516 if (slot)
03eb0929 517 {
fa4586d8 518 condition_info *info = *slot;
03eb0929
ML
519 if_chain *chain = new if_chain ();
520 chain->m_entries.safe_push (info);
521 /* Try to find a chain starting in this BB. */
522 while (true)
523 {
524 if (!single_pred_p (gimple_bb (info->m_cond)))
525 break;
526 edge e = single_pred_edge (gimple_bb (info->m_cond));
fa4586d8
ML
527 condition_info **info2 = conditions_in_bbs.get (e->src);
528 if (!info2 || info->m_ranges[0].exp != (*info2)->m_ranges[0].exp)
03eb0929
ML
529 break;
530
f7251a2c
ML
531 /* It is important that the blocks are linked through FALSE_EDGE.
532 For an expression of index != VALUE, true and false edges
533 are flipped. */
fa4586d8 534 if ((*info2)->m_false_edge != e)
f7251a2c
ML
535 break;
536
fa4586d8 537 chain->m_entries.safe_push (*info2);
03eb0929 538 bitmap_set_bit (seen_bbs, e->src->index);
fa4586d8 539 info = *info2;
03eb0929
ML
540 }
541
542 chain->m_entries.reverse ();
c961e949 543 if (chain->m_entries.length () >= 2
03eb0929
ML
544 && chain->check_non_overlapping_cases ()
545 && chain->is_beneficial ())
546 {
547 gcond *cond = chain->m_entries[0]->m_cond;
548 if (dump_enabled_p ())
549 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, cond,
550 "Condition chain with %d BBs "
551 "transformed into a switch statement.\n",
552 chain->m_entries.length ());
553 all_candidates.safe_push (chain);
554 }
fa4586d8
ML
555 else
556 delete chain;
03eb0929
ML
557 }
558 }
559
560 for (unsigned i = 0; i < all_candidates.length (); i++)
561 {
562 convert_if_conditions_to_switch (all_candidates[i]);
563 delete all_candidates[i];
564 }
565
566 free (rpo);
567
fa4586d8
ML
568 for (hash_map<basic_block, condition_info *>::iterator it
569 = conditions_in_bbs.begin (); it != conditions_in_bbs.end (); ++it)
570 delete (*it).second;
571
03eb0929
ML
572 if (!all_candidates.is_empty ())
573 {
574 free_dominance_info (CDI_DOMINATORS);
7875e8dc 575 return TODO_cleanup_cfg;
03eb0929
ML
576 }
577
578 return 0;
579}
580
581} // anon namespace
582
583gimple_opt_pass *
584make_pass_if_to_switch (gcc::context *ctxt)
585{
586 return new pass_if_to_switch (ctxt);
587}