Пример #1
0
bvt boolbvt::convert_power(const binary_exprt &expr)
{
  const typet &type=ns.follow(expr.type());

  std::size_t width=boolbv_width(type);

  if(width==0)
    return conversion_failed(expr);

  if(type.id()==ID_unsignedbv ||
     type.id()==ID_signedbv)
  {
    // Let's do the special case 2**x
    bvt op0=convert_bv(expr.op0());
    bvt op1=convert_bv(expr.op1());

    literalt eq_2=
      bv_utils.equal(op0, bv_utils.build_constant(2, op0.size()));

    bvt one=bv_utils.build_constant(1, width);
    bvt shift=bv_utils.shift(one, bv_utilst::LEFT, op1);

    bvt nondet=prop.new_variables(width);

    return bv_utils.select(eq_2, shift, nondet);
  }

  return conversion_failed(expr);
}
Пример #2
0
void boolbvt::convert_div(const exprt &expr, bvt &bv)
{
  if(expr.type().id()!=ID_unsignedbv &&
     expr.type().id()!=ID_signedbv &&
     expr.type().id()!=ID_fixedbv)
    return conversion_failed(expr, bv);

  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  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 conversion_failed(expr, bv);

  bvt op0=convert_bv(expr.op0());
  bvt op1=convert_bv(expr.op1());

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

  bvt res, rem;

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

    bvt zeros;
    zeros.resize(fraction_bits, const_literal(false));

    // add fraction_bits least-significant bits
    op0.insert(op0.begin(), zeros.begin(), zeros.end());
    op1=bv_utils.sign_extension(op1, op1.size()+fraction_bits);
  
    bv_utils.divider(op0, op1, res, rem, bv_utilst::SIGNED);
    
    // cut it down again
    res.resize(width);
  }
  else
  {
    bv_utilst::representationt rep=
      expr.type().id()==ID_signedbv?bv_utilst::SIGNED:
                                   bv_utilst::UNSIGNED;

    bv_utils.divider(op0, op1, res, rem, rep);
  }

  bv=res;
}
Пример #3
0
bvt boolbvt::convert_array_of(const array_of_exprt &expr)
{
  if(expr.type().id()!=ID_array)
    throw "array_of must be array-typed";

  const array_typet &array_type=to_array_type(expr.type());

  if(is_unbounded_array(array_type))
    return conversion_failed(expr);

  std::size_t width=boolbv_width(array_type);

  if(width==0)
  {
    // A zero-length array is acceptable;
    // an element with unknown size is not.
    if(boolbv_width(array_type.subtype())==0)
      return conversion_failed(expr);
    else
      return bvt();
  }

  const exprt &array_size=array_type.size();

  mp_integer size;

  if(to_integer(array_size, size))
    return conversion_failed(expr);

  const bvt &tmp=convert_bv(expr.op0());

  bvt bv;
  bv.resize(width);

  if(size*tmp.size()!=width)
    throw "convert_array_of: unexpected operand width";

  std::size_t offset=0;

  for(mp_integer i=0; i<size; i=i+1)
  {
    for(std::size_t j=0; j<tmp.size(); j++, offset++)
      bv[offset]=tmp[j];
  }

  assert(offset==bv.size());

  return bv;
}
Пример #4
0
void boolbvt::convert_index(
  const exprt &array,
  const mp_integer &index,
  bvt &bv)
{
  const array_typet &array_type=
    to_array_type(ns.follow(array.type()));

  unsigned width=boolbv_width(array_type.subtype());

  if(width==0)
    return conversion_failed(array, bv);

  bv.resize(width);
  
  const bvt &tmp=convert_bv(array); // recursive call

  mp_integer offset=index*width;

  if(offset>=0 &&
     offset+width<=mp_integer(tmp.size()))
  {
    // in bounds
    for(unsigned i=0; i<width; i++)
      bv[i]=tmp[integer2long(offset+i)];
  }
  else
  {
    // out of bounds
    for(unsigned i=0; i<width; i++)
      bv[i]=prop.new_variable();
  }
}
void boolbvt::convert_concatenation(const exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);
    
  const exprt::operandst &operands=expr.operands();

  if(operands.size()==0)
    throw "concatenation takes at least one operand";

  unsigned offset=width;
  bv.resize(width);

  forall_expr(it, operands)
  {
    const bvt &op=convert_bv(*it);

    if(op.size()>offset)
      throw "concatenation operand width too big";

    offset-=op.size();

    for(unsigned i=0; i<op.size(); i++)
      bv[offset+i]=op[i];
  }    

  if(offset!=0)
    throw "concatenation operand width too small";
}
Пример #6
0
bvt boolbvt::convert_array(const exprt &expr)
{
  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr);

  if(expr.type().id()==ID_array)
  {
    assert(expr.has_operands());
    const exprt::operandst &operands=expr.operands();
    assert(!operands.empty());
    std::size_t op_width=width/operands.size();

    bvt bv;
    bv.reserve(width);

    forall_expr(it, operands)
    {
      const bvt &tmp=convert_bv(*it);

      if(tmp.size()!=op_width)
        throw "convert_array: unexpected operand width";

      forall_literals(it2, tmp)
        bv.push_back(*it2);
    }

    return bv;
  }
