/* Execute symbolically all paths of the loop.
   Copyright (C) 2022-2025 Free Software Foundation, Inc.
   Contributed by Mariam Arutunian <mariamarutunian@gmail.com>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.   */

#ifndef GCC_CRC_VERIFICATION
#define GCC_CRC_VERIFICATION

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "cfgloop.h"
#include "sym-exec/sym-exec-state.h"

class crc_symbolic_execution {

 private:
  /* A vector of states to keep the current state of each executed path.  */
  vec<state *> m_states;

  /* A vector of final states
     to keep the returned_value and path conditions.  */
  vec<state *> m_final_states;

  /* Potential CRC loop, which must be executed symbolically,
     to check whether it calculates CRC.  */
  class loop *m_crc_loop;

  /* Output CRC from the last block of the loop.  */
  gphi *m_output_crc;

  /* Indicates whether the loop execution brought to loop exit.
     I.e. the condition of the loop is false.  */
  bool m_is_last_iteration;

  /* Returns true if the variable is used outside the loop.
     Otherwise, returns false.  */
  bool is_used_outside_the_loop (tree);

  /* Add next basic blocks of the conditional block
     for the execution path into the stack.
     If the condition depends on symbolic values, keep both edges.
     If the condition is true, keep true edge, else - false edge.
     Returns true if addition succeed.  Otherwise - false.  */
  bool add_next_bbs (basic_block, state *, auto_vec<edge> &);

  /* Keep conditions depending on symbolic variables in the states.  */
  static bool add_condition (const gcond *, state *, state *);

  /* The function adds E edge into the STACK if it doesn't have an immediate
     successor back edge.

     When loop counter is checked in the if condition,
     we mustn't continue on real path as we want to stop the execution before
     the second iteration.  */
  bool add_edge (edge, auto_vec<edge> &);

  /* Create new state for true and false branch.
     Keep conditions in new created states.  */
  bool resolve_condition (const gcond *, auto_vec<edge> &);

  /* If final states are less than two, adds new FINAL_STATE and returns true.
   Otherwise, returns false.
   In CRC cases we detect may not occur more than two final states.  */
  bool add_final_state (state *);

  /* Keep the state of the executed path in final states.  */
  bool keep_states ();

  bool execute_assign_statement (const gassign *);

  /* Execute gimple statements of the basic block.
     Keeping values of variables in the state.  */
  bool execute_bb_gimple_statements (basic_block, auto_vec<edge> &);

  /* Assign values of phi instruction to its result.
     Keep updated values in the state.  */
  bool execute_bb_phi_statements (basic_block, edge);

  /* Execute all statements of the basic block.
    Keeping values of variables in the state.  */
  bool execute_bb_statements (basic_block, edge, auto_vec<edge> &);

  /* Create initial state of the loop's header BB variables which have constant
   values.
   If it is the first iteration of the loop, initialise variables with the
   initial values, otherwise initialise the variable with the value calculated
   during the previous execution.  */
  state *create_initial_state (class loop *);

/* Traverse function fun's all paths from the first basic block to the last.
   Each time iterate loops only once.
   Symbolically execute statements of each path.  */
  bool traverse_function (function *);

  /* Execute the loop, which calculates crc with initial values,
   to calculate the polynomial.  */
  bool execute_crc_loop (gphi *, gphi *, bool);

 public:

  /* Returns calculated polynomial by executing the loop
     with concrete values.
     First value of the pair is the tree containing the value of the polynomial,
     second is the calculated polynomial.  The pair may contain nullptr.  */
  std::pair <tree, value *>
  extract_polynomial (gphi *, gphi *, tree, bool);

  /* Symbolically execute the CRC loop, doing one iteration.  */
  bool symb_execute_crc_loop ();

  const vec<state *> &get_final_states ()
  {
    return m_final_states;
  }

  bool is_last_iteration ()
  {
    return m_is_last_iteration;
  }

  crc_symbolic_execution (class loop *loop, gphi * output_crc) :
      m_crc_loop (loop), m_output_crc (output_crc), m_is_last_iteration (false)
  {
    /* Reserve memory for the vectors of states.  */
    int max_states = 2;
    m_states.create (max_states);
    m_final_states.create (max_states);
  }

  ~crc_symbolic_execution ()
  {
    /* Free memory.  */
    state::clear_states (&m_states);
    state::clear_states (&m_final_states);
  }
};


/**************************** LFSR MATCHING *********************************/

/* Returns true if all states match the LFSR, otherwise - false.  */
bool all_states_match_lfsr (value *, bool, tree, const vec<state *> &);


#endif //GCC_CRC_VERIFICATION
