//===-- ExprBuilder.cpp ---------------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "klee/ExprBuilder.h" using namespace klee; ExprBuilder::ExprBuilder() { } ExprBuilder::~ExprBuilder() { } namespace { class DefaultExprBuilder : public ExprBuilder { virtual ref Constant(uint64_t Value, Expr::Width W) { return ConstantExpr::alloc(Value, W); } virtual ref NotOptimized(const ref &Index) { return NotOptimizedExpr::alloc(Index); } virtual ref Read(const UpdateList &Updates, const ref &Index) { return ReadExpr::alloc(Updates, Index); } virtual ref Select(const ref &Cond, const ref &LHS, const ref &RHS) { return SelectExpr::alloc(Cond, LHS, RHS); } virtual ref Concat(const ref &LHS, const ref &RHS) { return ConcatExpr::alloc(LHS, RHS); } virtual ref Extract(const ref &LHS, unsigned Offset, Expr::Width W) { return ExtractExpr::alloc(LHS, Offset, W); } virtual ref ZExt(const ref &LHS, Expr::Width W) { return ZExtExpr::alloc(LHS, W); } virtual ref SExt(const ref &LHS, Expr::Width W) { return SExtExpr::alloc(LHS, W); } virtual ref Add(const ref &LHS, const ref &RHS) { return AddExpr::alloc(LHS, RHS); } virtual ref Sub(const ref &LHS, const ref &RHS) { return SubExpr::alloc(LHS, RHS); } virtual ref Mul(const ref &LHS, const ref &RHS) { return MulExpr::alloc(LHS, RHS); } virtual ref UDiv(const ref &LHS, const ref &RHS) { return UDivExpr::alloc(LHS, RHS); } virtual ref SDiv(const ref &LHS, const ref &RHS) { return SDivExpr::alloc(LHS, RHS); } virtual ref URem(const ref &LHS, const ref &RHS) { return URemExpr::alloc(LHS, RHS); } virtual ref SRem(const ref &LHS, const ref &RHS) { return SRemExpr::alloc(LHS, RHS); } virtual ref And(const ref &LHS, const ref &RHS) { return AndExpr::alloc(LHS, RHS); } virtual ref Or(const ref &LHS, const ref &RHS) { return OrExpr::alloc(LHS, RHS); } virtual ref Xor(const ref &LHS, const ref &RHS) { return XorExpr::alloc(LHS, RHS); } virtual ref Shl(const ref &LHS, const ref &RHS) { return ShlExpr::alloc(LHS, RHS); } virtual ref LShr(const ref &LHS, const ref &RHS) { return LShrExpr::alloc(LHS, RHS); } virtual ref AShr(const ref &LHS, const ref &RHS) { return AShrExpr::alloc(LHS, RHS); } virtual ref Eq(const ref &LHS, const ref &RHS) { return EqExpr::alloc(LHS, RHS); } virtual ref Ne(const ref &LHS, const ref &RHS) { return NeExpr::alloc(LHS, RHS); } virtual ref Ult(const ref &LHS, const ref &RHS) { return UltExpr::alloc(LHS, RHS); } virtual ref Ule(const ref &LHS, const ref &RHS) { return UleExpr::alloc(LHS, RHS); } virtual ref Ugt(const ref &LHS, const ref &RHS) { return UgtExpr::alloc(LHS, RHS); } virtual ref Uge(const ref &LHS, const ref &RHS) { return UgeExpr::alloc(LHS, RHS); } virtual ref Slt(const ref &LHS, const ref &RHS) { return SltExpr::alloc(LHS, RHS); } virtual ref Sle(const ref &LHS, const ref &RHS) { return SleExpr::alloc(LHS, RHS); } virtual ref Sgt(const ref &LHS, const ref &RHS) { return SgtExpr::alloc(LHS, RHS); } virtual ref Sge(const ref &LHS, const ref &RHS) { return SgeExpr::alloc(LHS, RHS); } }; /// ChainedBuilder - Helper class for construct specialized expression /// builders, which implements (non-virtual) methods which forward to a base /// expression builder, for all expressions. class ChainedBuilder { protected: /// Builder - The builder that this specialized builder is contained /// within. Provided for convenience to clients. ExprBuilder *Builder; /// Base - The base builder class for constructing expressions. ExprBuilder *Base; public: ChainedBuilder(ExprBuilder *_Builder, ExprBuilder *_Base) : Builder(_Builder), Base(_Base) {} ~ChainedBuilder() { delete Base; } ref Constant(uint64_t Value, Expr::Width W) { return Base->Constant(Value, W); } ref NotOptimized(const ref &Index) { return Base->NotOptimized(Index); } ref Read(const UpdateList &Updates, const ref &Index) { return Base->Read(Updates, Index); } ref Select(const ref &Cond, const ref &LHS, const ref &RHS) { return Base->Select(Cond, LHS, RHS); } ref Concat(const ref &LHS, const ref &RHS) { return Base->Concat(LHS, RHS); } ref Extract(const ref &LHS, unsigned Offset, Expr::Width W) { return Base->Extract(LHS, Offset, W); } ref ZExt(const ref &LHS, Expr::Width W) { return Base->ZExt(LHS, W); } ref SExt(const ref &LHS, Expr::Width W) { return Base->SExt(LHS, W); } ref Add(const ref &LHS, const ref &RHS) { return Base->Add(LHS, RHS); } ref Sub(const ref &LHS, const ref &RHS) { return Base->Sub(LHS, RHS); } ref Mul(const ref &LHS, const ref &RHS) { return Base->Mul(LHS, RHS); } ref UDiv(const ref &LHS, const ref &RHS) { return Base->UDiv(LHS, RHS); } ref SDiv(const ref &LHS, const ref &RHS) { return Base->SDiv(LHS, RHS); } ref URem(const ref &LHS, const ref &RHS) { return Base->URem(LHS, RHS); } ref SRem(const ref &LHS, const ref &RHS) { return Base->SRem(LHS, RHS); } ref And(const ref &LHS, const ref &RHS) { return Base->And(LHS, RHS); } ref Or(const ref &LHS, const ref &RHS) { return Base->Or(LHS, RHS); } ref Xor(const ref &LHS, const ref &RHS) { return Base->Xor(LHS, RHS); } ref Shl(const ref &LHS, const ref &RHS) { return Base->Shl(LHS, RHS); } ref LShr(const ref &LHS, const ref &RHS) { return Base->LShr(LHS, RHS); } ref AShr(const ref &LHS, const ref &RHS) { return Base->AShr(LHS, RHS); } ref Eq(const ref &LHS, const ref &RHS) { return Base->Eq(LHS, RHS); } ref Ne(const ref &LHS, const ref &RHS) { return Base->Ne(LHS, RHS); } ref Ult(const ref &LHS, const ref &RHS) { return Base->Ult(LHS, RHS); } ref Ule(const ref &LHS, const ref &RHS) { return Base->Ule(LHS, RHS); } ref Ugt(const ref &LHS, const ref &RHS) { return Base->Ugt(LHS, RHS); } ref Uge(const ref &LHS, const ref &RHS) { return Base->Uge(LHS, RHS); } ref Slt(const ref &LHS, const ref &RHS) { return Base->Slt(LHS, RHS); } ref Sle(const ref &LHS, const ref &RHS) { return Base->Sle(LHS, RHS); } ref Sgt(const ref &LHS, const ref &RHS) { return Base->Sgt(LHS, RHS); } ref Sge(const ref &LHS, const ref &RHS) { return Base->Sge(LHS, RHS); } }; /// ConstantSpecializedExprBuilder - A base expression builder class which /// handles dispatching to a helper class, based on whether the arguments are /// constant or not. /// /// The SpecializedBuilder template argument should be a helper class which /// implements methods for all the expression construction functions. These /// methods can be specialized to take [Non]ConstantExpr when desired. template class ConstantSpecializedExprBuilder : public ExprBuilder { SpecializedBuilder Builder; public: ConstantSpecializedExprBuilder(ExprBuilder *Base) : Builder(this, Base) {} ~ConstantSpecializedExprBuilder() {} virtual ref Constant(uint64_t Value, Expr::Width W) { return Builder.Constant(Value, W); } virtual ref NotOptimized(const ref &Index) { return Builder.NotOptimized(Index); } virtual ref Read(const UpdateList &Updates, const ref &Index) { // Roll back through writes when possible. const UpdateNode *UN = Updates.head; while (UN && Eq(Index, UN->index)->isFalse()) UN = UN->next; if (ConstantExpr *CE = dyn_cast(Index)) return Builder.Read(UpdateList(Updates.root, UN), CE); return Builder.Read(UpdateList(Updates.root, UN), Index); } virtual ref Select(const ref &Cond, const ref &LHS, const ref &RHS) { if (ConstantExpr *CE = dyn_cast(Cond)) return CE->isTrue() ? LHS : RHS; return Builder.Select(cast(Cond), LHS, RHS); } virtual ref Concat(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Concat(RCE); return Builder.Concat(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Concat(cast(LHS), RCE); } return Builder.Concat(cast(LHS), cast(RHS)); } virtual ref Extract(const ref &LHS, unsigned Offset, Expr::Width W) { if (ConstantExpr *CE = dyn_cast(LHS)) return CE->Extract(Offset, W); return Builder.Extract(cast(LHS), Offset, W); } virtual ref ZExt(const ref &LHS, Expr::Width W) { if (ConstantExpr *CE = dyn_cast(LHS)) return CE->ZExt(W); return Builder.ZExt(cast(LHS), W); } virtual ref SExt(const ref &LHS, Expr::Width W) { if (ConstantExpr *CE = dyn_cast(LHS)) return CE->SExt(W); return Builder.SExt(cast(LHS), W); } virtual ref Add(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Add(RCE); return Builder.Add(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Add(cast(LHS), RCE); } return Builder.Add(cast(LHS), cast(RHS)); } virtual ref Sub(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Sub(RCE); return Builder.Sub(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Sub(cast(LHS), RCE); } return Builder.Sub(cast(LHS), cast(RHS)); } virtual ref Mul(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Mul(RCE); return Builder.Mul(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Mul(cast(LHS), RCE); } return Builder.Mul(cast(LHS), cast(RHS)); } virtual ref UDiv(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->UDiv(RCE); return Builder.UDiv(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.UDiv(cast(LHS), RCE); } return Builder.UDiv(cast(LHS), cast(RHS)); } virtual ref SDiv(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->SDiv(RCE); return Builder.SDiv(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.SDiv(cast(LHS), RCE); } return Builder.SDiv(cast(LHS), cast(RHS)); } virtual ref URem(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->URem(RCE); return Builder.URem(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.URem(cast(LHS), RCE); } return Builder.URem(cast(LHS), cast(RHS)); } virtual ref SRem(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->SRem(RCE); return Builder.SRem(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.SRem(cast(LHS), RCE); } return Builder.SRem(cast(LHS), cast(RHS)); } virtual ref And(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->And(RCE); return Builder.And(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.And(cast(LHS), RCE); } return Builder.And(cast(LHS), cast(RHS)); } virtual ref Or(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Or(RCE); return Builder.Or(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Or(cast(LHS), RCE); } return Builder.Or(cast(LHS), cast(RHS)); } virtual ref Xor(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Xor(RCE); return Builder.Xor(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Xor(cast(LHS), RCE); } return Builder.Xor(cast(LHS), cast(RHS)); } virtual ref Shl(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Shl(RCE); return Builder.Shl(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Shl(cast(LHS), RCE); } return Builder.Shl(cast(LHS), cast(RHS)); } virtual ref LShr(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->LShr(RCE); return Builder.LShr(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.LShr(cast(LHS), RCE); } return Builder.LShr(cast(LHS), cast(RHS)); } virtual ref AShr(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->AShr(RCE); return Builder.AShr(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.AShr(cast(LHS), RCE); } return Builder.AShr(cast(LHS), cast(RHS)); } virtual ref Eq(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Eq(RCE); return Builder.Eq(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Eq(cast(LHS), RCE); } return Builder.Eq(cast(LHS), cast(RHS)); } virtual ref Ne(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Ne(RCE); return Builder.Ne(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Ne(cast(LHS), RCE); } return Builder.Ne(cast(LHS), cast(RHS)); } virtual ref Ult(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Ult(RCE); return Builder.Ult(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Ult(cast(LHS), RCE); } return Builder.Ult(cast(LHS), cast(RHS)); } virtual ref Ule(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Ule(RCE); return Builder.Ule(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Ule(cast(LHS), RCE); } return Builder.Ule(cast(LHS), cast(RHS)); } virtual ref Ugt(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Ugt(RCE); return Builder.Ugt(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Ugt(cast(LHS), RCE); } return Builder.Ugt(cast(LHS), cast(RHS)); } virtual ref Uge(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Uge(RCE); return Builder.Uge(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Uge(cast(LHS), RCE); } return Builder.Uge(cast(LHS), cast(RHS)); } virtual ref Slt(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Slt(RCE); return Builder.Slt(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Slt(cast(LHS), RCE); } return Builder.Slt(cast(LHS), cast(RHS)); } virtual ref Sle(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Sle(RCE); return Builder.Sle(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Sle(cast(LHS), RCE); } return Builder.Sle(cast(LHS), cast(RHS)); } virtual ref Sgt(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Sgt(RCE); return Builder.Sgt(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Sgt(cast(LHS), RCE); } return Builder.Sgt(cast(LHS), cast(RHS)); } virtual ref Sge(const ref &LHS, const ref &RHS) { if (ConstantExpr *LCE = dyn_cast(LHS)) { if (ConstantExpr *RCE = dyn_cast(RHS)) return LCE->Sge(RCE); return Builder.Sge(LCE, cast(RHS)); } else if (ConstantExpr *RCE = dyn_cast(RHS)) { return Builder.Sge(cast(LHS), RCE); } return Builder.Sge(cast(LHS), cast(RHS)); } }; class ConstantFoldingBuilder : public ChainedBuilder { public: ConstantFoldingBuilder(ExprBuilder *Builder, ExprBuilder *Base) : ChainedBuilder(Builder, Base) {} ref Add(const ref &LHS, const ref &RHS) { // 0 + X ==> X if (LHS->isZero()) return RHS; switch (RHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(RHS); // C_0 + (C_1 + X) ==> (C_0 + C1) + X if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(LHS->Add(CE), BE->right); // C_0 + (X + C_1) ==> (C_0 + C1) + X if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(LHS->Add(CE), BE->left); break; } case Expr::Sub: { BinaryExpr *BE = cast(RHS); // C_0 + (C_1 - X) ==> (C_0 + C1) - X if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Sub(LHS->Add(CE), BE->right); // C_0 + (X - C_1) ==> (C_0 - C1) + X if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(LHS->Sub(CE), BE->left); break; } } return Base->Add(LHS, RHS); } ref Add(const ref &LHS, const ref &RHS) { return Add(RHS, LHS); } ref Add(const ref &LHS, const ref &RHS) { switch (LHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(LHS); // (X + Y) + Z ==> X + (Y + Z) return Builder->Add(BE->left, Builder->Add(BE->right, RHS)); } case Expr::Sub: { BinaryExpr *BE = cast(LHS); // (X - Y) + Z ==> X + (Z - Y) return Builder->Add(BE->left, Builder->Sub(RHS, BE->right)); } } switch (RHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(RHS); // X + (C_0 + Y) ==> C_0 + (X + Y) if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(CE, Builder->Add(LHS, BE->right)); // X + (Y + C_0) ==> C_0 + (X + Y) if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(CE, Builder->Add(LHS, BE->left)); break; } case Expr::Sub: { BinaryExpr *BE = cast(RHS); // X + (C_0 - Y) ==> C_0 + (X - Y) if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(CE, Builder->Sub(LHS, BE->right)); // X + (Y - C_0) ==> -C_0 + (X + Y) if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(CE->Neg(), Builder->Add(LHS, BE->left)); break; } } return Base->Add(LHS, RHS); } ref Sub(const ref &LHS, const ref &RHS) { switch (RHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(RHS); // C_0 - (C_1 + X) ==> (C_0 - C1) - X if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Sub(LHS->Sub(CE), BE->right); // C_0 - (X + C_1) ==> (C_0 + C1) + X if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Sub(LHS->Sub(CE), BE->left); break; } case Expr::Sub: { BinaryExpr *BE = cast(RHS); // C_0 - (C_1 - X) ==> (C_0 - C1) + X if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(LHS->Sub(CE), BE->right); // C_0 - (X - C_1) ==> (C_0 + C1) - X if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Sub(LHS->Add(CE), BE->left); break; } } return Base->Sub(LHS, RHS); } ref Sub(const ref &LHS, const ref &RHS) { // X - C_0 ==> -C_0 + X return Add(RHS->Neg(), LHS); } ref Sub(const ref &LHS, const ref &RHS) { switch (LHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(LHS); // (X + Y) - Z ==> X + (Y - Z) return Builder->Add(BE->left, Builder->Sub(BE->right, RHS)); } case Expr::Sub: { BinaryExpr *BE = cast(LHS); // (X - Y) - Z ==> X - (Y + Z) return Builder->Sub(BE->left, Builder->Add(BE->right, RHS)); } } switch (RHS->getKind()) { default: break; case Expr::Add: { BinaryExpr *BE = cast(RHS); // X - (C + Y) ==> -C + (X - Y) if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(CE->Neg(), Builder->Sub(LHS, BE->right)); // X - (Y + C) ==> -C + (X + Y) if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(CE->Neg(), Builder->Sub(LHS, BE->left)); break; } case Expr::Sub: { BinaryExpr *BE = cast(RHS); // X - (C - Y) ==> -C + (X + Y) if (ConstantExpr *CE = dyn_cast(BE->left)) return Builder->Add(CE->Neg(), Builder->Add(LHS, BE->right)); // X - (Y - C) ==> C + (X - Y) if (ConstantExpr *CE = dyn_cast(BE->right)) return Builder->Add(CE, Builder->Sub(LHS, BE->left)); break; } } return Base->Sub(LHS, RHS); } ref Mul(const ref &LHS, const ref &RHS) { if (LHS->isZero()) return LHS; if (LHS->isOne()) return RHS; // FIXME: Unbalance nested muls, fold constants through // {sub,add}-with-constant, etc. return Base->Mul(LHS, RHS); } ref Mul(const ref &LHS, const ref &RHS) { return Mul(RHS, LHS); } ref Mul(const ref &LHS, const ref &RHS) { return Base->Mul(LHS, RHS); } ref And(const ref &LHS, const ref &RHS) { if (LHS->isZero()) return LHS; if (LHS->isAllOnes()) return RHS; // FIXME: Unbalance nested ands, fold constants through // {and,or}-with-constant, etc. return Base->And(LHS, RHS); } ref And(const ref &LHS, const ref &RHS) { return And(RHS, LHS); } ref And(const ref &LHS, const ref &RHS) { return Base->And(LHS, RHS); } ref Or(const ref &LHS, const ref &RHS) { if (LHS->isZero()) return RHS; if (LHS->isAllOnes()) return LHS; // FIXME: Unbalance nested ors, fold constants through // {and,or}-with-constant, etc. return Base->Or(LHS, RHS); } ref Or(const ref &LHS, const ref &RHS) { return Or(RHS, LHS); } ref Or(const ref &LHS, const ref &RHS) { return Base->Or(LHS, RHS); } ref Xor(const ref &LHS, const ref &RHS) { if (LHS->isZero()) return RHS; // FIXME: Unbalance nested ors, fold constants through // {and,or}-with-constant, etc. return Base->Xor(LHS, RHS); } ref Xor(const ref &LHS, const ref &RHS) { return Xor(RHS, LHS); } ref Xor(const ref &LHS, const ref &RHS) { return Base->Xor(LHS, RHS); } ref Eq(const ref &LHS, const ref &RHS) { Expr::Width Width = LHS->getWidth(); if (Width == Expr::Bool) { // true == X ==> X if (LHS->isTrue()) return RHS; // false == ... (not) // Eliminate double negation. if (const EqExpr *EE = dyn_cast(RHS)) { if (EE->left->getWidth() == Expr::Bool) { // false == (false == X) ==> X if (EE->left->isFalse()) return EE->right; // false == (X == false) ==> X if (EE->right->isFalse()) return EE->left; } } } return Base->Eq(LHS, RHS); } ref Eq(const ref &LHS, const ref &RHS) { return Eq(RHS, LHS); } ref Eq(const ref &LHS, const ref &RHS) { return Base->Eq(LHS, RHS); } }; typedef ConstantSpecializedExprBuilder ConstantFoldingExprBuilder; class SimplifyingBuilder : public ChainedBuilder { public: SimplifyingBuilder(ExprBuilder *Builder, ExprBuilder *Base) : ChainedBuilder(Builder, Base) {} ref Eq(const ref &LHS, const ref &RHS) { Expr::Width Width = LHS->getWidth(); if (Width == Expr::Bool) { // true == X ==> X if (LHS->isTrue()) return RHS; // false == X (not) // Transform !(a or b) ==> !a and !b. if (const OrExpr *OE = dyn_cast(RHS)) return Builder->And(Builder->Not(OE->left), Builder->Not(OE->right)); } return Base->Eq(LHS, RHS); } ref Eq(const ref &LHS, const ref &RHS) { return Eq(RHS, LHS); } ref Eq(const ref &LHS, const ref &RHS) { // X == X ==> true if (LHS == RHS) return Builder->True(); return Base->Eq(LHS, RHS); } ref Ne(const ref &LHS, const ref &RHS) { // X != Y ==> !(X == Y) return Builder->Not(Builder->Eq(LHS, RHS)); } ref Ugt(const ref &LHS, const ref &RHS) { // X u> Y ==> Y u< X return Builder->Ult(RHS, LHS); } ref Uge(const ref &LHS, const ref &RHS) { // X u>= Y ==> Y u<= X return Builder->Ule(RHS, LHS); } ref Sgt(const ref &LHS, const ref &RHS) { // X s> Y ==> Y s< X return Builder->Slt(RHS, LHS); } ref Sge(const ref &LHS, const ref &RHS) { // X s>= Y ==> Y s<= X return Builder->Sle(RHS, LHS); } }; typedef ConstantSpecializedExprBuilder SimplifyingExprBuilder; } ExprBuilder *klee::createDefaultExprBuilder() { return new DefaultExprBuilder(); } ExprBuilder *klee::createConstantFoldingExprBuilder(ExprBuilder *Base) { return new ConstantFoldingExprBuilder(Base); } ExprBuilder *klee::createSimplifyingExprBuilder(ExprBuilder *Base) { return new SimplifyingExprBuilder(Base); }