/* State will store states of variables for a function's single execution path.
   It will be used for bit-level symbolic execution to determine values of bits
   of function's return value and symbolic marked arguments.
   Copyright (C) 2022-2025 Free Software Foundation, Inc.
   Contributed by Matevos Mehrabyan <matevosmehrabyan@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/>.  */

/* This symbolic executor is designed to handle operations on the bit level.
   It can save values of variables on the bit level.  For example byte x = 9
   would be represented by the bit-vector x = <0, 0, 0, 0, 1, 0, 1, 0> of
   size 8.  Variables without values will be represented by bit-vectors of
   symbolic bits: x = <x[size - 1], ..., x[1], x[0]> where x[i] is the value
   of bit i of variable x.

   Operations are also performed on the bit level.  For example, for operation
   z = x & y
   where
   x = <x[size - 1], ..., x[1], x[0]>
   y = <y[size - 1], ..., y[1], y[0]>
   z will have the value
   z = <x[size - 1] & y[size - 1], ..., x[1] & y[1], x[0] & y[0]>

   Each bit of variable can be accessed and examined separately if needed.
   Moreover, it does basic optimizations in place.
   For example, for operation
   z = x | y
   where
   x = <x[size - 1], ..., x[1], x[0]>,
   y = <1, ..., 0, 1>,
   z will have the value
   z = <1, ..., x[1], 1>
   as x | 0 == x and x | 1 == 1

   Besides variables, the symbolic executor can also store
   conditions on the bit level.
   For example, for x == y
   It would add {x[size - 1] == y[size - 1], ..., x[1] == y[1], x[0] == y[0]}
   conditions.

   For a more complex condition x > y, it would add
   {x[size - 1] > y[size - 1] || (x[size - 1] == y[size -1]
	&& (x[size - 2] > y[size - 2] || (x[size - 2] == y[size - 2]
		&& ... (x[0] >= y[0])...)}

   The symbolic executor doesn't run by itself.  Instead, it must be dictated
   what to do.  This makes it flexible and allows for various pre- and
   post-processing tasks.  Developers adding new operation support must consider
   that the operation must be represented on the bit level.  Because of
   this restriction, it may be hard to add support for some operations.

   To use the symbolic executor, you must create a state object.  It is the main
   object that contains variables as bit-vectors and conditions.
   It is the state object that provides operations for symbolic execution.

   If you are going to execute multiple execution paths, you should clone
   the state at branching instructions and execute one state for the execution
   path where the branching condition evaluates to 'true', and
   the other state for the execution path where the branching condition
   evaluates to 'false'.  Besides that, you should add the corresponding
   conditions to states if you need them.

   Variables are stored in the state's 'var_states' field.  It maps the tree
   object of the variable to its bit-vector.  Path conditions are stored in
   the 'conditions' field.

   To declare a variable, you should use 'declare_if_needed' method of state.
   It declares the variable if it was not previously declared.
   'create_val_for_const' is used for constant declaration.

   The list of supported operations can be found in 'state::do_operation'
   method.  It calls the corresponding operation based on the specified
   tree_code operation.  This is the method that you should use to dictate
   to the symbolic executor what operations to perform.  You can execute the
   desired operations explicitly if needed.  Variables for participant
   operands will be created implicitly if it was not previously declared.
   To add conditions to the state, you should use 'state::add_*_cond' methods.

   A sample usage of the symbolic executor:

   // Example.

   unsigned char foo (unsigned char x, unsigned char y)
   {
     unsigned char D.2352;
     unsigned char result;

     result = x & y;
     result = result | 9;
     if (result == 23) goto <D.2350>; else goto <D.2351>;
     <D.2350>:
     result = result ^ y;
     <D.2351>:
     D.2352 = result;
     return D.2352;
   }

   // Now, we create the initial state and add the variables to it.
   state s;
   s.declare_if_needed (x, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (x))));
   s.declare_if_needed (y, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (y))));
   s.declare_if_needed (d_2352, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (d_2352))));
   s.declare_if_needed (result, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (result))));

   s.do_operation (BIT_AND_EXPR, x, y, result);
   s.do_operation (BIT_OR_EXPR, result, 9, result);

   state s2 (s);  // We duplicate the state to save values for each branch.
   s.add_equal_cond (result, 23);
   s2.add_not_equal_cond (result, 23);

   s.do_operation (BIT_XOR_EXPR, result, y, result);
   s.do_assign (result, d_2352);
   s2.do_assign (result, d_2352);

   // Now, we have variable values for each execution branch, and we can examine
   // them to make decisions.

   value * res = s.get_value (result);
   if (is_a<bit_expression *> ((*res)[0]))
   {
     bit_expression * expr = is_a<bit_expression *> ((*res)[0]);
     if (is_a<bit *> (expr->get_left ())
	 && as_a<bit *> (expr->get_left ())->get_val () == 0)
     {
       ... // Do something.
     }
   }

   A more general usage would be to iterate over instructions and
   call the executor:

   state s;
   ...

   for (inst : instructions)
   {
     enum tree_code rhs_code = gimple_assign_rhs_code (inst);
     tree op1 = gimple_assign_rhs1 (gs);
     tree op2 = gimple_assign_rhs2 (gs);
     tree lhs = gimple_assign_lhs (gs);
     s.do_operation (rhs_code, op1, op2, lhs);
     ...
   }

   */

#include "sym-exec-state.h"

/* Returns the minimum of A, B, C.  */

size_t min (size_t a, size_t b, size_t c)
{
  size_t min = (a < b ? a : b);
  return min < c ? min : c;
}


/* Copy constructor for state.  It copies all variables and conditions
   of the given state.  */

state::state (const state &s)
{
  for (auto iter = s.var_states.begin (); iter != s.var_states.end (); ++iter)
    {
      value val ((*iter).second.length (), (*iter).second.is_unsigned);
      for (size_t i = 0; i < (*iter).second.length (); i++)
	val.push ((*iter).second[i]->copy ());

      var_states.put ((*iter).first, val);
    }

  for (auto iter = s.conditions.begin (); iter != s.conditions.end (); ++iter)
    conditions.add (as_a<bit_expression *> ((*iter)->copy ()));
}


/* Destructor for state.  */

state::~state ()
{
  clear_conditions ();
}


/* Checks whether state for variable with specified name already
   exists or not.  */

bool
state::is_declared (tree var)
{
  return var_states.get (var) != NULL;
}


/* Declares given variable if it has not been declared yet.  */

void
state::declare_if_needed (tree var, size_t size)
{
  if (TREE_CODE (var) != INTEGER_CST && !is_declared (var))
    {
      make_symbolic (var, size);
      if (dump_file && (dump_flags & TDF_DETAILS))
	{
	  fprintf (dump_file,
		   "Declaring var ");
	  print_generic_expr (dump_file, var, dump_flags);
	  fprintf (dump_file,
		   " with size %zd\n", size);
	}
    }
}


/* Get value of the given variable.  */

value *
state::get_value (tree var)
{
  return var_states.get (var);
}


/* Get the value of the tree, which is in the beginning of the var_states.  */

value *
state::get_first_value ()
{
  return &(*(var_states.begin ())).second;
}


/* Returns the list of conditions in the state.  */

const hash_set<bit_expression *> &
state::get_conditions ()
{
  return conditions;
}


/* Checks if sizes of arguments and destination are compatible.  */

bool
state::check_args_compatibility (tree arg1, tree arg2, tree dest)
{
  if (!(get_var_size (arg1) == get_var_size (dest)
	|| TREE_CODE (arg1) == INTEGER_CST)
      || !(get_var_size (arg2) == get_var_size (dest)
	   || TREE_CODE (arg2) == INTEGER_CST))
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Sym-Exec: Incompatible destination"
			    "and argument sizes.\n");

      return false;
    }

  return true;
}


/* Creates value for given constant tree.  */

value
state::create_val_for_const (tree var, size_t size)
{
  unsigned HOST_WIDE_INT val = TYPE_UNSIGNED (TREE_TYPE (var))
			       ? tree_to_uhwi (var) : tree_to_shwi (var);
  value result (size, TYPE_UNSIGNED (TREE_TYPE (var)));

  for (size_t i = 0; i < size; i++)
    {
      result.push (new bit (val & 1));
      val >>= 1;
    }

  return result;
}


