OpenMP: Update documentation of metadirective implementation status.
[gcc.git] / gcc / gimple-crc-optimization.cc
bloba98cbe6752b56f104bd8717e2498a0dc4c1eb5f3
1 /* CRC optimization.
2 Copyright (C) 2022-2025 Free Software Foundation, Inc.
3 Contributed by Mariam Arutunian <mariamarutunian@gmail.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* This pass performs CRC optimization. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "tree-pass.h"
29 #include "ssa.h"
30 #include "gimple-iterator.h"
31 #include "tree-cfg.h"
32 #include "cfgloop.h"
33 #include "tree-scalar-evolution.h"
34 #include "crc-verification.h"
36 class crc_optimization {
37 private:
38 /* Record of statements already seen. */
39 bitmap m_visited_stmts;
41 /* Input CRC of the loop. */
42 tree m_crc_arg;
44 /* Input data of the loop. */
45 tree m_data_arg;
47 /* The statement doing shift 1 operation before/after xor operation. */
48 gimple *m_shift_stmt;
50 /* Phi statement from the head of the loop for CRC. */
51 gphi *m_phi_for_crc;
53 /* Phi statement for the data from the head of the loop if exists,
54 otherwise - nullptr. */
55 gphi *m_phi_for_data;
57 /* The loop, which probably calculates CRC. */
58 class loop *m_crc_loop;
60 /* Polynomial used in CRC calculation. */
61 unsigned HOST_WIDE_INT m_polynomial;
63 /* Depending on the value of M_IS_BIT_FORWARD, may be forward or reversed CRC.
64 If M_IS_BIT_FORWARD, then it is bit-forward implementation,
65 otherwise bit-reversed. */
66 bool m_is_bit_forward;
68 /* Sets initial values for CRC analyses. */
69 void set_initial_values ();
71 /* This is the main function that checks whether the given LOOP
72 calculates CRC and extracts details of the CRC calculation.
74 The main idea is to find the innermost loop with 8, 16, 24, 32, 64
75 iterations and xor instruction (xor is the key operation for naive CRC
76 calculation). Then, checks that the variable is shifted by one before/after
77 being used in xor.
78 Xor must be done under the condition of MSB/LSB being 1. */
79 bool loop_may_calculate_crc (class loop *loop);
81 /* Symbolically executes the loop and checks that LFSR and resulting states
82 match.
83 Returns true if it is verified that the loop calculates CRC.
84 Otherwise, return false.
85 OUTPUT_CRC is the phi statement which will hold the calculated CRC value
86 after the loop exit. */
87 bool loop_calculates_crc (gphi *output_crc,
88 std::pair<tree, value *> calc_polynom);
90 /* Returns true if there is only two conditional blocks in the loop
91 (one may be for the CRC bit check and the other for the loop counter).
92 This may filter out some real CRCs, where more than one condition
93 is checked for the CRC calculation. */
94 static bool loop_contains_two_conditional_bb (basic_block *loop_bbs,
95 unsigned loop_num_nodes);
97 /* Checks the FUNC_LOOP loop's iteration number.
98 The loop for CRC calculation may do 8, 16, 24, 32, 64 iterations. */
99 bool satisfies_crc_loop_iteration_count (class loop *func_loop);
101 /* This function checks if the XOR_STMT is used for CRC calculation.
102 It verifies the presence of a shift operation in the CRC_FUN function
103 inside the CRC loop. It examines operands of XOR, its dependencies, the
104 relative position of the shift operation, and the existence of a shift
105 operation in the opposite branch of conditional statements. It also
106 checks if XOR is performed when MSB/LSB is one.
107 If these conditions are met, the XOR operation may be part of a CRC
108 calculation. The function returns true if these conditions are fulfilled,
109 otherwise, it returns false. */
110 bool xor_calculates_crc (function *crc_fun, const gimple *xor_stmt);
112 /* Returns true if we can get definition of the VARIABLE, and the definition
113 it's not outside the loop. Otherwise, returns false. */
114 bool passes_checks_for_def_chain (tree variable);
116 /* This function goes up through the def-use chains of the parameter NAME.
117 Gathers all the statements within the loop,
118 from which the variable depends on and adds to the USE_DEFS.
119 Returns false, if there is a statement that may not exist in the CRC
120 loop. Otherwise, returns true. */
121 bool set_defs (tree name, auto_vec<gimple *>& use_defs,
122 bool keep_only_header_phis);
124 /* Set M_PHI_FOR_CRC and M_PHI_FOR_DATA fields.
125 Returns false if there are more than two (as in CRC calculation only CRC's
126 and data's phi may exist) or no phi statements in STMTS (at least there
127 must be CRC's phi).
128 Otherwise, returns true. */
129 bool set_crc_and_data_phi (auto_vec<gimple *>& stmts);
131 /* Returns true if the variable checked in the condition depends on possible
132 CRC value. Otherwise, returns false. */
133 bool cond_depends_on_crc (auto_vec<gimple *>& stmts);
136 /* Checks that the condition is for checking CRC.
137 Returns true if xor is done under the condition of MSB/LSB being 1, and
138 the condition's variable and xor-ed variable depend on the same variable.
139 Otherwise, returns false.
140 XOR_BB is the basic block, where the xor operation is done.
141 PRED_BB is the predecessor basic block of the XOR_BB, it is assumed that
142 the last stmt of PRED_BB checks the condition under which xor is done. */
143 bool crc_cond (basic_block pred_bb, basic_block xor_bb);
145 /* Returns true if xor is done in case the MSB/LSB is 1.
146 Otherwise, returns false.
147 In CRC calculation algorithms CRC is xor-ed with the polynomial only
148 if MSB/LSB is 1.
150 PRED_BB is the block containing the condition for the xor.
151 XOR_BB is the one of the successor blocks of PRED_BB, it is assumed that
152 CRC is xor-ed with the polynomial in XOR_BB.
153 COND is the condition, which is checked to satisfy the CRC condition. */
154 bool is_crc_satisfiable_cond (basic_block pred_bb, basic_block xor_bb,
155 gcond *cond);
157 /* Checks that the variable used in the condition COND is the assumed CRC
158 (or depends on the assumed CRC).
159 Also sets data member m_phi_for_data if it isn't set and exists. */
160 bool is_crc_checked (gcond *cond);
162 /* Returns true if condition COND checks MSB/LSB bit is 1.
163 Otherwise, return false. */
164 static bool cond_true_is_checked_for_bit_one (const gcond *cond);
166 /* Returns opposite block of the XOR_BB from PRED_BB's dest blocks. */
167 static basic_block get_xor_bb_opposite (basic_block pred_bb,
168 basic_block xor_bb);
170 /* Checks whether the pair of xor's shift exists in the opposite
171 basic block (OPPOSITE_BB).
172 If there is a shift and xor in the same block,
173 then in the opposite block must be another shift. */
174 bool exists_shift_for_opp_xor_shift (basic_block opposite_bb);
176 /* Follow def-use chains of XORED_CRC and return the statement where
177 XORED_CRC is shifted by one bit position. Only PHI statements are
178 allowed between XORED_CRC and the shift in the def-use chain.
180 If no such statement is found, return NULL. */
181 gimple *find_shift_after_xor (tree xored_crc);
183 /* Returns the statement which does shift 1 operation.
184 If there is no such statement, returns nullptr.
185 STMTS - are the statements within the loop before xor operation on
186 which possible CRC variable depends. */
187 gimple *find_shift_before_xor (const auto_vec <gimple *> &stmts);
189 /* Returns true if ASSIGN_STMT does shift with 1.
190 Otherwise, returns false. */
191 bool can_be_crc_shift (gimple *assign_stmt);
193 /* Returns true if the operation done in ASSIGN_STMT can occur during CRC
194 calculation. Otherwise, returns false. */
195 bool can_not_be_crc_stmt (gimple *assign_stmt);
197 /* Returns true if the statement with STMT_CODE may occur in CRC calculation.
198 Otherwise, returns false. */
199 static bool is_acceptable_stmt_code (const tree_code &stmt_code);
201 /* Prints extracted details of CRC calculation. */
202 void dump_crc_information ();
204 /* Returns true if OUTPUT_CRC's result is the input of m_phi_for_crc.
205 Otherwise, returns false. */
206 bool is_output_crc (gphi *output_crc);
208 /* Swaps m_phi_for_crc and m_phi_for_data if they are mixed. */
209 void swap_crc_and_data_if_needed (gphi *output_crc);
211 /* Validates CRC and data arguments and
212 sets them for potential CRC loop replacement.
214 The function extracts the CRC and data arguments from PHI nodes and
215 performs several checks to ensure that the CRC and data are suitable for
216 replacing the CRC loop with a more efficient implementation.
218 Returns true if the arguments are valid and the loop replacement is possible,
219 false otherwise. */
220 bool validate_crc_and_data ();
222 /* Convert polynomial to unsigned HOST_WIDE_INT. */
223 void construct_constant_polynomial (value *polynomial);
225 /* Returns phi statement which may hold the calculated CRC. */
226 gphi *get_output_phi ();
228 /* Attempts to optimize a CRC calculation loop by replacing it with a call to
229 an internal function (IFN_CRC or IFN_CRC_REV).
230 Returns true if replacement succeeded, otherwise false. */
231 bool optimize_crc_loop (gphi *output_crc);
233 public:
234 crc_optimization () : m_visited_stmts (BITMAP_ALLOC (NULL)),
235 m_crc_loop (nullptr), m_polynomial (0)
237 set_initial_values ();
239 ~crc_optimization ()
241 BITMAP_FREE (m_visited_stmts);
243 unsigned int execute (function *fun);
246 /* Prints extracted details of CRC calculation. */
248 void
249 crc_optimization::dump_crc_information ()
251 if (dump_file)
253 fprintf (dump_file,
254 "Loop iteration number is " HOST_WIDE_INT_PRINT_UNSIGNED ".\n",
255 tree_to_uhwi (m_crc_loop->nb_iterations));
256 if (m_is_bit_forward)
257 fprintf (dump_file, "Bit forward.\n");
258 else
259 fprintf (dump_file, "Bit reversed.\n");
263 /* Goes down by def-use chain (within the CRC loop) and returns the statement
264 where variable (dependent on xor-ed variable) is shifted with 1.
265 Between xor and shift operations only phi statements are allowed.
266 Otherwise, returns nullptr. */
268 gimple *
269 crc_optimization::find_shift_after_xor (tree xored_crc)
271 imm_use_iterator imm_iter;
272 use_operand_p use_p;
274 gcc_assert (TREE_CODE (xored_crc) == SSA_NAME);
276 unsigned v = SSA_NAME_VERSION (xored_crc);
277 if (bitmap_bit_p (m_visited_stmts, v))
278 return nullptr;
279 bitmap_set_bit (m_visited_stmts, v);
281 /* Iterate through the immediate uses of the XORED_CRC.
282 If there is a shift return true,
283 if before shift there is other instruction (besides phi) return false. */
284 FOR_EACH_IMM_USE_FAST (use_p, imm_iter, xored_crc)
286 gimple *stmt = USE_STMT (use_p);
287 // Consider only statements within the loop
288 if (!flow_bb_inside_loop_p (m_crc_loop, gimple_bb (stmt)))
289 continue;
291 /* If encountered phi statement, check immediate use of its result.
292 Otherwise, if encountered assign statement, check whether it does shift
293 (some other operations are allowed to be between shift and xor). */
294 if (gimple_code (stmt) == GIMPLE_PHI)
296 /* Don't continue searching if encountered the loop's beginning. */
297 if (bb_loop_header_p (gimple_bb (stmt)))
298 continue;
300 return find_shift_after_xor (gimple_phi_result (stmt));
302 else if (is_gimple_assign (stmt))
304 /* Check that stmt does shift by 1.
305 There are no other statements between
306 xor and shift, in CRC cases we detect. */
307 if (can_be_crc_shift (stmt))
308 return stmt;
309 return nullptr;
311 else if (!is_gimple_debug (stmt))
312 return nullptr;
314 return nullptr;
317 /* Returns opposite block of the XOR_BB from PRED_BB's dest blocks. */
319 basic_block
320 crc_optimization::get_xor_bb_opposite (basic_block pred_bb, basic_block xor_bb)
322 /* Check that the predecessor block has exactly two successors. */
323 if (EDGE_COUNT (pred_bb->succs) != 2)
324 return nullptr;
326 edge e0 = EDGE_SUCC (pred_bb, 0);
327 edge e1 = EDGE_SUCC (pred_bb, 1);
329 /* Ensure neither outgoing edge is marked as complex. */
330 if ((e0->flags & EDGE_COMPLEX)
331 || (e1->flags & EDGE_COMPLEX))
332 return nullptr;
334 /* Check that one of the successors is indeed XOR_BB. */
335 gcc_assert ((e0->dest == xor_bb)
336 || (e1->dest == xor_bb));
338 /* Return the opposite block of XOR_BB. */
339 if (EDGE_SUCC (pred_bb, 0)->dest != xor_bb)
340 return e0->dest;
341 return e1->dest;
344 /* Checks whether the pair of xor's shift exists in the opposite
345 basic block (OPPOSITE_BB).
346 If there is a shift and xor in the same block,
347 then in the opposite block must be another shift. */
349 bool
350 crc_optimization::exists_shift_for_opp_xor_shift (basic_block opposite_bb)
352 if (!opposite_bb)
353 return false;
355 /* Walk through the instructions of given basic block. */
356 for (gimple_stmt_iterator bsi = gsi_start_nondebug_bb (opposite_bb);
357 !gsi_end_p (bsi); gsi_next_nondebug (&bsi))
359 gimple *stmt = gsi_stmt (bsi);
360 /* Find assignment statement with shift operation.
361 Check that shift's direction is same with the shift done
362 on the path with xor, and it is a shift by one. */
363 if (is_gimple_assign (stmt))
365 if ((gimple_assign_rhs_code (stmt)
366 == gimple_assign_rhs_code (m_shift_stmt))
367 && integer_onep (gimple_assign_rhs2 (stmt)))
368 return true;
371 /* If there is no shift, return false. */
372 return false;
375 /* Returns true if condition COND checks MSB/LSB bit is 1.
376 Otherwise, return false. */
378 bool
379 crc_optimization::cond_true_is_checked_for_bit_one (const gcond *cond)
381 if (!cond)
382 return false;
384 tree rhs = gimple_cond_rhs (cond);
385 enum tree_code code = gimple_cond_code (cond);
387 /* If the condition is something == 1 -> return true. */
388 if (code == EQ_EXPR && integer_onep (rhs))
389 return true;
391 /* If the condition is something != 0 or something < 0 -> return true. */
392 if ((code == NE_EXPR || code == LT_EXPR)
393 && integer_zerop (rhs))
394 return true;
396 return false;
399 /* Returns true if xor is done in case the MSB/LSB is 1.
400 Otherwise, returns false.
401 In CRC calculation algorithms CRC is xor-ed with the polynomial only
402 if MSB/LSB is 1.
404 PRED_BB is the block containing the condition for the xor.
405 XOR_BB is the one of the successor blocks of PRED_BB, it is assumed that CRC
406 is xor-ed with the polynomial in XOR_BB.
407 COND is the condition, which is checked to satisfy the CRC condition. */
409 bool
410 crc_optimization::is_crc_satisfiable_cond (basic_block pred_bb,
411 basic_block xor_bb,
412 gcond *cond)
414 edge true_edge;
415 edge false_edge;
416 extract_true_false_edges_from_block (pred_bb, &true_edge, &false_edge);
417 bool cond_is_checked_for_bit_one = cond_true_is_checked_for_bit_one (cond);
418 /* Check that xor is done in case the MSB/LSB is 1. */
419 if (cond_is_checked_for_bit_one && true_edge->dest == xor_bb)
421 if (dump_file && (dump_flags & TDF_DETAILS))
422 fprintf (dump_file, "Xor is done on true branch.\n");
424 else if (!cond_is_checked_for_bit_one && false_edge->dest == xor_bb)
426 if (dump_file && (dump_flags & TDF_DETAILS))
427 fprintf (dump_file, "Xor is done on false branch.\n");
429 else
431 if (dump_file && (dump_flags & TDF_DETAILS))
432 fprintf (dump_file,
433 "Xor is done if MSB/LSB is not one, not CRC.\n");
434 return false;
436 return true;
439 /* Checks that the variable used in the condition COND is the assumed CRC
440 (or depends on the assumed CRC).
441 Also sets data member m_phi_for_data if it isn't set and exists. */
443 bool
444 crc_optimization::is_crc_checked (gcond *cond)
446 tree lhs = gimple_cond_lhs (cond);
448 /* As conditions are in canonical form, only left part must be an
449 SSA_NAME. */
450 if (TREE_CODE (lhs) == SSA_NAME)
452 /* Return whether there is a dependence between if condition's variable
453 and xor-ed variable. Also set phi statement of data if it is not
454 determined earlier and is used in the loop. */
455 auto_vec<gimple *> cond_dep_stmts (m_crc_loop->num_nodes);
456 bool set_defs_succeeded = set_defs (lhs, cond_dep_stmts, true);
457 bitmap_clear (m_visited_stmts);
458 if (!set_defs_succeeded)
459 return false;
460 return cond_depends_on_crc (cond_dep_stmts);
463 /* Return false if there is no dependence between if condition's variable
464 and xor-ed variable. */
465 return false;
468 /* Checks that the condition is for checking CRC.
469 Returns true if xor is done under the condition of MSB/LSB being 1, and
470 the condition's variable and xor-ed variable depend on the same variable.
471 Otherwise, returns false.
472 XOR_BB is the basic block, where the xor operation is done.
473 PRED_BB is the predecessor basic block of the XOR_BB, it is assumed that
474 the last stmt of PRED_BB checks the condition under which xor is done. */
476 bool
477 crc_optimization::crc_cond (basic_block pred_bb, basic_block xor_bb)
479 /* Check whether PRED_BB contains condition. We will consider only those
480 cases when xor is done immediately under the condition. */
481 gcond *cond = safe_dyn_cast<gcond *> (gsi_stmt (gsi_last_bb (pred_bb)));
482 if (!cond)
484 if (dump_file && (dump_flags & TDF_DETAILS))
485 fprintf (dump_file, "No condition.\n");
486 return false;
489 /* Check that xor is done in case the MSB/LSB is 1. */
490 if (!is_crc_satisfiable_cond (pred_bb, xor_bb, cond))
491 return false;
493 /* Check that CRC's MSB/LSB is checked in the condition.
494 Set data member if not set and exists. */
495 if (!is_crc_checked (cond))
497 if (dump_file && (dump_flags & TDF_DETAILS))
498 fprintf (dump_file, "The condition is not related to the CRC check.\n");
499 return false;
501 return true;
504 /* Returns true if the statement with STMT_CODE may occur in CRC calculation.
505 Otherwise, returns false. */
507 bool
508 crc_optimization::is_acceptable_stmt_code (const tree_code &stmt_code)
510 return (stmt_code == BIT_IOR_EXPR)
511 || (stmt_code == BIT_AND_EXPR)
512 || (stmt_code == BIT_XOR_EXPR)
513 || (stmt_code == MINUS_EXPR)
514 || (stmt_code == PLUS_EXPR)
515 || (stmt_code == RSHIFT_EXPR)
516 || (stmt_code == LSHIFT_EXPR)
517 || (TREE_CODE_CLASS (stmt_code) == tcc_unary);
520 /* Returns true if ASSIGN_STMT does shift with 1. Otherwise, returns false. */
522 bool
523 crc_optimization::can_be_crc_shift (gimple *assign_stmt)
525 tree_code stmt_code = gimple_assign_rhs_code (assign_stmt);
526 if (stmt_code == LSHIFT_EXPR || stmt_code == RSHIFT_EXPR)
528 m_is_bit_forward = (stmt_code == LSHIFT_EXPR);
529 /* Check that shift one is done, keep shift statement. */
530 if (integer_onep (gimple_assign_rhs2 (assign_stmt)))
532 if (m_shift_stmt)
534 if (dump_file && (dump_flags & TDF_DETAILS))
535 fprintf (dump_file,
536 "Already there is one shift.\n");
537 return false;
539 if (dump_file && (dump_flags & TDF_DETAILS))
540 fprintf (dump_file,
541 "Found <<1 or >>1.\n");
542 return true;
544 /* This filters out cases, when xor-ed variable is shifted by values
545 other than 1. */
547 return false;
550 /* Returns true if the operation done in ASSIGN_STMT can occur during CRC
551 calculation. Otherwise, returns false. */
553 bool
554 crc_optimization::can_not_be_crc_stmt (gimple *assign_stmt)
556 tree_code stmt_code = gimple_assign_rhs_code (assign_stmt);
557 if (!is_acceptable_stmt_code (stmt_code))
559 if (dump_file && (dump_flags & TDF_DETAILS))
560 fprintf (dump_file,
561 "\nStmt with the following operation "
562 "code %s between xor and shift, "
563 "may not be CRC.\n", get_tree_code_name (stmt_code));
565 return true;
567 return false;
570 /* Returns true if we can get definition of the VARIABLE, and the definition
571 is not outside the loop. Otherwise, returns false. */
573 bool
574 crc_optimization::passes_checks_for_def_chain (tree variable)
576 if (!(variable && TREE_CODE (variable) == SSA_NAME))
577 return false;
579 /* No definition chain for default defs. */
580 if (SSA_NAME_IS_DEFAULT_DEF (variable))
581 return false;
583 gimple *stmt = SSA_NAME_DEF_STMT (variable);
585 if (!stmt)
586 return false;
588 /* Don't go outside the loop. */
589 if (!flow_bb_inside_loop_p (m_crc_loop, gimple_bb (stmt)))
590 return false;
592 return true;
595 /* This function goes up through the def-use chains of the parameter NAME.
596 Gathers all the statements within the loop,
597 from which the variable depends on and adds to the USE_DEFS.
598 Returns false, if there is a statement that may not exist in the CRC
599 loop. Otherwise, returns true. */
601 bool
602 crc_optimization::set_defs (tree name, auto_vec<gimple *> &use_defs,
603 bool keep_only_header_phis = false)
605 if (!passes_checks_for_def_chain (name))
606 return true;
608 /* Don't consider already visited names. */
609 unsigned v = SSA_NAME_VERSION (name);
610 if (bitmap_bit_p (m_visited_stmts, v))
611 return true;
612 bitmap_set_bit (m_visited_stmts, v);
614 /* In CRC implementations with constant polynomial maximum 12 use_def
615 statements may occur. This limit is based on an analysis of various CRC
616 implementations as well as theoretical possibilities.
617 TODO: Find a better solution. */
618 if (use_defs.length () > 12)
619 return false;
621 gimple *stmt = SSA_NAME_DEF_STMT (name);
623 /* If it's not specified to keep only header phi's,
624 then keep all statements. */
625 if (!keep_only_header_phis)
626 use_defs.safe_push (stmt);
628 /* If it is an assignment statement,
629 get and check def-use chain for the first and second operands. */
630 if (is_a<gassign *> (stmt))
632 if (can_not_be_crc_stmt (stmt))
633 return false;
635 tree ssa1 = gimple_assign_rhs1 (stmt);
636 tree ssa2 = gimple_assign_rhs2 (stmt);
637 if (!set_defs (ssa1, use_defs, keep_only_header_phis))
638 return false;
639 if (!set_defs (ssa2, use_defs, keep_only_header_phis))
640 return false;
641 return true;
643 /* If it's a phi statement, not declared in loop's header,
644 get and check def-use chain for its values. For the one declared in loop's
645 header just return true and keep it, if keep_only_header_phis is true. */
646 else if (is_a<gphi *> (stmt))
648 if (bb_loop_header_p (gimple_bb (stmt)))
650 /* If it's specified to keep only header phi's, keep it. */
651 if (keep_only_header_phis)
652 use_defs.safe_push (stmt);
654 else
656 for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
658 tree val = gimple_phi_arg_def (stmt, i);
659 if (!set_defs (val, use_defs, keep_only_header_phis))
660 return false;
663 return true;
666 /* Return false for other than assigment and phi statement. */
667 return false;
670 /* Returns the statement which does shift 1 operation.
671 If there is no such statement, returns nullptr.
672 STMTS - are the statements within the loop before xor operation on
673 which possible CRC variable depends. */
675 gimple *
676 crc_optimization::find_shift_before_xor (const auto_vec<gimple *> &stmts)
678 for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
680 /* If it is an assignment statement, check that is does shift 1. */
681 if (is_a<gassign *> (*stmt_it))
683 if (can_be_crc_shift (*stmt_it))
684 return *stmt_it;
687 return nullptr;
690 /* This function sets M_PHI_FOR_CRC and M_PHI_FOR_DATA fields.
691 At this step phi nodes for CRC and data may be mixed in places.
692 It is fixed later with the "swap_crc_and_data_if_needed" function.
693 The function returns false if there are more than two (as in CRC calculation
694 only CRC's and data's phi may exist) or no phi statements in STMTS (at least
695 there must be CRC's phi).
696 Otherwise, returns true. */
698 bool
699 crc_optimization::set_crc_and_data_phi (auto_vec<gimple *> &stmts)
701 for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
703 if (is_a<gphi *> (*stmt_it) && bb_loop_header_p (gimple_bb (*stmt_it)))
705 if (!m_phi_for_crc)
706 m_phi_for_crc = as_a<gphi *> (*stmt_it);
707 else if (!m_phi_for_data)
708 m_phi_for_data = as_a<gphi *> (*stmt_it);
709 else
711 if (dump_file && (dump_flags & TDF_DETAILS))
712 fprintf (dump_file, "Xor-ed variable depends on more than 2 "
713 "phis.\n");
714 return false;
718 return m_phi_for_crc;
721 /* Returns true if the variable checked in the condition depends on possible
722 CRC value. Otherwise, returns false. */
724 bool
725 crc_optimization::cond_depends_on_crc (auto_vec<gimple *>& stmts)
727 bool con_depends_on_crc = false;
729 /* The condition may depend maximum on data and CRC phi's. */
730 if (stmts.length () > 2)
731 return false;
733 for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
735 if (is_a<gphi *> (*stmt_it) && bb_loop_header_p (gimple_bb (*stmt_it)))
737 /* Check whether variable checked in the condition depends on
738 M_PHI_FOR_CRC.
739 Here don't stop the check, to set data if needed. */
740 if (m_phi_for_crc == (*stmt_it))
741 con_depends_on_crc = true;
742 else if (m_phi_for_data && m_phi_for_data == (*stmt_it))
743 return true;
744 /* If M_PHI_FOR_DATA isn't determined, the phi statement maybe for the
745 data. Just set it. */
746 else if (!m_phi_for_data)
747 m_phi_for_data = as_a<gphi *> (*stmt_it);
750 return con_depends_on_crc;
753 /* Sets initial values for the CRC analysis.
754 This function is used multiple times during the analyses. */
756 void
757 crc_optimization::set_initial_values ()
759 m_crc_arg = nullptr;
760 m_data_arg = nullptr;
761 m_shift_stmt = nullptr;
762 m_phi_for_crc = nullptr;
763 m_phi_for_data = nullptr;
764 m_is_bit_forward = false;
767 /* This function checks if the XOR_STMT is used for CRC calculation.
768 It verifies the presence of a shift operation in the CRC_FUN function inside
769 the CRC loop. It examines operands of XOR, its dependencies, the relative
770 position of the shift operation, and the existence of a shift operation in
771 the opposite branch of conditional statements. It also checks if XOR is
772 performed when MSB/LSB is one.
773 If these conditions are met, the XOR operation may be part of a CRC
774 calculation. The function returns true if these conditions are fulfilled,
775 otherwise, it returns false. */
777 bool
778 crc_optimization::xor_calculates_crc (function *crc_fun,
779 const gimple *xor_stmt)
781 tree crc_var = gimple_assign_lhs (xor_stmt);
782 set_initial_values ();
783 tree ssa1 = gimple_assign_rhs1 (xor_stmt);
784 tree ssa2 = gimple_assign_rhs2 (xor_stmt);
785 if (TREE_CODE (ssa2) != INTEGER_CST)
787 if (dump_file && (dump_flags & TDF_DETAILS))
788 fprintf (dump_file, "Second operand of the "
789 "xor statement isn't an integer constant.\n");
790 return false;
793 /* Get the statements within the loop on which xor-ed variable depends. */
794 auto_vec<gimple *> xor_dep_stmts (m_crc_loop->num_nodes);
795 bool set_defs_succeeded = set_defs (ssa1, xor_dep_stmts);
796 bitmap_clear (m_visited_stmts);
797 if (!set_defs_succeeded)
799 xor_dep_stmts.release ();
800 return false;
803 m_shift_stmt = find_shift_before_xor (xor_dep_stmts);
805 if (!set_crc_and_data_phi (xor_dep_stmts))
807 if (dump_file && (dump_flags & TDF_DETAILS))
808 fprintf (dump_file, "Xor isn't used for CRC calculation.\n");
809 return false;
812 /* Check the case when shift is done after xor. */
813 if (!m_shift_stmt)
815 if (dump_file && (dump_flags & TDF_DETAILS))
816 fprintf (dump_file, "No shift before xor, trying to find after xor.\n");
818 m_shift_stmt = find_shift_after_xor (crc_var);
819 bitmap_clear (m_visited_stmts);
820 if (!m_shift_stmt)
821 return false;
824 /* Get the basic block where xor operation is done. */
825 basic_block xor_bb = gimple_bb (xor_stmt);
827 /* Get the predecessor basic block of xor's block. */
828 if (!single_pred_p (xor_bb))
829 return false;
830 basic_block block_of_condition = single_pred (xor_bb);
833 /* If the found shift operation is in the same block as the xor operation,
834 verify whether another shift exists in the opposite branch of the
835 conditional statements. */
836 if (m_shift_stmt && gimple_bb (m_shift_stmt) == xor_bb)
838 basic_block opposite_block = get_xor_bb_opposite (block_of_condition,
839 xor_bb);
840 if (!exists_shift_for_opp_xor_shift (opposite_block))
842 if (dump_file && (dump_flags & TDF_DETAILS))
843 fprintf (dump_file,
844 "Opposite block doesn't contain shift's pair.\n");
845 return false;
849 /* Check that xor is done if MSB/LSB is one.
850 If all checks succeed, then it may be a CRC. */
851 if (crc_cond (block_of_condition, xor_bb))
853 if (dump_file)
854 fprintf (dump_file,
855 "\n%s function maybe contains CRC calculation.\n",
856 function_name (crc_fun));
857 return true;
860 return false;
863 /* Returns true if there is only two conditional blocks in the loop,
864 one may be for the CRC bit check and the other for the loop counter.
865 This may filter out some real CRCs, where more than one condition
866 is checked for the CRC calculation and branch-less CRCs. */
868 bool
869 crc_optimization::loop_contains_two_conditional_bb (basic_block *loop_bbs,
870 unsigned loop_num_nodes)
872 unsigned conditional_bb_count = 0;
873 /* Iterate through the loop until the conditional branches count
874 is below 3. */
875 for (unsigned i = 0; i < loop_num_nodes && conditional_bb_count <= 2; i++)
877 basic_block bb = loop_bbs[i];
878 if (!single_succ_p (bb))
879 conditional_bb_count++;
881 return conditional_bb_count == 2;
884 /* Checks the FUNC_LOOP loop's iteration number.
885 The loop for CRC calculation may do 8, 16, 24, 32, 64 iterations. */
887 bool
888 crc_optimization::satisfies_crc_loop_iteration_count (class loop *func_loop)
890 /* Calculate the number of times the latch of the loop is executed.
891 The function sets NB_ITERATIONS field of the loop. */
892 number_of_latch_executions (func_loop);
893 tree n_inters = func_loop->nb_iterations;
894 if (n_inters == NULL_TREE || n_inters == chrec_dont_know)
896 if (dump_file && (dump_flags & TDF_DETAILS))
897 fprintf (dump_file,
898 "Loop iteration number is chrec_dont_know.\n");
899 return false;
902 else if (tree_fits_uhwi_p (n_inters))
904 unsigned HOST_WIDE_INT
905 loop_iteration_number = tree_to_uhwi (n_inters);
906 if (dump_file && (dump_flags & TDF_DETAILS))
907 fprintf (dump_file, "Loop iteration number is "
908 HOST_WIDE_INT_PRINT_UNSIGNED ".\n", loop_iteration_number);
910 if ((loop_iteration_number == 7 || loop_iteration_number == 15
911 || loop_iteration_number == 23 || loop_iteration_number == 31
912 || loop_iteration_number == 63))
913 return true;
915 if (stderr && (dump_flags & TDF_DETAILS))
916 fprintf (dump_file, "Loop iteration number isn't a constant.\n");
917 return false;
920 /* This is the main function that checks whether the given LOOP
921 calculates CRC and extracts details of the CRC calculation.
923 The main idea is to find the innermost loop with 8, 16, 24, 32, 64
924 iterations and xor instruction (xor is the key operation for naive CRC
925 calculation). Then, checks that the variable is shifted by one before/after
926 being used in xor.
927 Xor must be done under the condition of MSB/LSB being 1. */
929 bool
930 crc_optimization::loop_may_calculate_crc (class loop *loop)
932 /* Only examine innermost loops. */
933 if (!loop || loop->inner)
934 return false;
936 if (!satisfies_crc_loop_iteration_count (loop))
937 return false;
939 m_crc_loop = loop;
940 basic_block *loop_bbs = get_loop_body_in_dom_order (m_crc_loop);
942 /* Filter out the cases, which don't have exactly two conditions in the loop.
943 One for the CRC bit check, the other for the loop counter. */
944 if (!loop_contains_two_conditional_bb (loop_bbs, m_crc_loop->num_nodes))
946 if (dump_file && (dump_flags & TDF_DETAILS))
947 fprintf (dump_file,
948 "The number of conditional "
949 "branches in the loop isn't 2.\n");
950 free (loop_bbs);
951 return false;
954 unsigned short checked_xor_count = 0;
955 /* Walk bbs of the loop. */
956 for (unsigned int i = 0; i < m_crc_loop->num_nodes; i++)
958 basic_block bb = loop_bbs[i];
959 /* Walk instructions of the bb. */
960 for (gimple_stmt_iterator bsi = gsi_start_nondebug_bb (bb);
961 !gsi_end_p (bsi); gsi_next_nondebug (&bsi))
963 gimple *stmt = gsi_stmt (bsi);
964 /* If there is an xor instruction,
965 check that it is calculating CRC. */
966 if (is_gimple_assign (stmt)
967 && gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR)
969 if (dump_file && (dump_flags & TDF_DETAILS))
970 fprintf (dump_file,
971 "Found xor, "
972 "checking whether it is for CRC calculation.\n");
974 if (xor_calculates_crc (cfun, stmt))
976 dump_crc_information ();
977 free (loop_bbs);
978 return true;
981 if (++checked_xor_count == 2)
983 free (loop_bbs);
984 return false;
989 free (loop_bbs);
990 return false;
993 /* Symbolically executes the loop and checks that LFSR and resulting states
994 match.
995 Returns true if it is verified that the loop calculates CRC.
996 Otherwise, return false.
997 OUTPUT_CRC is the phi statement which will hold the calculated CRC value
998 after the loop exit. */
1000 bool
1001 crc_optimization::loop_calculates_crc (gphi *output_crc,
1002 std::pair<tree, value *> calc_polynom)
1004 /* Create LFSR state using extracted polynomial. */
1005 value * lfsr = state::create_lfsr (calc_polynom.first, calc_polynom.second,
1006 m_is_bit_forward);
1007 if (!lfsr)
1009 if (dump_file && (dump_flags & TDF_DETAILS))
1010 fprintf (dump_file, "Couldn't create LFSR!\n");
1011 return false;
1014 if (dump_file && (dump_flags & TDF_DETAILS))
1016 fprintf (dump_file, "\nLFSR value is \n");
1017 state::print_value (lfsr);
1020 /* Execute the loop with symbolic values
1021 (symbolic value is assigned to the variable when its value isn't known)
1022 to keep states, for further comparison. */
1023 bool is_crc = true;
1024 crc_symbolic_execution loop_executor (m_crc_loop, output_crc);
1025 while (!loop_executor.is_last_iteration ())
1027 if (!loop_executor.symb_execute_crc_loop ())
1029 if (dump_file)
1030 fprintf (dump_file, "\nCRC verification didn't succeed "
1031 "during symbolic execution!\n");
1032 is_crc = false;
1033 break;
1036 /* Check whether LFSR and obtained states are same. */
1037 tree calculated_crc = PHI_ARG_DEF_FROM_EDGE (output_crc,
1038 single_exit (m_crc_loop));
1039 if (!all_states_match_lfsr (lfsr, m_is_bit_forward, calculated_crc,
1040 loop_executor.get_final_states ()))
1042 if (dump_file && (dump_flags & TDF_DETAILS))
1043 fprintf (dump_file, "Returned state and LFSR differ.\n");
1044 is_crc = false;
1045 break;
1048 delete lfsr;
1049 return is_crc;
1052 /* Returns true if OUTPUT_CRC's result is the input of M_PHI_FOR_CRC.
1053 Otherwise, returns false. */
1055 bool
1056 crc_optimization::is_output_crc (gphi *output_crc)
1058 tree crc_of_exit
1059 = PHI_ARG_DEF_FROM_EDGE (output_crc, single_exit (m_crc_loop));
1060 tree crc_of_latch
1061 = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, loop_latch_edge (m_crc_loop));
1062 if (crc_of_exit == crc_of_latch)
1064 if (dump_file && (dump_flags & TDF_DETAILS))
1066 fprintf (dump_file, "Output CRC is ");
1067 print_gimple_expr (dump_file, (gimple *) output_crc, dump_flags);
1068 fprintf (dump_file, "\n");
1070 return true;
1072 else
1074 if (dump_file && (dump_flags & TDF_DETAILS))
1075 fprintf (dump_file, "Output CRC and determined input CRC "
1076 "differ.\n");
1077 return false;
1081 /* Swaps M_PHI_FOR_CRC and M_PHI_FOR_DATA if they are mixed. */
1083 void
1084 crc_optimization::swap_crc_and_data_if_needed (gphi *output_crc)
1086 tree crc_of_exit
1087 = PHI_ARG_DEF_FROM_EDGE (output_crc, single_exit (m_crc_loop));
1088 edge crc_loop_latch = loop_latch_edge (m_crc_loop);
1089 if (crc_of_exit != PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, crc_loop_latch))
1091 if (m_phi_for_data
1092 && crc_of_exit == PHI_ARG_DEF_FROM_EDGE (m_phi_for_data,
1093 crc_loop_latch))
1095 std::swap (m_phi_for_crc, m_phi_for_data);
1100 /* Validates CRC and data arguments and
1101 sets them for potential CRC loop replacement.
1103 The function extracts the CRC and data arguments from PHI nodes and
1104 performs several checks to ensure that the CRC and data are suitable for
1105 replacing the CRC loop with a more efficient implementation.
1107 Returns true if the arguments are valid and the loop replacement is possible,
1108 false otherwise. */
1110 bool crc_optimization::validate_crc_and_data ()
1112 /* Set m_crc_arg and check if fits in word_mode. */
1113 gcc_assert (m_phi_for_crc);
1114 m_crc_arg = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc,
1115 loop_preheader_edge (m_crc_loop));
1116 gcc_assert (m_crc_arg);
1118 unsigned HOST_WIDE_INT
1119 data_size = tree_to_uhwi (m_crc_loop->nb_iterations) + 1;
1120 /* We don't support the case where data is larger than the CRC. */
1121 if (TYPE_PRECISION (TREE_TYPE (m_crc_arg)) < data_size)
1122 return false;
1124 /* Set m_data_arg if a PHI node for data exists,
1125 and check its size against loop iterations.
1126 This is the case when data and CRC are XOR-ed in the loop. */
1127 if (m_phi_for_data)
1129 if (dump_file && (dump_flags & TDF_DETAILS))
1130 fprintf (dump_file,
1131 "Data and CRC are xor-ed in the for loop. Initializing data "
1132 "with its value.\n");
1133 m_data_arg = PHI_ARG_DEF_FROM_EDGE (m_phi_for_data,
1134 loop_preheader_edge (m_crc_loop));
1135 gcc_assert (m_data_arg);
1136 if (TYPE_PRECISION (TREE_TYPE (m_data_arg)) != data_size)
1138 if (dump_file && (dump_flags & TDF_DETAILS))
1139 fprintf (dump_file,
1140 "Loop iteration number and data's size differ.\n");
1141 return false;
1143 return true;
1145 return true;
1148 /* Convert polynomial to unsigned HOST_WIDE_INT. */
1150 void
1151 crc_optimization::construct_constant_polynomial (value *polynomial)
1153 m_polynomial = 0;
1154 for (unsigned i = 0; i < (*polynomial).length (); i++)
1156 value_bit *const_bit;
1157 if (m_is_bit_forward)
1158 const_bit = (*polynomial)[(*polynomial).length () - 1 - i];
1159 else
1160 const_bit = (*polynomial)[i];
1161 m_polynomial <<= 1;
1162 m_polynomial ^= (as_a<bit *> (const_bit))->get_val () ? 1 : 0;
1166 /* Returns phi statement which may hold the calculated CRC. */
1168 gphi *
1169 crc_optimization::get_output_phi ()
1171 edge loop_exit = single_exit (m_crc_loop);
1172 if (!loop_exit)
1174 if (dump_file && (dump_flags & TDF_DETAILS))
1175 fprintf (dump_file, "The loop doesn't have single exit.\n");
1176 return nullptr;
1178 basic_block bb = loop_exit->dest;
1179 gphi *output_crc = nullptr;
1180 int phi_count = 0;
1182 /* We are only interested in cases when there is only one phi at the
1183 loop exit, and that phi can potentially represent the CRC.
1184 If there are other phis present, it indicates that additional values are
1185 being calculated within the loop that are used outside it. */
1186 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
1187 gsi_next (&gsi))
1189 tree phi_result = gimple_phi_result (gsi.phi ());
1191 /* Don't consider virtual operands. */
1192 if (!virtual_operand_p (phi_result))
1194 if (phi_count < 1)
1196 output_crc = gsi.phi ();
1197 phi_count++;
1199 else
1201 if (dump_file && (dump_flags & TDF_DETAILS))
1202 fprintf (dump_file, "There is more than one output phi.\n");
1203 return nullptr;
1208 if (output_crc)
1210 if (gimple_phi_num_args (output_crc) == 1)
1211 return output_crc;
1214 if (dump_file && (dump_flags & TDF_DETAILS))
1215 fprintf (dump_file, "Couldn't determine output CRC.\n");
1216 return nullptr;
1219 /* Attempts to optimize a CRC calculation loop by replacing it with a call to
1220 an internal function (IFN_CRC or IFN_CRC_REV).
1221 Returns true if replacement succeeded, otherwise false. */
1223 bool
1224 crc_optimization::optimize_crc_loop (gphi *output_crc)
1226 if (!output_crc)
1228 if (dump_file)
1229 fprintf (dump_file, "Couldn't determine output CRC.\n");
1230 return false;
1233 if (!m_data_arg)
1235 if (dump_file && (dump_flags & TDF_DETAILS))
1236 fprintf (dump_file,
1237 "Data and CRC are xor-ed before for loop. Initializing data "
1238 "with 0.\n");
1239 /* Create a new variable for the data.
1240 Determine the data's size with the loop iteration count. */
1241 unsigned HOST_WIDE_INT
1242 data_size = tree_to_uhwi (m_crc_loop->nb_iterations) + 1;
1243 tree type = build_nonstandard_integer_type (data_size, 1);
1244 /* For the CRC calculation, it doesn't matter CRC is calculated for the
1245 (CRC^data, 0) or (CRC, data). */
1246 m_data_arg = build_int_cstu (type, 0);
1249 /* Build tree node for the polynomial from its constant value. */
1250 tree polynomial_arg = build_int_cstu (TREE_TYPE (m_crc_arg), m_polynomial);
1251 gcc_assert (polynomial_arg);
1253 internal_fn ifn;
1254 if (m_is_bit_forward)
1255 ifn = IFN_CRC;
1256 else
1257 ifn = IFN_CRC_REV;
1259 tree phi_result = gimple_phi_result (output_crc);
1260 location_t loc;
1261 loc = EXPR_LOCATION (phi_result);
1263 /* Add IFN call and write the return value in the phi_result. */
1264 gcall *call
1265 = gimple_build_call_internal (ifn, 3,
1266 m_crc_arg,
1267 m_data_arg,
1268 polynomial_arg);
1270 gimple_call_set_lhs (call, phi_result);
1271 gimple_set_location (call, loc);
1272 gimple_stmt_iterator si = gsi_start_bb (output_crc->bb);
1273 gsi_insert_before (&si, call, GSI_SAME_STMT);
1275 /* Remove phi statement, which was holding CRC result. */
1276 gimple_stmt_iterator tmp_gsi = gsi_for_stmt (output_crc);
1277 remove_phi_node (&tmp_gsi, false);
1279 /* Alter the exit condition of the loop to always exit. */
1280 gcond* loop_exit_cond = get_loop_exit_condition (m_crc_loop);
1281 gimple_cond_make_false (loop_exit_cond);
1282 update_stmt (loop_exit_cond);
1283 return true;
1286 unsigned int
1287 crc_optimization::execute (function *fun)
1289 if (dump_file && (dump_flags & TDF_DETAILS))
1290 fprintf (dump_file, "\nExamining %s function.\n",
1291 function_name (fun));
1293 if (number_of_loops (fun) <= 1)
1294 return 0;
1296 /* Get loops of the function. */
1297 auto loop_list = loops_list (fun, LI_ONLY_INNERMOST);
1298 for (auto loop: loop_list)
1300 /* Perform initial checks to filter out non-CRCs. */
1301 if (loop_may_calculate_crc (loop))
1303 /* Get the phi which will hold the calculated CRC. */
1304 gphi *output_crc = get_output_phi ();
1305 if (!output_crc)
1306 break;
1308 swap_crc_and_data_if_needed (output_crc);
1309 if (!is_output_crc (output_crc))
1310 break;
1311 if (!validate_crc_and_data ())
1312 break;
1314 edge loop_latch = loop_latch_edge (m_crc_loop);
1315 tree calced_crc = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, loop_latch);
1316 crc_symbolic_execution execute_loop (m_crc_loop, nullptr);
1317 /* Execute the loop assigning specific values to CRC and data
1318 for extracting the polynomial. */
1319 std::pair <tree, value *>
1320 calc_polynom = execute_loop.extract_polynomial (m_phi_for_crc,
1321 m_phi_for_data,
1322 calced_crc,
1323 m_is_bit_forward);
1325 value *polynom_value = calc_polynom.second;
1326 /* Stop analysis if we couldn't get the polynomial's value. */
1327 if (!polynom_value)
1328 break;
1330 /* Stop analysis in case optimize_size is specified
1331 and table-based would be generated. This check is only needed for
1332 TARGET_CRC case, as polynomial's value isn't known in the
1333 beginning. */
1334 construct_constant_polynomial (polynom_value);
1336 if (!loop_calculates_crc (output_crc, calc_polynom))
1337 break;
1339 if (dump_file)
1340 fprintf (dump_file, "The loop with %d header BB index "
1341 "calculates CRC!\n", m_crc_loop->header->index);
1343 if (!optimize_crc_loop (output_crc))
1345 if (dump_file)
1346 fprintf (dump_file, "Couldn't generate faster CRC code.\n");
1350 return 0;
1353 namespace
1356 const pass_data pass_data_crc_optimization
1358 GIMPLE_PASS, /* type */
1359 "crc", /* name */
1360 OPTGROUP_NONE, /* optinfo_flags */
1361 TV_GIMPLE_CRC_OPTIMIZATION, /* tv_id */
1362 (PROP_cfg | PROP_ssa), /* properties_required */
1363 0, /* properties_provided */
1364 0, /* properties_destroyed */
1365 0, /* todo_flags_start */
1366 0, /* todo_flags_finish */
1369 class pass_crc_optimization : public gimple_opt_pass {
1370 public:
1371 pass_crc_optimization (gcc::context *ctxt)
1372 : gimple_opt_pass (pass_data_crc_optimization, ctxt)
1375 /* opt_pass methods: */
1376 virtual bool gate (function *)
1378 return flag_optimize_crc;
1381 virtual unsigned int execute (function *);
1383 }; // class pass_crc_optimization
1385 unsigned int
1386 pass_crc_optimization::execute (function *fun)
1388 return crc_optimization ().execute (fun);
1391 } // anon namespace
1393 gimple_opt_pass *
1394 make_pass_crc_optimization (gcc::context *ctxt)
1396 return new pass_crc_optimization (ctxt);