Пример #7
0
void boolbvt::convert_replication(const exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

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

  mp_integer times;
  if(to_integer(expr.op0(), times))
    throw "replication takes constant as first parameter";
  const unsigned u_times=integer2unsigned(times);

  const bvt &op=convert_bv(expr.op1());

  unsigned offset=0;
  bv.resize(width);

  for(unsigned i=0; i<u_times; i++)
  {
    if(op.size()+offset>width)
      throw "replication operand width too big";

    for(unsigned i=0; i<op.size(); i++)
      bv[i+offset]=op[i];

    offset+=op.size();
  }    

  if(offset!=bv.size())
    throw "replication operand width too small";
}
Пример #8
0
void boolbvt::convert_constant(const constant_exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  bv.resize(width);
  
  const typet &expr_type=expr.type();
  
  if(expr_type.id()==ID_array)
  {
    unsigned op_width=width/expr.operands().size();
    unsigned offset=0;

    forall_operands(it, expr)
    {
      const bvt &tmp=convert_bv(*it);

      if(tmp.size()!=op_width)
        throw "convert_constant: unexpected operand width";

      for(unsigned j=0; j<op_width; j++)
        bv[offset+j]=tmp[j];

      offset+=op_width;
    }   
    
    return;
  }
Пример #9
0
void boolbvt::convert_cond(const exprt &expr, bvt &bv)
{
  const exprt::operandst &operands=expr.operands();

  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  bv.resize(width);

  // make it free variables
  Forall_literals(it, bv)
    *it=prop.new_variable();

  if(operands.size()<2)
    throw "cond takes at least two operands";

  if((operands.size()%2)!=0)
    throw "number of cond operands must be even";

  if(prop.has_set_to())
  {
    bool condition=true;
    literalt previous_cond=const_literal(false);
    literalt cond_literal=const_literal(false);

    forall_operands(it, expr)
    {
      if(condition)
      {
        cond_literal=convert(*it);
        cond_literal=prop.land(prop.lnot(previous_cond), cond_literal);

        previous_cond=prop.lor(previous_cond, cond_literal);
      }
      else
      {
        const bvt &op=convert_bv(*it);

        if(bv.size()!=op.size())
        {
          std::cerr << "result size: " << bv.size()
                    << std::endl
                    << "operand: " << op.size() << std::endl
                    << it->pretty()
                    << std::endl;

          throw "size of value operand does not match";
        }

        literalt value_literal=bv_utils.equal(bv, op);

        prop.l_set_to_true(prop.limplies(cond_literal, value_literal));
      }

      condition=!condition;
    }
  }
Пример #10
0
void boolbvt::convert_floatbv_typecast(
  const floatbv_typecast_exprt &expr, bvt &bv)
{
  const exprt &op0=expr.op(); // number to convert
  const exprt &op1=expr.rounding_mode(); // rounding mode

  bvt bv0=convert_bv(op0);
  bvt bv1=convert_bv(op1);

  const typet &src_type=ns.follow(expr.op0().type());
  const typet &dest_type=ns.follow(expr.type());
  
  if(src_type==dest_type) // redundant type cast?
  {
    bv=bv0;
    return;
  }

  float_utilst float_utils(prop);
  
  float_utils.set_rounding_mode(convert_bv(op1));
  
  if(src_type.id()==ID_floatbv &&
     dest_type.id()==ID_floatbv)
  {
    float_utils.spec=to_floatbv_type(src_type);
    bv=float_utils.conversion(bv0, to_floatbv_type(dest_type));
  }
  else if(src_type.id()==ID_signedbv &&
          dest_type.id()==ID_floatbv)
  {
    float_utils.spec=to_floatbv_type(dest_type);
    bv=float_utils.from_signed_integer(bv0);
  }
  else if(src_type.id()==ID_unsignedbv &&
          dest_type.id()==ID_floatbv)
  {
    float_utils.spec=to_floatbv_type(dest_type);
    bv=float_utils.from_unsigned_integer(bv0);
  }
  else if(src_type.id()==ID_floatbv &&
          dest_type.id()==ID_signedbv)
  {
    std::size_t dest_width=to_signedbv_type(dest_type).get_width();
    float_utils.spec=to_floatbv_type(src_type);
    bv=float_utils.to_signed_integer(bv0, dest_width);
  }
  else if(src_type.id()==ID_floatbv &&
          dest_type.id()==ID_unsignedbv)
  {
    std::size_t dest_width=to_unsignedbv_type(dest_type).get_width();
    float_utils.spec=to_floatbv_type(src_type);
    bv=float_utils.to_unsigned_integer(bv0, dest_width);
  }
  else
    return conversion_failed(expr, bv);
}
Пример #11
0
void boolbvt::convert_shift(const exprt &expr, bvt &bv)
{
  if(expr.type().id()!=ID_unsignedbv &&
     expr.type().id()!=ID_signedbv)
    return conversion_failed(expr, bv);

  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  if(width==0)
    throw "zero length bit vector type: "+expr.type().to_string();

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

  bvt op, dist;

  convert_bv(expr.op0(), op);
  convert_bv(expr.op1(), dist);

  if(op.size()!=width)
    throw "convert_shift: unexpected operand width";

  bv_utilst::shiftt shift;

  if(expr.id()==ID_shl)
    shift=bv_utilst::LEFT;
  else if(expr.id()==ID_ashr)
    shift=bv_utilst::ARIGHT;
  else if(expr.id()==ID_lshr)
    shift=bv_utilst::LRIGHT;
  else
    throw "unexpected operand";

  bv=bv_utils.shift(op, shift, dist);
}
Пример #12
0
bvt boolbvt::convert_bv_typecast(const typecast_exprt &expr)
{
  const typet &expr_type=ns.follow(expr.type());
  const exprt &op=expr.op();
  const typet &op_type=ns.follow(op.type());
  const bvt &op_bv=convert_bv(op);  

  bvt bv;

  if(type_conversion(op_type, op_bv, expr_type, bv))
    return conversion_failed(expr);

  return bv;
}
Пример #13
0
void boolbvt::convert_shift(const exprt &expr, bvt &bv)
{
  if(expr.type().id()!=ID_unsignedbv &&
     expr.type().id()!=ID_signedbv &&
     expr.type().id()!=ID_floatbv &&
     expr.type().id()!=ID_pointer &&
     expr.type().id()!=ID_bv)
    return conversion_failed(expr, bv);

  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

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

  const bvt &op=convert_bv(expr.op0());
  const bvt &dist=convert_bv(expr.op1());

  if(op.size()!=width)
    throw "convert_shift: unexpected operand width";

  bv_utilst::shiftt shift;

  if(expr.id()==ID_shl)
    shift=bv_utilst::LEFT;
  else if(expr.id()==ID_ashr)
    shift=bv_utilst::ARIGHT;
  else if(expr.id()==ID_lshr)
    shift=bv_utilst::LRIGHT;
  else
    throw "unexpected operand";

  bv=bv_utils.shift(op, shift, dist);
}
Пример #14
0
bvt boolbvt::convert_abs(const exprt &expr)
{
    std::size_t width=boolbv_width(expr.type());

    if(width==0)
        return conversion_failed(expr);

    const exprt::operandst &operands=expr.operands();

    if(operands.size()!=1)
        throw "abs takes one operand";

    const exprt &op0=expr.op0();

    const bvt &op_bv=convert_bv(op0);

    if(op0.type()!=expr.type())
        return conversion_failed(expr);

    bvtypet bvtype=get_bvtype(expr.type());

    if(bvtype==IS_FIXED ||
            bvtype==IS_SIGNED ||
            bvtype==IS_UNSIGNED)
    {
        return bv_utils.absolute_value(op_bv);
    }
    else if(bvtype==IS_FLOAT)
    {
        float_utilst float_utils(prop);
        float_utils.spec=to_floatbv_type(expr.type());
        return float_utils.abs(op_bv);
    }

    return conversion_failed(expr);
}
Пример #15
0
bvt boolbvt::convert_with(const exprt &expr)
{
  if(expr.operands().size()<3)
  {
    error().source_location=expr.find_source_location();
    error() << "with takes at least three operands" << eom;
    throw 0;
  }

  if((expr.operands().size()%2)!=1)
  {
    error().source_location=expr.find_source_location();
    error() << "with takes an odd number of operands" << eom;
    throw 0;
  }

  bvt bv=convert_bv(expr.op0());

  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr);

  if(bv.size()!=width)
  {
    error().source_location=expr.find_source_location();
    error() << "unexpected operand 0 width" << eom;
    throw 0;
  }

  bvt prev_bv;
  prev_bv.resize(width);

  const exprt::operandst &ops=expr.operands();

  for(std::size_t op_no=1; op_no<ops.size(); op_no+=2)
  {
    bv.swap(prev_bv);

    convert_with(expr.op0().type(),
                 ops[op_no],
                 ops[op_no+1],
                 prev_bv,
                 bv);
  }

  return bv;
}
Пример #16
0
bvt boolbvt::convert_union(const union_exprt &expr)
{
  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr);

  const bvt &op_bv=convert_bv(expr.op());

  if(width<op_bv.size())
    throw "union: unexpected operand op width";

  bvt bv;
  bv.resize(width);

  if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN)
  {
    for(std::size_t i=0; i<op_bv.size(); i++)
      bv[i]=op_bv[i];

    // pad with nondets
    for(std::size_t i=op_bv.size(); i<bv.size(); i++)
      bv[i]=prop.new_variable();
  }
  else
  {
    assert(
      config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_BIG_ENDIAN);

    endianness_mapt map_u(expr.type(), false, ns);
    endianness_mapt map_op(expr.op0().type(), false, ns);

    for(std::size_t i=0; i<op_bv.size(); i++)
      bv[map_u.map_bit(i)]=op_bv[map_op.map_bit(i)];

    // pad with nondets
    for(std::size_t i=op_bv.size(); i<bv.size(); i++)
      bv[map_u.map_bit(i)]=prop.new_variable();
  }

  return bv;
}
Пример #17
0
void boolbvt::convert_update(const exprt &expr, bvt &bv)
{
  const exprt::operandst &ops=expr.operands();

  if(ops.size()!=3)
    throw "update takes at three operands";

  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr, bv);

  bv=convert_bv(ops[0]);

  if(bv.size()!=width)
    throw "update: unexpected operand 0 width";

  // start the recursion
  convert_update_rec(
    expr.op1().operands(), 0, expr.type(), 0, expr.op2(), bv);
}
Пример #18
0
void boolbvt::convert_union(const exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr, bv);

  if(expr.operands().size()!=1)
    throw "union expects one argument";

  const bvt &op_bv=convert_bv(expr.op0());

  if(width<op_bv.size())
    throw "union: unexpected operand op width";

  bv.resize(width);
  
  for(unsigned i=0; i<op_bv.size(); i++)
    bv[i]=op_bv[i];

  // pad with nondets
  for(unsigned i=op_bv.size(); i<bv.size(); i++)
    bv[i]=prop.new_variable();
}
Пример #19
0
void boolbvt::convert_mult(const exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  bv.resize(width);

  const exprt::operandst &operands=expr.operands();
  if(operands.size()==0)
    throw "mult without operands";

  const exprt &op0=expr.op0();

  bool no_overflow=expr.id()=="no-overflow-mult";
  
  if(expr.type().id()==ID_fixedbv)
  {
    if(op0.type()!=expr.type())
      throw "multiplication with mixed types";
    
    bv=convert_bv(op0);

    if(bv.size()!=width)
      throw "convert_mult: unexpected operand width";

    unsigned fraction_bits=
      to_fixedbv_type(expr.type()).get_fraction_bits();
             
    // do a sign extension by fraction_bits bits
    bv=bv_utils.sign_extension(bv, bv.size()+fraction_bits);
      
    for(exprt::operandst::const_iterator it=operands.begin()+1;
        it!=operands.end(); it++)
    {
      if(it->type()!=expr.type())
        throw "multiplication with mixed types";

      bvt op=convert_bv(*it);

      if(op.size()!=width)
        throw "convert_mult: unexpected operand width";

      op=bv_utils.sign_extension(op, bv.size());

      bv=bv_utils.signed_multiplier(bv, op);
    }
    
    // cut it down again
    bv.erase(bv.begin(), bv.begin()+fraction_bits);

    return;
  }
  else if(expr.type().id()==ID_floatbv)
  {
    if(op0.type()!=expr.type())
      throw "multiplication with mixed types";
    
    bv=convert_bv(op0);

    if(bv.size()!=width)
      throw "convert_mult: unexpected operand width";

    float_utilst float_utils(prop);
    float_utils.spec=to_floatbv_type(expr.type());

    for(exprt::operandst::const_iterator it=operands.begin()+1;
        it!=operands.end(); it++)
    {
      if(it->type()!=expr.type())
        throw "multiplication with mixed types";

      const bvt &op=convert_bv(*it);

      if(op.size()!=width)
        throw "convert_mult: unexpected operand width";

      bv=float_utils.mul(bv, op);
    }
    
    return;
  }
  else if(expr.type().id()==ID_unsignedbv ||
          expr.type().id()==ID_signedbv)
  {
    if(op0.type()!=expr.type())
      throw "multiplication with mixed types";
      
    bv_utilst::representationt rep=
      expr.type().id()==ID_signedbv?bv_utilst::SIGNED:
                                    bv_utilst::UNSIGNED;
    
    bv=convert_bv(op0);

    if(bv.size()!=width)
      throw "convert_mult: unexpected operand width";
      
    for(exprt::operandst::const_iterator it=operands.begin()+1;
        it!=operands.end(); it++)
    {
      if(it->type()!=expr.type())
        throw "multiplication with mixed types";

      const bvt &op=convert_bv(*it);

      if(op.size()!=width)
        throw "convert_mult: unexpected operand width";

      if(no_overflow)
        bv=bv_utils.multiplier_no_overflow(bv, op, rep);
      else
        bv=bv_utils.multiplier(bv, op, rep);
    }    

    return;
  }
  
  conversion_failed(expr, bv);
}
Пример #20
0
void boolbvt::convert_index(const index_exprt &expr, bvt &bv)
{
  if(expr.id()!=ID_index)
    throw "expected index expression";

  if(expr.operands().size()!=2)
    throw "index takes two operands";
    
  const exprt &array=expr.array();
  const exprt &index=expr.index();
  
  const array_typet &array_type=
    to_array_type(ns.follow(array.type()));

  // see if the array size is constant

  if(is_unbounded_array(array_type))
  {
    // use array decision procedure
  
    unsigned width=boolbv_width(expr.type());
    
    if(width==0)
      return conversion_failed(expr, bv);

    // free variables

    bv.resize(width);
    for(unsigned i=0; i<width; i++)
      bv[i]=prop.new_variable();

    record_array_index(expr);

    // record type if array is a symbol

    if(array.id()==ID_symbol)
      map.get_map_entry(
        to_symbol_expr(array).get_identifier(), array_type);

    // make sure we have the index in the cache
    convert_bv(index);
    
    return;
  }

  // see if the index address is constant

  mp_integer index_value;
  if(!to_integer(index, index_value))
    return convert_index(array, index_value, bv);

  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  mp_integer array_size;
  if(to_integer(array_type.size(), array_size))
  {
    std::cout << to_array_type(array.type()).size().pretty() << std::endl;
    throw "failed to convert array size";
  }

  // get literals for the whole array

  const bvt &array_bv=convert_bv(array);

  if(array_size*width!=array_bv.size())
    throw "unexpected array size";
    
  // TODO: maybe a shifter-like construction would be better

  if(prop.has_set_to())
  {
    // free variables

    bv.resize(width);
    for(unsigned i=0; i<width; i++)
      bv[i]=prop.new_variable();

    // add implications

    equal_exprt index_equality;
    index_equality.lhs()=index; // index operand

    bvt equal_bv;
    equal_bv.resize(width);

    for(mp_integer i=0; i<array_size; i=i+1)
    {
      index_equality.rhs()=from_integer(i, index_equality.lhs().type());

      if(index_equality.rhs().is_nil())
        throw "number conversion failed (1)";

      mp_integer offset=i*width;

      for(unsigned j=0; j<width; j++)
        equal_bv[j]=prop.lequal(bv[j],
                           array_bv[integer2long(offset+j)]);

      prop.l_set_to_true(
        prop.limplies(convert(index_equality), prop.land(equal_bv)));
    }
  }
  else
  {
    bv.resize(width);

    equal_exprt equality;
    equality.lhs()=index; // index operand

    typet constant_type=index.type(); // type of index operand
    
    assert(array_size>0);

    for(mp_integer i=0; i<array_size; i=i+1)
    {
      equality.op1()=from_integer(i, constant_type);
        
      literalt e=convert(equality);

      mp_integer offset=i*width;

      for(unsigned j=0; j<width; j++)
      {
        literalt l=array_bv[integer2long(offset+j)];

        if(i==0) // this initializes bv
          bv[j]=l;
        else
          bv[j]=prop.lselect(e, l, bv[j]);
      }
    }    
  }
}
Пример #21
0
void boolbvt::convert_add_sub(const exprt &expr, bvt &bv)
{
  const typet &type=ns.follow(expr.type());

  if(type.id()!=ID_unsignedbv &&
     type.id()!=ID_signedbv &&
     type.id()!=ID_fixedbv &&
     type.id()!=ID_floatbv &&
     type.id()!=ID_range &&
     type.id()!=ID_vector)
    return conversion_failed(expr, bv);

  unsigned width=boolbv_width(type);
  
  if(width==0)
    return conversion_failed(expr, bv);
    
  const exprt::operandst &operands=expr.operands();

  if(operands.size()==0)
    throw "operand "+expr.id_string()+" takes at least one operand";

  const exprt &op0=expr.op0();

  if(op0.type()!=type)
  {
    std::cerr << expr.pretty() << std::endl;
    throw "add/sub with mixed types";
  }

  convert_bv(op0, bv);

  if(bv.size()!=width)
    throw "convert_add_sub: unexpected operand 0 width";

  bool subtract=(expr.id()==ID_minus ||
                 expr.id()=="no-overflow-minus");
                 
  bool no_overflow=(expr.id()=="no-overflow-plus" ||
                    expr.id()=="no-overflow-minus");

  typet arithmetic_type=
    (type.id()==ID_vector)?ns.follow(type.subtype()):type;

  bv_utilst::representationt rep=
    (arithmetic_type.id()==ID_signedbv ||
     arithmetic_type.id()==ID_fixedbv)?bv_utilst::SIGNED:
                                       bv_utilst::UNSIGNED;

  for(exprt::operandst::const_iterator
      it=operands.begin()+1;
      it!=operands.end(); it++)
  {
    if(it->type()!=type)
    {
      std::cerr << expr.pretty() << std::endl;
      throw "add/sub with mixed types";
    }

    bvt op;
    convert_bv(*it, op);

    if(op.size()!=width)
      throw "convert_add_sub: unexpected operand width";

    if(type.id()==ID_vector)
    {
      const typet &subtype=ns.follow(type.subtype());
    
      unsigned sub_width=boolbv_width(subtype);

      if(sub_width==0 || width%sub_width!=0)
        throw "convert_add_sub: unexpected vector operand width";

      unsigned size=width/sub_width;
      bv.resize(width);

      for(unsigned i=0; i<size; i++)
      {
        bvt tmp_op;
        tmp_op.resize(sub_width);

        for(unsigned j=0; j<tmp_op.size(); j++)
        {
          assert(i*sub_width+j<op.size());
          tmp_op[j]=op[i*sub_width+j];
        }
        
        bvt tmp_result;
        tmp_result.resize(sub_width);

        for(unsigned j=0; j<tmp_result.size(); j++)
        {
          assert(i*sub_width+j<bv.size());
          tmp_result[j]=bv[i*sub_width+j];
        }
        
        if(type.subtype().id()==ID_floatbv)
        {
          #ifdef HAVE_FLOATBV
          float_utilst float_utils(prop);
          float_utils.spec=to_floatbv_type(subtype);
          tmp_result=float_utils.add_sub(tmp_result, tmp_op, subtract);
          #else
          return conversion_failed(expr, bv);
          #endif
        }
        else
          tmp_result=bv_utils.add_sub(tmp_result, tmp_op, subtract);
      
        assert(tmp_result.size()==sub_width);
        
        for(unsigned j=0; j<tmp_result.size(); j++)
        {
          assert(i*sub_width+j<bv.size());
          bv[i*sub_width+j]=tmp_result[j];
        }
      }
    }
    else if(type.id()==ID_floatbv)
    {
      #ifdef HAVE_FLOATBV
      float_utilst float_utils(prop);
      float_utils.spec=to_floatbv_type(arithmetic_type);
      bv=float_utils.add_sub(bv, op, subtract);
      #else
      return conversion_failed(expr, bv);
      #endif
    }
    else if(no_overflow)
      bv=bv_utils.add_sub_no_overflow(bv, op, subtract, rep);
    else
      bv=bv_utils.add_sub(bv, op, subtract);
  }
}
void boolbvt::convert_constraint_select_one(const exprt &expr, bvt &bv)
{
  const exprt::operandst &operands=expr.operands();

  if(expr.id()!="constraint_select_one")
    throw "expected constraint_select_one expression";

  if(operands.size()<2)
    throw "constraint_select_one takes at least two operands";

  if(expr.type()!=expr.op0().type())
    throw "constraint_select_one expects matching types";
    
  if(prop.has_set_to())
  {
    std::vector<bvt> op_bv;
    op_bv.reserve(expr.operands().size());

    forall_operands(it, expr)
      op_bv.push_back(convert_bv(*it));

    bv=op_bv[0];

    // add constraints

    bvt equal_bv;
    equal_bv.resize(bv.size());

    bvt b;
    b.reserve(op_bv.size()-1);

    for(unsigned i=1; i<op_bv.size(); i++)
    {
      if(op_bv[i].size()!=bv.size())
        throw "constraint_select_one expects matching width";

      for(unsigned j=0; j<bv.size(); j++)
        equal_bv[j]=prop.lequal(bv[j], op_bv[i][j]);

      b.push_back(prop.land(equal_bv));
    }

    prop.l_set_to_true(prop.lor(b));
  }
  else
  {
    unsigned op_nr=0;
    forall_operands(it, expr)
    {
      const bvt &op_bv=convert_bv(*it);

      if(op_nr==0)
        bv=op_bv;
      else
      {
        if(op_bv.size()!=bv.size())
          return conversion_failed(expr, bv);

        for(unsigned i=0; i<op_bv.size(); i++)
          bv[i]=prop.lselect(prop.new_variable(), bv[i], op_bv[i]);
      }

      op_nr++;
    }
  }
}
Пример #23
0
void boolbvt::convert_unary_minus(const exprt &expr, bvt &bv)
{
  const typet &type=ns.follow(expr.type());

  unsigned width=boolbv_width(type);
  
  if(width==0)
    return conversion_failed(expr, bv);

  const exprt::operandst &operands=expr.operands();

  if(operands.size()!=1)
    throw "unary minus takes one operand";
    
  const exprt &op0=expr.op0();

  const bvt &op_bv=convert_bv(op0);

  bvtypet bvtype=get_bvtype(type);
  bvtypet op_bvtype=get_bvtype(op0.type());
  unsigned op_width=op_bv.size();

  bool no_overflow=(expr.id()=="no-overflow-unary-minus");
  
  if(op_width==0 || op_width!=width)
    return conversion_failed(expr, bv);

  if(bvtype==IS_UNKNOWN &&
     (type.id()==ID_vector || type.id()==ID_complex))
  {
    const typet &subtype=ns.follow(type.subtype());
  
    unsigned sub_width=boolbv_width(subtype);

    if(sub_width==0 || width%sub_width!=0)
      throw "unary-: unexpected vector operand width";

    unsigned size=width/sub_width;
    bv.resize(width);

    for(unsigned i=0; i<size; i++)
    {
      bvt tmp_op;
      tmp_op.resize(sub_width);

      for(unsigned j=0; j<tmp_op.size(); j++)
      {
        assert(i*sub_width+j<op_bv.size());
        tmp_op[j]=op_bv[i*sub_width+j];
      }
      
      bvt tmp_result;
      
      if(type.subtype().id()==ID_floatbv)
      {
        float_utilst float_utils(prop);
        float_utils.spec=to_floatbv_type(subtype);
        tmp_result=float_utils.negate(tmp_op);
      }
      else
        tmp_result=bv_utils.negate(tmp_op);
    
      assert(tmp_result.size()==sub_width);
      
      for(unsigned j=0; j<tmp_result.size(); j++)
      {
        assert(i*sub_width+j<bv.size());
        bv[i*sub_width+j]=tmp_result[j];
      }
    }

    return;
  }
  else if(bvtype==IS_FIXED && op_bvtype==IS_FIXED)
  {
    if(no_overflow)
      bv=bv_utils.negate_no_overflow(op_bv);
    else
      bv=bv_utils.negate(op_bv);

    return;
  }
  else if(bvtype==IS_FLOAT && op_bvtype==IS_FLOAT)
  {
    assert(!no_overflow);
    float_utilst float_utils(prop);
    float_utils.spec=to_floatbv_type(expr.type());
    bv=float_utils.negate(op_bv);
    return;
  }
  else if((op_bvtype==IS_SIGNED || op_bvtype==IS_UNSIGNED) &&
          (bvtype==IS_SIGNED || bvtype==IS_UNSIGNED))
  {
    if(no_overflow)
      prop.l_set_to(bv_utils.overflow_negate(op_bv), false);

    if(no_overflow)
      bv=bv_utils.negate_no_overflow(op_bv);
    else
      bv=bv_utils.negate(op_bv);

    return;
  }

  conversion_failed(expr, bv);
}
Пример #24
0
bvt boolbvt::convert_extractbits(const extractbits_exprt &expr)
{
  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr);

  const irep_idt &type_id=expr.type().id();

  if(type_id!=ID_signedbv &&
     type_id!=ID_unsignedbv &&
     type_id!=ID_c_enum &&
     type_id!=ID_c_enum_tag &&
     type_id!=ID_bv)
    return conversion_failed(expr);

  if(expr.operands().size()!=3)
  {
    error().source_location=expr.find_source_location();
    error() << "extractbits takes three operands" << eom;
    throw 0;
  }

  mp_integer o1, o2;
  const bvt &bv0=convert_bv(expr.op0());

  // We only do constants for now.
  // Should implement a shift here.
  if(to_integer(expr.op1(), o1) ||
     to_integer(expr.op2(), o2))
    return conversion_failed(expr);

  if(o1<0 || o1>=bv0.size())
  {
    error().source_location=expr.find_source_location();
    error() << "extractbits: second operand out of range: "
            << expr.pretty() << eom;
  }

  if(o2<0 || o2>=bv0.size())
  {
    error().source_location=expr.find_source_location();
    error() << "extractbits: third operand out of range: "
            << expr.pretty() << eom;
    throw 0;
  }

  if(o2>o1)
    std::swap(o1, o2);

  // now o2<=o1

  if((o1-o2+1)!=width)
  {
    error().source_location=expr.find_source_location();
    error() << "extractbits: wrong width (expected " << (o1-o2+1)
            << " but got " << width << "): " << expr.pretty() << eom;
    throw 0;
  }

  std::size_t offset=integer2unsigned(o2);

  bvt bv;
  bv.resize(width);

  for(std::size_t i=0; i<width; i++)
    bv[i]=bv0[offset+i];

  return bv;
}
Пример #25
0
void boolbvt::convert_floatbv_op(const exprt &expr, bvt &bv)
{
  const exprt::operandst &operands=expr.operands();
  
  if(operands.size()!=3)
    throw "operator "+expr.id_string()+" takes three operands";

  const exprt &op0=expr.op0(); // first operand
  const exprt &op1=expr.op1(); // second operand
  const exprt &op2=expr.op2(); // rounding mode

  bvt bv0=convert_bv(op0);
  bvt bv1=convert_bv(op1);
  bvt bv2=convert_bv(op2);

  const typet &type=ns.follow(expr.type());

  if(op0.type()!=type || op1.type()!=type)
  {
    std::cerr << expr.pretty() << std::endl;
    throw "float op with mixed types";
  }

  float_utilst float_utils(prop);
  
  float_utils.set_rounding_mode(bv2);

  if(type.id()==ID_floatbv)
  {
    float_utils.spec=to_floatbv_type(expr.type());

    if(expr.id()==ID_floatbv_plus)
      bv=float_utils.add_sub(bv0, bv1, false);
    else if(expr.id()==ID_floatbv_minus)
      bv=float_utils.add_sub(bv0, bv1, true);
    else if(expr.id()==ID_floatbv_mult)
      bv=float_utils.mul(bv0, bv1);
    else if(expr.id()==ID_floatbv_div)
      bv=float_utils.div(bv0, bv1);
    else if(expr.id()==ID_floatbv_rem)
      bv=float_utils.rem(bv0, bv1);
    else
      assert(false);
  }
  else if(type.id()==ID_vector || type.id()==ID_complex)
  {
    const typet &subtype=ns.follow(type.subtype());
    
    if(subtype.id()==ID_floatbv)
    {
      float_utils.spec=to_floatbv_type(subtype);

      std::size_t width=boolbv_width(type);
      std::size_t sub_width=boolbv_width(subtype);

      if(sub_width==0 || width%sub_width!=0)
        throw "convert_floatbv_op: unexpected vector operand width";

      std::size_t size=width/sub_width;
      bv.resize(width);

      for(std::size_t i=0; i<size; i++)
      {
        bvt tmp_bv0, tmp_bv1, tmp_bv;
        
        tmp_bv0.assign(bv0.begin()+i*sub_width, bv0.begin()+(i+1)*sub_width);
        tmp_bv1.assign(bv1.begin()+i*sub_width, bv1.begin()+(i+1)*sub_width);

        if(expr.id()==ID_floatbv_plus)
          tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, false);
        else if(expr.id()==ID_floatbv_minus)
          tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, true);
        else if(expr.id()==ID_floatbv_mult)
          tmp_bv=float_utils.mul(tmp_bv0, tmp_bv1);
        else if(expr.id()==ID_floatbv_div)
          tmp_bv=float_utils.div(tmp_bv0, tmp_bv1);
        else
          assert(false);

        assert(tmp_bv.size()==sub_width);
        assert(i*sub_width+sub_width-1<bv.size());
        std::copy(tmp_bv.begin(), tmp_bv.end(), bv.begin()+i*sub_width);
      }
    }
    else
      return conversion_failed(expr, bv);
  }
  else
    return conversion_failed(expr, bv);
}
Пример #26
0
void boolbvt::convert_bitwise(const exprt &expr, bvt &bv)
{
  unsigned width=boolbv_width(expr.type());
  
  if(width==0)
    return conversion_failed(expr, bv);

  if(expr.id()==ID_bitnot)
  {
    if(expr.operands().size()!=1)
      throw "bitnot takes one operand";

    const exprt &op0=expr.op0();
    
    const bvt &op_bv=convert_bv(op0);

    if(op_bv.size()!=width)
      throw "convert_bitwise: unexpected operand width";

    bv=bv_utils.inverted(op_bv);

    return;
  }
  else if(expr.id()==ID_bitand || expr.id()==ID_bitor ||
          expr.id()==ID_bitxor || 
          expr.id()==ID_bitnand || expr.id()==ID_bitnor ||
          expr.id()==ID_bitxnor)
  {
    bv.resize(width);
    
    forall_operands(it, expr)
    {
      const bvt &op=convert_bv(*it);

      if(op.size()!=width)
        throw "convert_bitwise: unexpected operand width";
        
      if(it==expr.operands().begin())
        bv=op;
      else
      {
        for(unsigned i=0; i<width; i++)
        {
          if(expr.id()==ID_bitand)
            bv[i]=prop.land(bv[i], op[i]);
          else if(expr.id()==ID_bitor)
            bv[i]=prop.lor(bv[i], op[i]);
          else if(expr.id()==ID_bitxor)
            bv[i]=prop.lxor(bv[i], op[i]);
          else if(expr.id()==ID_bitnand)
            bv[i]=prop.lnand(bv[i], op[i]);
          else if(expr.id()==ID_bitnor)
            bv[i]=prop.lnor(bv[i], op[i]);
          else if(expr.id()==ID_bitxnor)
            bv[i]=prop.lequal(bv[i], op[i]);
          else
            throw "unexpected operand";
        }
      }
    }    

    return;
  }
Пример #27
0
void boolbvt::convert_case(const exprt &expr, bvt &bv)
{
  const std::vector<exprt> &operands=expr.operands();

  unsigned width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr, bv);

  bv.resize(width);

  // make it free variables
  Forall_literals(it, bv)
    *it=prop.new_variable();

  if(operands.size()<3)
    throw "case takes at least three operands";

  if((operands.size()%2)!=1)
    throw "number of case operands must be odd";

  enum { FIRST, COMPARE, VALUE } what=FIRST;
  bvt compare_bv;
  literalt previous_compare=const_literal(false);
  literalt compare_literal=const_literal(false);

  forall_operands(it, expr)
  {
    bvt op=convert_bv(*it);

    switch(what)
    {
    case FIRST:
      compare_bv.swap(op);
      what=COMPARE;
      break;

    case COMPARE:
      if(compare_bv.size()!=op.size())
      {
        std::cerr << "compare operand: " << compare_bv.size()
                  << std::endl
                  << "operand: " << op.size() << std::endl
                  << it->pretty()
                  << std::endl;

        throw "size of compare operand does not match";
      }

      compare_literal=bv_utils.equal(compare_bv, op);
      compare_literal=prop.land(prop.lnot(previous_compare),
                           compare_literal);

      previous_compare=prop.lor(previous_compare, compare_literal);

      what=VALUE;
      break;

    case VALUE: 
      if(bv.size()!=op.size())
      {
        std::cerr << "result size: " << bv.size()
                  << std::endl
                  << "operand: " << op.size() << std::endl
                  << it->pretty()
                  << std::endl;

        throw "size of value operand does not match";
      }

      {
        literalt value_literal=bv_utils.equal(bv, op);

        prop.l_set_to_true(
          prop.limplies(compare_literal, value_literal));
      }

      what=COMPARE;
      break;

    default:
      assert(false);
    }
  }
Пример #28
0
bvt boolbvt::convert_shift(const binary_exprt &expr)
{
  const irep_idt &type_id=expr.type().id();

  if(type_id!=ID_unsignedbv &&
     type_id!=ID_signedbv &&
     type_id!=ID_floatbv &&
     type_id!=ID_pointer &&
     type_id!=ID_bv &&
     type_id!=ID_verilog_signedbv &&
     type_id!=ID_verilog_unsignedbv)
    return conversion_failed(expr);

  std::size_t width=boolbv_width(expr.type());

  if(width==0)
    return conversion_failed(expr);

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

  const bvt &op=convert_bv(expr.op0());

  if(op.size()!=width)
    throw "convert_shift: unexpected operand 0 width";

  bv_utilst::shiftt shift;

  if(expr.id()==ID_shl)
    shift=bv_utilst::shiftt::LEFT;
  else if(expr.id()==ID_ashr)
    shift=bv_utilst::shiftt::ARIGHT;
  else if(expr.id()==ID_lshr)
    shift=bv_utilst::shiftt::LRIGHT;
  else
    throw "unexpected shift operator";

  // we allow a constant as shift distance

  if(expr.op1().is_constant())
  {
    mp_integer i;
    if(to_integer(expr.op1(), i))
      throw "convert_shift: failed to convert constant";

    std::size_t distance;

    if(i<0 || i>std::numeric_limits<signed>::max())
      distance=0;
    else
      distance=integer2size_t(i);

    if(type_id==ID_verilog_signedbv ||
       type_id==ID_verilog_unsignedbv)
      distance*=2;

    return bv_utils.shift(op, shift, distance);
  }
  else
  {
    const bvt &distance=convert_bv(expr.op1());
    return bv_utils.shift(op, shift, distance);
  }
}