/* Adds the given variable to state.  */

bool
state::add_var_state (tree var, value *vstate)
{
  size_t size = vstate->length ();
  value val (size, vstate->is_unsigned);
  for (size_t i = 0; i < size; i++)
    val.push ((*vstate)[i]->copy ());

  return var_states.put (var, val);
}


/* Adds the given condition to the state.  */

bool
state::add_condition (bit_expression *cond)
{
  return conditions.add (as_a<bit_expression *> (cond->copy ()));
}


/* Bulk add the given conditions to the state.  */

bool
state::bulk_add_conditions (const hash_set<bit_expression *> &conds)
{
  bool status = true;
  for (auto iter = conds.begin (); iter != conds.end (); ++iter)
    status &= add_condition (*iter);

  return status;
}


/* Remove all states from the states' vector.  */

void
state::remove_states (vec<state *> *states)
{
  while (!states->is_empty ())
    {
      delete states->last ();
      states->pop ();
    }
}


/* Remove all states from the states' vector and release the vector.  */

void
state::clear_states (vec<state *> *states)
{
  remove_states (states);
  states->release ();
}


/* Removes all variables added to the state.  */

void
state::clear_var_states ()
{
  var_states.empty ();
}


/* Removes all conditions added to the state.  */

void
state::clear_conditions ()
{
  for (auto iter = conditions.begin (); iter != conditions.end (); ++iter)
    delete (*iter);
  conditions.empty ();
}


/* Performs AND operation for 2 symbolic_bit operands.  */

value_bit *
state::and_sym_bits (const value_bit *var1, const value_bit *var2)
{
  return new bit_and_expression (var1->copy (), var2->copy ());
}


/* Performs AND operation for a symbolic_bit and const_bit operands.  */

value_bit *
state::and_var_const (const value_bit *var1, const bit *const_bit)
{
  if (const_bit->get_val () == 1)
    return var1->copy ();

  return new bit (0);
}


/* Performs AND operation for 2 constant bit operands.  */

bit *
state::and_const_bits (const bit *const_bit1, const bit *const_bit2)
{
  if (const_bit1->get_val () == const_bit2->get_val ())
    return new bit (*const_bit1);

  return new bit (0);
}


/* Performs OR operation for 2 symbolic_bit operands.  */

value_bit *
state::or_sym_bits (const value_bit *var1, const value_bit *var2)
{
  return new bit_or_expression (var1->copy (), var2->copy ());
}


/* Performs OR operation for a symbolic_bit and a constant bit operands.  */

value_bit *
state::or_var_const (const value_bit *var1, const bit *const_bit)
{
  if (const_bit->get_val () == 0)
    return var1->copy ();

  return new bit (1);
}


/* Performs OR operation for 2 constant bit operands.  */

bit *
state::or_const_bits (const bit *const_bit1, const bit *const_bit2)
{
  if (const_bit1->get_val () == const_bit2->get_val ())
    return new bit (*const_bit1);

  return new bit (1);
}


/* Adds an empty state for the given variable.  */

bool
state::decl_var (tree var, unsigned size)
{
  if (is_declared (var))
    return false;

  value val (size, TYPE_UNSIGNED (TREE_TYPE (var)));
  for (unsigned i = 0; i < size; i++)
    val.push (nullptr);

  return var_states.put (var, val);
}


/* Returns size of the given variable.  */

unsigned
state::get_var_size (tree var)
{
  value *content = var_states.get (var);
  if (content == NULL)
    return 0;

  return content->allocated ();
}


/* Adds a variable with unknown value to state.  Such variables are
   represented as sequence of symbolic bits.  */

bool
state::make_symbolic (tree var, unsigned size)
{
  if (is_declared (var))
    return false;

  value val (size, TYPE_UNSIGNED (TREE_TYPE (var)));
  /* Initialize each bit of a variable with unknown value.  */
  for (size_t i = 0; i < size; i++)
    val.push (new symbolic_bit (i, var));

  return var_states.put (var, val);
}


/* Performs AND operation on two bits.  */

value_bit *
state::and_two_bits (value_bit *arg1, value_bit *arg2)
{
  value_bit *result = nullptr;

  if (is_a<bit *> (arg1) && is_a<bit *> (arg2))
    result = and_const_bits (as_a<bit *> (arg1), as_a<bit *> (arg2));

  else if (is_a<bit *> (arg1) && (is_a<symbolic_bit *> (arg2)
				  || (is_a<bit_expression *> (arg2))))
    result = and_var_const (arg2, as_a<bit *> (arg1));

  else if ((is_a<symbolic_bit *> (arg1)
	    || (is_a<bit_expression *> (arg1))) && is_a<bit *> (arg2))
    result = and_var_const (arg1, as_a<bit *> (arg2));

  else
    result = and_sym_bits (arg1, arg2);

  return result;
}


/* A wrapper for operations on two bits.
   Operation and operands are passed as arguments.  */

value_bit *
state::operate_bits (bit_func bit_op, value_bit *bit1, value_bit *bit2,
		     value_bit **)
{
  return (bit_op) (bit1, bit2);
}


/* A wrapper for operations on three bits.
   Operation and operands are passed as arguments.  */

value_bit *
state::operate_bits (bit_func3 bit_op, value_bit *bit1, value_bit *bit2,
		     value_bit **bit3)
{
  return (bit_op) (bit1, bit2, bit3);
}


/* Does preprocessing and postprocessing for expressions with tree operands.
   Handles value creation for constant and their removement in the end.  */

bool
state::do_binary_operation (tree arg1, tree arg2, tree dest,
			    binary_func bin_func)
{
  declare_if_needed (dest, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (dest))));
  declare_if_needed (arg1, var_states.get (dest)->allocated ());
  declare_if_needed (arg2, var_states.get (dest)->allocated ());

  if (!check_args_compatibility (arg1, arg2, dest))
    return false;

  size_t dest_size = var_states.get (dest)->length ();

  value *arg1_val = var_states.get (arg1);
  value arg1_const_val (dest_size, false);
  if (arg1_val == NULL && TREE_CODE (arg1) == INTEGER_CST)
    {
      arg1_const_val = create_val_for_const (arg1, dest_size);
      arg1_val = &arg1_const_val;
    }

  value *arg2_val = var_states.get (arg2);
  value arg2_const_val (dest_size, false);
  if (arg2_val == NULL && TREE_CODE (arg2) == INTEGER_CST)
    {
      arg2_const_val = create_val_for_const (arg2, dest_size);
      arg2_val = &arg2_const_val;
    }

  (this->*bin_func) (arg1_val, arg2_val, dest);
  print_value (var_states.get (dest));
  return true;
}


/* Performs AND operation on given values.  The result is stored in dest.  */

void
state::do_and (value *arg1, value *arg2, tree dest)
{
  /* Creating AND expressions for every bit pair of given arguments
     and store them as a new state for given destination.  */

  operate (arg1, arg2, nullptr, dest, &state::and_two_bits);
}


/* Performs OR operation on two bits.  */

value_bit *
state::or_two_bits (value_bit *arg1_bit, value_bit *arg2_bit)
{
  value_bit *result = nullptr;

  if (is_a<bit *> (arg1_bit) && is_a<bit *> (arg2_bit))
    result = or_const_bits (as_a<bit *> (arg1_bit), as_a<bit *> (arg2_bit));

  else if (is_a<bit *> (arg1_bit) && (is_a<symbolic_bit *> (arg2_bit)
				      || is_a<bit_expression *> (arg2_bit)))
    result = or_var_const (arg2_bit, as_a<bit *> (arg1_bit));

  else if ((is_a<symbolic_bit *> (arg1_bit)
	    || is_a<bit_expression *> (arg1_bit))
	   && is_a<bit *> (arg2_bit))
    result = or_var_const (arg1_bit, as_a<bit *> (arg2_bit));

  else
    result = or_sym_bits (arg1_bit, arg2_bit);

  return result;
}


/* Performs OR operation on given values.  The result is stored in dest.  */

