ExprVisitor::Action IndexTransformationExprVisitor::visitConcat(const ConcatExpr &ce) { if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(0))) { if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) { if (width == Expr::InvalidWidth) width = ce.getWidth(); } } else if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(1))) { if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) { if (width == Expr::InvalidWidth) width = ce.getWidth(); } } return Action::doChildren(); }
//-------------------------- VALUE-BASED OPTIMIZATION------------------------// ExprVisitor::Action ArrayReadExprVisitor::visitConcat(const ConcatExpr &ce) { ReadExpr *base = ArrayExprHelper::hasOrderedReads(ce); if (base) { return inspectRead(ce.hash(), ce.getWidth(), *base); } return Action::doChildren(); }
/** 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); } }
/** 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); } }