//===-- Expr.h --------------------------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef KLEE_EXPR_H #define KLEE_EXPR_H #include "klee/ADT/Bits.h" #include "klee/ADT/Ref.h" #include "klee/Support/CompilerWarning.h" DISABLE_WARNING_PUSH DISABLE_WARNING_DEPRECATED_DECLARATIONS #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" DISABLE_WARNING_POP #include #include #include #include namespace llvm { class Type; class raw_ostream; } namespace klee { class Array; class ArrayCache; class ConstantExpr; class ObjectState; template class ref; extern llvm::cl::OptionCategory ExprCat; /// Class representing symbolic expressions. /** Expression canonicalization: we define certain rules for canonicalization rules for Exprs in order to simplify code that pattern matches Exprs (since the number of forms are reduced), to open up further chances for optimization, and to increase similarity for caching and other purposes. The general rules are:
  1. No Expr has all constant arguments.
  2. Booleans:
    1. \c Ne, \c Ugt, \c Uge, \c Sgt, \c Sge are not used
    2. The only acceptable operations with boolean arguments are \c Not \c And, \c Or, \c Xor, \c Eq, as well as \c SExt, \c ZExt, \c Select and \c NotOptimized.
    3. The only boolean operation which may involve a constant is boolean not (== false).
  3. Linear Formulas:
    1. For any subtree representing a linear formula, a constant term must be on the LHS of the root node of the subtree. In particular, in a BinaryExpr a constant must always be on the LHS. For example, subtraction by a constant c is written as add(-c, ?).
  4. Chains are unbalanced to the right