void
state::do_or (value *arg1, value *arg2, tree dest)
{
  /* Creating OR expressions for every bit pair of given arguments
     and store them as a new state for given destination.  */
  operate (arg1, arg2, nullptr, dest, &state::or_two_bits);
}


/* Performs XOR operation on two bits.  */

value_bit *
state::xor_two_bits (value_bit *arg1_bit, value_bit *arg2_bit)
{
  value_bit *result = nullptr;

  if (is_a<bit *> (arg1_bit) && is_a<bit *> (arg2_bit))
    result = xor_const_bits (as_a<bit *> (arg1_bit), as_a<bit *> (arg2_bit));

  else if (is_a<bit *> (arg1_bit) && (is_a<symbolic_bit *> (arg2_bit)
				      || is_a<bit_expression *> (arg2_bit)))
    result = xor_var_const (arg2_bit, as_a<bit *> (arg1_bit));

  else if ((is_a<symbolic_bit *> (arg1_bit)
	    || is_a<bit_expression *> (arg1_bit))
	   && is_a<bit *> (arg2_bit))
    result = xor_var_const (arg1_bit, as_a<bit *> (arg2_bit));

  else
    result = xor_sym_bits (arg1_bit, arg2_bit);

  return result;
}


/* Performs XOR operation on given values.  The result is stored in dest.  */

void
state::do_xor (value *arg1, value *arg2, tree dest)
{
  operate (arg1, arg2, nullptr, dest, &state::xor_two_bits);
}


/* Shifts value right by size of shift_value.  */

value *
state::shift_right_by_const (value *var, size_t shift_value)
{
  value *shift_result = new value (var->length (), var->is_unsigned);
  if (var->length () <= shift_value)
    for (size_t i = 0; i < var->length (); i++)
      shift_result->push (new bit (0));
  else
    {
      size_t i = 0;
      for (; i < var->length () - shift_value; ++i)
	shift_result->push (((*var)[shift_value + i])->copy ());

      for (; i < var->length (); ++i)
	shift_result->push (var->is_unsigned ? new bit (0)
					     : var->last ()->copy ());
    }
  return shift_result;
}


/* Checks if all bits of the given value have constant bit type.  */

bool
state::is_bit_vector (const value *var)
{
  if (var == nullptr || !var->exists ())
    return false;

  for (size_t i = 0; i < var->length (); i++)
    if (!(is_a<bit *> ((*var)[i])))
      return false;
  return true;
}


/* Returns the number represented by the value.  */

unsigned HOST_WIDE_INT
state::make_number (const value *var)
{
  unsigned HOST_WIDE_INT
  number = 0;
  int value_size = var->length ();
  for (int i = value_size - 1; i >= 0; i--)
    {
      if (is_a<bit *> ((*var)[i]))
	number = (number << 1) | as_a<bit *> ((*var)[i])->get_val ();
      else
	return 0;
    }
  return number;
}


/* Shift_left operation.  Case: var2 is a symbolic value.  */

value_bit *
state::shift_left_sym_bits (value_bit *var1, value_bit *var2)
{
  return new shift_left_expression (var1->copy (), var2->copy ());
}


/* Performs shift left operation on given values.
   The result is stored in dest.  */

void
state::do_shift_left (value *arg1, value *arg2, tree dest)
{
  if (is_bit_vector (arg2))
    {
      size_t shift_value = make_number (arg2);
      value *result = shift_left_by_const (arg1, shift_value);
      for (size_t i = 0; i < get_var_size (dest); i++)
	{
	  delete (*var_states.get (dest))[i];
	  (*var_states.get (dest))[i] = (*result)[i]->copy ();
	}
      delete result;
    }
  else
    operate (arg1, arg2, nullptr, dest, &state::shift_left_sym_bits);
}


/* Performs shift right operation on given values.
   The result is stored in dest.  */

void
state::do_shift_right (value *arg1, value *arg2, tree dest)
{
  if (is_bit_vector (arg2))
    {
      size_t shift_value = make_number (arg2);
      value *result = shift_right_by_const (arg1, shift_value);
      for (size_t i = 0; i < get_var_size (dest); i++)
	{
	  delete (*var_states.get (dest))[i];
	  (*var_states.get (dest))[i] = (*result)[i]->copy ();
	}

      delete result;
    }
  else
    operate (arg1, arg2, nullptr, dest, &state::shift_right_sym_bits);
}


/* Adds two bits and carry value.
   Resturn result and stores new carry bit in "carry".  */

value_bit *
state::full_adder (value_bit *var1, value_bit *var2, value_bit **carry)
{
  value_bit *new_carry = and_two_bits (var1, var2);
  value_bit *sum = xor_two_bits (var1, var2);

  value_bit *result = xor_two_bits (sum, *carry);
  value_bit *sum_and_carry = and_two_bits (sum, *carry);

  delete *carry;
  delete sum;

  *carry = or_two_bits (sum_and_carry, new_carry);

  delete sum_and_carry;
  delete new_carry;

  return result;
}


/* Adds given values.  The result is stored in dest.  */

void
state::do_add (value *arg1, value *arg2, tree dest)
{
  value_bit *carry = new bit (0);
  operate (arg1, arg2, &carry, dest, &state::full_adder);
  delete carry;
}


/* Returns the additive inverse of the given number.  */

value *
state::additive_inverse (const value *number)
{
  value *result = new value (number->length (), number->is_unsigned);
  value one (number->length (), number->is_unsigned);

  size_t size = number->length ();
  one.push (new bit (1));
  result->push (complement_a_bit ((*number)[0]));

  for (size_t i = 1; i < size; i++)
    {
      one.push (new bit (0));
      result->push (complement_a_bit ((*number)[i]));
    }

  value_bit *carry = new bit (0);
  for (size_t i = 0; i < size; ++i)
    {
      value_bit *cur_bit = (*result)[i];
      (*result)[i] = full_adder (cur_bit, one[i], &carry);
      delete cur_bit;
    }

  delete carry;
  return result;
}


/* Subtracks second value from the first.  The result is stored in dest.  */

void
state::do_sub (value *arg1, value *arg2, tree dest)
{
  value *neg_arg2 = additive_inverse (arg2);
  do_add (arg1, neg_arg2, dest);
  delete neg_arg2;
}


/* Performs complement operation on a bit.  */

value_bit *
state::complement_a_bit (value_bit *var)
{
  value_bit *result = nullptr;
  if (is_a<bit *> (var))
    result = complement_const_bit (as_a<bit *> (var));
  else
    result = complement_sym_bit (var);

  return result;
}


/* Negates given variable.  */

bool
state::do_complement (tree arg, tree dest)
{
  declare_if_needed (dest, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (dest))));
  declare_if_needed (arg, var_states.get (dest)->allocated ());

  /* Creating complement expressions for every bit the given argument
     and store it as a new state for given destination.  */
  size_t iter_count = min (get_var_size (dest), get_var_size (arg),
			   get_var_size (arg));

  size_t i = 0;
  for (; i < iter_count; i++)
    {
      value_bit *result = complement_a_bit ((*var_states.get (arg))[i]);
      delete (*var_states.get (dest))[i];
      (*var_states.get (dest))[i] = result;
    }

  if (i >= get_var_size (dest))
    {
      print_value (var_states.get (dest));
      return true;
    }

  for (; i < get_var_size (dest); i++)
    {
      delete (*var_states.get (dest))[i];
      bit tmp (0);
      (*var_states.get (dest))[i] = complement_a_bit (&tmp);
    }

  print_value (var_states.get (dest));
  return true;
}


/* Does Assignment.  */

