/*******************************************************************\

Module:

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#ifndef CPROVER_BV_UTILS_H
#define CPROVER_BV_UTILS_H

#include "prop.h"

class bv_utilst
{
public:
  bv_utilst(propt &_prop):prop(_prop) { }

  void incrementer(bvt &op, literalt carry_in, literalt &carry_out);

  void negate(bvt &op);
  void negate_no_overflow(bvt &op);
  
  literalt overflow_negate(const bvt &op);

  void invert(bvt &op);

  literalt carry(literalt a, literalt b, literalt c);

  void adder(bvt &sum, const bvt &op, bool subtract,
             literalt carry_in, literalt &carry_out,
             bool carry_only);

  void adder(bvt &sum, const bvt &op, bool subtract);

  void adder_no_overflow(
    bvt &sum,
    const bvt &op,
    bool subtract,
    bool is_signed);

  typedef enum { LEFT, LRIGHT, ARIGHT } shiftt;
  void shifter(const shiftt shift, bvt &op, const bvt &dist);

  void unsigned_multiplier(bvt &product, const bvt &op);
   
  void signed_multiplier(bvt &product, const bvt &op);
  void multiplier(bvt &product, const bvt &op, bool is_signed);
  void multiplier_no_overflow(bvt &product, const bvt &op, bool is_signed);

  void divider(const bvt &op0, const bvt &op1,
               bvt &res, bvt &rem, bool is_signed);
  void signed_divider(const bvt &op0, const bvt &op1,
                      bvt &res, bvt &rem);
  void unsigned_divider(const bvt &op0, const bvt &op1,
                         bvt &res, bvt &rem);
  
  literalt equal(const bvt &op0, const bvt &op1);
  
  literalt is_zero(const bvt &op)
  { return prop.lnot(prop.lor(op)); }

  bvt bv_if(const literalt op0, const bvt &op1, const bvt &op2);

  literalt lt_or_le(bool or_equal,
                    const bvt &bv0,
                    const bvt &bv1,
                    bool is_signed);

  bool is_constant(const bvt &bv);
  
  void extend(bvt &bv, unsigned size, bool is_signed)
  {
    unsigned old_size=bv.size();
    bv.resize(size);
    for(unsigned i=old_size; i<size; i++)
      bv[i]=is_signed?bv[old_size-1]:prop.constant(false);
  }
                    
protected:
  void adder_no_overflow(bvt &sum, const bvt &op);

  void unsigned_multiplier_no_overflow(
    const bvt &op0, const bvt &op1,
    bvt &product);

  void unsigned_multiplier_no_overflow(
    bvt &product, const bvt &op);

  void signed_multiplier_no_overflow(
    bvt &product, const bvt &op);

  void cond_negate(bvt &bv, const literalt cond);
  
  void cond_negate_no_overflow(bvt &bv, const literalt cond);

  propt &prop;                                       
};

#endif
