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

Module:

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

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

#include <std_types.h>

#include "boolbv.h"

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

Function: boolbvt::convert_div

  Inputs:

 Outputs:

 Purpose:

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

bool boolbvt::convert_div(const exprt &expr, bvt &bv)
{
  if(expr.type().id()!="unsignedbv" &&
     expr.type().id()!="signedbv" &&
     expr.type().id()!="fixedbv")
    return true;

  unsigned width;
  if(get_width(expr.type(), width))
    return true;

  if(expr.operands().size()!=2)
    throw "division takes two operands";

  if(expr.op0().type().id()!=expr.type().id() ||
     expr.op1().type().id()!=expr.type().id())
    return true;

  bvt op0, op1;

  if(convert_bv(expr.op0(), op0)) return true;
  if(convert_bv(expr.op1(), op1)) return true;

  if(op0.size()!=width ||
     op1.size()!=width)
    throw "convert_div: unexpected operand width";

  bvt res, rem;

  if(expr.type().id()=="fixedbv")
  {
    unsigned fraction_bits=
      to_fixedbv_type(expr.type()).get_fraction_bits();

    bvt zeros;
    zeros.resize(fraction_bits, prop.constant(false));

    // add fraction_bits least-significant bits
    op0.insert(op0.begin(), zeros.begin(), zeros.end());
    bv_utils.extend(op1, op1.size()+fraction_bits, true);
  
    bv_utils.divider(op0, op1, res, rem, true);
    
    // cut it down again
    res.resize(width);
  }
  else
  {
    bv_utils.divider(op0, op1, res, rem, expr.type().id()=="signedbv");
  }

  bv=res;

  return false;
}