bool
state::do_assign (tree arg, tree dest)
{
  declare_if_needed (dest, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (dest))));
  if (TREE_CODE (arg) != INTEGER_CST)
    declare_if_needed (arg, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg))));
  else
    declare_if_needed (arg, var_states.get (dest)->allocated ());

  value *dest_val = var_states.get (dest);

  /* If the argument is already defined, then we must just copy its bits.  */
  if (auto arg_val = var_states.get (arg))
    {
      for (size_t i = 0; i < dest_val->length (); i++)
	{
	  value_bit *new_val = nullptr;
	  if (i < arg_val->length ())
	    new_val = (*arg_val)[i]->copy ();
	  else
	    new_val = new bit (0);

	  delete (*dest_val)[i];
	  (*dest_val)[i] = new_val;
	}
    }
    /* If the argument is a constant, we must save it as sequence of bits.  */
  else if (TREE_CODE (arg) == INTEGER_CST)
    {
      value arg_val
	= create_val_for_const (arg, dest_val->length ());
      for (size_t i = 0; i < dest_val->length (); i++)
	{
	  delete (*dest_val)[i];
	  (*dest_val)[i] = arg_val[i]->copy ();
	}
    }
  else
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Sym-Exec: Unsupported assignment"
			    " for given argument.\n");

      return false;
    }

  print_value (var_states.get (dest));
  return true;
}


/* Assigns pow 2 value.  */

bool
state::do_assign_pow2 (tree dest, unsigned pow)
{
  value *dest_val = var_states.get (dest);
  unsigned dest_size = dest_val ? dest_val->allocated ()
				: tree_to_uhwi (TYPE_SIZE (TREE_TYPE (dest)));
  if (pow > dest_size)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Sym-Exec: pow %u of 2 won't fit in"
			    " specified destination\n", pow);
      return false;
    }

  if (!dest_val)
    {
      decl_var (dest, tree_to_uhwi (TYPE_SIZE (TREE_TYPE (dest))));
      dest_val = var_states.get (dest);
    }
  else
    dest_val->free_bits ();

  for (unsigned i = 0; i < dest_val->length (); i++)
    {
      if (i == pow)
	(*dest_val)[i] = new bit (1);
      else
	(*dest_val)[i] = new bit (0);
    }

  print_value (dest_val);
  return true;
}


/* Performs NOT operation for constant bit.  */

bit *
state::complement_const_bit (const bit *const_bit)
{
  return new bit (1u ^ const_bit->get_val ());
}


/* Performs NOT operation for symbolic_bit.  */

value_bit *
state::complement_sym_bit (const value_bit *var)
{
  return new bit_complement_expression (var->copy ());
}


/* Performs XOR operation for 2 symbolic_bit operands.  */

value_bit *
state::xor_sym_bits (const value_bit *var1, const value_bit *var2)
{
  value_bit *var2_copy = var2->copy ();
  bit_expression *node2_with_const_child = nullptr;
  bit_expression *parent_of_node2_with_child = nullptr;
  get_parent_with_const_child (var2_copy, node2_with_const_child,
			       parent_of_node2_with_child);

  if (node2_with_const_child != nullptr)
    {
      value_bit *var1_copy = var1->copy ();
      bit_expression *node1_with_const_child = nullptr;
      bit_expression *parent_of_node1_with_child = nullptr;
      get_parent_with_const_child (var1_copy, node1_with_const_child,
				   parent_of_node1_with_child);

      /* If both subtrees have constant bit nodes,
	 we can merge them together.  */
      if (node1_with_const_child != nullptr)
	{
	  value_bit *var1_reformed = nullptr;
	  value_bit *var2_reformed = nullptr;

	  /* If var1's const bit is in its left subtree.  */
	  value_bit *var1_left = node1_with_const_child->get_left ();
	  if (var1_left != nullptr && is_a<bit *> (var1_left))
	    {
	      var1_reformed = node1_with_const_child->get_right ()->copy ();
	      value_bit *var2_left = node2_with_const_child->get_left ();

	      /* If var2's const bit is in its left subtree.  */
	      if (var2_left != nullptr && is_a<bit *> (var2_left))
		var2_reformed = node2_with_const_child->get_right ()->copy ();
	      else /* Var2's const bit is in its right subtree.  */
		var2_reformed = node2_with_const_child->get_left ()->copy ();
	    }
	  else /* Var1's const bit is in its right subtree.  */
	    {
	      var1_reformed = node1_with_const_child->get_left ()->copy ();
	      value_bit *var2_left = node2_with_const_child->get_left ();

	      /* If var2's const bit is in its left subtree.  */
	      if (var2_left != nullptr && is_a<bit *> (var2_left))
		var2_reformed = node2_with_const_child->get_right ()->copy ();
	      else /* Var2's const bit is in its right subtree.  */
		var2_reformed = node2_with_const_child->get_left ()->copy ();
	    }

	  if (parent_of_node1_with_child)
	    {
	      parent_of_node1_with_child->get_left ()
	      == node1_with_const_child
	      ? parent_of_node1_with_child->set_left (var1_reformed)
	      : parent_of_node1_with_child->set_right (var1_reformed);
	      delete node1_with_const_child;
	    }
	  else
	    {
	      delete var1_copy;
	      var1_copy = var1_reformed;
	    }

	  if (parent_of_node2_with_child)
	    {
	      parent_of_node2_with_child->get_left ()
	      == node2_with_const_child
	      ? parent_of_node2_with_child->set_left (var2_reformed)
	      : parent_of_node2_with_child->set_right (var2_reformed);
	      delete node2_with_const_child;
	    }
	  else
	    {
	      delete var2_copy;
	      var2_copy = var2_reformed;
	    }

	  return new bit_xor_expression (var1_copy, var2_copy);
	}
      delete var1_copy;
    }

  delete var2_copy;
  return new bit_xor_expression (var1->copy (), var2->copy ());
}


/* Performs XOR operation for 2 constant bit operands.  */

bit *
state::xor_const_bits (const bit *const_bit1, const bit *const_bit2)
{
  return new bit (const_bit1->get_val () ^ const_bit2->get_val ());
}


/* Performs XOR operation for a symbolic_bit and const_bit operands.  */

value_bit *
state::xor_var_const (const value_bit *var, const bit *const_bit)
{
  if (const_bit->get_val () == 0)
    return var->copy ();

  value_bit *var_copy = var->copy ();
  bit_expression *node_with_const_child = nullptr;
  bit_expression *tmp = nullptr;
  get_parent_with_const_child (var_copy, node_with_const_child, tmp);

  if (node_with_const_child != nullptr)
    {
      value_bit *left = node_with_const_child->get_left ();
      if (left != nullptr && is_a<bit *> (left))
	{
	  bit *new_left = xor_const_bits (as_a<bit *> (left), const_bit);
	  delete left;
	  node_with_const_child->set_left (new_left);
	}
      else
	{
	  value_bit *right = node_with_const_child->get_right ();
	  bit *new_right = xor_const_bits (as_a<bit *> (right), const_bit);
	  delete right;
	  node_with_const_child->set_right (new_right);
	}
      return var_copy;
    }

  delete var_copy;
  return new bit_xor_expression (var->copy (), const_bit->copy ());
}


/* Return node which has a const bit child.  Traversal is done based
   on safe branching.  */

void
state::get_parent_with_const_child (value_bit *root, bit_expression *&parent,
				    bit_expression *&parent_of_parent)
{
  parent_of_parent = nullptr;
  parent = nullptr;

  if (!is_a<bit_expression *> (root))
    return;

  bit_expression *expr_root = as_a<bit_expression *> (root);
  hash_set < bit_expression * > nodes_to_consider;
  nodes_to_consider.add (expr_root);

  hash_map < bit_expression * , bit_expression * > node_to_parent;
  node_to_parent.put (expr_root, nullptr);

  /* Traversing expression tree:
     considering only comutative expression nodes.  */
  while (!nodes_to_consider.is_empty ())
    {
      bit_expression *cur_element = *nodes_to_consider.begin ();
      nodes_to_consider.remove (cur_element);

      value_bit *left = cur_element->get_left ();
      value_bit *right = cur_element->get_right ();

      if ((left != nullptr && is_a<bit *> (left))
	  || (right != nullptr && is_a<bit *> (right)))
	{
	  parent = cur_element;
	  parent_of_parent = *node_to_parent.get (cur_element);
	}

      if (left != nullptr && is_a<bit_xor_expression *> (left))
	{
	  nodes_to_consider.add (as_a<bit_expression *> (left));
	  node_to_parent.put (as_a<bit_expression *> (left), cur_element);
	}

      if (right != nullptr && is_a<bit_xor_expression *> (right))
	{
	  nodes_to_consider.add (as_a<bit_expression *> (right));
	  node_to_parent.put (as_a<bit_expression *> (right), cur_element);
	}
    }
}