Steps required for adding an expr: -# Add case to printKind -# Add to ExprVisitor -# Add to IVC (implied value concretization) if possible Todo: Shouldn't bool \c Xor just be written as not equal? */ class Expr { public: static unsigned count; static const unsigned MAGIC_HASH_CONSTANT = 39; /// The type of an expression is simply its width, in bits. typedef unsigned Width; // NOTE: The prefix "Int" in no way implies the integer type of expression. // For example, Int64 can indicate i64, double or <2 * i32> in different cases. static const Width InvalidWidth = 0; static const Width Bool = 1; static const Width Int8 = 8; static const Width Int16 = 16; static const Width Int32 = 32; static const Width Int64 = 64; static const Width Fl80 = 80; static const Width Int128 = 128; static const Width Int256 = 256; static const Width Int512 = 512; static const Width MaxWidth = Int512; enum Kind { InvalidKind = -1, // Primitive Constant = 0, // Special /// Prevents optimization below the given expression. Used for /// testing: make equality constraints that KLEE will not use to /// optimize to concretes. NotOptimized, //// Skip old varexpr, just for deserialization, purge at some point Read=NotOptimized+2, Select, Concat, Extract, // Casting, ZExt, SExt, // Bit Not, // All subsequent kinds are binary. // Arithmetic Add, Sub, Mul, UDiv, SDiv, URem, SRem, // Bit And, Or, Xor, Shl, LShr, AShr, // Compare Eq, Ne, ///< Not used in canonical form Ult, Ule, Ugt, ///< Not used in canonical form Uge, ///< Not used in canonical form Slt, Sle, Sgt, ///< Not used in canonical form Sge, ///< Not used in canonical form LastKind=Sge, CastKindFirst=ZExt, CastKindLast=SExt, BinaryKindFirst=Add, BinaryKindLast=Sge, CmpKindFirst=Eq, CmpKindLast=Sge }; /// @brief Required by klee::ref-managed objects class ReferenceCounter _refCount; protected: unsigned hashValue; /// Compares `b` to `this` Expr and determines how they are ordered /// (ignoring their kid expressions - i.e. those returned by `getKid()`). /// /// Typically this requires comparing internal attributes of the Expr. /// /// Implementations can assume that `b` and `this` are of the same kind. /// /// This method effectively defines a partial order over Expr of the same /// kind (partial because kid Expr are not compared). /// /// This method should not be called directly. Instead `compare()` should /// be used. /// /// \param [in] b Expr to compare `this` to. /// /// \return One of the following values: /// /// * -1 if `this` is `<` `b` ignoring kid expressions. /// * 1 if `this` is `>` `b` ignoring kid expressions. /// * 0 if `this` and `b` are not ordered. /// /// `<` and `>` are binary relations that express the partial order. virtual int compareContents(const Expr &b) const = 0; public: Expr() { Expr::count++; } virtual ~Expr() { Expr::count--; } virtual Kind getKind() const = 0; virtual Width getWidth() const = 0; virtual unsigned getNumKids() const = 0; virtual ref getKid(unsigned i) const = 0; virtual void print(llvm::raw_ostream &os) const; /// dump - Print the expression to stderr. void dump() const; /// Returns the pre-computed hash of the current expression virtual unsigned hash() const { return hashValue; } /// (Re)computes the hash of the current expression. /// Returns the hash value. virtual unsigned computeHash(); /// Compares `b` to `this` Expr for structural equivalence. /// /// This method effectively defines a total order over all Expr. /// /// \param [in] b Expr to compare `this` to. /// /// \return One of the following values: /// /// * -1 iff `this` is `<` `b` /// * 0 iff `this` is structurally equivalent to `b` /// * 1 iff `this` is `>` `b` /// /// `<` and `>` are binary relations that express the total order. int compare(const Expr &b) const; // Given an array of new kids return a copy of the expression // but using those children. virtual ref rebuild(ref kids[/* getNumKids() */]) const = 0; /// isZero - Is this a constant zero. bool isZero() const; /// isTrue - Is this the true expression. bool isTrue() const; /// isFalse - Is this the false expression. bool isFalse() const; /* Static utility methods */ static void printKind(llvm::raw_ostream &os, Kind k); static void printWidth(llvm::raw_ostream &os, Expr::Width w); /// returns the smallest number of bytes in which the given width fits static inline unsigned getMinBytesForWidth(Width w) { return (w + 7) / 8; } /* Kind utilities */ /* Utility creation functions */ static ref createSExtToPointerWidth(ref e); static ref createZExtToPointerWidth(ref e); static ref createImplies(ref hyp, ref conc); static ref createIsZero(ref e); /// Create a little endian read of the given type at offset 0 of the /// given object. static ref createTempRead(const Array *array, Expr::Width w); static ref createPointer(uint64_t v); struct CreateArg; static ref createFromKind(Kind k, std::vector args); static bool isValidKidWidth(unsigned kid, Width w) { return true; } static bool needsResultType() { return false; } static bool classof(const Expr *) { return true; } private: typedef llvm::DenseSet > ExprEquivSet; int compare(const Expr &b, ExprEquivSet &equivs) const; }; struct Expr::CreateArg { ref expr; Width width; CreateArg(Width w = Bool) : expr(0), width(w) {} CreateArg(ref e) : expr(e), width(Expr::InvalidWidth) {} bool isExpr() { return !isWidth(); } bool isWidth() { return width != Expr::InvalidWidth; } }; // Comparison operators inline bool operator==(const Expr &lhs, const Expr &rhs) { return lhs.compare(rhs) == 0; } inline bool operator<(const Expr &lhs, const Expr &rhs) { return lhs.compare(rhs) < 0; } inline bool operator!=(const Expr &lhs, const Expr &rhs) { return !(lhs == rhs); } inline bool operator>(const Expr &lhs, const Expr &rhs) { return rhs < lhs; } inline bool operator<=(const Expr &lhs, const Expr &rhs) { return !(lhs > rhs); } inline bool operator>=(const Expr &lhs, const Expr &rhs) { return !(lhs < rhs); } // Printing operators inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Expr &e) { e.print(os); return os; } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Expr::Kind kind) { Expr::printKind(os, kind); return os; } inline std::stringstream &operator<<(std::stringstream &os, const Expr &e) { std::string str; llvm::raw_string_ostream TmpStr(str); e.print(TmpStr); os << TmpStr.str(); return os; } inline std::stringstream &operator<<(std::stringstream &os, const Expr::Kind kind) { std::string str; llvm::raw_string_ostream TmpStr(str); Expr::printKind(TmpStr, kind); os << TmpStr.str(); return os; } // Utility classes class NonConstantExpr : public Expr { public: static bool classof(const Expr *E) { return E->getKind() != Expr::Constant; } static bool classof(const NonConstantExpr *) { return true; } }; class BinaryExpr : public NonConstantExpr { public: ref left, right; public: unsigned getNumKids() const { return 2; } ref getKid(unsigned i) const { if(i == 0) return left; if(i == 1) return right; return 0; } protected: BinaryExpr(const ref &l, const ref &r) : left(l), right(r) {} public: static bool classof(const Expr *E) { Kind k = E->getKind(); return Expr::BinaryKindFirst <= k && k <= Expr::BinaryKindLast; } static bool classof(const BinaryExpr *) { return true; } }; class CmpExpr : public BinaryExpr { protected: CmpExpr(ref l, ref r) : BinaryExpr(l,r) {} public: Width getWidth() const { return Bool; } static bool classof(const Expr *E) { Kind k = E->getKind(); return Expr::CmpKindFirst <= k && k <= Expr::CmpKindLast; } static bool classof(const CmpExpr *) { return true; } }; // Special class NotOptimizedExpr : public NonConstantExpr { public: static const Kind kind = NotOptimized; static const unsigned numKids = 1; ref src; static ref alloc(const ref &src) { ref r(new NotOptimizedExpr(src)); r->computeHash(); return r; } static ref create(ref src); Width getWidth() const { return src->getWidth(); } Kind getKind() const { return NotOptimized; } unsigned getNumKids() const { return 1; } ref getKid(unsigned i) const { return src; } virtual ref rebuild(ref kids[]) const { return create(kids[0]); } private: NotOptimizedExpr(const ref &_src) : src(_src) {} protected: virtual int compareContents(const Expr &b) const { // No attributes to compare. return 0; } public: static bool classof(const Expr *E) { return E->getKind() == Expr::NotOptimized; } static bool classof(const NotOptimizedExpr *) { return true; } }; /// Class representing a byte update of an array. class UpdateNode { friend class UpdateList; // cache instead of recalc unsigned hashValue; public: const ref next; ref index, value; /// @brief Required by klee::ref-managed objects mutable class ReferenceCounter _refCount; private: /// size of this update sequence, including this update unsigned size; public: UpdateNode(const ref &_next, const ref &_index, const ref &_value); unsigned getSize() const { return size; } int compare(const UpdateNode &b) const; unsigned hash() const { return hashValue; } UpdateNode() = delete; ~UpdateNode() = default; unsigned computeHash(); }; class Array { public: // Name of the array const std::string name; // FIXME: Not 64-bit clean. const unsigned size; /// Domain is how many bits can be used to access the array [32 bits] /// Range is the size (in bits) of the number stored there (array of bytes -> 8) const Expr::Width domain, range; /// constantValues - The constant initial values for this array, or empty for /// a symbolic array. If non-empty, this size of this array is equivalent to /// the array size. const std::vector > constantValues; private: unsigned hashValue; // FIXME: Make =delete when we switch to C++11 Array(const Array& array); // FIXME: Make =delete when we switch to C++11 Array& operator =(const Array& array); ~Array(); /// Array - Construct a new array object. /// /// \param _name - The name for this array. Names should generally be unique /// across an application, but this is not necessary for correctness, except /// when printing expressions. When expressions are printed the output will /// not parse correctly since two arrays with the same name cannot be /// distinguished once printed. Array(const std::string &_name, uint64_t _size, const ref *constantValuesBegin = 0, const ref *constantValuesEnd = 0, Expr::Width _domain = Expr::Int32, Expr::Width _range = Expr::Int8); public: bool isSymbolicArray() const { return constantValues.empty(); } bool isConstantArray() const { return !isSymbolicArray(); } const std::string getName() const { return name; } unsigned getSize() const { return size; } Expr::Width getDomain() const { return domain; } Expr::Width getRange() const { return range; } /// ComputeHash must take into account the name, the size, the domain, and the range unsigned computeHash(); unsigned hash() const { return hashValue; } friend class ArrayCache; }; /// Class representing a complete list of updates into an array. class UpdateList { friend class ReadExpr; // for default constructor public: const Array *root; /// pointer to the most recent update node ref head; public: UpdateList(const Array *_root, const ref &_head); UpdateList(const UpdateList &b) = default; ~UpdateList() = default; UpdateList &operator=(const UpdateList &b) = default; /// size of this update list unsigned getSize() const { return head ? head->getSize() : 0; } void extend(const ref &index, const ref &value); int compare(const UpdateList &b) const; unsigned hash() const; }; /// Class representing a one byte read from an array. class ReadExpr : public NonConstantExpr { public: static const Kind kind = Read; static const unsigned numKids = 1; public: UpdateList updates; ref index; public: static ref alloc(const UpdateList &updates, const ref &index) { ref r(new ReadExpr(updates, index)); r->computeHash(); return r; } static ref create(const UpdateList &updates, ref i); Width getWidth() const { assert(updates.root); return updates.root->getRange(); } Kind getKind() const { return Read; } unsigned getNumKids() const { return numKids; } ref getKid(unsigned i) const { return !i ? index : 0; } int compareContents(const Expr &b) const; virtual ref rebuild(ref kids[]) const { return create(updates, kids[0]); } virtual unsigned computeHash(); private: ReadExpr(const UpdateList &_updates, const ref &_index) : updates(_updates), index(_index) { assert(updates.root); } public: static bool classof(const Expr *E) { return E->getKind() == Expr::Read; } static bool classof(const ReadExpr *) { return true; } }; /// Class representing an if-then-else expression. class SelectExpr : public NonConstantExpr { public: static const Kind kind = Select; static const unsigned numKids = 3; public: ref cond, trueExpr, falseExpr; public: static ref alloc(const ref &c, const ref &t, const ref &f) { ref r(new SelectExpr(c, t, f)); r->computeHash(); return r; } static ref create(ref c, ref t, ref f); Width getWidth() const { return trueExpr->getWidth(); } Kind getKind() const { return Select; } unsigned getNumKids() const { return numKids; } ref getKid(unsigned i) const { switch(i) { case 0: return cond; case 1: return trueExpr; case 2: return falseExpr; default: return 0; } } static bool isValidKidWidth(unsigned kid, Width w) { if (kid == 0) return w == Bool; else return true; } virtual ref rebuild(ref kids[]) const { return create(kids[0], kids[1], kids[2]); } private: SelectExpr(const ref &c, const ref &t, const ref &f) : cond(c), trueExpr(t), falseExpr(f) {} public: static bool classof(const Expr *E) { return E->getKind() == Expr::Select; } static bool classof(const SelectExpr *) { return true; } protected: virtual int compareContents(const Expr &b) const { // No attributes to compare. return 0; } }; /** Children of a concat expression can have arbitrary widths. Kid 0 is the left kid, kid 1 is the right kid. */ class ConcatExpr : public NonConstantExpr { public: static const Kind kind = Concat; static const unsigned numKids = 2; private: Width width; ref left, right; public: static ref alloc(const ref &l, const ref &r) { ref c(new ConcatExpr(l, r)); c->computeHash(); return c; } static ref create(const ref &l, const ref &r); Width getWidth() const { return width; } Kind getKind() const { return kind; } ref getLeft() const { return left; } ref getRight() const { return right; } unsigned getNumKids() const { return numKids; } ref getKid(unsigned i) const { if (i == 0) return left; else if (i == 1) return right; else return NULL; } /// Shortcuts to create larger concats. The chain returned is unbalanced to the right static ref createN(unsigned nKids, const ref kids[]); static ref create4(const ref &kid1, const ref &kid2, const ref &kid3, const ref &kid4); static ref create8(const ref &kid1, const ref &kid2, const ref &kid3, const ref &kid4, const ref &kid5, const ref &kid6, const ref &kid7, const ref &kid8); virtual ref rebuild(ref kids[]) const { return create(kids[0], kids[1]); } private: ConcatExpr(const ref &l, const ref &r) : left(l), right(r) { width = l->getWidth() + r->getWidth(); } public: static bool classof(const Expr *E) { return E->getKind() == Expr::Concat; } static bool classof(const ConcatExpr *) { return true; } protected: virtual int compareContents(const Expr &b) const { const ConcatExpr &eb = static_cast(b); if (width != eb.width) return width < eb.width ? -1 : 1; return 0; } }; /** This class represents an extract from expression {\tt expr}, at bit offset {\tt offset} of width {\tt width}. Bit 0 is the right most bit of the expression. */ class ExtractExpr : public NonConstantExpr { public: static const Kind kind = Extract; static const unsigned numKids = 1; public: ref expr; unsigned offset; Width width; public: static ref alloc(const ref &e, unsigned o, Width w) { ref r(new ExtractExpr(e, o, w)); r->computeHash(); return r; } /// Creates an ExtractExpr with the given bit offset and width static ref create(ref e, unsigned bitOff, Width w); Width getWidth() const { return width; } Kind getKind() const { return Extract; } unsigned getNumKids() const { return numKids; } ref getKid(unsigned i) const { return expr; } int compareContents(const Expr &b) const { const ExtractExpr &eb = static_cast(b); if (offset != eb.offset) return offset < eb.offset ? -1 : 1; if (width != eb.width) return width < eb.width ? -1 : 1; return 0; } virtual ref rebuild(ref kids[]) const { return create(kids[0], offset, width); } virtual unsigned computeHash(); private: ExtractExpr(const ref &e, unsigned b, Width w) : expr(e),offset(b),width(w) {} public: static bool classof(const Expr *E) { return E->getKind() == Expr::Extract; } static bool classof(const ExtractExpr *) { return true; } }; /** Bitwise Not */ class NotExpr : public NonConstantExpr { public: static const Kind kind = Not; static const unsigned numKids = 1; ref expr; public: static ref alloc(const ref &e) { ref r(new NotExpr(e)); r->computeHash(); return r; } static ref create(const ref &e); Width getWidth() const { return expr->getWidth(); } Kind getKind() const { return Not; } unsigned getNumKids() const { return numKids; } ref getKid(unsigned i) const { return expr; } virtual ref rebuild(ref kids[]) const { return create(kids[0]); } virtual unsigned computeHash(); public: static bool classof(const Expr *E) { return E->getKind() == Expr::Not; } static bool classof(const NotExpr *) { return true; } private: NotExpr(const ref &e) : expr(e) {} protected: virtual int compareContents(const Expr &b) const { // No attributes to compare. return 0; } }; // Casting class CastExpr : public NonConstantExpr { public: ref src; Width width; public: CastExpr(const ref &e, Width w) : src(e), width(w) {} Width getWidth() const { return width; } unsigned getNumKids() const { return 1; } ref getKid(unsigned i) const { return (i==0) ? src : 0; } static bool needsResultType() { return true; } int compareContents(const Expr &b) const { const CastExpr &eb = static_cast(b); if (width != eb.width) return width < eb.width ? -1 : 1; return 0; } virtual unsigned computeHash(); static bool classof(const Expr *E) { Expr::Kind k = E->getKind(); return Expr::CastKindFirst <= k && k <= Expr::CastKindLast; } static bool classof(const CastExpr *) { return true; } }; #define CAST_EXPR_CLASS(_class_kind) \ class _class_kind ## Expr : public CastExpr { \ public: \ static const Kind kind = _class_kind; \ static const unsigned numKids = 1; \ public: \ _class_kind ## Expr(ref e, Width w) : CastExpr(e,w) {} \ static ref alloc(const ref &e, Width w) { \ ref r(new _class_kind ## Expr(e, w)); \ r->computeHash(); \ return r; \ } \ static ref create(const ref &e, Width w); \ Kind getKind() const { return _class_kind; } \ virtual ref rebuild(ref kids[]) const { \ return create(kids[0], width); \ } \ \ static bool classof(const Expr *E) { \ return E->getKind() == Expr::_class_kind; \ } \ static bool classof(const _class_kind ## Expr *) { \ return true; \ } \ }; \ CAST_EXPR_CLASS(SExt) CAST_EXPR_CLASS(ZExt) // Arithmetic/Bit Exprs #define ARITHMETIC_EXPR_CLASS(_class_kind) \ class _class_kind##Expr : public BinaryExpr { \ public: \ static const Kind kind = _class_kind; \ static const unsigned numKids = 2; \ \ public: \ _class_kind##Expr(const ref &l, const ref &r) \ : BinaryExpr(l, r) {} \ static ref alloc(const ref &l, const ref &r) { \ ref res(new _class_kind##Expr(l, r)); \ res->computeHash(); \ return res; \ } \ static ref create(const ref &l, const ref &r); \ Width getWidth() const { return left->getWidth(); } \ Kind getKind() const { return _class_kind; } \ virtual ref rebuild(ref kids[]) const { \ return create(kids[0], kids[1]); \ } \ \ static bool classof(const Expr *E) { \ return E->getKind() == Expr::_class_kind; \ } \ static bool classof(const _class_kind##Expr *) { return true; } \ \ protected: \ virtual int compareContents(const Expr &b) const { \ /* No attributes to compare.*/ \ return 0; \ } \ }; ARITHMETIC_EXPR_CLASS(Add) ARITHMETIC_EXPR_CLASS(Sub) ARITHMETIC_EXPR_CLASS(Mul) ARITHMETIC_EXPR_CLASS(UDiv) ARITHMETIC_EXPR_CLASS(SDiv) ARITHMETIC_EXPR_CLASS(URem) ARITHMETIC_EXPR_CLASS(SRem) ARITHMETIC_EXPR_CLASS(And) ARITHMETIC_EXPR_CLASS(Or) ARITHMETIC_EXPR_CLASS(Xor) ARITHMETIC_EXPR_CLASS(Shl) ARITHMETIC_EXPR_CLASS(LShr) ARITHMETIC_EXPR_CLASS(AShr) // Comparison Exprs #define COMPARISON_EXPR_CLASS(_class_kind) \ class _class_kind##Expr : public CmpExpr { \ public: \ static const Kind kind = _class_kind; \ static const unsigned numKids = 2; \ \ public: \ _class_kind##Expr(const ref &l, const ref &r) \ : CmpExpr(l, r) {} \ static ref alloc(const ref &l, const ref &r) { \ ref res(new _class_kind##Expr(l, r)); \ res->computeHash(); \ return res; \ } \ static ref create(const ref &l, const ref &r); \ Kind getKind() const { return _class_kind; } \ virtual ref rebuild(ref kids[]) const { \ return create(kids[0], kids[1]); \ } \ \ static bool classof(const Expr *E) { \ return E->getKind() == Expr::_class_kind; \ } \ static bool classof(const _class_kind##Expr *) { return true; } \ \ protected: \ virtual int compareContents(const Expr &b) const { \ /* No attributes to compare. */ \ return 0; \ } \ }; COMPARISON_EXPR_CLASS(Eq) COMPARISON_EXPR_CLASS(Ne) COMPARISON_EXPR_CLASS(Ult) COMPARISON_EXPR_CLASS(Ule) COMPARISON_EXPR_CLASS(Ugt) COMPARISON_EXPR_CLASS(Uge) COMPARISON_EXPR_CLASS(Slt) COMPARISON_EXPR_CLASS(Sle) COMPARISON_EXPR_CLASS(Sgt) COMPARISON_EXPR_CLASS(Sge) // Terminal Exprs class ConstantExpr : public Expr { public: static const Kind kind = Constant; static const unsigned numKids = 0; private: llvm::APInt value; ConstantExpr(const llvm::APInt &v) : value(v) {} public: ~ConstantExpr() {} Width getWidth() const { return value.getBitWidth(); } Kind getKind() const { return Constant; } unsigned getNumKids() const { return 0; } ref getKid(unsigned i) const { return 0; } /// getAPValue - Return the arbitrary precision value directly. /// /// Clients should generally not use the APInt value directly and instead use /// native ConstantExpr APIs. const llvm::APInt &getAPValue() const { return value; } /// getZExtValue - Returns the constant value zero extended to the /// return type of this method. /// ///\param bits - optional parameter that can be used to check that the /// number of bits used by this constant is <= to the parameter /// value. This is useful for checking that type casts won't truncate /// useful bits. /// /// Example: unit8_t byte= (unit8_t) constant->getZExtValue(8); uint64_t getZExtValue(unsigned bits = 64) const { assert(getWidth() <= bits && "Value may be out of range!"); return value.getZExtValue(); } /// getLimitedValue - If this value is smaller than the specified limit, /// return it, otherwise return the limit value. uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const { return value.getLimitedValue(Limit); } /// toString - Return the constant value as a string /// \param Res specifies the string for the result to be placed in /// \param radix specifies the base (e.g. 2,10,16). The default is base 10 void toString(std::string &Res, unsigned radix = 10) const; int compareContents(const Expr &b) const { const ConstantExpr &cb = static_cast(b); if (getWidth() != cb.getWidth()) return getWidth() < cb.getWidth() ? -1 : 1; if (value == cb.value) return 0; return value.ult(cb.value) ? -1 : 1; } virtual ref rebuild(ref kids[]) const { assert(0 && "rebuild() on ConstantExpr"); return const_cast(this); } virtual unsigned computeHash(); static ref fromMemory(void *address, Width w); void toMemory(void *address); static ref alloc(const llvm::APInt &v) { ref r(new ConstantExpr(v)); r->computeHash(); return r; } static ref alloc(const llvm::APFloat &f) { return alloc(f.bitcastToAPInt()); } static ref alloc(uint64_t v, Width w) { return alloc(llvm::APInt(w, v)); } static ref create(uint64_t v, Width w) { #ifndef NDEBUG if (w <= 64) assert(v == bits64::truncateToNBits(v, w) && "invalid constant"); #endif return alloc(v, w); } static bool classof(const Expr *E) { return E->getKind() == Expr::Constant; } static bool classof(const ConstantExpr *) { return true; } /* Utility Functions */ /// isZero - Is this a constant zero. bool isZero() const { return getAPValue().isMinValue(); } /// isOne - Is this a constant one. bool isOne() const { return getLimitedValue() == 1; } /// isTrue - Is this the true expression. bool isTrue() const { return (getWidth() == Expr::Bool && value.getBoolValue() == true); } /// isFalse - Is this the false expression. bool isFalse() const { return (getWidth() == Expr::Bool && value.getBoolValue() == false); } /// isAllOnes - Is this constant all ones. bool isAllOnes() const { #if LLVM_VERSION_CODE <= LLVM_VERSION(13, 0) return getAPValue().isAllOnesValue(); #else return getAPValue().isAllOnes(); #endif } /* Constant Operations */ ref Concat(const ref &RHS); ref Extract(unsigned offset, Width W); ref ZExt(Width W); ref SExt(Width W); ref Add(const ref &RHS); ref Sub(const ref &RHS); ref Mul(const ref &RHS); ref UDiv(const ref &RHS); ref SDiv(const ref &RHS); ref URem(const ref &RHS); ref SRem(const ref &RHS); ref And(const ref &RHS); ref Or(const ref &RHS); ref Xor(const ref &RHS); ref Shl(const ref &RHS); ref LShr(const ref &RHS); ref AShr(const ref &RHS); // Comparisons return a constant expression of width 1. ref Eq(const ref &RHS); ref Ne(const ref &RHS); ref Ult(const ref &RHS); ref Ule(const ref &RHS); ref Ugt(const ref &RHS); ref Uge(const ref &RHS); ref Slt(const ref &RHS); ref Sle(const ref &RHS); ref Sgt(const ref &RHS); ref Sge(const ref &RHS); ref Neg(); ref Not(); }; // Implementations inline bool Expr::isZero() const { if (const ConstantExpr *CE = dyn_cast(this)) return CE->isZero(); return false; } inline bool Expr::isTrue() const { assert(getWidth() == Expr::Bool && "Invalid isTrue() call!"); if (const ConstantExpr *CE = dyn_cast(this)) return CE->isTrue(); return false; } inline bool Expr::isFalse() const { assert(getWidth() == Expr::Bool && "Invalid isFalse() call!"); if (const ConstantExpr *CE = dyn_cast(this)) return CE->isFalse(); return false; } } // End klee namespace #endif /* KLEE_EXPR_H */