Example #1
0
z3::expr Z3Builder::makeExpr(ref<Expr> e) {
    ++stats::queryConstructs;

    switch (e->getKind()) {
    case Expr::Constant: {
        ConstantExpr *CE = cast<ConstantExpr>(e);
        unsigned width = CE->getWidth();
        if (width == 1)
            return context_.bool_val(CE->isTrue());
        if (width <= 64)
            return context_.bv_val((__uint64)CE->getZExtValue(), width);

        // This is slower than concatenating 64-bit extractions, like STPBuilder
        // does, but the assumption is that it's quite infrequent.
        // TODO: Log these transformations.
        llvm::SmallString<32> const_repr;
        CE->getAPValue().toStringUnsigned(const_repr, 10);
        return context_.bv_val(const_repr.c_str(), width);
    }

    case Expr::NotOptimized: {
        NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
        return getOrMakeExpr(noe->src);
    }

    case Expr::Read: {
        return makeReadExpr(cast<ReadExpr>(e));
    }

    case Expr::Select: {
        SelectExpr *se = cast<SelectExpr>(e);
        // XXX: A bug in Clang prevents us from using z3::ite
        return z3::to_expr(context_, Z3_mk_ite(context_,
                getOrMakeExpr(se->cond),
                getOrMakeExpr(se->trueExpr),
                getOrMakeExpr(se->falseExpr)));
    }

    case Expr::Concat: {
        ConcatExpr *ce = cast<ConcatExpr>(e);

        unsigned numKids = ce->getNumKids();
        z3::expr res = getOrMakeExpr(ce->getKid(numKids-1));
        for (int i = numKids - 2; i >= 0; --i) {
            res = z3::to_expr(context_,
                    Z3_mk_concat(context_, getOrMakeExpr(ce->getKid(i)), res));
        }
        return res;
    }

    case Expr::Extract: {
        ExtractExpr *ee = cast<ExtractExpr>(e);

        z3::expr src = getOrMakeExpr(ee->expr);
        if (ee->getWidth() == 1) {
            return z3::to_expr(context_, Z3_mk_extract(context_,
                    ee->offset, ee->offset, src)) == context_.bv_val(1, 1);
        } else {
            return z3::to_expr(context_, Z3_mk_extract(context_,
                    ee->offset + ee->getWidth() - 1, ee->offset, src));
        }
    }

    // Casting

    case Expr::ZExt: {
        CastExpr *ce = cast<CastExpr>(e);

        z3::expr src = getOrMakeExpr(ce->src);
        if (src.is_bool()) {
            // XXX: A bug in Clang prevents us from using z3::ite
            return z3::to_expr(context_, Z3_mk_ite(context_,
                    src,
                    context_.bv_val(1, ce->getWidth()),
                    context_.bv_val(0, ce->getWidth())));
        } else {
            return z3::to_expr(context_, Z3_mk_zero_ext(context_,
                    ce->getWidth() - src.get_sort().bv_size(), src));
        }
    }

    case Expr::SExt: {
        CastExpr *ce = cast<CastExpr>(e);

        z3::expr src = getOrMakeExpr(ce->src);
        if (src.is_bool()) {
            return z3::to_expr(context_, Z3_mk_ite(context_,
                    src,
                    context_.bv_val(1, ce->getWidth()),
                    context_.bv_val(0, ce->getWidth())));
        } else {
            return z3::to_expr(context_, Z3_mk_sign_ext(context_,
                    ce->getWidth() - src.get_sort().bv_size(), src));
        }
    }

    // Arithmetic

    case Expr::Add: {
        AddExpr *ae = cast<AddExpr>(e);
        return getOrMakeExpr(ae->left) + getOrMakeExpr(ae->right);
    }

    case Expr::Sub: {
        SubExpr *se = cast<SubExpr>(e);

        // STP here takes an extra width parameter, wondering why...
        return getOrMakeExpr(se->left) - getOrMakeExpr(se->right);
    }

    case Expr::Mul: {
        MulExpr *me = cast<MulExpr>(e);

        // Again, we skip some optimizations from STPBuilder; just let the solver
        // do its own set of simplifications.
        return getOrMakeExpr(me->left) * getOrMakeExpr(me->right);
    }

    case Expr::UDiv: {
        UDivExpr *de = cast<UDivExpr>(e);
        return z3::udiv(getOrMakeExpr(de->left), getOrMakeExpr(de->right));
    }

    case Expr::SDiv: {
        SDivExpr *de = cast<SDivExpr>(e);
        return getOrMakeExpr(de->left) / getOrMakeExpr(de->right);
    }

    case Expr::URem: {
        URemExpr *de = cast<URemExpr>(e);
        return z3::to_expr(context_, Z3_mk_bvurem(context_,
                getOrMakeExpr(de->left),
                getOrMakeExpr(de->right)));
    }

    case Expr::SRem: {
        SRemExpr *de = cast<SRemExpr>(e);

        // Assuming the sign follows dividend (otherwise we should have used
        // the Z3_mk_bvsmod() call)
        return z3::to_expr(context_, Z3_mk_bvsrem(context_,
                getOrMakeExpr(de->left),
                getOrMakeExpr(de->right)));
    }

    // Bitwise

    case Expr::Not: {
        NotExpr *ne = cast<NotExpr>(e);

        z3::expr expr = getOrMakeExpr(ne->expr);
        if (expr.is_bool()) {
            return !expr;
        } else {
            return ~expr;
        }
    }

    case Expr::And: {
        AndExpr *ae = cast<AndExpr>(e);

        z3::expr left = getOrMakeExpr(ae->left);
        z3::expr right = getOrMakeExpr(ae->right);

        if (left.is_bool()) {
            return left && right;
        } else {
            return left & right;
        }
    }

    case Expr::Or: {
        OrExpr *oe = cast<OrExpr>(e);

        z3::expr left = getOrMakeExpr(oe->left);
        z3::expr right = getOrMakeExpr(oe->right);

        if (left.is_bool()) {
            return left || right;
        } else {
            return left | right;
        }
    }

    case Expr::Xor: {
        XorExpr *xe = cast<XorExpr>(e);

        z3::expr left = getOrMakeExpr(xe->left);
        z3::expr right = getOrMakeExpr(xe->right);

        if (left.is_bool()) {
            return z3::to_expr(context_, Z3_mk_xor(context_, left, right));
        } else {
            return left ^ right;
        }
    }

    case Expr::Shl: {
        ShlExpr *se = cast<ShlExpr>(e);
        return z3::to_expr(context_, Z3_mk_bvshl(context_,
                getOrMakeExpr(se->left),
                getOrMakeExpr(se->right)));
    }

    case Expr::LShr: {
        LShrExpr *lse = cast<LShrExpr>(e);
        return z3::to_expr(context_, Z3_mk_bvlshr(context_,
                getOrMakeExpr(lse->left),
                getOrMakeExpr(lse->right)));
    }

    case Expr::AShr: {
        AShrExpr *ase = cast<AShrExpr>(e);
        return z3::to_expr(context_, Z3_mk_bvashr(context_,
                getOrMakeExpr(ase->left),
                getOrMakeExpr(ase->right)));
    }

    // Comparison

    case Expr::Eq: {
        EqExpr *ee = cast<EqExpr>(e);
        return getOrMakeExpr(ee->left) == getOrMakeExpr(ee->right);
    }

    case Expr::Ult: {
        UltExpr *ue = cast<UltExpr>(e);
        return z3::ult(getOrMakeExpr(ue->left), getOrMakeExpr(ue->right));
    }

    case Expr::Ule: {
        UleExpr *ue = cast<UleExpr>(e);
        return z3::ule(getOrMakeExpr(ue->left), getOrMakeExpr(ue->right));
    }

    case Expr::Slt: {
        SltExpr *se = cast<SltExpr>(e);
        return getOrMakeExpr(se->left) < getOrMakeExpr(se->right);
    }

    case Expr::Sle: {
        SleExpr *se = cast<SleExpr>(e);
        return getOrMakeExpr(se->left) <= getOrMakeExpr(se->right);
    }

    // unused due to canonicalization
#if 0
    case Expr::Ne:
    case Expr::Ugt:
    case Expr::Uge:
    case Expr::Sgt:
    case Expr::Sge:
#endif

    default:
        assert(0 && "unhandled Expr type");
    }
}
Example #2
0
/** if *et_out==etBV then result is a bitvector,
    otherwise it is a bool */
ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out, STPExprType *et_out) {
  int width;
  if (!width_out) width_out = &width;

  ++stats::queryConstructs;

  switch (e->getKind()) {
  case Expr::Constant: {
    ConstantExpr *CE = cast<ConstantExpr>(e);
    *width_out = CE->getWidth();

    // Coerce to bool if necessary.
    if (*width_out == 1 && (*et_out == etBOOL || *et_out == etDontCare)) {
      *et_out = etBOOL;
      return CE->isTrue() ? getTrue() : getFalse();
    }

    *et_out = etBV;

    // Fast path.
    if (*width_out <= 32)
      return bvConst32(*width_out, CE->getZExtValue(32));
    if (*width_out <= 64)
      return bvConst64(*width_out, CE->getZExtValue());

    ref<ConstantExpr> Tmp = CE;
    ExprHandle Res = bvConst64(64, Tmp->Extract(0, 64)->getZExtValue());
    while (Tmp->getWidth() > 64) {
      Tmp = Tmp->Extract(64, Tmp->getWidth()-64);
      unsigned Width = std::min(64U, Tmp->getWidth());
      Res = vc_bvConcatExpr(vc, bvConst64(Width,
                                        Tmp->Extract(0, Width)->getZExtValue()),
                            Res);
    }
    return Res;
  }
    
  // Special
  case Expr::NotOptimized: {
    NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
    return construct(noe->src, width_out, et_out);
  }

  case Expr::Read: {
    ReadExpr *re = cast<ReadExpr>(e);
    *width_out = 8;
    *et_out = etBV;
    return vc_readExpr(vc,
                       getArrayForUpdate(re->updates.root, re->updates.head),
                       construct(re->index, 0, etBV));
  }
    
  case Expr::Select: {
    SelectExpr *se = cast<SelectExpr>(e);
    ExprHandle cond = construct(se->cond, 0, etBOOL);
    ExprHandle tExpr = construct(se->trueExpr, width_out, etBV);
    ExprHandle fExpr = construct(se->falseExpr, width_out, etBV);
    *et_out = etBV;
    return vc_iteExpr(vc, cond, tExpr, fExpr);
  }

  case Expr::Concat: {
    ConcatExpr *ce = cast<ConcatExpr>(e);
    unsigned numKids = ce->getNumKids();
    ExprHandle res = construct(ce->getKid(numKids-1), 0, etBV);
    for (int i=numKids-2; i>=0; i--) {
      res = vc_bvConcatExpr(vc, construct(ce->getKid(i), 0, etBV), res);
    }
    *width_out = ce->getWidth();
    *et_out = etBV;
    return res;
  }

  case Expr::Extract: {
    ExtractExpr *ee = cast<ExtractExpr>(e);
    ExprHandle src = construct(ee->expr, width_out, etBV);    
    *width_out = ee->getWidth();
    *et_out = etBV;
    return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
  }

    // Casting

  case Expr::ZExt: {
    int srcWidth;
    CastExpr *ce = cast<CastExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle src = construct(ce->src, &srcWidth, &src_rt);
    *width_out = ce->getWidth();
    *et_out = etBV;
    if (src_rt==etBOOL) {
      return vc_iteExpr(vc, src, bvOne(*width_out), bvZero(*width_out));
    } else {
      return vc_bvConcatExpr(vc, bvZero(*width_out-srcWidth), src);
    }
  }

  case Expr::SExt: {
    int srcWidth;
    CastExpr *ce = cast<CastExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle src = construct(ce->src, &srcWidth, &src_rt);
    *width_out = ce->getWidth();
    *et_out = etBV;
    if (src_rt==etBOOL) {
      return vc_iteExpr(vc, src, bvMinusOne(*width_out), bvZero(*width_out));
    } else {
      return vc_bvSignExtend(vc, src, *width_out);
    }
  }

    // Arithmetic

  case Expr::Add: {
    AddExpr *ae = cast<AddExpr>(e);
    ExprHandle left = construct(ae->left, width_out, etBV);
    ExprHandle right = construct(ae->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized add");
    *et_out = etBV;
    return vc_bvPlusExpr(vc, *width_out, left, right);
  }

  case Expr::Sub: {
    SubExpr *se = cast<SubExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sub");
    *et_out = etBV;
    return vc_bvMinusExpr(vc, *width_out, left, right);
  } 

  case Expr::Mul: {
    MulExpr *me = cast<MulExpr>(e);
    ExprHandle right = construct(me->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized mul");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(me->left))
      if (CE->getWidth() <= 64)
        return constructMulByConstant(right, *width_out, 
                                      CE->getZExtValue());

    ExprHandle left = construct(me->left, width_out, etBV);
    return vc_bvMultExpr(vc, *width_out, left, right);
  }

  case Expr::UDiv: {
    UDivExpr *de = cast<UDivExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized udiv");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
      if (CE->getWidth() <= 64) {
        uint64_t divisor = CE->getZExtValue();
      
        if (bits64::isPowerOfTwo(divisor)) {
          return bvRightShift(left,
                              bits64::indexOfSingleBit(divisor),
                              getShiftBits(*width_out));
        } else if (optimizeDivides) {
          if (*width_out == 32) //only works for 32-bit division
            return constructUDivByConstant( left, *width_out, 
                                            (uint32_t) divisor);
        }
      }
    } 

    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_bvDivExpr(vc, *width_out, left, right);
  }

  case Expr::SDiv: {
    SDivExpr *de = cast<SDivExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sdiv");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right))
      if (optimizeDivides)
	if (*width_out == 32) //only works for 32-bit division
	  return constructSDivByConstant( left, *width_out, 
                                          CE->getZExtValue(32));

    // XXX need to test for proper handling of sign, not sure I
    // trust STP
    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_sbvDivExpr(vc, *width_out, left, right);
  }

  case Expr::URem: {
    URemExpr *de = cast<URemExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized urem");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
      if (CE->getWidth() <= 64) {
        uint64_t divisor = CE->getZExtValue();

        if (bits64::isPowerOfTwo(divisor)) {
          unsigned bits = bits64::indexOfSingleBit(divisor);

          // special case for modding by 1 or else we bvExtract -1:0
          if (bits == 0) {
            return bvZero(*width_out);
          } else {
            return vc_bvConcatExpr(vc,
                                   bvZero(*width_out - bits),
                                   bvExtract(left, bits - 1, 0));
          }
        }

        // Use fast division to compute modulo without explicit division for
        // constant divisor.

        if (optimizeDivides) {
          if (*width_out == 32) { //only works for 32-bit division
            ExprHandle quotient = constructUDivByConstant( left, *width_out, (uint32_t)divisor );
            ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
            ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
            return rem;
          }
        }
      }
    }
    
    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_bvModExpr(vc, *width_out, left, right);
  }

  case Expr::SRem: {
    SRemExpr *de = cast<SRemExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    ExprHandle right = construct(de->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized srem");
    *et_out = etBV;

#if 0 //not faster per first benchmark
    if (optimizeDivides) {
      if (ConstantExpr *cre = de->right->asConstant()) {
	uint64_t divisor = cre->asUInt64;

	//use fast division to compute modulo without explicit division for constant divisor
      	if( *width_out == 32 ) { //only works for 32-bit division
	  ExprHandle quotient = constructSDivByConstant( left, *width_out, divisor );
	  ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
	  ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
	  return rem;
	}
      }
    }
#endif

    // XXX implement my fast path and test for proper handling of sign
    return vc_sbvModExpr(vc, *width_out, left, right);
  }

    // Bitwise

  case Expr::Not: {
    NotExpr *ne = cast<NotExpr>(e);
    ExprHandle expr = construct(ne->expr, width_out, et_out);
    if (*et_out == etBOOL) {
      return vc_notExpr(vc, expr);
    } else {
      return vc_bvNotExpr(vc, expr);
    }
  }    

  case Expr::And: {
    AndExpr *ae = cast<AndExpr>(e);
    ExprHandle left = construct(ae->left, width_out, et_out);
    ExprHandle right = construct(ae->right, width_out, *et_out);
    if (*et_out == etBOOL) {
      return vc_andExpr(vc, left, right);
    } else {
      return vc_bvAndExpr(vc, left, right);
    }
  }

  case Expr::Or: {
    OrExpr *oe = cast<OrExpr>(e);
    ExprHandle left = construct(oe->left, width_out, et_out);
    ExprHandle right = construct(oe->right, width_out, *et_out);
    if (*et_out == etBOOL) {
      return vc_orExpr(vc, left, right);
    } else {
      return vc_bvOrExpr(vc, left, right);
    }
  }

  case Expr::Xor: {
    XorExpr *xe = cast<XorExpr>(e);
    ExprHandle left = construct(xe->left, width_out, et_out);
    ExprHandle right = construct(xe->right, width_out, *et_out);
    
    if (*et_out == etBOOL) {
      // XXX check for most efficient?
      return vc_iteExpr(vc, left, 
                        ExprHandle(vc_notExpr(vc, right)), right);
    } else {
      return vc_bvXorExpr(vc, left, right);
    }
  }

  case Expr::Shl: {
    ShlExpr *se = cast<ShlExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized shl");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(se->right)) {
      return bvLeftShift(left, (unsigned) CE->getLimitedValue(), 
                         getShiftBits(*width_out));
    } else {
      int shiftWidth;
      ExprHandle amount = construct(se->right, &shiftWidth, etBV);
      return bvVarLeftShift( left, amount, *width_out );
    }
  }

  case Expr::LShr: {
    LShrExpr *lse = cast<LShrExpr>(e);
    ExprHandle left = construct(lse->left, width_out, etBV);
    unsigned shiftBits = getShiftBits(*width_out);
    assert(*width_out!=1 && "uncanonicalized lshr");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(lse->right)) {
      return bvRightShift(left, (unsigned) CE->getLimitedValue(), 
                          shiftBits);
    } else {
      int shiftWidth;
      ExprHandle amount = construct(lse->right, &shiftWidth, etBV);
      return bvVarRightShift( left, amount, *width_out );
    }
  }

  case Expr::AShr: {
    AShrExpr *ase = cast<AShrExpr>(e);
    ExprHandle left = construct(ase->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ashr");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ase->right)) {
      unsigned shift = (unsigned) CE->getLimitedValue();
      ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
      return constructAShrByConstant(left, shift, signedBool, 
                                     getShiftBits(*width_out));
    } else {
      int shiftWidth;
      ExprHandle amount = construct(ase->right, &shiftWidth, etBV);
      return bvVarArithRightShift( left, amount, *width_out );
    }
  }

    // Comparison

  case Expr::Eq: {
    EqExpr *ee = cast<EqExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle left = construct(ee->left, width_out, &src_rt);
    ExprHandle right = construct(ee->right, width_out, src_rt);
    *et_out = etBOOL;
    *width_out = 1;
    if (src_rt == etBOOL) {
      if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ee->left)) {
        if (CE->isTrue())
          return right;
        return vc_notExpr(vc, right);
      } else {
        return vc_iffExpr(vc, left, right);
      }
    } else {
      return vc_eqExpr(vc, left, right);
    }
  }

  case Expr::Ult: {
    UltExpr *ue = cast<UltExpr>(e);
    ExprHandle left = construct(ue->left, width_out, etBV);
    ExprHandle right = construct(ue->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ult");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_bvLtExpr(vc, left, right);
  }

  case Expr::Ule: {
    UleExpr *ue = cast<UleExpr>(e);
    ExprHandle left = construct(ue->left, width_out, etBV);
    ExprHandle right = construct(ue->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ule");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_bvLeExpr(vc, left, right);
  }

  case Expr::Slt: {
    SltExpr *se = cast<SltExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized slt");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_sbvLtExpr(vc, left, right);
  }

  case Expr::Sle: {
    SleExpr *se = cast<SleExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sle");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_sbvLeExpr(vc, left, right);
  }

    // unused due to canonicalization
#if 0
  case Expr::Ne:
  case Expr::Ugt:
  case Expr::Uge:
  case Expr::Sgt:
  case Expr::Sge:
#endif

  case Expr::FPToSI:
  case Expr::FPToUI: {
    if (UseFPToIAbstraction) {
      std::ostringstream ss;
      ss << "FPtoI" << fpCount++;
      *width_out = e->getWidth();
      *et_out = etBV;
      return buildVar(ss.str().c_str(), e->getWidth());
    } else {
      F2IConvertExpr *ce = cast<F2IConvertExpr>(e);
      ref<Expr> res = floatUtils(ce->src,
          ce->roundNearest()
            ? ieee_floatt::ROUND_TO_EVEN
            : ieee_floatt::ROUND_TO_ZERO).to_integer(ce->src, ce->getWidth(),
                                                  e->getKind() == Expr::FPToSI);
      return constructActual(res, width_out, et_out);
    }
  }

  case Expr::UIToFP: {
    UIToFPExpr *ue = cast<UIToFPExpr>(e);
    ref<Expr> res = floatUtils(e).from_unsigned_integer(ue->src);
    return constructActual(res, width_out, et_out);
  }

  case Expr::SIToFP: {
    SIToFPExpr *se = cast<SIToFPExpr>(e);
    ref<Expr> res = floatUtils(e).from_signed_integer(se->src);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FCmp: {
    FCmpExpr *ce = cast<FCmpExpr>(e);
    float_utilst &u = floatUtils(ce->left);
    ref<Expr> res;
    switch (ce->getPredicate()) {
    case FCmpExpr::OEQ:
      res = u.relation(ce->left, float_utilst::EQ, ce->right);
      break;
    case FCmpExpr::OGT:
      res = u.relation(ce->left, float_utilst::GT, ce->right);
      break;
    case FCmpExpr::OGE:
      res = u.relation(ce->left, float_utilst::GE, ce->right);
      break;
    case FCmpExpr::OLT:
      res = u.relation(ce->left, float_utilst::LT, ce->right);
      break;
    case FCmpExpr::OLE:
      res = u.relation(ce->left, float_utilst::LE, ce->right);
      break;
    case FCmpExpr::ONE:
      res = OrExpr::create(u.relation(ce->left, float_utilst::LT, ce->right),
                           u.relation(ce->left, float_utilst::GT, ce->right));
      break;
    case FCmpExpr::ORD:
      res = Expr::createIsZero(OrExpr::create(u.is_NaN(ce->left),
                                              u.is_NaN(ce->right)));
      break;
    case FCmpExpr::UNO:
      res = OrExpr::create(u.is_NaN(ce->left),
                           u.is_NaN(ce->right));
      break;
    case FCmpExpr::UEQ:
      res = Expr::createIsZero(
              OrExpr::create(u.relation(ce->left, float_utilst::LT, ce->right),
                            u.relation(ce->left, float_utilst::GT, ce->right)));
      break;
    case FCmpExpr::UGT:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::LE, ce->right));
      break;
    case FCmpExpr::UGE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::LT, ce->right));
      break;
    case FCmpExpr::ULT:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::GE, ce->right));
      break;
    case FCmpExpr::ULE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::GT, ce->right));
      break;
    case FCmpExpr::UNE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::EQ, ce->right));
      break;
    default:
      assert(0 && "fp cmp not implemented yet");
    }
    return constructActual(res, width_out, et_out);
  }

  case Expr::FPExt:
  case Expr::FPTrunc: {
    F2FConvertExpr *ce = cast<F2FConvertExpr>(e);
    float_utilst &fromu = floatUtils(ce->src), &tou = floatUtils(ce);
    ref<Expr> res = fromu.conversion(ce->src, tou.spec);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FAdd: {
    FAddExpr *ae = cast<FAddExpr>(e);
    ref<Expr> res = floatUtils(e).add(ae->left, ae->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FSub: {
    FSubExpr *se = cast<FSubExpr>(e);
    ref<Expr> res = floatUtils(e).sub(se->left, se->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FMul: {
    FMulExpr *me = cast<FMulExpr>(e);
    ref<Expr> res = floatUtils(e).mul(me->left, me->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FDiv: {
    FDivExpr *de = cast<FDivExpr>(e);
    ref<Expr> res = floatUtils(e).div(de->left, de->right);
    return constructActual(res, width_out, et_out);
  }

  default: 
    assert(0 && "unhandled Expr type");
    *et_out = etBOOL;
    return vc_trueExpr(vc);
  }
}
Example #3
0
/** if *width_out!=1 then result is a bitvector,
    otherwise it is a bool */
ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) {
    int width;
    if (!width_out) width_out = &width;

    ++stats::queryConstructs;

    switch (e->getKind()) {
    case Expr::Constant: {
        ConstantExpr *CE = cast<ConstantExpr>(e);
        *width_out = CE->getWidth();

        // Coerce to bool if necessary.
        if (*width_out == 1)
            return CE->isTrue() ? getTrue() : getFalse();

        // Fast path.
        if (*width_out <= 32)
            return bvConst32(*width_out, CE->getZExtValue(32));
        if (*width_out <= 64)
            return bvConst64(*width_out, CE->getZExtValue());

        ref<ConstantExpr> Tmp = CE;
        ExprHandle Res = bvConst64(64, Tmp->Extract(0, 64)->getZExtValue());
        while (Tmp->getWidth() > 64) {
            Tmp = Tmp->Extract(64, Tmp->getWidth()-64);
            unsigned Width = std::min(64U, Tmp->getWidth());
            Res = vc_bvConcatExpr(vc, bvConst64(Width,
                                                Tmp->Extract(0, Width)->getZExtValue()),
                                  Res);
        }
        return Res;
    }

    // Special
    case Expr::NotOptimized: {
        NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
        return construct(noe->src, width_out);
    }

    case Expr::Read: {
        ReadExpr *re = cast<ReadExpr>(e);
        assert(re && re->updates.root);
        *width_out = re->updates.root->getRange();
        return vc_readExpr(vc,
                           getArrayForUpdate(re->updates.root, re->updates.head),
                           construct(re->index, 0));
    }

    case Expr::Select: {
        SelectExpr *se = cast<SelectExpr>(e);
        ExprHandle cond = construct(se->cond, 0);
        ExprHandle tExpr = construct(se->trueExpr, width_out);
        ExprHandle fExpr = construct(se->falseExpr, width_out);
        return vc_iteExpr(vc, cond, tExpr, fExpr);
    }

    case Expr::Concat: {
        ConcatExpr *ce = cast<ConcatExpr>(e);
        unsigned numKids = ce->getNumKids();
        ExprHandle res = construct(ce->getKid(numKids-1), 0);
        for (int i=numKids-2; i>=0; i--) {
            res = vc_bvConcatExpr(vc, construct(ce->getKid(i), 0), res);
        }
        *width_out = ce->getWidth();
        return res;
    }

    case Expr::Extract: {
        ExtractExpr *ee = cast<ExtractExpr>(e);
        ExprHandle src = construct(ee->expr, width_out);
        *width_out = ee->getWidth();
        if (*width_out==1) {
            return bvBoolExtract(src, ee->offset);
        } else {
            return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
        }
    }

    // Casting

    case Expr::ZExt: {
        int srcWidth;
        CastExpr *ce = cast<CastExpr>(e);
        ExprHandle src = construct(ce->src, &srcWidth);
        *width_out = ce->getWidth();
        if (srcWidth==1) {
            return vc_iteExpr(vc, src, bvOne(*width_out), bvZero(*width_out));
        } else {
            return vc_bvConcatExpr(vc, bvZero(*width_out-srcWidth), src);
        }
    }

    case Expr::SExt: {
        int srcWidth;
        CastExpr *ce = cast<CastExpr>(e);
        ExprHandle src = construct(ce->src, &srcWidth);
        *width_out = ce->getWidth();
        if (srcWidth==1) {
            return vc_iteExpr(vc, src, bvMinusOne(*width_out), bvZero(*width_out));
        } else {
            return vc_bvSignExtend(vc, src, *width_out);
        }
    }

    // Arithmetic

    case Expr::Add: {
        AddExpr *ae = cast<AddExpr>(e);
        ExprHandle left = construct(ae->left, width_out);
        ExprHandle right = construct(ae->right, width_out);
        assert(*width_out!=1 && "uncanonicalized add");
        return vc_bvPlusExpr(vc, *width_out, left, right);
    }

    case Expr::Sub: {
        SubExpr *se = cast<SubExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized sub");
        return vc_bvMinusExpr(vc, *width_out, left, right);
    }

    case Expr::Mul: {
        MulExpr *me = cast<MulExpr>(e);
        ExprHandle right = construct(me->right, width_out);
        assert(*width_out!=1 && "uncanonicalized mul");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(me->left))
            if (CE->getWidth() <= 64)
                return constructMulByConstant(right, *width_out,
                                              CE->getZExtValue());

        ExprHandle left = construct(me->left, width_out);
        return vc_bvMultExpr(vc, *width_out, left, right);
    }

    case Expr::UDiv: {
        UDivExpr *de = cast<UDivExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized udiv");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
            if (CE->getWidth() <= 64) {
                uint64_t divisor = CE->getZExtValue();

                if (bits64::isPowerOfTwo(divisor)) {
                    return bvRightShift(left,
                                        bits64::indexOfSingleBit(divisor));
                } else if (optimizeDivides) {
                    if (*width_out == 32) //only works for 32-bit division
                        return constructUDivByConstant( left, *width_out,
                                                        (uint32_t) divisor);
                }
            }
        }

        ExprHandle right = construct(de->right, width_out);
        return vc_bvDivExpr(vc, *width_out, left, right);
    }

    case Expr::SDiv: {
        SDivExpr *de = cast<SDivExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized sdiv");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right))
            if (optimizeDivides)
                if (*width_out == 32) //only works for 32-bit division
                    return constructSDivByConstant( left, *width_out,
                                                    CE->getZExtValue(32));

        // XXX need to test for proper handling of sign, not sure I
        // trust STP
        ExprHandle right = construct(de->right, width_out);
        return vc_sbvDivExpr(vc, *width_out, left, right);
    }

    case Expr::URem: {
        URemExpr *de = cast<URemExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized urem");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
            if (CE->getWidth() <= 64) {
                uint64_t divisor = CE->getZExtValue();

                if (bits64::isPowerOfTwo(divisor)) {
                    unsigned bits = bits64::indexOfSingleBit(divisor);

                    // special case for modding by 1 or else we bvExtract -1:0
                    if (bits == 0) {
                        return bvZero(*width_out);
                    } else {
                        return vc_bvConcatExpr(vc,
                                               bvZero(*width_out - bits),
                                               bvExtract(left, bits - 1, 0));
                    }
                }

                // Use fast division to compute modulo without explicit division for
                // constant divisor.

                if (optimizeDivides) {
                    if (*width_out == 32) { //only works for 32-bit division
                        ExprHandle quotient = constructUDivByConstant( left, *width_out, (uint32_t)divisor );
                        ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
                        ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
                        return rem;
                    }
                }
            }
        }

        ExprHandle right = construct(de->right, width_out);
        return vc_bvModExpr(vc, *width_out, left, right);
    }

    case Expr::SRem: {
        SRemExpr *de = cast<SRemExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        ExprHandle right = construct(de->right, width_out);
        assert(*width_out!=1 && "uncanonicalized srem");

#if 0 //not faster per first benchmark
        if (optimizeDivides) {
            if (ConstantExpr *cre = de->right->asConstant()) {
                uint64_t divisor = cre->asUInt64;

                //use fast division to compute modulo without explicit division for constant divisor
                if( *width_out == 32 ) { //only works for 32-bit division
                    ExprHandle quotient = constructSDivByConstant( left, *width_out, divisor );
                    ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
                    ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
                    return rem;
                }
            }
        }
#endif

        // XXX implement my fast path and test for proper handling of sign
        return vc_sbvModExpr(vc, *width_out, left, right);
    }

    // Bitwise

    case Expr::Not: {
        NotExpr *ne = cast<NotExpr>(e);
        ExprHandle expr = construct(ne->expr, width_out);
        if (*width_out==1) {
            return vc_notExpr(vc, expr);
        } else {
            return vc_bvNotExpr(vc, expr);
        }
    }

    case Expr::And: {
        AndExpr *ae = cast<AndExpr>(e);
        ExprHandle left = construct(ae->left, width_out);
        ExprHandle right = construct(ae->right, width_out);
        if (*width_out==1) {
            return vc_andExpr(vc, left, right);
        } else {
            return vc_bvAndExpr(vc, left, right);
        }
    }

    case Expr::Or: {
        OrExpr *oe = cast<OrExpr>(e);
        ExprHandle left = construct(oe->left, width_out);
        ExprHandle right = construct(oe->right, width_out);
        if (*width_out==1) {
            return vc_orExpr(vc, left, right);
        } else {
            return vc_bvOrExpr(vc, left, right);
        }
    }

    case Expr::Xor: {
        XorExpr *xe = cast<XorExpr>(e);
        ExprHandle left = construct(xe->left, width_out);
        ExprHandle right = construct(xe->right, width_out);

        if (*width_out==1) {
            // XXX check for most efficient?
            return vc_iteExpr(vc, left,
                              ExprHandle(vc_notExpr(vc, right)), right);
        } else {
            return vc_bvXorExpr(vc, left, right);
        }
    }

    case Expr::Shl: {
        ShlExpr *se = cast<ShlExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        assert(*width_out!=1 && "uncanonicalized shl");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(se->right)) {
            return bvLeftShift(left, (unsigned) CE->getLimitedValue());
        } else {
            int shiftWidth;
            ExprHandle amount = construct(se->right, &shiftWidth);
            return bvVarLeftShift( left, amount);
        }
    }

    case Expr::LShr: {
        LShrExpr *lse = cast<LShrExpr>(e);
        ExprHandle left = construct(lse->left, width_out);
        assert(*width_out!=1 && "uncanonicalized lshr");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(lse->right)) {
            return bvRightShift(left, (unsigned) CE->getLimitedValue());
        } else {
            int shiftWidth;
            ExprHandle amount = construct(lse->right, &shiftWidth);
            return bvVarRightShift( left, amount);
        }
    }

    case Expr::AShr: {
        AShrExpr *ase = cast<AShrExpr>(e);
        ExprHandle left = construct(ase->left, width_out);
        assert(*width_out!=1 && "uncanonicalized ashr");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ase->right)) {
            unsigned shift = (unsigned) CE->getLimitedValue();
            ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
            return constructAShrByConstant(left, shift, signedBool);
        } else {
            int shiftWidth;
            ExprHandle amount = construct(ase->right, &shiftWidth);
            return bvVarArithRightShift( left, amount);
        }
    }

    // Comparison

    case Expr::Eq: {
        EqExpr *ee = cast<EqExpr>(e);
        ExprHandle left = construct(ee->left, width_out);
        ExprHandle right = construct(ee->right, width_out);
        if (*width_out==1) {
            if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ee->left)) {
                if (CE->isTrue())
                    return right;
                return vc_notExpr(vc, right);
            } else {
                return vc_iffExpr(vc, left, right);
            }
        } else {
            *width_out = 1;
            return vc_eqExpr(vc, left, right);
        }
    }

    case Expr::Ult: {
        UltExpr *ue = cast<UltExpr>(e);
        ExprHandle left = construct(ue->left, width_out);
        ExprHandle right = construct(ue->right, width_out);
        assert(*width_out!=1 && "uncanonicalized ult");
        *width_out = 1;
        return vc_bvLtExpr(vc, left, right);
    }

    case Expr::Ule: {
        UleExpr *ue = cast<UleExpr>(e);
        ExprHandle left = construct(ue->left, width_out);
        ExprHandle right = construct(ue->right, width_out);
        assert(*width_out!=1 && "uncanonicalized ule");
        *width_out = 1;
        return vc_bvLeExpr(vc, left, right);
    }

    case Expr::Slt: {
        SltExpr *se = cast<SltExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized slt");
        *width_out = 1;
        return vc_sbvLtExpr(vc, left, right);
    }

    case Expr::Sle: {
        SleExpr *se = cast<SleExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized sle");
        *width_out = 1;
        return vc_sbvLeExpr(vc, left, right);
    }

        // unused due to canonicalization