/* Shifts number left by size of shift_value.  */

value *
state::shift_left_by_const (const value *number, size_t shift_value)
{
  value *shift_result = new value (number->length (), number->is_unsigned);
  if (number->length () <= shift_value)
    for (size_t i = 0; i < number->length (); i++)
      shift_result->push (new bit (0));

  else
    {
      size_t i = 0;
      for (; i < shift_value; ++i)
	shift_result->push (new bit (0));
      for (size_t j = 0; i < number->length (); ++i, j++)
	shift_result->push (((*number)[j])->copy ());
    }
  return shift_result;
}


/* Shift_right operation.  Case: var2 is a symbolic value.  */

value_bit *
state::shift_right_sym_bits (value_bit *var1, value_bit *var2)
{
  return new shift_right_expression (var1->copy (), var2->copy ());
}


/* Adds two values, stores the result in the first one.  */

void
state::add_numbers (value *var1, const value *var2)
{
  value_bit *carry = new bit (0);
  for (unsigned i = 0; i < var1->length (); i++)
    {
      value_bit *temp = (*var1)[i];
      (*var1)[i] = full_adder ((*var1)[i], (*var2)[i], &carry);
      delete temp;
    }
  delete carry;
}


/* ANDs every bit of the vector with var_bit, stroes the result in var1.  */

void
state::and_number_bit (value *var1, value_bit *var_bit)
{
  for (unsigned i = 0; i < var1->length (); i++)
    {
      value_bit *tmp = (*var1)[i];
      (*var1)[i] = and_two_bits ((*var1)[i], var_bit);
      delete tmp;
    }

}


/* Multiplies given values.  The result is stored in dest.  */

void
state::do_mul (value *arg1, value *arg2, tree dest)
{
  value *shifted = new value (*arg1);
  value *dest_val = var_states.get (dest);

  for (unsigned i = 0; i < dest_val->length (); i++)
    {
      delete (*dest_val)[i];
      (*dest_val)[i] = new bit (0);
    }

  for (unsigned i = arg2->length (); i != 0; --i)
    {
      if (is_a<bit *> ((*arg2)[i - 1])
	  && as_a<bit *> ((*arg2)[i - 1])->get_val () != 0)
	add_numbers (dest_val, shifted);
      else if (is_a<symbolic_bit *> ((*arg2)[i - 1]))
	{
	  and_number_bit (shifted, as_a<symbolic_bit *> ((*arg2)[i - 1]));
	  add_numbers (dest_val, shifted);
	}

      value *temp = shifted;
      shifted = shift_left_by_const (shifted, 1);
      delete temp;
    }
  delete shifted;
}


/* Checks whether the given two constant values are equal.  */

bool
state::check_const_value_equality (value *arg1, value *arg2)
{
  for (size_t i = 0; i < arg1->length (); i++)
    if (as_a<bit *> ((*arg1)[i])->get_val ()
	!= as_a<bit *> ((*arg2)[i])->get_val ())
      return false;
  return true;
}


/* Adds EQUAL condition of given variables to state.  */

bool
state::add_equal_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_equal_cond);
}


/* Adds equality condition for two values.  */

void
state::add_equal_cond (value *arg1, value *arg2)
{

  /* If both arguments are constants then we can evaluate it.  */
  if (is_bit_vector (arg1) && is_bit_vector (arg2))
    {
      bool result = check_const_value_equality (arg1, arg2);
      last_cond_status = result ? condition_status::CS_TRUE
				: condition_status::CS_FALSE;
      return;
    }

  /* When some of bits are constants and they differ by value,
     then we can evalate it to be false.  */
  for (size_t i = 0; i < arg1->length (); i++)
    {
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i])
	  && as_a<bit *> ((*arg1)[i])->get_val ()
	     != as_a<bit *> ((*arg2)[i])->get_val ())
	{
	  last_cond_status = condition_status::CS_FALSE;
	  return;
	}
    }

  for (size_t i = 0; i < arg1->length (); i++)
    {
      /* If there is a constant bit pair, then they are equal
	 as we checked not equality above.  */
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i]))
	continue;

      conditions.add (new bit_condition ((*arg1)[i]->copy (),
					 (*arg2)[i]->copy (),
					 EQ_EXPR));
    }
  last_cond_status = condition_status::CS_SYM;
}


/* Checks whether the given two constant values are not equal.  */

bool
state::check_const_value_are_not_equal (value *arg1, value *arg2)
{
  for (size_t i = 0; i < arg1->length (); i++)
    if (as_a<bit *> ((*arg1)[i])->get_val ()
	!= as_a<bit *> ((*arg2)[i])->get_val ())
      return true;
  return false;
}


/* Adds NOT EQUAL condition of given variables to state.  */

bool
state::add_not_equal_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_not_equal_cond);
}


/* Adds not equal condition for two values.  */

void
state::add_not_equal_cond (value *arg1, value *arg2)
{
  if (is_bit_vector (arg1) && is_bit_vector (arg2))
    {
      bool result = check_const_value_are_not_equal (arg1, arg2);
      last_cond_status = result ? condition_status::CS_TRUE
				: condition_status::CS_FALSE;
      return;
    }

  /* When some of bits are constants and they differ by value,
     then we can evalate it to be true.  */
  for (size_t i = 0; i < arg1->length (); i++)
    {
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i])
	  && as_a<bit *> ((*arg1)[i])->get_val ()
	     != as_a<bit *> ((*arg2)[i])->get_val ())
	{
	  last_cond_status = condition_status::CS_TRUE;
	  return;
	}
    }

  bit_expression *prev = nullptr;
  for (size_t i = 0; i < arg1->length (); i++)
    {
      /* If there is a constant bit pair, then they are equal
	 as we checked not equality above.  */
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i]))
	continue;

      bit_condition *new_cond = new bit_condition ((*arg1)[i]->copy (),
						   (*arg2)[i]->copy (),
						   NE_EXPR);
      if (prev)
	prev = new bit_or_expression (prev, new_cond);
      else
	prev = new_cond;
    }

  last_cond_status = condition_status::CS_SYM;
  conditions.add (prev);
}


/* Checks whether the first given constant value
   is greater than the second one.  */

bool
state::check_const_value_is_greater_than (value *arg1, value *arg2)
{
  for (int i = arg1->length () - 1; i >= 0; i--)
    {
      if (as_a<bit *> ((*arg1)[i])->get_val ()
	  > as_a<bit *> ((*arg2)[i])->get_val ())
	return true;
      else if (as_a<bit *> ((*arg1)[i])->get_val ()
	       < as_a<bit *> ((*arg2)[i])->get_val ())
	return false;
    }
  return false;
}


/* Adds GREATER THAN condition of given variables to state.  */

bool
state::add_greater_than_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_greater_than_cond);
}


/* Adds greater than condition for two values.  */

void
state::add_greater_than_cond (value *arg1, value *arg2)
{
  if (is_bit_vector (arg1) && is_bit_vector (arg2))
    {
      bool result = check_const_value_is_greater_than (arg1, arg2);
      last_cond_status = result ? condition_status::CS_TRUE
				: condition_status::CS_FALSE;
      return;
    }

  if (is_bit_vector (arg2) && is_a<bit *> (arg1->last ())
      && make_number (arg2) == 0 && !arg1->is_unsigned)
    {
      if (as_a<bit *> (arg1->last ())->get_val () == 1)
	last_cond_status = condition_status::CS_FALSE;
      else
	{
	  for (size_t i = 0; i < arg1->length (); i++)
	    if (is_a<bit *> ((*arg1)[i])
		&& as_a<bit *> ((*arg1)[i])->get_val ())
	      {
		last_cond_status = condition_status::CS_TRUE;
		return;
	      }
	}
    }

  bit_expression *gt_cond = construct_great_than_cond (arg1, arg2);
  if (gt_cond)
    {
      /* Otherwise its status is already set.  */
      last_cond_status = condition_status::CS_SYM;
      conditions.add (gt_cond);
    }
}


/* Constructs expression trees of greater than condition for given values.  */

