void TritonToZ3Ast::operator()(triton::ast::SxNode& e) { Z3Result ext = this->eval(*e.getChilds()[0]); Z3Result value = this->eval(*e.getChilds()[1]); triton::uint32 extv = static_cast<triton::uint32>(ext.getUintValue()); z3::expr newexpr = to_expr(this->result.getContext(), Z3_mk_sign_ext(this->result.getContext(), extv, value.getExpr())); this->result.setExpr(newexpr); }
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"); } }