LCOV - code coverage report
Current view: top level - gcc - gimple-crc-optimization.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.1 % 432 398
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 33 33
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* CRC optimization.
       2              :    Copyright (C) 2022-2026 Free Software Foundation, Inc.
       3              :    Contributed by Mariam Arutunian <mariamarutunian@gmail.com>
       4              : 
       5              : This file is part of GCC.
       6              : 
       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.
      11              : 
      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.
      16              : 
      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/>.   */
      20              : 
      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"
      35              : 
      36              : class crc_optimization {
      37              :  private:
      38              :   /* Record of statements already seen.  */
      39              :   bitmap m_visited_stmts;
      40              : 
      41              :   /* Input CRC of the loop.  */
      42              :   tree m_crc_arg;
      43              : 
      44              :   /* Input data of the loop.  */
      45              :   tree m_data_arg;
      46              : 
      47              :   /* The statement doing shift 1 operation before/after xor operation.  */
      48              :   gimple *m_shift_stmt;
      49              : 
      50              :   /* Phi statement from the head of the loop for CRC.  */
      51              :   gphi *m_phi_for_crc;
      52              : 
      53              :   /* Phi statement for the data from the head of the loop if exists,
      54              :      otherwise - nullptr.  */
      55              :   gphi *m_phi_for_data;
      56              : 
      57              :   /* The loop, which probably calculates CRC.  */
      58              :   class loop *m_crc_loop;
      59              : 
      60              :   /* Polynomial used in CRC calculation.  */
      61              :   unsigned HOST_WIDE_INT m_polynomial;
      62              : 
      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;
      67              : 
      68              :   /* Sets initial values for CRC analyses.  */
      69              :   void set_initial_values ();
      70              : 
      71              :   /* This is the main function that checks whether the given LOOP
      72              :      calculates CRC and extracts details of the CRC calculation.
      73              : 
      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);
      80              : 
      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);
      89              : 
      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);
      96              : 
      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);
     100              : 
     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);
     111              : 
     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);
     115              : 
     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);
     123              : 
     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);
     130              : 
     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);
     134              : 
     135              : 
     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);
     144              : 
     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.
     149              : 
     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);
     156              : 
     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);
     161              : 
     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);
     165              : 
     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);
     169              : 
     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);
     175              : 
     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.
     179              : 
     180              :    If no such statement is found, return NULL.  */
     181              :   gimple *find_shift_after_xor (tree xored_crc);
     182              : 
     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);
     188              : 
     189              :   /* Returns true if ASSIGN_STMT does shift with 1.
     190              :      Otherwise, returns false.  */
     191              :   bool can_be_crc_shift (gimple *assign_stmt);
     192              : 
     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);
     196              : 
     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);
     200              : 
     201              :   /* Prints extracted details of CRC calculation.  */
     202              :   void dump_crc_information ();
     203              : 
     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);
     207              : 
     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);
     210              : 
     211              :   /* Validates CRC and data arguments and
     212              :    sets them for potential CRC loop replacement.
     213              : 
     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.
     217              : 
     218              :   Returns true if the arguments are valid and the loop replacement is possible,
     219              :   false otherwise.  */
     220              :   bool validate_crc_and_data ();
     221              : 
     222              :   /* Convert polynomial to unsigned HOST_WIDE_INT.  */
     223              :   void construct_constant_polynomial (value *polynomial);
     224              : 
     225              :   /* Returns phi statement which may hold the calculated CRC.  */
     226              :   gphi *get_output_phi ();
     227              : 
     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);
     232              : 
     233              :  public:
     234       225075 :   crc_optimization () : m_visited_stmts (BITMAP_ALLOC (NULL)),
     235       225075 :                         m_crc_loop (nullptr), m_polynomial (0)
     236              :   {
     237       225075 :     set_initial_values ();
     238       225075 :   }
     239       225075 :   ~crc_optimization ()
     240              :   {
     241       225075 :     BITMAP_FREE (m_visited_stmts);
     242              :   }
     243              :   unsigned int execute (function *fun);
     244              : };
     245              : 
     246              : /* Prints extracted details of CRC calculation.  */
     247              : 
     248              : void
     249          304 : crc_optimization::dump_crc_information ()
     250              : {
     251          304 :   if (dump_file)
     252              :     {
     253          244 :       fprintf (dump_file,
     254              :                "Loop iteration number is " HOST_WIDE_INT_PRINT_UNSIGNED ".\n",
     255          244 :                tree_to_uhwi (m_crc_loop->nb_iterations));
     256          244 :       if (m_is_bit_forward)
     257          117 :         fprintf (dump_file, "Bit forward.\n");
     258              :       else
     259          127 :         fprintf (dump_file, "Bit reversed.\n");
     260              :     }
     261          304 : }
     262              : 
     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.  */
     267              : 
     268              : gimple *
     269           29 : crc_optimization::find_shift_after_xor (tree xored_crc)
     270              : {
     271           29 :   imm_use_iterator imm_iter;
     272           29 :   use_operand_p use_p;
     273              : 
     274           29 :   gcc_assert (TREE_CODE (xored_crc) == SSA_NAME);
     275              : 
     276           29 :   unsigned v = SSA_NAME_VERSION (xored_crc);
     277           29 :   if (bitmap_bit_p (m_visited_stmts, v))
     278              :     return nullptr;
     279           29 :   bitmap_set_bit (m_visited_stmts, v);
     280              : 
     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           68 :   FOR_EACH_IMM_USE_FAST (use_p, imm_iter, xored_crc)
     285              :     {
     286           34 :       gimple *stmt = USE_STMT (use_p);
     287              :       // Consider only statements within the loop
     288           34 :       if (!flow_bb_inside_loop_p (m_crc_loop, gimple_bb (stmt)))
     289            5 :         continue;
     290              : 
     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           29 :       if (gimple_code (stmt) == GIMPLE_PHI)
     295              :         {
     296              :           /* Don't continue searching if encountered the loop's beginning.  */
     297           19 :           if (bb_loop_header_p (gimple_bb (stmt)))
     298            5 :             continue;
     299              : 
     300           14 :           return find_shift_after_xor (gimple_phi_result (stmt));
     301              :         }
     302           10 :       else if (is_gimple_assign (stmt))
     303              :         {
     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           10 :           if (can_be_crc_shift (stmt))
     308              :             return stmt;
     309              :           return nullptr;
     310              :         }
     311            0 :       else if (!is_gimple_debug (stmt))
     312              :         return  nullptr;
     313           24 :     }
     314            5 :     return nullptr;
     315              : }
     316              : 
     317              : /* Returns opposite block of the XOR_BB from PRED_BB's dest blocks.  */
     318              : 
     319              : basic_block
     320           40 : crc_optimization::get_xor_bb_opposite (basic_block pred_bb, basic_block xor_bb)
     321              : {
     322              :   /* Check that the predecessor block has exactly two successors.  */
     323           40 :   if (EDGE_COUNT (pred_bb->succs) != 2)
     324              :     return nullptr;
     325              : 
     326           40 :   edge e0 = EDGE_SUCC (pred_bb, 0);
     327           40 :   edge e1 = EDGE_SUCC (pred_bb, 1);
     328              : 
     329              :   /* Ensure neither outgoing edge is marked as complex.  */
     330           40 :   if ((e0->flags & EDGE_COMPLEX)
     331           40 :       || (e1->flags & EDGE_COMPLEX))
     332              :     return nullptr;
     333              : 
     334              :   /* Check that one of the successors is indeed XOR_BB.  */
     335           40 :   gcc_assert ((e0->dest == xor_bb)
     336              :               || (e1->dest == xor_bb));
     337              : 
     338              :   /* Return the opposite block of XOR_BB.  */
     339           40 :   if (EDGE_SUCC (pred_bb, 0)->dest != xor_bb)
     340              :     return e0->dest;
     341           40 :   return e1->dest;
     342              : }
     343              : 
     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.  */
     348              : 
     349              : bool
     350           40 : crc_optimization::exists_shift_for_opp_xor_shift (basic_block opposite_bb)
     351              : {
     352           40 :   if (!opposite_bb)
     353              :     return false;
     354              : 
     355              :   /* Walk through the instructions of given basic block.  */
     356           40 :   for (gimple_stmt_iterator bsi = gsi_start_nondebug_bb (opposite_bb);
     357           41 :        !gsi_end_p (bsi); gsi_next_nondebug (&bsi))
     358              :     {
     359           39 :       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           39 :       if (is_gimple_assign (stmt))
     364              :         {
     365           39 :           if ((gimple_assign_rhs_code (stmt)
     366           39 :                == gimple_assign_rhs_code (m_shift_stmt))
     367           39 :               && integer_onep (gimple_assign_rhs2 (stmt)))
     368           38 :             return true;
     369              :         }
     370              :     }
     371              :   /* If there is no shift, return false.  */
     372            2 :   return false;
     373              : }
     374              : 
     375              : /* Returns true if condition COND checks MSB/LSB bit is 1.
     376              :    Otherwise, return false.  */
     377              : 
     378              : bool
     379          309 : crc_optimization::cond_true_is_checked_for_bit_one (const gcond *cond)
     380              : {
     381          309 :   if (!cond)
     382              :     return false;
     383              : 
     384          309 :   tree rhs = gimple_cond_rhs (cond);
     385          309 :   enum tree_code code = gimple_cond_code (cond);
     386              : 
     387              :   /* If the condition is something == 1 -> return true.  */
     388          309 :   if (code == EQ_EXPR && integer_onep (rhs))
     389              :     return true;
     390              : 
     391              :   /* If the condition is something != 0  or something < 0 -> return true.  */
     392          307 :   if ((code == NE_EXPR || code == LT_EXPR)
     393          307 :        && integer_zerop (rhs))
     394              :     return true;
     395              : 
     396              :   return false;
     397              : }
     398              : 
     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.
     403              : 
     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.  */
     408              : 
     409              : bool
     410          309 : crc_optimization::is_crc_satisfiable_cond (basic_block pred_bb,
     411              :                                            basic_block xor_bb,
     412              :                                            gcond *cond)
     413              : {
     414          309 :   edge true_edge;
     415          309 :   edge false_edge;
     416          309 :   extract_true_false_edges_from_block (pred_bb, &true_edge, &false_edge);
     417          309 :   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          309 :   if (cond_is_checked_for_bit_one && true_edge->dest == xor_bb)
     420              :     {
     421          308 :       if (dump_file && (dump_flags & TDF_DETAILS))
     422          235 :         fprintf (dump_file, "Xor is done on true branch.\n");
     423              :     }
     424            1 :   else if (!cond_is_checked_for_bit_one && false_edge->dest == xor_bb)
     425              :     {
     426            1 :       if (dump_file && (dump_flags & TDF_DETAILS))
     427            1 :         fprintf (dump_file, "Xor is done on false branch.\n");
     428              :     }
     429              :   else
     430              :     {
     431            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     432            0 :         fprintf (dump_file,
     433              :                  "Xor is done if MSB/LSB is not one, not CRC.\n");
     434            0 :       return false;
     435              :     }
     436              :   return true;
     437              : }
     438              : 
     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.  */
     442              : 
     443              : bool
     444          309 : crc_optimization::is_crc_checked (gcond *cond)
     445              : {
     446          309 :   tree lhs = gimple_cond_lhs (cond);
     447              : 
     448              :   /* As conditions are in canonical form, only left part must be an
     449              :     SSA_NAME.  */
     450          309 :   if (TREE_CODE (lhs) == SSA_NAME)
     451              :     {
     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          309 :       auto_vec<gimple *> cond_dep_stmts (m_crc_loop->num_nodes);
     456          309 :       bool set_defs_succeeded = set_defs (lhs, cond_dep_stmts, true);
     457          309 :       bitmap_clear (m_visited_stmts);
     458          309 :       if (!set_defs_succeeded)
     459              :         return false;
     460          306 :       return cond_depends_on_crc (cond_dep_stmts);
     461          309 :     }
     462              : 
     463              :   /* Return false if there is no dependence between if condition's variable
     464              :      and xor-ed variable.  */
     465              :   return false;
     466              : }
     467              : 
     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.  */
     475              : 
     476              : bool
     477          309 : crc_optimization::crc_cond (basic_block pred_bb, basic_block xor_bb)
     478              : {
     479              :   /* Check whether PRED_BB contains condition.  We will consider only those
     480              :      cases when xor is done immediately under the condition.  */
     481          618 :   gcond *cond = safe_dyn_cast<gcond *> (gsi_stmt (gsi_last_bb (pred_bb)));
     482          309 :   if (!cond)
     483              :     {
     484            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     485            0 :         fprintf (dump_file, "No condition.\n");
     486            0 :       return false;
     487              :     }
     488              : 
     489              :   /* Check that xor is done in case the MSB/LSB is 1.  */
     490          309 :   if (!is_crc_satisfiable_cond (pred_bb, xor_bb, cond))
     491              :     return false;
     492              : 
     493              :   /* Check that CRC's MSB/LSB is checked in the condition.
     494              :      Set data member if not set and exists.  */
     495          309 :   if (!is_crc_checked (cond))
     496              :     {
     497            5 :       if (dump_file && (dump_flags & TDF_DETAILS))
     498            0 :         fprintf (dump_file, "The condition is not related to the CRC check.\n");
     499            5 :       return false;
     500              :     }
     501              :   return true;
     502              : }
     503              : 
     504              : /* Returns true if the statement with STMT_CODE may occur in CRC calculation.
     505              :    Otherwise, returns false.  */
     506              : 
     507              : bool
     508         1019 : crc_optimization::is_acceptable_stmt_code (const tree_code &stmt_code)
     509              : {
     510         1019 :   return (stmt_code == BIT_IOR_EXPR)
     511         1019 :          || (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          300 :          || (TREE_CODE_CLASS (stmt_code) == tcc_unary);
     518              : }
     519              : 
     520              : /* Returns true if ASSIGN_STMT does shift with 1.  Otherwise, returns false.  */
     521              : 
     522              : bool
     523          334 : crc_optimization::can_be_crc_shift (gimple *assign_stmt)
     524              : {
     525          334 :   tree_code stmt_code = gimple_assign_rhs_code (assign_stmt);
     526          334 :   if (stmt_code == LSHIFT_EXPR || stmt_code == RSHIFT_EXPR)
     527              :     {
     528          316 :       m_is_bit_forward = (stmt_code == LSHIFT_EXPR);
     529              :       /* Check that shift one is done, keep shift statement.  */
     530          316 :       if (integer_onep (gimple_assign_rhs2 (assign_stmt)))
     531              :         {
     532          311 :           if (m_shift_stmt)
     533              :             {
     534            0 :               if (dump_file && (dump_flags & TDF_DETAILS))
     535            0 :                 fprintf (dump_file,
     536              :                          "Already there is one shift.\n");
     537            0 :               return false;
     538              :             }
     539          311 :           if (dump_file && (dump_flags & TDF_DETAILS))
     540          236 :             fprintf (dump_file,
     541              :                      "Found <<1 or >>1.\n");
     542          311 :           return true;
     543              :         }
     544              :       /* This filters out cases, when xor-ed variable is shifted by values
     545              :          other than 1.  */
     546              :     }
     547              :     return false;
     548              : }
     549              : 
     550              : /* Returns true if the operation done in ASSIGN_STMT can occur during CRC
     551              :    calculation.  Otherwise, returns false.  */
     552              : 
     553              : bool
     554         1019 : crc_optimization::can_not_be_crc_stmt (gimple *assign_stmt)
     555              : {
     556         1019 :   tree_code stmt_code = gimple_assign_rhs_code (assign_stmt);
     557         1019 :   if (!is_acceptable_stmt_code (stmt_code))
     558              :     {
     559            4 :       if (dump_file && (dump_flags & TDF_DETAILS))
     560            0 :         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));
     564              : 
     565            4 :       return true;
     566              :     }
     567              :   return false;
     568              : }
     569              : 
     570              : /* Returns true if we can get definition of the VARIABLE, and the definition
     571              :    is not outside the loop.  Otherwise, returns false.  */
     572              : 
     573              : bool
     574         2658 : crc_optimization::passes_checks_for_def_chain (tree variable)
     575              : {
     576         2658 :   if (!(variable && TREE_CODE (variable) == SSA_NAME))
     577              :     return false;
     578              : 
     579              :   /* No definition chain for default defs.  */
     580         1809 :   if (SSA_NAME_IS_DEFAULT_DEF (variable))
     581              :     return false;
     582              : 
     583         1809 :   gimple *stmt = SSA_NAME_DEF_STMT (variable);
     584              : 
     585         1809 :   if (!stmt)
     586              :     return false;
     587              : 
     588              :   /* Don't go outside the loop.  */
     589         1809 :   if (!flow_bb_inside_loop_p (m_crc_loop, gimple_bb (stmt)))
     590              :     return false;
     591              : 
     592              :   return true;
     593              : }
     594              : 
     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.  */
     600              : 
     601              : bool
     602         2658 : crc_optimization::set_defs (tree name, auto_vec<gimple *> &use_defs,
     603              :                             bool keep_only_header_phis = false)
     604              : {
     605         2658 :   if (!passes_checks_for_def_chain (name))
     606              :     return true;
     607              : 
     608              :   /* Don't consider already visited names.  */
     609         1804 :   unsigned v = SSA_NAME_VERSION (name);
     610         1804 :   if (bitmap_bit_p (m_visited_stmts, v))
     611              :     return true;
     612         1802 :   bitmap_set_bit (m_visited_stmts, v);
     613              : 
     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         1802 :   if (use_defs.length () > 12)
     619              :     return false;
     620              : 
     621         1802 :   gimple *stmt = SSA_NAME_DEF_STMT (name);
     622              : 
     623              :   /* If it's not specified to keep only header phi's,
     624              :      then keep all statements.  */
     625         1802 :   if (!keep_only_header_phis)
     626          728 :     use_defs.safe_push (stmt);
     627              : 
     628              :   /* If it is an assignment statement,
     629              :      get and check def-use chain for the first and second operands.  */
     630         1802 :   if (is_a<gassign *> (stmt))
     631              :     {
     632         1019 :       if (can_not_be_crc_stmt (stmt))
     633              :         return false;
     634              : 
     635         1015 :       tree ssa1 = gimple_assign_rhs1 (stmt);
     636         1015 :       tree ssa2 = gimple_assign_rhs2 (stmt);
     637         1015 :       if (!set_defs (ssa1, use_defs, keep_only_header_phis))
     638              :         return false;
     639         1003 :       if (!set_defs (ssa2, use_defs, keep_only_header_phis))
     640              :         return false;
     641              :       return true;
     642              :     }
     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          783 :   else if (is_a<gphi *> (stmt))
     647              :     {
     648          770 :       if (bb_loop_header_p (gimple_bb (stmt)))
     649              :         {
     650              :           /* If it's specified to keep only header phi's, keep it.  */
     651          770 :           if (keep_only_header_phis)
     652          446 :             use_defs.safe_push (stmt);
     653              :         }
     654              :       else
     655              :         {
     656            0 :           for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
     657              :             {
     658            0 :               tree val = gimple_phi_arg_def (stmt, i);
     659            0 :               if (!set_defs (val, use_defs, keep_only_header_phis))
     660              :                 return false;
     661              :             }
     662              :         }
     663          770 :       return true;
     664              :     }
     665              : 
     666              :   /* Return false for other than assigment and phi statement.  */
     667              :   return false;
     668              : }
     669              : 
     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.  */
     674              : 
     675              : gimple *
     676          317 : crc_optimization::find_shift_before_xor (const auto_vec<gimple *> &stmts)
     677              : {
     678         1033 :   for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
     679              :     {
     680              :       /* If it is an assignment statement, check that is does shift 1.  */
     681          343 :       if (is_a<gassign *> (*stmt_it))
     682              :         {
     683          324 :           if (can_be_crc_shift (*stmt_it))
     684          302 :             return *stmt_it;
     685              :         }
     686              :     }
     687              :   return nullptr;
     688              : }
     689              : 
     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.  */
     697              : 
     698              : bool
     699          317 : crc_optimization::set_crc_and_data_phi (auto_vec<gimple *> &stmts)
     700              : {
     701         2359 :   for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
     702              :     {
     703          704 :       if (is_a<gphi *> (*stmt_it) && bb_loop_header_p (gimple_bb (*stmt_it)))
     704              :         {
     705          324 :           if (!m_phi_for_crc)
     706          317 :             m_phi_for_crc = as_a<gphi *> (*stmt_it);
     707            7 :           else if (!m_phi_for_data)
     708            7 :             m_phi_for_data = as_a<gphi *> (*stmt_it);
     709              :           else
     710              :             {
     711            0 :               if (dump_file && (dump_flags & TDF_DETAILS))
     712            0 :                 fprintf (dump_file, "Xor-ed variable depends on more than 2 "
     713              :                                     "phis.\n");
     714            0 :               return false;
     715              :             }
     716              :         }
     717              :     }
     718          317 :   return m_phi_for_crc;
     719              : }
     720              : 
     721              : /*  Returns true if the variable checked in the condition depends on possible
     722              :     CRC value.  Otherwise, returns false.  */
     723              : 
     724              : bool
     725          306 : crc_optimization::cond_depends_on_crc (auto_vec<gimple *>& stmts)
     726              : {
     727          306 :   bool con_depends_on_crc = false;
     728              : 
     729              :   /* The condition may depend maximum on data and CRC phi's.  */
     730          306 :   if (stmts.length () > 2)
     731              :     return false;
     732              : 
     733         1802 :   for (auto stmt_it = stmts.begin (); stmt_it != stmts.end (); stmt_it++)
     734              :     {
     735          446 :       if (is_a<gphi *> (*stmt_it) && bb_loop_header_p (gimple_bb (*stmt_it)))
     736              :         {
     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          446 :           if (m_phi_for_crc == (*stmt_it))
     741              :             con_depends_on_crc = true;
     742          142 :           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          138 :           else if (!m_phi_for_data)
     747          138 :             m_phi_for_data = as_a<gphi *> (*stmt_it);
     748              :         }
     749              :     }
     750              :   return con_depends_on_crc;
     751              : }
     752              : 
     753              : /* Sets initial values for the CRC analysis.
     754              :    This function is used multiple times during the analyses.  */
     755              : 
     756              : void
     757       225615 : crc_optimization::set_initial_values ()
     758              : {
     759       225615 :   m_crc_arg = nullptr;
     760       225615 :   m_data_arg = nullptr;
     761       225615 :   m_shift_stmt = nullptr;
     762       225615 :   m_phi_for_crc = nullptr;
     763       225615 :   m_phi_for_data = nullptr;
     764       225615 :   m_is_bit_forward = false;
     765       225615 : }
     766              : 
     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.  */
     776              : 
     777              : bool
     778          540 : crc_optimization::xor_calculates_crc (function *crc_fun,
     779              :                                       const gimple *xor_stmt)
     780              : {
     781          540 :   tree crc_var = gimple_assign_lhs (xor_stmt);
     782          540 :   set_initial_values ();
     783          540 :   tree ssa1 = gimple_assign_rhs1 (xor_stmt);
     784          540 :   tree ssa2 = gimple_assign_rhs2 (xor_stmt);
     785          540 :   if (TREE_CODE (ssa2) != INTEGER_CST)
     786              :     {
     787          209 :       if (dump_file && (dump_flags & TDF_DETAILS))
     788          143 :         fprintf (dump_file, "Second operand of the "
     789              :                             "xor statement isn't an integer constant.\n");
     790          209 :       return false;
     791              :     }
     792              : 
     793              :   /* Get the statements within the loop on which xor-ed variable depends.  */
     794          331 :   auto_vec<gimple *> xor_dep_stmts (m_crc_loop->num_nodes);
     795          331 :   bool set_defs_succeeded = set_defs (ssa1, xor_dep_stmts);
     796          331 :   bitmap_clear (m_visited_stmts);
     797          331 :   if (!set_defs_succeeded)
     798              :     {
     799           14 :       xor_dep_stmts.release ();
     800           14 :       return false;
     801              :     }
     802              : 
     803          317 :   m_shift_stmt = find_shift_before_xor (xor_dep_stmts);
     804              : 
     805          317 :   if (!set_crc_and_data_phi (xor_dep_stmts))
     806              :     {
     807            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     808            0 :         fprintf (dump_file, "Xor isn't used for CRC calculation.\n");
     809            0 :       return false;
     810              :     }
     811              : 
     812              :   /* Check the case when shift is done after xor.  */
     813          317 :   if (!m_shift_stmt)
     814              :     {
     815           15 :       if (dump_file && (dump_flags & TDF_DETAILS))
     816            9 :         fprintf (dump_file, "No shift before xor, trying to find after xor.\n");
     817              : 
     818           15 :       m_shift_stmt = find_shift_after_xor (crc_var);
     819           15 :       bitmap_clear (m_visited_stmts);
     820           15 :       if (!m_shift_stmt)
     821              :         return false;
     822              :     }
     823              : 
     824              :   /* Get the basic block where xor operation is done.  */
     825          311 :   basic_block xor_bb = gimple_bb (xor_stmt);
     826              : 
     827              :   /* Get the predecessor basic block of xor's block.  */
     828          338 :   if (!single_pred_p (xor_bb))
     829              :     return false;
     830          311 :   basic_block block_of_condition = single_pred (xor_bb);
     831              : 
     832              : 
     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          311 :   if (m_shift_stmt && gimple_bb (m_shift_stmt) == xor_bb)
     837              :     {
     838           40 :       basic_block opposite_block = get_xor_bb_opposite (block_of_condition,
     839              :                                                         xor_bb);
     840           40 :       if (!exists_shift_for_opp_xor_shift (opposite_block))
     841              :         {
     842            2 :           if (dump_file && (dump_flags & TDF_DETAILS))
     843            0 :             fprintf (dump_file,
     844              :                      "Opposite block doesn't contain shift's pair.\n");
     845            2 :           return false;
     846              :         }
     847              :     }
     848              : 
     849              :   /* Check that xor is done if MSB/LSB is one.
     850              :      If all checks succeed, then it may be a CRC.  */
     851          309 :   if (crc_cond (block_of_condition, xor_bb))
     852              :     {
     853          304 :       if (dump_file)
     854          244 :         fprintf (dump_file,
     855              :                  "\n%s function maybe contains CRC calculation.\n",
     856              :                  function_name (crc_fun));
     857          304 :       return true;
     858              :     }
     859              : 
     860              :   return false;
     861          331 : }
     862              : 
     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.  */
     867              : 
     868              : bool
     869        19363 : crc_optimization::loop_contains_two_conditional_bb (basic_block *loop_bbs,
     870              :                                                     unsigned loop_num_nodes)
     871              : {
     872        19363 :   unsigned conditional_bb_count = 0;
     873              :   /* Iterate through the loop until the conditional branches count
     874              :      is below 3.  */
     875        76016 :   for (unsigned i = 0; i < loop_num_nodes && conditional_bb_count <= 2; i++)
     876              :     {
     877        56653 :       basic_block bb = loop_bbs[i];
     878        56653 :       if (!single_succ_p (bb))
     879        26359 :         conditional_bb_count++;
     880              :     }
     881        19363 :   return conditional_bb_count == 2;
     882              : }
     883              : 
     884              : /* Checks the FUNC_LOOP loop's iteration number.
     885              :    The loop for CRC calculation may do 8, 16, 24, 32, 64 iterations.  */
     886              : 
     887              : bool
     888       511137 : crc_optimization::satisfies_crc_loop_iteration_count (class loop *func_loop)
     889              : {
     890              :   /* Calculate the number of times the latch of the loop is executed.
     891              :      The function sets NB_ITERATIONS field of the loop.  */
     892       511137 :   number_of_latch_executions (func_loop);
     893       511137 :   tree n_inters = func_loop->nb_iterations;
     894       511137 :   if (n_inters == NULL_TREE || n_inters == chrec_dont_know)
     895              :     {
     896       261153 :       if (dump_file && (dump_flags & TDF_DETAILS))
     897           41 :         fprintf (dump_file,
     898              :                  "Loop iteration number is chrec_dont_know.\n");
     899       261153 :       return false;
     900              : 
     901              :     }
     902       249984 :   else if (tree_fits_uhwi_p (n_inters))
     903              :     {
     904       159408 :       unsigned HOST_WIDE_INT
     905       159408 :       loop_iteration_number = tree_to_uhwi (n_inters);
     906       159408 :       if (dump_file && (dump_flags & TDF_DETAILS))
     907          271 :         fprintf (dump_file, "Loop iteration number is "
     908              :                  HOST_WIDE_INT_PRINT_UNSIGNED ".\n", loop_iteration_number);
     909              : 
     910       159408 :       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;
     914              :     }
     915       230621 :   if (stderr && (dump_flags & TDF_DETAILS))
     916           30 :     fprintf (dump_file, "Loop iteration number isn't a constant.\n");
     917              :   return false;
     918              : }
     919              : 
     920              : /* This is the main function that checks whether the given LOOP
     921              :    calculates CRC and extracts details of the CRC calculation.
     922              : 
     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.  */
     928              : 
     929              : bool
     930       511137 : crc_optimization::loop_may_calculate_crc (class loop *loop)
     931              : {
     932              :   /* Only examine innermost loops.  */
     933       511137 :   if (!loop || loop->inner)
     934              :     return false;
     935              : 
     936       511137 :   if (!satisfies_crc_loop_iteration_count (loop))
     937              :     return false;
     938              : 
     939        19363 :   m_crc_loop = loop;
     940        19363 :   basic_block *loop_bbs = get_loop_body_in_dom_order (m_crc_loop);
     941              : 
     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        19363 :   if (!loop_contains_two_conditional_bb (loop_bbs, m_crc_loop->num_nodes))
     945              :     {
     946        14657 :       if (dump_file && (dump_flags & TDF_DETAILS))
     947            6 :         fprintf (dump_file,
     948              :                  "The number of conditional "
     949              :                  "branches in the loop isn't 2.\n");
     950        14657 :       free (loop_bbs);
     951        14657 :       return false;
     952              :     }
     953              : 
     954              :   unsigned short checked_xor_count = 0;
     955              :   /* Walk bbs of the loop.  */
     956        26843 :   for (unsigned int i = 0; i < m_crc_loop->num_nodes; i++)
     957              :     {
     958        22458 :       basic_block bb = loop_bbs[i];
     959              :       /* Walk instructions of the bb.  */
     960        22458 :       for (gimple_stmt_iterator bsi = gsi_start_nondebug_bb (bb);
     961        73235 :            !gsi_end_p (bsi); gsi_next_nondebug (&bsi))
     962              :         {
     963        51098 :           gimple *stmt = gsi_stmt (bsi);
     964              :           /* If there is an xor instruction,
     965              :              check that it is calculating CRC.  */
     966        51098 :           if (is_gimple_assign (stmt)
     967        51098 :               && gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR)
     968              :             {
     969          540 :               if (dump_file && (dump_flags & TDF_DETAILS))
     970          379 :                 fprintf (dump_file,
     971              :                          "Found xor, "
     972              :                          "checking whether it is for CRC calculation.\n");
     973              : 
     974          540 :               if (xor_calculates_crc (cfun, stmt))
     975              :                 {
     976          304 :                   dump_crc_information ();
     977          304 :                   free (loop_bbs);
     978          321 :                   return true;
     979              :                 }
     980              : 
     981          236 :               if (++checked_xor_count == 2)
     982              :                 {
     983           17 :                   free (loop_bbs);
     984           17 :                   return false;
     985              :                 }
     986              :             }
     987              :         }
     988              :     }
     989         4385 :   free (loop_bbs);
     990         4385 :   return false;
     991              : }
     992              : 
     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.  */
     999              : 
    1000              : bool
    1001          261 : crc_optimization::loop_calculates_crc (gphi *output_crc,
    1002              :                                        std::pair<tree, value *> calc_polynom)
    1003              : {
    1004              :   /* Create LFSR state using extracted polynomial.  */
    1005          522 :   value * lfsr = state::create_lfsr (calc_polynom.first, calc_polynom.second,
    1006          261 :                                      m_is_bit_forward);
    1007          261 :   if (!lfsr)
    1008              :     {
    1009           20 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1010           14 :         fprintf (dump_file, "Couldn't create LFSR!\n");
    1011           20 :       return false;
    1012              :     }
    1013              : 
    1014          241 :   if (dump_file && (dump_flags & TDF_DETAILS))
    1015              :     {
    1016          180 :       fprintf (dump_file, "\nLFSR value is \n");
    1017          180 :       state::print_value (lfsr);
    1018              :     }
    1019              : 
    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          241 :   bool is_crc = true;
    1024          241 :   crc_symbolic_execution loop_executor (m_crc_loop, output_crc);
    1025         3635 :   while (!loop_executor.is_last_iteration ())
    1026              :     {
    1027         3158 :       if (!loop_executor.symb_execute_crc_loop ())
    1028              :         {
    1029            0 :           if (dump_file)
    1030            0 :             fprintf (dump_file, "\nCRC verification didn't succeed "
    1031              :                                 "during symbolic execution!\n");
    1032              :           is_crc = false;
    1033              :           break;
    1034              :         }
    1035              : 
    1036              :       /* Check whether LFSR and obtained states are same.  */
    1037         3158 :       tree calculated_crc = PHI_ARG_DEF_FROM_EDGE (output_crc,
    1038              :                                                    single_exit (m_crc_loop));
    1039         3158 :       if (!all_states_match_lfsr (lfsr, m_is_bit_forward, calculated_crc,
    1040              :                                  loop_executor.get_final_states ()))
    1041              :         {
    1042            5 :           if (dump_file && (dump_flags & TDF_DETAILS))
    1043            3 :             fprintf (dump_file, "Returned state and LFSR differ.\n");
    1044              :           is_crc = false;
    1045              :           break;
    1046              :         }
    1047              :     }
    1048          241 :   delete lfsr;
    1049          241 :   return is_crc;
    1050          241 : }
    1051              : 
    1052              : /* Returns true if OUTPUT_CRC's result is the input of M_PHI_FOR_CRC.
    1053              :   Otherwise, returns false.  */
    1054              : 
    1055              : bool
    1056          285 : crc_optimization::is_output_crc (gphi *output_crc)
    1057              : {
    1058          285 :   tree crc_of_exit
    1059          285 :     = PHI_ARG_DEF_FROM_EDGE (output_crc, single_exit (m_crc_loop));
    1060          285 :   tree crc_of_latch
    1061          285 :     = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, loop_latch_edge (m_crc_loop));
    1062          285 :   if (crc_of_exit == crc_of_latch)
    1063              :     {
    1064          282 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1065              :         {
    1066          215 :           fprintf (dump_file, "Output CRC is ");
    1067          215 :           print_gimple_expr (dump_file, (gimple *) output_crc, dump_flags);
    1068          215 :           fprintf (dump_file, "\n");
    1069              :         }
    1070          282 :       return true;
    1071              :     }
    1072              :   else
    1073              :     {
    1074            3 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1075            3 :         fprintf (dump_file, "Output CRC and determined input CRC "
    1076              :                             "differ.\n");
    1077            3 :       return false;
    1078              :     }
    1079              : }
    1080              : 
    1081              : /* Swaps M_PHI_FOR_CRC and M_PHI_FOR_DATA if they are mixed.  */
    1082              : 
    1083              : void
    1084          285 : crc_optimization::swap_crc_and_data_if_needed (gphi *output_crc)
    1085              : {
    1086          285 :   tree crc_of_exit
    1087          285 :     = PHI_ARG_DEF_FROM_EDGE (output_crc, single_exit (m_crc_loop));
    1088          285 :   edge crc_loop_latch = loop_latch_edge (m_crc_loop);
    1089          285 :   if (crc_of_exit != PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, crc_loop_latch))
    1090              :     {
    1091            7 :       if (m_phi_for_data
    1092            7 :           && crc_of_exit == PHI_ARG_DEF_FROM_EDGE (m_phi_for_data,
    1093              :                                                    crc_loop_latch))
    1094              :         {
    1095            4 :           std::swap (m_phi_for_crc, m_phi_for_data);
    1096              :         }
    1097              :     }
    1098          285 : }
    1099              : 
    1100              : /* Validates CRC and data arguments and
    1101              :    sets them for potential CRC loop replacement.
    1102              : 
    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.
    1106              : 
    1107              :   Returns true if the arguments are valid and the loop replacement is possible,
    1108              :   false otherwise.  */
    1109              : 
    1110          282 : bool crc_optimization::validate_crc_and_data ()
    1111              : {
    1112              :   /* Set m_crc_arg and check if fits in word_mode.  */
    1113          282 :   gcc_assert (m_phi_for_crc);
    1114          282 :   m_crc_arg = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc,
    1115              :                                      loop_preheader_edge (m_crc_loop));
    1116          282 :   gcc_assert (m_crc_arg);
    1117              : 
    1118          282 :   unsigned HOST_WIDE_INT
    1119          282 :   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          282 :   if (TYPE_PRECISION (TREE_TYPE (m_crc_arg)) < data_size)
    1122              :     return false;
    1123              : 
    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          282 :   if (m_phi_for_data)
    1128              :     {
    1129          125 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1130          121 :         fprintf (dump_file,
    1131              :                  "Data and CRC are xor-ed in the for loop.  Initializing data "
    1132              :                  "with its value.\n");
    1133          125 :       m_data_arg = PHI_ARG_DEF_FROM_EDGE (m_phi_for_data,
    1134              :                                           loop_preheader_edge (m_crc_loop));
    1135          125 :       gcc_assert (m_data_arg);
    1136          125 :       if (TYPE_PRECISION (TREE_TYPE (m_data_arg)) != data_size)
    1137              :         {
    1138            9 :           if (dump_file && (dump_flags & TDF_DETAILS))
    1139            9 :             fprintf (dump_file,
    1140              :                      "Loop iteration number and data's size differ.\n");
    1141            9 :           return false;
    1142              :         }
    1143              :         return true;
    1144              :     }
    1145              :   return true;
    1146              : }
    1147              : 
    1148              : /* Convert polynomial to unsigned HOST_WIDE_INT.  */
    1149              : 
    1150              : void
    1151          261 : crc_optimization::construct_constant_polynomial (value *polynomial)
    1152              : {
    1153          261 :   m_polynomial = 0;
    1154         6949 :   for (unsigned i = 0; i < (*polynomial).length (); i++)
    1155              :     {
    1156         6688 :       value_bit *const_bit;
    1157         6688 :       if (m_is_bit_forward)
    1158         2904 :         const_bit = (*polynomial)[(*polynomial).length () - 1 - i];
    1159              :       else
    1160         3784 :         const_bit = (*polynomial)[i];
    1161         6688 :       m_polynomial <<= 1;
    1162        11290 :       m_polynomial ^= (as_a<bit *> (const_bit))->get_val () ? 1 : 0;
    1163              :     }
    1164          261 : }
    1165              : 
    1166              : /* Returns phi statement which may hold the calculated CRC.  */
    1167              : 
    1168              : gphi *
    1169          304 : crc_optimization::get_output_phi ()
    1170              : {
    1171          304 :   edge loop_exit = single_exit (m_crc_loop);
    1172          304 :   if (!loop_exit)
    1173              :     {
    1174            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1175            0 :         fprintf (dump_file, "The loop doesn't have single exit.\n");
    1176            0 :       return nullptr;
    1177              :     }
    1178          304 :   basic_block bb = loop_exit->dest;
    1179          304 :   gphi *output_crc = nullptr;
    1180          304 :   int phi_count = 0;
    1181              : 
    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          647 :   for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
    1187          343 :        gsi_next (&gsi))
    1188              :     {
    1189          362 :       tree phi_result = gimple_phi_result (gsi.phi ());
    1190              : 
    1191              :       /* Don't consider virtual operands.  */
    1192          724 :       if (!virtual_operand_p (phi_result))
    1193              :         {
    1194          323 :           if (phi_count < 1)
    1195              :             {
    1196              :               output_crc = gsi.phi ();
    1197              :               phi_count++;
    1198              :             }
    1199              :           else
    1200              :             {
    1201           19 :               if (dump_file && (dump_flags & TDF_DETAILS))
    1202           18 :                 fprintf (dump_file, "There is more than one output phi.\n");
    1203           19 :               return nullptr;
    1204              :             }
    1205              :         }
    1206              :     }
    1207              : 
    1208          285 :   if (output_crc)
    1209              :     {
    1210          285 :       if (gimple_phi_num_args (output_crc) == 1)
    1211              :         return output_crc;
    1212              :     }
    1213              : 
    1214            0 :   if (dump_file && (dump_flags & TDF_DETAILS))
    1215            0 :     fprintf (dump_file, "Couldn't determine output CRC.\n");
    1216              :   return nullptr;
    1217              : }
    1218              : 
    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.  */
    1222              : 
    1223              : bool
    1224          236 : crc_optimization::optimize_crc_loop (gphi *output_crc)
    1225              : {
    1226          236 :   if (!output_crc)
    1227              :     {
    1228            0 :       if (dump_file)
    1229            0 :         fprintf (dump_file, "Couldn't determine output CRC.\n");
    1230            0 :       return false;
    1231              :     }
    1232              : 
    1233          236 :   if (!m_data_arg)
    1234              :     {
    1235          139 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1236           80 :         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          139 :       unsigned HOST_WIDE_INT
    1242          139 :         data_size = tree_to_uhwi (m_crc_loop->nb_iterations) + 1;
    1243          139 :       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          139 :       m_data_arg = build_int_cstu (type, 0);
    1247              :     }
    1248              : 
    1249              :   /* Build tree node for the polynomial from its constant value.  */
    1250          236 :   tree polynomial_arg = build_int_cstu (TREE_TYPE (m_crc_arg), m_polynomial);
    1251          236 :   gcc_assert (polynomial_arg);
    1252              : 
    1253          236 :   internal_fn ifn;
    1254          236 :   if (m_is_bit_forward)
    1255              :     ifn = IFN_CRC;
    1256              :   else
    1257          120 :     ifn = IFN_CRC_REV;
    1258              : 
    1259          236 :   tree phi_result = gimple_phi_result (output_crc);
    1260          236 :   location_t loc;
    1261          236 :   loc = EXPR_LOCATION (phi_result);
    1262              : 
    1263              :   /* Add IFN call and write the return value in the phi_result.  */
    1264          236 :   gcall *call = gimple_build_call_internal (ifn, 3, m_crc_arg, m_data_arg,
    1265              :                                             polynomial_arg);
    1266              : 
    1267          236 :   gimple_call_set_lhs (call, phi_result);
    1268          236 :   gimple_set_location (call, loc);
    1269          236 :   gimple_stmt_iterator si = gsi_after_labels (gimple_bb (output_crc));
    1270          236 :   gsi_insert_before (&si, call, GSI_SAME_STMT);
    1271              : 
    1272              :   /* Remove phi statement, which was holding CRC result.  */
    1273          236 :   gimple_stmt_iterator tmp_gsi = gsi_for_stmt (output_crc);
    1274          236 :   remove_phi_node (&tmp_gsi, false);
    1275              : 
    1276              :   /* Alter the exit condition of the loop to always exit.  */
    1277          236 :   gcond* loop_exit_cond = get_loop_exit_condition (m_crc_loop);
    1278          236 :   gimple_cond_make_false (loop_exit_cond);
    1279          236 :   update_stmt (loop_exit_cond);
    1280          236 :   return true;
    1281              : }
    1282              : 
    1283              : unsigned int
    1284       225075 : crc_optimization::execute (function *fun)
    1285              : {
    1286       225075 :   if (dump_file && (dump_flags & TDF_DETAILS))
    1287          297 :     fprintf (dump_file, "\nExamining %s function.\n",
    1288              :              function_name (fun));
    1289              : 
    1290       450150 :   if (number_of_loops (fun) <= 1)
    1291              :     return 0;
    1292              : 
    1293              :   /* Get loops of the function.  */
    1294       225075 :   auto loop_list = loops_list (fun, LI_ONLY_INNERMOST);
    1295      1186294 :   for (auto loop: loop_list)
    1296              :     {
    1297              :       /* Perform initial checks to filter out non-CRCs.  */
    1298       511137 :       if (loop_may_calculate_crc (loop))
    1299              :         {
    1300              :           /* Get the phi which will hold the calculated CRC.  */
    1301          304 :           gphi *output_crc = get_output_phi ();
    1302          304 :           if (!output_crc)
    1303              :             break;
    1304              : 
    1305          285 :           swap_crc_and_data_if_needed (output_crc);
    1306          285 :           if (!is_output_crc (output_crc))
    1307              :             break;
    1308          282 :           if (!validate_crc_and_data ())
    1309              :             break;
    1310              : 
    1311          273 :           edge loop_latch = loop_latch_edge (m_crc_loop);
    1312          273 :           tree calced_crc = PHI_ARG_DEF_FROM_EDGE (m_phi_for_crc, loop_latch);
    1313          273 :           crc_symbolic_execution execute_loop (m_crc_loop, nullptr);
    1314              :           /* Execute the loop assigning specific values to CRC and data
    1315              :              for extracting the polynomial.  */
    1316          273 :           std::pair <tree, value *>
    1317          273 :               calc_polynom = execute_loop.extract_polynomial (m_phi_for_crc,
    1318              :                                                               m_phi_for_data,
    1319              :                                                               calced_crc,
    1320          273 :                                                               m_is_bit_forward);
    1321              : 
    1322          273 :           value *polynom_value = calc_polynom.second;
    1323              :           /* Stop analysis if we couldn't get the polynomial's value.  */
    1324          273 :           if (!polynom_value)
    1325              :             break;
    1326              : 
    1327              :           /* Stop analysis in case optimize_size is specified
    1328              :              and table-based would be generated.  This check is only needed for
    1329              :              TARGET_CRC case, as polynomial's value isn't known in the
    1330              :              beginning.  */
    1331          261 :           construct_constant_polynomial (polynom_value);
    1332              : 
    1333          261 :           if (!loop_calculates_crc (output_crc, calc_polynom))
    1334              :             break;
    1335              : 
    1336          236 :           if (dump_file)
    1337          180 :             fprintf (dump_file, "The loop with %d header BB index "
    1338          180 :                                 "calculates CRC!\n", m_crc_loop->header->index);
    1339              : 
    1340          236 :           if (!optimize_crc_loop (output_crc))
    1341              :             {
    1342            0 :               if (dump_file)
    1343            0 :                 fprintf (dump_file, "Couldn't generate faster CRC code.\n");
    1344              :             }
    1345          273 :         }
    1346              :     }
    1347       225075 :   return 0;
    1348       225075 : }
    1349              : 
    1350              : namespace
    1351              : {
    1352              : 
    1353              :     const pass_data pass_data_crc_optimization
    1354              :         = {
    1355              :             GIMPLE_PASS, /* type */
    1356              :             "crc", /* name */
    1357              :             OPTGROUP_NONE, /* optinfo_flags */
    1358              :             TV_GIMPLE_CRC_OPTIMIZATION, /* tv_id */
    1359              :             (PROP_cfg | PROP_ssa), /* properties_required */
    1360              :             0, /* properties_provided */
    1361              :             0, /* properties_destroyed */
    1362              :             0, /* todo_flags_start */
    1363              :             0, /* todo_flags_finish */
    1364              :         };
    1365              : 
    1366              :     class pass_crc_optimization : public gimple_opt_pass {
    1367              :      public:
    1368       285722 :       pass_crc_optimization (gcc::context *ctxt)
    1369       571444 :           : gimple_opt_pass (pass_data_crc_optimization, ctxt)
    1370              :       {}
    1371              : 
    1372              :       /* opt_pass methods: */
    1373       241458 :       virtual bool gate (function *)
    1374              :       {
    1375       241458 :         return flag_optimize_crc;
    1376              :       }
    1377              : 
    1378              :       virtual unsigned int execute (function *);
    1379              : 
    1380              :     }; // class pass_crc_optimization
    1381              : 
    1382              :     unsigned int
    1383       225075 :     pass_crc_optimization::execute (function *fun)
    1384              :     {
    1385       225075 :       return crc_optimization ().execute (fun);
    1386              :     }
    1387              : 
    1388              : } // anon namespace
    1389              : 
    1390              : gimple_opt_pass *
    1391       285722 : make_pass_crc_optimization (gcc::context *ctxt)
    1392              : {
    1393       285722 :   return new pass_crc_optimization (ctxt);
    1394              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.