bit_expression *
state::construct_great_than_cond (value *arg1, value *arg2)
{
  bit_expression *prev = nullptr;
  int i = arg1->length () - 1;
  for (; i >= 0; i--)
    {
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i]))
	{
	  if (as_a<bit *> ((*arg1)[i])->get_val ()
	      > as_a<bit *> ((*arg2)[i])->get_val ())
	    {
	      if (!prev)
		last_cond_status = condition_status::CS_TRUE;
	      return prev;
	    }
	  else if (as_a<bit *> ((*arg1)[i])->get_val ()
		   < as_a<bit *> ((*arg2)[i])->get_val ())
	    {
	      if (prev)
		{
		  bit_expression *ret_val
		    = as_a<bit_expression *> (prev->get_left ()->copy ());
		  delete prev;
		  return ret_val;
		}
	      else
		{
		  last_cond_status = condition_status::CS_FALSE;
		  return nullptr;
		}
	    }
	}
      else
	{
	  bit_condition *gt_cond
	    = new bit_condition ((*arg1)[i]->copy (), (*arg2)[i]->copy (),
				 GT_EXPR);
	  bit_expression *expr = nullptr;
	  if (i)
	    {
	      bit_condition *eq_cond
		= new bit_condition ((*arg1)[i]->copy (), (*arg2)[i]->copy (),
				     EQ_EXPR);
	      expr = new bit_or_expression (gt_cond, eq_cond);
	    }
	  else
	    expr = gt_cond;

	  if (prev)
	    prev = new bit_and_expression (expr, prev);
	  else
	    prev = expr;
	}
    }

  return prev;
}


/* Checks whether the first given constant value
   is less than the second one.  */

bool
state::check_const_value_is_less_than (value *arg1, value *arg2)
{
  for (int i = arg1->length () - 1; i >= 0; i--)
    {
      if (as_a<bit *> ((*arg1)[i])->get_val ()
	  < as_a<bit *> ((*arg2)[i])->get_val ())
	return true;
      else if (as_a<bit *> ((*arg1)[i])->get_val ()
	       > as_a<bit *> ((*arg2)[i])->get_val ())
	return false;
    }
  return false;
}


/* Adds LESS THAN condition of given variables to state.  */

bool
state::add_less_than_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_less_than_cond);
}


/* Adds less than condition for two values.  */

void
state::add_less_than_cond (value *arg1, value *arg2)
{
  if (is_bit_vector (arg1) && is_bit_vector (arg2)
      && (make_number (arg2) != 0 || arg1->is_unsigned))
    {
      bool result = check_const_value_is_less_than (arg1, arg2);
      last_cond_status = result ? condition_status::CS_TRUE
				: condition_status::CS_FALSE;
      return;
    }

  last_cond_status = condition_status::CS_SYM;
  if (is_bit_vector (arg2) && make_number (arg2) == 0 && !arg1->is_unsigned)
    {
      if (is_a<bit *> (arg1->last ()))
	{
	  if (as_a<bit *> (arg1->last ())->get_val () == 1)
	    last_cond_status = condition_status::CS_TRUE;
	  else
	    last_cond_status = condition_status::CS_FALSE;
	}
      else
	conditions.add (new bit_condition (arg1->last ()->copy (), new bit (1),
					   EQ_EXPR));

      return;
    }

  bit_expression *lt_cond = construct_less_than_cond (arg1, arg2);
  if (lt_cond)
    /* Otherwise its status is already set.  */
    conditions.add (lt_cond);
}


/* Constructs expression trees of less than condition for given values.  */

bit_expression *
state::construct_less_than_cond (value *arg1, value *arg2)
{
  bit_expression *prev = nullptr;
  int i = arg1->length () - 1;
  for (; i >= 0; i--)
    {
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i]))
	{
	  if (as_a<bit *> ((*arg1)[i])->get_val ()
	      < as_a<bit *> ((*arg2)[i])->get_val ())
	    {
	      if (!prev)
		last_cond_status = condition_status::CS_TRUE;
	      return prev;
	    }
	  else if (as_a<bit *> ((*arg1)[i])->get_val ()
		   > as_a<bit *> ((*arg2)[i])->get_val ())
	    {
	      if (prev)
		{
		  bit_expression *ret_val
		    = as_a<bit_expression *> (prev->get_left ()->copy ());
		  delete prev;
		  return ret_val;
		}
	      else
		{
		  last_cond_status = condition_status::CS_FALSE;
		  return nullptr;
		}
	    }
	}
      else
	{
	  bit_condition *lt_cond
	    = new bit_condition ((*arg1)[i]->copy (), (*arg2)[i]->copy (),
				 LT_EXPR);
	  bit_expression *expr = nullptr;
	  if (i)
	    {
	      bit_condition *eq_cond
		= new bit_condition ((*arg1)[i]->copy (), (*arg2)[i]->copy (),
				     EQ_EXPR);
	      expr = new bit_or_expression (lt_cond, eq_cond);
	    }
	  else
	    expr = lt_cond;

	  if (prev)
	    prev = new bit_and_expression (expr, prev);
	  else
	    prev = expr;
	}
    }

  return prev;
}


/* Adds GREATER OR EQUAL condition of given variables to state.  */

bool
state::add_greater_or_equal_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_greater_or_equal_cond);
}


/* Adds greater or equal condition for two values.  */

void
state::add_greater_or_equal_cond (value *arg1, value *arg2)
{
  if (is_bit_vector (arg1) && is_bit_vector (arg2)
      && (make_number (arg2) != 0 || arg1->is_unsigned))
    {
      bool is_greater_than = check_const_value_is_greater_than (arg1,
								arg2);
      bool is_equal = check_const_value_equality (arg1, arg2);
      last_cond_status = (is_greater_than | is_equal)
			 ? condition_status::CS_TRUE
			 : condition_status::CS_FALSE;
      return;
    }

  last_cond_status = condition_status::CS_SYM;
  if (is_bit_vector (arg2) && make_number (arg2) == 0 && !arg1->is_unsigned)
    {
      if (is_a<bit *> (arg1->last ()))
	{
	  if (as_a<bit *> (arg1->last ())->get_val () == 1)
	    last_cond_status = condition_status::CS_FALSE;
	  else
	    last_cond_status = condition_status::CS_TRUE;
	}
      else
	conditions.add (new bit_condition (arg1->last ()->copy (), new bit (0),
					   EQ_EXPR));

      return;
    }

  bit_expression *eq_cond = construct_equal_cond (arg1, arg2);
  if (!eq_cond)
    return;

  bit_expression *gt_cond = construct_great_than_cond (arg1, arg2);
  if (gt_cond)
    /* Otherwise its status is already set.  */
    conditions.add (new bit_or_expression (eq_cond, gt_cond));
}


/* Adds LESS OR EQUAL condition of given variables to state.  */

bool
state::add_less_or_equal_cond (tree arg1, tree arg2)
{
  return add_binary_cond (arg1, arg2, &state::add_less_or_equal_cond);
}


/* Adds less or equal condition for two values.  */

void
state::add_less_or_equal_cond (value *arg1, value *arg2)
{
  if (is_bit_vector (arg1) && is_bit_vector (arg2))
    {
      bool is_less_than = check_const_value_is_less_than (arg1, arg2);
      bool is_equal = check_const_value_equality (arg1, arg2);
      last_cond_status = (is_less_than | is_equal)
			 ? condition_status::CS_TRUE
			 : condition_status::CS_FALSE;
      return;
    }

  last_cond_status = condition_status::CS_SYM;
  bit_expression *eq_cond = construct_equal_cond (arg1, arg2);
  if (!eq_cond)
    return;

  bit_expression *lt_cond = construct_less_than_cond (arg1, arg2);
  if (lt_cond)
    /* Otherwise its status is already set.  */
    conditions.add (new bit_or_expression (eq_cond, lt_cond));
}


/* Adds a bool condition to state.  */