#if 0
    case Expr::Ne:
    case Expr::Ugt:
    case Expr::Uge:
    case Expr::Sgt:
    case Expr::Sge:
#endif

    default:
        assert(0 && "unhandled Expr type");
        return vc_trueExpr(vc);
    }
}
Example #4
0
uint64_t ExprFrame::SerializeExpr(const ref<Expr> e) {
  data::ExprNode *ser_expr_node = expr_data_->add_expr();
  ser_expr_node->set_id(s_.next_id_++);
  ser_expr_node->set_kind((data::ExprKind)e->getKind());

  switch (e->getKind()) {
  case Expr::Constant: {
    ConstantExpr *ce = cast<ConstantExpr>(e);

    assert(ce->getWidth() <= 64 && "FIXME");
    ser_expr_node->set_value(ce->getZExtValue());
    ser_expr_node->set_width(ce->getWidth());
    break;
  }

  case Expr::NotOptimized: {
    NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(noe->src));
    break;
  }

  case Expr::Read: {
    ReadExpr *re = cast<ReadExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(re->index));

    if (re->updates.head) {
      ExprSerializer::UpdateNodePosition un_pos = GetOrSerializeUpdateList(re->updates);
      ser_expr_node->set_update_list_id(un_pos.first);
      ser_expr_node->set_update_list_offset(un_pos.second);
    }
    ser_expr_node->set_array_id(GetOrSerializeArray(re->updates.root));
    break;
  }

  case Expr::Select: {
    SelectExpr *se = cast<SelectExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(se->cond));
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(se->trueExpr));
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(se->falseExpr));
    break;
  }

  case Expr::Concat: {
    ConcatExpr *ce = cast<ConcatExpr>(e);
    for (unsigned i = 0; i < ce->getNumKids(); ++i) {
      ser_expr_node->add_child_expr_id(GetOrSerializeExpr(ce->getKid(i)));
    }
    break;
  }

  case Expr::Extract: {
    ExtractExpr *ee = cast<ExtractExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(ee->expr));
    ser_expr_node->set_offset(ee->offset);
    ser_expr_node->set_width(ee->getWidth());
    break;
  }

    // Casting,
  case Expr::ZExt:
  case Expr::SExt: {
    CastExpr *ce = cast<CastExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(ce->src));
    ser_expr_node->set_width(ce->getWidth());
    break;
  }

    // All subsequent kinds are binary.

    // Arithmetic
  case Expr::Add:
  case Expr::Sub:
  case Expr::Mul:
  case Expr::UDiv:
  case Expr::SDiv:
  case Expr::URem:
  case Expr::SRem: {
    BinaryExpr *be = cast<BinaryExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->left));
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->right));
    break;
  }

    // Bit
  case Expr::Not: {
    NotExpr *ne = cast<NotExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(ne->expr));
    break;
  }

  case Expr::And:
  case Expr::Or:
  case Expr::Xor:
  case Expr::Shl:
  case Expr::LShr:
  case Expr::AShr: {
    BinaryExpr *be = cast<BinaryExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->left));
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->right));
    break;
  }

    // Compare
  case Expr::Eq:
  case Expr::Ne:  ///< Not used in canonical form
  case Expr::Ult:
  case Expr::Ule:
  case Expr::Ugt: ///< Not used in canonical form
  case Expr::Uge: ///< Not used in canonical form
  case Expr::Slt:
  case Expr::Sle:
  case Expr::Sgt: ///< Not used in canonical form
  case Expr::Sge: { ///< Not used in canonical form
    BinaryExpr *be = cast<BinaryExpr>(e);
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->left));
    ser_expr_node->add_child_expr_id(GetOrSerializeExpr(be->right));
    break;
  }

  default:
    assert(0 && "Unhandled Expr type");
  }

  return ser_expr_node->id();
}