bool
state::add_bool_cond (tree arg)
{
  if (!is_declared (arg))
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Sym-Exec: Argument must be declared "
			    "for bool condition.\n");

      return false;
    }

  value *arg_bits = var_states.get (arg);
  for (size_t i = 0; i < arg_bits->length (); i++)
    if (is_a<bit *> ((*arg_bits)[i])
	&& as_a<bit *> ((*arg_bits)[i])->get_val () != 0)
      {
	last_cond_status = condition_status::CS_TRUE;
	print_conditions ();
	return true;
      }

  if (is_bit_vector (arg_bits))
    {
      last_cond_status = condition_status::CS_FALSE;
      print_conditions ();
      return true;
    }

  bit_expression *prev = nullptr;
  for (size_t i = 0; i < arg_bits->length (); i++)
    {
      if (is_a<bit *> ((*arg_bits)[i]))
	continue;

      bit_condition *not_eq_cond
	= new bit_condition ((*arg_bits)[i], new bit (0), NE_EXPR);
      if (prev)
	prev = new bit_or_expression (not_eq_cond, prev);
      else
	prev = not_eq_cond;
    }

  last_cond_status = condition_status::CS_SYM;
  conditions.add (prev);
  print_conditions ();
  return true;
}


/* Does preprocessing and postprocessing for condition adding.
   Handles value creation for constants and their removement in the end.  */

bool
state::add_binary_cond (tree arg1, tree arg2, binary_cond_func cond_func)
{
  bool arg1_is_declared = is_declared (arg1);
  bool arg2_is_declared = is_declared (arg2);

  if (!arg1_is_declared && !arg2_is_declared)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "Sym-Exec: At least one of arguments must be"
			    " declared for adding the condition.\n");

      return false;
    }

  if (arg1_is_declared)
    declare_if_needed (arg2, var_states.get (arg1)->length ());

  if (arg2_is_declared)
    declare_if_needed (arg1, var_states.get (arg2)->length ());

  value *arg1_val = var_states.get (arg1);
  value arg1_const_val (MAX_VALUE_SIZE, false);

  if (arg1_val == NULL && TREE_CODE (arg1) == INTEGER_CST)
    {
      arg1_const_val = create_val_for_const (arg1,
					     var_states.get (arg2)->length ());
      arg1_val = &arg1_const_val;
    }

  value *arg2_val = var_states.get (arg2);
  value arg2_const_val (MAX_VALUE_SIZE, false);
  if (arg2_val == NULL && TREE_CODE (arg2) == INTEGER_CST)
    {
      arg2_const_val = create_val_for_const (arg2,
					     var_states.get (arg1)->length ());
      arg2_val = &arg2_const_val;
    }

  (this->*cond_func) (arg1_val, arg2_val);
  print_conditions ();
  return true;
}


/* Constructs expression trees of equal condition for given values.  */

bit_expression *
state::construct_equal_cond (value *arg1, value *arg2)
{
  /* If both arguments are constants then we can evaluate it.  */
  if (is_bit_vector (arg1) && is_bit_vector (arg2))
    {
      bool result = check_const_value_equality (arg1, arg2);
      last_cond_status = result ? condition_status::CS_TRUE
				: condition_status::CS_FALSE;
      return nullptr;
    }

  /* When some bits are constants, and they differ by value,
     then we can evaluate it to be false.  */
  for (size_t i = 0; i < arg1->length (); i++)
    {
      if (is_a<bit *> ((*arg1)[i]) && is_a<bit *> ((*arg2)[i])
	  && as_a<bit *> ((*arg1)[i])->get_val ()
	     != as_a<bit *> ((*arg2)[i])->get_val ())
	{
	  last_cond_status = condition_status::CS_FALSE;
	  return nullptr;
	}
    }

  bit_expression *prev = nullptr;
  for (size_t i = 0; i < arg1->length (); i++)
    {
      bit_condition *eq_expr = new bit_condition ((*arg1)[i]->copy (),
						  (*arg2)[i]->copy (), EQ_EXPR);
      if (prev)
	prev = new bit_and_expression (eq_expr, prev);
      else
	prev = eq_expr;
    }

  return prev;
}


/* Constructor for value.  The first argument is the size of the bit-vector
   and the second argument is the sign of the number.  */

value::value (unsigned size, bool is_unsigned) : is_unsigned (is_unsigned)
{
  number.create (size);
}


/* Copy constructor for value.  */

value::value (const value &other) : is_unsigned (other.is_unsigned)
{
  number.create (other.length ());
  for (size_t i = 0; i < other.length (); ++i)
    {
      value_bit *temp = other[i] ? other[i]->copy () : other[i];
      number.quick_push (temp);
    }
}


/* Returns pushed bits count.  */

unsigned
value::length () const
{
  return number.length ();
}


/* Wrapper of vec<..>::operator[] for the bit-vector.  */

value_bit *&
value::operator[] (unsigned i)
{
  return number[i];
}


/* Assignment operator.  If the specified value's size is smaller,
   then 0 constant bit will be assigned to the remaining upper bits.  */

value &
value::operator= (const value &other)
{
  unsigned smallest = number.allocated () < other.length ()
		      ? number.allocated () : other.length ();

  for (size_t i = 0; i < smallest; i++)
    if (i < number.length ())
      {
	delete number[i];
	number[i] = other[i]->copy ();
      }
    else
      number.quick_push (other[i]->copy ());

  for (size_t i = smallest; i < number.allocated (); i++)
    if (i < number.length ())
      {
	delete number[i];
	number[i] = other.is_unsigned ? new bit (0)
				      : other[other.length () - 1]->copy ();
      }
    else
      number.quick_push (other.is_unsigned
			 ? new bit (0) : other[other.length () - 1]->copy ());

  return (*this);
}


/* Wrapper of vec<..>::operator[] const for the bit-vector.  */

value_bit *
value::operator[] (unsigned i) const
{
  return number[i];
}


/* Wrapper of vec<..>.exists for the bit-vector.  */

bool
value::exists () const
{
  return number.exists ();
}


/* Returns the size in bits.  */

unsigned
value::allocated () const
{
  return number.allocated ();
}


/* Returns a reference the last bit.  */

value_bit *&
value::last ()
{
  return number.last ();
}


/* Make a copy of given bits.  */

vec<value_bit *> *
state::make_copy (vec<value_bit *> *bits)
{
  vec < value_bit * > *copied_bits = new vec<value_bit *> ();
  copied_bits->create (bits->length ());
  for (size_t i = 0; i < bits->length (); i++)
    copied_bits->quick_push ((*bits)[i]->copy ());

  return copied_bits;
}


/* Returns status of last added condition.  */

condition_status
state::get_last_cond_status ()
{
  return last_cond_status;
}


/* Prints the given value.  */

void
state::print_value (value *var)
{
  if (!dump_file || !(dump_flags & TDF_DETAILS))
    return;

  fprintf (dump_file, "{");
  for (int i = var->length () - 1; i >= 0; i--)
    {
      (*var)[i]->print ();

      if (i)
	fprintf (dump_file, ", ");
    }
  fprintf (dump_file, "}\n");
}


/* Create LFSR value for the reversed CRC.  */

void
state::create_reversed_lfsr (value &lfsr, const value &crc,
			     const value &polynomial)
{
  size_t size = polynomial.length ();

  /* Determine values of all bits, except MSB.  */
  for (size_t i = 0; i < size - 1; i++)
  {
    if (as_a<bit *> (polynomial[i])->get_val ())
      lfsr.push (state::xor_two_bits (crc[i + 1], crc[0]));
    else
      lfsr.push (crc[i + 1]->copy ());
  }

  /* Determine value of MSB.  */
  if (as_a<bit *> (polynomial[size - 1])->get_val ())
    lfsr.push (crc[0]->copy ());
  else
    lfsr.push (new bit (0));
}


/* Create LFSR value for the forward CRC.  */

void
state::create_forward_lfsr (value &lfsr, const value &crc,
			    const value &polynomial)
{
  size_t size = polynomial.length ();
  /* Determine value of LSB.  */
  if (as_a<bit *> (polynomial[0])->get_val ())
    lfsr.push (crc[size - 1]->copy ());
  else
    lfsr.push (new bit (0));

  /* Determine values of remaining bits.  */
  for (size_t i = 1; i < size; i++)
  {
    if (as_a<bit *> (polynomial[i])->get_val ())
      lfsr.push (state::xor_two_bits (crc[i - 1], crc[size - 1]));
    else
      lfsr.push (crc[i - 1]->copy ());
  }
}


/* Get the last 1 bit index.  */

size_t
last_set_bit (const value &polynomial)
{
  for (size_t i = 0; i < polynomial.length (); ++i)
    {
      if (as_a<bit *> (polynomial[polynomial.length () - i - 1])->get_val ())
	return polynomial.length () - i - 1;
    }
  return 0;
}


/* Create LFSR value.  */

value *
state::create_lfsr (tree crc, value *polynomial, bool is_bit_forward)
{
  /* Check size compatibility․  */
  unsigned HOST_WIDE_INT polynomial_length = polynomial->length ();
  unsigned HOST_WIDE_INT crc_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (crc)));
  if (crc_size < polynomial_length)
  {
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "LFSR state creation: "
			  "Polynomial doesn't fit into the crc.\n");

    return nullptr;
  }

  /* Get the minimal byte size to keep the polynomial.
     Ie, if the last 1 bit of the polynomial is at 6 index, size will be 8.  */
  size_t required_polynomial_size = ((last_set_bit (*polynomial)/8) + 1) * 8;

  /* Polynomial's length actually equals to the CRC variable's size.
     Now we detect only those CRC calculation algorithms, where leading 1 of the
     polynomial isn't kept.  */
  if (required_polynomial_size == 0
      || required_polynomial_size != polynomial_length)
  {
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "Polynomial's all bits are zeros "
			  "or the size of the polynomial is uncertain.\n");
    return nullptr;
  }

  /* Create vector of symbolic bits for crc.  */
  value crc_value (polynomial_length, TYPE_UNSIGNED (TREE_TYPE (crc)));

  for (unsigned HOST_WIDE_INT i = 0; i < polynomial_length; i++)
  crc_value.push (new symbolic_bit (i, crc));

  /* create LFSR vector.  */
  value *lfsr = new value (polynomial_length, TYPE_UNSIGNED (TREE_TYPE (crc)));

  /* Calculate values for LFSR.  */
  if (is_bit_forward)
    create_forward_lfsr (*lfsr, crc_value, *polynomial);
  else
    create_reversed_lfsr (*lfsr, crc_value, *polynomial);

  return lfsr;
}


/* Prints added conditions.  */

void
state::print_conditions ()
{
  if (!dump_file || !(dump_flags & TDF_DETAILS))
    return;

  fprintf (dump_file, "Conditions {");
  auto iter = conditions.begin ();
  while (true)
    {
      if (iter != conditions.end ())
	{
	  (*iter)->print ();
	  ++iter;
	}

      if (iter != conditions.end ())
	fprintf (dump_file, ", ");
      else
	break;
    }
  fprintf (dump_file, "}\n");
}


/* Pushes the given bit to the end of the bit vector.  */

value_bit **
value::push (value_bit *elem)
{
  return number.quick_push (elem);
}


/* Destructor for value.  */

value::~value ()
{
  free_bits ();
  number.release ();
}


/* Removes given sequence of bits.  */

void
value::free_bits ()
{
  if (!number.exists ())
    return;

  for (size_t i = 0; i < number.length (); i++)
    {
      delete number[i];
      number[i] = nullptr;
    }
}


/* For the given value_bit, iterates over its expression tree, complements
   those bit which came from the given origin.  */

value_bit *
state::complement_bits_with_origin (value_bit *root, tree origin)
{
  /* Be careful.  This function doesn't make a full copy of the bit.  */
  if (!is_a<bit_expression *> (root))
    {
      if (is_a<symbolic_bit *> (root)
	  && as_a<symbolic_bit *> (root)->get_origin () == origin)
	root = new bit_complement_expression (root);

      return root;
    }

  bit_expression *expr_root = as_a<bit_expression *> (root);
  hash_set <value_bit *> nodes_to_consider;
  nodes_to_consider.add (expr_root);
  hash_map <value_bit *, value_bit *> node_to_parent;
  node_to_parent.put (expr_root, nullptr);

  /* Traversing expression tree.  */
  while (!nodes_to_consider.is_empty ())
    {
      value_bit *cur_element = *nodes_to_consider.begin ();
      nodes_to_consider.remove (cur_element);

      if (is_a<symbolic_bit *> (cur_element))
	{
	  if (as_a<symbolic_bit *> (cur_element)->get_origin () != origin)
	    continue;

	  bit_expression *parent
	  = as_a<bit_expression *> (*node_to_parent.get (cur_element));
	  if (is_a<bit_complement_expression *> (parent))
	    {
	      value_bit *parent_of_parent = *node_to_parent.get (parent);
	      if (parent_of_parent)
		{
		  bit_expression *parent_of_parent_expr
		  = as_a<bit_expression *> (parent_of_parent);
		  parent->set_right (nullptr);
		  delete parent;
		  parent_of_parent_expr->get_left () == parent
		    ? parent_of_parent_expr->set_left (cur_element)
		    : parent_of_parent_expr->set_right (cur_element);
		}
	      else
		{
		  /* Parent is our root.  */
		  as_a<bit_expression *> (root)->set_right (nullptr);
		  delete root;
		  root = cur_element;
		}
	    }
	  else
	    {
	      value_bit* new_bit = new bit_complement_expression (cur_element);
	      parent->get_left () == cur_element ? parent->set_left (new_bit)
						 : parent->set_right (new_bit);
	    }
	  continue;
	}

      bit_expression* cur_elem_expr = as_a<bit_expression *> (cur_element);
      value_bit *left = cur_elem_expr->get_left ();
      value_bit *right = cur_elem_expr->get_right ();
      if (left != nullptr && !is_a<bit *> (left))
	{
	  nodes_to_consider.add (left);
	  node_to_parent.put (left, cur_element);
	}

      if (right != nullptr && !is_a<bit *> (right))
	{
	  nodes_to_consider.add (right);
	  node_to_parent.put (right, cur_element);
	}
    }

  return root;
}


/* Iterates over every bit of the given value and complements their
   expression trees' those bits, that came from the given origin.  */

void
state::complement_val_bits_with_origin (value *val, tree origin)
{
  for (size_t i = 0; i < val->length (); i++)
    {
      (*val)[i] = complement_bits_with_origin ((*val)[i], origin);
    }
}


/* Complements all bits of all values that came from the given origin.  */

void
state::complement_all_vars_bits_with_origin (tree origin)
{
  for (auto iter = var_states.begin (); iter != var_states.end (); ++iter)
    {
      complement_val_bits_with_origin (&(*iter).second, origin);
    }
}


/* Complements all bits with the given origin of all added conditions.  */

void
state::complement_conditions_with_origin (tree origin)
{
  hash_set<bit_expression *> updated_conditions;
  for (auto iter = conditions.begin (); iter != conditions.end (); ++iter)
    updated_conditions.add (as_a<bit_expression *> (
      complement_bits_with_origin (*iter, origin)));

  conditions.empty ();
  for (auto iter = updated_conditions.begin ();
       iter != updated_conditions.end (); ++iter)
    conditions.add (*iter);
}


/* Complements all bits with the given origin of all values
   and added conditions.  */

void
state::complement_state_with_origin (tree origin)
{
  complement_all_vars_bits_with_origin (origin);
  complement_conditions_with_origin (origin);
}


/* Performs the specified operation on passed variables.  */

bool
state::do_operation (tree_code op_code, tree arg1, tree arg2, tree dest)
{
  switch (op_code)
    {
      case BIT_NOT_EXPR:
	return do_complement (arg1, dest);
      case NOP_EXPR:
      case SSA_NAME:
      case VAR_DECL:
      case INTEGER_CST:
	return do_assign (arg1, dest);
      case LSHIFT_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_shift_left);
      case RSHIFT_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_shift_right);
      case BIT_AND_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_and);
      case BIT_IOR_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_or);
      case BIT_XOR_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_xor);
      case PLUS_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_add);
      case MINUS_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_sub);
      case MULT_EXPR:
	return do_binary_operation (arg1, arg2, dest, &state::do_mul);
      default:
	{
	  if (dump_file)
	    fprintf (dump_file,
		     "Warning, encountered unsupported operation "
		     "with %s code while executing assign statement!\n",
		     get_tree_code_name (op_code));
	  return false;
	}
    }
}