[llvm-commits] [klee] r72205 [2/3] - in /klee/trunk: ./ autoconf/ docs/ docs/SMT-COMP/ examples/ examples/regexp/ examples/sort/ include/ include/expr/ include/klee/ include/klee/Config/ include/klee/Internal/ include/klee/Internal/ADT/ include/klee/Internal/Module/ include/klee/Internal/Support/ include/klee/Internal/System/ include/klee/util/ lib/ lib/Basic/ lib/Core/ lib/Expr/ lib/Module/ lib/Solver/ lib/Support/ runtime/ runtime/Intrinsic/ runtime/POSIX/ runtime/POSIX/testing-dir/ runtime/POSIX/testing-dir/e/ runti...
Daniel Dunbar
daniel at zuster.org
Wed May 20 21:36:47 PDT 2009
Added: klee/trunk/lib/Expr/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/Expr.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/Expr.cpp (added)
+++ klee/trunk/lib/Expr/Expr.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1122 @@
+//===-- Expr.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/Expr.h"
+
+
+#include "klee/Machine.h"
+// FIXME: This shouldn't be here.
+//#include "klee/Memory.h"
+#include "llvm/Type.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+// FIXME: We shouldn't need this once fast constant support moves into
+// Core. If we need to do arithmetic, we probably want to use APInt.
+#include "klee/Internal/Support/IntEvaluation.h"
+
+#include "klee/util/ExprPPrinter.h"
+
+using namespace klee;
+using namespace llvm;
+
+namespace {
+ cl::opt<bool>
+ ConstArrayOpt("const-array-opt",
+ cl::init(false),
+ cl::desc("Enable various optimizations involving all-constant arrays."));
+}
+
+/***/
+
+unsigned Expr::count = 0;
+
+ref<Expr> Expr::createTempRead(const Array *array, Expr::Width w) {
+ UpdateList ul(array, true, 0);
+
+ switch (w) {
+ case Expr::Bool:
+ return ZExtExpr::create(ReadExpr::create(ul,
+ ref<Expr>(0,kMachinePointerType)),
+ Expr::Bool);
+ case Expr::Int8:
+ return ReadExpr::create(ul,
+ ref<Expr>(0,kMachinePointerType));
+ case Expr::Int16:
+ return ConcatExpr::create(ReadExpr::create(ul,
+ ref<Expr>(1,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(0,kMachinePointerType)));
+ case Expr::Int32:
+ return ConcatExpr::create4(ReadExpr::create(ul,
+ ref<Expr>(3,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(2,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(1,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(0,kMachinePointerType)));
+ case Expr::Int64:
+ return ConcatExpr::create8(ReadExpr::create(ul,
+ ref<Expr>(7,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(6,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(5,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(4,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(3,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(2,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(1,kMachinePointerType)),
+ ReadExpr::create(ul,
+ ref<Expr>(0,kMachinePointerType)));
+ default: assert(0 && "invalid width");
+ }
+}
+
+// returns 0 if b is structurally equal to *this
+int Expr::compare(const Expr &b) const {
+ if (this == &b) return 0;
+
+ Kind ak = getKind(), bk = b.getKind();
+ if (ak!=bk)
+ return (ak < bk) ? -1 : 1;
+
+ if (hashValue != b.hashValue)
+ return (hashValue < b.hashValue) ? -1 : 1;
+
+ if (int res = compareContents(b))
+ return res;
+
+ unsigned aN = getNumKids();
+ for (unsigned i=0; i<aN; i++)
+ if (int res = getKid(i).compare(b.getKid(i)))
+ return res;
+
+ return 0;
+}
+
+void Expr::printKind(std::ostream &os, Kind k) {
+ switch(k) {
+#define X(C) case C: os << #C; break
+ X(Constant);
+ X(NotOptimized);
+ X(Read);
+ X(Select);
+ X(Concat);
+ X(Extract);
+ X(ZExt);
+ X(SExt);
+ X(Add);
+ X(Sub);
+ X(Mul);
+ X(UDiv);
+ X(SDiv);
+ X(URem);
+ X(SRem);
+ X(And);
+ X(Or);
+ X(Xor);
+ X(Shl);
+ X(LShr);
+ X(AShr);
+ X(Eq);
+ X(Ne);
+ X(Ult);
+ X(Ule);
+ X(Ugt);
+ X(Uge);
+ X(Slt);
+ X(Sle);
+ X(Sgt);
+ X(Sge);
+#undef X
+ default:
+ assert(0 && "invalid kind");
+ }
+}
+
+////////
+//
+// Simple hash functions for various kinds of Exprs
+//
+///////
+
+unsigned Expr::computeHash() {
+ unsigned res = getKind() * Expr::MAGIC_HASH_CONSTANT;
+
+ int n = getNumKids();
+ for (int i = 0; i < n; i++) {
+ res <<= 1;
+ res ^= getKid(i).hash() * Expr::MAGIC_HASH_CONSTANT;
+ }
+
+ hashValue = res;
+ return hashValue;
+}
+
+unsigned ConstantExpr::computeHash() {
+ hashValue = Expr::hashConstant(asUInt64, width);
+ return hashValue;
+}
+
+unsigned CastExpr::computeHash() {
+ unsigned res = getWidth() * Expr::MAGIC_HASH_CONSTANT;
+ hashValue = res ^ src.hash() * Expr::MAGIC_HASH_CONSTANT;
+ return hashValue;
+}
+
+unsigned ExtractExpr::computeHash() {
+ unsigned res = offset * Expr::MAGIC_HASH_CONSTANT;
+ res ^= getWidth() * Expr::MAGIC_HASH_CONSTANT;
+ hashValue = res ^ expr.hash() * Expr::MAGIC_HASH_CONSTANT;
+ return hashValue;
+}
+
+unsigned ReadExpr::computeHash() {
+ unsigned res = index.hash() * Expr::MAGIC_HASH_CONSTANT;
+ res ^= updates.hash();
+ hashValue = res;
+ return hashValue;
+}
+
+uint64_t Expr::getConstantValue() const {
+ assert(getKind() == Constant);
+ return static_cast<const ConstantExpr*>(this)->asUInt64;
+}
+
+ref<Expr> Expr::createFromKind(Kind k, std::vector<CreateArg> args) {
+ unsigned numArgs = args.size();
+
+ switch(k) {
+ case NotOptimized:
+ assert(numArgs == 1 && args[0].isExpr() &&
+ "invalid args array for given opcode");
+ return NotOptimizedExpr::create(args[0].expr);
+
+ case Select:
+ assert(numArgs == 3 && args[0].isExpr() &&
+ args[1].isExpr() && args[2].isExpr() &&
+ "invalid args array for Select opcode");
+ return SelectExpr::create(args[0].expr,
+ args[1].expr,
+ args[2].expr);
+
+ case Concat: {
+ assert(numArgs == 2 && args[0].isExpr() && args[1].isExpr() &&
+ "invalid args array for Concat opcode");
+
+ return ConcatExpr::create(args[0].expr, args[1].expr);
+ }
+
+#define CAST_EXPR_CASE(T) \
+ case T: \
+ assert(numArgs == 2 && \
+ args[0].isExpr() && args[1].isWidth() && \
+ "invalid args array for given opcode"); \
+ return T ## Expr::create(args[0].expr, args[1].width); \
+
+#define BINARY_EXPR_CASE(T) \
+ case T: \
+ assert(numArgs == 2 && \
+ args[0].isExpr() && args[1].isExpr() && \
+ "invalid args array for given opcode"); \
+ return T ## Expr::create(args[0].expr, args[1].expr); \
+
+ CAST_EXPR_CASE(ZExt);
+ CAST_EXPR_CASE(SExt);
+
+ BINARY_EXPR_CASE(Add);
+ BINARY_EXPR_CASE(Sub);
+ BINARY_EXPR_CASE(Mul);
+ BINARY_EXPR_CASE(UDiv);
+ BINARY_EXPR_CASE(SDiv);
+ BINARY_EXPR_CASE(URem);
+ BINARY_EXPR_CASE(SRem);
+ BINARY_EXPR_CASE(And);
+ BINARY_EXPR_CASE(Or);
+ BINARY_EXPR_CASE(Xor);
+ BINARY_EXPR_CASE(Shl);
+ BINARY_EXPR_CASE(LShr);
+ BINARY_EXPR_CASE(AShr);
+
+ BINARY_EXPR_CASE(Eq);
+ BINARY_EXPR_CASE(Ne);
+ BINARY_EXPR_CASE(Ult);
+ BINARY_EXPR_CASE(Ule);
+ BINARY_EXPR_CASE(Ugt);
+ BINARY_EXPR_CASE(Uge);
+ BINARY_EXPR_CASE(Slt);
+ BINARY_EXPR_CASE(Sle);
+ BINARY_EXPR_CASE(Sgt);
+ BINARY_EXPR_CASE(Sge);
+
+ case Constant:
+ case Extract:
+ case Read:
+ default:
+ assert(0 && "invalid kind");
+ }
+
+}
+
+
+void Expr::printWidth(std::ostream &os, Width width) {
+ switch(width) {
+ case Expr::Bool: os << "Expr::Bool"; break;
+ case Expr::Int8: os << "Expr::Int8"; break;
+ case Expr::Int16: os << "Expr::Int16"; break;
+ case Expr::Int32: os << "Expr::Int32"; break;
+ case Expr::Int64: os << "Expr::Int64"; break;
+ default: os << "<invalid type: " << (unsigned) width << ">";
+ }
+}
+
+Expr::Width Expr::getWidthForLLVMType(const llvm::Type *t) {
+ switch (t->getTypeID()) {
+ case llvm::Type::IntegerTyID: {
+ Width w = cast<IntegerType>(t)->getBitWidth();
+
+ // should remove this limitation soon
+ if (w == 1 || w == 8 || w == 16 || w == 32 || w == 64)
+ return w;
+ else {
+ assert(0 && "XXX arbitrary bit widths unsupported");
+ abort();
+ }
+ }
+ case llvm::Type::FloatTyID: return Expr::Int32;
+ case llvm::Type::DoubleTyID: return Expr::Int64;
+ case llvm::Type::X86_FP80TyID: return Expr::Int64; // XXX: needs to be fixed
+ case llvm::Type::PointerTyID: return kMachinePointerType;
+ default:
+ cerr << "non-primitive type argument to Expr::getTypeForLLVMType()\n";
+ abort();
+ }
+}
+
+ref<Expr> Expr::createImplies(ref<Expr> hyp, ref<Expr> conc) {
+ return OrExpr::create(Expr::createNot(hyp), conc);
+}
+
+ref<Expr> Expr::createIsZero(ref<Expr> e) {
+ return EqExpr::create(e, ConstantExpr::create(0, e.getWidth()));
+}
+
+ref<Expr> Expr::createCoerceToPointerType(ref<Expr> e) {
+ return ZExtExpr::create(e, kMachinePointerType);
+}
+
+ref<Expr> Expr::createNot(ref<Expr> e) {
+ return createIsZero(e);
+}
+
+ref<Expr> Expr::createPointer(uint64_t v) {
+ return ConstantExpr::create(v, kMachinePointerType);
+}
+
+Expr* Expr::createConstant(uint64_t val, Width w) {
+ Expr *r = new ConstantExpr(val, w);
+ r->computeHash();
+ return r;
+}
+
+void Expr::print(std::ostream &os) const {
+ const ref<Expr> tmp((Expr*)this);
+ ExprPPrinter::printOne(os, "", tmp);
+}
+
+/***/
+
+ref<ConstantExpr> ConstantExpr::fromMemory(void *address, Width width) {
+ switch (width) {
+ case Expr::Bool: return ConstantExpr::create(*(( uint8_t*) address), width);
+ case Expr::Int8: return ConstantExpr::create(*(( uint8_t*) address), width);
+ case Expr::Int16: return ConstantExpr::create(*((uint16_t*) address), width);
+ case Expr::Int32: return ConstantExpr::create(*((uint32_t*) address), width);
+ case Expr::Int64: return ConstantExpr::create(*((uint64_t*) address), width);
+ default: assert(0 && "invalid type");
+ }
+}
+
+void ConstantExpr::toMemory(void *address) {
+ switch (width) {
+ case Expr::Bool: *(( uint8_t*) address) = asUInt64; break;
+ case Expr::Int8: *(( uint8_t*) address) = asUInt64; break;
+ case Expr::Int16: *((uint16_t*) address) = asUInt64; break;
+ case Expr::Int32: *((uint32_t*) address) = asUInt64; break;
+ case Expr::Int64: *((uint64_t*) address) = asUInt64; break;
+ default: assert(0 && "invalid type");
+ }
+}
+
+/***/
+
+ref<Expr> NotOptimizedExpr::create(ref<Expr> src) {
+ return NotOptimizedExpr::alloc(src);
+}
+
+ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) {
+ // rollback index when possible...
+
+ // XXX this doesn't really belong here... there are basically two
+ // cases, one is rebuild, where we want to optimistically try various
+ // optimizations when the index has changed, and the other is
+ // initial creation, where we expect the ObjectState to have constructed
+ // a smart UpdateList so it is not worth rescanning.
+
+ const UpdateNode *un = ul.head;
+ for (; un; un=un->next) {
+ ref<Expr> cond = EqExpr::create(index, un->index);
+
+ if (cond.isConstant()) {
+ if (cond.getConstantValue())
+ return un->value;
+ } else {
+ break;
+ }
+ }
+
+ return ReadExpr::alloc(ul, index);
+}
+
+int ReadExpr::compareContents(const Expr &b) const {
+ return updates.compare(static_cast<const ReadExpr&>(b).updates);
+}
+
+ref<Expr> SelectExpr::create(ref<Expr> c, ref<Expr> t, ref<Expr> f) {
+ Expr::Width kt = t.getWidth();
+
+ assert(c.getWidth()==Bool && "type mismatch");
+ assert(kt==f.getWidth() && "type mismatch");
+
+ if (c.isConstant()) {
+ return c.getConstantValue() ? t : f;
+ } else if (t==f) {
+ return t;
+ } else if (kt==Expr::Bool) { // c ? t : f <=> (c and t) or (not c and f)
+ if (t.isConstant()) {
+ if (t.getConstantValue()) {
+ return OrExpr::create(c, f);
+ } else {
+ return AndExpr::create(Expr::createNot(c), f);
+ }
+ } else if (f.isConstant()) {
+ if (f.getConstantValue()) {
+ return OrExpr::create(Expr::createNot(c), t);
+ } else {
+ return AndExpr::create(c, t);
+ }
+ }
+ }
+
+ return SelectExpr::alloc(c, t, f);
+}
+
+/***/
+
+
+ref<Expr> ConcatExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ Expr::Width w = l.getWidth() + r.getWidth();
+
+ /* Constant folding */
+ if (l.getKind() == Expr::Constant && r.getKind() == Expr::Constant) {
+ // XXX: should fix this constant limitation soon
+ assert(w <= 64 && "ConcatExpr::create(): don't support concats describing constants greater than 64 bits yet");
+
+ uint64_t res = (l.getConstantValue() << r.getWidth()) + r.getConstantValue();
+ return ConstantExpr::create(res, w);
+ }
+
+ // Merge contiguous Extracts
+ if (l.getKind() == Expr::Extract && r.getKind() == Expr::Extract) {
+ const ExtractExpr* ee_left = static_ref_cast<ExtractExpr>(l);
+ const ExtractExpr* ee_right = static_ref_cast<ExtractExpr>(r);
+ if (ee_left->expr == ee_right->expr &&
+ ee_right->offset + ee_right->width == ee_left->offset) {
+ return ExtractExpr::create(ee_left->expr, ee_right->offset, w);
+ }
+ }
+
+ return ConcatExpr::alloc(l, r);
+}
+
+/// Shortcut to concat N kids. The chain returned is unbalanced to the right
+ref<Expr> ConcatExpr::createN(unsigned n_kids, const ref<Expr> kids[]) {
+ assert(n_kids > 0);
+ if (n_kids == 1)
+ return kids[0];
+
+ ref<Expr> r = ConcatExpr::create(kids[n_kids-2], kids[n_kids-1]);
+ for (int i=n_kids-3; i>=0; i--)
+ r = ConcatExpr::create(kids[i], r);
+ return r;
+}
+
+/// Shortcut to concat 4 kids. The chain returned is unbalanced to the right
+ref<Expr> ConcatExpr::create4(const ref<Expr> &kid1, const ref<Expr> &kid2,
+ const ref<Expr> &kid3, const ref<Expr> &kid4) {
+ return ConcatExpr::create(kid1, ConcatExpr::create(kid2, ConcatExpr::create(kid3, kid4)));
+}
+
+/// Shortcut to concat 8 kids. The chain returned is unbalanced to the right
+ref<Expr> ConcatExpr::create8(const ref<Expr> &kid1, const ref<Expr> &kid2,
+ const ref<Expr> &kid3, const ref<Expr> &kid4,
+ const ref<Expr> &kid5, const ref<Expr> &kid6,
+ const ref<Expr> &kid7, const ref<Expr> &kid8) {
+ return ConcatExpr::create(kid1, ConcatExpr::create(kid2, ConcatExpr::create(kid3,
+ ConcatExpr::create(kid4, ConcatExpr::create4(kid5, kid6, kid7, kid8)))));
+}
+
+/***/
+
+ref<Expr> ExtractExpr::create(ref<Expr> expr, unsigned off, Width w) {
+ unsigned kw = expr.getWidth();
+ assert(w > 0 && off + w <= kw && "invalid extract");
+
+ if (w == kw)
+ return expr;
+ else if (expr.isConstant()) {
+ return ConstantExpr::create(ints::trunc(expr.getConstantValue() >> off, w, kw), w);
+ }
+ else
+ // Extract(Concat)
+ if (ConcatExpr *ce = dyn_ref_cast<ConcatExpr>(expr)) {
+ // if the extract skips the right side of the concat
+ if (off >= ce->getRight().getWidth())
+ return ExtractExpr::create(ce->getLeft(), off - ce->getRight().getWidth(), w);
+
+ // if the extract skips the left side of the concat
+ if (off + w <= ce->getRight().getWidth())
+ return ExtractExpr::create(ce->getRight(), off, w);
+
+ // E(C(x,y)) = C(E(x), E(y))
+ return ConcatExpr::create(ExtractExpr::create(ce->getKid(0), 0, w - ce->getKid(1).getWidth() + off),
+ ExtractExpr::create(ce->getKid(1), off, ce->getKid(1).getWidth() - off));
+ }
+
+ return ExtractExpr::alloc(expr, off, w);
+}
+
+
+ref<Expr> ExtractExpr::createByteOff(ref<Expr> expr, unsigned offset, Width bits) {
+ return ExtractExpr::create(expr, 8*offset, bits);
+}
+
+/***/
+
+ref<Expr> ZExtExpr::create(const ref<Expr> &e, Width w) {
+ unsigned kBits = e.getWidth();
+ if (w == kBits) {
+ return e;
+ } else if (w < kBits) { // trunc
+ return ExtractExpr::createByteOff(e, 0, w);
+ } else {
+ if (e.isConstant()) {
+ return ConstantExpr::create(ints::zext(e.getConstantValue(), w, kBits),
+ w);
+ }
+
+ return ZExtExpr::alloc(e, w);
+ }
+}
+
+ref<Expr> SExtExpr::create(const ref<Expr> &e, Width w) {
+ unsigned kBits = e.getWidth();
+ if (w == kBits) {
+ return e;
+ } else if (w < kBits) { // trunc
+ return ExtractExpr::createByteOff(e, 0, w);
+ } else {
+ if (e.isConstant()) {
+ return ConstantExpr::create(ints::sext(e.getConstantValue(), w, kBits),
+ w);
+ }
+
+ return SExtExpr::alloc(e, w);
+ }
+}
+
+/***/
+
+static ref<Expr> AndExpr_create(Expr *l, Expr *r);
+static ref<Expr> XorExpr_create(Expr *l, Expr *r);
+
+static ref<Expr> EqExpr_createPartial(Expr *l, const ref<Expr> &cr);
+static ref<Expr> AndExpr_createPartialR(const ref<Expr> &cl, Expr *r);
+static ref<Expr> SubExpr_createPartialR(const ref<Expr> &cl, Expr *r);
+static ref<Expr> XorExpr_createPartialR(const ref<Expr> &cl, Expr *r);
+
+static ref<Expr> AddExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ assert(cl.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cl.getConstantValue();
+ Expr::Width type = cl.getWidth();
+
+ if (type==Expr::Bool) {
+ return XorExpr_createPartialR(cl, r);
+ } else if (!value) {
+ return r;
+ } else {
+ Expr::Kind rk = r->getKind();
+ if (rk==Expr::Add && r->getKid(0).isConstant()) { // A + (B+c) == (A+B) + c
+ return AddExpr::create(AddExpr::create(cl, r->getKid(0)),
+ r->getKid(1));
+ } else if (rk==Expr::Sub && r->getKid(0).isConstant()) { // A + (B-c) == (A+B) - c
+ return SubExpr::create(AddExpr::create(cl, r->getKid(0)),
+ r->getKid(1));
+ } else {
+ return AddExpr::alloc(cl, r);
+ }
+ }
+}
+static ref<Expr> AddExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ return AddExpr_createPartialR(cr, l);
+}
+static ref<Expr> AddExpr_create(Expr *l, Expr *r) {
+ Expr::Width type = l->getWidth();
+
+ if (type == Expr::Bool) {
+ return XorExpr_create(l, r);
+ } else {
+ Expr::Kind lk = l->getKind(), rk = r->getKind();
+ if (lk==Expr::Add && l->getKid(0).isConstant()) { // (k+a)+b = k+(a+b)
+ return AddExpr::create(l->getKid(0),
+ AddExpr::create(l->getKid(1), r));
+ } else if (lk==Expr::Sub && l->getKid(0).isConstant()) { // (k-a)+b = k+(b-a)
+ return AddExpr::create(l->getKid(0),
+ SubExpr::create(r, l->getKid(1)));
+ } else if (rk==Expr::Add && r->getKid(0).isConstant()) { // a + (k+b) = k+(a+b)
+ return AddExpr::create(r->getKid(0),
+ AddExpr::create(l, r->getKid(1)));
+ } else if (rk==Expr::Sub && r->getKid(0).isConstant()) { // a + (k-b) = k+(a-b)
+ return AddExpr::create(r->getKid(0),
+ SubExpr::create(l, r->getKid(1)));
+ } else {
+ return AddExpr::alloc(l, r);
+ }
+ }
+}
+
+static ref<Expr> SubExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ assert(cl.isConstant() && "non-constant passed in place of constant");
+ Expr::Width type = cl.getWidth();
+
+ if (type==Expr::Bool) {
+ return XorExpr_createPartialR(cl, r);
+ } else {
+ Expr::Kind rk = r->getKind();
+ if (rk==Expr::Add && r->getKid(0).isConstant()) { // A - (B+c) == (A-B) - c
+ return SubExpr::create(SubExpr::create(cl, r->getKid(0)),
+ r->getKid(1));
+ } else if (rk==Expr::Sub && r->getKid(0).isConstant()) { // A - (B-c) == (A-B) + c
+ return AddExpr::create(SubExpr::create(cl, r->getKid(0)),
+ r->getKid(1));
+ } else {
+ return SubExpr::alloc(cl, r);
+ }
+ }
+}
+static ref<Expr> SubExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ assert(cr.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cr.getConstantValue();
+ Expr::Width width = cr.getWidth();
+ uint64_t nvalue = ints::sub(0, value, width);
+
+ return AddExpr_createPartial(l, ConstantExpr::create(nvalue, width));
+}
+static ref<Expr> SubExpr_create(Expr *l, Expr *r) {
+ Expr::Width type = l->getWidth();
+
+ if (type == Expr::Bool) {
+ return XorExpr_create(l, r);
+ } else if (*l==*r) {
+ return ref<Expr>(0, type);
+ } else {
+ Expr::Kind lk = l->getKind(), rk = r->getKind();
+ if (lk==Expr::Add && l->getKid(0).isConstant()) { // (k+a)-b = k+(a-b)
+ return AddExpr::create(l->getKid(0),
+ SubExpr::create(l->getKid(1), r));
+ } else if (lk==Expr::Sub && l->getKid(0).isConstant()) { // (k-a)-b = k-(a+b)
+ return SubExpr::create(l->getKid(0),
+ AddExpr::create(l->getKid(1), r));
+ } else if (rk==Expr::Add && r->getKid(0).isConstant()) { // a - (k+b) = (a-c) - k
+ return SubExpr::create(SubExpr::create(l, r->getKid(1)),
+ r->getKid(0));
+ } else if (rk==Expr::Sub && r->getKid(0).isConstant()) { // a - (k-b) = (a+b) - k
+ return SubExpr::create(AddExpr::create(l, r->getKid(1)),
+ r->getKid(0));
+ } else {
+ return SubExpr::alloc(l, r);
+ }
+ }
+}
+
+static ref<Expr> MulExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ assert(cl.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cl.getConstantValue();
+ Expr::Width type = cl.getWidth();
+
+ if (type == Expr::Bool) {
+ return AndExpr_createPartialR(cl, r);
+ } else if (value == 1) {
+ return r;
+ } else if (!value) {
+ return cl;
+ } else {
+ return MulExpr::alloc(cl, r);
+ }
+}
+static ref<Expr> MulExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ return MulExpr_createPartialR(cr, l);
+}
+static ref<Expr> MulExpr_create(Expr *l, Expr *r) {
+ Expr::Width type = l->getWidth();
+
+ if (type == Expr::Bool) {
+ return AndExpr::alloc(l, r);
+ } else {
+ return MulExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> AndExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ assert(cr.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cr.getConstantValue();
+ Expr::Width width = cr.getWidth();;
+
+ if (value==ints::sext(1, width, 1)) {
+ return l;
+ } else if (!value) {
+ return cr;
+ } else {
+ return AndExpr::alloc(l, cr);
+ }
+}
+static ref<Expr> AndExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ return AndExpr_createPartial(r, cl);
+}
+static ref<Expr> AndExpr_create(Expr *l, Expr *r) {
+ return AndExpr::alloc(l, r);
+}
+
+static ref<Expr> OrExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ assert(cr.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cr.getConstantValue();
+ Expr::Width width = cr.getWidth();
+
+ if (value == ints::sext(1, width, 1)) {
+ return cr;
+ } else if (!value) {
+ return l;
+ } else {
+ return OrExpr::alloc(l, cr);
+ }
+}
+static ref<Expr> OrExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ return OrExpr_createPartial(r, cl);
+}
+static ref<Expr> OrExpr_create(Expr *l, Expr *r) {
+ return OrExpr::alloc(l, r);
+}
+
+static ref<Expr> XorExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ assert(cl.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cl.getConstantValue();
+ Expr::Width type = cl.getWidth();
+
+ if (type==Expr::Bool) {
+ if (value) {
+ return EqExpr_createPartial(r, ConstantExpr::create(0, Expr::Bool));
+ } else {
+ return r;
+ }
+ } else if (!value) {
+ return r;
+ } else {
+ return XorExpr::alloc(cl, r);
+ }
+}
+
+static ref<Expr> XorExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ return XorExpr_createPartialR(cr, l);
+}
+static ref<Expr> XorExpr_create(Expr *l, Expr *r) {
+ return XorExpr::alloc(l, r);
+}
+
+static ref<Expr> UDivExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // r must be 1
+ return l;
+ } else{
+ return UDivExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> SDivExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // r must be 1
+ return l;
+ } else{
+ return SDivExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> URemExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // r must be 1
+ return ConstantExpr::create(0, Expr::Bool);
+ } else{
+ return URemExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> SRemExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // r must be 1
+ return ConstantExpr::create(0, Expr::Bool);
+ } else{
+ return SRemExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> ShlExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // l & !r
+ return AndExpr::create(l, Expr::createNot(r));
+ } else{
+ return ShlExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> LShrExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // l & !r
+ return AndExpr::create(l, Expr::createNot(r));
+ } else{
+ return LShrExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> AShrExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // l
+ return l;
+ } else{
+ return AShrExpr::alloc(l, r);
+ }
+}
+
+#define BCREATE_R(_e_op, _op, partialL, partialR) \
+ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
+ assert(l.getWidth()==r.getWidth() && "type mismatch"); \
+ if (l.isConstant()) { \
+ if (r.isConstant()) { \
+ Expr::Width width = l.getWidth(); \
+ uint64_t val = ints::_op(l.getConstantValue(), \
+ r.getConstantValue(), width); \
+ return ConstantExpr::create(val, width); \
+ } else { \
+ return _e_op ## _createPartialR(l, r.get()); \
+ } \
+ } else if (r.isConstant()) { \
+ return _e_op ## _createPartial(l.get(), r); \
+ } \
+ return _e_op ## _create(l.get(), r.get()); \
+}
+
+#define BCREATE(_e_op, _op) \
+ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
+ assert(l.getWidth()==r.getWidth() && "type mismatch"); \
+ if (l.isConstant()) { \
+ if (r.isConstant()) { \
+ Expr::Width width = l.getWidth(); \
+ uint64_t val = ints::_op(l.getConstantValue(), \
+ r.getConstantValue(), width); \
+ return ConstantExpr::create(val, width); \
+ } \
+ } \
+ return _e_op ## _create(l, r); \
+}
+
+BCREATE_R(AddExpr, add, AddExpr_createPartial, AddExpr_createPartialR)
+BCREATE_R(SubExpr, sub, SubExpr_createPartial, SubExpr_createPartialR)
+BCREATE_R(MulExpr, mul, MulExpr_createPartial, MulExpr_createPartialR)
+BCREATE_R(AndExpr, land, AndExpr_createPartial, AndExpr_createPartialR)
+BCREATE_R(OrExpr, lor, OrExpr_createPartial, OrExpr_createPartialR)
+BCREATE_R(XorExpr, lxor, XorExpr_createPartial, XorExpr_createPartialR)
+BCREATE(UDivExpr, udiv)
+BCREATE(SDivExpr, sdiv)
+BCREATE(URemExpr, urem)
+BCREATE(SRemExpr, srem)
+BCREATE(ShlExpr, shl)
+BCREATE(LShrExpr, lshr)
+BCREATE(AShrExpr, ashr)
+
+#define CMPCREATE(_e_op, _op) \
+ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
+ assert(l.getWidth()==r.getWidth() && "type mismatch"); \
+ if (l.isConstant()) { \
+ if (r.isConstant()) { \
+ Expr::Width width = l.getWidth(); \
+ uint64_t val = ints::_op(l.getConstantValue(), \
+ r.getConstantValue(), width); \
+ return ConstantExpr::create(val, Expr::Bool); \
+ } \
+ } \
+ return _e_op ## _create(l, r); \
+}
+
+#define CMPCREATE_T(_e_op, _op, _reflexive_e_op, partialL, partialR) \
+ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
+ assert(l.getWidth()==r.getWidth() && "type mismatch"); \
+ if (l.isConstant()) { \
+ if (r.isConstant()) { \
+ Expr::Width width = l.getWidth(); \
+ uint64_t val = ints::_op(l.getConstantValue(), \
+ r.getConstantValue(), width); \
+ return ConstantExpr::create(val, Expr::Bool); \
+ } else { \
+ return partialR(l, r.get()); \
+ } \
+ } else if (r.isConstant()) { \
+ return partialL(l.get(), r); \
+ } else { \
+ return _e_op ## _create(l.get(), r.get()); \
+ } \
+}
+
+
+static ref<Expr> EqExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l == r) {
+ return ref<Expr>(1, Expr::Bool);
+ } else {
+ return EqExpr::alloc(l, r);
+ }
+}
+
+
+/// Tries to optimize EqExpr cl == rd, where cl is a ConstantExpr and
+/// rd a ReadExpr. If rd is a read into an all-constant array,
+/// returns a disjunction of equalities on the index. Otherwise,
+/// returns the initial equality expression.
+static ref<Expr> TryConstArrayOpt(const ref<Expr> &cl,
+ ReadExpr *rd) {
+ assert(cl.isConstant() && "constant expression required");
+ assert(rd->getKind() == Expr::Read && "read expression required");
+
+ uint64_t ct = cl.getConstantValue();
+ ref<Expr> first_idx_match;
+
+ // number of positions in the array that contain value ct
+ unsigned matches = 0;
+
+ //llvm::cerr << "Size updates/root: " << rd->updates.getSize() << " / " << (rd->updates.root)->size << "\n";
+
+ // for now, just assume standard "flushing" of a concrete array,
+ // where the concrete array has one update for each index, in order
+ bool all_const = true;
+ if (rd->updates.getSize() == rd->updates.root->size) {
+ unsigned k = rd->updates.getSize();
+ for (const UpdateNode *un = rd->updates.head; un; un = un->next) {
+ assert(k > 0);
+ k--;
+
+ ref<Expr> idx = un->index;
+ ref<Expr> val = un->value;
+ if (!idx.isConstant() || !val.isConstant()) {
+ all_const = false;
+ //llvm::cerr << "Idx or val not constant\n";
+ break;
+ }
+ else {
+ if (idx.getConstantValue() != k) {
+ all_const = false;
+ //llvm::cerr << "Wrong constant\n";
+ break;
+ }
+ if (val.getConstantValue() == ct) {
+ matches++;
+ if (matches == 1)
+ first_idx_match = un->index;
+ }
+ }
+ }
+ }
+ else all_const = false;
+
+ if (all_const && matches <= 100) {
+ // apply optimization
+ //llvm::cerr << "\n\n=== Applying const array optimization ===\n\n";
+
+ if (matches == 0)
+ return ref<Expr>(0, Expr::Bool);
+
+ ref<Expr> res = EqExpr::create(first_idx_match, rd->index);
+ if (matches == 1)
+ return res;
+
+ for (const UpdateNode *un = rd->updates.head; un; un = un->next) {
+ if (un->index != first_idx_match && un->value.getConstantValue() == ct) {
+ ref<Expr> curr_eq = EqExpr::create(un->index, rd->index);
+ res = OrExpr::create(curr_eq, res);
+ }
+ }
+
+ return res;
+ }
+
+ return EqExpr_create(cl, ref<Expr>(rd));
+}
+
+
+static ref<Expr> EqExpr_createPartialR(const ref<Expr> &cl, Expr *r) {
+ assert(cl.isConstant() && "non-constant passed in place of constant");
+ uint64_t value = cl.getConstantValue();
+ Expr::Width width = cl.getWidth();
+
+ Expr::Kind rk = r->getKind();
+ if (width == Expr::Bool) {
+ if (value) {
+ return r;
+ } else {
+ // 0 != ...
+
+ if (rk == Expr::Eq) {
+ const EqExpr *ree = static_ref_cast<EqExpr>(r);
+
+ // eliminate double negation
+ if (ree->left.isConstant() &&
+ ree->left.getWidth()==Expr::Bool) {
+ assert(!ree->left.getConstantValue());
+ return ree->right;
+ }
+ } else if (rk == Expr::Or) {
+ const OrExpr *roe = static_ref_cast<OrExpr>(r);
+
+ // transform not(or(a,b)) to and(not a, not b)
+ return AndExpr::create(Expr::createNot(roe->left),
+ Expr::createNot(roe->right));
+ }
+ }
+ } else if (rk == Expr::SExt) {
+ // (sext(a,T)==c) == (a==c)
+ const SExtExpr *see = static_ref_cast<SExtExpr>(r);
+ Expr::Width fromBits = see->src.getWidth();
+ uint64_t trunc = bits64::truncateToNBits(value, fromBits);
+
+ // pathological check, make sure it is possible to
+ // sext to this value *from any value*
+ if (value == ints::sext(trunc, width, fromBits)) {
+ return EqExpr::create(see->src, ConstantExpr::create(trunc, fromBits));
+ } else {
+ return ConstantExpr::create(0, Expr::Bool);
+ }
+ } else if (rk == Expr::ZExt) {
+ // (zext(a,T)==c) == (a==c)
+ const ZExtExpr *zee = static_ref_cast<ZExtExpr>(r);
+ Expr::Width fromBits = zee->src.getWidth();
+ uint64_t trunc = bits64::truncateToNBits(value, fromBits);
+
+ // pathological check, make sure it is possible to
+ // zext to this value *from any value*
+ if (value == ints::zext(trunc, width, fromBits)) {
+ return EqExpr::create(zee->src, ConstantExpr::create(trunc, fromBits));
+ } else {
+ return ConstantExpr::create(0, Expr::Bool);
+ }
+ } else if (rk==Expr::Add) {
+ const AddExpr *ae = static_ref_cast<AddExpr>(r);
+ if (ae->left.isConstant()) {
+ // c0 = c1 + b => c0 - c1 = b
+ return EqExpr_createPartialR(SubExpr::create(cl, ae->left),
+ ae->right.get());
+ }
+ } else if (rk==Expr::Sub) {
+ const SubExpr *se = static_ref_cast<SubExpr>(r);
+ if (se->left.isConstant()) {
+ // c0 = c1 - b => c1 - c0 = b
+ return EqExpr_createPartialR(SubExpr::create(se->left, cl),
+ se->right.get());
+ }
+ } else if (rk == Expr::Read && ConstArrayOpt) {
+ return TryConstArrayOpt(cl, static_cast<ReadExpr*>(r));
+ }
+
+ return EqExpr_create(cl, r);
+}
+
+static ref<Expr> EqExpr_createPartial(Expr *l, const ref<Expr> &cr) {
+ return EqExpr_createPartialR(cr, l);
+}
+
+ref<Expr> NeExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ return EqExpr::create(ConstantExpr::create(0, Expr::Bool),
+ EqExpr::create(l, r));
+}
+
+ref<Expr> UgtExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ return UltExpr::create(r, l);
+}
+ref<Expr> UgeExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ return UleExpr::create(r, l);
+}
+
+ref<Expr> SgtExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ return SltExpr::create(r, l);
+}
+ref<Expr> SgeExpr::create(const ref<Expr> &l, const ref<Expr> &r) {
+ return SleExpr::create(r, l);
+}
+
+static ref<Expr> UltExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ Expr::Width t = l.getWidth();
+ if (t == Expr::Bool) { // !l && r
+ return AndExpr::create(Expr::createNot(l), r);
+ } else {
+ if (r.isConstant()) {
+ uint64_t value = r.getConstantValue();
+ if (value <= 8) {
+ ref<Expr> res(0,Expr::Bool);
+ for (unsigned i=0; i<value; i++) {
+ res = OrExpr::create(EqExpr::create(l, ref<Expr>(i,t)), res);
+ }
+ // llvm::cerr << l << "<" << r << " <=> " << res << "\n";
+ return res;
+ }
+ }
+ return UltExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> UleExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // !(l && !r)
+ return OrExpr::create(Expr::createNot(l), r);
+ } else {
+ return UleExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> SltExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // l && !r
+ return AndExpr::create(l, Expr::createNot(r));
+ } else {
+ return SltExpr::alloc(l, r);
+ }
+}
+
+static ref<Expr> SleExpr_create(const ref<Expr> &l, const ref<Expr> &r) {
+ if (l.getWidth() == Expr::Bool) { // !(!l && r)
+ return OrExpr::create(l, Expr::createNot(r));
+ } else {
+ return SleExpr::alloc(l, r);
+ }
+}
+
+CMPCREATE_T(EqExpr, eq, EqExpr, EqExpr_createPartial, EqExpr_createPartialR)
+CMPCREATE(UltExpr, ult)
+CMPCREATE(UleExpr, ule)
+CMPCREATE(SltExpr, slt)
+CMPCREATE(SleExpr, sle)
Added: klee/trunk/lib/Expr/ExprEvaluator.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/ExprEvaluator.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/ExprEvaluator.cpp (added)
+++ klee/trunk/lib/Expr/ExprEvaluator.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,74 @@
+//===-- ExprEvaluator.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/util/ExprEvaluator.h"
+
+using namespace klee;
+
+ExprVisitor::Action ExprEvaluator::evalRead(const UpdateList &ul,
+ unsigned index) {
+ for (const UpdateNode *un=ul.head; un; un=un->next) {
+ ref<Expr> ui = visit(un->index);
+
+ if (ui.isConstant()) {
+ if (ui.getConstantValue() == index)
+ return Action::changeTo(visit(un->value));
+ } else {
+ // update index is unknown, so may or may not be index, we
+ // cannot guarantee value. we can rewrite to read at this
+ // version though (mostly for debugging).
+
+ UpdateList fwd(ul.root, un, 0);
+ return Action::changeTo(ReadExpr::create(fwd,
+ ref<Expr>(index,Expr::Int32)));
+ }
+ }
+
+ return Action::changeTo(getInitialValue(*ul.root, index));
+}
+
+ExprVisitor::Action ExprEvaluator::visitRead(const ReadExpr &re) {
+ ref<Expr> v = visit(re.index);
+
+ if (v.isConstant()) {
+ return evalRead(re.updates, v.getConstantValue());
+ } else {
+ return Action::doChildren();
+ }
+}
+
+// we need to check for div by zero during partial evaluation,
+// if this occurs then simply ignore the 0 divisor and use the
+// original expression.
+ExprVisitor::Action ExprEvaluator::protectedDivOperation(const BinaryExpr &e) {
+ ref<Expr> kids[2] = { visit(e.left),
+ visit(e.right) };
+
+ if (kids[1].isConstant() && !kids[1].getConstantValue())
+ kids[1] = e.right;
+
+ if (kids[0]!=e.left || kids[1]!=e.right) {
+ return Action::changeTo(e.rebuild(kids));
+ } else {
+ return Action::skipChildren();
+ }
+}
+
+ExprVisitor::Action ExprEvaluator::visitUDiv(const UDivExpr &e) {
+ return protectedDivOperation(e);
+}
+ExprVisitor::Action ExprEvaluator::visitSDiv(const SDivExpr &e) {
+ return protectedDivOperation(e);
+}
+ExprVisitor::Action ExprEvaluator::visitURem(const URemExpr &e) {
+ return protectedDivOperation(e);
+}
+ExprVisitor::Action ExprEvaluator::visitSRem(const SRemExpr &e) {
+ return protectedDivOperation(e);
+}
Added: klee/trunk/lib/Expr/ExprPPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/ExprPPrinter.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/ExprPPrinter.cpp (added)
+++ klee/trunk/lib/Expr/ExprPPrinter.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,478 @@
+//===-- ExprPPrinter.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/util/ExprPPrinter.h"
+
+#include "klee/Constraints.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#include <map>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+using namespace klee;
+
+namespace {
+ llvm::cl::opt<bool>
+ PCWidthAsArg("pc-width-as-arg", llvm::cl::init(true));
+
+ llvm::cl::opt<bool>
+ PCAllWidths("pc-all-widths", llvm::cl::init(false));
+
+ llvm::cl::opt<bool>
+ PCPrefixWidth("pc-prefix-width", llvm::cl::init(true));
+
+ llvm::cl::opt<bool>
+ PCMultibyteReads("pc-multibyte-reads", llvm::cl::init(true));
+
+ llvm::cl::opt<bool>
+ PCAllConstWidths("pc-all-const-widths", llvm::cl::init(false));
+}
+
+/// PrintContext - Helper class for storing extra information for
+/// the pretty printer.
+class PrintContext {
+private:
+ std::ostream &os;
+ std::stringstream ss;
+ std::string newline;
+
+public:
+ /// Number of characters on the current line.
+ unsigned pos;
+
+public:
+ PrintContext(std::ostream &_os) : os(_os), newline("\n"), pos(0) {}
+
+ void setNewline(const std::string &_newline) {
+ newline = _newline;
+ }
+
+ void breakLine(unsigned indent=0) {
+ os << newline;
+ if (indent)
+ os << std::setw(indent) << ' ';
+ pos = indent;
+ }
+
+ /// write - Output a string to the stream and update the
+ /// position. The stream should not have any newlines.
+ void write(const std::string &s) {
+ os << s;
+ pos += s.length();
+ }
+
+ template <typename T>
+ PrintContext &operator<<(T elt) {
+ ss.str("");
+ ss << elt;
+ write(ss.str());
+ return *this;
+ }
+};
+
+class PPrinter : public ExprPPrinter {
+ std::map<ref<Expr>, unsigned> bindings;
+ std::map<const UpdateNode*, unsigned> updateBindings;
+ std::set< ref<Expr> > couldPrint, shouldPrint;
+ std::set<const UpdateNode*> couldPrintUpdates, shouldPrintUpdates;
+ std::ostream &os;
+ unsigned counter;
+ unsigned updateCounter;
+ bool hasScan;
+ std::string newline;
+
+ /// shouldPrintWidth - Predicate for whether this expression should
+ /// be printed with its width.
+ bool shouldPrintWidth(ref<Expr> e) {
+ if (PCAllWidths)
+ return true;
+ return e.getWidth() != Expr::Bool;
+ }
+
+ bool isVerySimple(const ref<Expr> &e) {
+ return e.isConstant() || bindings.find(e)!=bindings.end();
+ }
+
+ bool isVerySimpleUpdate(const UpdateNode *un) {
+ return !un || updateBindings.find(un)!=updateBindings.end();
+ }
+
+
+ // document me!
+ bool isSimple(const ref<Expr> &e) {
+ if (isVerySimple(e)) {
+ return true;
+ } else if (const ReadExpr *re = dyn_ref_cast<ReadExpr>(e)) {
+ return isVerySimple(re->index) && isVerySimpleUpdate(re->updates.head);
+ } else {
+ Expr *ep = e.get();
+ for (unsigned i=0; i<ep->getNumKids(); i++)
+ if (!isVerySimple(ep->getKid(i)))
+ return false;
+ return true;
+ }
+ }
+
+ bool hasSimpleKids(const Expr *ep) {
+ for (unsigned i=0; i<ep->getNumKids(); i++)
+ if (!isSimple(ep->getKid(i)))
+ return false;
+ return true;
+ }
+
+ void scanUpdate(const UpdateNode *un) {
+ if (un) {
+ if (couldPrintUpdates.insert(un).second) {
+ scanUpdate(un->next);
+ scan1(un->index);
+ scan1(un->value);
+ } else {
+ shouldPrintUpdates.insert(un);
+ }
+ }
+ }
+
+ void scan1(const ref<Expr> &e) {
+ if (!e.isConstant()) {
+ if (couldPrint.insert(e).second) {
+ Expr *ep = e.get();
+ for (unsigned i=0; i<ep->getNumKids(); i++)
+ scan1(ep->getKid(i));
+ if (const ReadExpr *re = dyn_ref_cast<ReadExpr>(e))
+ scanUpdate(re->updates.head);
+ } else {
+ shouldPrint.insert(e);
+ }
+ }
+ }
+
+ void printUpdateList(const UpdateList &updates, PrintContext &PC) {
+ const UpdateNode *head = updates.head;
+
+ // Special case empty list.
+ if (!head) {
+ if (updates.isRooted) {
+ PC << "arr" << updates.root->id;
+ } else {
+ PC << "[]";
+ }
+ return;
+ }
+
+ // FIXME: Explain this breaking policy.
+ bool openedList = false, nextShouldBreak = false;
+ unsigned outerIndent = PC.pos;
+ unsigned middleIndent = 0;
+ for (const UpdateNode *un = head; un; un = un->next) {
+ // We are done if we hit the cache.
+ std::map<const UpdateNode*, unsigned>::iterator it =
+ updateBindings.find(un);
+ if (it!=updateBindings.end()) {
+ if (openedList)
+ PC << "] @ ";
+ PC << "U" << it->second;
+ return;
+ } else if (!hasScan || shouldPrintUpdates.count(un)) {
+ if (openedList)
+ PC << "] @";
+ if (un != head)
+ PC.breakLine(outerIndent);
+ PC << "U" << updateCounter << ":";
+ updateBindings.insert(std::make_pair(un, updateCounter++));
+ openedList = nextShouldBreak = false;
+ }
+
+ if (!openedList) {
+ openedList = 1;
+ PC << '[';
+ middleIndent = PC.pos;
+ } else {
+ PC << ',';
+ printSeparator(PC, !nextShouldBreak, middleIndent);
+ }
+ //PC << "(=";
+ //unsigned innerIndent = PC.pos;
+ print(un->index, PC);
+ //printSeparator(PC, isSimple(un->index), innerIndent);
+ PC << "=";
+ print(un->value, PC);
+ //PC << ')';
+
+ nextShouldBreak = !(un->index.isConstant() && un->value.isConstant());
+ }
+
+ if (openedList)
+ PC << ']';
+
+ if (updates.isRooted)
+ PC << " @ arr" << updates.root->id;
+ }
+
+ void printWidth(PrintContext &PC, ref<Expr> e) {
+ if (!shouldPrintWidth(e))
+ return;
+
+ if (PCWidthAsArg) {
+ PC << ' ';
+ if (PCPrefixWidth)
+ PC << 'w';
+ }
+
+ PC << e.getWidth();
+ }
+
+ /// hasOrderedReads - True iff all children are reads with
+ /// consecutive offsets according to the given \arg stride.
+ bool hasOrderedReads(const Expr *ep, int stride) {
+ const ReadExpr *base = dyn_ref_cast<ReadExpr>(ep->getKid(0));
+ if (!base)
+ return false;
+
+ // Get stride expr in proper index width.
+ Expr::Width idxWidth = base->index.getWidth();
+ ref<Expr> strideExpr(stride, idxWidth), offset(0, idxWidth);
+ for (unsigned i=1; i<ep->getNumKids(); ++i) {
+ const ReadExpr *re = dyn_ref_cast<ReadExpr>(ep->getKid(i));
+ if (!re)
+ return false;
+
+ // Check if the index follows the stride.
+ // FIXME: How aggressive should this be simplified. The
+ // canonicalizing builder is probably the right choice, but this
+ // is yet another area where we would really prefer it to be
+ // global or else use static methods.
+ offset = AddExpr::create(offset, strideExpr);
+ if (SubExpr::create(re->index, base->index) != offset)
+ return false;
+ }
+
+ return true;
+ }
+
+ /// hasAllByteReads - True iff all children are byte level reads.
+ bool hasAllByteReads(const Expr *ep) {
+ for (unsigned i=0; i<ep->getNumKids(); ++i) {
+ const ReadExpr *re = dyn_ref_cast<ReadExpr>(ep->getKid(i));
+ if (!re || re->getWidth() != Expr::Int8)
+ return false;
+ }
+ return true;
+ }
+
+ void printRead(const ReadExpr *re, PrintContext &PC, unsigned indent) {
+ print(re->index, PC);
+ printSeparator(PC, isVerySimple(re->index), indent);
+ printUpdateList(re->updates, PC);
+ }
+
+ void printExtract(const ExtractExpr *ee, PrintContext &PC, unsigned indent) {
+ PC << ee->offset << ' ';
+ print(ee->expr, PC);
+ }
+
+ void printExpr(const Expr *ep, PrintContext &PC, unsigned indent, bool printConstWidth=false) {
+ bool simple = hasSimpleKids(ep);
+
+ print(ep->getKid(0), PC);
+ for (unsigned i=1; i<ep->getNumKids(); i++) {
+ printSeparator(PC, simple, indent);
+ print(ep->getKid(i), PC, printConstWidth);
+ }
+ }
+
+public:
+ PPrinter(std::ostream &_os) : os(_os), newline("\n") {
+ reset();
+ }
+
+ void setNewline(const std::string &_newline) {
+ newline = _newline;
+ }
+
+ void reset() {
+ counter = 0;
+ updateCounter = 0;
+ hasScan = false;
+ bindings.clear();
+ updateBindings.clear();
+ couldPrint.clear();
+ shouldPrint.clear();
+ couldPrintUpdates.clear();
+ shouldPrintUpdates.clear();
+ }
+
+ void scan(const ref<Expr> &e) {
+ hasScan = true;
+ scan1(e);
+ }
+
+ void print(const ref<Expr> &e, unsigned level=0) {
+ PrintContext PC(os);
+ PC.pos = level;
+ print(e, PC);
+ }
+
+ void printConst(const ref<Expr> &e, PrintContext &PC, bool printWidth) {
+ assert(e.isConstant());
+
+ if (e.getWidth() == Expr::Bool)
+ PC << (e.getConstantValue() ? "true" : "false");
+ else {
+ if (PCAllConstWidths)
+ printWidth = true;
+
+ if (printWidth)
+ PC << "(w" << e.getWidth() << " ";
+
+ PC << e.getConstantValue();
+
+ if (printWidth)
+ PC << ")";
+ }
+ }
+
+ void print(const ref<Expr> &e, PrintContext &PC, bool printConstWidth=false) {
+ if (e.isConstant())
+ printConst(e, PC, printConstWidth);
+ else {
+ std::map<ref<Expr>, unsigned>::iterator it = bindings.find(e);
+ if (it!=bindings.end()) {
+ PC << 'N' << it->second;
+ } else {
+ if (!hasScan || shouldPrint.count(e)) {
+ PC << 'N' << counter << ':';
+ bindings.insert(std::make_pair(e, counter++));
+ }
+
+ // Detect Not.
+ // FIXME: This should be in common code.
+ if (const EqExpr *ee = dyn_ref_cast<EqExpr>(e)) {
+ if (ee->left == ref<Expr>(false, Expr::Bool)) {
+ PC << "(Not";
+ printWidth(PC, e);
+ PC << ' ';
+ // FIXME: This is a boom if right is a constant.
+ print(ee->right, PC);
+ PC << ')';
+ return;
+ }
+ }
+
+ // Detect multibyte reads.
+ // FIXME: Hrm. One problem with doing this is that we are
+ // masking the sharing of the indices which aren't
+ // visible. Need to think if this matters... probably not
+ // because if they are offset reads then its either constant,
+ // or they are (base + offset) and base will get printed with
+ // a declaration.
+ if (PCMultibyteReads && e.getKind() == Expr::Concat) {
+ const Expr *ep = e.get();
+ if (hasAllByteReads(ep)) {
+ bool isMSB = hasOrderedReads(ep, 1);
+ if (isMSB || hasOrderedReads(ep, -1)) {
+ PC << "(Read" << (isMSB ? "MSB" : "LSB");
+ printWidth(PC, e);
+ PC << ' ';
+ unsigned firstIdx = isMSB ? 0 : ep->getNumKids()-1;
+ printRead(static_ref_cast<ReadExpr>(ep->getKid(firstIdx)),
+ PC, PC.pos);
+ PC << ')';
+ return;
+ }
+ }
+ }
+
+ PC << '(' << e.getKind();
+ printWidth(PC, e);
+ PC << ' ';
+
+ // Indent at first argument and dispatch to appropriate print
+ // routine for exprs which require special handling.
+ unsigned indent = PC.pos;
+ if (const ReadExpr *re = dyn_ref_cast<ReadExpr>(e)) {
+ printRead(re, PC, indent);
+ } else if (const ExtractExpr *ee = dyn_ref_cast<ExtractExpr>(e)) {
+ printExtract(ee, PC, indent);
+ } else if (e.getKind() == Expr::Concat || e.getKind() == Expr::SExt)
+ printExpr(e.get(), PC, indent, true);
+ else
+ printExpr(e.get(), PC, indent);
+ PC << ")";
+ }
+ }
+ }
+
+ /* Public utility functions */
+
+ void printSeparator(PrintContext &PC, bool simple, unsigned indent) {
+ if (simple) {
+ PC << ' ';
+ } else {
+ PC.breakLine(indent);
+ }
+ }
+};
+
+ExprPPrinter *klee::ExprPPrinter::create(std::ostream &os) {
+ return new PPrinter(os);
+}
+
+void ExprPPrinter::printOne(std::ostream &os,
+ const char *message,
+ const ref<Expr> &e) {
+ PPrinter p(os);
+ p.scan(e);
+
+ // FIXME: Need to figure out what to do here. Probably print as a
+ // "forward declaration" with whatever syntax we pick for that.
+ PrintContext PC(os);
+ PC << message << ": ";
+ p.print(e, PC);
+ PC.breakLine();
+}
+
+void ExprPPrinter::printConstraints(std::ostream &os,
+ const ConstraintManager &constraints) {
+ printQuery(os, constraints, ref<Expr>(false, Expr::Bool));
+}
+
+void ExprPPrinter::printQuery(std::ostream &os,
+ const ConstraintManager &constraints,
+ const ref<Expr> &q) {
+ PPrinter p(os);
+
+ for (ConstraintManager::const_iterator it = constraints.begin(),
+ ie = constraints.end(); it != ie; ++it)
+ p.scan(*it);
+ p.scan(q);
+
+ PrintContext PC(os);
+ PC << "(query [";
+
+ // Ident at constraint list;
+ unsigned indent = PC.pos;
+ for (ConstraintManager::const_iterator it = constraints.begin(),
+ ie = constraints.end(); it != ie;) {
+ p.print(*it, PC);
+ ++it;
+ if (it != ie)
+ PC.breakLine(indent);
+ }
+ PC << ']';
+
+ p.printSeparator(PC, constraints.empty(), indent-1);
+ p.print(q, PC);
+
+ PC << ')';
+ PC.breakLine();
+}
Added: klee/trunk/lib/Expr/ExprUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/ExprUtil.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/ExprUtil.cpp (added)
+++ klee/trunk/lib/Expr/ExprUtil.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,127 @@
+//===-- ExprUtil.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/util/ExprUtil.h"
+#include "klee/util/ExprHashMap.h"
+
+#include "klee/Expr.h"
+
+#include "klee/util/ExprVisitor.h"
+
+#include <set>
+
+using namespace klee;
+
+void klee::findReads(ref<Expr> e,
+ bool visitUpdates,
+ std::vector< ref<ReadExpr> > &results) {
+ // Invariant: \forall_{i \in stack} !i.isConstant() && i \in visited
+ std::vector< ref<Expr> > stack;
+ ExprHashSet visited;
+ std::set<const UpdateNode *> updates;
+
+ if (!e.isConstant()) {
+ visited.insert(e);
+ stack.push_back(e);
+ }
+
+ while (!stack.empty()) {
+ ref<Expr> top = stack.back();
+ stack.pop_back();
+
+ if (ReadExpr *re = dyn_ref_cast<ReadExpr>(top)) {
+ // We memoized so can just add to list without worrying about
+ // repeats.
+ results.push_back(re);
+
+ if (!re->index.isConstant() &&
+ visited.insert(re->index).second)
+ stack.push_back(re->index);
+
+ if (visitUpdates) {
+ // XXX this is probably suboptimal. We want to avoid a potential
+ // explosion traversing update lists which can be quite
+ // long. However, it seems silly to hash all of the update nodes
+ // especially since we memoize all the expr results anyway. So
+ // we take a simple approach of memoizing the results for the
+ // head, which often will be shared among multiple nodes.
+ if (updates.insert(re->updates.head).second) {
+ for (const UpdateNode *un=re->updates.head; un; un=un->next) {
+ if (!un->index.isConstant() &&
+ visited.insert(un->index).second)
+ stack.push_back(un->index);
+ if (!un->value.isConstant() &&
+ visited.insert(un->value).second)
+ stack.push_back(un->value);
+ }
+ }
+ }
+ } else if (!top.isConstant()) {
+ Expr *e = top.get();
+ for (unsigned i=0; i<e->getNumKids(); i++) {
+ ref<Expr> k = e->getKid(i);
+ if (!k.isConstant() &&
+ visited.insert(k).second)
+ stack.push_back(k);
+ }
+ }
+ }
+}
+
+///
+
+namespace klee {
+
+class SymbolicObjectFinder : public ExprVisitor {
+protected:
+ Action visitRead(const ReadExpr &re) {
+ const UpdateList &ul = re.updates;
+
+ // XXX should we memo better than what ExprVisitor is doing for us?
+ for (const UpdateNode *un=ul.head; un; un=un->next) {
+ visit(un->index);
+ visit(un->value);
+ }
+
+ if (ul.isRooted)
+ if (results.insert(ul.root).second)
+ objects.push_back(ul.root);
+
+ return Action::doChildren();
+ }
+
+public:
+ std::set<const Array*> results;
+ std::vector<const Array*> &objects;
+
+ SymbolicObjectFinder(std::vector<const Array*> &_objects)
+ : objects(_objects) {}
+};
+
+}
+
+template<typename InputIterator>
+void klee::findSymbolicObjects(InputIterator begin,
+ InputIterator end,
+ std::vector<const Array*> &results) {
+ SymbolicObjectFinder of(results);
+ for (; begin!=end; ++begin)
+ of.visit(*begin);
+}
+
+void klee::findSymbolicObjects(ref<Expr> e,
+ std::vector<const Array*> &results) {
+ findSymbolicObjects(&e, &e+1, results);
+}
+
+typedef std::vector< ref<Expr> >::iterator A;
+template void klee::findSymbolicObjects<A>(A, A, std::vector<const Array*> &);
+
+typedef std::set< ref<Expr> >::iterator B;
+template void klee::findSymbolicObjects<B>(B, B, std::vector<const Array*> &);
Added: klee/trunk/lib/Expr/ExprVisitor.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/ExprVisitor.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/ExprVisitor.cpp (added)
+++ klee/trunk/lib/Expr/ExprVisitor.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,253 @@
+//===-- ExprVisitor.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/Expr.h"
+#include "klee/util/ExprVisitor.h"
+
+#include "llvm/Support/CommandLine.h"
+
+namespace {
+ llvm::cl::opt<bool>
+ UseVisitorHash("use-visitor-hash",
+ llvm::cl::desc("Use hash-consing during expr visitation."),
+ llvm::cl::init(true));
+}
+
+using namespace klee;
+
+ref<Expr> ExprVisitor::visit(const ref<Expr> &e) {
+ if (!UseVisitorHash || e.isConstant()) {
+ return visitActual(e);
+ } else {
+ visited_ty::iterator it = visited.find(e);
+
+ if (it!=visited.end()) {
+ return it->second;
+ } else {
+ ref<Expr> res = visitActual(e);
+ visited.insert(std::make_pair(e, res));
+ return res;
+ }
+ }
+}
+
+ref<Expr> ExprVisitor::visitActual(const ref<Expr> &e) {
+ if (e.isConstant()) {
+ return e;
+ } else {
+ Expr &ep = *e.get();
+
+ Action res = visitExpr(ep);
+ switch(res.kind) {
+ case Action::DoChildren:
+ // continue with normal action
+ break;
+ case Action::SkipChildren:
+ return e;
+ case Action::ChangeTo:
+ return res.argument;
+ }
+
+ switch(ep.getKind()) {
+ case Expr::NotOptimized: res = visitNotOptimized(static_cast<NotOptimizedExpr&>(ep)); break;
+ case Expr::Read: res = visitRead(static_cast<ReadExpr&>(ep)); break;
+ case Expr::Select: res = visitSelect(static_cast<SelectExpr&>(ep)); break;
+ case Expr::Concat: res = visitConcat(static_cast<ConcatExpr&>(ep)); break;
+ case Expr::Extract: res = visitExtract(static_cast<ExtractExpr&>(ep)); break;
+ case Expr::ZExt: res = visitZExt(static_cast<ZExtExpr&>(ep)); break;
+ case Expr::SExt: res = visitSExt(static_cast<SExtExpr&>(ep)); break;
+ case Expr::Add: res = visitAdd(static_cast<AddExpr&>(ep)); break;
+ case Expr::Sub: res = visitSub(static_cast<SubExpr&>(ep)); break;
+ case Expr::Mul: res = visitMul(static_cast<MulExpr&>(ep)); break;
+ case Expr::UDiv: res = visitUDiv(static_cast<UDivExpr&>(ep)); break;
+ case Expr::SDiv: res = visitSDiv(static_cast<SDivExpr&>(ep)); break;
+ case Expr::URem: res = visitURem(static_cast<URemExpr&>(ep)); break;
+ case Expr::SRem: res = visitSRem(static_cast<SRemExpr&>(ep)); break;
+ case Expr::And: res = visitAnd(static_cast<AndExpr&>(ep)); break;
+ case Expr::Or: res = visitOr(static_cast<OrExpr&>(ep)); break;
+ case Expr::Xor: res = visitXor(static_cast<XorExpr&>(ep)); break;
+ case Expr::Shl: res = visitShl(static_cast<ShlExpr&>(ep)); break;
+ case Expr::LShr: res = visitLShr(static_cast<LShrExpr&>(ep)); break;
+ case Expr::AShr: res = visitAShr(static_cast<AShrExpr&>(ep)); break;
+ case Expr::Eq: res = visitEq(static_cast<EqExpr&>(ep)); break;
+ case Expr::Ne: res = visitNe(static_cast<NeExpr&>(ep)); break;
+ case Expr::Ult: res = visitUlt(static_cast<UltExpr&>(ep)); break;
+ case Expr::Ule: res = visitUle(static_cast<UleExpr&>(ep)); break;
+ case Expr::Ugt: res = visitUgt(static_cast<UgtExpr&>(ep)); break;
+ case Expr::Uge: res = visitUge(static_cast<UgeExpr&>(ep)); break;
+ case Expr::Slt: res = visitSlt(static_cast<SltExpr&>(ep)); break;
+ case Expr::Sle: res = visitSle(static_cast<SleExpr&>(ep)); break;
+ case Expr::Sgt: res = visitSgt(static_cast<SgtExpr&>(ep)); break;
+ case Expr::Sge: res = visitSge(static_cast<SgeExpr&>(ep)); break;
+ case Expr::Constant:
+ default:
+ assert(0 && "invalid expression kind");
+ }
+
+ switch(res.kind) {
+ case Action::DoChildren: {
+ bool rebuild = false;
+ ref<Expr> e(&ep), kids[8];
+ unsigned count = ep.getNumKids();
+ for (unsigned i=0; i<count; i++) {
+ ref<Expr> kid = ep.getKid(i);
+ kids[i] = visit(kid);
+ if (kids[i] != kid)
+ rebuild = true;
+ }
+ if (rebuild) {
+ e = ep.rebuild(kids);
+ if (recursive)
+ e = visit(e);
+ }
+ if (!e.isConstant()) {
+ res = visitExprPost(*e.get());
+ if (res.kind==Action::ChangeTo)
+ e = res.argument;
+ }
+ return e;
+ }
+ case Action::SkipChildren:
+ return e;
+ case Action::ChangeTo:
+ return res.argument;
+ default:
+ assert(0 && "invalid kind");
+ }
+ }
+}
+
+ExprVisitor::Action ExprVisitor::visitExpr(const Expr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitExprPost(const Expr&) {
+ return Action::skipChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitNotOptimized(const NotOptimizedExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitRead(const ReadExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSelect(const SelectExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitConcat(const ConcatExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitExtract(const ExtractExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitZExt(const ZExtExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSExt(const SExtExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitAdd(const AddExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSub(const SubExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitMul(const MulExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitUDiv(const UDivExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSDiv(const SDivExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitURem(const URemExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSRem(const SRemExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitAnd(const AndExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitOr(const OrExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitXor(const XorExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitShl(const ShlExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitLShr(const LShrExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitAShr(const AShrExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitEq(const EqExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitNe(const NeExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitUlt(const UltExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitUle(const UleExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitUgt(const UgtExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitUge(const UgeExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSlt(const SltExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSle(const SleExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSgt(const SgtExpr&) {
+ return Action::doChildren();
+}
+
+ExprVisitor::Action ExprVisitor::visitSge(const SgeExpr&) {
+ return Action::doChildren();
+}
+
Added: klee/trunk/lib/Expr/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/Lexer.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/Lexer.cpp (added)
+++ klee/trunk/lib/Expr/Lexer.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,261 @@
+//===-- Lexer.cpp ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "expr/Lexer.h"
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+
+#include <iomanip>
+#include <iostream>
+#include <string.h>
+
+using namespace llvm;
+using namespace klee;
+using namespace klee::expr;
+
+///
+
+const char *Token::getKindName() const {
+ switch (kind) {
+ default:
+ case Unknown: return "Unknown";
+ case Arrow: return "Arrow";
+ case At: return "At";
+ case Colon: return "Colon";
+ case Comma: return "Comma";
+ case Comment: return "Comment";
+ case EndOfFile: return "EndOfFile";
+ case Equals: return "Equals";
+ case Identifier: return "Identifier";
+ case KWFalse: return "KWFalse";
+ case KWQuery: return "KWQuery";
+ case KWReserved: return "KWReserved";
+ case KWTrue: return "KWTrue";
+ case KWWidth: return "KWWidth";
+ case LBrace: return "LBrace";
+ case LParen: return "LParen";
+ case LSquare: return "LSquare";
+ case Number: return "Number";
+ case RBrace: return "RBrace";
+ case RParen: return "RParen";
+ case RSquare: return "RSquare";
+ case Semicolon: return "Semicolon";
+ }
+}
+
+void Token::dump() {
+ llvm::cerr << "(Token \"" << getKindName() << "\" "
+ << (void*) start << " " << length << " "
+ << line << " " << column << ")";
+}
+
+///
+
+static inline bool isInternalIdentifierChar(int Char) {
+ return isalnum(Char) || Char == '_' || Char == '.';
+}
+
+Lexer::Lexer(const llvm::MemoryBuffer *MB)
+ : BufferPos(MB->getBufferStart()), BufferEnd(MB->getBufferEnd()),
+ LineNumber(1), ColumnNumber(0) {
+}
+
+Lexer::~Lexer() {
+}
+
+int Lexer::PeekNextChar() {
+ if (BufferPos == BufferEnd)
+ return -1;
+ return *BufferPos;
+}
+
+int Lexer::GetNextChar() {
+ if (BufferPos == BufferEnd)
+ return -1;
+
+ // Handle DOS/Mac newlines here, by stripping duplicates and by
+ // returning '\n' for both.
+ char Result = *BufferPos++;
+ if (Result == '\n' || Result == '\r') {
+ if (BufferPos != BufferEnd && *BufferPos == ('\n' + '\r' - Result))
+ ++BufferPos;
+ Result = '\n';
+ }
+
+ if (Result == '\n') {
+ ++LineNumber;
+ ColumnNumber = 0;
+ } else {
+ ++ColumnNumber;
+ }
+
+ return Result;
+}
+
+Token &Lexer::SetTokenKind(Token &Result, Token::Kind k) {
+ Result.kind = k;
+ Result.length = BufferPos - Result.start;
+ return Result;
+}
+
+static bool isReservedKW(const char *Str, unsigned N) {
+ unsigned i;
+
+ // Check for i[0-9]+
+ if (N>1 && Str[0] == 'i') {
+ for (i=1; i<N; ++i)
+ if (!isdigit(Str[i]))
+ break;
+ if (i==N)
+ return true;
+ }
+
+ // Check for fp[0-9]+([.].*)?$
+ if (N>3 && Str[0]=='f' && Str[1]=='p' && isdigit(Str[2])) {
+ for (i=3; i<N; ++i)
+ if (!isdigit(Str[i]))
+ break;
+ if (i==N || Str[i]=='.')
+ return true;
+ }
+
+ return false;
+}
+static bool isWidthKW(const char *Str, unsigned N) {
+ if (N<2 || Str[0] != 'w')
+ return false;
+ for (unsigned i=1; i<N; ++i)
+ if (!isdigit(Str[i]))
+ return false;
+ return true;
+}
+Token &Lexer::SetIdentifierTokenKind(Token &Result) {
+ unsigned Length = BufferPos - Result.start;
+ switch (Length) {
+ case 3:
+ if (memcmp("def", Result.start, 3) == 0)
+ return SetTokenKind(Result, Token::KWReserved);
+ if (memcmp("var", Result.start, 3) == 0)
+ return SetTokenKind(Result, Token::KWReserved);
+ break;
+
+ case 4:
+ if (memcmp("true", Result.start, 4) == 0)
+ return SetTokenKind(Result, Token::KWTrue);
+ break;
+
+ case 5:
+ if (memcmp("array", Result.start, 5) == 0)
+ return SetTokenKind(Result, Token::KWReserved);
+ if (memcmp("false", Result.start, 5) == 0)
+ return SetTokenKind(Result, Token::KWFalse);
+ if (memcmp("query", Result.start, 5) == 0)
+ return SetTokenKind(Result, Token::KWQuery);
+ break;
+
+ case 6:
+ if (memcmp("define", Result.start, 6) == 0)
+ return SetTokenKind(Result, Token::KWReserved);
+ break;
+
+ case 7:
+ if (memcmp("declare", Result.start, 7) == 0)
+ return SetTokenKind(Result, Token::KWReserved);
+ break;
+ }
+
+ if (isReservedKW(Result.start, Length))
+ return SetTokenKind(Result, Token::KWReserved);
+ if (isWidthKW(Result.start, Length))
+ return SetTokenKind(Result, Token::KWWidth);
+
+ return SetTokenKind(Result, Token::Identifier);
+}
+
+void Lexer::SkipToEndOfLine() {
+ for (;;) {
+ int Char = GetNextChar();
+ if (Char == -1 || Char =='\n')
+ break;
+ }
+}
+
+Token &Lexer::LexNumber(Token &Result) {
+ while (isalnum(PeekNextChar()) || PeekNextChar()=='_')
+ GetNextChar();
+ return SetTokenKind(Result, Token::Number);
+}
+
+Token &Lexer::LexIdentifier(Token &Result) {
+ while (isInternalIdentifierChar(PeekNextChar()))
+ GetNextChar();
+
+ // Recognize keywords specially.
+ return SetIdentifierTokenKind(Result);
+}
+
+Token &Lexer::Lex(Token &Result) {
+ Result.kind = Token::Unknown;
+ Result.length = 0;
+ Result.start = BufferPos;
+
+ // Skip whitespace.
+ while (isspace(PeekNextChar()))
+ GetNextChar();
+
+ Result.start = BufferPos;
+ Result.line = LineNumber;
+ Result.column = ColumnNumber;
+ int Char = GetNextChar();
+ switch (Char) {
+ case -1: return SetTokenKind(Result, Token::EndOfFile);
+
+ case '(': return SetTokenKind(Result, Token::LParen);
+ case ')': return SetTokenKind(Result, Token::RParen);
+ case ',': return SetTokenKind(Result, Token::Comma);
+ case ':': return SetTokenKind(Result, Token::Colon);
+ case ';': return SetTokenKind(Result, Token::Semicolon);
+ case '=': return SetTokenKind(Result, Token::Equals);
+ case '@': return SetTokenKind(Result, Token::At);
+ case '[': return SetTokenKind(Result, Token::LSquare);
+ case ']': return SetTokenKind(Result, Token::RSquare);
+ case '{': return SetTokenKind(Result, Token::LBrace);
+ case '}': return SetTokenKind(Result, Token::RBrace);
+
+ case '#':
+ SkipToEndOfLine();
+ return SetTokenKind(Result, Token::Comment);
+
+ case '+': {
+ if (isdigit(PeekNextChar()))
+ return LexNumber(Result);
+ else
+ return SetTokenKind(Result, Token::Unknown);
+ }
+
+ case '-': {
+ int Next = PeekNextChar();
+ if (Next == '>')
+ return GetNextChar(), SetTokenKind(Result, Token::Arrow);
+ else if (isdigit(Next))
+ return LexNumber(Result);
+ else
+ return SetTokenKind(Result, Token::Unknown);
+ break;
+ }
+
+ default:
+ if (isdigit(Char))
+ return LexNumber(Result);
+ else if (isalpha(Char) || Char == '_')
+ return LexIdentifier(Result);
+ return SetTokenKind(Result, Token::Unknown);
+ }
+}
Added: klee/trunk/lib/Expr/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/Makefile (added)
+++ klee/trunk/lib/Expr/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+#===-- lib/Expr/Makefile -----------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleaverExpr
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+
+include $(LEVEL)/Makefile.common
Added: klee/trunk/lib/Expr/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/Parser.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/Parser.cpp (added)
+++ klee/trunk/lib/Expr/Parser.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1310 @@
+//===-- Parser.cpp --------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "expr/Parser.h"
+
+#include "expr/Lexer.h"
+
+#include "klee/Constraints.h"
+#include "klee/Solver.h"
+#include "klee/util/ExprPPrinter.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+
+#include <cassert>
+#include <iostream>
+#include <map>
+
+using namespace llvm;
+using namespace klee;
+using namespace klee::expr;
+
+namespace {
+ /// ParseResult - Represent a possibly invalid parse result.
+ template<typename T>
+ struct ParseResult {
+ bool IsValid;
+ T Value;
+
+ public:
+ ParseResult() : IsValid(false) {}
+ ParseResult(T _Value) : IsValid(true), Value(_Value) {}
+ ParseResult(bool _IsValid, T _Value) : IsValid(_IsValid), Value(_Value) {}
+
+ bool isValid() {
+ return IsValid;
+ }
+ T get() {
+ assert(IsValid && "get() on invalid ParseResult!");
+ return Value;
+ }
+ };
+
+ typedef ParseResult<Decl*> DeclResult;
+ typedef ParseResult<ExprHandle> ExprResult;
+ typedef ParseResult<Expr::Width> TypeResult;
+ typedef ParseResult<VersionHandle> VersionResult;
+
+ /// NumberOrExprResult - Represent a number or expression. This is used to
+ /// wrap an expression production which may be a number, but for
+ /// which the type width is unknown.
+ class NumberOrExprResult {
+ Token AsNumber;
+ ExprResult AsExpr;
+ bool IsNumber;
+
+ public:
+ NumberOrExprResult() : IsNumber(false) {}
+ explicit NumberOrExprResult(Token _AsNumber) : AsNumber(_AsNumber),
+ IsNumber(true) {}
+ explicit NumberOrExprResult(ExprResult _AsExpr) : AsExpr(_AsExpr),
+ IsNumber(false) {}
+
+ bool isNumber() const { return IsNumber; }
+ const Token &getNumber() const {
+ assert(IsNumber && "Invalid accessor call.");
+ return AsNumber;
+ }
+ const ExprResult &getExpr() const {
+ assert(!IsNumber && "Invalid accessor call.");
+ return AsExpr;
+ }
+ };
+
+ /// ParserImpl - Parser implementation.
+ class ParserImpl : public Parser {
+ typedef std::map<const std::string, const Identifier*> IdentifierTabTy;
+ typedef std::map<const Identifier*, ExprHandle> ExprSymTabTy;
+ typedef std::map<const Identifier*, VersionHandle> VersionSymTabTy;
+
+ const std::string Filename;
+ const MemoryBuffer *TheMemoryBuffer;
+ Lexer TheLexer;
+ unsigned MaxErrors;
+ unsigned NumErrors;
+
+ // FIXME: Use LLVM symbol tables?
+ IdentifierTabTy IdentifierTab;
+
+ std::map<const Identifier*, const ArrayDecl*> ArraySymTab;
+ ExprSymTabTy ExprSymTab;
+ VersionSymTabTy VersionSymTab;
+
+ /// Tok - The currently lexed token.
+ Token Tok;
+
+ /// ParenLevel - The current depth of matched '(' tokens.
+ unsigned ParenLevel;
+ /// SquareLevel - The current depth of matched '[' tokens.
+ unsigned SquareLevel;
+
+ /* Core parsing functionality */
+
+ const Identifier *GetOrCreateIdentifier(const Token &Tok);
+
+ void GetNextNonCommentToken() {
+ do {
+ TheLexer.Lex(Tok);
+ } while (Tok.kind == Token::Comment);
+ }
+
+ /// ConsumeToken - Consume the current 'peek token' and lex the next one.
+ void ConsumeToken() {
+ assert(Tok.kind != Token::LParen && Tok.kind != Token::RParen);
+ GetNextNonCommentToken();
+ }
+
+ /// ConsumeExpectedToken - Check that the current token is of the
+ /// expected kind and consume it.
+ void ConsumeExpectedToken(Token::Kind k) {
+ assert(Tok.kind == k && "Unexpected token!");
+ GetNextNonCommentToken();
+ }
+
+ void ConsumeLParen() {
+ ++ParenLevel;
+ ConsumeExpectedToken(Token::LParen);
+ }
+
+ void ConsumeRParen() {
+ if (ParenLevel) // Cannot go below zero.
+ --ParenLevel;
+ ConsumeExpectedToken(Token::RParen);
+ }
+
+ void ConsumeLSquare() {
+ ++SquareLevel;
+ ConsumeExpectedToken(Token::LSquare);
+ }
+
+ void ConsumeRSquare() {
+ if (SquareLevel) // Cannot go below zero.
+ --SquareLevel;
+ ConsumeExpectedToken(Token::RSquare);
+ }
+
+ void ConsumeAnyToken() {
+ switch (Tok.kind) {
+ case Token::LParen: return ConsumeLParen();
+ case Token::RParen: return ConsumeRParen();
+ case Token::LSquare: return ConsumeLSquare();
+ case Token::RSquare: return ConsumeRSquare();
+ default:
+ return ConsumeToken();
+ }
+ }
+
+ /* Utility functions */
+
+ /// SkipUntilRParen - Scan forward to the next token following an
+ /// rparen at the given level, or EOF, whichever is first.
+ void SkipUntilRParen(unsigned Level) {
+ // FIXME: I keep wavering on whether it is an error to call this
+ // with the current token an rparen. In most cases this should
+ // have been handled differently (error reported,
+ // whatever). Audit & resolve.
+ assert(Level <= ParenLevel &&
+ "Refusing to skip until rparen at higher level.");
+ while (Tok.kind != Token::EndOfFile) {
+ if (Tok.kind == Token::RParen && ParenLevel == Level) {
+ ConsumeRParen();
+ break;
+ }
+ ConsumeAnyToken();
+ }
+ }
+
+ /// SkipUntilRParen - Scan forward until reaching an rparen token
+ /// at the current level (or EOF).
+ void SkipUntilRParen() {
+ SkipUntilRParen(ParenLevel);
+ }
+
+ /// ExpectRParen - Utility method to close an sexp. This expects to
+ /// eat an rparen, and emits a diagnostic and skips to the next one
+ /// (or EOF) if it cannot.
+ void ExpectRParen(const char *Msg) {
+ if (Tok.kind == Token::EndOfFile) {
+ // FIXME: Combine with Msg
+ Error("expected ')' but found end-of-file.", Tok);
+ } else if (Tok.kind != Token::RParen) {
+ Error(Msg, Tok);
+ SkipUntilRParen();
+ } else {
+ ConsumeRParen();
+ }
+ }
+
+ /// SkipUntilRSquare - Scan forward to the next token following an
+ /// rsquare at the given level, or EOF, whichever is first.
+ void SkipUntilRSquare(unsigned Level) {
+ // FIXME: I keep wavering on whether it is an error to call this
+ // with the current token an rparen. In most cases this should
+ // have been handled differently (error reported,
+ // whatever). Audit & resolve.
+ assert(Level <= ParenLevel &&
+ "Refusing to skip until rparen at higher level.");
+ while (Tok.kind != Token::EndOfFile) {
+ if (Tok.kind == Token::RSquare && ParenLevel == Level) {
+ ConsumeRSquare();
+ break;
+ }
+ ConsumeAnyToken();
+ }
+ }
+
+ /// SkipUntilRSquare - Scan forward until reaching an rsquare token
+ /// at the current level (or EOF).
+ void SkipUntilRSquare() {
+ SkipUntilRSquare(ParenLevel);
+ }
+
+ /// ExpectRSquare - Utility method to close an array. This expects
+ /// to eat an rparen, and emits a diagnostic and skips to the next
+ /// one (or EOF) if it cannot.
+ void ExpectRSquare(const char *Msg) {
+ if (Tok.kind == Token::EndOfFile) {
+ // FIXME: Combine with Msg
+ Error("expected ']' but found end-of-file.", Tok);
+ } else if (Tok.kind != Token::RSquare) {
+ Error(Msg, Tok);
+ SkipUntilRSquare();
+ } else {
+ ConsumeRSquare();
+ }
+ }
+
+ /*** Grammar productions ****/
+
+ /* Top level decls */
+
+ DeclResult ParseArrayDecl();
+ DeclResult ParseExprVarDecl();
+ DeclResult ParseVersionVarDecl();
+ DeclResult ParseCommandDecl();
+
+ /* Commands */
+
+ DeclResult ParseQueryCommand();
+
+ /* Etc. */
+
+ NumberOrExprResult ParseNumberOrExpr();
+
+ ExprResult ParseExpr(TypeResult ExpectedType);
+ ExprResult ParseParenExpr(TypeResult ExpectedType);
+ ExprResult ParseUnaryParenExpr(const Token &Name,
+ unsigned Kind, bool IsFixed,
+ Expr::Width ResTy);
+ ExprResult ParseBinaryParenExpr(const Token &Name,
+ unsigned Kind, bool IsFixed,
+ Expr::Width ResTy);
+ ExprResult ParseSelectParenExpr(const Token &Name, Expr::Width ResTy);
+ ExprResult ParseConcatParenExpr(const Token &Name, Expr::Width ResTy);
+ ExprResult ParseExtractParenExpr(const Token &Name, Expr::Width ResTy);
+ ExprResult ParseAnyReadParenExpr(const Token &Name,
+ unsigned Kind,
+ Expr::Width ResTy);
+ void ParseMatchedBinaryArgs(const Token &Name,
+ TypeResult ExpectType,
+ ExprResult &LHS, ExprResult &RHS);
+ ExprResult ParseNumber(Expr::Width Width);
+ ExprResult ParseNumberToken(Expr::Width Width, const Token &Tok);
+
+ VersionResult ParseVersionSpecifier();
+ VersionResult ParseVersion();
+
+ TypeResult ParseTypeSpecifier();
+
+ /*** Diagnostics ***/
+
+ void Error(const char *Message, const Token &At);
+ void Error(const char *Message) { Error(Message, Tok); }
+
+ public:
+ ParserImpl(const std::string _Filename,
+ const MemoryBuffer *MB) : Filename(_Filename),
+ TheMemoryBuffer(MB),
+ TheLexer(MB),
+ MaxErrors(~0u),
+ NumErrors(0) {}
+
+ /// Initialize - Initialize the parsing state. This must be called
+ /// prior to the start of parsing.
+ void Initialize() {
+ ParenLevel = SquareLevel = 0;
+
+ ConsumeAnyToken();
+ }
+
+ /* Parser interface implementation */
+
+ virtual Decl *ParseTopLevelDecl();
+
+ virtual void SetMaxErrors(unsigned N) {
+ MaxErrors = N;
+ }
+
+ virtual unsigned GetNumErrors() const {
+ return NumErrors;
+ }
+ };
+}
+
+const Identifier *ParserImpl::GetOrCreateIdentifier(const Token &Tok) {
+ // FIXME: Make not horribly inefficient please.
+ assert(Tok.kind == Token::Identifier && "Expected only identifier tokens.");
+ std::string Name(Tok.start, Tok.length);
+ IdentifierTabTy::iterator it = IdentifierTab.find(Name);
+ if (it != IdentifierTab.end())
+ return it->second;
+
+ Identifier *I = new Identifier(Name);
+ IdentifierTab.insert(std::make_pair(Name, I));
+
+ return I;
+}
+
+Decl *ParserImpl::ParseTopLevelDecl() {
+ // Repeat until success or EOF.
+ while (Tok.kind != Token::EndOfFile) {
+ // Only handle commands for now.
+ if (Tok.kind == Token::LParen) {
+ DeclResult Res = ParseCommandDecl();
+ if (Res.isValid())
+ return Res.get();
+ } else {
+ Error("expected '(' token.");
+ ConsumeAnyToken();
+ }
+ }
+
+ return 0;
+}
+
+/// ParseCommandDecl - Parse a command declaration. The lexer should
+/// be positioned at the opening '('.
+///
+/// command = '(' name ... ')'
+DeclResult ParserImpl::ParseCommandDecl() {
+ ConsumeLParen();
+
+ if (!Tok.isKeyword()) {
+ Error("malformed command.");
+ SkipUntilRParen();
+ return DeclResult();
+ }
+
+ switch (Tok.kind) {
+ case Token::KWQuery:
+ return ParseQueryCommand();
+
+ default:
+ Error("malformed command (unexpected keyword).");
+ SkipUntilRParen();
+ return DeclResult();
+ }
+}
+
+/// ParseQueryCommand - Parse query command. The lexer should be
+/// positioned at the 'query' keyword.
+///
+/// 'query' expressions-list expression [expression-list [array-list]]
+DeclResult ParserImpl::ParseQueryCommand() {
+ // FIXME: We need a command for this. Or something.
+ ExprSymTab.clear();
+ VersionSymTab.clear();
+
+ std::vector<ExprHandle> Constraints;
+ ConsumeExpectedToken(Token::KWQuery);
+ if (Tok.kind != Token::LSquare) {
+ Error("malformed query, expected constraint list.");
+ SkipUntilRParen();
+ return DeclResult();
+ }
+
+ ConsumeExpectedToken(Token::LSquare);
+ // FIXME: Should avoid reading past unbalanced parens here.
+ while (Tok.kind != Token::RSquare) {
+ if (Tok.kind == Token::EndOfFile) {
+ Error("unexpected end of file.");
+ return new QueryCommand(Constraints.begin(), Constraints.end(),
+ ref<Expr>(false, Expr::Bool));
+ }
+
+ ExprResult Res = ParseExpr(TypeResult(Expr::Bool));
+ if (Res.isValid())
+ Constraints.push_back(Res.get());
+ }
+
+ ConsumeRSquare();
+
+ ExprResult Res = ParseExpr(TypeResult());
+ if (!Res.isValid()) // Error emitted by ParseExpr.
+ Res = ExprResult(ref<Expr>(0, Expr::Bool));
+
+ ExpectRParen("unexpected argument to 'query'.");
+ return new QueryCommand(Constraints.begin(), Constraints.end(),
+ Res.get());
+}
+
+/// ParseNumberOrExpr - Parse an expression whose type cannot be
+/// predicted.
+NumberOrExprResult ParserImpl::ParseNumberOrExpr() {
+ if (Tok.kind == Token::Number){
+ Token Num = Tok;
+ ConsumeToken();
+ return NumberOrExprResult(Num);
+ } else {
+ return NumberOrExprResult(ParseExpr(TypeResult()));
+ }
+}
+
+/// ParseExpr - Parse an expression with the given \arg
+/// ExpectedType. \arg ExpectedType can be invalid if the type cannot
+/// be inferred from the context.
+///
+/// expr = false | true
+/// expr = <constant>
+/// expr = <identifier>
+/// expr = [<identifier>:] paren-expr
+ExprResult ParserImpl::ParseExpr(TypeResult ExpectedType) {
+ // FIXME: Is it right to need to do this here?
+ if (Tok.kind == Token::EndOfFile) {
+ Error("unexpected end of file.");
+ return ExprResult();
+ }
+
+ if (Tok.kind == Token::KWFalse || Tok.kind == Token::KWTrue) {
+ bool Value = Tok.kind == Token::KWTrue;
+ ConsumeToken();
+ return ExprResult(ref<Expr>(Value, Expr::Bool));
+ }
+
+ if (Tok.kind == Token::Number) {
+ if (!ExpectedType.isValid()) {
+ Error("cannot infer type of number.");
+ ConsumeToken();
+ return ExprResult();
+ }
+
+ return ParseNumber(ExpectedType.get());
+ }
+
+ const Identifier *Label = 0;
+ if (Tok.kind == Token::Identifier) {
+ Token LTok = Tok;
+ Label = GetOrCreateIdentifier(Tok);
+ ConsumeToken();
+
+ if (Tok.kind != Token::Colon) {
+ ExprSymTabTy::iterator it = ExprSymTab.find(Label);
+
+ if (it == ExprSymTab.end()) {
+ Error("invalid expression label reference.", LTok);
+ return ExprResult();
+ }
+
+ return it->second;
+ }
+
+ ConsumeToken();
+ if (ExprSymTab.count(Label)) {
+ Error("duplicate expression label definition.", LTok);
+ Label = 0;
+ }
+ }
+
+ Token Start = Tok;
+ ExprResult Res = ParseParenExpr(ExpectedType);
+ if (!Res.isValid()) {
+ // If we know the type, define the identifier just so we don't get
+ // use-of-undef errors.
+ // FIXME: Maybe we should let the symbol table map to invalid
+ // entries?
+ if (Label && ExpectedType.isValid())
+ ExprSymTab.insert(std::make_pair(Label,
+ ref<Expr>(0, ExpectedType.get())));
+ return Res;
+ } else if (ExpectedType.isValid()) {
+ // Type check result.
+ if (Res.get().getWidth() != ExpectedType.get()) {
+ // FIXME: Need more info, and range
+ Error("expression has incorrect type.", Start);
+ return ExprResult();
+ }
+ }
+
+ if (Label)
+ ExprSymTab.insert(std::make_pair(Label, Res.get()));
+ return Res;
+}
+
+// Additional kinds for macro forms.
+enum MacroKind {
+ eMacroKind_Not = Expr::LastKind + 1, // false == x
+ eMacroKind_Neg, // 0 - x
+ eMacroKind_ReadLSB, // Multibyte read
+ eMacroKind_ReadMSB, // Multibyte write
+ eMacroKind_Concat, // Magic concatenation syntax
+ eMacroKind_LastMacroKind = eMacroKind_ReadMSB
+};
+
+/// LookupExprInfo - Return information on the named token, if it is
+/// recognized.
+///
+/// \param Kind [out] - The Expr::Kind or MacroKind of the identifier.
+/// \param IsFixed [out] - True if the given kinds result and
+/// (expression) arguments are all of the same width.
+/// \param NumArgs [out] - The number of expression arguments for this
+/// kind. -1 indicates the kind is variadic or has non-expression
+/// arguments.
+/// \return True if the token is a valid kind or macro name.
+static bool LookupExprInfo(const Token &Tok, unsigned &Kind,
+ bool &IsFixed, int &NumArgs) {
+#define SetOK(kind, isfixed, numargs) (Kind=kind, IsFixed=isfixed,\
+ NumArgs=numargs, true)
+ assert(Tok.kind == Token::Identifier && "Unexpected token.");
+
+ switch (Tok.length) {
+ case 2:
+ if (memcmp(Tok.start, "Eq", 2) == 0)
+ return SetOK(Expr::Eq, false, 2);
+ if (memcmp(Tok.start, "Ne", 2) == 0)
+ return SetOK(Expr::Ne, false, 2);
+
+ if (memcmp(Tok.start, "Or", 2) == 0)
+ return SetOK(Expr::Or, true, 2);
+ break;
+
+ case 3:
+ if (memcmp(Tok.start, "Add", 3) == 0)
+ return SetOK(Expr::Add, true, 2);
+ if (memcmp(Tok.start, "Sub", 3) == 0)
+ return SetOK(Expr::Sub, true, 2);
+ if (memcmp(Tok.start, "Mul", 3) == 0)
+ return SetOK(Expr::Mul, true, 2);
+
+ if (memcmp(Tok.start, "And", 3) == 0)
+ return SetOK(Expr::And, true, 2);
+ if (memcmp(Tok.start, "Shl", 3) == 0)
+ return SetOK(Expr::Shl, true, 2);
+ if (memcmp(Tok.start, "Xor", 3) == 0)
+ return SetOK(Expr::Xor, true, 2);
+
+ if (memcmp(Tok.start, "Not", 3) == 0)
+ return SetOK(eMacroKind_Not, true, 1);
+ if (memcmp(Tok.start, "Neg", 3) == 0)
+ return SetOK(eMacroKind_Neg, true, 1);
+ if (memcmp(Tok.start, "Ult", 3) == 0)
+ return SetOK(Expr::Ult, false, 2);
+ if (memcmp(Tok.start, "Ule", 3) == 0)
+ return SetOK(Expr::Ule, false, 2);
+ if (memcmp(Tok.start, "Ugt", 3) == 0)
+ return SetOK(Expr::Ugt, false, 2);
+ if (memcmp(Tok.start, "Uge", 3) == 0)
+ return SetOK(Expr::Uge, false, 2);
+ if (memcmp(Tok.start, "Slt", 3) == 0)
+ return SetOK(Expr::Slt, false, 2);
+ if (memcmp(Tok.start, "Sle", 3) == 0)
+ return SetOK(Expr::Sle, false, 2);
+ if (memcmp(Tok.start, "Sgt", 3) == 0)
+ return SetOK(Expr::Sgt, false, 2);
+ if (memcmp(Tok.start, "Sge", 3) == 0)
+ return SetOK(Expr::Sge, false, 2);
+ break;
+
+ case 4:
+ if (memcmp(Tok.start, "Read", 4) == 0)
+ return SetOK(Expr::Read, true, -1);
+ if (memcmp(Tok.start, "AShr", 4) == 0)
+ return SetOK(Expr::AShr, true, 2);
+ if (memcmp(Tok.start, "LShr", 4) == 0)
+ return SetOK(Expr::LShr, true, 2);
+
+ if (memcmp(Tok.start, "UDiv", 4) == 0)
+ return SetOK(Expr::UDiv, true, 2);
+ if (memcmp(Tok.start, "SDiv", 4) == 0)
+ return SetOK(Expr::SDiv, true, 2);
+ if (memcmp(Tok.start, "URem", 4) == 0)
+ return SetOK(Expr::URem, true, 2);
+ if (memcmp(Tok.start, "SRem", 4) == 0)
+ return SetOK(Expr::SRem, true, 2);
+
+ if (memcmp(Tok.start, "SExt", 4) == 0)
+ return SetOK(Expr::SExt, false, 1);
+ if (memcmp(Tok.start, "ZExt", 4) == 0)
+ return SetOK(Expr::ZExt, false, 1);
+ break;
+
+ case 6:
+ if (memcmp(Tok.start, "Concat", 6) == 0)
+ return SetOK(eMacroKind_Concat, false, -1);
+ if (memcmp(Tok.start, "Select", 6) == 0)
+ return SetOK(Expr::Select, false, 3);
+ break;
+
+ case 7:
+ if (memcmp(Tok.start, "Extract", 7) == 0)
+ return SetOK(Expr::Extract, false, -1);
+ if (memcmp(Tok.start, "ReadLSB", 7) == 0)
+ return SetOK(eMacroKind_ReadLSB, true, -1);
+ if (memcmp(Tok.start, "ReadMSB", 7) == 0)
+ return SetOK(eMacroKind_ReadMSB, true, -1);
+ break;
+ }
+
+ return false;
+#undef SetOK
+}
+
+/// ParseParenExpr - Parse a parenthesized expression with the given
+/// \arg ExpectedType. \arg ExpectedType can be invalid if the type
+/// cannot be inferred from the context.
+///
+/// paren-expr = '(' type number ')'
+/// paren-expr = '(' identifier [type] expr+ ')
+/// paren-expr = '(' ('Read' | 'ReadMSB' | 'ReadLSB') type expr update-list ')'
+ExprResult ParserImpl::ParseParenExpr(TypeResult FIXME_UNUSED) {
+ if (Tok.kind != Token::LParen) {
+ Error("unexpected token.");
+ ConsumeAnyToken();
+ return ExprResult();
+ }
+
+ ConsumeLParen();
+
+ // Check for coercion case (w32 11).
+ if (Tok.kind == Token::KWWidth) {
+ TypeResult ExpectedType = ParseTypeSpecifier();
+
+ if (Tok.kind != Token::Number) {
+ Error("coercion can only apply to a number.");
+ SkipUntilRParen();
+ return ExprResult();
+ }
+
+ // Make sure this was a type specifier we support.
+ ExprResult Res;
+ if (ExpectedType.isValid())
+ Res = ParseNumber(ExpectedType.get());
+ else
+ ConsumeToken();
+
+ ExpectRParen("unexpected argument in coercion.");
+ return Res;
+ }
+
+ if (Tok.kind != Token::Identifier) {
+ Error("unexpected token, expected expression.");
+ SkipUntilRParen();
+ return ExprResult();
+ }
+
+ Token Name = Tok;
+ ConsumeToken();
+
+ // FIXME: Use invalid type (i.e. width==0)?
+ Token TypeTok = Tok;
+ bool HasType = TypeTok.kind == Token::KWWidth;
+ TypeResult Type = HasType ? ParseTypeSpecifier() : Expr::Bool;
+
+ // FIXME: For now just skip to rparen on error. It might be nice
+ // to try and actually parse the child nodes though for error
+ // messages & better recovery?
+ if (!Type.isValid()) {
+ SkipUntilRParen();
+ return ExprResult();
+ }
+ Expr::Width ResTy = Type.get();
+
+ unsigned ExprKind;
+ bool IsFixed;
+ int NumArgs;
+ if (!LookupExprInfo(Name, ExprKind, IsFixed, NumArgs)) {
+ // FIXME: For now just skip to rparen on error. It might be nice
+ // to try and actually parse the child nodes though for error
+ // messages & better recovery?
+ Error("unknown expression kind.", Name);
+ SkipUntilRParen();
+ return ExprResult();
+ }
+
+ // See if we have to parse this form specially.
+ if (NumArgs == -1) {
+ switch (ExprKind) {
+ case eMacroKind_Concat:
+ return ParseConcatParenExpr(Name, ResTy);
+
+ case Expr::Extract:
+ return ParseExtractParenExpr(Name, ResTy);
+
+ case eMacroKind_ReadLSB:
+ case eMacroKind_ReadMSB:
+ case Expr::Read:
+ return ParseAnyReadParenExpr(Name, ExprKind, ResTy);
+
+ default:
+ Error("internal error, unimplemented special form.", Name);
+ SkipUntilRParen();
+ return ExprResult(ref<Expr>(0, ResTy));
+ }
+ }
+
+ switch (NumArgs) {
+ case 1:
+ return ParseUnaryParenExpr(Name, ExprKind, IsFixed, ResTy);
+ case 2:
+ return ParseBinaryParenExpr(Name, ExprKind, IsFixed, ResTy);
+ case 3:
+ if (ExprKind == Expr::Select)
+ return ParseSelectParenExpr(Name, ResTy);
+ default:
+ assert(0 && "Invalid argument kind (number of args).");
+ return ExprResult();
+ }
+}
+
+ExprResult ParserImpl::ParseUnaryParenExpr(const Token &Name,
+ unsigned Kind, bool IsFixed,
+ Expr::Width ResTy) {
+ if (Tok.kind == Token::RParen) {
+ Error("unexpected end of arguments.", Name);
+ ConsumeRParen();
+ return ref<Expr>(0, ResTy);
+ }
+
+ ExprResult Arg = ParseExpr(IsFixed ? ResTy : TypeResult());
+ if (!Arg.isValid())
+ Arg = ref<Expr>(0, ResTy);
+
+ ExpectRParen("unexpected argument in unary expression.");
+ ExprHandle E = Arg.get();
+ switch (Kind) {
+ case eMacroKind_Not:
+ return EqExpr::alloc(ref<Expr>(0, E.getWidth()), E);
+ case eMacroKind_Neg:
+ return SubExpr::alloc(ref<Expr>(0, E.getWidth()), E);
+ case Expr::SExt:
+ // FIXME: Type check arguments.
+ return SExtExpr::alloc(E, ResTy);
+ case Expr::ZExt:
+ // FIXME: Type check arguments.
+ return ZExtExpr::alloc(E, ResTy);
+ default:
+ Error("internal error, unhandled kind.", Name);
+ return ref<Expr>(0, ResTy);
+ }
+}
+
+/// ParseMatchedBinaryArgs - Parse a pair of arguments who are
+/// expected to be of the same type. Upon return, if both LHS and RHS
+/// are valid then they are guaranteed to have the same type.
+///
+/// Name - The name token of the expression, for diagnostics.
+/// ExpectType - The expected type of the arguments, if known.
+void ParserImpl::ParseMatchedBinaryArgs(const Token &Name,
+ TypeResult ExpectType,
+ ExprResult &LHS, ExprResult &RHS) {
+ if (Tok.kind == Token::RParen) {
+ Error("unexpected end of arguments.", Name);
+ ConsumeRParen();
+ return;
+ }
+
+ // Avoid NumberOrExprResult overhead and give more precise
+ // diagnostics when we know the type.
+ if (ExpectType.isValid()) {
+ LHS = ParseExpr(ExpectType);
+ if (Tok.kind == Token::RParen) {
+ Error("unexpected end of arguments.", Name);
+ ConsumeRParen();
+ return;
+ }
+ RHS = ParseExpr(ExpectType);
+ } else {
+ NumberOrExprResult LHS_NOE = ParseNumberOrExpr();
+
+ if (Tok.kind == Token::RParen) {
+ Error("unexpected end of arguments.", Name);
+ ConsumeRParen();
+ return;
+ }
+
+ if (LHS_NOE.isNumber()) {
+ NumberOrExprResult RHS_NOE = ParseNumberOrExpr();
+
+ if (RHS_NOE.isNumber()) {
+ Error("ambiguous arguments to expression.", Name);
+ } else {
+ RHS = RHS_NOE.getExpr();
+ if (RHS.isValid())
+ LHS = ParseNumberToken(RHS.get().getWidth(), LHS_NOE.getNumber());
+ }
+ } else {
+ LHS = LHS_NOE.getExpr();
+ if (!LHS.isValid()) {
+ // FIXME: Should suppress ambiguity warnings here.
+ RHS = ParseExpr(TypeResult());
+ } else {
+ RHS = ParseExpr(LHS.get().getWidth());
+ }
+ }
+ }
+
+ ExpectRParen("unexpected argument to expression.");
+}
+
+ExprResult ParserImpl::ParseBinaryParenExpr(const Token &Name,
+ unsigned Kind, bool IsFixed,
+ Expr::Width ResTy) {
+ ExprResult LHS, RHS;
+ ParseMatchedBinaryArgs(Name, IsFixed ? TypeResult(ResTy) : TypeResult(),
+ LHS, RHS);
+ if (!LHS.isValid() || !RHS.isValid())
+ return ref<Expr>(0, ResTy);
+
+ ref<Expr> LHS_E = LHS.get(), RHS_E = RHS.get();
+ assert(LHS_E.getWidth() == RHS_E.getWidth() && "Mismatched types!");
+
+ switch (Kind) {
+ case Expr::Add: return AddExpr::alloc(LHS_E, RHS_E);
+ case Expr::Sub: return SubExpr::alloc(LHS_E, RHS_E);
+ case Expr::Mul: return MulExpr::alloc(LHS_E, RHS_E);
+ case Expr::UDiv: return UDivExpr::alloc(LHS_E, RHS_E);
+ case Expr::SDiv: return SDivExpr::alloc(LHS_E, RHS_E);
+ case Expr::URem: return URemExpr::alloc(LHS_E, RHS_E);
+ case Expr::SRem: return SRemExpr::alloc(LHS_E, RHS_E);
+
+ case Expr::AShr: return AShrExpr::alloc(LHS_E, RHS_E);
+ case Expr::LShr: return LShrExpr::alloc(LHS_E, RHS_E);
+ case Expr::Shl: return AndExpr::alloc(LHS_E, RHS_E);
+
+ case Expr::And: return AndExpr::alloc(LHS_E, RHS_E);
+ case Expr::Or: return OrExpr::alloc(LHS_E, RHS_E);
+ case Expr::Xor: return XorExpr::alloc(LHS_E, RHS_E);
+
+ case Expr::Eq: return EqExpr::alloc(LHS_E, RHS_E);
+ case Expr::Ne: return NeExpr::alloc(LHS_E, RHS_E);
+ case Expr::Ult: return UltExpr::alloc(LHS_E, RHS_E);
+ case Expr::Ule: return UleExpr::alloc(LHS_E, RHS_E);
+ case Expr::Ugt: return UgtExpr::alloc(LHS_E, RHS_E);
+ case Expr::Uge: return UgeExpr::alloc(LHS_E, RHS_E);
+ case Expr::Slt: return SltExpr::alloc(LHS_E, RHS_E);
+ case Expr::Sle: return SleExpr::alloc(LHS_E, RHS_E);
+ case Expr::Sgt: return SgtExpr::alloc(LHS_E, RHS_E);
+ case Expr::Sge: return SgeExpr::alloc(LHS_E, RHS_E);
+ default:
+ Error("FIXME: unhandled kind.", Name);
+ return ref<Expr>(0, ResTy);
+ }
+}
+
+ExprResult ParserImpl::ParseSelectParenExpr(const Token &Name,
+ Expr::Width ResTy) {
+ // FIXME: Why does this need to be here?
+ if (Tok.kind == Token::RParen) {
+ Error("unexpected end of arguments.", Name);
+ ConsumeRParen();
+ return ref<Expr>(0, ResTy);
+ }
+
+ ExprResult Cond = ParseExpr(Expr::Bool);
+ ExprResult LHS, RHS;
+ ParseMatchedBinaryArgs(Name, ResTy, LHS, RHS);
+ if (!Cond.isValid() || !LHS.isValid() || !RHS.isValid())
+ return ref<Expr>(0, ResTy);
+ return SelectExpr::alloc(Cond.get(), LHS.get(), RHS.get());
+}
+
+
+// need to decide if we want to allow n-ary Concat expressions in the
+// language
+ExprResult ParserImpl::ParseConcatParenExpr(const Token &Name,
+ Expr::Width ResTy) {
+ std::vector<ExprHandle> Kids;
+
+ unsigned Width = 0;
+ while (Tok.kind != Token::RParen) {
+ ExprResult E = ParseExpr(TypeResult());
+
+ // Skip to end of expr on error.
+ if (!E.isValid()) {
+ SkipUntilRParen();
+ return ref<Expr>(0, ResTy);
+ }
+
+ Kids.push_back(E.get());
+ Width += E.get().getWidth();
+ }
+
+ ConsumeRParen();
+
+ if (Width != ResTy) {
+ Error("concat does not match expected result size.");
+ return ref<Expr>(0, ResTy);
+ }
+
+ return ConcatExpr::createN(Kids.size(), &Kids[0]);
+}
+
+ExprResult ParserImpl::ParseExtractParenExpr(const Token &Name,
+ Expr::Width ResTy) {
+ // FIXME: Pull out parse constant integer expression.
+ ExprResult OffsetExpr = ParseNumber(Expr::Int32);
+ ExprResult Child = ParseExpr(TypeResult());
+
+ ExpectRParen("unexpected argument to expression.");
+
+ if (!OffsetExpr.isValid() || !Child.isValid())
+ return ref<Expr>(0, ResTy);
+
+ assert(OffsetExpr.get().isConstant() && "ParseNumber returned non-constant.");
+ unsigned Offset = (unsigned) OffsetExpr.get().getConstantValue();
+
+ if (Offset + ResTy > Child.get().getWidth()) {
+ Error("extract out-of-range of child expression.", Name);
+ return ref<Expr>(0, ResTy);
+ }
+
+ return ExtractExpr::alloc(Child.get(), Offset, ResTy);
+}
+
+ExprResult ParserImpl::ParseAnyReadParenExpr(const Token &Name,
+ unsigned Kind,
+ Expr::Width ResTy) {
+ NumberOrExprResult Index = ParseNumberOrExpr();
+ VersionResult Array = ParseVersionSpecifier();
+ ExpectRParen("unexpected argument in read expression.");
+
+ if (!Array.isValid())
+ return ref<Expr>(0, ResTy);
+
+ // FIXME: Need generic way to get array width. Needs to work with
+ // anonymous arrays.
+ Expr::Width ArrayDomainType = Expr::Int32;
+ Expr::Width ArrayRangeType = Expr::Int8;
+
+ // Coerce number to correct type.
+ ExprResult IndexExpr;
+ if (Index.isNumber())
+ IndexExpr = ParseNumberToken(ArrayDomainType, Index.getNumber());
+ else
+ IndexExpr = Index.getExpr();
+
+ if (!IndexExpr.isValid())
+ return ref<Expr>(0, ResTy);
+ else if (IndexExpr.get().getWidth() != ArrayDomainType) {
+ Error("index width does not match array domain.");
+ return ref<Expr>(0, ResTy);
+ }
+
+ // FIXME: Check range width.
+
+ switch (Kind) {
+ default:
+ assert(0 && "Invalid kind.");
+ return ref<Expr>(0, ResTy);
+ case eMacroKind_ReadLSB:
+ case eMacroKind_ReadMSB: {
+ unsigned NumReads = ResTy / ArrayRangeType;
+ if (ResTy != NumReads*ArrayRangeType) {
+ Error("invalid ordered read (not multiple of range type).", Name);
+ return ref<Expr>(0, ResTy);
+ }
+ std::vector<ExprHandle> Kids;
+ Kids.reserve(NumReads);
+ ExprHandle Index = IndexExpr.get();
+ for (unsigned i=0; i<NumReads; ++i) {
+ // FIXME: using folding here
+ ExprHandle OffsetIndex = AddExpr::create(IndexExpr.get(),
+ ref<Expr>(i, ArrayDomainType));
+ Kids.push_back(ReadExpr::alloc(Array.get(), OffsetIndex));
+ }
+ if (Kind == eMacroKind_ReadLSB)
+ std::reverse(Kids.begin(), Kids.end());
+ return ConcatExpr::createN(NumReads, &Kids[0]);
+ }
+ case Expr::Read:
+ return ReadExpr::alloc(Array.get(), IndexExpr.get());
+ }
+}
+
+/// version-specifier = <identifier>
+/// version-specifier = [<identifier>:] [ version ]
+VersionResult ParserImpl::ParseVersionSpecifier() {
+ const Identifier *Label = 0;
+ if (Tok.kind == Token::Identifier) {
+ Token LTok = Tok;
+ Label = GetOrCreateIdentifier(Tok);
+ ConsumeToken();
+
+ // FIXME: hack: add array declarations and ditch this.
+ if (memcmp(Label->Name.c_str(), "arr", 3) == 0) {
+ // Declare or create array.
+ const ArrayDecl *&A = ArraySymTab[Label];
+ if (!A) {
+ // Array = new ArrayDecl(Label, 0, 32, 8);
+ unsigned id = atoi(&Label->Name.c_str()[3]);
+ Array *root = new Array(0, id, 0);
+ // Create update list mapping of name -> array.
+ VersionSymTab.insert(std::make_pair(Label,
+ UpdateList(root, true, NULL)));
+ }
+ }
+
+ if (Tok.kind != Token::Colon) {
+ VersionSymTabTy::iterator it = VersionSymTab.find(Label);
+
+ if (it == VersionSymTab.end()) {
+ Error("invalid update list label reference.", LTok);
+ return VersionResult(false,
+ UpdateList(0, true, NULL));
+ }
+
+ return it->second;
+ }
+
+ ConsumeToken();
+ if (VersionSymTab.count(Label)) {
+ Error("duplicate update list label definition.", LTok);
+ Label = 0;
+ }
+ }
+
+ Token Start = Tok;
+ VersionResult Res = ParseVersion();
+ // Define update list to avoid use-of-undef errors.
+ if (!Res.isValid())
+ Res = VersionResult(false,
+ UpdateList(0, true, NULL));
+
+ if (Label)
+ VersionSymTab.insert(std::make_pair(Label, Res.get()));
+ return Res;
+}
+
+/// version - '[' update-list? ']' ['@' version-specifier]
+/// update-list - empty
+/// update-list - lhs '=' rhs [',' update-list]
+VersionResult ParserImpl::ParseVersion() {
+ if (Tok.kind != Token::LSquare)
+ return VersionResult(false, UpdateList(0, false, NULL));
+
+ std::vector< std::pair<NumberOrExprResult, NumberOrExprResult> > Writes;
+ ConsumeLSquare();
+ for (;;) {
+ // FIXME: Type check exprs.
+
+ // FIXME: We need to do this (the above) anyway just to handle
+ // implicit constants correctly.
+ NumberOrExprResult LHS = ParseNumberOrExpr();
+
+ if (Tok.kind != Token::Equals) {
+ Error("expected '='.", Tok);
+ break;
+ }
+
+ ConsumeToken();
+ NumberOrExprResult RHS = ParseNumberOrExpr();
+
+ Writes.push_back(std::make_pair(LHS, RHS));
+
+ if (Tok.kind == Token::Comma)
+ ConsumeToken();
+ else
+ break;
+ }
+ ExpectRSquare("expected close of update list");
+
+ VersionHandle Base(0, false, NULL);
+
+ // Anonymous array case.
+ if (Tok.kind != Token::At) {
+ Array *root = new Array(0, 0, 0);
+ Base = UpdateList(root, false, NULL);
+ } else {
+ ConsumeToken();
+
+ VersionResult BaseRes = ParseVersionSpecifier();
+ if (!BaseRes.isValid())
+ return BaseRes;
+
+ Base = BaseRes.get();
+ }
+
+ Expr::Width ArrayDomainType = Expr::Int32;
+ Expr::Width ArrayRangeType = Expr::Int8;
+
+ for (std::vector< std::pair<NumberOrExprResult, NumberOrExprResult> >::reverse_iterator
+ it = Writes.rbegin(), ie = Writes.rend(); it != ie; ++it) {
+ ExprResult LHS, RHS;
+ // FIXME: This can be factored into common helper for coercing a
+ // NumberOrExpr into an Expr.
+ if (it->first.isNumber()) {
+ LHS = ParseNumberToken(ArrayDomainType, it->first.getNumber());
+ } else {
+ LHS = it->first.getExpr();
+ if (LHS.isValid() && LHS.get().getWidth() != ArrayDomainType) {
+ // FIXME: bad token location. We should maybe try and know the
+ // array up-front?
+ Error("invalid value in write index (doesn't match domain).", Tok);
+ LHS = ExprResult();
+ }
+ }
+
+ if (it->second.isNumber()) {
+ RHS = ParseNumberToken(ArrayRangeType, it->second.getNumber());
+ } else {
+ RHS = it->second.getExpr();
+ if (RHS.isValid() && RHS.get().getWidth() != ArrayRangeType) {
+ // FIXME: bad token location. We should maybe try and know the
+ // array up-front?
+ Error("invalid value in write assignment (doesn't match range).", Tok);
+ RHS = ExprResult();
+ }
+ }
+
+ if (LHS.isValid() && RHS.isValid())
+ Base.extend(LHS.get(), RHS.get());
+ }
+
+ return Base;
+}
+
+/// ParseNumber - Parse a number of the given type.
+ExprResult ParserImpl::ParseNumber(Expr::Width Type) {
+ ExprResult Res = ParseNumberToken(Type, Tok);
+ ConsumeExpectedToken(Token::Number);
+ return Res;
+}
+
+/// ParseNumberToken - Parse a number of the given type from the given
+/// token.
+ExprResult ParserImpl::ParseNumberToken(Expr::Width Type, const Token &Tok) {
+ const char *S = Tok.start;
+ unsigned N = Tok.length;
+ unsigned Radix = 10, RadixBits = 4;
+ bool HasMinus = false;
+
+ // Detect +/- (a number token cannot have both).
+ if (S[0] == '+') {
+ ++S;
+ --N;
+ } else if (S[0] == '-') {
+ HasMinus = true;
+ ++S;
+ --N;
+ }
+
+ // Detect 0[box].
+ if ((Tok.length >= 2 && S[0] == '0') &&
+ (S[1] == 'b' || S[1] == 'o' || S[1] == 'x')) {
+ if (S[1] == 'b') {
+ Radix = 2;
+ RadixBits = 1;
+ } else if (S[1] == 'o') {
+ Radix = 8;
+ RadixBits = 3;
+ } else {
+ Radix = 16;
+ RadixBits = 4;
+ }
+ S += 2;
+ N -= 2;
+
+ // Diagnose 0[box] with no trailing digits.
+ if (!N) {
+ Error("invalid numeric token (no digits).", Tok);
+ return ref<Expr>(0, Type);
+ }
+ }
+
+ // This is a simple but slow way to handle overflow.
+ APInt Val(std::max(64U, RadixBits * N), 0);
+ APInt RadixVal(Val.getBitWidth(), Radix);
+ APInt DigitVal(Val.getBitWidth(), 0);
+ for (unsigned i=0; i<N; ++i) {
+ unsigned Digit, Char = S[i];
+
+ if (Char == '_')
+ continue;
+
+ if ('0' <= Char && Char <= '9')
+ Digit = Char - '0';
+ else if ('a' <= Char && Char <= 'z')
+ Digit = Char - 'a' + 10;
+ else if ('A' <= Char && Char <= 'Z')
+ Digit = Char - 'A' + 10;
+ else {
+ Error("invalid character in numeric token.", Tok);
+ return ref<Expr>(0, Type);
+ }
+
+ if (Digit >= Radix) {
+ Error("invalid character in numeric token (out of range).", Tok);
+ return ref<Expr>(0, Type);
+ }
+
+ DigitVal = Digit;
+ Val = Val * RadixVal + DigitVal;
+ }
+
+ // FIXME: Actually do the check for overflow.
+ if (HasMinus)
+ Val = -Val;
+
+ return ExprResult(ref<Expr>(Val.trunc(Type).getZExtValue(), Type));
+}
+
+/// ParseTypeSpecifier - Parse a type specifier.
+///
+/// type = w[0-9]+
+TypeResult ParserImpl::ParseTypeSpecifier() {
+ assert(Tok.kind == Token::KWWidth && "Unexpected token.");
+
+ // FIXME: Need APInt technically.
+ Token TypeTok = Tok;
+ int width = atoi(std::string(Tok.start+1,Tok.length-1).c_str());
+ ConsumeToken();
+
+ // FIXME: We should impose some sort of maximum just for sanity?
+ return TypeResult(width);
+}
+
+void ParserImpl::Error(const char *Message, const Token &At) {
+ ++NumErrors;
+ if (MaxErrors && NumErrors >= MaxErrors)
+ return;
+
+ llvm::cerr << Filename
+ << ":" << At.line << ":" << At.column
+ << ": error: " << Message << "\n";
+
+ // Skip carat diagnostics on EOF token.
+ if (At.kind == Token::EndOfFile)
+ return;
+
+ // Simple caret style diagnostics.
+ const char *LineBegin = At.start, *LineEnd = At.start,
+ *BufferBegin = TheMemoryBuffer->getBufferStart(),
+ *BufferEnd = TheMemoryBuffer->getBufferEnd();
+
+ // Run line pointers forward and back.
+ while (LineBegin > BufferBegin &&
+ LineBegin[-1] != '\r' && LineBegin[-1] != '\n')
+ --LineBegin;
+ while (LineEnd < BufferEnd &&
+ LineEnd[0] != '\r' && LineEnd[0] != '\n')
+ ++LineEnd;
+
+ // Show the line.
+ llvm::cerr << std::string(LineBegin, LineEnd) << "\n";
+
+ // Show the caret or squiggly, making sure to print back spaces the
+ // same.
+ for (const char *S=LineBegin; S != At.start; ++S)
+ llvm::cerr << (isspace(*S) ? *S : ' ');
+ if (At.length > 1) {
+ for (unsigned i=0; i<At.length; ++i)
+ llvm::cerr << '~';
+ } else
+ llvm::cerr << '^';
+ llvm::cerr << '\n';
+}
+
+// AST API
+// FIXME: Move out of parser.
+
+Decl::Decl() {}
+
+void QueryCommand::dump() {
+ // FIXME: This is masking the difference between an actual query and
+ // a query decl.
+ ExprPPrinter::printQuery(std::cerr,
+ ConstraintManager(Constraints),
+ Query);
+}
+
+// Public parser API
+
+Parser::Parser() {
+}
+
+Parser::~Parser() {
+}
+
+Parser *Parser::Create(const std::string Filename,
+ const MemoryBuffer *MB) {
+ ParserImpl *P = new ParserImpl(Filename, MB);
+ P->Initialize();
+ return P;
+}
Added: klee/trunk/lib/Expr/Updates.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Expr/Updates.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Expr/Updates.cpp (added)
+++ klee/trunk/lib/Expr/Updates.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,126 @@
+//===-- Updates.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/Expr.h"
+
+#include <cassert>
+
+using namespace klee;
+
+///
+
+UpdateNode::UpdateNode(const UpdateNode *_next,
+ const ref<Expr> &_index,
+ const ref<Expr> &_value)
+ : refCount(0),
+ stpArray(0),
+ next(_next),
+ index(_index),
+ value(_value) {
+ assert(_value.getWidth() == Expr::Int8 && "Update value should be 8-bit wide.");
+ computeHash();
+ if (next) {
+ ++next->refCount;
+ size = 1 + next->size;
+ }
+ else size = 1;
+}
+
+extern "C" void vc_DeleteExpr(void*);
+
+UpdateNode::~UpdateNode() {
+ // XXX gross
+ if (stpArray)
+ ::vc_DeleteExpr(stpArray);
+}
+
+int UpdateNode::compare(const UpdateNode &b) const {
+ if (int i = index.compare(b.index))
+ return i;
+ return value.compare(b.value);
+}
+
+unsigned UpdateNode::computeHash() {
+ hashValue = index.hash() ^ value.hash();
+ if (next)
+ hashValue ^= next->hash();
+ return hashValue;
+}
+
+///
+
+UpdateList::UpdateList(const Array *_root, bool _isRooted,
+ const UpdateNode *_head)
+ : root(_root),
+ head(_head),
+ isRooted(_isRooted) {
+ if (head) ++head->refCount;
+}
+
+UpdateList::UpdateList(const UpdateList &b)
+ : root(b.root),
+ head(b.head),
+ isRooted(b.isRooted) {
+ if (head) ++head->refCount;
+}
+
+UpdateList::~UpdateList() {
+ // We need to be careful and avoid recursion here. We do this in
+ // cooperation with the private dtor of UpdateNode which does not
+ // recursively free its tail.
+ while (head && --head->refCount==0) {
+ const UpdateNode *n = head->next;
+ delete head;
+ head = n;
+ }
+}
+
+UpdateList &UpdateList::operator=(const UpdateList &b) {
+ if (b.head) ++b.head->refCount;
+ if (head && --head->refCount==0) delete head;
+ root = b.root;
+ head = b.head;
+ isRooted = b.isRooted;
+ return *this;
+}
+
+void UpdateList::extend(const ref<Expr> &index, const ref<Expr> &value) {
+ if (head) --head->refCount;
+ head = new UpdateNode(head, index, value);
+ ++head->refCount;
+}
+
+int UpdateList::compare(const UpdateList &b) const {
+ // use object id to increase determinism
+ if (root->id != b.root->id)
+ return root->id < b.root->id ? -1 : 1;
+
+ if (getSize() < b.getSize()) return -1;
+ else if (getSize() > b.getSize()) return 1;
+
+ // XXX build comparison into update, make fast
+ const UpdateNode *an=head, *bn=b.head;
+ for (; an && bn; an=an->next,bn=bn->next) {
+ if (an==bn) { // exploit shared list structure
+ return 0;
+ } else {
+ if (int res = an->compare(*bn))
+ return res;
+ }
+ }
+ assert(!an && !bn);
+ return 0;
+}
+
+unsigned UpdateList::hash() const {
+ unsigned res = root->id * Expr::MAGIC_HASH_CONSTANT;
+ if (head)
+ res ^= head->hash();
+ return res;
+}
Added: klee/trunk/lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Makefile (added)
+++ klee/trunk/lib/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,15 @@
+#===-- lib/Makefile ----------------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=..
+
+PARALLEL_DIRS=Basic Support Expr Solver Module Core
+
+include $(LEVEL)/Makefile.common
+
Added: klee/trunk/lib/Module/Checks.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/Checks.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/Checks.cpp (added)
+++ klee/trunk/lib/Module/Checks.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,68 @@
+//===-- Checks.cpp --------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Function.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/Instruction.h"
+#include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Type.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Target/TargetData.h"
+
+using namespace llvm;
+using namespace klee;
+
+char DivCheckPass::ID;
+
+bool DivCheckPass::runOnModule(Module &M) {
+ Function *divZeroCheckFunction = 0;
+
+ bool moduleChanged = false;
+
+ for (Module::iterator f = M.begin(), fe = M.end(); f != fe; ++f) {
+ for (Function::iterator b = f->begin(), be = f->end(); b != be; ++b) {
+ for (BasicBlock::iterator i = b->begin(), ie = b->end(); i != ie; ++i) {
+ if (BinaryOperator* binOp = dyn_cast<BinaryOperator>(i)) {
+ // find all [s|u][div|mod] instructions
+ Instruction::BinaryOps opcode = binOp->getOpcode();
+ if (opcode == Instruction::SDiv || opcode == Instruction::UDiv ||
+ opcode == Instruction::SRem || opcode == Instruction::URem) {
+
+ CastInst *denominator =
+ CastInst::CreateIntegerCast(i->getOperand(1),
+ (Type*)Type::Int64Ty,
+ false, /* sign doesn't matter */
+ "int_cast_to_i64",
+ i);
+
+ // Lazily bind the function to avoid always importing it.
+ if (!divZeroCheckFunction) {
+ Constant *fc = M.getOrInsertFunction("klee_div_zero_check",
+ Type::VoidTy,
+ Type::Int64Ty, NULL);
+ divZeroCheckFunction = cast<Function>(fc);
+ }
+
+ CallInst::Create(divZeroCheckFunction, denominator, "", &*i);
+ moduleChanged = true;
+ }
+ }
+ }
+ }
+ }
+ return moduleChanged;
+}
Added: klee/trunk/lib/Module/InstructionInfoTable.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/InstructionInfoTable.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/InstructionInfoTable.cpp (added)
+++ klee/trunk/lib/Module/InstructionInfoTable.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,196 @@
+//===-- InstructionInfoTable.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/Internal/Module/InstructionInfoTable.h"
+
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/Linker.h"
+#include "llvm/Module.h"
+#include "llvm/Assembly/AsmAnnotationWriter.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Analysis/ValueTracking.h"
+
+#include <map>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+using namespace llvm;
+using namespace klee;
+
+class InstructionToLineAnnotator : public llvm::AssemblyAnnotationWriter {
+public:
+ void emitInstructionAnnot(const Instruction *i, llvm::raw_ostream &os) {
+ os << "%%%" << (uintptr_t) i;
+ }
+};
+
+static void buildInstructionToLineMap(Module *m,
+ std::map<const Instruction*, unsigned> &out) {
+ InstructionToLineAnnotator a;
+ std::ostringstream buffer;
+ m->print(buffer, &a);
+ std::string str = buffer.str();
+ const char *s;
+
+ unsigned line = 1;
+ for (s=str.c_str(); *s; s++) {
+ if (*s=='\n') {
+ line++;
+ if (s[1]=='%' && s[2]=='%' && s[3]=='%') {
+ s += 4;
+ char *end;
+ unsigned long long value = strtoull(s, &end, 10);
+ if (end!=s) {
+ out.insert(std::make_pair((const Instruction*) value, line));
+ }
+ s = end;
+ }
+ }
+ }
+}
+
+static std::string getDSPIPath(DbgStopPointInst *dspi) {
+ std::string dir, file;
+ bool res = GetConstantStringInfo(dspi->getDirectory(), dir);
+ assert(res && "GetConstantStringInfo failed");
+ res = GetConstantStringInfo(dspi->getFileName(), file);
+ assert(res && "GetConstantStringInfo failed");
+ if (dir.empty()) {
+ return file;
+ } else if (*dir.rbegin() == '/') {
+ return dir + file;
+ } else {
+ return dir + "/" + file;
+ }
+}
+
+InstructionInfoTable::InstructionInfoTable(Module *m)
+ : dummyString(""), dummyInfo(0, dummyString, 0, 0) {
+ unsigned id = 0;
+ std::map<const Instruction*, unsigned> lineTable;
+ buildInstructionToLineMap(m, lineTable);
+
+ for (Module::iterator fnIt = m->begin(), fn_ie = m->end();
+ fnIt != fn_ie; ++fnIt) {
+ const std::string *initialFile = &dummyString;
+ unsigned initialLine = 0;
+
+ // It may be better to look for the closest stoppoint to the entry
+ // following the CFG, but it is not clear that it ever matters in
+ // practice.
+ for (inst_iterator it = inst_begin(fnIt), ie = inst_end(fnIt);
+ it != ie; ++it) {
+ if (DbgStopPointInst *dspi = dyn_cast<DbgStopPointInst>(&*it)) {
+ initialFile = internString(getDSPIPath(dspi));
+ initialLine = dspi->getLine();
+ break;
+ }
+ }
+
+ typedef std::map<BasicBlock*, std::pair<const std::string*,unsigned> >
+ sourceinfo_ty;
+ sourceinfo_ty sourceInfo;
+ for (llvm::Function::iterator bbIt = fnIt->begin(), bbie = fnIt->end();
+ bbIt != bbie; ++bbIt) {
+ std::pair<sourceinfo_ty::iterator, bool>
+ res = sourceInfo.insert(std::make_pair(bbIt,
+ std::make_pair(initialFile,
+ initialLine)));
+ if (!res.second)
+ continue;
+
+ std::vector<BasicBlock*> worklist;
+ worklist.push_back(bbIt);
+
+ do {
+ BasicBlock *bb = worklist.back();
+ worklist.pop_back();
+
+ sourceinfo_ty::iterator si = sourceInfo.find(bb);
+ assert(si != sourceInfo.end());
+ const std::string *file = si->second.first;
+ unsigned line = si->second.second;
+
+ for (BasicBlock::iterator it = bb->begin(), ie = bb->end();
+ it != ie; ++it) {
+ Instruction *instr = it;
+ unsigned assemblyLine = 0;
+ std::map<const Instruction*, unsigned>::const_iterator ltit =
+ lineTable.find(instr);
+ if (ltit!=lineTable.end())
+ assemblyLine = ltit->second;
+ if (DbgStopPointInst *dspi = dyn_cast<DbgStopPointInst>(instr)) {
+ file = internString(getDSPIPath(dspi));
+ line = dspi->getLine();
+ }
+ infos.insert(std::make_pair(instr,
+ InstructionInfo(id++,
+ *file,
+ line,
+ assemblyLine)));
+ }
+
+ for (succ_iterator it = succ_begin(bb), ie = succ_end(bb);
+ it != ie; ++it) {
+ if (sourceInfo.insert(std::make_pair(*it,
+ std::make_pair(file, line))).second)
+ worklist.push_back(*it);
+ }
+ } while (!worklist.empty());
+ }
+ }
+}
+
+InstructionInfoTable::~InstructionInfoTable() {
+ for (std::set<const std::string *, ltstr>::iterator
+ it = internedStrings.begin(), ie = internedStrings.end();
+ it != ie; ++it)
+ delete *it;
+}
+
+const std::string *InstructionInfoTable::internString(std::string s) {
+ std::set<const std::string *, ltstr>::iterator it = internedStrings.find(&s);
+ if (it==internedStrings.end()) {
+ std::string *interned = new std::string(s);
+ internedStrings.insert(interned);
+ return interned;
+ } else {
+ return *it;
+ }
+}
+
+unsigned InstructionInfoTable::getMaxID() const {
+ return infos.size();
+}
+
+const InstructionInfo &
+InstructionInfoTable::getInfo(const Instruction *inst) const {
+ std::map<const llvm::Instruction*, InstructionInfo>::const_iterator it =
+ infos.find(inst);
+ if (it==infos.end()) {
+ return dummyInfo;
+ } else {
+ return it->second;
+ }
+}
+
+const InstructionInfo &
+InstructionInfoTable::getFunctionInfo(const Function *f) const {
+ if (f->isDeclaration()) {
+ return dummyInfo;
+ } else {
+ return getInfo(f->begin()->begin());
+ }
+}
Added: klee/trunk/lib/Module/IntrinsicCleaner.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/IntrinsicCleaner.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/IntrinsicCleaner.cpp (added)
+++ klee/trunk/lib/Module/IntrinsicCleaner.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,119 @@
+//===-- IntrinsicCleaner.cpp ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Function.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/Instruction.h"
+#include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Type.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Target/TargetData.h"
+
+using namespace llvm;
+
+namespace klee {
+
+char IntrinsicCleanerPass::ID;
+
+bool IntrinsicCleanerPass::runOnModule(Module &M) {
+ bool dirty = false;
+ for (Module::iterator f = M.begin(), fe = M.end(); f != fe; ++f)
+ for (Function::iterator b = f->begin(), be = f->end(); b != be; ++b)
+ dirty |= runOnBasicBlock(*b);
+ return dirty;
+}
+
+bool IntrinsicCleanerPass::runOnBasicBlock(BasicBlock &b) {
+ bool dirty = false;
+
+ for (BasicBlock::iterator i = b.begin(), ie = b.end(); i != ie;) {
+ IntrinsicInst *ii = dyn_cast<IntrinsicInst>(&*i);
+ // increment now since LowerIntrinsic deletion makes iterator invalid.
+ ++i;
+ if(ii) {
+ switch (ii->getIntrinsicID()) {
+ case Intrinsic::vastart:
+ case Intrinsic::vaend:
+ break;
+
+ // Lower vacopy so that object resolution etc is handled by
+ // normal instructions. FIXME: This is broken for non-x86_32.
+ case Intrinsic::vacopy: { // (dst, src) -> *((i8**) dst) = *((i8**) src)
+ Value *dst = ii->getOperand(1);
+ Value *src = ii->getOperand(2);
+ Type *i8pp = PointerType::getUnqual(PointerType::getUnqual(Type::Int8Ty));
+ Value *castedDst = CastInst::CreatePointerCast(dst, i8pp, "vacopy.cast.dst", ii);
+ Value *castedSrc = CastInst::CreatePointerCast(src, i8pp, "vacopy.cast.src", ii);
+ Value *load = new LoadInst(castedSrc, "vacopy.read", ii);
+ new StoreInst(load, castedDst, false, ii);
+ ii->removeFromParent();
+ delete ii;
+ break;
+ }
+
+ case Intrinsic::dbg_stoppoint: {
+ // We can remove this stoppoint if the next instruction is
+ // sure to be another stoppoint. This is nice for cleanliness
+ // but also important for switch statements where it can allow
+ // the targets to be joined.
+ bool erase = false;
+ if (isa<DbgStopPointInst>(i) ||
+ isa<UnreachableInst>(i)) {
+ erase = true;
+ } else if (isa<BranchInst>(i) ||
+ isa<SwitchInst>(i)) {
+ BasicBlock *bb = i->getParent();
+ erase = true;
+ for (succ_iterator it=succ_begin(bb), ie=succ_end(bb);
+ it!=ie; ++it) {
+ if (!isa<DbgStopPointInst>(it->getFirstNonPHI())) {
+ erase = false;
+ break;
+ }
+ }
+ }
+
+ if (erase) {
+ ii->eraseFromParent();
+ dirty = true;
+ }
+ break;
+ }
+
+ case Intrinsic::dbg_region_start:
+ case Intrinsic::dbg_region_end:
+ case Intrinsic::dbg_func_start:
+ case Intrinsic::dbg_declare:
+ // Remove these regardless of lower intrinsics flag. This can
+ // be removed once IntrinsicLowering is fixed to not have bad
+ // caches.
+ ii->eraseFromParent();
+ dirty = true;
+ break;
+
+ default:
+ if (LowerIntrinsics)
+ IL->LowerIntrinsicCall(ii);
+ dirty = true;
+ break;
+ }
+ }
+ }
+
+ return dirty;
+}
+}
Added: klee/trunk/lib/Module/KInstruction.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/KInstruction.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/KInstruction.cpp (added)
+++ klee/trunk/lib/Module/KInstruction.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+//===-- KInstruction.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/Internal/Module/KInstruction.h"
+
+using namespace llvm;
+using namespace klee;
+
+/***/
+
+KInstruction::~KInstruction() {
+ delete[] operands;
+}
Added: klee/trunk/lib/Module/KModule.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/KModule.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/KModule.cpp (added)
+++ klee/trunk/lib/Module/KModule.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,506 @@
+//===-- KModule.cpp -------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: This does not belong here.
+#include "../Core/Common.h"
+
+#include "klee/Internal/Module/KModule.h"
+
+#include "Passes.h"
+
+#include "klee/Interpreter.h"
+#include "klee/Internal/Module/Cell.h"
+#include "klee/Internal/Module/KInstruction.h"
+#include "klee/Internal/Module/InstructionInfoTable.h"
+#include "klee/Internal/Support/ModuleUtil.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/ValueSymbolTable.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/System/Path.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Transforms/Scalar.h"
+
+#include <sstream>
+
+using namespace llvm;
+using namespace klee;
+
+namespace {
+ enum SwitchImplType {
+ eSwitchTypeSimple,
+ eSwitchTypeLLVM,
+ eSwitchTypeInternal
+ };
+
+ cl::list<std::string>
+ MergeAtExit("merge-at-exit");
+
+ cl::opt<bool>
+ NoTruncateSourceLines("no-truncate-source-lines",
+ cl::desc("Don't truncate long lines in the output source"));
+
+ cl::opt<bool>
+ OutputSource("output-source",
+ cl::desc("Write the assembly for the final transformed source"),
+ cl::init(true));
+
+ cl::opt<bool>
+ OutputModule("output-module",
+ cl::desc("Write the bitcode for the final transformed module"),
+ cl::init(false));
+
+ cl::opt<SwitchImplType>
+ SwitchType("switch-type", cl::desc("Select the implementation of switch"),
+ cl::values(clEnumValN(eSwitchTypeSimple, "simple",
+ "lower to ordered branches"),
+ clEnumValN(eSwitchTypeLLVM, "llvm",
+ "lower using LLVM"),
+ clEnumValN(eSwitchTypeInternal, "internal",
+ "execute switch internally"),
+ clEnumValEnd),
+ cl::init(eSwitchTypeInternal));
+
+ cl::opt<bool>
+ DebugPrintEscapingFunctions("debug-print-escaping-functions",
+ cl::desc("Print functions whose address is taken."));
+}
+
+KModule::KModule(Module *_module)
+ : module(_module),
+ targetData(new TargetData(module)),
+ dbgStopPointFn(0),
+ kleeMergeFn(0),
+ infos(0),
+ constantTable(0) {
+}
+
+KModule::~KModule() {
+ delete[] constantTable;
+ delete infos;
+
+ for (std::vector<KFunction*>::iterator it = functions.begin(),
+ ie = functions.end(); it != ie; ++it)
+ delete *it;
+
+ delete targetData;
+ delete module;
+}
+
+/***/
+
+namespace llvm {
+extern void Optimize(Module*);
+}
+
+// what a hack
+static Function *getStubFunctionForCtorList(Module *m,
+ GlobalVariable *gv,
+ std::string name) {
+ assert(!gv->isDeclaration() && !gv->hasInternalLinkage() &&
+ "do not support old LLVM style constructor/destructor lists");
+
+ std::vector<const Type*> nullary;
+
+ Function *fn = Function::Create(FunctionType::get(Type::VoidTy,
+ nullary, false),
+ GlobalVariable::InternalLinkage,
+ name,
+ m);
+ BasicBlock *bb = BasicBlock::Create("entry", fn);
+
+ // From lli:
+ // Should be an array of '{ int, void ()* }' structs. The first value is
+ // the init priority, which we ignore.
+ ConstantArray *arr = dyn_cast<ConstantArray>(gv->getInitializer());
+ if (arr) {
+ for (unsigned i=0; i<arr->getNumOperands(); i++) {
+ ConstantStruct *cs = cast<ConstantStruct>(arr->getOperand(i));
+ assert(cs->getNumOperands()==2 && "unexpected element in ctor initializer list");
+
+ Constant *fp = cs->getOperand(1);
+ if (!fp->isNullValue()) {
+ if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(fp))
+ fp = ce->getOperand(0);
+
+ if (Function *f = dyn_cast<Function>(fp)) {
+ CallInst::Create(f, "", bb);
+ } else {
+ assert(0 && "unable to get function pointer from ctor initializer list");
+ }
+ }
+ }
+ }
+
+ ReturnInst::Create(bb);
+
+ return fn;
+}
+
+static void injectStaticConstructorsAndDestructors(Module *m) {
+ GlobalVariable *ctors = m->getNamedGlobal("llvm.global_ctors");
+ GlobalVariable *dtors = m->getNamedGlobal("llvm.global_dtors");
+
+ if (ctors || dtors) {
+ Function *mainFn = m->getFunction("main");
+ assert(mainFn && "unable to find main function");
+
+ if (ctors)
+ CallInst::Create(getStubFunctionForCtorList(m, ctors, "klee.ctor_stub"),
+ "", mainFn->begin()->begin());
+ if (dtors) {
+ Function *dtorStub = getStubFunctionForCtorList(m, dtors, "klee.dtor_stub");
+ for (Function::iterator it = mainFn->begin(), ie = mainFn->end();
+ it != ie; ++it) {
+ if (isa<ReturnInst>(it->getTerminator()))
+ CallInst::Create(dtorStub, "", it->getTerminator());
+ }
+ }
+ }
+}
+
+static void forceImport(Module *m, const char *name, const Type *retType, ...) {
+ // If module lacks an externally visible symbol for the name then we
+ // need to create one. We have to look in the symbol table because
+ // we want to check everything (global variables, functions, and
+ // aliases).
+
+ Value *v = m->getValueSymbolTable().lookup(name);
+ GlobalValue *gv = dyn_cast_or_null<GlobalValue>(v);
+
+ if (!gv || gv->hasInternalLinkage()) {
+ va_list ap;
+
+ va_start(ap, retType);
+ std::vector<const Type *> argTypes;
+ while (const Type *t = va_arg(ap, const Type*))
+ argTypes.push_back(t);
+ va_end(ap);
+
+ m->getOrInsertFunction(name, FunctionType::get(retType, argTypes, false));
+ }
+}
+
+void KModule::prepare(const Interpreter::ModuleOptions &opts,
+ InterpreterHandler *ih) {
+ if (!MergeAtExit.empty()) {
+ Function *mergeFn = module->getFunction("klee_merge");
+ if (!mergeFn) {
+ const llvm::FunctionType *Ty =
+ FunctionType::get(Type::VoidTy, std::vector<const Type*>(), false);
+ mergeFn = Function::Create(Ty, GlobalVariable::ExternalLinkage,
+ "klee_merge",
+ module);
+ }
+
+ for (cl::list<std::string>::iterator it = MergeAtExit.begin(),
+ ie = MergeAtExit.end(); it != ie; ++it) {
+ std::string &name = *it;
+ Function *f = module->getFunction(name);
+ if (!f) {
+ klee_error("cannot insert merge-at-exit for: %s (cannot find)",
+ name.c_str());
+ } else if (f->isDeclaration()) {
+ klee_error("cannot insert merge-at-exit for: %s (external)",
+ name.c_str());
+ }
+
+ BasicBlock *exit = BasicBlock::Create("exit", f);
+ PHINode *result = 0;
+ if (f->getReturnType() != Type::VoidTy)
+ result = PHINode::Create(f->getReturnType(), "retval", exit);
+ CallInst::Create(mergeFn, "", exit);
+ ReturnInst::Create(result, exit);
+
+ llvm::cerr << "KLEE: adding klee_merge at exit of: " << name << "\n";
+ for (llvm::Function::iterator bbit = f->begin(), bbie = f->end();
+ bbit != bbie; ++bbit) {
+ if (&*bbit != exit) {
+ Instruction *i = bbit->getTerminator();
+ if (i->getOpcode()==Instruction::Ret) {
+ if (result) {
+ result->addIncoming(i->getOperand(0), bbit);
+ }
+ i->eraseFromParent();
+ BranchInst::Create(exit, bbit);
+ }
+ }
+ }
+ }
+ }
+
+ // Inject checks prior to optimization... we also perform the
+ // invariant transformations that we will end up doing later so that
+ // optimize is seeing what is as close as possible to the final
+ // module.
+ PassManager pm;
+ pm.add(new RaiseAsmPass());
+ if (opts.CheckDivZero) pm.add(new DivCheckPass());
+ // FIXME: This false here is to work around a bug in
+ // IntrinsicLowering which caches values which may eventually be
+ // deleted (via RAUW). This can be removed once LLVM fixes this
+ // issue.
+ pm.add(new IntrinsicCleanerPass(*targetData, false));
+ pm.run(*module);
+
+ if (opts.Optimize)
+ Optimize(module);
+
+ // Force importing functions required by intrinsic lowering. Kind of
+ // unfortunate clutter when we don't need them but we won't know
+ // that until after all linking and intrinsic lowering is
+ // done. After linking and passes we just try to manually trim these
+ // by name. We only add them if such a function doesn't exist to
+ // avoid creating stale uses.
+
+ forceImport(module, "memcpy", PointerType::getUnqual(Type::Int8Ty),
+ PointerType::getUnqual(Type::Int8Ty),
+ PointerType::getUnqual(Type::Int8Ty),
+ targetData->getIntPtrType(), (Type*) 0);
+ forceImport(module, "memmove", PointerType::getUnqual(Type::Int8Ty),
+ PointerType::getUnqual(Type::Int8Ty),
+ PointerType::getUnqual(Type::Int8Ty),
+ targetData->getIntPtrType(), (Type*) 0);
+ forceImport(module, "memset", PointerType::getUnqual(Type::Int8Ty),
+ PointerType::getUnqual(Type::Int8Ty),
+ Type::Int32Ty,
+ targetData->getIntPtrType(), (Type*) 0);
+
+ // FIXME: Missing force import for various math functions.
+
+ // FIXME: Find a way that we can test programs without requiring
+ // this to be linked in, it makes low level debugging much more
+ // annoying.
+ llvm::sys::Path path(opts.LibraryDir);
+ path.appendComponent("libintrinsic.bca");
+ module = linkWithLibrary(module, path.c_str());
+
+ // Needs to happen after linking (since ctors/dtors can be modified)
+ // and optimization (since global optimization can rewrite lists).
+ injectStaticConstructorsAndDestructors(module);
+
+ // Finally, run the passes that maintain invariants we expect during
+ // interpretation. We run the intrinsic cleaner just in case we
+ // linked in something with intrinsics but any external calls are
+ // going to be unresolved. We really need to handle the intrinsics
+ // directly I think?
+ PassManager pm3;
+ pm3.add(createCFGSimplificationPass());
+ switch(SwitchType) {
+ case eSwitchTypeInternal: break;
+ case eSwitchTypeSimple: pm3.add(new LowerSwitchPass()); break;
+ case eSwitchTypeLLVM: pm3.add(createLowerSwitchPass()); break;
+ default: klee_error("invalid --switch-type");
+ }
+ pm3.add(new IntrinsicCleanerPass(*targetData));
+ pm3.add(new PhiCleanerPass());
+ pm3.run(*module);
+
+ // For cleanliness see if we can discard any of the functions we
+ // forced to import.
+ Function *f;
+ f = module->getFunction("memcpy");
+ if (f && f->use_empty()) f->eraseFromParent();
+ f = module->getFunction("memmove");
+ if (f && f->use_empty()) f->eraseFromParent();
+ f = module->getFunction("memset");
+ if (f && f->use_empty()) f->eraseFromParent();
+
+
+ // Write out the .ll assembly file. We truncate long lines to work
+ // around a kcachegrind parsing bug (it puts them on new lines), so
+ // that source browsing works.
+ if (OutputSource) {
+ std::ostream *os = ih->openOutputFile("assembly.ll");
+ assert(os && os->good() && "unable to open source output");
+
+ // We have an option for this in case the user wants a .ll they
+ // can compile.
+ if (NoTruncateSourceLines) {
+ *os << *module;
+ } else {
+ bool truncated = false;
+ std::stringstream buffer;
+ buffer << *module;
+ std::string string = buffer.str();
+ const char *position = string.c_str();
+
+ for (;;) {
+ const char *end = index(position, '\n');
+ if (!end) {
+ *os << position;
+ break;
+ } else {
+ unsigned count = (end - position) + 1;
+ if (count<255) {
+ os->write(position, count);
+ } else {
+ os->write(position, 254);
+ *os << "\n";
+ truncated = true;
+ }
+ position = end+1;
+ }
+ }
+ }
+
+ delete os;
+ }
+
+ if (OutputModule) {
+ std::ostream *f = ih->openOutputFile("final.bc");
+ WriteBitcodeToFile(module, *f);
+ delete f;
+ }
+
+ dbgStopPointFn = module->getFunction("llvm.dbg.stoppoint");
+ kleeMergeFn = module->getFunction("klee_merge");
+
+ /* Build shadow structures */
+
+ infos = new InstructionInfoTable(module);
+
+ for (Module::iterator it = module->begin(), ie = module->end();
+ it != ie; ++it) {
+ if (it->isDeclaration())
+ continue;
+
+ KFunction *kf = new KFunction(it, this);
+
+ for (unsigned i=0; i<kf->numInstructions; ++i) {
+ KInstruction *ki = kf->instructions[i];
+ ki->info = &infos->getInfo(ki->inst);
+ }
+
+ functions.push_back(kf);
+ functionMap.insert(std::make_pair(it, kf));
+ }
+
+ /* Compute various interesting properties */
+
+ for (std::vector<KFunction*>::iterator it = functions.begin(),
+ ie = functions.end(); it != ie; ++it) {
+ KFunction *kf = *it;
+ if (functionEscapes(kf->function))
+ escapingFunctions.insert(kf->function);
+ }
+
+ if (DebugPrintEscapingFunctions && !escapingFunctions.empty()) {
+ llvm::cerr << "KLEE: escaping functions: [";
+ for (std::set<Function*>::iterator it = escapingFunctions.begin(),
+ ie = escapingFunctions.end(); it != ie; ++it) {
+ llvm::cerr << (*it)->getName() << ", ";
+ }
+ llvm::cerr << "]\n";
+ }
+}
+
+KConstant* KModule::getKConstant(Constant *c) {
+ std::map<llvm::Constant*, KConstant*>::iterator it = constantMap.find(c);
+ if (it != constantMap.end())
+ return it->second;
+ return NULL;
+}
+
+unsigned KModule::getConstantID(Constant *c, KInstruction* ki) {
+ KConstant *kc = getKConstant(c);
+ if (kc)
+ return kc->id;
+
+ unsigned id = constants.size();
+ kc = new KConstant(c, id, ki);
+ constantMap.insert(std::make_pair(c, kc));
+ constants.push_back(c);
+ return id;
+}
+
+/***/
+
+KConstant::KConstant(llvm::Constant* _ct, unsigned _id, KInstruction* _ki) {
+ ct = _ct;
+ id = _id;
+ ki = _ki;
+}
+
+/***/
+
+KFunction::KFunction(llvm::Function *_function,
+ KModule *km)
+ : function(_function),
+ numArgs(function->arg_size()),
+ numInstructions(0),
+ trackCoverage(true) {
+ for (llvm::Function::iterator bbit = function->begin(),
+ bbie = function->end(); bbit != bbie; ++bbit) {
+ BasicBlock *bb = bbit;
+ basicBlockEntry[bb] = numInstructions;
+ numInstructions += bb->size();
+ }
+
+ instructions = new KInstruction*[numInstructions];
+
+ std::map<Instruction*, unsigned> registerMap;
+
+ // The first arg_size() registers are reserved for formals.
+ unsigned rnum = numArgs;
+ for (llvm::Function::iterator bbit = function->begin(),
+ bbie = function->end(); bbit != bbie; ++bbit) {
+ for (llvm::BasicBlock::iterator it = bbit->begin(), ie = bbit->end();
+ it != ie; ++it)
+ registerMap[it] = rnum++;
+ }
+ numRegisters = rnum;
+
+ unsigned i = 0;
+ for (llvm::Function::iterator bbit = function->begin(),
+ bbie = function->end(); bbit != bbie; ++bbit) {
+ for (llvm::BasicBlock::iterator it = bbit->begin(), ie = bbit->end();
+ it != ie; ++it) {
+ KInstruction *ki;
+
+ switch(it->getOpcode()) {
+ case Instruction::GetElementPtr:
+ ki = new KGEPInstruction(); break;
+ default:
+ ki = new KInstruction(); break;
+ }
+
+ unsigned numOperands = it->getNumOperands();
+ ki->inst = it;
+ ki->operands = new int[numOperands];
+ ki->dest = registerMap[it];
+ for (unsigned j=0; j<numOperands; j++) {
+ Value *v = it->getOperand(j);
+
+ if (Instruction *inst = dyn_cast<Instruction>(v)) {
+ ki->operands[j] = registerMap[inst];
+ } else if (Argument *a = dyn_cast<Argument>(v)) {
+ ki->operands[j] = a->getArgNo();
+ } else if (isa<BasicBlock>(v) || isa<InlineAsm>(v)) {
+ ki->operands[j] = -1;
+ } else {
+ assert(isa<Constant>(v));
+ Constant *c = cast<Constant>(v);
+ ki->operands[j] = -(km->getConstantID(c, ki) + 2);
+ }
+ }
+
+ instructions[i++] = ki;
+ }
+ }
+}
+
+KFunction::~KFunction() {
+ for (unsigned i=0; i<numInstructions; ++i)
+ delete instructions[i];
+ delete[] instructions;
+}
Added: klee/trunk/lib/Module/LowerSwitch.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/LowerSwitch.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/LowerSwitch.cpp (added)
+++ klee/trunk/lib/Module/LowerSwitch.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,134 @@
+//===-- LowerSwitch.cpp - Eliminate Switch instructions -------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Derived from LowerSwitch.cpp in LLVM, heavily modified by piotrek
+// to get rid of the binary search transform, as it was creating
+// multiple paths through the program (i.e., extra paths that didn't
+// exist in the original program).
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+#include <algorithm>
+
+using namespace llvm;
+
+namespace klee {
+
+char LowerSwitchPass::ID = 0;
+
+// The comparison function for sorting the switch case values in the vector.
+struct SwitchCaseCmp {
+ bool operator () (const LowerSwitchPass::SwitchCase& C1,
+ const LowerSwitchPass::SwitchCase& C2) {
+
+ const ConstantInt* CI1 = cast<const ConstantInt>(C1.value);
+ const ConstantInt* CI2 = cast<const ConstantInt>(C2.value);
+ return CI1->getValue().slt(CI2->getValue());
+ }
+};
+
+bool LowerSwitchPass::runOnFunction(Function &F) {
+ bool changed = false;
+
+ for (Function::iterator I = F.begin(), E = F.end(); I != E; ) {
+ BasicBlock *cur = I++; // Advance over block so we don't traverse new blocks
+
+ if (SwitchInst *SI = dyn_cast<SwitchInst>(cur->getTerminator())) {
+ changed = true;
+ processSwitchInst(SI);
+ }
+ }
+
+ return changed;
+}
+
+// switchConvert - Convert the switch statement into a linear scan
+// through all the case values
+void LowerSwitchPass::switchConvert(CaseItr begin, CaseItr end,
+ Value* value, BasicBlock* origBlock,
+ BasicBlock* defaultBlock)
+{
+ BasicBlock *curHead = defaultBlock;
+ Function *F = origBlock->getParent();
+
+ // iterate through all the cases, creating a new BasicBlock for each
+ for (CaseItr it = begin; it < end; ++it) {
+ BasicBlock *newBlock = BasicBlock::Create("NodeBlock");
+ Function::iterator FI = origBlock;
+ F->getBasicBlockList().insert(++FI, newBlock);
+
+ ICmpInst *cmpInst = new ICmpInst(ICmpInst::ICMP_EQ,
+ value,
+ it->value,
+ "Case Comparison");
+
+ newBlock->getInstList().push_back(cmpInst);
+ BranchInst::Create(it->block, curHead, cmpInst, newBlock);
+
+ // If there were any PHI nodes in this successor, rewrite one entry
+ // from origBlock to come from newBlock.
+ for (BasicBlock::iterator bi = it->block->begin(); isa<PHINode>(bi); ++bi) {
+ PHINode* PN = cast<PHINode>(bi);
+
+ int blockIndex = PN->getBasicBlockIndex(origBlock);
+ assert(blockIndex != -1 && "Switch didn't go to this successor??");
+ PN->setIncomingBlock((unsigned)blockIndex, newBlock);
+ }
+
+ curHead = newBlock;
+ }
+
+ // Branch to our shiny new if-then stuff...
+ BranchInst::Create(curHead, origBlock);
+}
+
+// processSwitchInst - Replace the specified switch instruction with a sequence
+// of chained if-then instructions.
+//
+void LowerSwitchPass::processSwitchInst(SwitchInst *SI) {
+ BasicBlock *origBlock = SI->getParent();
+ BasicBlock *defaultBlock = SI->getDefaultDest();
+ Function *F = origBlock->getParent();
+ Value *switchValue = SI->getOperand(0);
+
+ // Create a new, empty default block so that the new hierarchy of
+ // if-then statements go to this and the PHI nodes are happy.
+ BasicBlock* newDefault = BasicBlock::Create("newDefault");
+
+ F->getBasicBlockList().insert(defaultBlock, newDefault);
+ BranchInst::Create(defaultBlock, newDefault);
+
+ // If there is an entry in any PHI nodes for the default edge, make sure
+ // to update them as well.
+ for (BasicBlock::iterator I = defaultBlock->begin(); isa<PHINode>(I); ++I) {
+ PHINode *PN = cast<PHINode>(I);
+ int BlockIdx = PN->getBasicBlockIndex(origBlock);
+ assert(BlockIdx != -1 && "Switch didn't go to this successor??");
+ PN->setIncomingBlock((unsigned)BlockIdx, newDefault);
+ }
+
+ CaseVector cases;
+ for (unsigned i = 1; i < SI->getNumSuccessors(); ++i)
+ cases.push_back(SwitchCase(SI->getSuccessorValue(i),
+ SI->getSuccessor(i)));
+
+ // reverse cases, as switchConvert constructs a chain of
+ // basic blocks by appending to the front. if we reverse,
+ // the if comparisons will happen in the same order
+ // as the cases appear in the switch
+ std::reverse(cases.begin(), cases.end());
+
+ switchConvert(cases.begin(), cases.end(), switchValue, origBlock, newDefault);
+
+ // We are now done with the switch instruction, so delete it
+ origBlock->getInstList().erase(SI);
+}
+
+}
Added: klee/trunk/lib/Module/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/Makefile (added)
+++ klee/trunk/lib/Module/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+#===-- lib/Module/Makefile ---------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleeModule
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+
+include $(LEVEL)/Makefile.common
Propchange: klee/trunk/lib/Module/Makefile
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/lib/Module/ModuleUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/ModuleUtil.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/ModuleUtil.cpp (added)
+++ klee/trunk/lib/Module/ModuleUtil.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,101 @@
+//===-- ModuleUtil.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/Internal/Support/ModuleUtil.h"
+
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/Linker.h"
+#include "llvm/Module.h"
+#include "llvm/Assembly/AsmAnnotationWriter.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Analysis/ValueTracking.h"
+
+#include <map>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+using namespace llvm;
+using namespace klee;
+
+Module *klee::linkWithLibrary(Module *module,
+ const std::string &libraryName) {
+ try {
+ Linker linker("klee", module, false);
+
+ llvm::sys::Path libraryPath(libraryName);
+ bool native = false;
+
+ if (linker.LinkInFile(libraryPath, native)) {
+ assert(0 && "linking in library failed!");
+ }
+
+ return linker.releaseModule();
+ } catch (...) {
+ assert(0 && "error during linking");
+ }
+}
+
+Function *klee::getDirectCallTarget(const Instruction *i) {
+ assert(isa<CallInst>(i) || isa<InvokeInst>(i));
+
+ Value *v = i->getOperand(0);
+ if (Function *f = dyn_cast<Function>(v)) {
+ return f;
+ } else if (llvm::ConstantExpr *ce = dyn_cast<llvm::ConstantExpr>(v)) {
+ if (ce->getOpcode()==Instruction::BitCast)
+ if (Function *f = dyn_cast<Function>(ce->getOperand(0)))
+ return f;
+
+ // NOTE: This assert may fire, it isn't necessarily a problem and
+ // can be disabled, I just wanted to know when and if it happened.
+ assert(0 && "FIXME: Unresolved direct target for a constant expression.");
+ }
+
+ return 0;
+}
+
+static bool valueIsOnlyCalled(const Value *v) {
+ for (Value::use_const_iterator it = v->use_begin(), ie = v->use_end();
+ it != ie; ++it) {
+ if (const Instruction *instr = dyn_cast<Instruction>(*it)) {
+ if (instr->getOpcode()==0) continue; // XXX function numbering inst
+ if (!isa<CallInst>(instr) && !isa<InvokeInst>(instr)) return false;
+
+ // Make sure that the value is only the target of this call and
+ // not an argument.
+ for (unsigned i=1,e=instr->getNumOperands(); i!=e; ++i)
+ if (instr->getOperand(i)==v)
+ return false;
+ } else if (const llvm::ConstantExpr *ce =
+ dyn_cast<llvm::ConstantExpr>(*it)) {
+ if (ce->getOpcode()==Instruction::BitCast)
+ if (valueIsOnlyCalled(ce))
+ continue;
+ return false;
+ } else if (const GlobalAlias *ga = dyn_cast<GlobalAlias>(*it)) {
+ // XXX what about v is bitcast of aliasee?
+ if (v==ga->getAliasee() && !valueIsOnlyCalled(ga))
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool klee::functionEscapes(const Function *f) {
+ return !valueIsOnlyCalled(f);
+}
Added: klee/trunk/lib/Module/Optimize.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/Optimize.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/Optimize.cpp (added)
+++ klee/trunk/lib/Module/Optimize.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,272 @@
+// FIXME: This file is a bastard child of opt.cpp and llvm-ld's
+// Optimize.cpp. This stuff should live in common code.
+
+
+//===- Optimize.cpp - Optimize a complete program -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements all optimization of the linked module for llvm-ld.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Analysis/Passes.h"
+#include "llvm/Analysis/LoopPass.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/System/DynamicLibrary.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Support/PassNameParser.h"
+#include "llvm/Support/PluginLoader.h"
+#include <iostream>
+using namespace llvm;
+
+#if 0
+// Pass Name Options as generated by the PassNameParser
+static cl::list<const PassInfo*, bool, PassNameParser>
+ OptimizationList(cl::desc("Optimizations available:"));
+#endif
+
+// Don't verify at the end
+static cl::opt<bool> DontVerify("disable-verify", cl::ReallyHidden);
+
+static cl::opt<bool> DisableInline("disable-inlining",
+ cl::desc("Do not run the inliner pass"));
+
+static cl::opt<bool>
+DisableOptimizations("disable-opt",
+ cl::desc("Do not run any optimization passes"));
+
+static cl::opt<bool> DisableInternalize("disable-internalize",
+ cl::desc("Do not mark all symbols as internal"));
+
+static cl::opt<bool> VerifyEach("verify-each",
+ cl::desc("Verify intermediate results of all passes"));
+
+static cl::alias ExportDynamic("export-dynamic",
+ cl::aliasopt(DisableInternalize),
+ cl::desc("Alias for -disable-internalize"));
+
+static cl::opt<bool> Strip("strip-all",
+ cl::desc("Strip all symbol info from executable"));
+
+static cl::alias A0("s", cl::desc("Alias for --strip-all"),
+ cl::aliasopt(Strip));
+
+static cl::opt<bool> StripDebug("strip-debug",
+ cl::desc("Strip debugger symbol info from executable"));
+
+static cl::alias A1("S", cl::desc("Alias for --strip-debug"),
+ cl::aliasopt(StripDebug));
+
+// A utility function that adds a pass to the pass manager but will also add
+// a verifier pass after if we're supposed to verify.
+static inline void addPass(PassManager &PM, Pass *P) {
+ // Add the pass to the pass manager...
+ PM.add(P);
+
+ // If we are verifying all of the intermediate steps, add the verifier...
+ if (VerifyEach)
+ PM.add(createVerifierPass());
+}
+
+namespace llvm {
+
+
+static void AddStandardCompilePasses(PassManager &PM) {
+ PM.add(createVerifierPass()); // Verify that input is correct
+
+ addPass(PM, createLowerSetJmpPass()); // Lower llvm.setjmp/.longjmp
+
+ // If the -strip-debug command line option was specified, do it.
+ if (StripDebug)
+ addPass(PM, createStripSymbolsPass(true));
+
+ if (DisableOptimizations) return;
+
+ addPass(PM, createRaiseAllocationsPass()); // call %malloc -> malloc inst
+ addPass(PM, createCFGSimplificationPass()); // Clean up disgusting code
+ addPass(PM, createPromoteMemoryToRegisterPass());// Kill useless allocas
+ addPass(PM, createGlobalOptimizerPass()); // Optimize out global vars
+ addPass(PM, createGlobalDCEPass()); // Remove unused fns and globs
+ addPass(PM, createIPConstantPropagationPass());// IP Constant Propagation
+ addPass(PM, createDeadArgEliminationPass()); // Dead argument elimination
+ addPass(PM, createInstructionCombiningPass()); // Clean up after IPCP & DAE
+ addPass(PM, createCFGSimplificationPass()); // Clean up after IPCP & DAE
+
+ addPass(PM, createPruneEHPass()); // Remove dead EH info
+ addPass(PM, createFunctionAttrsPass()); // Deduce function attrs
+
+ if (!DisableInline)
+ addPass(PM, createFunctionInliningPass()); // Inline small functions
+ addPass(PM, createArgumentPromotionPass()); // Scalarize uninlined fn args
+
+ addPass(PM, createSimplifyLibCallsPass()); // Library Call Optimizations
+ addPass(PM, createInstructionCombiningPass()); // Cleanup for scalarrepl.
+ addPass(PM, createJumpThreadingPass()); // Thread jumps.
+ addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs
+ addPass(PM, createScalarReplAggregatesPass()); // Break up aggregate allocas
+ addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
+ addPass(PM, createCondPropagationPass()); // Propagate conditionals
+
+ addPass(PM, createTailCallEliminationPass()); // Eliminate tail calls
+ addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs
+ addPass(PM, createReassociatePass()); // Reassociate expressions
+ addPass(PM, createLoopRotatePass());
+ addPass(PM, createLICMPass()); // Hoist loop invariants
+ addPass(PM, createLoopUnswitchPass()); // Unswitch loops.
+ addPass(PM, createLoopIndexSplitPass()); // Index split loops.
+ // FIXME : Removing instcombine causes nestedloop regression.
+ addPass(PM, createInstructionCombiningPass());
+ addPass(PM, createIndVarSimplifyPass()); // Canonicalize indvars
+ addPass(PM, createLoopDeletionPass()); // Delete dead loops
+ addPass(PM, createLoopUnrollPass()); // Unroll small loops
+ addPass(PM, createInstructionCombiningPass()); // Clean up after the unroller
+ addPass(PM, createGVNPass()); // Remove redundancies
+ addPass(PM, createMemCpyOptPass()); // Remove memcpy / form memset
+ addPass(PM, createSCCPPass()); // Constant prop with SCCP
+
+ // Run instcombine after redundancy elimination to exploit opportunities
+ // opened up by them.
+ addPass(PM, createInstructionCombiningPass());
+ addPass(PM, createCondPropagationPass()); // Propagate conditionals
+
+ addPass(PM, createDeadStoreEliminationPass()); // Delete dead stores
+ addPass(PM, createAggressiveDCEPass()); // Delete dead instructions
+ addPass(PM, createCFGSimplificationPass()); // Merge & remove BBs
+ addPass(PM, createStripDeadPrototypesPass()); // Get rid of dead prototypes
+ addPass(PM, createDeadTypeEliminationPass()); // Eliminate dead types
+ addPass(PM, createConstantMergePass()); // Merge dup global constants
+}
+
+/// Optimize - Perform link time optimizations. This will run the scalar
+/// optimizations, any loaded plugin-optimization modules, and then the
+/// inter-procedural optimizations if applicable.
+void Optimize(Module* M) {
+
+ // Instantiate the pass manager to organize the passes.
+ PassManager Passes;
+
+ // If we're verifying, start off with a verification pass.
+ if (VerifyEach)
+ Passes.add(createVerifierPass());
+
+ // Add an appropriate TargetData instance for this module...
+ addPass(Passes, new TargetData(M));
+
+ // DWD - Run the opt standard pass list as well.
+ AddStandardCompilePasses(Passes);
+
+ if (!DisableOptimizations) {
+ // Now that composite has been compiled, scan through the module, looking
+ // for a main function. If main is defined, mark all other functions
+ // internal.
+ if (!DisableInternalize)
+ addPass(Passes, createInternalizePass(true));
+
+ // Propagate constants at call sites into the functions they call. This
+ // opens opportunities for globalopt (and inlining) by substituting function
+ // pointers passed as arguments to direct uses of functions.
+ addPass(Passes, createIPSCCPPass());
+
+ // Now that we internalized some globals, see if we can hack on them!
+ addPass(Passes, createGlobalOptimizerPass());
+
+ // Linking modules together can lead to duplicated global constants, only
+ // keep one copy of each constant...
+ addPass(Passes, createConstantMergePass());
+
+ // Remove unused arguments from functions...
+ addPass(Passes, createDeadArgEliminationPass());
+
+ // Reduce the code after globalopt and ipsccp. Both can open up significant
+ // simplification opportunities, and both can propagate functions through
+ // function pointers. When this happens, we often have to resolve varargs
+ // calls, etc, so let instcombine do this.
+ addPass(Passes, createInstructionCombiningPass());
+
+ if (!DisableInline)
+ addPass(Passes, createFunctionInliningPass()); // Inline small functions
+
+ addPass(Passes, createPruneEHPass()); // Remove dead EH info
+ addPass(Passes, createGlobalOptimizerPass()); // Optimize globals again.
+ addPass(Passes, createGlobalDCEPass()); // Remove dead functions
+
+ // If we didn't decide to inline a function, check to see if we can
+ // transform it to pass arguments by value instead of by reference.
+ addPass(Passes, createArgumentPromotionPass());
+
+ // The IPO passes may leave cruft around. Clean up after them.
+ addPass(Passes, createInstructionCombiningPass());
+ addPass(Passes, createJumpThreadingPass()); // Thread jumps.
+ addPass(Passes, createScalarReplAggregatesPass()); // Break up allocas
+
+ // Run a few AA driven optimizations here and now, to cleanup the code.
+ addPass(Passes, createFunctionAttrsPass()); // Add nocapture
+ addPass(Passes, createGlobalsModRefPass()); // IP alias analysis
+
+ addPass(Passes, createLICMPass()); // Hoist loop invariants
+ addPass(Passes, createGVNPass()); // Remove redundancies
+ addPass(Passes, createMemCpyOptPass()); // Remove dead memcpy's
+ addPass(Passes, createDeadStoreEliminationPass()); // Nuke dead stores
+
+ // Cleanup and simplify the code after the scalar optimizations.
+ addPass(Passes, createInstructionCombiningPass());
+
+ addPass(Passes, createJumpThreadingPass()); // Thread jumps.
+ addPass(Passes, createPromoteMemoryToRegisterPass()); // Cleanup jumpthread.
+
+ // Delete basic blocks, which optimization passes may have killed...
+ addPass(Passes, createCFGSimplificationPass());
+
+ // Now that we have optimized the program, discard unreachable functions...
+ addPass(Passes, createGlobalDCEPass());
+ }
+
+ // If the -s or -S command line options were specified, strip the symbols out
+ // of the resulting program to make it smaller. -s and -S are GNU ld options
+ // that we are supporting; they alias -strip-all and -strip-debug.
+ if (Strip || StripDebug)
+ addPass(Passes, createStripSymbolsPass(StripDebug && !Strip));
+
+#if 0
+ // Create a new optimization pass for each one specified on the command line
+ std::auto_ptr<TargetMachine> target;
+ for (unsigned i = 0; i < OptimizationList.size(); ++i) {
+ const PassInfo *Opt = OptimizationList[i];
+ if (Opt->getNormalCtor())
+ addPass(Passes, Opt->getNormalCtor()());
+ else
+ std::cerr << "llvm-ld: cannot create pass: " << Opt->getPassName()
+ << "\n";
+ }
+#endif
+
+ // The user's passes may leave cruft around. Clean up after them them but
+ // only if we haven't got DisableOptimizations set
+ if (!DisableOptimizations) {
+ addPass(Passes, createInstructionCombiningPass());
+ addPass(Passes, createCFGSimplificationPass());
+ addPass(Passes, createAggressiveDCEPass());
+ addPass(Passes, createGlobalDCEPass());
+ }
+
+ // Make sure everything is still good.
+ if (!DontVerify)
+ Passes.add(createVerifierPass());
+
+ // Run our queue of passes all at once now, efficiently.
+ Passes.run(*M);
+}
+
+}
Added: klee/trunk/lib/Module/Passes.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/Passes.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/Passes.h (added)
+++ klee/trunk/lib/Module/Passes.h Wed May 20 23:36:41 2009
@@ -0,0 +1,132 @@
+//===-- Passes.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_PASSES_H
+#define KLEE_PASSES_H
+
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/CodeGen/IntrinsicLowering.h"
+
+namespace llvm {
+ class Function;
+ class Instruction;
+ class Module;
+ class TargetData;
+ class Type;
+}
+
+namespace klee {
+
+ /// RaiseAsmPass - This pass raises some common occurences of inline
+ /// asm which are used by glibc into normal LLVM IR.
+class RaiseAsmPass : public llvm::ModulePass {
+ static char ID;
+
+ llvm::Function *getIntrinsic(llvm::Module &M,
+ unsigned IID,
+ const llvm::Type **Tys,
+ unsigned NumTys);
+ llvm::Function *getIntrinsic(llvm::Module &M,
+ unsigned IID,
+ const llvm::Type *Ty0) {
+ return getIntrinsic(M, IID, &Ty0, 1);
+ }
+
+ bool runOnInstruction(llvm::Module &M, llvm::Instruction *I);
+
+public:
+ RaiseAsmPass() : llvm::ModulePass((intptr_t) &ID) {}
+
+ virtual bool runOnModule(llvm::Module &M);
+};
+
+ // This is a module pass because it can add and delete module
+ // variables (via intrinsic lowering).
+class IntrinsicCleanerPass : public llvm::ModulePass {
+ static char ID;
+ llvm::IntrinsicLowering *IL;
+ bool LowerIntrinsics;
+
+ bool runOnBasicBlock(llvm::BasicBlock &b);
+public:
+ IntrinsicCleanerPass(const llvm::TargetData &TD,
+ bool LI=true)
+ : llvm::ModulePass((intptr_t) &ID),
+ IL(new llvm::IntrinsicLowering(TD)),
+ LowerIntrinsics(LI) {}
+ ~IntrinsicCleanerPass() { delete IL; }
+
+ virtual bool runOnModule(llvm::Module &M);
+};
+
+ // performs two transformations which make interpretation
+ // easier and faster.
+ //
+ // 1) Ensure that all the PHI nodes in a basic block have
+ // the incoming block list in the same order. Thus the
+ // incoming block index only needs to be computed once
+ // for each transfer.
+ //
+ // 2) Ensure that no PHI node result is used as an argument to
+ // a subsequent PHI node in the same basic block. This allows
+ // the transfer to execute the instructions in order instead
+ // of in two passes.
+class PhiCleanerPass : public llvm::FunctionPass {
+ static char ID;
+
+public:
+ PhiCleanerPass() : llvm::FunctionPass((intptr_t) &ID) {}
+
+ virtual bool runOnFunction(llvm::Function &f);
+};
+
+class DivCheckPass : public llvm::ModulePass {
+ static char ID;
+public:
+ DivCheckPass(): ModulePass((intptr_t) &ID) {}
+ virtual bool runOnModule(llvm::Module &M);
+};
+
+/// LowerSwitchPass - Replace all SwitchInst instructions with chained branch
+/// instructions. Note that this cannot be a BasicBlock pass because it
+/// modifies the CFG!
+class LowerSwitchPass : public llvm::FunctionPass {
+public:
+ static char ID; // Pass identification, replacement for typeid
+ LowerSwitchPass() : FunctionPass((intptr_t) &ID) {}
+
+ virtual bool runOnFunction(llvm::Function &F);
+
+ struct SwitchCase {
+ llvm ::Constant *value;
+ llvm::BasicBlock *block;
+
+ SwitchCase() : value(0), block(0) { }
+ SwitchCase(llvm::Constant *v, llvm::BasicBlock *b) :
+ value(v), block(b) { }
+ };
+
+ typedef std::vector<SwitchCase> CaseVector;
+ typedef std::vector<SwitchCase>::iterator CaseItr;
+
+private:
+ void processSwitchInst(llvm::SwitchInst *SI);
+ void switchConvert(CaseItr begin,
+ CaseItr end,
+ llvm::Value *value,
+ llvm::BasicBlock *origBlock,
+ llvm::BasicBlock *defaultBlock);
+};
+
+}
+
+#endif
Added: klee/trunk/lib/Module/PhiCleaner.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/PhiCleaner.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/PhiCleaner.cpp (added)
+++ klee/trunk/lib/Module/PhiCleaner.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,83 @@
+//===-- PhiCleaner.cpp ----------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+
+#include <set>
+
+using namespace llvm;
+
+char klee::PhiCleanerPass::ID = 0;
+
+bool klee::PhiCleanerPass::runOnFunction(Function &f) {
+ bool changed = false;
+
+ for (Function::iterator b = f.begin(), be = f.end(); b != be; ++b) {
+ BasicBlock::iterator it = b->begin();
+
+ if (it->getOpcode() == Instruction::PHI) {
+ PHINode *reference = cast<PHINode>(it);
+
+ std::set<Value*> phis;
+ phis.insert(reference);
+
+ unsigned numBlocks = reference->getNumIncomingValues();
+ for (++it; isa<PHINode>(*it); ++it) {
+ PHINode *pi = cast<PHINode>(it);
+
+ assert(numBlocks == pi->getNumIncomingValues());
+
+ // see if it is out of order
+ unsigned i;
+ for (i=0; i<numBlocks; i++)
+ if (pi->getIncomingBlock(i) != reference->getIncomingBlock(i))
+ break;
+
+ if (i!=numBlocks) {
+ std::vector<Value*> values;
+ values.reserve(numBlocks);
+ for (unsigned i=0; i<numBlocks; i++)
+ values[i] = pi->getIncomingValueForBlock(reference->getIncomingBlock(i));
+ for (unsigned i=0; i<numBlocks; i++) {
+ pi->setIncomingBlock(i, reference->getIncomingBlock(i));
+ pi->setIncomingValue(i, values[i]);
+ }
+ changed = true;
+ }
+
+ // see if it uses any previously defined phi nodes
+ for (i=0; i<numBlocks; i++) {
+ Value *value = pi->getIncomingValue(i);
+
+ if (phis.find(value) != phis.end()) {
+ // fix by making a "move" at the end of the incoming block
+ // to a new temporary, which is thus known not to be a phi
+ // result. we could be somewhat more efficient about this
+ // by sharing temps and by reordering phi instructions so
+ // this isn't completely necessary, but in the end this is
+ // just a pathological case which does not occur very
+ // often.
+ Instruction *tmp =
+ new BitCastInst(value,
+ value->getType(),
+ value->getName() + ".phiclean",
+ pi->getIncomingBlock(i)->getTerminator());
+ pi->setIncomingValue(i, tmp);
+ }
+
+ changed = true;
+ }
+
+ phis.insert(pi);
+ }
+ }
+ }
+
+ return changed;
+}
Added: klee/trunk/lib/Module/RaiseAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Module/RaiseAsm.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Module/RaiseAsm.cpp (added)
+++ klee/trunk/lib/Module/RaiseAsm.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,69 @@
+//===-- RaiseAsm.cpp ------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Passes.h"
+
+#include "llvm/InlineAsm.h"
+
+using namespace llvm;
+using namespace klee;
+
+char RaiseAsmPass::ID = 0;
+
+Function *RaiseAsmPass::getIntrinsic(llvm::Module &M,
+ unsigned IID,
+ const Type **Tys,
+ unsigned NumTys) {
+ return Intrinsic::getDeclaration(&M, (llvm::Intrinsic::ID) IID, Tys, NumTys);
+}
+
+// FIXME: This should just be implemented as a patch to
+// X86TargetAsmInfo.cpp, then everyone will benefit.
+bool RaiseAsmPass::runOnInstruction(Module &M, Instruction *I) {
+ if (CallInst *ci = dyn_cast<CallInst>(I)) {
+ if (InlineAsm *ia = dyn_cast<InlineAsm>(ci->getCalledValue())) {
+ const std::string &as = ia->getAsmString();
+ const std::string &cs = ia->getConstraintString();
+ const llvm::Type *T = ci->getType();
+
+ // bswaps
+ if (ci->getNumOperands() == 2 &&
+ T == ci->getOperand(1)->getType() &&
+ ((T == llvm::Type::Int16Ty &&
+ as == "rorw $$8, ${0:w}" &&
+ cs == "=r,0,~{dirflag},~{fpsr},~{flags},~{cc}") ||
+ (T == llvm::Type::Int32Ty &&
+ as == "rorw $$8, ${0:w};rorl $$16, $0;rorw $$8, ${0:w}" &&
+ cs == "=r,0,~{dirflag},~{fpsr},~{flags},~{cc}"))) {
+ llvm::Value *Arg0 = ci->getOperand(1);
+ Function *F = getIntrinsic(M, Intrinsic::bswap, Arg0->getType());
+ ci->setOperand(0, F);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool RaiseAsmPass::runOnModule(Module &M) {
+ bool changed = false;
+
+ for (Module::iterator fi = M.begin(), fe = M.end(); fi != fe; ++fi) {
+ for (Function::iterator bi = fi->begin(), be = fi->end(); bi != be; ++bi) {
+ for (BasicBlock::iterator ii = bi->begin(), ie = bi->end(); ii != ie;) {
+ Instruction *i = ii;
+ ++ii;
+ changed |= runOnInstruction(M, i);
+ }
+ }
+ }
+
+ return changed;
+}
Added: klee/trunk/lib/README.txt
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/README.txt?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/README.txt (added)
+++ klee/trunk/lib/README.txt Wed May 20 23:36:41 2009
@@ -0,0 +1,18 @@
+The klee and kleaver code is organized as follows:
+
+lib/Basic - Low level support for both klee and kleaver which should
+ be independent of LLVM.
+
+lib/Support - Higher level support, but only used by klee. This can
+ use LLVM facilities.
+
+lib/Expr - The core kleaver expression library.
+
+lib/Solver - The kleaver solver library.
+
+lib/Module - klee facilities for working with LLVM modules, including
+ the shadow module/instruction structures we use during
+ execution.
+
+lib/Core - The core symbolic virtual machine.
+
Added: klee/trunk/lib/Solver/CachingSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/CachingSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/CachingSolver.cpp (added)
+++ klee/trunk/lib/Solver/CachingSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,241 @@
+//===-- CachingSolver.cpp - Caching expression solver ---------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "klee/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/IncompleteSolver.h"
+#include "klee/SolverImpl.h"
+
+#include "SolverStats.h"
+
+#include <tr1/unordered_map>
+
+using namespace klee;
+
+class CachingSolver : public SolverImpl {
+private:
+ ref<Expr> canonicalizeQuery(ref<Expr> originalQuery,
+ bool &negationUsed);
+
+ void cacheInsert(const Query& query,
+ IncompleteSolver::PartialValidity result);
+
+ bool cacheLookup(const Query& query,
+ IncompleteSolver::PartialValidity &result);
+
+ struct CacheEntry {
+ CacheEntry(const ConstraintManager &c, ref<Expr> q)
+ : constraints(c), query(q) {}
+
+ CacheEntry(const CacheEntry &ce)
+ : constraints(ce.constraints), query(ce.query) {}
+
+ ConstraintManager constraints;
+ ref<Expr> query;
+
+ bool operator==(const CacheEntry &b) const {
+ return constraints==b.constraints && *query.get()==*b.query.get();
+ }
+ };
+
+ struct CacheEntryHash {
+ unsigned operator()(const CacheEntry &ce) const {
+ unsigned result = ce.query.hash();
+
+ for (ConstraintManager::constraint_iterator it = ce.constraints.begin();
+ it != ce.constraints.end(); ++it)
+ result ^= it->hash();
+
+ return result;
+ }
+ };
+
+ typedef std::tr1::unordered_map<CacheEntry,
+ IncompleteSolver::PartialValidity,
+ CacheEntryHash> cache_map;
+
+ Solver *solver;
+ cache_map cache;
+
+public:
+ CachingSolver(Solver *s) : solver(s) {}
+ ~CachingSolver() { cache.clear(); delete solver; }
+
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query& query, ref<Expr> &result) {
+ return solver->impl->computeValue(query, result);
+ }
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ return solver->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+ }
+};
+
+/** @returns the canonical version of the given query. The reference
+ negationUsed is set to true if the original query was negated in
+ the canonicalization process. */
+ref<Expr> CachingSolver::canonicalizeQuery(ref<Expr> originalQuery,
+ bool &negationUsed) {
+ ref<Expr> negatedQuery = Expr::createNot(originalQuery);
+
+ // select the "smaller" query to the be canonical representation
+ if (originalQuery.compare(negatedQuery) < 0) {
+ negationUsed = false;
+ return originalQuery;
+ } else {
+ negationUsed = true;
+ return negatedQuery;
+ }
+}
+
+/** @returns true on a cache hit, false of a cache miss. Reference
+ value result only valid on a cache hit. */
+bool CachingSolver::cacheLookup(const Query& query,
+ IncompleteSolver::PartialValidity &result) {
+ bool negationUsed;
+ ref<Expr> canonicalQuery = canonicalizeQuery(query.expr, negationUsed);
+
+ CacheEntry ce(query.constraints, canonicalQuery);
+ cache_map::iterator it = cache.find(ce);
+
+ if (it != cache.end()) {
+ result = (negationUsed ?
+ IncompleteSolver::negatePartialValidity(it->second) :
+ it->second);
+ return true;
+ }
+
+ return false;
+}
+
+/// Inserts the given query, result pair into the cache.
+void CachingSolver::cacheInsert(const Query& query,
+ IncompleteSolver::PartialValidity result) {
+ bool negationUsed;
+ ref<Expr> canonicalQuery = canonicalizeQuery(query.expr, negationUsed);
+
+ CacheEntry ce(query.constraints, canonicalQuery);
+ IncompleteSolver::PartialValidity cachedResult =
+ (negationUsed ? IncompleteSolver::negatePartialValidity(result) : result);
+
+ cache.insert(std::make_pair(ce, cachedResult));
+}
+
+bool CachingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ IncompleteSolver::PartialValidity cachedResult;
+ bool tmp, cacheHit = cacheLookup(query, cachedResult);
+
+ if (cacheHit) {
+ ++stats::queryCacheHits;
+
+ switch(cachedResult) {
+ case IncompleteSolver::MustBeTrue:
+ result = Solver::True;
+ return true;
+ case IncompleteSolver::MustBeFalse:
+ result = Solver::False;
+ return true;
+ case IncompleteSolver::TrueOrFalse:
+ result = Solver::Unknown;
+ return true;
+ case IncompleteSolver::MayBeTrue: {
+ if (!solver->impl->computeTruth(query, tmp))
+ return false;
+ if (tmp) {
+ cacheInsert(query, IncompleteSolver::MustBeTrue);
+ result = Solver::True;
+ return true;
+ } else {
+ cacheInsert(query, IncompleteSolver::TrueOrFalse);
+ result = Solver::Unknown;
+ return true;
+ }
+ }
+ case IncompleteSolver::MayBeFalse: {
+ if (!solver->impl->computeTruth(query.negateExpr(), tmp))
+ return false;
+ if (tmp) {
+ cacheInsert(query, IncompleteSolver::MustBeFalse);
+ result = Solver::False;
+ return true;
+ } else {
+ cacheInsert(query, IncompleteSolver::TrueOrFalse);
+ result = Solver::Unknown;
+ return true;
+ }
+ }
+ default: assert(0 && "unreachable");
+ }
+ }
+
+ ++stats::queryCacheMisses;
+
+ if (!solver->impl->computeValidity(query, result))
+ return false;
+
+ switch (result) {
+ case Solver::True:
+ cachedResult = IncompleteSolver::MustBeTrue; break;
+ case Solver::False:
+ cachedResult = IncompleteSolver::MustBeFalse; break;
+ default:
+ cachedResult = IncompleteSolver::TrueOrFalse; break;
+ }
+
+ cacheInsert(query, cachedResult);
+ return true;
+}
+
+bool CachingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ IncompleteSolver::PartialValidity cachedResult;
+ bool cacheHit = cacheLookup(query, cachedResult);
+
+ // a cached result of MayBeTrue forces us to check whether
+ // a False assignment exists.
+ if (cacheHit && cachedResult != IncompleteSolver::MayBeTrue) {
+ ++stats::queryCacheHits;
+ isValid = (cachedResult == IncompleteSolver::MustBeTrue);
+ return true;
+ }
+
+ ++stats::queryCacheMisses;
+
+ // cache miss: query solver
+ if (!solver->impl->computeTruth(query, isValid))
+ return false;
+
+ if (isValid) {
+ cachedResult = IncompleteSolver::MustBeTrue;
+ } else if (cacheHit) {
+ // We know a true assignment exists, and query isn't valid, so
+ // must be TrueOrFalse.
+ assert(cachedResult == IncompleteSolver::MayBeTrue);
+ cachedResult = IncompleteSolver::TrueOrFalse;
+ } else {
+ cachedResult = IncompleteSolver::MayBeFalse;
+ }
+
+ cacheInsert(query, cachedResult);
+ return true;
+}
+
+///
+
+Solver *klee::createCachingSolver(Solver *_solver) {
+ return new Solver(new CachingSolver(_solver));
+}
Added: klee/trunk/lib/Solver/CexCachingSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/CexCachingSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/CexCachingSolver.cpp (added)
+++ klee/trunk/lib/Solver/CexCachingSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,313 @@
+//===-- CexCachingSolver.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/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/SolverImpl.h"
+#include "klee/TimerStatIncrementer.h"
+#include "klee/util/Assignment.h"
+#include "klee/util/ExprUtil.h"
+#include "klee/util/ExprVisitor.h"
+#include "klee/Internal/ADT/MapOfSets.h"
+
+#include "SolverStats.h"
+
+#include "llvm/Support/CommandLine.h"
+
+using namespace klee;
+using namespace llvm;
+
+namespace {
+ cl::opt<bool>
+ DebugCexCacheCheckBinding("debug-cex-cache-check-binding");
+
+ cl::opt<bool>
+ CexCacheTryAll("cex-cache-try-all",
+ cl::desc("try substituting all counterexamples before asking STP"),
+ cl::init(false));
+
+ cl::opt<bool>
+ CexCacheExperimental("cex-cache-exp", cl::init(false));
+
+}
+
+///
+
+typedef std::set< ref<Expr> > KeyType;
+
+struct AssignmentLessThan {
+ bool operator()(const Assignment *a, const Assignment *b) {
+ return a->bindings < b->bindings;
+ }
+};
+
+
+class CexCachingSolver : public SolverImpl {
+ typedef std::set<Assignment*, AssignmentLessThan> assignmentsTable_ty;
+
+ Solver *solver;
+
+ MapOfSets<ref<Expr>, Assignment*> cache;
+ // memo table
+ assignmentsTable_ty assignmentsTable;
+
+ bool searchForAssignment(KeyType &key,
+ Assignment *&result);
+
+ bool lookupAssignment(const Query& query, Assignment *&result);
+
+ bool getAssignment(const Query& query, Assignment *&result);
+
+public:
+ CexCachingSolver(Solver *_solver) : solver(_solver) {}
+ ~CexCachingSolver();
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+///
+
+struct NullAssignment {
+ bool operator()(Assignment *a) const { return !a; }
+};
+
+struct NonNullAssignment {
+ bool operator()(Assignment *a) const { return a!=0; }
+};
+
+struct NullOrSatisfyingAssignment {
+ KeyType &key;
+
+ NullOrSatisfyingAssignment(KeyType &_key) : key(_key) {}
+
+ bool operator()(Assignment *a) const {
+ return !a || a->satisfies(key.begin(), key.end());
+ }
+};
+
+bool CexCachingSolver::searchForAssignment(KeyType &key, Assignment *&result) {
+ Assignment * const *lookup = cache.lookup(key);
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+
+ if (CexCacheTryAll) {
+ Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
+ if (!lookup) lookup = cache.findSubset(key, NullAssignment());
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+ for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
+ ie = assignmentsTable.end(); it != ie; ++it) {
+ Assignment *a = *it;
+ if (a->satisfies(key.begin(), key.end())) {
+ result = a;
+ return true;
+ }
+ }
+ } else {
+ // XXX which order? one is sure to be better
+ Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
+ if (!lookup) lookup = cache.findSubset(key, NullOrSatisfyingAssignment(key));
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CexCachingSolver::lookupAssignment(const Query &query,
+ Assignment *&result) {
+ KeyType key(query.constraints.begin(), query.constraints.end());
+ ref<Expr> neg = Expr::createNot(query.expr);
+ if (neg.isConstant()) {
+ if (!neg.getConstantValue()) {
+ result = (Assignment*) 0;
+ return true;
+ }
+ } else {
+ key.insert(neg);
+ }
+
+ return searchForAssignment(key, result);
+}
+
+bool CexCachingSolver::getAssignment(const Query& query, Assignment *&result) {
+ KeyType key(query.constraints.begin(), query.constraints.end());
+ ref<Expr> neg = Expr::createNot(query.expr);
+ if (neg.isConstant()) {
+ if (!neg.getConstantValue()) {
+ result = (Assignment*) 0;
+ return true;
+ }
+ } else {
+ key.insert(neg);
+ }
+
+ if (!searchForAssignment(key, result)) {
+ // need to solve
+
+ std::vector<const Array*> objects;
+ findSymbolicObjects(key.begin(), key.end(), objects);
+
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+ if (!solver->impl->computeInitialValues(query, objects, values,
+ hasSolution))
+ return false;
+
+ Assignment *binding;
+ if (hasSolution) {
+ binding = new Assignment(objects, values);
+
+ // memoization
+ std::pair<assignmentsTable_ty::iterator, bool>
+ res = assignmentsTable.insert(binding);
+ if (!res.second) {
+ delete binding;
+ binding = *res.first;
+ }
+
+ if (DebugCexCacheCheckBinding)
+ assert(binding->satisfies(key.begin(), key.end()));
+ } else {
+ binding = (Assignment*) 0;
+ }
+
+ result = binding;
+ cache.insert(key, binding);
+ }
+
+ return true;
+}
+
+///
+
+CexCachingSolver::~CexCachingSolver() {
+ cache.clear();
+ delete solver;
+ for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
+ ie = assignmentsTable.end(); it != ie; ++it)
+ delete *it;
+}
+
+bool CexCachingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+ Assignment *a;
+ if (!getAssignment(query.withFalse(), a))
+ return false;
+ assert(a && "computeValidity() must have assignment");
+ ref<Expr> q = a->evaluate(query.expr);
+ assert(q.isConstant() && "assignment evaluation did not result in constant");
+
+ if (q.getConstantValue()) {
+ if (!getAssignment(query, a))
+ return false;
+ result = !a ? Solver::True : Solver::Unknown;
+ } else {
+ if (!getAssignment(query.negateExpr(), a))
+ return false;
+ result = !a ? Solver::False : Solver::Unknown;
+ }
+
+ return true;
+}
+
+bool CexCachingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+
+ // There is a small amount of redundancy here. We only need to know
+ // truth and do not really need to compute an assignment. This means
+ // that we could check the cache to see if we already know that
+ // state ^ query has no assignment. In that case, by the validity of
+ // state, we know that state ^ !query must have an assignment, and
+ // so query cannot be true (valid). This does get hits, but doesn't
+ // really seem to be worth the overhead.
+
+ if (CexCacheExperimental) {
+ Assignment *a;
+ if (lookupAssignment(query.negateExpr(), a) && !a)
+ return false;
+ }
+
+ Assignment *a;
+ if (!getAssignment(query, a))
+ return false;
+
+ isValid = !a;
+
+ return true;
+}
+
+bool CexCachingSolver::computeValue(const Query& query,
+ ref<Expr> &result) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+
+ Assignment *a;
+ if (!getAssignment(query.withFalse(), a))
+ return false;
+ assert(a && "computeValue() must have assignment");
+ result = a->evaluate(query.expr);
+ assert(result.isConstant() &&
+ "assignment evaluation did not result in constant");
+ return true;
+}
+
+bool
+CexCachingSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+ Assignment *a;
+ if (!getAssignment(query, a))
+ return false;
+ hasSolution = !!a;
+
+ if (!a)
+ return true;
+
+ // FIXME: We should use smarter assignment for result so we don't
+ // need redundant copy.
+ values = std::vector< std::vector<unsigned char> >(objects.size());
+ for (unsigned i=0; i < objects.size(); ++i) {
+ const Array *os = objects[i];
+ Assignment::bindings_ty::iterator it = a->bindings.find(os);
+
+ if (it == a->bindings.end()) {
+ values[i] = std::vector<unsigned char>(os->size, 0);
+ } else {
+ values[i] = it->second;
+ }
+ }
+
+ return true;
+}
+
+///
+
+Solver *klee::createCexCachingSolver(Solver *_solver) {
+ return new Solver(new CexCachingSolver(_solver));
+}
Added: klee/trunk/lib/Solver/ConstantDivision.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/ConstantDivision.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/ConstantDivision.cpp (added)
+++ klee/trunk/lib/Solver/ConstantDivision.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,146 @@
+//===-- ConstantDivision.cpp ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ConstantDivision.h"
+
+#include "klee/util/Bits.h"
+
+#include <algorithm>
+#include <cassert>
+
+namespace klee {
+
+/* Macros and functions which define the basic bit-level operations
+ * needed to implement quick division operations.
+ *
+ * Based on Hacker's Delight (2003) by Henry S. Warren, Jr.
+ */
+
+/* 32 -- number of bits in the integer type on this architecture */
+
+/* 2^32 -- NUM_BITS=32 requires 64 bits to represent this unsigned value */
+#define TWO_TO_THE_32_U64 (1ULL << 32)
+
+/* 2e31 -- NUM_BITS=32 requires 64 bits to represent this signed value */
+#define TWO_TO_THE_31_S64 (1LL << 31)
+
+/* ABS(x) -- positive x */
+#define ABS(x) ( ((x)>0)?x:-(x) ) /* fails if x is the min value of its type */
+
+/* XSIGN(x) -- -1 if x<0 and 0 otherwise */
+#define XSIGN(x) ( (x) >> 31 )
+
+/* LOG2_CEIL(x) -- logarithm base 2 of x, rounded up */
+#define LOG2_CEIL(x) ( 32 - ldz(x - 1) )
+
+/* ones(x) -- counts the number of bits in x with the value 1 */
+static uint32_t ones( register uint32_t x ) {
+ x -= ((x >> 1) & 0x55555555);
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+ x = (((x >> 4) + x) & 0x0f0f0f0f);
+ x += (x >> 8);
+ x += (x >> 16);
+
+ return( x & 0x0000003f );
+}
+
+/* ldz(x) -- counts the number of leading zeroes in a 32-bit word */
+static uint32_t ldz( register uint32_t x ) {
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+
+ return 32 - ones(x);
+}
+
+/* exp_base_2(n) -- 2^n computed as an integer */
+static uint32_t exp_base_2( register int32_t n ) {
+ register uint32_t x = ~n & (n - 32);
+ x = x >> 31;
+ return( x << n );
+}
+
+// A simple algorithm: Iterate over all contiguous regions of 1 bits
+// in x starting with the lowest bits.
+//
+// For a particular range where x is 1 for bits [low,high) then:
+// 1) if the range is just one bit, simple add it
+// 2) if the range is more than one bit, replace with an add
+// of the high bit and a subtract of the low bit. we apply
+// one useful optimization: if we were going to add the bit
+// below the one we wish to subtract, we simply change that
+// add to a subtract instead of subtracting the low bit itself.
+// Obviously we must take care when high==64.
+void ComputeMultConstants64(uint64_t multiplicand,
+ uint64_t &add, uint64_t &sub) {
+ uint64_t x = multiplicand;
+ add = sub = 0;
+
+ while (x) {
+ // Determine rightmost contiguous region of 1s.
+ unsigned low = bits64::indexOfRightmostBit(x);
+ uint64_t lowbit = 1LL << low;
+ uint64_t p = x + lowbit;
+ uint64_t q = bits64::isolateRightmostBit(p);
+ unsigned high = q ? bits64::indexOfSingleBit(q) : 64;
+
+ if (high==low+1) { // Just one bit...
+ add |= lowbit;
+ } else {
+ // Rewrite as +(1<<high) - (1<<low).
+
+ // Optimize +(1<<x) - (1<<(x+1)) to -(1<<x).
+ if (low && (add & (lowbit>>1))) {
+ add ^= lowbit>>1;
+ sub ^= lowbit>>1;
+ } else {
+ sub |= lowbit;
+ }
+
+ if (high!=64)
+ add |= 1LL << high;
+ }
+
+ x = p ^ q;
+ }
+
+ assert(multiplicand == add - sub);
+}
+
+void ComputeUDivConstants32(uint32_t d, uint32_t &mprime, uint32_t &sh1,
+ uint32_t &sh2) {
+ int32_t l = LOG2_CEIL( d ); /* signed so l-1 => -1 when l=0 (see sh2) */
+ uint32_t mid = exp_base_2(l) - d;
+
+ mprime = (TWO_TO_THE_32_U64 * mid / d) + 1;
+ sh1 = std::min( l, 1 );
+ sh2 = std::max( l-1, 0 );
+}
+
+void ComputeSDivConstants32(int32_t d, int32_t &mprime, int32_t &dsign,
+ int32_t &shpost ) {
+ uint64_t abs_d = ABS( (int64_t)d ); /* use 64-bits in case d is INT32_MIN */
+
+ /* LOG2_CEIL works on 32-bits, so we cast abs_d. The only possible value
+ * outside the 32-bit rep. is 2^31. This is special cased to save computer
+ * time since 64-bit routines would be overkill. */
+ int32_t l = std::max( 1U, LOG2_CEIL((uint32_t)abs_d) );
+ if( abs_d == TWO_TO_THE_31_S64 ) l = 31;
+
+ uint32_t mid = exp_base_2( l - 1 );
+ uint64_t m = TWO_TO_THE_32_U64 * mid / abs_d + 1ULL;
+
+ mprime = m - TWO_TO_THE_32_U64; /* implicit cast to 32-bits signed */
+ dsign = XSIGN( d );
+ shpost = l - 1;
+}
+
+}
Added: klee/trunk/lib/Solver/ConstantDivision.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/ConstantDivision.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/ConstantDivision.h (added)
+++ klee/trunk/lib/Solver/ConstantDivision.h Wed May 20 23:36:41 2009
@@ -0,0 +1,51 @@
+//===-- ConstantDivision.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 __UTIL_CONSTANTDIVISION_H__
+#define __UTIL_CONSTANTDIVISION_H__
+
+#include <stdint.h>
+
+namespace klee {
+
+/// ComputeMultConstants64 - Compute add and sub such that add-sub==x,
+/// while attempting to minimize the number of bits in add and sub
+/// combined.
+void ComputeMultConstants64(uint64_t x, uint64_t &add_out,
+ uint64_t &sub_out);
+
+/// Compute the constants to perform a quicker equivalent of a division of some
+/// 32-bit unsigned integer n by a known constant d (also a 32-bit unsigned
+/// integer). The constants to compute n/d without explicit division will be
+/// stored in mprime, sh1, and sh2 (unsigned 32-bit integers).
+///
+/// @param d - denominator (divisor)
+///
+/// @param [out] mprime
+/// @param [out] sh1
+/// @param [out] sh2
+void ComputeUDivConstants32(uint32_t d, uint32_t &mprime, uint32_t &sh1,
+ uint32_t &sh2);
+
+/// Compute the constants to perform a quicker equivalent of a division of some
+/// 32-bit signed integer n by a known constant d (also a 32-bit signed
+/// integer). The constants to compute n/d without explicit division will be
+/// stored in mprime, dsign, and shpost (signed 32-bit integers).
+///
+/// @param d - denominator (divisor)
+///
+/// @param [out] mprime
+/// @param [out] dsign
+/// @param [out] shpost
+void ComputeSDivConstants32(int32_t d, int32_t &mprime, int32_t &dsign,
+ int32_t &shpost);
+
+}
+
+#endif
Added: klee/trunk/lib/Solver/FastCexSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/FastCexSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/FastCexSolver.cpp (added)
+++ klee/trunk/lib/Solver/FastCexSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,959 @@
+//===-- FastCexSolver.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/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/IncompleteSolver.h"
+#include "klee/util/ExprEvaluator.h"
+#include "klee/util/ExprRangeEvaluator.h"
+#include "klee/util/ExprVisitor.h"
+// FIXME: Use APInt.
+#include "klee/Internal/Support/IntEvaluation.h"
+
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include <map>
+#include <vector>
+
+using namespace klee;
+
+/***/
+
+//#define LOG
+#ifdef LOG
+std::ostream *theLog;
+#endif
+
+ // Hacker's Delight, pgs 58-63
+static uint64_t minOR(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (~a & c & m) {
+ temp = (a | m) & -m;
+ if (temp <= b) { a = temp; break; }
+ } else if (a & ~c & m) {
+ temp = (c | m) & -m;
+ if (temp <= d) { c = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return a | c;
+}
+static uint64_t maxOR(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+
+ while (m) {
+ if (b & d & m) {
+ temp = (b - m) | (m - 1);
+ if (temp >= a) { b = temp; break; }
+ temp = (d - m) | (m -1);
+ if (temp >= c) { d = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return b | d;
+}
+static uint64_t minAND(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (~a & ~c & m) {
+ temp = (a | m) & -m;
+ if (temp <= b) { a = temp; break; }
+ temp = (c | m) & -m;
+ if (temp <= d) { c = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return a & c;
+}
+static uint64_t maxAND(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (b & ~d & m) {
+ temp = (b & ~m) | (m - 1);
+ if (temp >= a) { b = temp; break; }
+ } else if (~b & d & m) {
+ temp = (d & ~m) | (m - 1);
+ if (temp >= c) { d = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return b & d;
+}
+
+///
+
+class ValueRange {
+private:
+ uint64_t m_min, m_max;
+
+public:
+ ValueRange() : m_min(1),m_max(0) {}
+ ValueRange(uint64_t value) : m_min(value), m_max(value) {}
+ ValueRange(uint64_t _min, uint64_t _max) : m_min(_min), m_max(_max) {}
+ ValueRange(const ValueRange &b) : m_min(b.m_min), m_max(b.m_max) {}
+
+ void print(std::ostream &os) const {
+ if (isFixed()) {
+ os << m_min;
+ } else {
+ os << "[" << m_min << "," << m_max << "]";
+ }
+ }
+
+ bool isEmpty() const {
+ return m_min>m_max;
+ }
+ bool contains(uint64_t value) const {
+ return this->intersects(ValueRange(value));
+ }
+ bool intersects(const ValueRange &b) const {
+ return !this->set_intersection(b).isEmpty();
+ }
+
+ bool isFullRange(unsigned bits) {
+ return m_min==0 && m_max==bits64::maxValueOfNBits(bits);
+ }
+
+ ValueRange set_intersection(const ValueRange &b) const {
+ return ValueRange(std::max(m_min,b.m_min), std::min(m_max,b.m_max));
+ }
+ ValueRange set_union(const ValueRange &b) const {
+ return ValueRange(std::min(m_min,b.m_min), std::max(m_max,b.m_max));
+ }
+ ValueRange set_difference(const ValueRange &b) const {
+ if (b.isEmpty() || b.m_min > m_max || b.m_max < m_min) { // no intersection
+ return *this;
+ } else if (b.m_min <= m_min && b.m_max >= m_max) { // empty
+ return ValueRange(1,0);
+ } else if (b.m_min <= m_min) { // one range out
+ // cannot overflow because b.m_max < m_max
+ return ValueRange(b.m_max+1, m_max);
+ } else if (b.m_max >= m_max) {
+ // cannot overflow because b.min > m_min
+ return ValueRange(m_min, b.m_min-1);
+ } else {
+ // two ranges, take bottom
+ return ValueRange(m_min, b.m_min-1);
+ }
+ }
+ ValueRange binaryAnd(const ValueRange &b) const {
+ // XXX
+ assert(!isEmpty() && !b.isEmpty() && "XXX");
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min & b.m_min);
+ } else {
+ return ValueRange(minAND(m_min, m_max, b.m_min, b.m_max),
+ maxAND(m_min, m_max, b.m_min, b.m_max));
+ }
+ }
+ ValueRange binaryAnd(uint64_t b) const { return binaryAnd(ValueRange(b)); }
+ ValueRange binaryOr(ValueRange b) const {
+ // XXX
+ assert(!isEmpty() && !b.isEmpty() && "XXX");
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min | b.m_min);
+ } else {
+ return ValueRange(minOR(m_min, m_max, b.m_min, b.m_max),
+ maxOR(m_min, m_max, b.m_min, b.m_max));
+ }
+ }
+ ValueRange binaryOr(uint64_t b) const { return binaryOr(ValueRange(b)); }
+ ValueRange binaryXor(ValueRange b) const {
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min ^ b.m_min);
+ } else {
+ uint64_t t = m_max | b.m_max;
+ while (!bits64::isPowerOfTwo(t))
+ t = bits64::withoutRightmostBit(t);
+ return ValueRange(0, (t<<1)-1);
+ }
+ }
+
+ ValueRange binaryShiftLeft(unsigned bits) const {
+ return ValueRange(m_min<<bits, m_max<<bits);
+ }
+ ValueRange binaryShiftRight(unsigned bits) const {
+ return ValueRange(m_min>>bits, m_max>>bits);
+ }
+
+ ValueRange concat(const ValueRange &b, unsigned bits) const {
+ return binaryShiftLeft(bits).binaryOr(b);
+ }
+ ValueRange extract(uint64_t lowBit, uint64_t maxBit) const {
+ return binaryShiftRight(lowBit).binaryAnd(bits64::maxValueOfNBits(maxBit-lowBit));
+ }
+
+ ValueRange add(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange sub(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange mul(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange udiv(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange sdiv(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange urem(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange srem(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+
+ // use min() to get value if true (XXX should we add a method to
+ // make code clearer?)
+ bool isFixed() const { return m_min==m_max; }
+
+ bool operator==(const ValueRange &b) const { return m_min==b.m_min && m_max==b.m_max; }
+ bool operator!=(const ValueRange &b) const { return !(*this==b); }
+
+ bool mustEqual(const uint64_t b) const { return m_min==m_max && m_min==b; }
+ bool mayEqual(const uint64_t b) const { return m_min<=b && m_max>=b; }
+
+ bool mustEqual(const ValueRange &b) const { return isFixed() && b.isFixed() && m_min==b.m_min; }
+ bool mayEqual(const ValueRange &b) const { return this->intersects(b); }
+
+ uint64_t min() const {
+ assert(!isEmpty() && "cannot get minimum of empty range");
+ return m_min;
+ }
+
+ uint64_t max() const {
+ assert(!isEmpty() && "cannot get maximum of empty range");
+ return m_max;
+ }
+
+ int64_t minSigned(unsigned bits) const {
+ assert((m_min>>bits)==0 && (m_max>>bits)==0 &&
+ "range is outside given number of bits");
+
+ // if max allows sign bit to be set then it can be smallest value,
+ // otherwise since the range is not empty, min cannot have a sign
+ // bit
+
+ uint64_t smallest = ((uint64_t) 1 << (bits-1));
+ if (m_max >= smallest) {
+ return ints::sext(smallest, 64, bits);
+ } else {
+ return m_min;
+ }
+ }
+
+ int64_t maxSigned(unsigned bits) const {
+ assert((m_min>>bits)==0 && (m_max>>bits)==0 &&
+ "range is outside given number of bits");
+
+ uint64_t smallest = ((uint64_t) 1 << (bits-1));
+
+ // if max and min have sign bit then max is max, otherwise if only
+ // max has sign bit then max is largest signed integer, otherwise
+ // max is max
+
+ if (m_min < smallest && m_max >= smallest) {
+ return smallest - 1;
+ } else {
+ return ints::sext(m_max, 64, bits);
+ }
+ }
+};
+
+inline std::ostream &operator<<(std::ostream &os, const ValueRange &vr) {
+ vr.print(os);
+ return os;
+}
+
+// used to find all memory object ids and the maximum size of any
+// object state that references them (for symbolic size).
+class ObjectFinder : public ExprVisitor {
+protected:
+ Action visitRead(const ReadExpr &re) {
+ addUpdates(re.updates);
+ return Action::doChildren();
+ }
+
+ // XXX nice if this information was cached somewhere, used by
+ // independence as well right?
+ void addUpdates(const UpdateList &ul) {
+ for (const UpdateNode *un=ul.head; un; un=un->next) {
+ visit(un->index);
+ visit(un->value);
+ }
+
+ addObject(*ul.root);
+ }
+
+public:
+ void addObject(const Array& array) {
+ unsigned id = array.id;
+ std::map<unsigned,unsigned>::iterator it = results.find(id);
+
+ // FIXME: Not 64-bit size clean.
+ if (it == results.end()) {
+ results[id] = (unsigned) array.size;
+ } else {
+ it->second = std::max(it->second, (unsigned) array.size);
+ }
+ }
+
+public:
+ std::map<unsigned, unsigned> results;
+};
+
+// XXX waste of space, rather have ByteValueRange
+typedef ValueRange CexValueData;
+
+class CexObjectData {
+public:
+ unsigned size;
+ CexValueData *values;
+
+public:
+ CexObjectData(unsigned _size) : size(_size), values(new CexValueData[size]) {
+ for (unsigned i=0; i<size; i++)
+ values[i] = ValueRange(0, 255);
+ }
+};
+
+class CexRangeEvaluator : public ExprRangeEvaluator<ValueRange> {
+public:
+ std::map<unsigned, CexObjectData> &objectValues;
+ CexRangeEvaluator(std::map<unsigned, CexObjectData> &_objectValues)
+ : objectValues(_objectValues) {}
+
+ ValueRange getInitialReadRange(const Array &os, ValueRange index) {
+ return ValueRange(0, 255);
+ }
+};
+
+class CexConstifier : public ExprEvaluator {
+protected:
+ ref<Expr> getInitialValue(const Array& array, unsigned index) {
+ std::map<unsigned, CexObjectData>::iterator it =
+ objectValues.find(array.id);
+ assert(it != objectValues.end() && "missing object?");
+ CexObjectData &cod = it->second;
+
+ if (index >= cod.size) {
+ return ReadExpr::create(UpdateList(&array, true, 0),
+ ref<Expr>(index, Expr::Int32));
+ } else {
+ CexValueData &cvd = cod.values[index];
+ assert(cvd.min() == cvd.max() && "value is not fixed");
+ return ref<Expr>(cvd.min(), Expr::Int8);
+ }
+ }
+
+public:
+ std::map<unsigned, CexObjectData> &objectValues;
+ CexConstifier(std::map<unsigned, CexObjectData> &_objectValues)
+ : objectValues(_objectValues) {}
+};
+
+class CexData {
+public:
+ std::map<unsigned, CexObjectData> objectValues;
+
+public:
+ CexData(ObjectFinder &finder) {
+ for (std::map<unsigned,unsigned>::iterator it = finder.results.begin(),
+ ie = finder.results.end(); it != ie; ++it) {
+ objectValues.insert(std::pair<unsigned, CexObjectData>(it->first,
+ CexObjectData(it->second)));
+ }
+ }
+ ~CexData() {
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it)
+ delete[] it->second.values;
+ }
+
+ void forceExprToValue(ref<Expr> e, uint64_t value) {
+ forceExprToRange(e, CexValueData(value,value));
+ }
+
+ void forceExprToRange(ref<Expr> e, CexValueData range) {
+#ifdef LOG
+ // *theLog << "force: " << e << " to " << range << "\n";
+#endif
+ switch (e.getKind()) {
+ case Expr::Constant: {
+ // rather a pity if the constant isn't in the range, but how can
+ // we use this?
+ break;
+ }
+
+ // Special
+
+ case Expr::NotOptimized: break;
+
+ case Expr::Read: {
+ ReadExpr *re = static_ref_cast<ReadExpr>(e);
+ const Array *array = re->updates.root;
+ CexObjectData &cod = objectValues.find(array->id)->second;
+
+ // XXX we need to respect the version here and object state chain
+
+ if (re->index.isConstant() &&
+ re->index.getConstantValue() < array->size) {
+ CexValueData &cvd = cod.values[re->index.getConstantValue()];
+ CexValueData tmp = cvd.set_intersection(range);
+
+ if (tmp.isEmpty()) {
+ if (range.isFixed()) // ranges conflict, if new one is fixed use that
+ cvd = range;
+ } else {
+ cvd = tmp;
+ }
+ } else {
+ // XXX fatal("XXX not implemented");
+ }
+
+ break;
+ }
+
+ case Expr::Select: {
+ SelectExpr *se = static_ref_cast<SelectExpr>(e);
+ ValueRange cond = evalRangeForExpr(se->cond);
+ if (cond.isFixed()) {
+ if (cond.min()) {
+ forceExprToRange(se->trueExpr, range);
+ } else {
+ forceExprToRange(se->falseExpr, range);
+ }
+ } else {
+ // XXX imprecise... we have a choice here. One method is to
+ // simply force both sides into the specified range (since the
+ // condition is indetermined). This may lose in two ways, the
+ // first is that the condition chosen may limit further
+ // restrict the range in each of the children, however this is
+ // less of a problem as the range will be a superset of legal
+ // values. The other is if the condition ends up being forced
+ // by some other constraints, then we needlessly forced one
+ // side into the given range.
+ //
+ // The other method would be to force the condition to one
+ // side and force that side into the given range. This loses
+ // when we force the condition to an unsatisfiable value
+ // (either because the condition cannot be that, or the
+ // resulting range given that condition is not in the required
+ // range).
+ //
+ // Currently we just force both into the range. A hybrid would
+ // be to evaluate the ranges for each of the children... if
+ // one of the ranges happens to already be a subset of the
+ // required range then it may be preferable to force the
+ // condition to that side.
+ forceExprToRange(se->trueExpr, range);
+ forceExprToRange(se->falseExpr, range);
+ }
+ break;
+ }
+
+ // XXX imprecise... the problem here is that extracting bits
+ // loses information about what bits are connected across the
+ // bytes. if a value can be 1 or 256 then either the top or
+ // lower byte is 0, but just extraction loses this information
+ // and will allow neither,one,or both to be 1.
+ //
+ // we can protect against this in a limited fashion by writing
+ // the extraction a byte at a time, then checking the evaluated
+ // value, isolating for that range, and continuing.
+ case Expr::Concat: {
+ ConcatExpr *ce = static_ref_cast<ConcatExpr>(e);
+ if (ce->is2ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(1), range.extract( 0, 8));
+ }
+ else if (ce->is4ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract(24, 32));
+ forceExprToRange(ce->getKid(1), range.extract(16, 24));
+ forceExprToRange(ce->getKid(2), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(3), range.extract( 0, 8));
+ }
+ else if (ce->is8ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract(56, 64));
+ forceExprToRange(ce->getKid(1), range.extract(48, 56));
+ forceExprToRange(ce->getKid(2), range.extract(40, 48));
+ forceExprToRange(ce->getKid(3), range.extract(32, 40));
+ forceExprToRange(ce->getKid(4), range.extract(24, 32));
+ forceExprToRange(ce->getKid(5), range.extract(16, 24));
+ forceExprToRange(ce->getKid(6), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(7), range.extract( 0, 8));
+ }
+
+ break;
+ }
+
+ case Expr::Extract: {
+ // XXX
+ break;
+ }
+
+ // Casting
+
+ // Simply intersect the output range with the range of all
+ // possible outputs and then truncate to the desired number of
+ // bits.
+
+ // For ZExt this simplifies to just intersection with the
+ // possible input range.
+ case Expr::ZExt: {
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ unsigned inBits = ce->src.getWidth();
+ ValueRange input = range.set_intersection(ValueRange(0, bits64::maxValueOfNBits(inBits)));
+ forceExprToRange(ce->src, input);
+ break;
+ }
+ // For SExt instead of doing the intersection we just take the output range
+ // minus the impossible values. This is nicer since it is a single interval.
+ case Expr::SExt: {
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ unsigned inBits = ce->src.getWidth();
+ unsigned outBits = ce->width;
+ ValueRange output = range.set_difference(ValueRange(1<<(inBits-1),
+ (bits64::maxValueOfNBits(outBits)-
+ bits64::maxValueOfNBits(inBits-1)-1)));
+ ValueRange input = output.binaryAnd(bits64::maxValueOfNBits(inBits));
+ forceExprToRange(ce->src, input);
+ break;
+ }
+
+ // Binary
+
+ case Expr::And: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (be->getWidth()==Expr::Bool) {
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ if (!range.min()) {
+ if (left.mustEqual(0) || right.mustEqual(0)) {
+ // all is well
+ } else {
+ // XXX heuristic, which order
+
+ forceExprToValue(be->left, 0);
+ left = evalRangeForExpr(be->left);
+
+ // see if that worked
+ if (!left.mustEqual(1))
+ forceExprToValue(be->right, 0);
+ }
+ } else {
+ if (!left.mustEqual(1)) forceExprToValue(be->left, 1);
+ if (!right.mustEqual(1)) forceExprToValue(be->right, 1);
+ }
+ }
+ } else {
+ // XXX
+ }
+ break;
+ }
+
+ case Expr::Or: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (be->getWidth()==Expr::Bool) {
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ if (range.min()) {
+ if (left.mustEqual(1) || right.mustEqual(1)) {
+ // all is well
+ } else {
+ // XXX heuristic, which order?
+
+ // force left to value we need
+ forceExprToValue(be->left, 1);
+ left = evalRangeForExpr(be->left);
+
+ // see if that worked
+ if (!left.mustEqual(1))
+ forceExprToValue(be->right, 1);
+ }
+ } else {
+ if (!left.mustEqual(0)) forceExprToValue(be->left, 0);
+ if (!right.mustEqual(0)) forceExprToValue(be->right, 0);
+ }
+ }
+ } else {
+ // XXX
+ }
+ break;
+ }
+
+ case Expr::Xor: break;
+
+ // Comparison
+
+ case Expr::Eq: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (range.isFixed()) {
+ if (be->left.isConstant()) {
+ uint64_t value = be->left.getConstantValue();
+ if (range.min()) {
+ forceExprToValue(be->right, value);
+ } else {
+ if (value==0) {
+ forceExprToRange(be->right,
+ CexValueData(1,
+ ints::sext(1,
+ be->right.getWidth(),
+ 1)));
+ } else {
+ // XXX heuristic / lossy, could be better to pick larger range?
+ forceExprToRange(be->right, CexValueData(0, value-1));
+ }
+ }
+ } else {
+ // XXX what now
+ }
+ }
+ break;
+ }
+
+ case Expr::Ult: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+
+ // XXX heuristic / lossy, what order if conflict
+
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ uint64_t maxValue = bits64::maxValueOfNBits(be->right.getWidth());
+
+ // XXX should deal with overflow (can lead to empty range)
+
+ if (left.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->right, CexValueData(left.min()+1, maxValue));
+ } else {
+ forceExprToRange(be->right, CexValueData(0, left.min()));
+ }
+ } else if (right.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->left, CexValueData(0, right.min()-1));
+ } else {
+ forceExprToRange(be->left, CexValueData(right.min(), maxValue));
+ }
+ } else {
+ // XXX ???
+ }
+ }
+ break;
+ }
+ case Expr::Ule: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+
+ // XXX heuristic / lossy, what order if conflict
+
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ // XXX should deal with overflow (can lead to empty range)
+
+ uint64_t maxValue = bits64::maxValueOfNBits(be->right.getWidth());
+ if (left.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->right, CexValueData(left.min(), maxValue));
+ } else {
+ forceExprToRange(be->right, CexValueData(0, left.min()-1));
+ }
+ } else if (right.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->left, CexValueData(0, right.min()));
+ } else {
+ forceExprToRange(be->left, CexValueData(right.min()+1, maxValue));
+ }
+ } else {
+ // XXX ???
+ }
+ }
+ break;
+ }
+
+ case Expr::Ne:
+ case Expr::Ugt:
+ case Expr::Uge:
+ case Expr::Sgt:
+ case Expr::Sge:
+ assert(0 && "invalid expressions (uncanonicalized");
+
+ default:
+ break;
+ }
+ }
+
+ void fixValues() {
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ for (unsigned i=0; i<cod.size; i++) {
+ CexValueData &cvd = cod.values[i];
+ cvd = CexValueData(cvd.min() + (cvd.max()-cvd.min())/2);
+ }
+ }
+ }
+
+ ValueRange evalRangeForExpr(ref<Expr> &e) {
+ CexRangeEvaluator ce(objectValues);
+ return ce.evaluate(e);
+ }
+
+ bool exprMustBeValue(ref<Expr> e, uint64_t value) {
+ CexConstifier cc(objectValues);
+ ref<Expr> v = cc.visit(e);
+ if (!v.isConstant()) return false;
+ // XXX reenable once all reads and vars are fixed
+ // assert(v.isConstant() && "not all values have been fixed");
+ return v.getConstantValue()==value;
+ }
+};
+
+/* *** */
+
+
+class FastCexSolver : public IncompleteSolver {
+public:
+ FastCexSolver();
+ ~FastCexSolver();
+
+ IncompleteSolver::PartialValidity computeTruth(const Query&);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+FastCexSolver::FastCexSolver() { }
+
+FastCexSolver::~FastCexSolver() { }
+
+IncompleteSolver::PartialValidity
+FastCexSolver::computeTruth(const Query& query) {
+#ifdef LOG
+ std::ostringstream log;
+ theLog = &log;
+ // log << "------ start FastCexSolver::mustBeTrue ------\n";
+ log << "-- QUERY --\n";
+ unsigned i=0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ log << " C" << i++ << ": " << *it << ", \n";
+ log << " Q : " << query.expr << "\n";
+#endif
+
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+ cd.forceExprToValue(query.expr, 0);
+
+#ifdef LOG
+ log << " -- ranges --\n";
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ log << " arr" << it->first << "[" << cod.size << "] = [";
+ unsigned continueFrom=cod.size-1;
+ for (; continueFrom>0; continueFrom--)
+ if (cod.values[continueFrom-1]!=cod.values[continueFrom])
+ break;
+ for (unsigned i=0; i<cod.size; i++) {
+ log << cod.values[i];
+ if (i<cod.size-1) {
+ log << ", ";
+ if (i==continueFrom) {
+ log << "...";
+ break;
+ }
+ }
+ }
+ log << "]\n";
+ }
+#endif
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+#ifdef LOG
+ log << " -- fixed values --\n";
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ log << " arr" << it->first << "[" << cod.size << "] = [";
+ unsigned continueFrom=cod.size-1;
+ for (; continueFrom>0; continueFrom--)
+ if (cod.values[continueFrom-1]!=cod.values[continueFrom])
+ break;
+ for (unsigned i=0; i<cod.size; i++) {
+ log << cod.values[i];
+ if (i<cod.size-1) {
+ log << ", ";
+ if (i==continueFrom) {
+ log << "...";
+ break;
+ }
+ }
+ }
+ log << "]\n";
+ }
+#endif
+
+ // check the result
+
+ bool isGood = true;
+
+ if (!cd.exprMustBeValue(query.expr, 0)) isGood = false;
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ isGood = false;
+
+#ifdef LOG
+ log << " -- evaluating result --\n";
+
+ i=0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it) {
+ bool res = cd.exprMustBeValue(*it, 1);
+ log << " C" << i++ << ": " << (res?"true":"false") << "\n";
+ }
+ log << " Q : "
+ << (cd.exprMustBeValue(query.expr, 0)?"true":"false") << "\n";
+
+ log << "\n\n";
+#endif
+
+ return isGood ? IncompleteSolver::MayBeFalse : IncompleteSolver::None;
+}
+
+bool FastCexSolver::computeValue(const Query& query, ref<Expr> &result) {
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+ // check the result
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ return false;
+
+ CexConstifier cc(cd.objectValues);
+ ref<Expr> value = cc.visit(query.expr);
+
+ if (value.isConstant()) {
+ result = value;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+FastCexSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ for (unsigned i = 0; i != objects.size(); ++i)
+ of.addObject(*objects[i]);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+ cd.forceExprToValue(query.expr, 0);
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+ // check the result
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ return false;
+ if (!cd.exprMustBeValue(query.expr, 0))
+ return false;
+
+ hasSolution = true;
+ CexConstifier cc(cd.objectValues);
+ for (unsigned i = 0; i != objects.size(); ++i) {
+ const Array *array = objects[i];
+ std::vector<unsigned char> data;
+ data.reserve(array->size);
+
+ for (unsigned i=0; i < array->size; i++) {
+ ref<Expr> value =
+ cc.visit(ReadExpr::create(UpdateList(array, true, 0),
+ ConstantExpr::create(i,
+ kMachinePointerType)));
+
+ if (value.isConstant()) {
+ data.push_back(value.getConstantValue());
+ } else {
+ // FIXME: When does this happen?
+ return false;
+ }
+ }
+
+ values.push_back(data);
+ }
+
+ return true;
+}
+
+
+Solver *klee::createFastCexSolver(Solver *s) {
+ return new Solver(new StagedSolverImpl(new FastCexSolver(), s));
+}
Added: klee/trunk/lib/Solver/IncompleteSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/IncompleteSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/IncompleteSolver.cpp (added)
+++ klee/trunk/lib/Solver/IncompleteSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,136 @@
+//===-- IncompleteSolver.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/IncompleteSolver.h"
+
+#include "klee/Constraints.h"
+
+using namespace klee;
+using namespace llvm;
+
+/***/
+
+IncompleteSolver::PartialValidity
+IncompleteSolver::negatePartialValidity(PartialValidity pv) {
+ switch(pv) {
+ case MustBeTrue: return MustBeFalse;
+ case MustBeFalse: return MustBeTrue;
+ case MayBeTrue: return MayBeFalse;
+ case MayBeFalse: return MayBeTrue;
+ case TrueOrFalse: return TrueOrFalse;
+ default: assert(0 && "invalid partial validity");
+ }
+}
+
+IncompleteSolver::PartialValidity
+IncompleteSolver::computeValidity(const Query& query) {
+ PartialValidity trueResult = computeTruth(query);
+
+ if (trueResult == MustBeTrue) {
+ return MustBeTrue;
+ } else {
+ PartialValidity falseResult = computeTruth(query.negateExpr());
+
+ if (falseResult == MustBeTrue) {
+ return MustBeFalse;
+ } else {
+ bool trueCorrect = trueResult != None,
+ falseCorrect = falseResult != None;
+
+ if (trueCorrect && falseCorrect) {
+ return TrueOrFalse;
+ } else if (trueCorrect) { // ==> trueResult == MayBeFalse
+ return MayBeFalse;
+ } else if (falseCorrect) { // ==> falseResult == MayBeFalse
+ return MayBeTrue;
+ } else {
+ return None;
+ }
+ }
+ }
+}
+
+/***/
+
+StagedSolverImpl::StagedSolverImpl(IncompleteSolver *_primary,
+ Solver *_secondary)
+ : primary(_primary),
+ secondary(_secondary) {
+}
+
+StagedSolverImpl::~StagedSolverImpl() {
+ delete primary;
+ delete secondary;
+}
+
+bool StagedSolverImpl::computeTruth(const Query& query, bool &isValid) {
+ IncompleteSolver::PartialValidity trueResult = primary->computeTruth(query);
+
+ if (trueResult != IncompleteSolver::None) {
+ isValid = (trueResult == IncompleteSolver::MustBeTrue);
+ return true;
+ }
+
+ return secondary->impl->computeTruth(query, isValid);
+}
+
+bool StagedSolverImpl::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ bool tmp;
+
+ switch(primary->computeValidity(query)) {
+ case IncompleteSolver::MustBeTrue:
+ result = Solver::True;
+ break;
+ case IncompleteSolver::MustBeFalse:
+ result = Solver::False;
+ break;
+ case IncompleteSolver::TrueOrFalse:
+ result = Solver::Unknown;
+ break;
+ case IncompleteSolver::MayBeTrue:
+ if (!secondary->impl->computeTruth(query, tmp))
+ return false;
+ result = tmp ? Solver::True : Solver::Unknown;
+ break;
+ case IncompleteSolver::MayBeFalse:
+ if (!secondary->impl->computeTruth(query.negateExpr(), tmp))
+ return false;
+ result = tmp ? Solver::False : Solver::Unknown;
+ break;
+ default:
+ if (!secondary->impl->computeValidity(query, result))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+bool StagedSolverImpl::computeValue(const Query& query,
+ ref<Expr> &result) {
+ if (primary->computeValue(query, result))
+ return true;
+
+ return secondary->impl->computeValue(query, result);
+}
+
+bool
+StagedSolverImpl::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ if (primary->computeInitialValues(query, objects, values, hasSolution))
+ return true;
+
+ return secondary->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+}
Added: klee/trunk/lib/Solver/IndependentSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/IndependentSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/IndependentSolver.cpp (added)
+++ klee/trunk/lib/Solver/IndependentSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,314 @@
+//===-- IndependentSolver.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/Solver.h"
+
+#include "klee/Expr.h"
+#include "klee/Constraints.h"
+#include "klee/SolverImpl.h"
+
+#include "klee/util/ExprUtil.h"
+
+#include "llvm/Support/Streams.h"
+
+#include <map>
+#include <vector>
+
+using namespace klee;
+using namespace llvm;
+
+template<class T>
+class DenseSet {
+ typedef std::set<T> set_ty;
+ set_ty s;
+
+public:
+ DenseSet() {}
+
+ void add(T x) {
+ s.insert(x);
+ }
+ void add(T start, T end) {
+ for (; start<end; start++)
+ s.insert(start);
+ }
+
+ // returns true iff set is changed by addition
+ bool add(const DenseSet &b) {
+ bool modified = false;
+ for (typename set_ty::const_iterator it = b.s.begin(), ie = b.s.end();
+ it != ie; ++it) {
+ if (modified || !s.count(*it)) {
+ modified = true;
+ s.insert(*it);
+ }
+ }
+ return modified;
+ }
+
+ bool intersects(const DenseSet &b) {
+ for (typename set_ty::iterator it = s.begin(), ie = s.end();
+ it != ie; ++it)
+ if (b.s.count(*it))
+ return true;
+ return false;
+ }
+
+ void print(std::ostream &os) const {
+ bool first = true;
+ os << "{";
+ for (typename set_ty::iterator it = s.begin(), ie = s.end();
+ it != ie; ++it) {
+ if (first) {
+ first = false;
+ } else {
+ os << ",";
+ }
+ os << *it;
+ }
+ os << "}";
+ }
+};
+
+template<class T>
+inline std::ostream &operator<<(std::ostream &os, const DenseSet<T> &dis) {
+ dis.print(os);
+ return os;
+}
+
+class IndependentElementSet {
+ typedef std::map<const Array*, DenseSet<unsigned> > elements_ty;
+ elements_ty elements;
+ std::set<const Array*> wholeObjects;
+
+public:
+ IndependentElementSet() {}
+ IndependentElementSet(ref<Expr> e) {
+ std::vector< ref<ReadExpr> > reads;
+ findReads(e, /* visitUpdates= */ true, reads);
+ for (unsigned i = 0; i != reads.size(); ++i) {
+ ReadExpr *re = reads[i].get();
+ if (re->updates.isRooted) {
+ const Array *array = re->updates.root;
+ if (!wholeObjects.count(array)) {
+ if (re->index.isConstant()) {
+ DenseSet<unsigned> &dis = elements[array];
+ dis.add((unsigned) re->index.getConstantValue());
+ } else {
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2!=elements.end())
+ elements.erase(it2);
+ wholeObjects.insert(array);
+ }
+ }
+ }
+ }
+ }
+ IndependentElementSet(const IndependentElementSet &ies) :
+ elements(ies.elements),
+ wholeObjects(ies.wholeObjects) {}
+
+ IndependentElementSet &operator=(const IndependentElementSet &ies) {
+ elements = ies.elements;
+ wholeObjects = ies.wholeObjects;
+ return *this;
+ }
+
+ void print(std::ostream &os) const {
+ os << "{";
+ bool first = true;
+ for (std::set<const Array*>::iterator it = wholeObjects.begin(),
+ ie = wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+
+ if (first) {
+ first = false;
+ } else {
+ os << ", ";
+ }
+
+ os << "MO" << array->id;
+ }
+ for (elements_ty::const_iterator it = elements.begin(), ie = elements.end();
+ it != ie; ++it) {
+ const Array *array = it->first;
+ const DenseSet<unsigned> &dis = it->second;
+
+ if (first) {
+ first = false;
+ } else {
+ os << ", ";
+ }
+
+ os << "MO" << array->id << " : " << dis;
+ }
+ os << "}";
+ }
+
+ // more efficient when this is the smaller set
+ bool intersects(const IndependentElementSet &b) {
+ for (std::set<const Array*>::iterator it = wholeObjects.begin(),
+ ie = wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ if (b.wholeObjects.count(array) ||
+ b.elements.find(array) != b.elements.end())
+ return true;
+ }
+ for (elements_ty::iterator it = elements.begin(), ie = elements.end();
+ it != ie; ++it) {
+ const Array *array = it->first;
+ if (b.wholeObjects.count(array))
+ return true;
+ elements_ty::const_iterator it2 = b.elements.find(array);
+ if (it2 != b.elements.end()) {
+ if (it->second.intersects(it2->second))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // returns true iff set is changed by addition
+ bool add(const IndependentElementSet &b) {
+ bool modified = false;
+ for (std::set<const Array*>::const_iterator it = b.wholeObjects.begin(),
+ ie = b.wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2!=elements.end()) {
+ modified = true;
+ elements.erase(it2);
+ wholeObjects.insert(array);
+ } else {
+ if (!wholeObjects.count(array)) {
+ modified = true;
+ wholeObjects.insert(array);
+ }
+ }
+ }
+ for (elements_ty::const_iterator it = b.elements.begin(),
+ ie = b.elements.end(); it != ie; ++it) {
+ const Array *array = it->first;
+ if (!wholeObjects.count(array)) {
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2==elements.end()) {
+ modified = true;
+ elements.insert(*it);
+ } else {
+ if (it2->second.add(it->second))
+ modified = true;
+ }
+ }
+ }
+ return modified;
+ }
+};
+
+inline std::ostream &operator<<(std::ostream &os, const IndependentElementSet &ies) {
+ ies.print(os);
+ return os;
+}
+
+static
+IndependentElementSet getIndependentConstraints(const Query& query,
+ std::vector< ref<Expr> > &result) {
+ IndependentElementSet eltsClosure(query.expr);
+ std::vector< std::pair<ref<Expr>, IndependentElementSet> > worklist;
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ worklist.push_back(std::make_pair(*it, IndependentElementSet(*it)));
+
+ // XXX This should be more efficient (in terms of low level copy stuff).
+ bool done = false;
+ do {
+ done = true;
+ std::vector< std::pair<ref<Expr>, IndependentElementSet> > newWorklist;
+ for (std::vector< std::pair<ref<Expr>, IndependentElementSet> >::iterator
+ it = worklist.begin(), ie = worklist.end(); it != ie; ++it) {
+ if (it->second.intersects(eltsClosure)) {
+ if (eltsClosure.add(it->second))
+ done = false;
+ result.push_back(it->first);
+ } else {
+ newWorklist.push_back(*it);
+ }
+ }
+ worklist.swap(newWorklist);
+ } while (!done);
+
+ if (0) {
+ std::set< ref<Expr> > reqset(result.begin(), result.end());
+ llvm::cerr << "--\n";
+ llvm::cerr << "Q: " << query.expr << "\n";
+ llvm::cerr << "\telts: " << IndependentElementSet(query.expr) << "\n";
+ int i = 0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it) {
+ llvm::cerr << "C" << i++ << ": " << *it;
+ llvm::cerr << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n";
+ llvm::cerr << "\telts: " << IndependentElementSet(*it) << "\n";
+ }
+ llvm::cerr << "elts closure: " << eltsClosure << "\n";
+ }
+
+ return eltsClosure;
+}
+
+class IndependentSolver : public SolverImpl {
+private:
+ Solver *solver;
+
+public:
+ IndependentSolver(Solver *_solver)
+ : solver(_solver) {}
+ ~IndependentSolver() { delete solver; }
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ return solver->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+ }
+};
+
+bool IndependentSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeValidity(Query(tmp, query.expr),
+ result);
+}
+
+bool IndependentSolver::computeTruth(const Query& query, bool &isValid) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeTruth(Query(tmp, query.expr),
+ isValid);
+}
+
+bool IndependentSolver::computeValue(const Query& query, ref<Expr> &result) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeValue(Query(tmp, query.expr), result);
+}
+
+Solver *klee::createIndependentSolver(Solver *s) {
+ return new Solver(new IndependentSolver(s));
+}
Added: klee/trunk/lib/Solver/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/Makefile (added)
+++ klee/trunk/lib/Solver/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+#===-- lib/Solver/Makefile ---------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleaverSolver
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+
+include $(LEVEL)/Makefile.common
Propchange: klee/trunk/lib/Solver/Makefile
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/lib/Solver/PCLoggingSolver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/PCLoggingSolver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/PCLoggingSolver.cpp (added)
+++ klee/trunk/lib/Solver/PCLoggingSolver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,134 @@
+//===-- PCLoggingSolver.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/Solver.h"
+
+// FIXME: This should not be here.
+#include "klee/ExecutionState.h"
+#include "klee/Expr.h"
+#include "klee/SolverImpl.h"
+#include "klee/Statistics.h"
+#include "klee/util/ExprPPrinter.h"
+#include "klee/Internal/Support/QueryLog.h"
+#include "klee/Internal/System/Time.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#include <fstream>
+
+using namespace klee;
+using namespace llvm;
+using namespace klee::util;
+
+///
+
+class PCLoggingSolver : public SolverImpl {
+ Solver *solver;
+ std::ofstream os;
+ ExprPPrinter *printer;
+ unsigned queryCount;
+ double startTime;
+
+ void startQuery(const Query& query, const char *typeName) {
+ Statistic *S = theStatisticManager->getStatisticByName("Instructions");
+ uint64_t instructions = S ? S->getValue() : 0;
+ os << "# Query " << queryCount++ << " -- "
+ << "Type: " << typeName << ", "
+ << "Instructions: " << instructions << "\n";
+ printer->printQuery(os, query.constraints, query.expr);
+
+ startTime = getWallTime();
+ }
+
+ void finishQuery(bool success) {
+ double delta = getWallTime() - startTime;
+ os << "# " << (success ? "OK" : "FAIL") << " -- "
+ << "Elapsed: " << delta << "\n";
+ }
+
+public:
+ PCLoggingSolver(Solver *_solver, std::string path)
+ : solver(_solver),
+ os(path.c_str(), std::ios::trunc),
+ printer(ExprPPrinter::create(os)),
+ queryCount(0) {
+ }
+ ~PCLoggingSolver() {
+ delete printer;
+ delete solver;
+ }
+
+ bool computeTruth(const Query& query, bool &isValid) {
+ startQuery(query, "Truth");
+ bool success = solver->impl->computeTruth(query, isValid);
+ finishQuery(success);
+ if (success)
+ os << "# Is Valid: " << (isValid ? "true" : "false") << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeValidity(const Query& query, Solver::Validity &result) {
+ startQuery(query, "Validity");
+ bool success = solver->impl->computeValidity(query, result);
+ finishQuery(success);
+ if (success)
+ os << "# Validity: " << result << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeValue(const Query& query, ref<Expr> &result) {
+ startQuery(query, "Value");
+ bool success = solver->impl->computeValue(query, result);
+ finishQuery(success);
+ if (success)
+ os << "# Result: " << result << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ // FIXME: Add objects to output.
+ startQuery(query, "InitialValues");
+ bool success = solver->impl->computeInitialValues(query, objects,
+ values, hasSolution);
+ finishQuery(success);
+ if (success) {
+ os << "# Solvable: " << (hasSolution ? "true" : "false") << "\n";
+ if (hasSolution) {
+ std::vector< std::vector<unsigned char> >::iterator
+ values_it = values.begin();
+ for (std::vector<const Array*>::const_iterator i = objects.begin(),
+ e = objects.end(); i != e; ++i, ++values_it) {
+ const Array *array = *i;
+ std::vector<unsigned char> &data = *values_it;
+ os << "# arr" << array->id << " = [";
+ for (unsigned j = 0; j < array->size; j++) {
+ os << (int) data[j];
+ if (j+1 < array->size)
+ os << ",";
+ }
+ os << "]\n";
+ }
+ }
+ }
+ os << "\n";
+ return success;
+ }
+};
+
+///
+
+Solver *klee::createPCLoggingSolver(Solver *_solver, std::string path) {
+ return new Solver(new PCLoggingSolver(_solver, path));
+}
Added: klee/trunk/lib/Solver/STPBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/STPBuilder.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/STPBuilder.cpp (added)
+++ klee/trunk/lib/Solver/STPBuilder.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,819 @@
+//===-- STPBuilder.cpp ----------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "STPBuilder.h"
+
+#include "klee/Expr.h"
+#include "klee/Solver.h"
+#include "klee/util/Bits.h"
+
+#include "ConstantDivision.h"
+#include "SolverStats.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#define vc_bvBoolExtract IAMTHESPAWNOFSATAN
+// unclear return
+#define vc_bvLeftShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvRightShiftExpr IAMTHESPAWNOFSATAN
+// bad refcnt'ng
+#define vc_bvVar32LeftShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvVar32RightShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvVar32DivByPowOfTwoExpr IAMTHESPAWNOFSATAN
+#define vc_bvCreateMemoryArray IAMTHESPAWNOFSATAN
+#define vc_bvReadMemoryArray IAMTHESPAWNOFSATAN
+#define vc_bvWriteToMemoryArray IAMTHESPAWNOFSATAN
+
+#include <algorithm> // max, min
+#include <cassert>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+
+using namespace klee;
+
+namespace {
+ llvm::cl::opt<bool>
+ UseConstructHash("use-construct-hash",
+ llvm::cl::desc("Use hash-consing during STP query construction."),
+ llvm::cl::init(true));
+}
+
+///
+
+/***/
+
+STPBuilder::STPBuilder(::VC _vc, bool _optimizeDivides)
+ : vc(_vc), optimizeDivides(_optimizeDivides)
+{
+ tempVars[0] = buildVar("__tmpInt8", 8);
+ tempVars[1] = buildVar("__tmpInt16", 16);
+ tempVars[2] = buildVar("__tmpInt32", 32);
+ tempVars[3] = buildVar("__tmpInt64", 64);
+}
+
+STPBuilder::~STPBuilder() {
+}
+
+///
+
+/* Warning: be careful about what c_interface functions you use. Some of
+ them look like they cons memory but in fact don't, which is bad when
+ you call vc_DeleteExpr on them. */
+
+::VCExpr STPBuilder::buildVar(const char *name, unsigned width) {
+ // XXX don't rebuild if this stuff cons's
+ ::Type t = (width==1) ? vc_boolType(vc) : vc_bvType(vc, width);
+ ::VCExpr res = vc_varExpr(vc, (char*) name, t);
+ vc_DeleteExpr(t);
+ return res;
+}
+
+::VCExpr STPBuilder::buildArray(const char *name, unsigned indexWidth, unsigned valueWidth) {
+ // XXX don't rebuild if this stuff cons's
+ ::Type t1 = vc_bvType(vc, indexWidth);
+ ::Type t2 = vc_bvType(vc, valueWidth);
+ ::Type t = vc_arrayType(vc, t1, t2);
+ ::VCExpr res = vc_varExpr(vc, (char*) name, t);
+ vc_DeleteExpr(t);
+ vc_DeleteExpr(t2);
+ vc_DeleteExpr(t1);
+ return res;
+}
+
+ExprHandle STPBuilder::getTempVar(Expr::Width w) {
+ switch (w) {
+ case Expr::Int8: return tempVars[0];
+ case Expr::Int16: return tempVars[1];
+ case Expr::Int32: return tempVars[2];
+ case Expr::Int64: return tempVars[3];
+ default:
+ assert(0 && "invalid type");
+ }
+}
+
+ExprHandle STPBuilder::getTrue() {
+ return vc_trueExpr(vc);
+}
+ExprHandle STPBuilder::getFalse() {
+ return vc_falseExpr(vc);
+}
+ExprHandle STPBuilder::bvOne(unsigned width) {
+ return bvConst32(width, 1);
+}
+ExprHandle STPBuilder::bvZero(unsigned width) {
+ return bvConst32(width, 0);
+}
+ExprHandle STPBuilder::bvMinusOne(unsigned width) {
+ return bvConst64(width, (int64_t) -1);
+}
+ExprHandle STPBuilder::bvConst32(unsigned width, uint32_t value) {
+ return vc_bvConstExprFromInt(vc, width, value);
+}
+ExprHandle STPBuilder::bvConst64(unsigned width, uint64_t value) {
+ return vc_bvConstExprFromLL(vc, width, value);
+}
+
+ExprHandle STPBuilder::bvBoolExtract(ExprHandle expr, int bit) {
+ return vc_eqExpr(vc, bvExtract(expr, bit, bit), bvOne(1));
+}
+ExprHandle STPBuilder::bvExtract(ExprHandle expr, unsigned top, unsigned bottom) {
+ return vc_bvExtract(vc, expr, top, bottom);
+}
+ExprHandle STPBuilder::eqExpr(ExprHandle a, ExprHandle b) {
+ return vc_eqExpr(vc, a, b);
+}
+
+// logical right shift
+ExprHandle STPBuilder::bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width) {
+ return bvZero(width);
+ } else {
+ return vc_bvConcatExpr(vc,
+ bvZero(shift),
+ bvExtract(expr, width - 1, shift));
+ }
+}
+
+// logical left shift
+ExprHandle STPBuilder::bvLeftShift(ExprHandle expr, unsigned amount, unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width) {
+ return bvZero(width);
+ } else {
+ // stp shift does "expr @ [0 x s]" which we then have to extract,
+ // rolling our own gives slightly smaller exprs
+ return vc_bvConcatExpr(vc,
+ bvExtract(expr, width - shift - 1, 0),
+ bvZero(shift));
+ }
+}
+
+// left shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ ExprHandle res = bvZero(width);
+
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ for( int i=width-1; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits, i)),
+ bvLeftShift(expr, i, shiftBits),
+ res);
+ }
+ return res;
+}
+
+// logical right shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ ExprHandle res = bvZero(width);
+
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ for( int i=width-1; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits, i)),
+ bvRightShift(expr, i, shiftBits),
+ res);
+ }
+
+ return res;
+}
+
+// arithmetic right shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //get the sign bit to fill with
+ ExprHandle signedBool = bvBoolExtract(expr, width-1);
+
+ //start with the result if shifting by width-1
+ ExprHandle res = constructAShrByConstant(expr, width-1, signedBool, shiftBits);
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ // XXX more efficient to move the ite on the sign outside all exprs?
+ // XXX more efficient to sign extend, right shift, then extract lower bits?
+ for( int i=width-2; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits,i)),
+ constructAShrByConstant(expr,
+ i,
+ signedBool,
+ shiftBits),
+ res);
+ }
+
+ return res;
+}
+
+ExprHandle STPBuilder::constructAShrByConstant(ExprHandle expr,
+ unsigned amount,
+ ExprHandle isSigned,
+ unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width-1) {
+ return vc_iteExpr(vc, isSigned, bvMinusOne(width), bvZero(width));
+ } else {
+ return vc_iteExpr(vc,
+ isSigned,
+ ExprHandle(vc_bvConcatExpr(vc,
+ bvMinusOne(shift),
+ bvExtract(expr, width - 1, shift))),
+ bvRightShift(expr, shift, shiftBits));
+ }
+}
+
+ExprHandle STPBuilder::constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x) {
+ unsigned shiftBits = getShiftBits(width);
+ uint64_t add, sub;
+ ExprHandle res = 0;
+
+ // expr*x == expr*(add-sub) == expr*add - expr*sub
+ ComputeMultConstants64(x, add, sub);
+
+ // legal, these would overflow completely
+ add = bits64::truncateToNBits(add, width);
+ sub = bits64::truncateToNBits(sub, width);
+
+ for (int j=63; j>=0; j--) {
+ uint64_t bit = 1LL << j;
+
+ if ((add&bit) || (sub&bit)) {
+ assert(!((add&bit) && (sub&bit)) && "invalid mult constants");
+ ExprHandle op = bvLeftShift(expr, j, shiftBits);
+
+ if (add&bit) {
+ if (res) {
+ res = vc_bvPlusExpr(vc, width, res, op);
+ } else {
+ res = op;
+ }
+ } else {
+ if (res) {
+ res = vc_bvMinusExpr(vc, width, res, op);
+ } else {
+ res = vc_bvUMinusExpr(vc, op);
+ }
+ }
+ }
+ }
+
+ if (!res)
+ res = bvZero(width);
+
+ return res;
+}
+
+/*
+ * Compute the 32-bit unsigned integer division of n by a divisor d based on
+ * the constants derived from the constant divisor d.
+ *
+ * Returns n/d without doing explicit division. The cost is 2 adds, 3 shifts,
+ * and a (64-bit) multiply.
+ *
+ * @param n numerator (dividend) as an expression
+ * @param width number of bits used to represent the value
+ * @param d the divisor
+ *
+ * @return n/d without doing explicit division
+ */
+ExprHandle STPBuilder::constructUDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d) {
+ assert(width==32 && "can only compute udiv constants for 32-bit division");
+
+ // Compute the constants needed to compute n/d for constant d w/o
+ // division by d.
+ uint32_t mprime, sh1, sh2;
+ ComputeUDivConstants32(d, mprime, sh1, sh2);
+ ExprHandle expr_sh1 = bvConst32( 32, sh1);
+ ExprHandle expr_sh2 = bvConst32( 32, sh2);
+
+ // t1 = MULUH(mprime, n) = ( (uint64_t)mprime * (uint64_t)n ) >> 32
+ ExprHandle expr_n_64 = vc_bvConcatExpr( vc, bvZero(32), expr_n ); //extend to 64 bits
+ ExprHandle t1_64bits = constructMulByConstant( expr_n_64, 64, (uint64_t)mprime );
+ ExprHandle t1 = vc_bvExtract( vc, t1_64bits, 63, 32 ); //upper 32 bits
+
+ // n/d = (((n - t1) >> sh1) + t1) >> sh2;
+ ExprHandle n_minus_t1 = vc_bvMinusExpr( vc, width, expr_n, t1 );
+ ExprHandle shift_sh1 = bvVarRightShift( n_minus_t1, expr_sh1, 32 );
+ ExprHandle plus_t1 = vc_bvPlusExpr( vc, width, shift_sh1, t1 );
+ ExprHandle res = bvVarRightShift( plus_t1, expr_sh2, 32 );
+
+ return res;
+}
+
+/*
+ * Compute the 32-bitnsigned integer division of n by a divisor d based on
+ * the constants derived from the constant divisor d.
+ *
+ * Returns n/d without doing explicit division. The cost is 3 adds, 3 shifts,
+ * a (64-bit) multiply, and an XOR.
+ *
+ * @param n numerator (dividend) as an expression
+ * @param width number of bits used to represent the value
+ * @param d the divisor
+ *
+ * @return n/d without doing explicit division
+ */
+ExprHandle STPBuilder::constructSDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d) {
+ assert(width==32 && "can only compute udiv constants for 32-bit division");
+
+ // Compute the constants needed to compute n/d for constant d w/o division by d.
+ int32_t mprime, dsign, shpost;
+ ComputeSDivConstants32(d, mprime, dsign, shpost);
+ ExprHandle expr_dsign = bvConst32( 32, dsign);
+ ExprHandle expr_shpost = bvConst32( 32, shpost);
+
+ // q0 = n + MULSH( mprime, n ) = n + (( (int64_t)mprime * (int64_t)n ) >> 32)
+ int64_t mprime_64 = (int64_t)mprime;
+
+ ExprHandle expr_n_64 = vc_bvSignExtend( vc, expr_n, 64 );
+ ExprHandle mult_64 = constructMulByConstant( expr_n_64, 64, mprime_64 );
+ ExprHandle mulsh = vc_bvExtract( vc, mult_64, 63, 32 ); //upper 32-bits
+ ExprHandle n_plus_mulsh = vc_bvPlusExpr( vc, width, expr_n, mulsh );
+
+ // Improved variable arithmetic right shift: sign extend, shift,
+ // extract.
+ ExprHandle extend_npm = vc_bvSignExtend( vc, n_plus_mulsh, 64 );
+ ExprHandle shift_npm = bvVarRightShift( extend_npm, expr_shpost, 64 );
+ ExprHandle shift_shpost = vc_bvExtract( vc, shift_npm, 31, 0 ); //lower 32-bits
+
+ // XSIGN(n) is -1 if n is negative, positive one otherwise
+ ExprHandle is_signed = bvBoolExtract( expr_n, 31 );
+ ExprHandle neg_one = bvMinusOne(32);
+ ExprHandle xsign_of_n = vc_iteExpr( vc, is_signed, neg_one, bvZero(32) );
+
+ // q0 = (n_plus_mulsh >> shpost) - XSIGN(n)
+ ExprHandle q0 = vc_bvMinusExpr( vc, width, shift_shpost, xsign_of_n );
+
+ // n/d = (q0 ^ dsign) - dsign
+ ExprHandle q0_xor_dsign = vc_bvXorExpr( vc, q0, expr_dsign );
+ ExprHandle res = vc_bvMinusExpr( vc, width, q0_xor_dsign, expr_dsign );
+
+ return res;
+}
+
+::VCExpr STPBuilder::getInitialArray(const Array *root) {
+ if (root->stpInitialArray) {
+ return root->stpInitialArray;
+ } else {
+ char buf[32];
+ sprintf(buf, "arr%d", root->id);
+ root->stpInitialArray = buildArray(buf, 32, 8);
+ return root->stpInitialArray;
+ }
+}
+
+ExprHandle STPBuilder::getInitialRead(const Array *root, unsigned index) {
+ return vc_readExpr(vc, getInitialArray(root), bvConst32(32, index));
+}
+
+::VCExpr STPBuilder::getArrayForUpdate(const Array *root,
+ const UpdateNode *un) {
+ if (!un) {
+ return getInitialArray(root);
+ } else {
+ // FIXME: This really needs to be non-recursive.
+ if (!un->stpArray)
+ un->stpArray = vc_writeExpr(vc,
+ getArrayForUpdate(root, un->next),
+ construct(un->index, 0),
+ construct(un->value, 0));
+
+ return un->stpArray;
+ }
+}
+
+/** if *width_out!=1 then result is a bitvector,
+ otherwise it is a bool */
+ExprHandle STPBuilder::construct(ref<Expr> e, int *width_out) {
+ if (!UseConstructHash || e.isConstant()) {
+ return constructActual(e, width_out);
+ } else {
+ ExprHashMap< std::pair<ExprHandle, unsigned> >::iterator it =
+ constructed.find(e);
+ if (it!=constructed.end()) {
+ if (width_out)
+ *width_out = it->second.second;
+ return it->second.first;
+ } else {
+ int width;
+ if (!width_out) width_out = &width;
+ ExprHandle res = constructActual(e, width_out);
+ constructed.insert(std::make_pair(e, std::make_pair(res, *width_out)));
+ return res;
+ }
+ }
+}
+
+
+/** 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: {
+ uint64_t asUInt64 = e.getConstantValue();
+ *width_out = e.getWidth();
+
+ if (*width_out > 64)
+ assert(0 && "constructActual: width > 64");
+
+ if (*width_out == 1)
+ return asUInt64 ? getTrue() : getFalse();
+ else if (*width_out <= 32)
+ return bvConst32(*width_out, asUInt64);
+ else return bvConst64(*width_out, asUInt64);
+ }
+
+ // Special
+ case Expr::NotOptimized: {
+ NotOptimizedExpr *noe = static_ref_cast<NotOptimizedExpr>(e);
+ return construct(noe->src, width_out);
+ }
+
+ case Expr::Read: {
+ ReadExpr *re = static_ref_cast<ReadExpr>(e);
+ *width_out = 8;
+ return vc_readExpr(vc,
+ getArrayForUpdate(re->updates.root, re->updates.head),
+ construct(re->index, 0));
+ }
+
+ case Expr::Select: {
+ SelectExpr *se = static_ref_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 = static_ref_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 = static_ref_cast<ExtractExpr>(e);
+ ExprHandle src = construct(ee->expr, width_out);
+ *width_out = ee->getWidth();
+ if (*width_out==1) {
+ return bvBoolExtract(src, 0);
+ } else {
+ return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
+ }
+ }
+
+ // Casting
+
+ case Expr::ZExt: {
+ int srcWidth;
+ CastExpr *ce = static_ref_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 = static_ref_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 = static_ref_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 = static_ref_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 = static_ref_cast<MulExpr>(e);
+ ExprHandle right = construct(me->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized mul");
+
+ if (me->left.isConstant()) {
+ return constructMulByConstant(right, *width_out, me->left.getConstantValue());
+ } else {
+ ExprHandle left = construct(me->left, width_out);
+ return vc_bvMultExpr(vc, *width_out, left, right);
+ }
+ }
+
+ case Expr::UDiv: {
+ UDivExpr *de = static_ref_cast<UDivExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized udiv");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ 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);
+ return vc_bvDivExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::SDiv: {
+ SDivExpr *de = static_ref_cast<SDivExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized sdiv");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ if (optimizeDivides) {
+ if (*width_out == 32) //only works for 32-bit division
+ return constructSDivByConstant( left, *width_out, divisor);
+ }
+ }
+
+ // 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 = static_ref_cast<URemExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized urem");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ 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 = static_ref_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);
+ }
+
+ // Binary
+
+ case Expr::And: {
+ AndExpr *ae = static_ref_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 = static_ref_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 = static_ref_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 = static_ref_cast<ShlExpr>(e);
+ ExprHandle left = construct(se->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized shl");
+
+ if (se->right.isConstant()) {
+ return bvLeftShift(left, se->right.getConstantValue(), getShiftBits(*width_out));
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(se->right, &shiftWidth);
+ return bvVarLeftShift( left, amount, *width_out );
+ }
+ }
+
+ case Expr::LShr: {
+ LShrExpr *lse = static_ref_cast<LShrExpr>(e);
+ ExprHandle left = construct(lse->left, width_out);
+ unsigned shiftBits = getShiftBits(*width_out);
+ assert(*width_out!=1 && "uncanonicalized lshr");
+
+ if (lse->right.isConstant()) {
+ return bvRightShift(left, (unsigned) lse->right.getConstantValue(), shiftBits);
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(lse->right, &shiftWidth);
+ return bvVarRightShift( left, amount, *width_out );
+ }
+ }
+
+ case Expr::AShr: {
+ AShrExpr *ase = static_ref_cast<AShrExpr>(e);
+ ExprHandle left = construct(ase->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized ashr");
+
+ if (ase->right.isConstant()) {
+ unsigned shift = (unsigned) ase->right.getConstantValue();
+ ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
+ return constructAShrByConstant(left, shift, signedBool, getShiftBits(*width_out));
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(ase->right, &shiftWidth);
+ return bvVarArithRightShift( left, amount, *width_out );
+ }
+ }
+
+ // Comparison
+
+ case Expr::Eq: {
+ EqExpr *ee = static_ref_cast<EqExpr>(e);
+ ExprHandle left = construct(ee->left, width_out);
+ ExprHandle right = construct(ee->right, width_out);
+ if (*width_out==1) {
+ if (ee->left.isConstant()) {
+ assert(!ee->left.getConstantValue() && "uncanonicalized eq");
+ 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 = static_ref_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 = static_ref_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 = static_ref_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 = static_ref_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);
+ }
+}
Added: klee/trunk/lib/Solver/STPBuilder.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/STPBuilder.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/STPBuilder.h (added)
+++ klee/trunk/lib/Solver/STPBuilder.h Wed May 20 23:36:41 2009
@@ -0,0 +1,125 @@
+//===-- STPBuilder.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 __UTIL_STPBUILDER_H__
+#define __UTIL_STPBUILDER_H__
+
+#include "klee/util/ExprHashMap.h"
+#include "klee/Config/config.h"
+
+#include <vector>
+#include <map>
+
+#define Expr VCExpr
+#include "stp/c_interface.h"
+
+#if ENABLE_STPLOG == 1
+#include "stp/stplog.h"
+#endif
+#undef Expr
+
+namespace klee {
+ class ExprHolder {
+ friend class ExprHandle;
+ ::VCExpr expr;
+ unsigned count;
+
+ public:
+ ExprHolder(const ::VCExpr _expr) : expr(_expr), count(0) {}
+ ~ExprHolder() {
+ if (expr) vc_DeleteExpr(expr);
+ }
+ };
+
+ class ExprHandle {
+ ExprHolder *H;
+
+ public:
+ ExprHandle() : H(new ExprHolder(0)) { H->count++; }
+ ExprHandle(::VCExpr _expr) : H(new ExprHolder(_expr)) { H->count++; }
+ ExprHandle(const ExprHandle &b) : H(b.H) { H->count++; }
+ ~ExprHandle() { if (--H->count == 0) delete H; }
+
+ ExprHandle &operator=(const ExprHandle &b) {
+ if (--H->count == 0) delete H;
+ H = b.H;
+ H->count++;
+ return *this;
+ }
+
+ operator bool () { return H->expr; }
+ operator ::VCExpr () { return H->expr; }
+ };
+
+class STPBuilder {
+ ::VC vc;
+ ExprHandle tempVars[4];
+ ExprHashMap< std::pair<ExprHandle, unsigned> > constructed;
+
+ /// optimizeDivides - Rewrite division and reminders by constants
+ /// into multiplies and shifts. STP should probably handle this for
+ /// use.
+ bool optimizeDivides;
+
+private:
+ unsigned getShiftBits(unsigned amount) {
+ return (amount == 64) ? 6 : 5;
+ }
+
+ ExprHandle bvOne(unsigned width);
+ ExprHandle bvZero(unsigned width);
+ ExprHandle bvMinusOne(unsigned width);
+ ExprHandle bvConst32(unsigned width, uint32_t value);
+ ExprHandle bvConst64(unsigned width, uint64_t value);
+
+ ExprHandle bvBoolExtract(ExprHandle expr, int bit);
+ ExprHandle bvExtract(ExprHandle expr, unsigned top, unsigned bottom);
+ ExprHandle eqExpr(ExprHandle a, ExprHandle b);
+
+ //logical left and right shift (not arithmetic)
+ ExprHandle bvLeftShift(ExprHandle expr, unsigned shift, unsigned shiftBits);
+ ExprHandle bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits);
+ ExprHandle bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width);
+ ExprHandle bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width);
+ ExprHandle bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width);
+
+ ExprHandle constructAShrByConstant(ExprHandle expr, unsigned shift,
+ ExprHandle isSigned, unsigned shiftBits);
+ ExprHandle constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x);
+ ExprHandle constructUDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d);
+ ExprHandle constructSDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d);
+
+ ::VCExpr getInitialArray(const Array *os);
+ ::VCExpr getArrayForUpdate(const Array *root, const UpdateNode *un);
+
+ ExprHandle constructActual(ref<Expr> e, int *width_out);
+ ExprHandle construct(ref<Expr> e, int *width_out);
+
+ ::VCExpr buildVar(const char *name, unsigned width);
+ ::VCExpr buildArray(const char *name, unsigned indexWidth, unsigned valueWidth);
+
+public:
+ STPBuilder(::VC _vc, bool _optimizeDivides=true);
+ ~STPBuilder();
+
+ ExprHandle getTrue();
+ ExprHandle getFalse();
+ ExprHandle getTempVar(Expr::Width w);
+ ExprHandle getInitialRead(const Array *os, unsigned index);
+
+ ExprHandle construct(ref<Expr> e) {
+ ExprHandle res = construct(e, 0);
+ constructed.clear();
+ return res;
+ }
+};
+
+}
+
+#endif
Added: klee/trunk/lib/Solver/Solver.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/Solver.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/Solver.cpp (added)
+++ klee/trunk/lib/Solver/Solver.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,643 @@
+//===-- Solver.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/Solver.h"
+#include "klee/SolverImpl.h"
+
+#include "SolverStats.h"
+#include "STPBuilder.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/TimerStatIncrementer.h"
+#include "klee/util/Assignment.h"
+#include "klee/util/ExprPPrinter.h"
+#include "klee/util/ExprUtil.h"
+#include "klee/Internal/Support/Timer.h"
+
+#define vc_bvBoolExtract IAMTHESPAWNOFSATAN
+
+#include <cassert>
+#include <map>
+#include <vector>
+
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+using namespace klee;
+
+/***/
+
+const char *Solver::validity_to_str(Validity v) {
+ switch (v) {
+ default: return "Unknown";
+ case True: return "True";
+ case False: return "False";
+ }
+}
+
+Solver::~Solver() {
+ delete impl;
+}
+
+SolverImpl::~SolverImpl() {
+}
+
+bool Solver::evaluate(const Query& query, Validity &result) {
+ assert(query.expr.getWidth() == Expr::Bool && "Invalid expression type!");
+
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr.getConstantValue() ? True : False;
+ return true;
+ }
+
+ return impl->computeValidity(query, result);
+}
+
+bool SolverImpl::computeValidity(const Query& query, Solver::Validity &result) {
+ bool isTrue, isFalse;
+ if (!computeTruth(query, isTrue))
+ return false;
+ if (isTrue) {
+ result = Solver::True;
+ } else {
+ if (!computeTruth(query.negateExpr(), isFalse))
+ return false;
+ result = isFalse ? Solver::False : Solver::Unknown;
+ }
+ return true;
+}
+
+bool Solver::mustBeTrue(const Query& query, bool &result) {
+ assert(query.expr.getWidth() == Expr::Bool && "Invalid expression type!");
+
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr.getConstantValue() ? true : false;
+ return true;
+ }
+
+ return impl->computeTruth(query, result);
+}
+
+bool Solver::mustBeFalse(const Query& query, bool &result) {
+ return mustBeTrue(query.negateExpr(), result);
+}
+
+bool Solver::mayBeTrue(const Query& query, bool &result) {
+ bool res;
+ if (!mustBeFalse(query, res))
+ return false;
+ result = !res;
+ return true;
+}
+
+bool Solver::mayBeFalse(const Query& query, bool &result) {
+ bool res;
+ if (!mustBeTrue(query, res))
+ return false;
+ result = !res;
+ return true;
+}
+
+bool Solver::getValue(const Query& query, ref<Expr> &result) {
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr;
+ return true;
+ }
+
+ return impl->computeValue(query, result);
+}
+
+bool
+Solver::getInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values) {
+ bool hasSolution;
+ bool success =
+ impl->computeInitialValues(query, objects, values, hasSolution);
+ // FIXME: Propogate this out.
+ if (!hasSolution)
+ return false;
+
+ return success;
+}
+
+std::pair< ref<Expr>, ref<Expr> > Solver::getRange(const Query& query) {
+ ref<Expr> e = query.expr;
+ Expr::Width width = e.getWidth();
+ uint64_t min, max;
+
+ if (width==1) {
+ Solver::Validity result;
+ if (!evaluate(query, result))
+ assert(0 && "computeValidity failed");
+ switch (result) {
+ case Solver::True:
+ min = max = 1; break;
+ case Solver::False:
+ min = max = 0; break;
+ default:
+ min = 0, max = 1; break;
+ }
+ } else if (e.isConstant()) {
+ min = max = e.getConstantValue();
+ } else {
+ // binary search for # of useful bits
+ uint64_t lo=0, hi=width, mid, bits=0;
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res;
+ bool success =
+ mustBeTrue(query.withExpr(
+ EqExpr::create(LShrExpr::create(e,
+ ConstantExpr::create(mid,
+ width)),
+ ConstantExpr::create(0, width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+
+ bits = lo;
+ }
+
+ // could binary search for training zeros and offset
+ // min max but unlikely to be very useful
+
+ // check common case
+ bool res = false;
+ bool success =
+ mayBeTrue(query.withExpr(EqExpr::create(e, ConstantExpr::create(0,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ min = 0;
+ } else {
+ // binary search for min
+ lo=0, hi=bits64::maxValueOfNBits(bits);
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res = false;
+ bool success =
+ mayBeTrue(query.withExpr(UleExpr::create(e,
+ ConstantExpr::create(mid,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+ }
+
+ min = lo;
+ }
+
+ // binary search for max
+ lo=min, hi=bits64::maxValueOfNBits(bits);
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res;
+ bool success =
+ mustBeTrue(query.withExpr(UleExpr::create(e,
+ ConstantExpr::create(mid,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+ }
+
+ max = lo;
+ }
+
+ return std::make_pair(ConstantExpr::create(min, width),
+ ConstantExpr::create(max, width));
+}
+
+/***/
+
+class ValidatingSolver : public SolverImpl {
+private:
+ Solver *solver, *oracle;
+
+public:
+ ValidatingSolver(Solver *_solver, Solver *_oracle)
+ : solver(_solver), oracle(_oracle) {}
+ ~ValidatingSolver() { delete solver; }
+
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+bool ValidatingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ bool answer;
+
+ if (!solver->impl->computeTruth(query, isValid))
+ return false;
+ if (!oracle->impl->computeTruth(query, answer))
+ return false;
+
+ if (isValid != answer)
+ assert(0 && "invalid solver result (computeTruth)");
+
+ return true;
+}
+
+bool ValidatingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ Solver::Validity answer;
+
+ if (!solver->impl->computeValidity(query, result))
+ return false;
+ if (!oracle->impl->computeValidity(query, answer))
+ return false;
+
+ if (result != answer)
+ assert(0 && "invalid solver result (computeValidity)");
+
+ return true;
+}
+
+bool ValidatingSolver::computeValue(const Query& query,
+ ref<Expr> &result) {
+ bool answer;
+
+ if (!solver->impl->computeValue(query, result))
+ return false;
+ // We don't want to compare, but just make sure this is a legal
+ // solution.
+ if (!oracle->impl->computeTruth(query.withExpr(NeExpr::create(query.expr,
+ result)),
+ answer))
+ return false;
+
+ if (answer)
+ assert(0 && "invalid solver result (computeValue)");
+
+ return true;
+}
+
+bool
+ValidatingSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ bool answer;
+
+ if (!solver->impl->computeInitialValues(query, objects, values,
+ hasSolution))
+ return false;
+
+ if (hasSolution) {
+ // Assert the bindings as constraints, and verify that the
+ // conjunction of the actual constraints is satisfiable.
+ std::vector< ref<Expr> > bindings;
+ for (unsigned i = 0; i != values.size(); ++i) {
+ const Array *array = objects[i];
+ for (unsigned j=0; j<array->size; j++) {
+ unsigned char value = values[i][j];
+ bindings.push_back(EqExpr::create(ReadExpr::create(UpdateList(array,
+ true, 0),
+ ref<Expr>(j, Expr::Int32)),
+ ref<Expr>(value, Expr::Int8)));
+ }
+ }
+ ConstraintManager tmp(bindings);
+ ref<Expr> constraints = Expr::createNot(query.expr);
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ constraints = AndExpr::create(constraints, *it);
+
+ if (!oracle->impl->computeTruth(Query(tmp, constraints), answer))
+ return false;
+ if (!answer)
+ assert(0 && "invalid solver result (computeInitialValues)");
+ } else {
+ if (!oracle->impl->computeTruth(query, answer))
+ return false;
+ if (!answer)
+ assert(0 && "invalid solver result (computeInitialValues)");
+ }
+
+ return true;
+}
+
+Solver *klee::createValidatingSolver(Solver *s, Solver *oracle) {
+ return new Solver(new ValidatingSolver(s, oracle));
+}
+
+/***/
+
+class STPSolverImpl : public SolverImpl {
+private:
+ /// The solver we are part of, for access to public information.
+ STPSolver *solver;
+ VC vc;
+ STPBuilder *builder;
+ double timeout;
+ bool useForkedSTP;
+
+public:
+ STPSolverImpl(STPSolver *_solver, bool _useForkedSTP);
+ ~STPSolverImpl();
+
+ char *getConstraintLog(const Query&);
+ void setTimeout(double _timeout) { timeout = _timeout; }
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+static unsigned char *shared_memory_ptr;
+static const unsigned shared_memory_size = 1<<20;
+static int shared_memory_id;
+
+static void stp_error_handler(const char* err_msg) {
+ fprintf(stderr, "error: STP Error: %s\n", err_msg);
+ abort();
+}
+
+STPSolverImpl::STPSolverImpl(STPSolver *_solver, bool _useForkedSTP)
+ : solver(_solver),
+ vc(vc_createValidityChecker()),
+ builder(new STPBuilder(vc)),
+ timeout(0.0),
+ useForkedSTP(_useForkedSTP)
+{
+ assert(vc && "unable to create validity checker");
+ assert(builder && "unable to create STPBuilder");
+
+ vc_registerErrorHandler(::stp_error_handler);
+
+ if (useForkedSTP) {
+ shared_memory_id = shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700);
+ assert(shared_memory_id>=0 && "shmget failed");
+ shared_memory_ptr = (unsigned char*) shmat(shared_memory_id, NULL, 0);
+ assert(shared_memory_ptr!=(void*)-1 && "shmat failed");
+ shmctl(shared_memory_id, IPC_RMID, NULL);
+ }
+}
+
+STPSolverImpl::~STPSolverImpl() {
+ delete builder;
+
+ vc_Destroy(vc);
+}
+
+/***/
+
+STPSolver::STPSolver(bool useForkedSTP)
+ : Solver(new STPSolverImpl(this, useForkedSTP))
+{
+}
+
+char *STPSolver::getConstraintLog(const Query &query) {
+ return static_cast<STPSolverImpl*>(impl)->getConstraintLog(query);
+}
+
+void STPSolver::setTimeout(double timeout) {
+ static_cast<STPSolverImpl*>(impl)->setTimeout(timeout);
+}
+
+/***/
+
+char *STPSolverImpl::getConstraintLog(const Query &query) {
+ vc_push(vc);
+ for (std::vector< ref<Expr> >::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ vc_assertFormula(vc, builder->construct(*it));
+ assert(query.expr == ref<Expr>(0, Expr::Bool) &&
+ "Unexpected expression in query!");
+
+ char *buffer;
+ unsigned long length;
+ vc_printQueryStateToBuffer(vc, builder->getFalse(),
+ &buffer, &length, false);
+ vc_pop(vc);
+
+ return buffer;
+}
+
+bool STPSolverImpl::computeTruth(const Query& query,
+ bool &isValid) {
+ std::vector<const Array*> objects;
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+
+ if (!computeInitialValues(query, objects, values, hasSolution))
+ return false;
+
+ isValid = !hasSolution;
+ return true;
+}
+
+bool STPSolverImpl::computeValue(const Query& query,
+ ref<Expr> &result) {
+ std::vector<const Array*> objects;
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+
+ // Find the object used in the expression, and compute an assignment
+ // for them.
+ findSymbolicObjects(query.expr, objects);
+ if (!computeInitialValues(query.withFalse(), objects, values, hasSolution))
+ return false;
+ assert(hasSolution && "state has invalid constraint set");
+
+ // Evaluate the expression with the computed assignment.
+ Assignment a(objects, values);
+ result = a.evaluate(query.expr);
+
+ return true;
+}
+
+static void runAndGetCex(::VC vc, STPBuilder *builder, ::VCExpr q,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ // XXX I want to be able to timeout here, safely
+ hasSolution = !vc_query(vc, q);
+
+ if (hasSolution) {
+ values.reserve(objects.size());
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ std::vector<unsigned char> data;
+
+ data.reserve(array->size);
+ for (unsigned offset = 0; offset < array->size; offset++) {
+ ExprHandle counter =
+ vc_getCounterExample(vc, builder->getInitialRead(array, offset));
+ unsigned char val = getBVUnsigned(counter);
+ data.push_back(val);
+ }
+
+ values.push_back(data);
+ }
+ }
+}
+
+static void stpTimeoutHandler(int x) {
+ _exit(52);
+}
+
+static bool runAndGetCexForked(::VC vc,
+ STPBuilder *builder,
+ ::VCExpr q,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution,
+ double timeout) {
+ unsigned char *pos = shared_memory_ptr;
+ unsigned sum = 0;
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it)
+ sum += (*it)->size;
+ assert(sum<shared_memory_size && "not enough shared memory for counterexample");
+
+ fflush(stdout);
+ fflush(stderr);
+ int pid = fork();
+ if (pid==-1) {
+ fprintf(stderr, "error: fork failed (for STP)");
+ return false;
+ }
+
+ if (pid == 0) {
+ if (timeout) {
+ ::alarm(0); /* Turn off alarm so we can safely set signal handler */
+ ::signal(SIGALRM, stpTimeoutHandler);
+ ::alarm(std::max(1, (int)timeout));
+ }
+ unsigned res = vc_query(vc, q);
+ if (!res) {
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ for (unsigned offset = 0; offset < array->size; offset++) {
+ ExprHandle counter =
+ vc_getCounterExample(vc, builder->getInitialRead(array, offset));
+ *pos++ = getBVUnsigned(counter);
+ }
+ }
+ }
+ _exit(res);
+ } else {
+ int status;
+ int res = waitpid(pid, &status, 0);
+
+ if (res<0) {
+ fprintf(stderr, "error: waitpid() for STP failed");
+ return false;
+ }
+
+ // From timed_run.py: It appears that linux at least will on
+ // "occasion" return a status when the process was terminated by a
+ // signal, so test signal first.
+ if (WIFSIGNALED(status) || !WIFEXITED(status)) {
+ fprintf(stderr, "error: STP did not return successfully");
+ return false;
+ }
+
+ int exitcode = WEXITSTATUS(status);
+ if (exitcode==0) {
+ hasSolution = true;
+ } else if (exitcode==1) {
+ hasSolution = false;
+ } else if (exitcode==52) {
+ fprintf(stderr, "error: STP timed out");
+ return false;
+ } else {
+ fprintf(stderr, "error: STP did not return a recognized code");
+ return false;
+ }
+
+ if (hasSolution) {
+ values = std::vector< std::vector<unsigned char> >(objects.size());
+ unsigned i=0;
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ std::vector<unsigned char> &data = values[i++];
+ data.insert(data.begin(), pos, pos + array->size);
+ pos += array->size;
+ }
+ }
+
+ return true;
+ }
+}
+
+bool
+STPSolverImpl::computeInitialValues(const Query &query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ TimerStatIncrementer t(stats::queryTime);
+
+ vc_push(vc);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ vc_assertFormula(vc, builder->construct(*it));
+
+ ++stats::queries;
+ ++stats::queryCounterexamples;
+
+ ExprHandle stp_e = builder->construct(query.expr);
+
+ bool success;
+ if (useForkedSTP) {
+ success = runAndGetCexForked(vc, builder, stp_e, objects, values,
+ hasSolution, timeout);
+ } else {
+ runAndGetCex(vc, builder, stp_e, objects, values, hasSolution);
+ success = true;
+ }
+
+ if (success) {
+ if (hasSolution)
+ ++stats::queriesInvalid;
+ else
+ ++stats::queriesValid;
+ }
+
+ vc_pop(vc);
+
+ return success;
+}
Added: klee/trunk/lib/Solver/SolverStats.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/SolverStats.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/SolverStats.cpp (added)
+++ klee/trunk/lib/Solver/SolverStats.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,23 @@
+//===-- SolverStats.cpp ---------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SolverStats.h"
+
+using namespace klee;
+
+Statistic stats::cexCacheTime("CexCacheTime", "CCtime");
+Statistic stats::queries("Queries", "Q");
+Statistic stats::queriesInvalid("QueriesInvalid", "Qiv");
+Statistic stats::queriesValid("QueriesValid", "Qv");
+Statistic stats::queryCacheHits("QueryCacheHits", "QChits") ;
+Statistic stats::queryCacheMisses("QueryCacheMisses", "QCmisses");
+Statistic stats::queryConstructTime("QueryConstructTime", "QBtime") ;
+Statistic stats::queryConstructs("QueriesConstructs", "QB");
+Statistic stats::queryCounterexamples("QueriesCEX", "Qcex");
+Statistic stats::queryTime("QueryTime", "Qtime");
Added: klee/trunk/lib/Solver/SolverStats.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Solver/SolverStats.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Solver/SolverStats.h (added)
+++ klee/trunk/lib/Solver/SolverStats.h Wed May 20 23:36:41 2009
@@ -0,0 +1,32 @@
+//===-- SolverStats.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_SOLVERSTATS_H
+#define KLEE_SOLVERSTATS_H
+
+#include "klee/Statistic.h"
+
+namespace klee {
+namespace stats {
+
+ extern Statistic cexCacheTime;
+ extern Statistic queries;
+ extern Statistic queriesInvalid;
+ extern Statistic queriesValid;
+ extern Statistic queryCacheHits;
+ extern Statistic queryCacheMisses;
+ extern Statistic queryConstructTime;
+ extern Statistic queryConstructs;
+ extern Statistic queryCounterexamples;
+ extern Statistic queryTime;
+
+}
+}
+
+#endif
Added: klee/trunk/lib/Support/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/Makefile (added)
+++ klee/trunk/lib/Support/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+#===-- lib/Support/Makefile --------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleeSupport
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+
+include $(LEVEL)/Makefile.common
Added: klee/trunk/lib/Support/README.txt
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/README.txt?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/README.txt (added)
+++ klee/trunk/lib/Support/README.txt Wed May 20 23:36:41 2009
@@ -0,0 +1,2 @@
+This directory holds basic support facilities (data structures,
+utilities, etc.) used by klee.
Added: klee/trunk/lib/Support/RNG.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/RNG.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/RNG.cpp (added)
+++ klee/trunk/lib/Support/RNG.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,146 @@
+/*
+ A C-program for MT19937, with initialization improved 2002/1/26.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+ Modified to be a C++ class by Daniel Dunbar.
+
+ Before using, initialize the state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include "klee/Internal/ADT/RNG.h"
+
+using namespace klee;
+
+/* initializes mt[N] with a seed */
+RNG::RNG(unsigned int s) {
+ seed(s);
+}
+
+void RNG::seed(unsigned int s) {
+ mt[0]= s & 0xffffffffUL;
+ for (mti=1; mti<N; mti++) {
+ mt[mti] =
+ (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array mt[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ mt[mti] &= 0xffffffffUL;
+ /* for >32 bit machines */
+ }
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned int RNG::getInt32() {
+ unsigned int y;
+ static unsigned int mag01[2]={0x0UL, MATRIX_A};
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (mti >= N) { /* generate N words at one time */
+ int kk;
+
+ for (kk=0;kk<N-M;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ for (;kk<N-1;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+ mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return y;
+}
+
+/* generates a random number on [0,0x7fffffff]-interval */
+int RNG::getInt31() {
+ return (int)(getInt32()>>1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double RNG::getDoubleLR() {
+ return getInt32()*(1.0/4294967295.0);
+ /* divided by 2^32-1 */
+}
+
+/* generates a random number on [0,1)-real-interval */
+double RNG::getDoubleL() {
+ return getInt32()*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/* generates a random number on (0,1)-real-interval */
+double RNG::getDouble() {
+ return (((double)getInt32()) + 0.5)*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+float RNG::getFloatLR() {
+ return getInt32()*(1.0f/4294967295.0f);
+ /* divided by 2^32-1 */
+}
+float RNG::getFloatL() {
+ return getInt32()*(1.0f/4294967296.0f);
+ /* divided by 2^32 */
+}
+float RNG::getFloat() {
+ return (getInt32() + 0.5f)*(1.0f/4294967296.0f);
+ /* divided by 2^32 */
+}
+
+bool RNG::getBool() {
+ unsigned bits = getInt32();
+ bits ^= bits >> 16;
+ bits ^= bits >> 8;
+ bits ^= bits >> 4;
+ bits ^= bits >> 2;
+ bits ^= bits >> 1;
+ return bits&1;
+}
Added: klee/trunk/lib/Support/Time.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/Time.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/Time.cpp (added)
+++ klee/trunk/lib/Support/Time.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,27 @@
+//===-- Time.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/Internal/System/Time.h"
+
+#include "llvm/System/Process.h"
+
+using namespace llvm;
+using namespace klee;
+
+double util::getUserTime() {
+ sys::TimeValue now(0,0),user(0,0),sys(0,0);
+ sys::Process::GetTimeUsage(now,user,sys);
+ return (user.seconds() + (double) user.nanoseconds() * 1e-9);
+}
+
+double util::getWallTime() {
+ sys::TimeValue now(0,0),user(0,0),sys(0,0);
+ sys::Process::GetTimeUsage(now,user,sys);
+ return (now.seconds() + (double) now.nanoseconds() * 1e-9);
+}
Added: klee/trunk/lib/Support/Timer.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/Timer.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/Timer.cpp (added)
+++ klee/trunk/lib/Support/Timer.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,27 @@
+//===-- Timer.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/Internal/Support/Timer.h"
+
+#include "llvm/System/Process.h"
+
+using namespace klee;
+using namespace llvm;
+
+WallTimer::WallTimer() {
+ sys::TimeValue now(0,0),user(0,0),sys(0,0);
+ sys::Process::GetTimeUsage(now,user,sys);
+ startMicroseconds = now.usec();
+}
+
+uint64_t WallTimer::check() {
+ sys::TimeValue now(0,0),user(0,0),sys(0,0);
+ sys::Process::GetTimeUsage(now,user,sys);
+ return now.usec() - startMicroseconds;
+}
Added: klee/trunk/lib/Support/TreeStream.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/lib/Support/TreeStream.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/lib/Support/TreeStream.cpp (added)
+++ klee/trunk/lib/Support/TreeStream.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,201 @@
+//===-- TreeStream.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/Internal/ADT/TreeStream.h"
+
+#include <cassert>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <iterator>
+#include <map>
+
+#include <string.h>
+
+using namespace klee;
+
+///
+
+TreeStreamWriter::TreeStreamWriter(const std::string &_path)
+ : lastID(0),
+ bufferCount(0),
+ path(_path),
+ output(new std::ofstream(path.c_str(),
+ std::ios::out | std::ios::binary)),
+ ids(1) {
+ if (!output->good()) {
+ delete output;
+ output = 0;
+ }
+}
+
+TreeStreamWriter::~TreeStreamWriter() {
+ flush();
+ if (output)
+ delete output;
+}
+
+bool TreeStreamWriter::good() {
+ return !!output;
+}
+
+TreeOStream TreeStreamWriter::open() {
+ return open(TreeOStream(*this, 0));
+}
+
+TreeOStream TreeStreamWriter::open(const TreeOStream &os) {
+ assert(output && os.writer==this);
+ flushBuffer();
+ unsigned id = ids++;
+ output->write(reinterpret_cast<const char*>(&os.id), 4);
+ unsigned tag = id | (1<<31);
+ output->write(reinterpret_cast<const char*>(&tag), 4);
+ return TreeOStream(*this, id);
+}
+
+void TreeStreamWriter::write(TreeOStream &os, const char *s, unsigned size) {
+#if 1
+ if (bufferCount &&
+ (os.id!=lastID || size+bufferCount>bufferSize))
+ flushBuffer();
+ if (bufferCount) { // (os.id==lastID && size+bufferCount<=bufferSize)
+ memcpy(&buffer[bufferCount], s, size);
+ bufferCount += size;
+ } else if (size<bufferSize) {
+ lastID = os.id;
+ memcpy(buffer, s, size);
+ bufferCount = size;
+ } else {
+ output->write(reinterpret_cast<const char*>(&os.id), 4);
+ output->write(reinterpret_cast<const char*>(&size), 4);
+ output->write(buffer, size);
+ }
+#else
+ output->write(reinterpret_cast<const char*>(&os.id), 4);
+ output->write(reinterpret_cast<const char*>(&size), 4);
+ output->write(s, size);
+#endif
+}
+
+void TreeStreamWriter::flushBuffer() {
+ if (bufferCount) {
+ output->write(reinterpret_cast<const char*>(&lastID), 4);
+ output->write(reinterpret_cast<const char*>(&bufferCount), 4);
+ output->write(buffer, bufferCount);
+ bufferCount = 0;
+ }
+}
+
+void TreeStreamWriter::flush() {
+ flushBuffer();
+ output->flush();
+}
+
+void TreeStreamWriter::readStream(TreeStreamID streamID,
+ std::vector<unsigned char> &out) {
+ assert(streamID>0 && streamID<ids);
+ flush();
+
+ std::ifstream is(path.c_str(),
+ std::ios::in | std::ios::binary);
+ assert(is.good());
+#if 0
+ std::cout << "finding chain for: " << streamID << "\n";
+#endif
+
+ std::map<unsigned,unsigned> parents;
+ std::vector<unsigned> roots;
+ for (;;) {
+ assert(is.good());
+ unsigned id;
+ unsigned tag;
+ is.read(reinterpret_cast<char*>(&id), 4);
+ is.read(reinterpret_cast<char*>(&tag), 4);
+ if (tag&(1<<31)) { // fork
+ unsigned child = tag ^ (1<<31);
+
+ if (child==streamID) {
+ roots.push_back(child);
+ while (id) {
+ roots.push_back(id);
+ std::map<unsigned, unsigned>::iterator it = parents.find(id);
+ assert(it!=parents.end());
+ id = it->second;
+ }
+ break;
+ } else {
+ parents.insert(std::make_pair(child,id));
+ }
+ } else {
+ unsigned size = tag;
+ while (size--) is.get();
+ }
+ }
+#if 0
+ std::cout << "roots: ";
+ std::copy(roots.begin(), roots.end(), std::ostream_iterator<unsigned>(std::cout, " "));
+ std::cout << "\n";
+#endif
+ is.seekg(0, std::ios::beg);
+ for (;;) {
+ unsigned id;
+ unsigned tag;
+ is.read(reinterpret_cast<char*>(&id), 4);
+ is.read(reinterpret_cast<char*>(&tag), 4);
+ if (!is.good()) break;
+ if (tag&(1<<31)) { // fork
+ unsigned child = tag ^ (1<<31);
+ if (id==roots.back() && roots.size()>1 && child==roots[roots.size()-2])
+ roots.pop_back();
+ } else {
+ unsigned size = tag;
+ if (id==roots.back()) {
+ while (size--) out.push_back(is.get());
+ } else {
+ while (size--) is.get();
+ }
+ }
+ }
+}
+
+///
+
+TreeOStream::TreeOStream()
+ : writer(0),
+ id(0) {
+}
+
+TreeOStream::TreeOStream(TreeStreamWriter &_writer, unsigned _id)
+ : writer(&_writer),
+ id(_id) {
+}
+
+TreeOStream::~TreeOStream() {
+}
+
+unsigned TreeOStream::getID() const {
+ assert(writer);
+ return id;
+}
+
+void TreeOStream::write(const char *buffer, unsigned size) {
+ assert(writer);
+ writer->write(*this, buffer, size);
+}
+
+TreeOStream &TreeOStream::operator<<(const std::string &s) {
+ assert(writer);
+ write(s.c_str(), s.size());
+ return *this;
+}
+
+void TreeOStream::flush() {
+ assert(writer);
+ writer->flush();
+}
Added: klee/trunk/runtime/Intrinsic/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/Makefile (added)
+++ klee/trunk/runtime/Intrinsic/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,20 @@
+#===-- runtime/Intrinsic/Makefile --------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=intrinsic
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+BYTECODE_LIBRARY=1
+# Don't strip debug info from the module.
+DEBUG_RUNTIME=1
+NO_PEDANTIC=1
+
+include $(LEVEL)/Makefile.common
Added: klee/trunk/runtime/Intrinsic/klee_div_zero_check.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/klee_div_zero_check.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/klee_div_zero_check.c (added)
+++ klee/trunk/runtime/Intrinsic/klee_div_zero_check.c Wed May 20 23:36:41 2009
@@ -0,0 +1,15 @@
+//===-- klee_div_zero_check.c ---------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <klee/klee.h>
+
+void klee_div_zero_check(long long z) {
+ if (z == 0)
+ klee_report_error(__FILE__, __LINE__, "divide by zero", "div.err");
+}
Added: klee/trunk/runtime/Intrinsic/klee_int.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/klee_int.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/klee_int.c (added)
+++ klee/trunk/runtime/Intrinsic/klee_int.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- klee_int.c --------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <klee/klee.h>
+
+int klee_int(const char *name) {
+ int x;
+ klee_make_symbolic_name(&x, sizeof x, name);
+ return x;
+}
Added: klee/trunk/runtime/Intrinsic/klee_make_symbolic.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/klee_make_symbolic.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/klee_make_symbolic.c (added)
+++ klee/trunk/runtime/Intrinsic/klee_make_symbolic.c Wed May 20 23:36:41 2009
@@ -0,0 +1,14 @@
+//===-- klee_make_symbolic.c ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <klee/klee.h>
+
+void klee_make_symbolic(void *addr, unsigned nbytes) {
+ klee_make_symbolic_name(addr, nbytes, "unnamed");
+}
Added: klee/trunk/runtime/Intrinsic/klee_range.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/klee_range.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/klee_range.c (added)
+++ klee/trunk/runtime/Intrinsic/klee_range.c Wed May 20 23:36:41 2009
@@ -0,0 +1,33 @@
+//===-- klee_range.c ------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <klee/klee.h>
+
+int klee_range(int start, int end, const char* name) {
+ int x;
+
+ assert(start < end);
+
+ if (start+1==end) {
+ return start;
+ } else {
+ klee_make_symbolic_name(&x, sizeof x, name);
+
+ /* Make nicer constraint when simple... */
+ if (start==0) {
+ klee_assume((unsigned) x < (unsigned) end);
+ } else {
+ klee_assume(start <= x);
+ klee_assume(x < end);
+ }
+
+ return x;
+ }
+}
Added: klee/trunk/runtime/Intrinsic/memcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/memcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/memcpy.c (added)
+++ klee/trunk/runtime/Intrinsic/memcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+//===-- memcpy.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memcpy(void *destaddr, void const *srcaddr, unsigned int len) {
+ char *dest = destaddr;
+ char const *src = srcaddr;
+
+ while (len-- > 0)
+ *dest++ = *src++;
+ return destaddr;
+}
Added: klee/trunk/runtime/Intrinsic/memmove.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/memmove.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/memmove.c (added)
+++ klee/trunk/runtime/Intrinsic/memmove.c Wed May 20 23:36:41 2009
@@ -0,0 +1,28 @@
+//===-- memmove.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memmove(void *dst, const void *src, size_t count) {
+ char *a = dst;
+ const char *b = src;
+
+ if (src == dst)
+ return dst;
+
+ if (src>dst) {
+ while (count--) *a++ = *b++;
+ } else {
+ a+=count-1;
+ b+=count-1;
+ while (count--) *a-- = *b--;
+ }
+
+ return dst;
+}
Added: klee/trunk/runtime/Intrinsic/mempcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/mempcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/mempcpy.c (added)
+++ klee/trunk/runtime/Intrinsic/mempcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+//===-- mempcpy.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *mempcpy(void *destaddr, void const *srcaddr, unsigned int len) {
+ char *dest = destaddr;
+ char const *src = srcaddr;
+
+ while (len-- > 0)
+ *dest++ = *src++;
+ return dest;
+}
Added: klee/trunk/runtime/Intrinsic/memset.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Intrinsic/memset.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Intrinsic/memset.c (added)
+++ klee/trunk/runtime/Intrinsic/memset.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- memset.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memset(void * dst, int s, size_t count) {
+ char * a = dst;
+ while (count-- > 0)
+ *a++ = s;
+ return dst;
+}
Added: klee/trunk/runtime/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Makefile (added)
+++ klee/trunk/runtime/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,26 @@
+#===-- runtime/Makefile ------------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+#
+# Relative path to the top of the source tree.
+#
+LEVEL=..
+
+#
+# List all of the subdirectories that we will compile.
+#
+PARALLEL_DIRS=Intrinsic klee-libc Runtest
+
+include $(LEVEL)/Makefile.config
+
+ifeq ($(ENABLE_POSIX_RUNTIME),1)
+PARALLEL_DIRS += POSIX
+endif
+
+include $(LEVEL)/Makefile.common
Propchange: klee/trunk/runtime/Makefile
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/runtime/POSIX/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/Makefile (added)
+++ klee/trunk/runtime/POSIX/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,20 @@
+#===-- runtime/POSIX/Makefile ------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleeRuntimePOSIX
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+BYTECODE_LIBRARY=1
+# Don't strip debug info from the module.
+DEBUG_RUNTIME=1
+NO_PEDANTIC=1
+
+include $(LEVEL)/Makefile.common
Added: klee/trunk/runtime/POSIX/fd.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/fd.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/fd.c (added)
+++ klee/trunk/runtime/POSIX/fd.c Wed May 20 23:36:41 2009
@@ -0,0 +1,1287 @@
+//===-- fd.c --------------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LARGEFILE64_SOURCE
+#include "fd.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <termios.h>
+#include <sys/select.h>
+#include <klee/klee.h>
+
+/* #define DEBUG */
+
+void klee_warning(const char*);
+void klee_warning_once(const char*);
+int klee_get_errno(void);
+
+/* Returns pointer to the symbolic file structure is the pathname is symbolic */
+static exe_disk_file_t *__get_sym_file(const char *pathname) {
+ char c = pathname[0];
+ unsigned i;
+
+ if (c == 0 || pathname[1] != 0)
+ return NULL;
+
+ for (i=0; i<__exe_fs.n_sym_files; ++i) {
+ if (c == 'A' + (char) i) {
+ exe_disk_file_t *df = &__exe_fs.sym_files[i];
+ if (df->stat->st_ino == 0)
+ return NULL;
+ return df;
+ }
+ }
+
+ return NULL;
+}
+
+static void *__concretize_ptr(const void *p);
+static size_t __concretize_size(size_t s);
+static const char *__concretize_string(const char *s);
+
+/* Returns pointer to the file entry for a valid fd */
+static exe_file_t *__get_file(int fd) {
+ if (fd>=0 && fd<MAX_FDS) {
+ exe_file_t *f = &__exe_env.fds[fd];
+ if (f->flags & eOpen)
+ return f;
+ }
+
+ return 0;
+}
+
+int access(const char *pathname, int mode) {
+ exe_disk_file_t *dfile = __get_sym_file(pathname);
+
+ if (dfile) {
+ /* XXX we should check against stat values but we also need to
+ enforce in open and friends then. */
+ return 0;
+ } else {
+ int r = syscall(__NR_access, __concretize_string(pathname), mode);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+mode_t umask(mode_t mask) {
+ mode_t r = __exe_env.umask;
+ __exe_env.umask = mask & 0777;
+ return r;
+}
+
+
+/* Returns 1 if the process has the access rights specified by 'flags'
+ to the file with stat 's'. Returns 0 otherwise*/
+static int has_permission(int flags, struct stat64 *s) {
+ int write_access, read_access;
+ mode_t mode = s->st_mode;
+
+ if (flags & O_RDONLY || flags & O_RDWR)
+ read_access = 1;
+ else read_access = 0;
+
+ if (flags & O_WRONLY || flags & O_RDWR)
+ write_access = 1;
+ else write_access = 0;
+
+ /* XXX: We don't worry about process uid and gid for now.
+ We allow access if any user has access to the file. */
+#if 0
+ uid_t uid = s->st_uid;
+ uid_t euid = geteuid();
+ gid_t gid = s->st_gid;
+ gid_t egid = getegid();
+#endif
+
+ if (read_access && ((mode & S_IRUSR) | (mode & S_IRGRP) | (mode & S_IROTH)))
+ return 0;
+
+ if (write_access && !((mode & S_IWUSR) | (mode & S_IWGRP) | (mode & S_IWOTH)))
+ return 0;
+
+ return 1;
+}
+
+
+int __fd_open(const char *pathname, int flags, mode_t mode) {
+ exe_disk_file_t *df;
+ exe_file_t *f;
+ int fd;
+
+ for (fd = 0; fd < MAX_FDS; ++fd)
+ if (!(__exe_env.fds[fd].flags & eOpen))
+ break;
+ if (fd == MAX_FDS) {
+ errno = EMFILE;
+ return -1;
+ }
+
+ f = &__exe_env.fds[fd];
+
+ /* Should be the case if file was available, but just in case. */
+ memset(f, 0, sizeof *f);
+
+ df = __get_sym_file(pathname);
+ if (df) {
+ /* XXX Should check access against mode / stat / possible
+ deletion. */
+ f->dfile = df;
+
+ if ((flags & O_CREAT) && (flags & O_EXCL)) {
+ errno = EEXIST;
+ return -1;
+ }
+
+ if ((flags & O_TRUNC) && (flags & O_RDONLY)) {
+ /* The result of using O_TRUNC with O_RDONLY is undefined, so we
+ return error */
+ fprintf(stderr, "Undefined call to open(): O_TRUNC | O_RDONLY\n");
+ errno = EACCES;
+ return -1;
+ }
+
+ if ((flags & O_EXCL) && !(flags & O_CREAT)) {
+ /* The result of using O_EXCL without O_CREAT is undefined, so
+ we return error */
+ fprintf(stderr, "Undefined call to open(): O_EXCL w/o O_RDONLY\n");
+ errno = EACCES;
+ return -1;
+ }
+
+ if (!has_permission(flags, df->stat)) {
+ errno = EACCES;
+ return -1;
+ }
+ else
+ f->dfile->stat->st_mode = ((f->dfile->stat->st_mode & ~0777) |
+ (mode & ~__exe_env.umask));
+ } else {
+ int os_fd = syscall(__NR_open, __concretize_string(pathname), flags, mode);
+ if (os_fd == -1) {
+ errno = klee_get_errno();
+ return -1;
+ }
+ f->fd = os_fd;
+ }
+
+ f->flags = eOpen;
+ if ((flags & O_ACCMODE) == O_RDONLY) {
+ f->flags |= eReadable;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ f->flags |= eWriteable;
+ } else { /* XXX What actually happens here if != O_RDWR. */
+ f->flags |= eReadable | eWriteable;
+ }
+
+ return fd;
+}
+
+int close(int fd) {
+ static int n_calls = 0;
+ exe_file_t *f;
+ int r = 0;
+
+ n_calls++;
+
+ f = __get_file(fd);
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (__exe_fs.max_failures && *__exe_fs.close_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+#if 0
+ if (!f->dfile) {
+ /* if a concrete fd */
+ r = syscall(__NR_close, f->fd);
+ }
+ else r = 0;
+#endif
+
+ memset(f, 0, sizeof *f);
+
+ return r;
+}
+
+ssize_t read(int fd, void *buf, size_t count) {
+ static int n_calls = 0;
+ exe_file_t *f;
+
+ n_calls++;
+
+ if (count == 0)
+ return 0;
+
+ if (buf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (__exe_fs.max_failures && *__exe_fs.read_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+ if (!f->dfile) {
+ /* concrete file */
+ int r;
+ buf = __concretize_ptr(buf);
+ count = __concretize_size(count);
+ /* XXX In terms of looking for bugs we really should do this check
+ before concretization, at least once the routine has been fixed
+ to properly work with symbolics. */
+ klee_check_memory_access(buf, count);
+ if (f->fd == 0)
+ r = syscall(__NR_read, f->fd, buf, count);
+ else
+ r = syscall(__NR_pread64, f->fd, buf, count, (off64_t) f->off);
+
+ if (r == -1) {
+ errno = klee_get_errno();
+ return -1;
+ }
+
+ if (f->fd != 0)
+ f->off += r;
+ return r;
+ }
+ else {
+ assert(f->off >= 0);
+ if (f->dfile->size < f->off)
+ return 0;
+
+ /* symbolic file */
+ if (f->off + count > f->dfile->size) {
+ count = f->dfile->size - f->off;
+ }
+
+ memcpy(buf, f->dfile->contents + f->off, count);
+ f->off += count;
+
+ return count;
+ }
+}
+
+
+ssize_t write(int fd, const void *buf, size_t count) {
+ static int n_calls = 0;
+ exe_file_t *f;
+
+ n_calls++;
+
+ f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (__exe_fs.max_failures && *__exe_fs.write_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+ if (!f->dfile) {
+ int r;
+
+ buf = __concretize_ptr(buf);
+ count = __concretize_size(count);
+ /* XXX In terms of looking for bugs we really should do this check
+ before concretization, at least once the routine has been fixed
+ to properly work with symbolics. */
+ klee_check_memory_access(buf, count);
+ if (f->fd == 1 || f->fd == 2)
+ r = syscall(__NR_write, f->fd, buf, count);
+ else r = syscall(__NR_pwrite64, f->fd, buf, count, (off64_t) f->off);
+
+ if (r == -1) {
+ errno = klee_get_errno();
+ return -1;
+ }
+
+ assert(r >= 0);
+ if (f->fd != 1 && f->fd != 2)
+ f->off += r;
+
+ return r;
+ }
+ else {
+ /* symbolic file */
+ size_t actual_count = 0;
+ if (f->off + count <= f->dfile->size)
+ actual_count = count;
+ else {
+ if (__exe_env.save_all_writes)
+ assert(0);
+ else {
+ if (f->off < f->dfile->size)
+ actual_count = f->dfile->size - f->off;
+ }
+ }
+
+ if (actual_count)
+ memcpy(f->dfile->contents + f->off, buf, actual_count);
+
+ if (count != actual_count)
+ fprintf(stderr, "WARNING: write() ignores bytes.\n");
+
+ if (f->dfile == __exe_fs.sym_stdout)
+ __exe_fs.stdout_writes += actual_count;
+
+ f->off += count;
+ return count;
+ }
+}
+
+
+off64_t __fd_lseek(int fd, off64_t offset, int whence) {
+ off64_t new_off;
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (!f->dfile) {
+ /* We could always do SEEK_SET then whence, but this causes
+ troubles with directories since we play nasty tricks with the
+ offset, and the OS doesn't want us to randomly seek
+ directories. We could detect if it is a directory and correct
+ the offset, but really directories should only be SEEK_SET, so
+ this solves the problem. */
+ if (whence == SEEK_SET) {
+ new_off = syscall(__NR_lseek, f->fd, (int) offset, SEEK_SET);
+ } else {
+ new_off = syscall(__NR_lseek, f->fd, (int) f->off, SEEK_SET);
+
+ /* If we can't seek to start off, just return same error.
+ Probably ESPIPE. */
+ if (new_off != -1) {
+ assert(new_off == f->off);
+ new_off = syscall(__NR_lseek, f->fd, (int) offset, whence);
+ }
+ }
+
+ if (new_off == -1) {
+ errno = klee_get_errno();
+ return -1;
+ }
+
+ f->off = new_off;
+ return new_off;
+ }
+
+ switch (whence) {
+ case SEEK_SET: new_off = offset; break;
+ case SEEK_CUR: new_off = f->off + offset; break;
+ case SEEK_END: new_off = f->dfile->size + offset; break;
+ default: {
+ errno = EINVAL;
+ return (off64_t) -1;
+ }
+ }
+
+ if (new_off < 0) {
+ errno = EINVAL;
+ return (off64_t) -1;
+ }
+
+ f->off = new_off;
+ return f->off;
+}
+
+int __fd_stat(const char *path, struct stat64 *buf) {
+ exe_disk_file_t *dfile = __get_sym_file(path);
+ if (dfile) {
+ memcpy(buf, dfile->stat, sizeof(*dfile->stat));
+ return 0;
+ }
+
+ {
+ int r = syscall(__NR_stat64, __concretize_string(path), buf);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int __fd_lstat(const char *path, struct stat64 *buf) {
+ exe_disk_file_t *dfile = __get_sym_file(path);
+ if (dfile) {
+ memcpy(buf, dfile->stat, sizeof(*dfile->stat));
+ return 0;
+ }
+
+ {
+ int r = syscall(__NR_lstat64, __concretize_string(path), buf);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int chdir(const char *path) {
+ exe_disk_file_t *dfile = __get_sym_file(path);
+
+ if (dfile) {
+ /* XXX incorrect */
+ klee_warning("symbolic file, ignoring (ENOENT)");
+ errno = ENOENT;
+ return -1;
+ }
+
+ {
+ int r = syscall(__NR_chdir, __concretize_string(path));
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fchdir(int fd) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (f->dfile) {
+ klee_warning("symbolic file, ignoring (ENOENT)");
+ errno = ENOENT;
+ return -1;
+ } else {
+ int r = syscall(__NR_fchdir, f->fd);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+/* Sets mode and or errno and return appropriate result. */
+static int __df_chmod(exe_disk_file_t *df, mode_t mode) {
+ if (geteuid() == df->stat->st_uid) {
+ if (getgid() != df->stat->st_gid)
+ mode &= ~ S_ISGID;
+ df->stat->st_mode = ((df->stat->st_mode & ~07777) |
+ (mode & 07777));
+ return 0;
+ } else {
+ errno = EPERM;
+ return -1;
+ }
+}
+
+int chmod(const char *path, mode_t mode) {
+ static int n_calls = 0;
+
+ exe_disk_file_t *dfile = __get_sym_file(path);
+
+ n_calls++;
+ if (__exe_fs.max_failures && *__exe_fs.chmod_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+ if (dfile) {
+ return __df_chmod(dfile, mode);
+ } else {
+ int r = syscall(__NR_chmod, __concretize_string(path), mode);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fchmod(int fd, mode_t mode) {
+ static int n_calls = 0;
+
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ n_calls++;
+ if (__exe_fs.max_failures && *__exe_fs.fchmod_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+ if (f->dfile) {
+ return __df_chmod(f->dfile, mode);
+ } else {
+ int r = syscall(__NR_fchmod, f->fd, mode);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+static int __df_chown(exe_disk_file_t *df, uid_t owner, gid_t group) {
+ klee_warning("symbolic file, ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int chown(const char *path, uid_t owner, gid_t group) {
+ exe_disk_file_t *df = __get_sym_file(path);
+
+ if (df) {
+ return __df_chown(df, owner, group);
+ } else {
+ int r = syscall(__NR_chown, __concretize_string(path), owner, group);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fchown(int fd, uid_t owner, gid_t group) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (f->dfile) {
+ return __df_chown(f->dfile, owner, group);
+ } else {
+ int r = syscall(__NR_fchown, fd, owner, group);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int lchown(const char *path, uid_t owner, gid_t group) {
+ /* XXX Ignores 'l' part */
+ exe_disk_file_t *df = __get_sym_file(path);
+
+ if (df) {
+ return __df_chown(df, owner, group);
+ } else {
+ int r = syscall(__NR_chown, __concretize_string(path), owner, group);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int __fd_fstat(int fd, struct stat64 *buf) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (!f->dfile) {
+ int r = syscall(__NR_fstat64, f->fd, buf);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+
+ memcpy(buf, f->dfile->stat, sizeof(*f->dfile->stat));
+ return 0;
+}
+
+int __fd_ftruncate(int fd, off64_t length) {
+ static int n_calls = 0;
+ exe_file_t *f = __get_file(fd);
+
+ n_calls++;
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (__exe_fs.max_failures && *__exe_fs.ftruncate_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = EIO;
+ return -1;
+ }
+
+ if (f->dfile) {
+ klee_warning("symbolic file, ignoring (EIO)");
+ errno = EIO;
+ return -1;
+ } else {
+ int r = syscall(__NR_ftruncate64, f->fd, length);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int __fd_getdents(unsigned int fd, struct dirent64 *dirp, unsigned int count) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (f->dfile) {
+ klee_warning("symbolic file, ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+ } else {
+ if ((unsigned) f->off < 4096u) {
+ /* Return our dirents */
+ unsigned i, pad, bytes=0;
+
+ /* What happens for bad offsets? */
+ i = f->off / sizeof(*dirp);
+ if ((i * sizeof(*dirp) != f->off) ||
+ i > __exe_fs.n_sym_files) {
+ errno = EINVAL;
+ return -1;
+ }
+ for (; i<__exe_fs.n_sym_files; ++i) {
+ exe_disk_file_t *df = &__exe_fs.sym_files[i];
+ dirp->d_ino = df->stat->st_ino;
+ dirp->d_reclen = sizeof(*dirp);
+ dirp->d_type = IFTODT(df->stat->st_mode);
+ dirp->d_name[0] = 'A' + i;
+ dirp->d_name[1] = '\0';
+ dirp->d_off = (i+1) * sizeof(*dirp);
+ bytes += dirp->d_reclen;
+ ++dirp;
+ }
+
+ /* Fake jump to OS records by a "deleted" file. */
+ pad = count>=4096 ? 4096 : count;
+ dirp->d_ino = 0;
+ dirp->d_reclen = pad - bytes;
+ dirp->d_type = DT_UNKNOWN;
+ dirp->d_name[0] = '\0';
+ dirp->d_off = 4096;
+ bytes += dirp->d_reclen;
+ f->off = pad;
+ return bytes;
+ } else {
+ unsigned os_pos = f->off - 4096;
+ int res, s;
+
+ /* For reasons which I really don't understand, if I don't
+ memset this then sometimes the kernel returns d_ino==0 for
+ some valid entries? Am I crazy? Can writeback possibly be
+ failing?
+
+ Even more bizarre, interchanging the memset and the seek also
+ case strange behavior. Really should be debugged properly. */
+ memset(dirp, 0, count);
+ s = syscall(__NR_lseek, f->fd, (int) os_pos, SEEK_SET);
+ assert(s != (off64_t) -1);
+ res = syscall(__NR_getdents64, f->fd, dirp, count);
+ if (res == -1) {
+ errno = klee_get_errno();
+ } else {
+ int pos = 0;
+
+ f->off = syscall(__NR_lseek, f->fd, 0, SEEK_CUR) + 4096;
+
+ /* Patch offsets */
+
+ while (pos < res) {
+ struct dirent64 *dp = (struct dirent64*) ((char*) dirp + pos);
+ dp->d_off += 4096;
+ pos += dp->d_reclen;
+ }
+ }
+ return res;
+ }
+ }
+}
+
+int ioctl(int fd, unsigned long request, ...) {
+ exe_file_t *f = __get_file(fd);
+ va_list ap;
+ void *buf;
+
+#if 0
+ printf("In ioctl(%d, ...)\n", fd);
+#endif
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ va_start(ap, request);
+ buf = va_arg(ap, void*);
+ va_end(ap);
+
+ if (f->dfile) {
+ struct stat *stat = (struct stat*) f->dfile->stat;
+
+ switch (request) {
+ case TCGETS: {
+ struct termios *ts = buf;
+
+ klee_warning_once("(TCGETS) symbolic file, incomplete model");
+
+ /* XXX need more data, this is ok but still not good enough */
+ if (S_ISCHR(stat->st_mode)) {
+ /* Just copied from my system, munged to match what fields
+ uclibc thinks are there. */
+ ts->c_iflag = 27906;
+ ts->c_oflag = 5;
+ ts->c_cflag = 1215;
+ ts->c_lflag = 35287;
+ ts->c_line = 0;
+ ts->c_cc[0] = '\x03';
+ ts->c_cc[1] = '\x1c';
+ ts->c_cc[2] = '\x7f';
+ ts->c_cc[3] = '\x15';
+ ts->c_cc[4] = '\x04';
+ ts->c_cc[5] = '\x00';
+ ts->c_cc[6] = '\x01';
+ ts->c_cc[7] = '\xff';
+ ts->c_cc[8] = '\x11';
+ ts->c_cc[9] = '\x13';
+ ts->c_cc[10] = '\x1a';
+ ts->c_cc[11] = '\xff';
+ ts->c_cc[12] = '\x12';
+ ts->c_cc[13] = '\x0f';
+ ts->c_cc[14] = '\x17';
+ ts->c_cc[15] = '\x16';
+ ts->c_cc[16] = '\xff';
+ ts->c_cc[17] = '\x0';
+ ts->c_cc[18] = '\x0';
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case TCSETS: {
+ /* const struct termios *ts = buf; */
+ klee_warning_once("(TCSETS) symbolic file, silently ignoring");
+ if (S_ISCHR(stat->st_mode)) {
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case TCSETSW: {
+ /* const struct termios *ts = buf; */
+ klee_warning_once("(TCSETSW) symbolic file, silently ignoring");
+ if (fd==0) {
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case TCSETSF: {
+ /* const struct termios *ts = buf; */
+ klee_warning_once("(TCSETSF) symbolic file, silently ignoring");
+ if (S_ISCHR(stat->st_mode)) {
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case TIOCGWINSZ: {
+ struct winsize *ws = buf;
+ ws->ws_row = 24;
+ ws->ws_col = 80;
+ klee_warning_once("(TIOCGWINSZ) symbolic file, incomplete model");
+ if (S_ISCHR(stat->st_mode)) {
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case TIOCSWINSZ: {
+ /* const struct winsize *ws = buf; */
+ klee_warning_once("(TIOCSWINSZ) symbolic file, ignoring (EINVAL)");
+ if (S_ISCHR(stat->st_mode)) {
+ errno = EINVAL;
+ return -1;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case FIONREAD: {
+ int *res = buf;
+ klee_warning_once("(FIONREAD) symbolic file, incomplete model");
+ if (S_ISCHR(stat->st_mode)) {
+ if (f->off < f->dfile->size) {
+ *res = f->dfile->size - f->off;
+ } else {
+ *res = 0;
+ }
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ case MTIOCGET: {
+ klee_warning("(MTIOCGET) symbolic file, ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+ }
+ default:
+ klee_warning("symbolic file, ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ int r = syscall(__NR_ioctl, f->fd, request, buf );
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fcntl(int fd, int cmd, ...) {
+ exe_file_t *f = __get_file(fd);
+ va_list ap;
+ unsigned arg; /* 32 bit assumption (int/ptr) */
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (cmd==F_GETFD || cmd==F_GETFL || cmd==F_GETOWN || cmd==F_GETSIG ||
+ cmd==F_GETLEASE || cmd==F_NOTIFY) {
+ arg = 0;
+ } else {
+ va_start(ap, cmd);
+ arg = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ if (f->dfile) {
+ switch(cmd) {
+ case F_GETFD: {
+ int flags = 0;
+ if (f->flags & eCloseOnExec)
+ flags |= FD_CLOEXEC;
+ return flags;
+ }
+ case F_SETFD: {
+ f->flags &= ~eCloseOnExec;
+ if (arg & FD_CLOEXEC)
+ f->flags |= eCloseOnExec;
+ return 0;
+ }
+ case F_GETFL: {
+ /* XXX (CrC): This should return the status flags: O_APPEND,
+ O_ASYNC, O_DIRECT, O_NOATIME, O_NONBLOCK. As of now, we
+ discard these flags during open(). We should save them and
+ return them here. These same flags can be set by F_SETFL,
+ which we could also handle properly.
+ */
+ return 0;
+ }
+ default:
+ klee_warning("symbolic file, ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ int r = syscall(__NR_fcntl, f->fd, cmd, arg );
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int __fd_statfs(const char *path, struct statfs *buf) {
+ exe_disk_file_t *dfile = __get_sym_file(path);
+ if (dfile) {
+ /* XXX incorrect */
+ klee_warning("symbolic file, ignoring (ENOENT)");
+ errno = ENOENT;
+ return -1;
+ }
+
+ {
+ int r = syscall(__NR_statfs, __concretize_string(path), buf);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fstatfs(int fd, struct statfs *buf) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (f->dfile) {
+ klee_warning("symbolic file, ignoring (EBADF)");
+ errno = EBADF;
+ return -1;
+ } else {
+ int r = syscall(__NR_fstatfs, f->fd, buf);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int fsync(int fd) {
+ exe_file_t *f = __get_file(fd);
+
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ } else if (f->dfile) {
+ return 0;
+ } else {
+ int r = syscall(__NR_fsync, f->fd);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+int dup2(int oldfd, int newfd) {
+ exe_file_t *f = __get_file(oldfd);
+
+ if (!f || !(newfd>=0 && newfd<MAX_FDS)) {
+ errno = EBADF;
+ return -1;
+ } else {
+ exe_file_t *f2 = &__exe_env.fds[newfd];
+ if (f2->flags & eOpen) close(newfd);
+
+ /* XXX Incorrect, really we need another data structure for open
+ files */
+ *f2 = *f;
+
+ f2->flags &= ~eCloseOnExec;
+
+ /* I'm not sure it is wise, but we can get away with not dup'ng
+ the OS fd, since actually that will in many cases effect the
+ sharing of the open file (and the process should never have
+ access to it). */
+
+ return newfd;
+ }
+}
+
+int dup(int oldfd) {
+ exe_file_t *f = __get_file(oldfd);
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ } else {
+ int fd;
+ for (fd = 0; fd < MAX_FDS; ++fd)
+ if (!(__exe_env.fds[fd].flags & eOpen))
+ break;
+ if (fd == MAX_FDS) {
+ errno = EMFILE;
+ return -1;
+ } else {
+ return dup2(oldfd, fd);
+ }
+ }
+}
+
+int rmdir(const char *pathname) {
+ exe_disk_file_t *dfile = __get_sym_file(pathname);
+ if (dfile) {
+ /* XXX check access */
+ if (S_ISDIR(dfile->stat->st_mode)) {
+ dfile->stat->st_ino = 0;
+ return 0;
+ } else {
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int unlink(const char *pathname) {
+ exe_disk_file_t *dfile = __get_sym_file(pathname);
+ if (dfile) {
+ /* XXX check access */
+ if (S_ISREG(dfile->stat->st_mode)) {
+ dfile->stat->st_ino = 0;
+ return 0;
+ } else if (S_ISDIR(dfile->stat->st_mode)) {
+ errno = EISDIR;
+ return -1;
+ } else {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+ssize_t readlink(const char *path, char *buf, size_t bufsize) {
+ exe_disk_file_t *dfile = __get_sym_file(path);
+ if (dfile) {
+ /* XXX We need to get the sym file name really, but since we don't
+ handle paths anyway... */
+ if (S_ISLNK(dfile->stat->st_mode)) {
+ buf[0] = path[0];
+ if (bufsize>1) buf[1] = '.';
+ if (bufsize>2) buf[2] = 'l';
+ if (bufsize>3) buf[3] = 'n';
+ if (bufsize>4) buf[4] = 'k';
+ return (bufsize>5) ? 5 : bufsize;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ int r = syscall(__NR_readlink, path, buf, bufsize);
+ if (r == -1)
+ errno = klee_get_errno();
+ return r;
+ }
+}
+
+#undef FD_SET
+#undef FD_CLR
+#undef FD_ISSET
+#undef FD_ZERO
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+int select(int nfds, fd_set *read, fd_set *write,
+ fd_set *except, struct timeval *timeout) {
+ fd_set in_read, in_write, in_except, os_read, os_write, os_except;
+ int i, count = 0, os_nfds = 0;
+
+ if (read) {
+ in_read = *read;
+ FD_ZERO(read);
+ } else {
+ FD_ZERO(&in_read);
+ }
+
+ if (write) {
+ in_write = *write;
+ FD_ZERO(write);
+ } else {
+ FD_ZERO(&in_write);
+ }
+
+ if (except) {
+ in_except = *except;
+ FD_ZERO(except);
+ } else {
+ FD_ZERO(&in_except);
+ }
+
+ FD_ZERO(&os_read);
+ FD_ZERO(&os_write);
+ FD_ZERO(&os_except);
+
+ /* Check for symbolic stuff */
+ for (i=0; i<nfds; i++) {
+ if (FD_ISSET(i, &in_read) || FD_ISSET(i, &in_write) || FD_ISSET(i, &in_except)) {
+ exe_file_t *f = __get_file(i);
+ if (!f) {
+ errno = EBADF;
+ return -1;
+ } else if (f->dfile) {
+ /* Operations on this fd will never block... */
+ if (FD_ISSET(i, &in_read)) FD_SET(i, read);
+ if (FD_ISSET(i, &in_write)) FD_SET(i, write);
+ if (FD_ISSET(i, &in_except)) FD_SET(i, except);
+ ++count;
+ } else {
+ if (FD_ISSET(i, &in_read)) FD_SET(f->fd, &os_read);
+ if (FD_ISSET(i, &in_write)) FD_SET(f->fd, &os_write);
+ if (FD_ISSET(i, &in_except)) FD_SET(f->fd, &os_except);
+ if (f->fd >= os_nfds) os_nfds = f->fd + 1;
+ }
+ }
+ }
+
+ if (os_nfds > 0) {
+ /* Never allow blocking select. This is broken but what else can
+ we do. */
+ struct timeval tv = { 0, 0 };
+ int r = syscall(__NR_select, os_nfds,
+ &os_read, &os_write, &os_except, &tv);
+
+ if (r == -1) {
+ /* If no symbolic results, return error. Otherwise we will
+ silently ignore the OS error. */
+ if (!count) {
+ errno = klee_get_errno();
+ return -1;
+ }
+ } else {
+ count += r;
+
+ /* Translate resulting sets back */
+ for (i=0; i<nfds; i++) {
+ exe_file_t *f = __get_file(i);
+ if (f && !f->dfile) {
+ if (read && FD_ISSET(f->fd, &os_read)) FD_SET(i, read);
+ if (write && FD_ISSET(f->fd, &os_write)) FD_SET(i, write);
+ if (except && FD_ISSET(f->fd, &os_except)) FD_SET(i, except);
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+/*** Library functions ***/
+
+char *getcwd(char *buf, size_t size) {
+ static int n_calls = 0;
+ int r;
+
+ n_calls++;
+
+ if (__exe_fs.max_failures && *__exe_fs.getcwd_fail == n_calls) {
+ __exe_fs.max_failures--;
+ errno = ERANGE;
+ return NULL;
+ }
+
+ if (!buf) {
+ if (!size)
+ size = 1024;
+ buf = malloc(size);
+ }
+
+ buf = __concretize_ptr(buf);
+ size = __concretize_size(size);
+ /* XXX In terms of looking for bugs we really should do this check
+ before concretization, at least once the routine has been fixed
+ to properly work with symbolics. */
+ klee_check_memory_access(buf, size);
+ r = syscall(__NR_getcwd, buf, size);
+ if (r == -1) {
+ errno = klee_get_errno();
+ return NULL;
+ }
+
+ return buf;
+}
+
+/*** Helper functions ***/
+
+static void *__concretize_ptr(const void *p) {
+ /* XXX 32-bit assumption */
+ char *pc = (char*) klee_get_value((unsigned) (long) p);
+ klee_assume(pc == p);
+ return pc;
+}
+
+static size_t __concretize_size(size_t s) {
+ size_t sc = klee_get_value(s);
+ klee_assume(sc == s);
+ return sc;
+}
+
+static const char *__concretize_string(const char *s) {
+ char *sc = __concretize_ptr(s);
+ unsigned i;
+
+ for (i=0; ; ++i) {
+ char c = *sc;
+ if (!(i&(i-1))) {
+ if (!c) {
+ *sc++ = 0;
+ break;
+ } else if (c=='/') {
+ *sc++ = '/';
+ }
+ } else {
+ char cc = (char) klee_get_value(c);
+ klee_assume(cc == c);
+ *sc++ = cc;
+ if (!cc) break;
+ }
+ }
+
+ return s;
+}
+
+
+
+/* Trivial model:
+ if path is "/" (basically no change) accept, otherwise reject
+*/
+int chroot(const char *path) {
+ if (path[0] == '\0') {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (path[0] == '/' && path[1] == '\0') {
+ return 0;
+ }
+
+ klee_warning("ignoring (ENOENT)");
+ errno = ENOENT;
+ return -1;
+}
Added: klee/trunk/runtime/POSIX/fd.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/fd.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/fd.h (added)
+++ klee/trunk/runtime/POSIX/fd.h Wed May 20 23:36:41 2009
@@ -0,0 +1,90 @@
+//===-- fd.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 __EXE_FD__
+#define __EXE_FD__
+
+#ifndef _LARGEFILE64_SOURCE
+#error "_LARGEFILE64_SOURCE should be defined"
+#endif
+#include <sys/types.h>
+#include <sys/statfs.h>
+#include <dirent.h>
+
+typedef struct {
+ unsigned size; /* in bytes */
+ char* contents;
+ struct stat64* stat;
+} exe_disk_file_t;
+
+typedef enum {
+ eOpen = (1 << 0),
+ eCloseOnExec = (1 << 1),
+ eReadable = (1 << 2),
+ eWriteable = (1 << 3)
+} exe_file_flag_t;
+
+typedef struct {
+ int fd; /* actual fd if not symbolic */
+ unsigned flags; /* set of exe_file_flag_t values. fields
+ are only defined when flags at least
+ has eOpen. */
+ off64_t off; /* offset */
+ exe_disk_file_t* dfile; /* ptr to file on disk, if symbolic */
+} exe_file_t;
+
+typedef struct {
+ unsigned n_sym_files; /* number of symbolic input files, excluding stdin */
+ exe_disk_file_t *sym_stdin, *sym_stdout;
+ unsigned stdout_writes; /* how many chars were written to stdout */
+ exe_disk_file_t *sym_files;
+ /* --- */
+ /* the maximum number of failures on one path; gets decremented after each failure */
+ unsigned max_failures;
+
+ /* Which read, write etc. call should fail */
+ int *read_fail, *write_fail, *close_fail, *ftruncate_fail, *getcwd_fail;
+ int *chmod_fail, *fchmod_fail;
+} exe_file_system_t;
+
+#define MAX_FDS 32
+
+/* Note, if you change this structure be sure to update the
+ initialization code if necessary. New fields should almost
+ certainly be at the end. */
+typedef struct {
+ exe_file_t fds[MAX_FDS];
+ mode_t umask; /* process umask */
+ unsigned version;
+ /* If set, writes execute as expected. Otherwise, writes extending
+ the file size only change the contents up to the initial
+ size. The file offset is always incremented correctly. */
+ int save_all_writes;
+} exe_sym_env_t;
+
+extern exe_file_system_t __exe_fs;
+extern exe_sym_env_t __exe_env;
+
+void klee_init_fds(unsigned n_files, unsigned file_length,
+ int sym_stdout_flag, int do_all_writes_flag,
+ unsigned max_failures);
+void klee_init_env(int *argcPtr, char ***argvPtr);
+
+/* *** */
+
+int __fd_open(const char *pathname, int flags, mode_t mode);
+off64_t __fd_lseek(int fd, off64_t offset, int whence);
+int __fd_stat(const char *path, struct stat64 *buf);
+int __fd_lstat(const char *path, struct stat64 *buf);
+int __fd_fstat(int fd, struct stat64 *buf);
+int __fd_ftruncate(int fd, off64_t length);
+int __fd_statfs(const char *path, struct statfs *buf);
+int __fd_getdents(unsigned int fd, struct dirent64 *dirp, unsigned int count);
+
+#endif /* __EXE_FD__ */
Added: klee/trunk/runtime/POSIX/fd_32.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/fd_32.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/fd_32.c (added)
+++ klee/trunk/runtime/POSIX/fd_32.c Wed May 20 23:36:41 2009
@@ -0,0 +1,196 @@
+//===-- fd_32.c -----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LARGEFILE64_SOURCE
+#include "fd.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/vfs.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/***/
+
+static void __stat64_to_stat(struct stat64 *a, struct stat *b) {
+ b->st_dev = a->st_dev;
+ b->st_ino = a->st_ino;
+ b->st_mode = a->st_mode;
+ b->st_nlink = a->st_nlink;
+ b->st_uid = a->st_uid;
+ b->st_gid = a->st_gid;
+ b->st_rdev = a->st_rdev;
+ b->st_size = a->st_size;
+ b->st_atime = a->st_atime;
+ b->st_mtime = a->st_mtime;
+ b->st_ctime = a->st_ctime;
+ b->st_blksize = a->st_blksize;
+ b->st_blocks = a->st_blocks;
+}
+
+/***/
+
+int open(const char *pathname, int flags, ...) {
+ mode_t mode = 0;
+
+ if (flags & O_CREAT) {
+ /* get mode */
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ return __fd_open(pathname, flags, mode);
+}
+
+off_t lseek(int fd, off_t off, int whence) {
+ return (off_t) __fd_lseek(fd, off, whence);
+}
+
+int __xstat(int vers, const char *path, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_stat(path, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int stat(const char *path, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_stat(path, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int __lxstat(int vers, const char *path, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_lstat(path, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int lstat(const char *path, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_lstat(path, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int __fxstat(int vers, int fd, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_fstat(fd, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int fstat(int fd, struct stat *buf) {
+ struct stat64 tmp;
+ int res = __fd_fstat(fd, &tmp);
+ __stat64_to_stat(&tmp, buf);
+ return res;
+}
+
+int ftruncate(int fd, off_t length) {
+ return __fd_ftruncate(fd, length);
+}
+
+int statfs(const char *path, struct statfs *buf32) {
+#if 0
+ struct statfs64 buf;
+
+ if (__fd_statfs(path, &buf) < 0)
+ return -1;
+
+ buf32->f_type = buf.f_type;
+ buf32->f_bsize = buf.f_bsize;
+ buf32->f_blocks = buf.f_blocks;
+ buf32->f_bfree = buf.f_bfree;
+ buf32->f_bavail = buf.f_bavail;
+ buf32->f_files = buf.f_files;
+ buf32->f_ffree = buf.f_ffree;
+ buf32->f_fsid = buf.f_fsid;
+ buf32->f_namelen = buf.f_namelen;
+
+ return 0;
+#else
+ return __fd_statfs(path, buf32);
+#endif
+}
+
+/* Based on uclibc version. We use getdents64 and then rewrite the
+ results over themselves, as dirent32s. */
+ssize_t getdents(int fd, struct dirent *dirp, size_t nbytes) {
+ struct dirent64 *dp64 = (struct dirent64*) dirp;
+ ssize_t res = __fd_getdents(fd, dp64, nbytes);
+
+ if (res>0) {
+ struct dirent64 *end = (struct dirent64*) ((char*) dp64 + res);
+ while (dp64 < end) {
+ struct dirent *dp = (struct dirent *) dp64;
+ unsigned name_len = (dp64->d_reclen -
+ (unsigned) &((struct dirent64*) 0)->d_name);
+ dp->d_ino = dp64->d_ino;
+ dp->d_off = dp64->d_off;
+ dp->d_reclen = dp64->d_reclen;
+ dp->d_type = dp64->d_type;
+ memmove(dp->d_name, dp64->d_name, name_len);
+ dp64 = (struct dirent64*) ((char*) dp64 + dp->d_reclen);
+ }
+ }
+
+ return res;
+}
+int __getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
+ __attribute__((alias("getdents")));
+
+/* Forward to 64 versions (uclibc expects versions w/o asm specifier) */
+
+int open64(const char *pathname, int flags, ...) __attribute__((weak));
+int open64(const char *pathname, int flags, ...) {
+ mode_t mode = 0;
+
+ if (flags & O_CREAT) {
+ /* get mode */
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ return __fd_open(pathname, flags, mode);
+}
+
+off64_t lseek64(int fd, off64_t off, int whence) __attribute__((weak));
+off64_t lseek64(int fd, off64_t off, int whence) {
+ return __fd_lseek(fd, off, whence);
+}
+
+int stat64(const char *path, struct stat64 *buf) __attribute__((weak));
+int stat64(const char *path, struct stat64 *buf) {
+ return __fd_stat(path, buf);
+}
+
+int lstat64(const char *path, struct stat64 *buf) __attribute__((weak));
+int lstat64(const char *path, struct stat64 *buf) {
+ return __fd_lstat(path, buf);
+}
+
+int fstat64(int fd, struct stat64 *buf) __attribute__((weak));
+int fstat64(int fd, struct stat64 *buf) {
+ return __fd_fstat(fd, buf);
+}
Added: klee/trunk/runtime/POSIX/fd_64.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/fd_64.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/fd_64.c (added)
+++ klee/trunk/runtime/POSIX/fd_64.c Wed May 20 23:36:41 2009
@@ -0,0 +1,90 @@
+//===-- fd_64.c -----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#include "fd.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <termios.h>
+#include <sys/select.h>
+#include <klee/klee.h>
+
+/*** Forward to actual implementations ***/
+
+int open(const char *pathname, int flags, ...) {
+ mode_t mode = 0;
+
+ if (flags & O_CREAT) {
+ /* get mode */
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ return __fd_open(pathname, flags, mode);
+}
+
+off64_t lseek(int fd, off64_t offset, int whence) {
+ return __fd_lseek(fd, offset, whence);
+}
+
+int __xstat(int vers, const char *path, struct stat *buf) {
+ return __fd_stat(path, (struct stat64*) buf);
+}
+
+int stat(const char *path, struct stat *buf) {
+ return __fd_stat(path, (struct stat64*) buf);
+}
+
+int __lxstat(int vers, const char *path, struct stat *buf) {
+ return __fd_lstat(path, (struct stat64*) buf);
+}
+
+int lstat(const char *path, struct stat *buf) {
+ return __fd_lstat(path, (struct stat64*) buf);
+}
+
+int __fxstat(int vers, int fd, struct stat *buf) {
+ return __fd_fstat(fd, (struct stat64*) buf);
+}
+
+int fstat(int fd, struct stat *buf) {
+ return __fd_fstat(fd, (struct stat64*) buf);
+}
+
+int ftruncate64(int fd, off64_t length) {
+ return __fd_ftruncate(fd, length);
+}
+
+int statfs(const char *path, struct statfs *buf) __attribute__((weak));
+int statfs(const char *path, struct statfs *buf) {
+ return __fd_statfs(path, buf);
+}
+
+int getdents64(unsigned int fd, struct dirent *dirp, unsigned int count) {
+ return __fd_getdents(fd, (struct dirent64*) dirp, count);
+}
+int __getdents64(unsigned int fd, struct dirent *dirp, unsigned int count)
+ __attribute__((alias("getdents64")));
Added: klee/trunk/runtime/POSIX/fd_init.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/fd_init.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/fd_init.c (added)
+++ klee/trunk/runtime/POSIX/fd_init.c Wed May 20 23:36:41 2009
@@ -0,0 +1,161 @@
+//===-- fd_init.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#include "fd.h"
+#include <klee/klee.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+
+exe_file_system_t __exe_fs;
+
+/* NOTE: It is important that these are statically initialized
+ correctly, since things that run before main may hit them given the
+ current way things are linked. */
+
+/* XXX Technically these flags are initialized w.o.r. to the
+ environment we are actually running in. We could patch them in
+ klee_init_fds, but we still have the problem that uclibc calls
+ prior to main will get the wrong data. Not such a big deal since we
+ mostly care about sym case anyway. */
+
+
+exe_sym_env_t __exe_env = {
+ {{ 0, eOpen | eReadable, 0, 0},
+ { 1, eOpen | eWriteable, 0, 0},
+ { 2, eOpen | eWriteable, 0, 0}},
+ 022,
+ 0,
+ 0
+};
+
+static void __create_new_dfile(exe_disk_file_t *dfile, unsigned size,
+ const char *name, struct stat64 *defaults) {
+ struct stat64 *s = malloc(sizeof(*s));
+ const char *sp;
+ char sname[64];
+ for (sp=name; *sp; ++sp)
+ sname[sp-name] = *sp;
+ memcpy(&sname[sp-name], "-stat", 6);
+
+ assert(size);
+
+ dfile->size = size;
+ dfile->contents = malloc(dfile->size);
+ klee_make_symbolic_name(dfile->contents, dfile->size, name);
+
+ klee_make_symbolic_name(s, sizeof(*s), sname);
+
+ /* For broken tests */
+ if (!klee_is_symbolic(s->st_ino) &&
+ (s->st_ino & 0x7FFFFFFF) == 0)
+ s->st_ino = defaults->st_ino;
+
+ /* Important since we copy this out through getdents, and readdir
+ will otherwise skip this entry. For same reason need to make sure
+ it fits in low bits. */
+ klee_assume((s->st_ino & 0x7FFFFFFF) != 0);
+
+ /* uclibc opendir uses this as its buffer size, try to keep
+ reasonable. */
+ klee_assume((s->st_blksize & ~0xFFFF) == 0);
+
+ klee_prefer_cex(s, !(s->st_mode & ~(S_IFMT | 0777)));
+ klee_prefer_cex(s, s->st_dev == defaults->st_dev);
+ klee_prefer_cex(s, s->st_rdev == defaults->st_rdev);
+ klee_prefer_cex(s, (s->st_mode&0700) == 0600);
+ klee_prefer_cex(s, (s->st_mode&0070) == 0020);
+ klee_prefer_cex(s, (s->st_mode&0007) == 0002);
+ klee_prefer_cex(s, (s->st_mode&S_IFMT) == S_IFREG);
+ klee_prefer_cex(s, s->st_nlink == 1);
+ klee_prefer_cex(s, s->st_uid == defaults->st_uid);
+ klee_prefer_cex(s, s->st_gid == defaults->st_gid);
+ klee_prefer_cex(s, s->st_blksize == 4096);
+ klee_prefer_cex(s, s->st_atime == defaults->st_atime);
+ klee_prefer_cex(s, s->st_mtime == defaults->st_mtime);
+ klee_prefer_cex(s, s->st_ctime == defaults->st_ctime);
+
+ s->st_size = dfile->size;
+ s->st_blocks = 8;
+ dfile->stat = s;
+}
+
+static unsigned __sym_uint32(const char *name) {
+ unsigned x;
+ klee_make_symbolic_name(&x, sizeof x, name);
+ return x;
+}
+
+/* n_files: number of symbolic input files, excluding stdin
+ file_length: size in bytes of each symbolic file, including stdin
+ sym_stdout_flag: 1 if stdout should be symbolic, 0 otherwise
+ save_all_writes_flag: 1 if all writes are executed as expected, 0 if
+ writes past the initial file size are discarded
+ (file offset is always incremented)
+ max_failures: maximum number of system call failures */
+void klee_init_fds(unsigned n_files, unsigned file_length,
+ int sym_stdout_flag, int save_all_writes_flag,
+ unsigned max_failures) {
+ unsigned k;
+ char name[7] = "?-data";
+ struct stat64 s;
+
+ stat64(".", &s);
+
+ __exe_fs.n_sym_files = n_files;
+ __exe_fs.sym_files = malloc(sizeof(*__exe_fs.sym_files) * n_files);
+ for (k=0; k < n_files; k++) {
+ name[0] = 'A' + k;
+ __create_new_dfile(&__exe_fs.sym_files[k], file_length, name, &s);
+ }
+
+ /* setting symbolic stdin */
+ if (file_length) {
+ __exe_fs.sym_stdin = malloc(sizeof(*__exe_fs.sym_stdin));
+ __create_new_dfile(__exe_fs.sym_stdin, file_length, "stdin", &s);
+ __exe_env.fds[0].dfile = __exe_fs.sym_stdin;
+ }
+ else __exe_fs.sym_stdin = NULL;
+
+ __exe_fs.max_failures = max_failures;
+ if (__exe_fs.max_failures) {
+ __exe_fs.read_fail = malloc(sizeof(*__exe_fs.read_fail));
+ __exe_fs.write_fail = malloc(sizeof(*__exe_fs.write_fail));
+ __exe_fs.close_fail = malloc(sizeof(*__exe_fs.close_fail));
+ __exe_fs.ftruncate_fail = malloc(sizeof(*__exe_fs.ftruncate_fail));
+ __exe_fs.getcwd_fail = malloc(sizeof(*__exe_fs.getcwd_fail));
+
+ klee_make_symbolic_name(__exe_fs.read_fail, sizeof(*__exe_fs.read_fail), "read_fail");
+ klee_make_symbolic_name(__exe_fs.write_fail, sizeof(*__exe_fs.write_fail), "write_fail");
+ klee_make_symbolic_name(__exe_fs.close_fail, sizeof(*__exe_fs.close_fail), "close_fail");
+ klee_make_symbolic_name(__exe_fs.ftruncate_fail, sizeof(*__exe_fs.ftruncate_fail), "ftruncate_fail");
+ klee_make_symbolic_name(__exe_fs.getcwd_fail, sizeof(*__exe_fs.getcwd_fail), "getcwd_fail");
+ }
+
+ /* setting symbolic stdout */
+ if (sym_stdout_flag) {
+ __exe_fs.sym_stdout = malloc(sizeof(*__exe_fs.sym_stdout));
+ __create_new_dfile(__exe_fs.sym_stdout, 1024, "stdout", &s);
+ __exe_env.fds[1].dfile = __exe_fs.sym_stdout;
+ __exe_fs.stdout_writes = 0;
+ }
+ else __exe_fs.sym_stdout = NULL;
+
+ __exe_env.save_all_writes = save_all_writes_flag;
+ __exe_env.version = __sym_uint32("model_version");
+ klee_assume(__exe_env.version == 1);
+}
Added: klee/trunk/runtime/POSIX/illegal.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/illegal.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/illegal.c (added)
+++ klee/trunk/runtime/POSIX/illegal.c Wed May 20 23:36:41 2009
@@ -0,0 +1,70 @@
+//===-- illegal.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+
+#include <klee/klee.h>
+
+void klee_warning(const char*);
+void klee_warning_once(const char*);
+
+int kill(pid_t pid, int sig) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int _setjmp (struct __jmp_buf_tag __env[1]) __attribute__((weak));
+int _setjmp (struct __jmp_buf_tag __env[1]) {
+ klee_warning_once("ignoring");
+ return 0;
+}
+
+void longjmp(jmp_buf env, int val) {
+ klee_report_error(__FILE__, __LINE__, "longjmp unsupported", "xxx.err");
+}
+
+/* Macro so function name from klee_warning comes out correct. */
+#define __bad_exec() \
+ (klee_warning("ignoring (EACCES)"),\
+ errno = EACCES,\
+ -1)
+
+/* This need to be weak because uclibc wants to define them as well,
+ but we will want to make sure a definition is around in case we
+ don't link with it. */
+
+int execl(const char *path, const char *arg, ...) __attribute__((weak));
+int execlp(const char *file, const char *arg, ...) __attribute__((weak));
+int execle(const char *path, const char *arg, ...) __attribute__((weak));
+int execv(const char *path, char *const argv[]) __attribute__((weak));
+int execvp(const char *file, char *const argv[]) __attribute__((weak));
+int execve(const char *file, char *const argv[], char *const envp[]) __attribute__((weak));
+
+int execl(const char *path, const char *arg, ...) { return __bad_exec(); }
+int execlp(const char *file, const char *arg, ...) { return __bad_exec(); }
+int execle(const char *path, const char *arg, ...) { return __bad_exec(); }
+int execv(const char *path, char *const argv[]) { return __bad_exec(); }
+int execvp(const char *file, char *const argv[]) { return __bad_exec(); }
+int execve(const char *file, char *const argv[], char *const envp[]) { return __bad_exec(); }
+
+pid_t fork(void) {
+ klee_warning("ignoring (ENOMEM)");
+ errno = ENOMEM;
+ return -1;
+}
+
+pid_t vfork(void) {
+ return fork();
+}
Added: klee/trunk/runtime/POSIX/klee_init_env.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/klee_init_env.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/klee_init_env.c (added)
+++ klee/trunk/runtime/POSIX/klee_init_env.c Wed May 20 23:36:41 2009
@@ -0,0 +1,181 @@
+//===-- klee_init_env.c ---------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/klee.h"
+#define _LARGEFILE64_SOURCE
+#include "fd.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static void __emit_error(const char *msg) {
+ klee_report_error(__FILE__, __LINE__, msg, "user.err");
+}
+
+/* Helper function that converts a string to an integer, and
+ terminates the program with an error message is the string is not a
+ proper number */
+static long int __str_to_int(char *s, const char *error_msg) {
+ long int res = 0;
+ char c;
+
+ if (!*s) __emit_error(error_msg);
+
+ while ((c = *s++)) {
+ if (c == '\0') {
+ break;
+ } else if (c>='0' && c<='9') {
+ res = res*10 + (c - '0');
+ } else {
+ __emit_error(error_msg);
+ }
+ }
+ return res;
+}
+
+static int __isprint(const char c) {
+ /* Assume ASCII */
+ return (32 <= c && c <= 126);
+}
+
+static int __streq(const char *a, const char *b) {
+ while (*a == *b) {
+ if (!*a)
+ return 1;
+ a++;
+ b++;
+ }
+ return 0;
+}
+
+static char *__get_sym_str(int numChars, char *name) {
+ int i;
+ char *s = malloc(numChars+1);
+ klee_mark_global(s);
+ klee_make_symbolic_name(s, numChars+1, name);
+
+ for (i=0; i<numChars; i++)
+ klee_prefer_cex(s, __isprint(s[i]));
+
+ s[numChars] = '\0';
+ return s;
+}
+
+static void __add_arg(int *argc, char **argv, char *arg, int argcMax) {
+ if (*argc==argcMax) {
+ __emit_error("too many arguments for klee_init_env");
+ } else {
+ argv[*argc] = arg;
+ (*argc)++;
+ }
+}
+
+void klee_init_env(int* argcPtr, char*** argvPtr) {
+ int argc = *argcPtr;
+ char** argv = *argvPtr;
+
+ int new_argc = 0, n_args;
+ char* new_argv[1024];
+ unsigned max_len, min_argvs, max_argvs;
+ unsigned sym_files = 0, sym_file_len = 0;
+ int sym_stdout_flag = 0;
+ int save_all_writes_flag = 0;
+ int fd_fail = 0;
+ char** final_argv;
+ char sym_arg_name[5] = "arg";
+ unsigned sym_arg_num = 0;
+ int k=0, i;
+
+ sym_arg_name[4] = '\0';
+
+ while (k < argc) {
+ if (__streq(argv[k], "--sym-arg") || __streq(argv[k], "-sym-arg")) {
+ const char *msg = "--sym-arg expects an integer argument <max-len>";
+ if (++k == argc)
+ __emit_error(msg);
+
+ max_len = __str_to_int(argv[k++], msg);
+ sym_arg_name[3] = '0' + sym_arg_num++;
+ __add_arg(&new_argc, new_argv,
+ __get_sym_str(max_len, sym_arg_name),
+ 1024);
+ }
+ else if (__streq(argv[k], "--sym-args") || __streq(argv[k], "-sym-args")) {
+ const char *msg =
+ "--sym-args expects three integer arguments <min-argvs> <max-argvs> <max-len>";
+
+ if (k+3 >= argc)
+ __emit_error(msg);
+
+ k++;
+ min_argvs = __str_to_int(argv[k++], msg);
+ max_argvs = __str_to_int(argv[k++], msg);
+ max_len = __str_to_int(argv[k++], msg);
+
+ n_args = klee_range(min_argvs, max_argvs+1, "n_args");
+ for (i=0; i < n_args; i++) {
+ sym_arg_name[3] = '0' + sym_arg_num++;
+ __add_arg(&new_argc, new_argv,
+ __get_sym_str(max_len, sym_arg_name),
+ 1024);
+ }
+ }
+ else if (__streq(argv[k], "--sym-files") || __streq(argv[k], "-sym-files")) {
+ const char* msg = "--sym-files expects two integer arguments <no-sym-files> <sym-file-len>";
+
+ if (k+2 >= argc)
+ __emit_error(msg);
+
+ k++;
+ sym_files = __str_to_int(argv[k++], msg);
+ sym_file_len = __str_to_int(argv[k++], msg);
+
+ }
+ else if (__streq(argv[k], "--sym-stdout") || __streq(argv[k], "-sym-stdout")) {
+ sym_stdout_flag = 1;
+ k++;
+ }
+ else if (__streq(argv[k], "--save-all-writes") || __streq(argv[k], "-save-all-writes")) {
+ save_all_writes_flag = 1;
+ k++;
+ }
+ else if (__streq(argv[k], "--fd-fail") || __streq(argv[k], "-fd-fail")) {
+ fd_fail = 1;
+ k++;
+ }
+ else if (__streq(argv[k], "--max-fail") || __streq(argv[k], "-max-fail")) {
+ const char *msg = "--max-fail expects an integer argument <max-failures>";
+ if (++k == argc)
+ __emit_error(msg);
+
+ fd_fail = __str_to_int(argv[k++], msg);
+ }
+ else {
+ /* simply copy arguments */
+ __add_arg(&new_argc, new_argv, argv[k++], 1024);
+ }
+ }
+
+ final_argv = (char**) malloc((new_argc+1) * sizeof(*final_argv));
+ klee_mark_global(final_argv);
+ memcpy(final_argv, new_argv, new_argc * sizeof(*final_argv));
+ final_argv[new_argc] = 0;
+
+ *argcPtr = new_argc;
+ *argvPtr = final_argv;
+
+ klee_init_fds(sym_files, sym_file_len,
+ sym_stdout_flag, save_all_writes_flag,
+ fd_fail);
+}
+
Added: klee/trunk/runtime/POSIX/misc.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/misc.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/misc.c (added)
+++ klee/trunk/runtime/POSIX/misc.c Wed May 20 23:36:41 2009
@@ -0,0 +1,87 @@
+//===-- misc.c ------------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <klee/klee.h>
+#include <string.h>
+
+#if 0
+#define MAX_SYM_ENV_SIZE 32
+typedef struct {
+ char name[MAX_SYM_ENV_SIZE];
+ char *value;
+} sym_env_var;
+
+static sym_env_var *__klee_sym_env = 0;
+static unsigned __klee_sym_env_count = 0;
+static unsigned __klee_sym_env_nvars = 0;
+static unsigned __klee_sym_env_var_size = 0;
+void __klee_init_environ(unsigned nvars,
+ unsigned var_size) {
+ assert(var_size);
+ __klee_sym_env = malloc(sizeof(*__klee_sym_env) * nvars);
+ assert(__klee_sym_env);
+
+ __klee_sym_env_nvars = nvars;
+ __klee_sym_env_var_size = var_size;
+}
+
+static unsigned __strlen(const char *s) {
+ const char *s2 = s;
+ while (*s2) ++s2;
+ return s2-s;
+}
+
+extern char *__getenv(const char *name);
+char *getenv(const char *name) {
+ char *res = __getenv(name);
+
+ if (!__klee_sym_env_nvars)
+ return res;
+
+ /* If it exists in the system environment fork and return the actual
+ result or 0. */
+ if (res) {
+ return klee_range(0, 2, name) ? res : 0;
+ } else {
+ unsigned i, len = __strlen(name);
+
+ if (len>=MAX_SYM_ENV_SIZE) {
+ /* Don't deal with strings to large to fit in our name. */
+ return 0;
+ } else {
+ /* Check for existing entry */
+ for (i=0; i<__klee_sym_env_count; ++i)
+ if (memcmp(__klee_sym_env[i].name, name, len+1)==0)
+ return __klee_sym_env[i].value;
+
+ /* Otherwise create if room and we choose to */
+ if (__klee_sym_env_count < __klee_sym_env_nvars) {
+ if (klee_range(0, 2, name)) {
+ char *s = malloc(__klee_sym_env_var_size+1);
+ klee_make_symbolic(s, __klee_sym_env_var_size+1);
+ s[__klee_sym_env_var_size] = '\0';
+
+ memcpy(__klee_sym_env[__klee_sym_env_count].name, name, len+1);
+ __klee_sym_env[__klee_sym_env_count].value = s;
+ ++__klee_sym_env_count;
+
+ return s;
+ }
+ }
+
+ return 0;
+ }
+ }
+}
+#endif
Added: klee/trunk/runtime/POSIX/selinux.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/selinux.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/selinux.c (added)
+++ klee/trunk/runtime/POSIX/selinux.c Wed May 20 23:36:41 2009
@@ -0,0 +1,80 @@
+//===-- selinux.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/* Very basic SELinux support */
+
+#include "klee/Config/config.h"
+
+#ifdef HAVE_SELINUX_SELINUX_H
+
+#include "klee/klee.h"
+
+#include <selinux/selinux.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* for now, assume we run on an SELinux machine */
+int exe_selinux = 1;
+
+/* NULL is the default policy behavior */
+security_context_t create_con = NULL;
+
+
+int is_selinux_enabled() {
+ return exe_selinux;
+}
+
+
+/***/
+
+int getfscreatecon(security_context_t *context) {
+ *context = create_con;
+ return 0;
+}
+
+
+int setfscreatecon(security_context_t context) {
+ if (context == NULL) {
+ create_con = context;
+ return 0;
+ }
+
+ /* on my machine, setfscreatecon seems to incorrectly accept one
+ char strings.. Also, make sure mcstrans > 0.2.8 for replay
+ (important bug fixed) */
+ if (context[0] != '\0' && context[1] == '\0')
+ klee_silent_exit(1);
+
+ return -1;
+}
+
+/***/
+
+int setfilecon(const char *path, security_context_t con) {
+ if (con)
+ return 0;
+
+ errno = ENOSPC;
+ return -1;
+}
+
+int lsetfilecon(const char *path, security_context_t con) {
+ return setfilecon(path, con);
+}
+
+int fsetfilecon(int fd, security_context_t con) {
+ return setfilecon("", con);
+}
+
+/***/
+
+void freecon(security_context_t con) {}
+void freeconary(security_context_t *con) {}
+
+#endif
Added: klee/trunk/runtime/POSIX/stubs.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/stubs.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/stubs.c (added)
+++ klee/trunk/runtime/POSIX/stubs.c Wed May 20 23:36:41 2009
@@ -0,0 +1,560 @@
+//===-- stubs.c -----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <utime.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "klee/Config/config.h"
+
+void klee_warning(const char*);
+void klee_warning_once(const char*);
+
+/* Silent ignore */
+
+int __syscall_rt_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact, size_t _something)
+ __attribute__((weak));
+
+int __syscall_rt_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact, size_t _something) {
+ klee_warning_once("silently ignoring");
+ return 0;
+}
+
+int sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact) __attribute__((weak));
+
+int sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact) {
+ klee_warning_once("silently ignoring");
+ return 0;
+}
+
+int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+ __attribute__((weak));
+int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
+ klee_warning_once("silently ignoring");
+ return 0;
+}
+
+/* Not even worth warning about these */
+int fdatasync(int fd) __attribute__((weak));
+int fdatasync(int fd) {
+ return 0;
+}
+
+/* Not even worth warning about this */
+void sync(void) __attribute__((weak));
+void sync(void) {
+}
+
+/* Error ignore */
+
+extern int __fgetc_unlocked(FILE *f);
+extern int __fputc_unlocked(int c, FILE *f);
+
+int __socketcall(int type, int *args) __attribute__((weak));
+int __socketcall(int type, int *args) {
+ klee_warning("ignoring (EAFNOSUPPORT)");
+ errno = EAFNOSUPPORT;
+ return -1;
+}
+
+int _IO_getc(FILE *f) __attribute__((weak));
+int _IO_getc(FILE *f) {
+ return __fgetc_unlocked(f);
+}
+
+int _IO_putc(int c, FILE *f) __attribute__((weak));
+int _IO_putc(int c, FILE *f) {
+ return __fputc_unlocked(c, f);
+}
+
+int mkdir(const char *pathname, mode_t mode) __attribute__((weak));
+int mkdir(const char *pathname, mode_t mode) {
+ klee_warning("ignoring (EIO)");
+ errno = EIO;
+ return -1;
+}
+
+int mkfifo(const char *pathname, mode_t mode) __attribute__((weak));
+int mkfifo(const char *pathname, mode_t mode) {
+ klee_warning("ignoring (EIO)");
+ errno = EIO;
+ return -1;
+}
+
+int mknod(const char *pathname, mode_t mode, dev_t dev) __attribute__((weak));
+int mknod(const char *pathname, mode_t mode, dev_t dev) {
+ klee_warning("ignoring (EIO)");
+ errno = EIO;
+ return -1;
+}
+
+int pipe(int filedes[2]) __attribute__((weak));
+int pipe(int filedes[2]) {
+ klee_warning("ignoring (ENFILE)");
+ errno = ENFILE;
+ return -1;
+}
+
+int link(const char *oldpath, const char *newpath) __attribute__((weak));
+int link(const char *oldpath, const char *newpath) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int symlink(const char *oldpath, const char *newpath) __attribute__((weak));
+int symlink(const char *oldpath, const char *newpath) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int rename(const char *oldpath, const char *newpath) __attribute__((weak));
+int rename(const char *oldpath, const char *newpath) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int nanosleep(const struct timespec *req, struct timespec *rem) __attribute__((weak));
+int nanosleep(const struct timespec *req, struct timespec *rem) {
+ return 0;
+}
+
+/* XXX why can't I call this internally? */
+int clock_gettime(clockid_t clk_id, struct timespec *res) __attribute__((weak));
+int clock_gettime(clockid_t clk_id, struct timespec *res) {
+ /* Fake */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ res->tv_sec = tv.tv_sec;
+ res->tv_nsec = tv.tv_usec * 1000;
+ return 0;
+}
+
+int clock_settime(clockid_t clk_id, const struct timespec *res) __attribute__((weak));
+int clock_settime(clockid_t clk_id, const struct timespec *res) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+time_t time(time_t *t) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ if (t)
+ *t = tv.tv_sec;
+ return tv.tv_sec;
+}
+
+clock_t times(struct tms *buf) {
+ /* Fake */
+ buf->tms_utime = 0;
+ buf->tms_stime = 0;
+ buf->tms_cutime = 0;
+ buf->tms_cstime = 0;
+ return 0;
+}
+
+struct utmpx *getutxent(void) __attribute__((weak));
+struct utmpx *getutxent(void) {
+ return (struct utmpx*) getutent();
+}
+
+void setutxent(void) __attribute__((weak));
+void setutxent(void) {
+ setutent();
+}
+
+void endutxent(void) __attribute__((weak));
+void endutxent(void) {
+ endutent();
+}
+
+int utmpxname(const char *file) __attribute__((weak));
+int utmpxname(const char *file) {
+ utmpname(file);
+ return 0;
+}
+
+int euidaccess(const char *pathname, int mode) __attribute__((weak));
+int euidaccess(const char *pathname, int mode) {
+ return access(pathname, mode);
+}
+
+int eaccess(const char *pathname, int mode) __attribute__((weak));
+int eaccess(const char *pathname, int mode) {
+ return euidaccess(pathname, mode);
+}
+
+int group_member (gid_t __gid) __attribute__((weak));
+int group_member (gid_t __gid) {
+ return ((__gid == getgid ()) || (__gid == getegid ()));
+}
+
+int utime(const char *filename, const struct utimbuf *buf) __attribute__((weak));
+int utime(const char *filename, const struct utimbuf *buf) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int utimes(const char *filename, const struct timeval times[2]) __attribute__((weak));
+int utimes(const char *filename, const struct timeval times[2]) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int futimes(int fd, const struct timeval times[2]) __attribute__((weak));
+int futimes(int fd, const struct timeval times[2]) {
+ klee_warning("ignoring (EBADF)");
+ errno = EBADF;
+ return -1;
+}
+
+int strverscmp (__const char *__s1, __const char *__s2) {
+ return strcmp(__s1, __s2); /* XXX no doubt this is bad */
+}
+
+unsigned int gnu_dev_major(unsigned long long int __dev) __attribute__((weak));
+unsigned int gnu_dev_major(unsigned long long int __dev) {
+ return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);
+}
+
+unsigned int gnu_dev_minor(unsigned long long int __dev) __attribute__((weak));
+unsigned int gnu_dev_minor(unsigned long long int __dev) {
+ return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);
+}
+
+unsigned long long int gnu_dev_makedev(unsigned int __major, unsigned int __minor) __attribute__((weak));
+unsigned long long int gnu_dev_makedev(unsigned int __major, unsigned int __minor) {
+ return ((__minor & 0xff) | ((__major & 0xfff) << 8)
+ | (((unsigned long long int) (__minor & ~0xff)) << 12)
+ | (((unsigned long long int) (__major & ~0xfff)) << 32));
+}
+
+char *canonicalize_file_name (const char *name) __attribute__((weak));
+char *canonicalize_file_name (const char *name) {
+ char *res = malloc(PATH_MAX);
+ char *rp_res = realpath(name, res);
+ if (!rp_res)
+ free(res);
+ return rp_res;
+}
+
+int getloadavg(double loadavg[], int nelem) __attribute__((weak));
+int getloadavg(double loadavg[], int nelem) {
+ klee_warning("ignoring (-1 result)");
+ return -1;
+}
+
+pid_t wait(int *status) __attribute__((weak));
+pid_t wait(int *status) {
+ klee_warning("ignoring (ECHILD)");
+ errno = ECHILD;
+ return -1;
+}
+
+pid_t wait3(int *status, int options, struct rusage *rusage) __attribute__((weak));
+pid_t wait3(int *status, int options, struct rusage *rusage) {
+ klee_warning("ignoring (ECHILD)");
+ errno = ECHILD;
+ return -1;
+}
+
+pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) __attribute__((weak));
+pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) {
+ klee_warning("ignoring (ECHILD)");
+ errno = ECHILD;
+ return -1;
+}
+
+pid_t waitpid(pid_t pid, int *status, int options) __attribute__((weak));
+pid_t waitpid(pid_t pid, int *status, int options) {
+ klee_warning("ignoring (ECHILD)");
+ errno = ECHILD;
+ return -1;
+}
+
+pid_t waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) __attribute__((weak));
+pid_t waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) {
+ klee_warning("ignoring (ECHILD)");
+ errno = ECHILD;
+ return -1;
+}
+
+/* ACL */
+
+/* FIXME: We need autoconf magic for this. */
+
+#ifdef HAVE_SYS_ACL_H
+
+#include <sys/acl.h>
+
+int acl_delete_def_file(const char *path_p) __attribute__((weak));
+int acl_delete_def_file(const char *path_p) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int acl_extended_file(const char path_p) __attribute__((weak));
+int acl_extended_file(const char path_p) {
+ klee_warning("ignoring (ENOENT)");
+ errno = ENOENT;
+ return -1;
+}
+
+int acl_entries(acl_t acl) __attribute__((weak));
+int acl_entries(acl_t acl) {
+ klee_warning("ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+}
+
+acl_t acl_from_mode(mode_t mode) __attribute__((weak));
+acl_t acl_from_mode(mode_t mode) {
+ klee_warning("ignoring (ENOMEM)");
+ errno = ENOMEM;
+ return NULL;
+}
+
+acl_t acl_get_fd(int fd) __attribute__((weak));
+acl_t acl_get_fd(int fd) {
+ klee_warning("ignoring (ENOMEM)");
+ errno = ENOMEM;
+ return NULL;
+}
+
+acl_t acl_get_file(const char *pathname, acl_type_t type) __attribute__((weak));
+acl_t acl_get_file(const char *pathname, acl_type_t type) {
+ klee_warning("ignoring (ENONMEM)");
+ errno = ENOMEM;
+ return NULL;
+}
+
+int acl_set_fd(int fd, acl_t acl) __attribute__((weak));
+int acl_set_fd(int fd, acl_t acl) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int acl_set_file(const char *path_p, acl_type_t type, acl_t acl) __attribute__((weak));
+int acl_set_file(const char *path_p, acl_type_t type, acl_t acl) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int acl_free(void *obj_p) __attribute__((weak));
+int acl_free(void *obj_p) {
+ klee_warning("ignoring (EINVAL)");
+ errno = EINVAL;
+ return -1;
+}
+
+#endif
+
+int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) __attribute__((weak));
+int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int umount(const char *target) __attribute__((weak));
+int umount(const char *target) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int umount2(const char *target, int flags) __attribute__((weak));
+int umount2(const char *target, int flags) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int swapon(const char *path, int swapflags) __attribute__((weak));
+int swapon(const char *path, int swapflags) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int swapoff(const char *path) __attribute__((weak));
+int swapoff(const char *path) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setgid(gid_t gid) __attribute__((weak));
+int setgid(gid_t gid) {
+ klee_warning("silently ignoring (returning 0)");
+ return 0;
+}
+
+int setgroups(size_t size, const gid_t *list) __attribute__((weak));
+int setgroups(size_t size, const gid_t *list) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int sethostname(const char *name, size_t len) __attribute__((weak));
+int sethostname(const char *name, size_t len) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setpgid(pid_t pid, pid_t pgid) __attribute__((weak));
+int setpgid(pid_t pid, pid_t pgid) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setpgrp(void) __attribute__((weak));
+int setpgrp(void) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setpriority(__priority_which_t which, id_t who, int prio) __attribute__((weak));
+int setpriority(__priority_which_t which, id_t who, int prio) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid) __attribute__((weak));
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setresuid(uid_t ruid, uid_t euid, uid_t suid) __attribute__((weak));
+int setresuid(uid_t ruid, uid_t euid, uid_t suid) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setrlimit(__rlimit_resource_t resource, const struct rlimit *rlim) __attribute__((weak));
+int setrlimit(__rlimit_resource_t resource, const struct rlimit *rlim) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setrlimit64(__rlimit_resource_t resource, const struct rlimit64 *rlim) __attribute__((weak));
+int setrlimit64(__rlimit_resource_t resource, const struct rlimit64 *rlim) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+pid_t setsid(void) __attribute__((weak));
+pid_t setsid(void) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int settimeofday(const struct timeval *tv, const struct timezone *tz) __attribute__((weak));
+int settimeofday(const struct timeval *tv, const struct timezone *tz) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int setuid(uid_t uid) __attribute__((weak));
+int setuid(uid_t uid) {
+ klee_warning("silently ignoring (returning 0)");
+ return 0;
+}
+
+int reboot(int flag) __attribute__((weak));
+int reboot(int flag) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int mlock(const void *addr, size_t len) __attribute__((weak));
+int mlock(const void *addr, size_t len) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int munlock(const void *addr, size_t len) __attribute__((weak));
+int munlock(const void *addr, size_t len) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+int pause(void) __attribute__((weak));
+int pause(void) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+ssize_t readahead(int fd, off64_t *offset, size_t count) __attribute__((weak));
+ssize_t readahead(int fd, off64_t *offset, size_t count) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
+
+void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) __attribute__((weak));
+void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return (void*) -1;
+}
+
+void *mmap64(void *start, size_t length, int prot, int flags, int fd, off64_t offset) __attribute__((weak));
+void *mmap64(void *start, size_t length, int prot, int flags, int fd, off64_t offset) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return (void*) -1;
+}
+
+int munmap(void*start, size_t length) __attribute__((weak));
+int munmap(void*start, size_t length) {
+ klee_warning("ignoring (EPERM)");
+ errno = EPERM;
+ return -1;
+}
Added: klee/trunk/runtime/POSIX/testing-dir/a
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/testing-dir/a?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/testing-dir/a (added)
+++ klee/trunk/runtime/POSIX/testing-dir/a Wed May 20 23:36:41 2009
@@ -0,0 +1 @@
+link /dev/null
\ No newline at end of file
Propchange: klee/trunk/runtime/POSIX/testing-dir/a
------------------------------------------------------------------------------
svn:special = *
Added: klee/trunk/runtime/POSIX/testing-dir/b
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/testing-dir/b?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/testing-dir/b (added)
+++ klee/trunk/runtime/POSIX/testing-dir/b Wed May 20 23:36:41 2009
@@ -0,0 +1 @@
+link /dev/random
\ No newline at end of file
Propchange: klee/trunk/runtime/POSIX/testing-dir/b
------------------------------------------------------------------------------
svn:special = *
Added: klee/trunk/runtime/POSIX/testing-dir/c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/testing-dir/c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/testing-dir/c (added)
+++ klee/trunk/runtime/POSIX/testing-dir/c Wed May 20 23:36:41 2009
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "Hello world!"
Propchange: klee/trunk/runtime/POSIX/testing-dir/c
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/runtime/POSIX/testing-dir/d
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/testing-dir/d?rev=72205&view=auto
==============================================================================
(empty)
Added: klee/trunk/runtime/POSIX/testing-env
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/POSIX/testing-env?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/POSIX/testing-env (added)
+++ klee/trunk/runtime/POSIX/testing-env Wed May 20 23:36:41 2009
@@ -0,0 +1,27 @@
+# This file is sourced prior to running the testing environment, make
+# sure to quote things.
+
+export TERM="xterm"
+export SHELL="/bin/bash"
+export LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35:*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35:"
+export PATH="/usr/local/bin:/usr/bin:/bin"
+export COLORTERM="gnome-terminal"
+export LC_ALL=C
+export TABSIZE=8
+export COLUMNS=80
+
+# 1 BLOCK_SIZE
+# 2 COLUMNS
+# 1 DF_BLOCK_SIZE
+# 1 DU_BLOCK_SIZE
+# 1 HOME
+# 1 LS_BLOCK_SIZE
+# 1 LS_COLORS
+# 11 POSIXLY_CORRECT
+# 1 QUOTING_STYLE
+# 3 SHELL
+# 4 SIMPLE_BACKUP_SUFFIX
+# 1 TABSIZE
+# 2 TERM
+# 2 TIME_STYLE
+# 4 TMPDIR
Added: klee/trunk/runtime/Runtest/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Runtest/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Runtest/Makefile (added)
+++ klee/trunk/runtime/Runtest/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+#===-- runtime/Runtest/Makefile ----------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+USEDLIBS=kleeBasic.a
+LIBRARYNAME=kleeRuntest
+SHARED_LIBRARY=1
+LINK_LIBS_IN_SHARED = 1
+DONT_BUILD_RELINKED = 1
+NO_PEDANTIC=1
+
+include $(LEVEL)/Makefile.common
Added: klee/trunk/runtime/Runtest/intrinsics.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/Runtest/intrinsics.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/Runtest/intrinsics.c (added)
+++ klee/trunk/runtime/Runtest/intrinsics.c Wed May 20 23:36:41 2009
@@ -0,0 +1,154 @@
+//===-- intrinsics.c ------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/* Straight C for linking simplicity */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "klee/klee.h"
+
+#include "klee/Internal/ADT/BOut.h"
+
+static BOut *testData = 0;
+static unsigned testPosition = 0;
+
+static unsigned char rand_byte(void) {
+ unsigned x = rand();
+ x ^= x>>16;
+ x ^= x>>8;
+ return x & 0xFF;
+}
+
+void klee_make_symbolic_name(void *array, unsigned nbytes, const char *name) {
+ static int rand_init = -1;
+
+ if (rand_init == -1) {
+ if (getenv("KLEE_RANDOM")) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ rand_init = 1;
+ srand(tv.tv_sec ^ tv.tv_usec);
+ } else {
+ rand_init = 0;
+ }
+ }
+
+ if (rand_init) {
+ if (!strcmp(name,"syscall_a0")) {
+ unsigned long long *v = array;
+ assert(nbytes == 8);
+ *v = rand() % 69;
+ } else {
+ char *c = array;
+ unsigned i;
+ for (i=0; i<nbytes; i++)
+ c[i] = rand_byte();
+ }
+ return;
+ }
+
+ if (!testData) {
+ char tmp[256];
+ char *name = getenv("KLEE_RUNTEST");
+
+ if (!name) {
+ fprintf(stdout, "KLEE-RUNTIME: KLEE_RUNTEST not set, please enter .bout path: ");
+ fflush(stdout);
+ name = tmp;
+ if (!fgets(tmp, sizeof tmp, stdin) || !strlen(tmp)) {
+ fprintf(stderr, "KLEE-RUNTIME: cannot replay, no KLEE_RUNTEST or user input\n");
+ exit(1);
+ }
+ tmp[strlen(tmp)-1] = '\0'; /* kill newline */
+ }
+ testData = bOut_fromFile(name);
+ if (!testData) {
+ fprintf(stderr, "KLEE-RUNTIME: unable to open .bout file\n");
+ exit(1);
+ }
+ }
+
+ if (testPosition >= testData->numObjects) {
+ fprintf(stderr, "ERROR: out of inputs, using zero\n");
+ memset(array, 0, nbytes);
+ } else {
+ BOutObject *o = &testData->objects[testPosition++];
+ memcpy(array, o->bytes, nbytes<o->numBytes ? nbytes : o->numBytes);
+ if (nbytes != o->numBytes) {
+ fprintf(stderr, "ERROR: object sizes differ\n");
+ if (o->numBytes < nbytes)
+ memset((char*) array + o->numBytes, 0, nbytes - o->numBytes);
+ }
+ }
+}
+
+void klee_make_symbolic(void *array, unsigned nbytes) {
+ klee_make_symbolic_name(array, nbytes, "unnamed");
+}
+
+void *klee_malloc_n(unsigned nelems, unsigned size, unsigned alignment) {
+#if 1
+ return mmap((void*) 0x90000000, nelems*size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE
+#ifdef MAP_ANONYMOUS
+ |MAP_ANONYMOUS
+#endif
+ , 0, 0);
+#else
+ char *buffer = malloc(nelems*size + alignment - 1);
+ buffer += (alignment - (long)buffer % alignment);
+ return buffer;
+#endif
+}
+
+void klee_silent_exit(int x) {
+ exit(x);
+}
+
+unsigned klee_choose(unsigned n) {
+ unsigned x;
+ klee_make_symbolic(&x, sizeof x);
+ if(x >= n)
+ fprintf(stderr, "ERROR: max = %d, got = %d\n", n, x);
+ assert(x < n);
+ return x;
+}
+
+void klee_assume(unsigned x) {
+ if (!x) {
+ fprintf(stderr, "ERROR: invalid klee_assume\n");
+ }
+}
+
+unsigned klee_get_value(unsigned x) {
+ return x;
+}
+
+int klee_range_name(int begin, int end, const char* name) {
+ int x;
+ klee_make_symbolic_name(&x, sizeof x, name);
+ if (x<begin || x>=end) {
+ fprintf(stderr,
+ "KLEE: ERROR: invalid klee_range(%u,%u,%s) value, got: %u\n",
+ begin, end, name, x);
+ abort();
+ }
+ return x;
+}
+
+/* not sure we should even define. is for debugging. */
+void klee_print_expr(const char *msg, ...) { }
+
+void klee_set_forking(unsigned enable) { }
Added: klee/trunk/runtime/klee-libc/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/Makefile (added)
+++ klee/trunk/runtime/klee-libc/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+#===-- runtime/klee-libc/Makefile --------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=klee-libc
+DONT_BUILD_RELINKED=1
+BYTECODE_LIBRARY=1
+# Don't strip debug info from the module.
+DEBUG_RUNTIME=1
+NO_PEDANTIC=1
+
+include $(LEVEL)/Makefile.common
Propchange: klee/trunk/runtime/klee-libc/Makefile
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/runtime/klee-libc/__cxa_atexit.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/__cxa_atexit.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/__cxa_atexit.c (added)
+++ klee/trunk/runtime/klee-libc/__cxa_atexit.c Wed May 20 23:36:41 2009
@@ -0,0 +1,49 @@
+//===-- __cxa_atexit.c ----------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/klee.h"
+
+#define MAX_ATEXIT 128
+
+static struct {
+ void (*fn)(void*);
+ void *arg;
+ void *dso_handle;
+} AtExit[MAX_ATEXIT];
+static unsigned NumAtExit = 0;
+
+static void RunAtExit(void) __attribute__((destructor));
+static void RunAtExit(void) {
+ unsigned i;
+
+ for (i=0; i<NumAtExit; ++i)
+ AtExit[i].fn(AtExit[i].arg);
+}
+
+int __cxa_atexit(void (*fn)(void*),
+ void *arg,
+ void *dso_handle) {
+ klee_warning_once("FIXME: __cxa_atexit being ignored");
+
+ /* Better to just report an error here than return 1 (the defined
+ * semantics).
+ */
+ if (NumAtExit == MAX_ATEXIT)
+ klee_report_error(__FILE__,
+ __LINE__,
+ "__cxa_atexit: no room in array!",
+ "exec");
+
+ AtExit[NumAtExit].fn = fn;
+ AtExit[NumAtExit].arg = arg;
+ ++NumAtExit;
+
+ return 0;
+}
+
Added: klee/trunk/runtime/klee-libc/abort.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/abort.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/abort.c (added)
+++ klee/trunk/runtime/klee-libc/abort.c Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+//===-- abort.c -----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+#include "klee/klee.h"
+
+void abort(void) {
+ klee_abort();
+}
Added: klee/trunk/runtime/klee-libc/atexit.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/atexit.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/atexit.c (added)
+++ klee/trunk/runtime/klee-libc/atexit.c Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+//===-- atexit.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int __cxa_atexit(void (*fn)(void*),
+ void *arg,
+ void *dso_handle);
+
+int atexit(void (*fn)(void)) {
+ return __cxa_atexit((void(*)(void*)) fn, 0, 0);
+}
Added: klee/trunk/runtime/klee-libc/atoi.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/atoi.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/atoi.c (added)
+++ klee/trunk/runtime/klee-libc/atoi.c Wed May 20 23:36:41 2009
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdlib.h>
+
+int atoi(const char *str) {
+ return (int)strtol(str, (char **)NULL, 10);
+}
Added: klee/trunk/runtime/klee-libc/calloc.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/calloc.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/calloc.c (added)
+++ klee/trunk/runtime/klee-libc/calloc.c Wed May 20 23:36:41 2009
@@ -0,0 +1,46 @@
+//===-- calloc.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+#include <string.h>
+
+// DWD - I prefer to be internal
+#if 0
+void *calloc(size_t nmemb, size_t size) {
+ unsigned nbytes = nmemb * size;
+ void *addr = malloc(nbytes);
+ if(addr)
+ memset(addr, 0, nbytes);
+ return addr;
+}
+// Always reallocate.
+void *realloc(void *ptr, size_t nbytes) {
+ if(!ptr)
+ return malloc(nbytes);
+
+ if(!nbytes) {
+ free(ptr);
+ return 0;
+ }
+
+ unsigned copy_nbytes = klee_get_obj_size(ptr);
+ //printf("REALLOC: current object = %d bytes!\n", copy_nbytes);
+
+ void *addr = malloc(nbytes);
+ if(addr) {
+ // shrinking
+ if(copy_nbytes > nbytes)
+ copy_nbytes = nbytes;
+ //printf("REALLOC: copying = %d bytes!\n", copy_nbytes);
+ memcpy(addr, ptr, copy_nbytes);
+ free(ptr);
+ }
+ return addr;
+}
+#endif
Added: klee/trunk/runtime/klee-libc/htonl.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/htonl.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/htonl.c (added)
+++ klee/trunk/runtime/klee-libc/htonl.c Wed May 20 23:36:41 2009
@@ -0,0 +1,49 @@
+//===-- htonl.c -----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdint.h>
+
+#undef htons
+#undef htonl
+#undef ntohs
+#undef ntohl
+
+// Make sure we can recognize the endianness.
+#if (!defined(BYTE_ORDER) || !defined(BIG_ENDIAN) || !defined(LITTLE_ENDIAN))
+#error "Unknown platform endianness!"
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+uint16_t htons(uint16_t v) {
+ return (v >> 8) | (v << 8);
+}
+uint32_t htonl(uint32_t v) {
+ return htons(v >> 16) | (htons((uint16_t) v) << 16);
+}
+
+#else
+
+uint16_t htons(uint16_t v) {
+ return v;
+}
+uint32_t htonl(uint32_t v) {
+ return v;
+}
+
+#endif
+
+uint16_t ntohs(uint32_t v) {
+ return htons(v);
+}
+uint32_t ntohl(uint32_t v) {
+ return htonl(v);
+}
Added: klee/trunk/runtime/klee-libc/klee-choose.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/klee-choose.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/klee-choose.c (added)
+++ klee/trunk/runtime/klee-libc/klee-choose.c Wed May 20 23:36:41 2009
@@ -0,0 +1,20 @@
+//===-- klee-choose.c -----------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/klee.h"
+
+unsigned klee_choose(unsigned n) {
+ unsigned x;
+ klee_make_symbolic(&x, sizeof x);
+
+ // NB: this will *not* work if they don't compare to n values.
+ if(x >= n)
+ klee_silent_exit(0);
+ return x;
+}
Added: klee/trunk/runtime/klee-libc/memchr.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/memchr.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/memchr.c (added)
+++ klee/trunk/runtime/klee-libc/memchr.c Wed May 20 23:36:41 2009
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+void *
+memchr(s, c, n)
+ const void *s;
+ int c;
+ size_t n;
+{
+ if (n != 0) {
+ const unsigned char *p = s;
+
+ do {
+ if (*p++ == c)
+ return ((void *)(p - 1));
+ } while (--n != 0);
+ }
+ return (NULL);
+}
Added: klee/trunk/runtime/klee-libc/memcmp.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/memcmp.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/memcmp.c (added)
+++ klee/trunk/runtime/klee-libc/memcmp.c Wed May 20 23:36:41 2009
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+/*
+ * Compare memory regions.
+ */
+int memcmp(const void *s1, const void *s2, size_t n) {
+ if (n != 0) {
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ do {
+ if (*p1++ != *p2++) {
+ return (*--p1 - *--p2);
+ }
+ } while (--n != 0);
+ }
+ return (0);
+}
Added: klee/trunk/runtime/klee-libc/memcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/memcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/memcpy.c (added)
+++ klee/trunk/runtime/klee-libc/memcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+//===-- memcpy.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memcpy(void *destaddr, void const *srcaddr, unsigned int len) {
+ char *dest = destaddr;
+ char const *src = srcaddr;
+
+ while (len-- > 0)
+ *dest++ = *src++;
+ return destaddr;
+}
Added: klee/trunk/runtime/klee-libc/memmove.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/memmove.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/memmove.c (added)
+++ klee/trunk/runtime/klee-libc/memmove.c Wed May 20 23:36:41 2009
@@ -0,0 +1,28 @@
+//===-- memmove.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memmove(void *dst, const void *src, size_t count) {
+ char *a = dst;
+ const char *b = src;
+
+ if (src == dst)
+ return dst;
+
+ if (src>dst) {
+ while (count--) *a++ = *b++;
+ } else {
+ a+=count-1;
+ b+=count-1;
+ while (count--) *a-- = *b--;
+ }
+
+ return dst;
+}
Added: klee/trunk/runtime/klee-libc/mempcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/mempcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/mempcpy.c (added)
+++ klee/trunk/runtime/klee-libc/mempcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,19 @@
+//===-- mempcpy.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *mempcpy(void *destaddr, void const *srcaddr, unsigned int len) {
+ char *dest = destaddr;
+ char const *src = srcaddr;
+
+ while (len-- > 0)
+ *dest++ = *src++;
+ return dest;
+}
Added: klee/trunk/runtime/klee-libc/memset.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/memset.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/memset.c (added)
+++ klee/trunk/runtime/klee-libc/memset.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- memset.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+void *memset(void * dst, int s, size_t count) {
+ char * a = dst;
+ while (count-- > 0)
+ *a++ = s;
+ return dst;
+}
Added: klee/trunk/runtime/klee-libc/putchar.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/putchar.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/putchar.c (added)
+++ klee/trunk/runtime/klee-libc/putchar.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- putchar.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <unistd.h>
+
+int putchar(int c) {
+ char x = c;
+ write(1, &x, 1);
+ return 1;
+}
Added: klee/trunk/runtime/klee-libc/stpcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/stpcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/stpcpy.c (added)
+++ klee/trunk/runtime/klee-libc/stpcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1999
+ * David E. O'Brien
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+/* Defeat object checking stuff. */
+#undef stpcpy
+
+char *
+stpcpy(char * to, const char * from)
+{
+
+ for (; (*to = *from); ++from, ++to);
+ return(to);
+}
Added: klee/trunk/runtime/klee-libc/strcat.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strcat.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strcat.c (added)
+++ klee/trunk/runtime/klee-libc/strcat.c Wed May 20 23:36:41 2009
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+/* Defeat object checking stuff. */
+#undef strcat
+
+char * strcat(char * s, const char * append) {
+ char *save = s;
+
+ for (; *s; ++s)
+ ;
+ while ((*s++ = *append++))
+ ;
+ return(save);
+}
Added: klee/trunk/runtime/klee-libc/strchr.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strchr.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strchr.c (added)
+++ klee/trunk/runtime/klee-libc/strchr.c Wed May 20 23:36:41 2009
@@ -0,0 +1,23 @@
+//===-- strchr.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+char *strchr(const char *p, int ch) {
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c) {
+ return ((char *)p);
+ } else if (*p == '\0') {
+ return 0;
+ }
+ }
+ /* NOTREACHED */
+ return 0;
+}
Added: klee/trunk/runtime/klee-libc/strcmp.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strcmp.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strcmp.c (added)
+++ klee/trunk/runtime/klee-libc/strcmp.c Wed May 20 23:36:41 2009
@@ -0,0 +1,14 @@
+//===-- strcmp.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int strcmp(const char *a, const char *b) {
+ while (*a && *a == *b)
+ ++a, ++b;
+ return *a - *b;
+}
Added: klee/trunk/runtime/klee-libc/strcoll.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strcoll.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strcoll.c (added)
+++ klee/trunk/runtime/klee-libc/strcoll.c Wed May 20 23:36:41 2009
@@ -0,0 +1,15 @@
+//===-- strcoll.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+// according to the manpage, this is equiv in the POSIX/C locale.
+int strcoll(const char *s1, const char *s2) {
+ return strcmp(s1,s2);
+}
Added: klee/trunk/runtime/klee-libc/strcpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strcpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strcpy.c (added)
+++ klee/trunk/runtime/klee-libc/strcpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- strcpy.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+char *strcpy(char *to, const char *from) {
+ char *start = to;
+
+ while ((*to = *from))
+ ++to, ++from;
+
+ return start;
+}
Added: klee/trunk/runtime/klee-libc/strlen.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strlen.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strlen.c (added)
+++ klee/trunk/runtime/klee-libc/strlen.c Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+//===-- strlen.c ----------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+size_t strlen(const char *str) {
+ const char *s = str;
+ while (*s)
+ ++s;
+ return s - str;
+}
Added: klee/trunk/runtime/klee-libc/strncmp.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strncmp.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strncmp.c (added)
+++ klee/trunk/runtime/klee-libc/strncmp.c Wed May 20 23:36:41 2009
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+
+ if (n == 0)
+ return (0);
+ do {
+ if (*s1 != *s2++)
+ return (*(unsigned char *)s1 -
+ *(unsigned char *)(s2 - 1));
+ if (*s1++ == 0)
+ break;
+ } while (--n != 0);
+ return (0);
+}
Added: klee/trunk/runtime/klee-libc/strncpy.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strncpy.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strncpy.c (added)
+++ klee/trunk/runtime/klee-libc/strncpy.c Wed May 20 23:36:41 2009
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+/*
+ * Copy src to dst, truncating or null-padding to always copy n bytes.
+ * Return dst.
+ */
+char * strncpy(char * dst, const char * src, size_t n)
+{
+ if (n != 0) {
+ char *d = dst;
+ const char *s = src;
+
+ do {
+ if ((*d++ = *s++) == 0) {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ *d++ = 0;
+ break;
+ }
+ } while (--n != 0);
+ }
+ return (dst);
+}
Added: klee/trunk/runtime/klee-libc/strrchr.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strrchr.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strrchr.c (added)
+++ klee/trunk/runtime/klee-libc/strrchr.c Wed May 20 23:36:41 2009
@@ -0,0 +1,21 @@
+//===-- strrchr.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+char *strrchr(const char *t, int c) {
+ char ch;
+ const char *l=0;
+
+ ch = c;
+ for (;;) {
+ if (*t == ch) l=t; if (!*t) return (char*)l; ++t;
+ }
+ return (char*)l;
+}
Added: klee/trunk/runtime/klee-libc/strtol.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strtol.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strtol.c (added)
+++ klee/trunk/runtime/klee-libc/strtol.c Wed May 20 23:36:41 2009
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(const char * nptr, char ** endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
Added: klee/trunk/runtime/klee-libc/strtoul.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/strtoul.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/strtoul.c (added)
+++ klee/trunk/runtime/klee-libc/strtoul.c Wed May 20 23:36:41 2009
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char * nptr, char ** endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
Added: klee/trunk/runtime/klee-libc/tolower.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/tolower.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/tolower.c (added)
+++ klee/trunk/runtime/klee-libc/tolower.c Wed May 20 23:36:41 2009
@@ -0,0 +1,14 @@
+//===-- tolower.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int tolower(int ch) {
+ if ( (unsigned int)(ch - 'A') < 26u )
+ ch -= 'A' - 'a';
+ return ch;
+}
Added: klee/trunk/runtime/klee-libc/toupper.c
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/runtime/klee-libc/toupper.c?rev=72205&view=auto
==============================================================================
--- klee/trunk/runtime/klee-libc/toupper.c (added)
+++ klee/trunk/runtime/klee-libc/toupper.c Wed May 20 23:36:41 2009
@@ -0,0 +1,14 @@
+//===-- toupper.c ---------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int toupper(int ch) {
+ if ( (unsigned int)(ch - 'a') < 26u )
+ ch += 'A' - 'a';
+ return ch;
+}
Added: klee/trunk/scripts/IStatsMerge.py
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/scripts/IStatsMerge.py?rev=72205&view=auto
==============================================================================
--- klee/trunk/scripts/IStatsMerge.py (added)
+++ klee/trunk/scripts/IStatsMerge.py Wed May 20 23:36:41 2009
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+
+from __future__ import division
+
+import sys, os
+
+class MergeError(Exception):
+ pass
+
+def checkAssemblies(directories):
+ def read(d):
+ try:
+ return open(os.path.join(d,'assembly.ll')).read()
+ except:
+ raise MergeError("unable to open assembly for: %s"%(`d`,))
+
+ reference = read(directories[0])
+ for d in directories[1:]:
+ if reference != read(d):
+ return False
+ return True
+
+def allEqual(l):
+ return not [i for i in l if i!=l[0]]
+
+def merge(inputs, output, outputDir):
+ inputs = [[None,iter(i)] for i in inputs]
+
+ def getLine(elt):
+ la,i = elt
+ if la is None:
+ try:
+ ln = i.next()
+ except StopIteration:
+ ln = None
+ except:
+ raise MergeError("unexpected IO error")
+ return ln
+ else:
+ elt[0] = None
+ return la
+ def getLines():
+ return map(getLine,inputs)
+ def putback(ln,elt):
+ assert elt[0] is None
+ elt[0] = ln
+
+ events = None
+
+ # read header (up to ob=)
+ while 1:
+ lns = getLines()
+ ln = lns[0]
+ if ln.startswith('ob='):
+ if [l for l in lns if not l.startswith('ob=')]:
+ raise MergeError("headers differ")
+ output.write('ob=%s\n'%(os.path.join(outputDir,'assembly.ll'),))
+ break
+ else:
+ if ln.startswith('positions:'):
+ if ln!='positions: instr line\n':
+ raise MergeError("unexpected 'positions' directive")
+ elif ln.startswith('events:'):
+ events = ln[len('events: '):].strip().split(' ')
+ if not allEqual(lns):
+ raise MergeError("headers differ")
+ output.write(ln)
+
+ if events is None:
+ raise MergeError('missing events directive')
+ boolTypes = set(['Icov','Iuncov'])
+ numEvents = len(events)
+ eventTypes = [e in boolTypes for e in events]
+
+ def mergeStats(datas):
+ if not allEqual([d[:2] for d in datas]):
+ raise MergeError("instruction or line specifications differ")
+ elif [d for d in datas if len(d)!=numEvents+2]:
+ raise MergeError("statistics differ in event counts")
+
+ result = [datas[0][0],datas[0][1]]
+ for i,ev in enumerate(events):
+ s = sum([d[i+2] for d in datas])
+ if ev=='Icov':
+ result.append(max([d[i+2] for d in datas])) # true iff any are non-zero
+ elif ev=='Iuncov':
+ result.append(min([d[i+2] for d in datas])) # true iff any are non-zero
+ else:
+ result.append(s)
+ return result
+
+ def readCalls():
+ results = {}
+ for elt in inputs:
+ while 1:
+ ln = getLine(elt)
+ if ln is not None and (ln.startswith('cfl=') or ln.startswith('cfn=')):
+ if ln.startswith('cfl='):
+ cfl = ln
+ cfn = getLine(elt)
+ if not cfn.startswith('cfn='):
+ raise MergeError("unexpected cfl directive without function")
+ else:
+ cfl = None
+ cfn = ln
+ target = getLine(elt)
+ if not target.startswith('calls='):
+ raise MergeError("unexpected cfn directive with calls")
+ stat = map(int,getLine(elt).strip().split(' '))
+ key = target
+ existing = results.get(target)
+ if existing is None:
+ results[key] = [cfl,cfn,target,stat]
+ else:
+ if existing[0]!=cfl or existing[1]!=cfn:
+ raise MergeError("multiple call descriptions for a single target")
+ existing[3] = mergeStats([existing[3],stat])
+ else:
+ putback(ln, elt)
+ break
+ return results
+
+ # read statistics
+ while 1:
+ lns = getLines()
+ ln = lns[0]
+ if ln is None:
+ if not allEqual(lns):
+ raise MergeError("unexpected end of input")
+ break
+ elif ln.startswith('fn') or ln.startswith('fl'):
+ if not allEqual(lns):
+ raise MergeError("files differ")
+ output.write(ln)
+ else:
+ # an actual statistic
+ data = [map(int,ln.strip().split(' ')) for ln in lns]
+ print >>output,' '.join(map(str,mergeStats(data)))
+
+ # read any associated calls
+ for cfl,cfn,calls,stat in readCalls().values():
+ if cfl is not None:
+ output.write(cfl)
+ output.write(cfn)
+ output.write(calls)
+ print >>output,' '.join(map(str,stat))
+
+def main(args):
+ from optparse import OptionParser
+ op = OptionParser("usage: %prog [options] directories+ output")
+ opts,args = op.parse_args()
+
+ output = args.pop()
+ directories = args
+
+ if len(directories)<=1:
+ op.error("incorrect number of arguments")
+
+ print 'Merging:',', '.join(directories)
+ print 'Into:',output
+
+ if not checkAssemblies(directories):
+ raise MergeError("executables differ")
+
+ if not os.path.exists(output):
+ os.mkdir(output)
+
+ assembly = open(os.path.join(directories[0],'assembly.ll')).read()
+ open(os.path.join(output,'assembly.ll'),'w').write(assembly)
+
+ inputs = [open(os.path.join(d,'run.istats')) for d in directories]
+ merge(inputs, open(os.path.join(output,'run.istats'),'w'), output)
+
+if __name__=='__main__':
+ main(sys.argv)
Propchange: klee/trunk/scripts/IStatsMerge.py
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/scripts/IStatsSum.py
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/scripts/IStatsSum.py?rev=72205&view=auto
==============================================================================
--- klee/trunk/scripts/IStatsSum.py (added)
+++ klee/trunk/scripts/IStatsSum.py Wed May 20 23:36:41 2009
@@ -0,0 +1,129 @@
+#!/usr/bin/python
+
+from __future__ import division
+
+import sys, os
+
+def getSummary(input):
+ inputs = [[None,iter(open(input))]]
+ def getLine(elt):
+ la,i = elt
+ if la is None:
+ try:
+ ln = i.next()
+ except StopIteration:
+ ln = None
+ except:
+ raise ValueError("unexpected IO error")
+ return ln
+ else:
+ elt[0] = None
+ return la
+ def getLines():
+ return map(getLine,inputs)
+ def putback(ln,elt):
+ assert elt[0] is None
+ elt[0] = ln
+
+ events = None
+
+ # read header (up to ob=)
+ while 1:
+ lns = getLines()
+ ln = lns[0]
+ if ln.startswith('ob='):
+ break
+ else:
+ if ln.startswith('positions:'):
+ if ln!='positions: instr line\n':
+ raise ValueError("unexpected 'positions' directive")
+ elif ln.startswith('events:'):
+ events = ln[len('events: '):].strip().split(' ')
+
+ if events is None:
+ raise ValueError('missing events directive')
+ boolTypes = set(['Icov','Iuncov'])
+ numEvents = len(events)
+ eventTypes = [e in boolTypes for e in events]
+
+ def readCalls():
+ results = {}
+ for elt in inputs:
+ while 1:
+ ln = getLine(elt)
+ if ln is not None and (ln.startswith('cfl=') or ln.startswith('cfn=')):
+ if ln.startswith('cfl='):
+ cfl = ln
+ cfn = getLine(elt)
+ if not cfn.startswith('cfn='):
+ raise ValueError("unexpected cfl directive without function")
+ else:
+ cfl = None
+ cfn = ln
+ target = getLine(elt)
+ if not target.startswith('calls='):
+ raise ValueError("unexpected cfn directive with calls")
+ stat = map(int,getLine(elt).strip().split(' '))
+ key = target
+ existing = results.get(target)
+ if existing is None:
+ results[key] = [cfl,cfn,target,stat]
+ else:
+ if existing[0]!=cfl or existing[1]!=cfn:
+ raise ValueError("multiple call descriptions for a single target")
+ existing[3] = mergeStats([existing[3],stat])
+ else:
+ putback(ln, elt)
+ break
+ return results
+
+ summed = [0]*len(events)
+
+ # read statistics
+ while 1:
+ lns = getLines()
+ ln = lns[0]
+ if ln is None:
+ break
+ elif ln.startswith('fn') or ln.startswith('fl'):
+ pass
+ elif ln.strip():
+ # an actual statistic
+ data = [map(int,ln.strip().split(' ')) for ln in lns][0]
+ summed = map(lambda a,b: a+b, data[2:], summed)
+
+ # read any associated calls
+ for cfl,cfn,calls,stat in readCalls().values():
+ pass
+
+ return events,summed
+
+def main(args):
+ from optparse import OptionParser
+ op = OptionParser("usage: %prog [options] file")
+ opts,args = op.parse_args()
+
+ total = {}
+ for i in args:
+ events,summed = getSummary(i)
+ for e,s in zip(events,summed):
+ total[e] = total.get(e,[0,0])
+ total[e][0] += s
+ total[e][1] += 1
+ print '-- %s --'%(i,)
+ items = zip(events,summed)
+ items.sort()
+ for e,s in items:
+ print '%s: %s'%(e,s)
+
+ print '-- totals --'
+ items = total.items()
+ table = []
+ for e,(s,N) in items:
+ table.append((str(e),str(s),str(N),str(s//N)))
+ w = map(lambda l: max(map(len,l)), zip(*table))
+ for (a,b,c,d) in table:
+ print '%-*s: %*s (in %*s files, avg: %*s)'%(w[0],a,w[1],b,w[2],c,w[3],d)
+
+if __name__=='__main__':
+ main(sys.argv)
Propchange: klee/trunk/scripts/IStatsSum.py
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/scripts/PrintStats.py
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/scripts/PrintStats.py?rev=72205&view=auto
==============================================================================
--- klee/trunk/scripts/PrintStats.py (added)
+++ klee/trunk/scripts/PrintStats.py Wed May 20 23:36:41 2009
@@ -0,0 +1,231 @@
+#!/usr/bin/python
+
+from __future__ import division
+
+import sys
+import os
+
+def getFile(dir):
+ return os.path.join(dir,'run.stats')
+
+def getLastRecord(dir):
+ f = open(getFile(dir))
+ try:
+ f.seek(-1024, 2)
+ except IOError:
+ pass # at beginning?
+ for ln in f.read(1024).split('\n')[::-1]:
+ ln = ln.strip()
+ if ln.startswith('(') and ln.endswith(')'):
+ if '(' in ln[1:]:
+ print >>sys.stderr, 'WARNING: corrupted line in file, out of disk space?'
+ ln = ln[ln.index('(',1):]
+ return eval(ln)
+ raise IOError
+
+
+class LazyEvalList:
+ def __init__(self, lines):
+ self.lines = lines
+
+ def __getitem__(self, index):
+ item = self.lines[index]
+ if isinstance(item,str):
+ item = self.lines[index] = eval(item)
+ return item
+
+ def __len__(self):
+ return len(self.lines)
+
+
+def getMatchedRecord(data,reference,key):
+ refKey = key(reference)
+ lo = 1 # header
+ hi = len(data)-1
+ while lo<hi:
+ mid = (lo+hi)//2
+ if key(data[mid])<=refKey:
+ lo = mid + 1
+ else:
+ hi = mid
+ return data[lo]
+
+
+def stripCommonPathPrefix(table, col):
+ paths = map(os.path.normpath, [row[col] for row in table])
+ pathElts = [p.split('/') for p in paths]
+ zipped = zip(*pathElts)
+ idx = 0
+ for idx,elts in enumerate(zipped):
+ if len(set(elts))>1:
+ break
+ paths = ['/'.join(elts[idx:]) for elts in pathElts]
+ for i,row in enumerate(table):
+ table[i] = row[:col] + (paths[i],) + row[col+1:]
+
+
+def getKeyIndex(keyName,labels):
+ def normalizedKey(key):
+ if key.endswith("(#)") or key.endswith("(%)") or key.endswith("(s)"):
+ key = key[:-3]
+ return key.lower()
+
+ keyIndex = None
+ for i,title in enumerate(labels):
+ if normalizedKey(title)==normalizedKey(keyName):
+ keyIndex = i
+ break
+ else:
+ raise ValueError,'invalid keyName to sort by: %s'%`keyName`
+ return keyIndex
+
+
+def sortTable(table, labels, keyName, ascending=False):
+ indices = range(len(table))
+ keyIndex = getKeyIndex(keyName,labels)
+ indices.sort(key = lambda n: table[n][keyIndex])
+ if not ascending:
+ indices.reverse()
+ table[:] = [table[n] for n in indices]
+
+
+def printTable(table):
+ def strOrNone(ob):
+ if ob is None:
+ return ''
+ elif isinstance(ob,float):
+ return '%.2f'%ob
+ else:
+ return str(ob)
+ def printRow(row):
+ if row is None:
+ print header
+ else:
+ out.write('|')
+ for j,elt in enumerate(row):
+ if j:
+ out.write(' %*s |'%(widths[j],elt))
+ else:
+ out.write(' %-*s |'%(widths[j],elt))
+ out.write('\n')
+ maxLen = max([len(r) for r in table if r])
+ for i,row in enumerate(table):
+ if row:
+ table[i] = row + (None,)*(maxLen-len(row))
+ table = [row and map(strOrNone,row) or None for row in table]
+ tableLens = [map(len,row) for row in table if row]
+ from pprint import pprint
+ widths = map(max, zip(*tableLens))
+ out = sys.stdout
+ header = '-'*(sum(widths) + maxLen*3 + 1)
+ map(printRow, table)
+
+
+def main(args):
+ from optparse import OptionParser
+ op = OptionParser(usage="usage: %prog [options] directories*",
+ epilog=
+ "LEGEND "
+ "------ "
+ "Instrs: Number of executed instructions "
+ "Time: Total wall time (s) "
+ "ICov: Instruction coverage in the LLVM bitcode (%) "
+ "BCov: Branch coverage in the LLVM bitcode (%) "
+ "ICount: Total static instructions in the LLVM bitcode "
+ "Solver: Time spent in the constraint solver (%) "
+ "States: Number of currently active states "
+ "Mem: Megabytes of memory currently used "
+ "Queries: Number of queries issued to STP "
+ "AvgQC: Average number of query constructs per query "
+ "Tcex: Time spent in the counterexample caching code (%) "
+ "Tfork: Time spent forking (%) ")
+
+ op.add_option('', '--print-more', dest='printMore',
+ action='store_true', default=False,
+ help='Print extra information (needed when monitoring an ongoing run).')
+ op.add_option('', '--print-all', dest='printAll',
+ action='store_true', default=False,
+ help='Print all available information.')
+ op.add_option('','--sort-by', dest='sortBy',
+ help='key value to sort by, e.g. --sort-by=Instrs')
+ op.add_option('','--ascending', dest='ascending',
+ action='store_true', default=False,
+ help='sort in ascending order (default is descending)')
+ op.add_option('','--compare-by', dest='compBy',
+ help="key value on which to compare runs to the reference one (which is the first one). E.g., --compare-by=Instrs shows how each run compares to the reference run after executing the same number of instructions as the reference run. If a run hasn't executed as many instructions as the reference one, we simply print the statistics at the end of that run.")
+ opts,dirs = op.parse_args()
+
+ actualDirs = []
+ for dir in dirs:
+ if os.path.exists(os.path.join(dir,'info')):
+ actualDirs.append(dir)
+ else:
+ for root,dirs,_ in os.walk(dir):
+ for d in dirs:
+ p = os.path.join(root,d)
+ if os.path.exists(os.path.join(p,'info')):
+ actualDirs.append(p)
+ dirs = actualDirs
+
+ summary = []
+
+ if (opts.printAll):
+ labels = ('Path','Instrs','Time(s)','ICov(%)','BCov(%)','ICount','Solver(%)', 'States', 'Mem(MB)', 'Queries', 'AvgQC', 'Tcex(%)', 'Tfork(%)')
+ elif (opts.printMore):
+ labels = ('Path','Instrs','Time(s)','ICov(%)','BCov(%)','ICount','Solver(%)', 'States', 'Mem(MB)')
+ else:
+ labels = ('Path','Instrs','Time(s)','ICov(%)','BCov(%)','ICount','Solver(%)')
+
+
+ def addRecord(Path,rec):
+ (I,BFull,BPart,BTot,T,St,Mem,QTot,QCon,NObjs,Treal,SCov,SUnc,QT,Ts,Tcex,Tf) = rec
+ Mem=Mem/1024./1024.
+ AvgQC = int(QCon/max(1,QTot))
+ if (opts.printAll):
+ table.append((Path, I, Treal, 100.*SCov/(SCov+SUnc), 100.*(2*BFull+BPart)/(2.*BTot),
+ SCov+SUnc, 100.*Ts/Treal, St, Mem, QTot, AvgQC, 100.*Tcex/Treal, 100.*Tf/Treal))
+ elif (opts.printMore):
+ table.append((Path, I, Treal, 100.*SCov/(SCov+SUnc), 100.*(2*BFull+BPart)/(2.*BTot),
+ SCov+SUnc, 100.*Ts/Treal, St, Mem))
+ else:
+ table.append((Path, I, Treal, 100.*SCov/(SCov+SUnc), 100.*(2*BFull+BPart)/(2.*BTot),
+ SCov+SUnc, 100.*Ts/Treal))
+
+ def addRow(Path,data):
+ data = tuple(data[:17]) + (None,)*(17-len(data))
+ addRecord(Path,data)
+ if not summary:
+ summary[:] = list(data)
+ else:
+ summary[:] = [(a+b) for a,b in zip(summary,data)]
+
+ datas = [(dir,LazyEvalList(list(open(getFile(dir))))) for dir in dirs]
+ reference = datas[0][1][-1]
+
+ table = []
+
+ for dir,data in datas:
+ try:
+ if opts.compBy:
+ addRow(dir,getMatchedRecord(data,reference,lambda f: f[getKeyIndex(opts.compBy,labels)-1]))
+ else:
+ addRow(dir, data[len(data)-1]) #getLastRecord(dir))
+ except IOError:
+ print 'Unable to open: ',dir
+ continue
+
+ stripCommonPathPrefix(table, 0)
+ if opts.sortBy:
+ sortTable(table, labels, opts.sortBy, opts.ascending)
+ if not table:
+ sys.exit(1)
+ elif len(table)>1:
+ table.append(None)
+ addRecord('Total (%d)'%(len(table)-1,),summary)
+ table[0:0] = [None,labels,None]
+ table.append(None)
+ printTable(table)
+
+
+if __name__=='__main__':
+ main(sys.argv)
Propchange: klee/trunk/scripts/PrintStats.py
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/scripts/klee-control
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/scripts/klee-control?rev=72205&view=auto
==============================================================================
--- klee/trunk/scripts/klee-control (added)
+++ klee/trunk/scripts/klee-control Wed May 20 23:36:41 2009
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+
+import os, signal, popen2
+
+def getPID(dir):
+ f = open(os.path.join(dir,'info'))
+ for ln in f.readlines():
+ if ln.startswith('PID: '):
+ return int(ln[5:])
+ return None
+
+def execCmd(pid, gdbCmd, opts):
+ cmd = ("gdb " +
+ "--batch " +
+ "--pid=%d " +
+ "--eval-command=\"%s\" " +
+ "--eval-command=detach")%(pid,gdbCmd)
+ cout,cin = popen2.popen2(cmd)
+ cin.close()
+ return cout.read()
+
+def main():
+ from optparse import OptionParser
+ op = OptionParser("usage: %prog <PID | test directory>")
+ op.add_option('','--backtrace', dest='backtrace',
+ action='store_true', default=False)
+ op.add_option('-s','--stop-forking', dest='stopForking',
+ action='store_true', default=False)
+ op.add_option('-H','--halt-execution', dest='haltExecution',
+ action='store_true', default=False)
+ op.add_option('-d','--dump-states', dest='dumpStates',
+ action='store_true', default=False)
+ op.add_option('-t','--dump-tree', dest='dumpTree',
+ action='store_true', default=False)
+ op.add_option('-i','--int', dest='int',
+ action='store_true', default=False)
+ op.add_option('-k','--kill', dest='kill',
+ action='store_true', default=False)
+ op.add_option('','--print-pid', dest='printPid',
+ action='store_true', default=False)
+ op.add_option('','--print-ticks', dest='printTicks',
+ action='store_true', default=False)
+ opts,args = op.parse_args()
+
+ if len(args) != 1:
+ op.error("invalid arguments")
+
+ try:
+ pid = int(args[0])
+ except:
+ pid = None
+
+ if pid is None:
+ try:
+ pid = getPID(args[0])
+ except:
+ pid = None
+
+ if pid is None:
+ op.error("unable to determine PID (bad pid or test directory)")
+
+ if opts.printPid:
+ print pid
+ return
+ print 'pid: %d'%pid
+ if opts.backtrace:
+ execCmd(pid, 'bt', opts)
+ if opts.dumpStates:
+ execCmd(pid, "p dumpStates = 1", opts)
+ if opts.dumpTree:
+ execCmd(pid, "p dumpPTree = 1", opts)
+ if opts.stopForking:
+ execCmd(pid, 'p stop_forking()', opts)
+ if opts.haltExecution:
+ execCmd(pid, 'p halt_execution()', opts)
+ if opts.printTicks:
+ res = execCmd(pid, 'p timerTicks', opts)
+ lns = res.split('\n')
+ for ln in lns:
+ if ln.startswith('$1') and '=' in ln:
+ print ln.split('=',1)[1].strip()
+ if opts.int:
+ os.kill(pid, signal.SIGINT)
+ if opts.kill:
+ os.kill(pid, signal.SIGKILL)
+
+if __name__=='__main__':
+ main()
+
Propchange: klee/trunk/scripts/klee-control
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/scripts/objdump
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/scripts/objdump?rev=72205&view=auto
==============================================================================
--- klee/trunk/scripts/objdump (added)
+++ klee/trunk/scripts/objdump Wed May 20 23:36:41 2009
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+
+"""
+An objdump wrapper for use with klee & kcachegrind.
+
+This allows klee to output instruction level statistic information which
+kcachegrind can then display by intercepting kcachegrind's calls to objdump
+and returning the LLVM instructions in a format that it can parse.
+"""
+
+import os, sys
+
+kActualObjdump = os.path.join(os.path.dirname(__file__),'objdump.actual')
+if not os.path.exists(kActualObjdump):
+ for path in ['/usr/bin','/usr/local/bin']:
+ p = os.path.join(path,'objdump')
+ if os.path.exists(p):
+ kActualObjdump = p
+
+def fakeObjdumpOutput(file, start, end):
+ print 'Using fake objdump output:\n\n'
+
+ lines = open(file).readlines()
+ for i in range(max(0,start-1),min(end-1,len(lines))):
+ print '%x: _ %s'%(i+1,lines[i])
+
+def main(args):
+ # exact pattern match kcachegrind's calling sequence
+ if (len(args)>=6 and
+ args[1]=='-C' and
+ args[2]=='-d' and
+ args[3].startswith('--start-address=') and
+ args[4].startswith('--stop-address=') and
+ args[5].endswith('.ll')):
+ fakeObjdumpOutput(args[5], eval(args[3].split('=',1)[1]), eval(args[4].split('=',1)[1]))
+ else:
+ os.execv(kActualObjdump, args)
+ raise RuntimeError
+
+if __name__=='__main__':
+ main(sys.argv)
Propchange: klee/trunk/scripts/objdump
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/stp/AST/AST.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/AST.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/AST.cpp (added)
+++ klee/trunk/stp/AST/AST.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1587 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+#include "AST.h"
+namespace BEEV {
+ //some global variables that are set through commandline options. it
+ //is best that these variables remain global. Default values set
+ //here
+ //
+ //collect statistics on certain functions
+ bool stats = false;
+ //print DAG nodes
+ bool print_nodes = false;
+ //tentative global var to allow for variable activity optimization
+ //in the SAT solver. deprecated.
+ bool variable_activity_optimize = false;
+ //run STP in optimized mode
+ bool optimize = true;
+ //do sat refinement, i.e. underconstraint the problem, and feed to
+ //SAT. if this works, great. else, add a set of suitable constraints
+ //to re-constraint the problem correctly, and call SAT again, until
+ //all constraints have been added.
+ bool arrayread_refinement = true;
+ //flag to control write refinement
+ bool arraywrite_refinement = true;
+ //check the counterexample against the original input to STP
+ bool check_counterexample = false;
+ //construct the counterexample in terms of original variable based
+ //on the counterexample returned by SAT solver
+ bool construct_counterexample = true;
+ bool print_counterexample = false;
+ //if this option is true then print the way dawson wants using a
+ //different printer. do not use this printer.
+ bool print_arrayval_declaredorder = false;
+ //flag to decide whether to print "valid/invalid" or not
+ bool print_output = false;
+ //do linear search in the array values of an input array. experimental
+ bool linear_search = false;
+ //print the variable order chosen by the sat solver while it is
+ //solving.
+ bool print_sat_varorder = false;
+ //turn on word level bitvector solver
+ bool wordlevel_solve = true;
+ //turn off XOR flattening
+ bool xor_flatten = false;
+
+ //the smtlib parser has been turned on
+ bool smtlib_parser_enable = false;
+ //print the input back
+ bool print_STPinput_back = false;
+
+ //global BEEVMGR for the parser
+ BeevMgr * globalBeevMgr_for_parser;
+
+ void (*vc_error_hdlr)(const char* err_msg) = NULL;
+ /** This is reusable empty vector, for representing empty children arrays */
+ ASTVec _empty_ASTVec;
+ ////////////////////////////////////////////////////////////////
+ // ASTInternal members
+ ////////////////////////////////////////////////////////////////
+ /** Trivial but virtual destructor */
+ ASTInternal::~ASTInternal() { }
+
+ ////////////////////////////////////////////////////////////////
+ // ASTInterior members
+ ////////////////////////////////////////////////////////////////
+ /** Copy constructor */
+ // ASTInterior::ASTInterior(const ASTInterior &int_node)
+ // {
+ // _kind = int_node._kind;
+ // _children = int_node._children;
+ // }
+
+ /** Trivial but virtual destructor */
+ ASTInterior::~ASTInterior() { }
+
+ // FIXME: Darn it! I think this ends up copying the children twice!
+ /** Either return an old node or create it if it doesn't exist.
+ Note that nodes are physically allocated in the hash table. */
+
+ // There is an inelegance here that I don't know how to solve. I'd
+ // like to heap allocate and do some other initialization on keys only
+ // if they aren't in the hash table. It would be great if the
+ // "insert" method took a "creator" class so that I could do that
+ // between when it notices that the key is not there and when it
+ // inserts it. Alternatively, it would be great if I could insert the
+ // temporary key and replace it if it actually got inserted. But STL
+ // hash_set doesn't have the creator feature and paternalistically
+ // declares that keys are immutable, even though (it seems to me) that
+ // they could be mutated if the hash value and eq values did not
+ // change.
+
+ ASTInterior *BeevMgr::LookupOrCreateInterior(ASTInterior *n_ptr) {
+ ASTInteriorSet::iterator it;
+
+ if ((it = _interior_unique_table.find(n_ptr)) == _interior_unique_table.end()) {
+ // Make a new ASTInterior node
+ // We want (NOT alpha) always to have alpha.nodenum + 1.
+ if (n_ptr->GetKind() == NOT) {
+ n_ptr->SetNodeNum(n_ptr->GetChildren()[0].GetNodeNum()+1);
+ }
+ else {
+ n_ptr->SetNodeNum(NewNodeNum());
+ }
+ pair<ASTInteriorSet::const_iterator, bool> p = _interior_unique_table.insert(n_ptr);
+ return *(p.first);
+ }
+ else
+ // Delete the temporary node, and return the found node.
+ delete n_ptr;
+ return *it;
+ }
+
+ size_t ASTInterior::ASTInteriorHasher::operator() (const ASTInterior *int_node_ptr) const {
+ //size_t hashval = 0;
+ size_t hashval = ((size_t) int_node_ptr->GetKind());
+ const ASTVec &ch = int_node_ptr->GetChildren();
+ ASTVec::const_iterator iend = ch.end();
+ for (ASTVec::const_iterator i = ch.begin(); i != iend; i++) {
+ //Using "One at a time hash" by Bob Jenkins
+ hashval += i->Hash();
+ hashval += (hashval << 10);
+ hashval ^= (hashval >> 6);
+ }
+
+ hashval += (hashval << 3);
+ hashval ^= (hashval >> 11);
+ hashval += (hashval << 15);
+ return hashval;
+ //return hashval += ((size_t) int_node_ptr->GetKind());
+ }
+
+
+ void ASTInterior::CleanUp() {
+ // cout << "Deleting node " << this->GetNodeNum() << endl;
+ _bm._interior_unique_table.erase(this);
+ delete this;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // ASTNode members
+ ////////////////////////////////////////////////////////////////
+ //ASTNode constructors are inlined in AST.h
+ bool ASTNode::IsAlreadyPrinted() const {
+ BeevMgr &bm = GetBeevMgr();
+ return (bm.AlreadyPrintedSet.find(*this) != bm.AlreadyPrintedSet.end());
+ }
+
+ void ASTNode::MarkAlreadyPrinted() const {
+ // FIXME: Fetching BeevMgr is annoying. Can we put this in lispprinter class?
+ BeevMgr &bm = GetBeevMgr();
+ bm.AlreadyPrintedSet.insert(*this);
+ }
+
+ // Get the name from a symbol (char *). It's an error if kind != SYMBOL
+ const char * const ASTNode::GetName() const {
+ if (GetKind() != SYMBOL)
+ FatalError("GetName: Called GetName on a non-symbol: ", *this);
+ return ((ASTSymbol *) _int_node_ptr)->GetName();
+ }
+
+ // Print in lisp format
+ ostream &ASTNode::LispPrint(ostream &os, int indentation) const {
+ // Clear the PrintMap
+ BeevMgr& bm = GetBeevMgr();
+ bm.AlreadyPrintedSet.clear();
+ return LispPrint_indent(os, indentation);
+ }
+
+ // Print newline and indentation, then print the thing.
+ ostream &ASTNode::LispPrint_indent(ostream &os,
+ int indentation) const
+ {
+ os << endl << spaces(indentation);
+ LispPrint1(os, indentation);
+ return os;
+ }
+
+ /** Internal function to print in lisp format. Assume newline
+ and indentation printed already before first line. Recursive
+ calls will have newline & indent, though */
+ ostream &ASTNode::LispPrint1(ostream &os, int indentation) const {
+ if (!IsDefined()) {
+ os << "<undefined>";
+ return os;
+ }
+ Kind kind = GetKind();
+ // FIXME: figure out how to avoid symbols with same names as kinds.
+// if (kind == READ) {
+// const ASTVec &children = GetChildren();
+// children[0].LispPrint1(os, indentation);
+// os << "[" << children[1] << "]";
+// } else
+ if(kind == BVGETBIT) {
+ const ASTVec &children = GetChildren();
+ // child 0 is a symbol. Print without the NodeNum.
+ os << GetNodeNum() << ":";
+
+
+
+ children[0]._int_node_ptr->nodeprint(os);
+ //os << "{" << children[1].GetBVConst() << "}";
+ os << "{";
+ children[1]._int_node_ptr->nodeprint(os);
+ os << "}";
+ } else if (kind == NOT) {
+ const ASTVec &children = GetChildren();
+ os << GetNodeNum() << ":";
+ os << "(NOT ";
+ children[0].LispPrint1(os, indentation);
+ os << ")";
+ }
+ else if (Degree() == 0) {
+ // Symbol or a kind with no children print as index:NAME if shared,
+ // even if they have been printed before.
+ os << GetNodeNum() << ":";
+ _int_node_ptr->nodeprint(os);
+ // os << "(" << _int_node_ptr->_ref_count << ")";
+ // os << "{" << GetValueWidth() << "}";
+ }
+ else if (IsAlreadyPrinted()) {
+ // print non-symbols as "[index]" if seen before.
+ os << "[" << GetNodeNum() << "]";
+ // << "(" << _int_node_ptr->_ref_count << ")";
+ }
+ else {
+ MarkAlreadyPrinted();
+ const ASTVec &children = GetChildren();
+ os << GetNodeNum() << ":"
+ //<< "(" << _int_node_ptr->_ref_count << ")"
+ << "(" << kind << " ";
+ // os << "{" << GetValueWidth() << "}";
+ ASTVec::const_iterator iend = children.end();
+ for (ASTVec::const_iterator i = children.begin(); i != iend; i++) {
+ i->LispPrint_indent(os, indentation+2);
+ }
+ os << ")";
+ }
+ return os;
+ }
+
+ //print in PRESENTATION LANGUAGE
+ //
+ //two pass algorithm:
+ //
+ //1. In the first pass, letize this Node, N: i.e. if a node
+ //1. appears more than once in N, then record this fact.
+ //
+ //2. In the second pass print a "global let" and then print N
+ //2. as follows: Every occurence of a node occuring more than
+ //2. once is replaced with the corresponding let variable.
+ ostream& ASTNode::PL_Print(ostream &os,
+ int indentation) const {
+ // Clear the PrintMap
+ BeevMgr& bm = GetBeevMgr();
+ bm.PLPrintNodeSet.clear();
+ bm.NodeLetVarMap.clear();
+ bm.NodeLetVarVec.clear();
+ bm.NodeLetVarMap1.clear();
+
+ //pass 1: letize the node
+ LetizeNode();
+
+ //pass 2:
+ //
+ //2. print all the let variables and their counterpart expressions
+ //2. as follows (LET var1 = expr1, var2 = expr2, ...
+ //
+ //3. Then print the Node itself, replacing every occurence of
+ //3. expr1 with var1, expr2 with var2, ...
+ //os << "(";
+ if(0 < bm.NodeLetVarMap.size()) {
+ //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin();
+ //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end();
+ std::vector<pair<ASTNode,ASTNode> >::iterator it = bm.NodeLetVarVec.begin();
+ std::vector<pair<ASTNode,ASTNode> >::iterator itend = bm.NodeLetVarVec.end();
+
+ os << "(LET ";
+ //print the let var first
+ it->first.PL_Print1(os,indentation,false);
+ os << " = ";
+ //print the expr
+ it->second.PL_Print1(os,indentation,false);
+
+ //update the second map for proper printing of LET
+ bm.NodeLetVarMap1[it->second] = it->first;
+
+ for(it++;it!=itend;it++) {
+ os << "," << endl;
+ //print the let var first
+ it->first.PL_Print1(os,indentation,false);
+ os << " = ";
+ //print the expr
+ it->second.PL_Print1(os,indentation,false);
+
+ //update the second map for proper printing of LET
+ bm.NodeLetVarMap1[it->second] = it->first;
+ }
+
+ os << " IN " << endl;
+ PL_Print1(os,indentation, true);
+ os << ") ";
+ }
+ else
+ PL_Print1(os,indentation, false);
+ //os << " )";
+ os << " ";
+ return os;
+ } //end of PL_Print()
+
+ //traverse "*this", and construct "let variables" for terms that
+ //occur more than once in "*this".
+ void ASTNode::LetizeNode(void) const {
+ Kind kind = this->GetKind();
+
+ if(kind == SYMBOL ||
+ kind == BVCONST ||
+ kind == FALSE ||
+ kind == TRUE)
+ return;
+
+ //FIXME: this is ugly.
+ BeevMgr& bm = GetBeevMgr();
+ const ASTVec &c = this->GetChildren();
+ for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++){
+ ASTNode ccc = *it;
+ if(bm.PLPrintNodeSet.find(ccc) == bm.PLPrintNodeSet.end()){
+ //If branch: if *it is not in NodeSet then,
+ //
+ //1. add it to NodeSet
+ //
+ //2. Letize its childNodes
+
+ //FIXME: Fetching BeevMgr is annoying. Can we put this in
+ //some kind of a printer class
+ bm.PLPrintNodeSet.insert(ccc);
+ //debugging
+ //cerr << ccc;
+ ccc.LetizeNode();
+ }
+ else{
+ Kind k = ccc.GetKind();
+ if(k == SYMBOL ||
+ k == BVCONST ||
+ k == FALSE ||
+ k == TRUE)
+ continue;
+
+ //0. Else branch: Node has been seen before
+ //
+ //1. Check if the node has a corresponding letvar in the
+ //1. NodeLetVarMap.
+ //
+ //2. if no, then create a new var and add it to the
+ //2. NodeLetVarMap
+ if(bm.NodeLetVarMap.find(ccc) == bm.NodeLetVarMap.end()) {
+ //Create a new symbol. Get some name. if it conflicts with a
+ //declared name, too bad.
+ int sz = bm.NodeLetVarMap.size();
+ ostringstream oss;
+ oss << "let_k_" << sz;
+
+ ASTNode CurrentSymbol = bm.CreateSymbol(oss.str().c_str());
+ CurrentSymbol.SetValueWidth(this->GetValueWidth());
+ CurrentSymbol.SetIndexWidth(this->GetIndexWidth());
+ /* If for some reason the variable being created here is
+ * already declared by the user then the printed output will
+ * not be a legal input to the system. too bad. I refuse to
+ * check for this. [Vijay is the author of this comment.]
+ */
+
+ bm.NodeLetVarMap[ccc] = CurrentSymbol;
+ std::pair<ASTNode,ASTNode> node_letvar_pair(CurrentSymbol,ccc);
+ bm.NodeLetVarVec.push_back(node_letvar_pair);
+ }
+ }
+ }
+ } //end of LetizeNode()
+
+ void ASTNode::PL_Print1(ostream& os,
+ int indentation,
+ bool letize) const {
+ //os << spaces(indentation);
+ //os << endl << spaces(indentation);
+ if (!IsDefined()) {
+ os << "<undefined>";
+ return;
+ }
+
+ //if this node is present in the letvar Map, then print the letvar
+ BeevMgr &bm = GetBeevMgr();
+
+ //this is to print letvars for shared subterms inside the printing
+ //of "(LET v0 = term1, v1=term1 at term2,...
+ if((bm.NodeLetVarMap1.find(*this) != bm.NodeLetVarMap1.end()) && !letize) {
+ (bm.NodeLetVarMap1[*this]).PL_Print1(os,indentation,letize);
+ return;
+ }
+
+ //this is to print letvars for shared subterms inside the actual
+ //term to be printed
+ if((bm.NodeLetVarMap.find(*this) != bm.NodeLetVarMap.end()) && letize) {
+ (bm.NodeLetVarMap[*this]).PL_Print1(os,indentation,letize);
+ return;
+ }
+
+ //otherwise print it normally
+ Kind kind = GetKind();
+ const ASTVec &c = GetChildren();
+ switch(kind) {
+ case BVGETBIT:
+ c[0].PL_Print1(os,indentation,letize);
+ os << "{";
+ c[1].PL_Print1(os,indentation,letize);
+ os << "}";
+ break;
+ case BITVECTOR:
+ os << "BITVECTOR(";
+ unsigned char * str;
+ str = CONSTANTBV::BitVector_to_Hex(c[0].GetBVConst());
+ os << str << ")";
+ CONSTANTBV::BitVector_Dispose(str);
+ break;
+ case BOOLEAN:
+ os << "BOOLEAN";
+ break;
+ case FALSE:
+ case TRUE:
+ os << kind;
+ break;
+ case BVCONST:
+ case SYMBOL:
+ _int_node_ptr->nodeprint(os);
+ break;
+ case READ:
+ c[0].PL_Print1(os, indentation,letize);
+ os << "[";
+ c[1].PL_Print1(os,indentation,letize);
+ os << "]";
+ break;
+ case WRITE:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " WITH [";
+ c[1].PL_Print1(os,indentation,letize);
+ os << "] := ";
+ c[2].PL_Print1(os,indentation,letize);
+ os << ")";
+ os << endl;
+ break;
+ case BVUMINUS:
+ os << kind << "( ";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ")";
+ break;
+ case NOT:
+ os << "NOT(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ") " << endl;
+ break;
+ case BVNEG:
+ os << " ~(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ")";
+ break;
+ case BVCONCAT:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " @ ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case BVOR:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " | ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")";
+ break;
+ case BVAND:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " & ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")";
+ break;
+ case BVEXTRACT:
+ c[0].PL_Print1(os,indentation,letize);
+ os << "[";
+ os << GetUnsignedConst(c[1]);
+ os << ":";
+ os << GetUnsignedConst(c[2]);
+ os << "]";
+ break;
+ case BVLEFTSHIFT:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " << ";
+ os << GetUnsignedConst(c[1]);
+ os << ")";
+ break;
+ case BVRIGHTSHIFT:
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << " >> ";
+ os << GetUnsignedConst(c[1]);
+ os << ")";
+ break;
+ case BVMULT:
+ case BVSUB:
+ case BVPLUS:
+ case SBVDIV:
+ case SBVMOD:
+ case BVDIV:
+ case BVMOD:
+ os << kind << "(";
+ os << this->GetValueWidth();
+ for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++) {
+ os << ", " << endl;
+ it->PL_Print1(os,indentation,letize);
+ }
+ os << ")" << endl;
+ break;
+ case ITE:
+ os << "IF(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ os << "THEN ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << endl << "ELSE ";
+ c[2].PL_Print1(os,indentation,letize);
+ os << endl << "ENDIF";
+ break;
+ case BVLT:
+ case BVLE:
+ case BVGT:
+ case BVGE:
+ case BVXOR:
+ case BVNAND:
+ case BVNOR:
+ case BVXNOR:
+ os << kind << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case BVSLT:
+ os << "SBVLT" << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case BVSLE:
+ os << "SBVLE" << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case BVSGT:
+ os << "SBVGT" << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case BVSGE:
+ os << "SBVGE" << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")" << endl;
+ break;
+ case EQ:
+ c[0].PL_Print1(os,indentation,letize);
+ os << " = ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << endl;
+ break;
+ case NEQ:
+ c[0].PL_Print1(os,indentation,letize);
+ os << " /= ";
+ c[1].PL_Print1(os,indentation,letize);
+ os << endl;
+ break;
+ case AND:
+ case OR:
+ case NAND:
+ case NOR:
+ case XOR: {
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ ASTVec::const_iterator it=c.begin();
+ ASTVec::const_iterator itend=c.end();
+
+ it++;
+ for(;it!=itend;it++) {
+ os << " " << kind << " ";
+ it->PL_Print1(os,indentation,letize);
+ os << endl;
+ }
+ os << ")";
+ break;
+ }
+ case IFF:
+ os << "(";
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ")";
+ os << " <=> ";
+ os << "(";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")";
+ os << ")";
+ os << endl;
+ break;
+ case IMPLIES:
+ os << "(";
+ os << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ")";
+ os << " => ";
+ os << "(";
+ c[1].PL_Print1(os,indentation,letize);
+ os << ")";
+ os << ")";
+ os << endl;
+ break;
+ case BVSX:
+ os << kind << "(";
+ c[0].PL_Print1(os,indentation,letize);
+ os << ",";
+ os << this->GetValueWidth();
+ os << ")" << endl;
+ break;
+ default:
+ //remember to use LispPrinter here. Otherwise this function will
+ //go into an infinite loop. Recall that "<<" is overloaded to
+ //the lisp printer. FatalError uses lispprinter
+ FatalError("PL_Print1: printing not implemented for this kind: ",*this);
+ break;
+ }
+ } //end of PL_Print1()
+
+ ////////////////////////////////////////////////////////////////
+ // BeevMgr members
+ ////////////////////////////////////////////////////////////////
+ ASTNode BeevMgr::CreateNode(Kind kind, const ASTVec & back_children) {
+ // create a new node. Children will be modified.
+ ASTInterior *n_ptr = new ASTInterior(kind, *this);
+
+ // insert all of children at end of new_children.
+ ASTNode n(CreateInteriorNode(kind, n_ptr, back_children));
+ return n;
+ }
+
+ ASTNode BeevMgr::CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTVec & back_children) {
+
+ ASTInterior *n_ptr = new ASTInterior(kind, *this);
+ ASTVec &front_children = n_ptr->_children;
+ front_children.push_back(child0);
+ ASTNode n(CreateInteriorNode(kind, n_ptr, back_children));
+ return n;
+ }
+
+ ASTNode BeevMgr::CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTVec & back_children) {
+
+ ASTInterior *n_ptr = new ASTInterior(kind, *this);
+ ASTVec &front_children = n_ptr->_children;
+ front_children.push_back(child0);
+ front_children.push_back(child1);
+ ASTNode n(CreateInteriorNode(kind, n_ptr, back_children));
+ return n;
+ }
+
+
+ ASTNode BeevMgr::CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2,
+ const ASTVec & back_children) {
+ ASTInterior *n_ptr = new ASTInterior(kind, *this);
+ ASTVec &front_children = n_ptr->_children;
+ front_children.push_back(child0);
+ front_children.push_back(child1);
+ front_children.push_back(child2);
+ ASTNode n(CreateInteriorNode(kind, n_ptr, back_children));
+ return n;
+ }
+
+
+ ASTInterior *BeevMgr::CreateInteriorNode(Kind kind,
+ // children array of this node will be modified.
+ ASTInterior *n_ptr,
+ const ASTVec & back_children) {
+
+ // insert back_children at end of front_children
+ ASTVec &front_children = n_ptr->_children;
+
+ front_children.insert(front_children.end(), back_children.begin(), back_children.end());
+
+ // check for undefined nodes.
+ ASTVec::const_iterator it_end = front_children.end();
+ for (ASTVec::const_iterator it = front_children.begin(); it != it_end; it++) {
+ if (it->IsNull())
+ FatalError("CreateInteriorNode: Undefined childnode in CreateInteriorNode: ", ASTUndefined);
+ }
+
+ return LookupOrCreateInterior(n_ptr);
+ }
+
+ /** Trivial but virtual destructor */
+ ASTSymbol::~ASTSymbol() {}
+
+ ostream &operator<<(ostream &os, const ASTNodeMap &nmap)
+ {
+ ASTNodeMap::const_iterator iend = nmap.end();
+ for (ASTNodeMap::const_iterator i = nmap.begin(); i!=iend; i++) {
+ os << "Key: " << i->first << endl;
+ os << "Value: " << i->second << endl;
+ }
+ return os;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // BeevMgr member functions to create ASTSymbol and ASTBVConst
+ ////////////////////////////////////////////////////////////////
+ ASTNode BeevMgr::CreateSymbol(const char * const name)
+ {
+ ASTSymbol temp_sym(name, *this);
+ ASTNode n(LookupOrCreateSymbol(temp_sym));
+ return n;
+ }
+
+#ifndef NATIVE_C_ARITH
+ //Create a ASTBVConst node
+ ASTNode BeevMgr::CreateBVConst(unsigned int width,
+ unsigned long long int bvconst){
+ if(width > (sizeof(unsigned long long int)<<3) || width <= 0)
+ FatalError("CreateBVConst: trying to create a bvconst of width: ", ASTUndefined, width);
+
+
+ CBV bv = CONSTANTBV::BitVector_Create(width, true);
+ unsigned long c_val = (0x00000000ffffffffLL) & bvconst;
+ unsigned int copied = 0;
+
+ // sizeof(unsigned long) returns the number of bytes in unsigned
+ // long. In order to convert it to bits, we need to shift left by
+ // 3. Hence, sizeof(unsigned long) << 3
+
+ //The algo below works as follows: It starts by copying the
+ //lower-order bits of the input "bvconst" in chunks of size =
+ //number of bits in unsigned long. The variable "copied" keeps
+ //track of the number of chunks copied so far
+
+ while(copied + (sizeof(unsigned long)<<3) < width){
+ CONSTANTBV::BitVector_Chunk_Store(bv, sizeof(unsigned long)<<3,copied,c_val);
+ bvconst = bvconst >> (sizeof(unsigned long) << 3);
+ c_val = (0x00000000ffffffffLL) & bvconst;
+ copied += sizeof(unsigned long) << 3;
+ }
+ CONSTANTBV::BitVector_Chunk_Store(bv,width - copied,copied,c_val);
+ return CreateBVConst(bv,width);
+ }
+
+ //Create a ASTBVConst node from std::string
+ ASTNode BeevMgr::CreateBVConst(const char* const strval, int base) {
+ size_t width = strlen((const char *)strval);
+ if(!(2 == base || 10 == base || 16 == base)){
+ FatalError("CreateBVConst: unsupported base: ",ASTUndefined,base);
+ }
+ //FIXME Tim: Earlier versions of the code assume that the length of
+ //binary strings is 32 bits.
+ if(10 == base) width = 32;
+ if(16 == base) width = width * 4;
+
+ //checking if the input is in the correct format
+ CBV bv = CONSTANTBV::BitVector_Create(width,true);
+ CONSTANTBV::ErrCode e;
+ if(2 == base){
+ e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*)strval);
+ }else if(10 == base){
+ e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*)strval);
+ }else if(16 == base){
+ e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*)strval);
+ }else{
+ e = CONSTANTBV::ErrCode_Pars;
+ }
+
+ if(0 != e) {
+ cerr << "CreateBVConst: " << BitVector_Error(e);
+ FatalError("",ASTUndefined);
+ }
+
+ //FIXME
+ return CreateBVConst(bv, width);
+ }
+
+
+ //FIXME Code currently assumes that it will destroy the bitvector passed to it
+ ASTNode BeevMgr::CreateBVConst(CBV bv, unsigned width){
+ ASTBVConst temp_bvconst(bv, width, *this);
+ ASTNode n(LookupOrCreateBVConst(temp_bvconst));
+
+ CONSTANTBV::BitVector_Destroy(bv);
+
+ return n;
+ }
+
+ ASTNode BeevMgr::CreateZeroConst(unsigned width) {
+ CBV z = CONSTANTBV::BitVector_Create(width, true);
+ return CreateBVConst(z, width);
+ }
+
+ ASTNode BeevMgr::CreateOneConst(unsigned width) {
+ CBV o = CONSTANTBV::BitVector_Create(width, true);
+ CONSTANTBV::BitVector_increment(o);
+
+ return CreateBVConst(o,width);
+ }
+
+ ASTNode BeevMgr::CreateTwoConst(unsigned width) {
+ CBV two = CONSTANTBV::BitVector_Create(width, true);
+ CONSTANTBV::BitVector_increment(two);
+ CONSTANTBV::BitVector_increment(two);
+
+ return CreateBVConst(two,width);
+ }
+
+ ASTNode BeevMgr::CreateMaxConst(unsigned width) {
+ CBV max = CONSTANTBV::BitVector_Create(width, false);
+ CONSTANTBV::BitVector_Fill(max);
+
+ return CreateBVConst(max,width);
+ }
+
+ //To ensure unique BVConst nodes, lookup the node in unique-table
+ //before creating a new one.
+ ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) {
+ ASTBVConst *s_ptr = &s; // it's a temporary key.
+
+ // Do an explicit lookup to see if we need to create a copy of the string.
+ ASTBVConstSet::const_iterator it;
+ if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) {
+ // Make a new ASTBVConst with duplicated string (can't assign
+ // _name because it's const). Can cast the iterator to
+ // non-const -- carefully.
+
+ ASTBVConst * s_copy = new ASTBVConst(s);
+ s_copy->SetNodeNum(NewNodeNum());
+
+ pair<ASTBVConstSet::const_iterator, bool> p = _bvconst_unique_table.insert(s_copy);
+ return *p.first;
+ }
+ else{
+ // return symbol found in table.
+ return *it;
+ }
+ }
+
+ // Inline because we need to wait until unique_table is defined
+ void ASTBVConst::CleanUp() {
+ // cout << "Deleting node " << this->GetNodeNum() << endl;
+ _bm._bvconst_unique_table.erase(this);
+ delete this;
+ }
+
+ // Get the value of bvconst from a bvconst. It's an error if kind != BVCONST
+ CBV const ASTNode::GetBVConst() const {
+ if(GetKind() != BVCONST)
+ FatalError("GetBVConst: non bitvector-constant: ",*this);
+ return ((ASTBVConst *) _int_node_ptr)->GetBVConst();
+ }
+#else
+ //Create a ASTBVConst node
+ ASTNode BeevMgr::CreateBVConst(const unsigned int width,
+ const unsigned long long int bvconst) {
+ if(width > 64 || width <= 0)
+ FatalError("Fatal Error: CreateBVConst: trying to create a bvconst of width:", ASTUndefined, width);
+
+ //64 bit mask
+ unsigned long long int mask = 0xffffffffffffffffLL;
+ mask = mask >> (64 - width);
+
+ unsigned long long int bv = bvconst;
+ bv = bv & mask;
+
+ ASTBVConst temp_bvconst(bv, *this);
+ temp_bvconst._value_width = width;
+ ASTNode n(LookupOrCreateBVConst(temp_bvconst));
+ n.SetValueWidth(width);
+ n.SetIndexWidth(0);
+ return n;
+ }
+ //Create a ASTBVConst node from std::string
+ ASTNode BeevMgr::CreateBVConst(const char* strval, int base) {
+ if(!(base == 2 || base == 16 || base == 10))
+ FatalError("CreateBVConst: This base is not supported: ", ASTUndefined, base);
+
+ if(10 != base) {
+ unsigned int width = (base == 2) ? strlen(strval) : strlen(strval)*4;
+ unsigned long long int val = strtoull(strval, NULL, base);
+ ASTNode bvcon = CreateBVConst(width, val);
+ return bvcon;
+ }
+ else {
+ //this is an ugly hack to accomodate SMTLIB format
+ //restrictions. SMTLIB format represents bitvector constants in
+ //base 10 (what a terrible idea, but i have no choice but to
+ //support it), and make an implicit assumption that the length
+ //is 32 (another terrible idea).
+ unsigned width = 32;
+ unsigned long long int val = strtoull(strval, NULL, base);
+ ASTNode bvcon = CreateBVConst(width, val);
+ return bvcon;
+ }
+ }
+
+ //To ensure unique BVConst nodes, lookup the node in unique-table
+ //before creating a new one.
+ ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) {
+ ASTBVConst *s_ptr = &s; // it's a temporary key.
+
+ // Do an explicit lookup to see if we need to create a copy of the
+ // string.
+ ASTBVConstSet::const_iterator it;
+ if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) {
+ // Make a new ASTBVConst. Can cast the iterator to non-const --
+ // carefully.
+ unsigned int width = s_ptr->_value_width;
+ ASTBVConst * s_ptr1 = new ASTBVConst(s_ptr->GetBVConst(), *this);
+ s_ptr1->SetNodeNum(NewNodeNum());
+ s_ptr1->_value_width = width;
+ pair<ASTBVConstSet::const_iterator, bool> p = _bvconst_unique_table.insert(s_ptr1);
+ return *p.first;
+ }
+ else
+ // return BVConst found in table.
+ return *it;
+ }
+
+ // Inline because we need to wait until unique_table is defined
+ void ASTBVConst::CleanUp() {
+ // cout << "Deleting node " << this->GetNodeNum() << endl;
+ _bm._bvconst_unique_table.erase(this);
+ delete this;
+ }
+
+ // Get the value of bvconst from a bvconst. It's an error if kind
+ // != BVCONST
+ unsigned long long int ASTNode::GetBVConst() const {
+ if(GetKind() != BVCONST)
+ FatalError("GetBVConst: non bitvector-constant: ", *this);
+ return ((ASTBVConstTmp *) _int_node_ptr)->GetBVConst();
+ }
+
+ ASTNode BeevMgr::CreateZeroConst(unsigned width) {
+ return CreateBVConst(width,0);
+ }
+
+ ASTNode BeevMgr::CreateOneConst(unsigned width) {
+ return CreateBVConst(width,1);
+ }
+
+ ASTNode BeevMgr::CreateTwoConst(unsigned width) {
+ return CreateBVConst(width,2);
+ }
+
+ ASTNode BeevMgr::CreateMaxConst(unsigned width) {
+ std::string s;
+ s.insert(s.end(),width,'1');
+ return CreateBVConst(s.c_str(),2);
+ }
+
+#endif
+
+ // FIXME: _name is now a constant field, and this assigns to it
+ // because it tries not to copy the string unless it needs to. How
+ // do I avoid copying children in ASTInterior? Perhaps I don't!
+
+ // Note: There seems to be a limitation of hash_set, in that insert
+ // returns a const iterator to the value. That prevents us from
+ // modifying the name (in a hash-preserving way) after the symbol is
+ // inserted. FIXME: Is there a way to do this with insert? Need a
+ // function to make a new object in the middle of insert. Read STL
+ // documentation.
+
+ ASTSymbol *BeevMgr::LookupOrCreateSymbol(ASTSymbol& s) {
+ ASTSymbol *s_ptr = &s; // it's a temporary key.
+
+ // Do an explicit lookup to see if we need to create a copy of the string.
+ ASTSymbolSet::const_iterator it;
+ if ((it = _symbol_unique_table.find(s_ptr)) == _symbol_unique_table.end()) {
+ // Make a new ASTSymbol with duplicated string (can't assign
+ // _name because it's const). Can cast the iterator to
+ // non-const -- carefully.
+ //std::string strname(s_ptr->GetName());
+ ASTSymbol * s_ptr1 = new ASTSymbol(strdup(s_ptr->GetName()), *this);
+ s_ptr1->SetNodeNum(NewNodeNum());
+ s_ptr1->_value_width = s_ptr->_value_width;
+ pair<ASTSymbolSet::const_iterator, bool> p = _symbol_unique_table.insert(s_ptr1);
+ return *p.first;
+ }
+ else
+ // return symbol found in table.
+ return *it;
+ }
+
+ bool BeevMgr::LookupSymbol(ASTSymbol& s) {
+ ASTSymbol* s_ptr = &s; // it's a temporary key.
+
+ if(_symbol_unique_table.find(s_ptr) == _symbol_unique_table.end())
+ return false;
+ else
+ return true;
+ }
+
+ // Inline because we need to wait until unique_table is defined
+ void ASTSymbol::CleanUp() {
+ // cout << "Deleting node " << this->GetNodeNum() << endl;
+ _bm._symbol_unique_table.erase(this);
+ //FIXME This is a HUGE free to invoke.
+ //TEST IT!
+ free((char*) this->_name);
+ delete this;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // IO manipulators for Lisp format printing of AST.
+ //
+ ////////////////////////////////////////////////////////////////
+
+ // FIXME: Additional controls
+ // * Print node numbers (addresses/nums)
+ // * Printlength limit
+ // * Printdepth limit
+
+ /** Print a vector of ASTNodes in lisp format */
+ ostream &LispPrintVec(ostream &os, const ASTVec &v, int indentation)
+ {
+ // Print the children
+ ASTVec::const_iterator iend = v.end();
+ for (ASTVec::const_iterator i = v.begin(); i != iend; i++) {
+ i->LispPrint_indent(os, indentation);
+ }
+ return os;
+ }
+
+ // FIXME: Made non-ref in the hope that it would work better.
+ void lp(ASTNode node)
+ {
+ cout << lisp(node) << endl;
+ }
+
+ void lpvec(const ASTVec &vec)
+ {
+ vec[0].GetBeevMgr().AlreadyPrintedSet.clear();
+ LispPrintVec(cout, vec, 0);
+ cout << endl;
+ }
+
+ // Copy constructor. Maintain _ref_count
+ ASTNode::ASTNode(const ASTNode &n) : _int_node_ptr(n._int_node_ptr) {
+#ifndef SMTLIB
+ if (n._int_node_ptr) {
+ n._int_node_ptr->IncRef();
+ }
+#endif
+ }
+
+
+ /* FUNCTION: Typechecker for terms and formulas
+ *
+ * TypeChecker: Assumes that the immediate Children of the input
+ * ASTNode have been typechecked. This function is suitable in
+ * scenarios like where you are building the ASTNode Tree, and you
+ * typecheck as you go along. It is not suitable as a general
+ * typechecker
+ */
+ void BeevMgr::BVTypeCheck(const ASTNode& n) {
+ Kind k = n.GetKind();
+ //The children of bitvector terms are in turn bitvectors.
+ ASTVec v = n.GetChildren();
+ if(is_Term_kind(k)) {
+ switch(k) {
+ case BVCONST:
+ if(BITVECTOR_TYPE != n.GetType())
+ FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n);
+ break;
+ case SYMBOL:
+ return;
+ case ITE:
+ if(BOOLEAN_TYPE != n[0].GetType() &&
+ BITVECTOR_TYPE != n[1].GetType() &&
+ BITVECTOR_TYPE != n[2].GetType())
+ FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n);
+ if(n[1].GetValueWidth() != n[2].GetValueWidth())
+ FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n);
+ if(n[1].GetIndexWidth() != n[2].GetIndexWidth())
+ FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n);
+ break;
+ case READ:
+ if(n[0].GetIndexWidth() != n[1].GetValueWidth()) {
+ cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl;
+ cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl;
+ FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n);
+ }
+ break;
+ case WRITE:
+ if(n[0].GetIndexWidth() != n[1].GetValueWidth())
+ FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n);
+ if(n[0].GetValueWidth() != n[2].GetValueWidth())
+ FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n",n);
+ break;
+ case BVOR:
+ case BVAND:
+ case BVXOR:
+ case BVNOR:
+ case BVNAND:
+ case BVXNOR:
+ case BVPLUS:
+ case BVMULT:
+ case BVDIV:
+ case BVMOD:
+ case BVSUB: {
+ if(!(v.size() >= 2))
+ FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have atleast two arguments\n",n);
+ unsigned int width = n.GetValueWidth();
+ for(ASTVec::iterator it=v.begin(),itend=v.end();it!=itend;it++){
+ if(width != it->GetValueWidth()) {
+ cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n";
+ cerr << n << endl;
+ cerr << "width of term:" << width << endl;
+ cerr << "width of offending operand:" << it->GetValueWidth() << endl;
+ FatalError("BVTypeCheck:Offending operand:\n",*it);
+ }
+ if(BITVECTOR_TYPE != it->GetType())
+ FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n",n);
+ }
+ break;
+ }
+ case BVSX:
+ //in BVSX(n[0],len), the length of the BVSX term must be
+ //greater than the length of n[0]
+ if(n[0].GetValueWidth() >= n.GetValueWidth()) {
+ FatalError("BVTypeCheck: BVSX(t,bvsx_len) : length of 't' must be <= bvsx_len\n",n);
+ }
+ break;
+ default:
+ for(ASTVec::iterator it=v.begin(),itend=v.end();it!=itend;it++)
+ if(BITVECTOR_TYPE != it->GetType()) {
+ cerr << "The type is: " << it->GetType() << endl;
+ FatalError("BVTypeCheck:ChildNodes of bitvector-terms must be bitvectors\n",n);
+ }
+ break;
+ }
+
+ switch(k) {
+ case BVCONCAT:
+ if(n.Degree() != 2)
+ FatalError("BVTypeCheck: should have exactly 2 args\n",n);
+ if(n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth())
+ FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n",n);
+ break;
+ case BVUMINUS:
+ case BVNEG:
+ if(n.Degree() != 1)
+ FatalError("BVTypeCheck: should have exactly 1 args\n",n);
+ break;
+ case BVEXTRACT:
+ if(n.Degree() != 3)
+ FatalError("BVTypeCheck: should have exactly 3 args\n",n);
+ if(!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind()))
+ FatalError("BVTypeCheck: indices should be BVCONST\n",n);
+ if(n.GetValueWidth() != GetUnsignedConst(n[1])- GetUnsignedConst(n[2])+1)
+ FatalError("BVTypeCheck: length mismatch\n",n);
+ break;
+ case BVLEFTSHIFT:
+ case BVRIGHTSHIFT:
+ if(n.Degree() != 2)
+ FatalError("BVTypeCheck: should have exactly 2 args\n",n);
+ break;
+ //case BVVARSHIFT:
+ //case BVSRSHIFT:
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ if(!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType()))
+ FatalError("BVTypeCheck: not a formula:",n);
+ switch(k){
+ case TRUE:
+ case FALSE:
+ case SYMBOL:
+ return;
+ case EQ:
+ case NEQ:
+ if(!(n[0].GetValueWidth() == n[1].GetValueWidth() &&
+ n[0].GetIndexWidth() == n[1].GetIndexWidth())) {
+ cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl;
+ cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl;
+ cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl;
+ cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl;
+ FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n);
+ }
+ break;
+ case BVLT:
+ case BVLE:
+ case BVGT:
+ case BVGE:
+ case BVSLT:
+ case BVSLE:
+ case BVSGT:
+ case BVSGE:
+ if(BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType())
+ FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors",n);
+ if(n[0].GetValueWidth() != n[1].GetValueWidth())
+ FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n);
+ if(n[0].GetIndexWidth() != n[1].GetIndexWidth())
+ FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n);
+ break;
+ case NOT:
+ if(1 != n.Degree())
+ FatalError("BVTypeCheck: NOT formula can have exactly one childNode",n);
+ break;
+ case AND:
+ case OR:
+ case XOR:
+ case NAND:
+ case NOR:
+ if(2 > n.Degree())
+ FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes",n);
+ break;
+ case IFF:
+ case IMPLIES:
+ if(2 != n.Degree())
+ FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes",n);
+ break;
+ case ITE:
+ if(3 != n.Degree())
+ FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes",n);
+ break;
+ default:
+ FatalError("BVTypeCheck: Unrecognized kind: ",ASTUndefined);
+ break;
+ }
+ }
+ } //End of TypeCheck function
+
+ //add an assertion to the current logical context
+ void BeevMgr::AddAssert(const ASTNode& assert) {
+ if(!(is_Form_kind(assert.GetKind()) && BOOLEAN_TYPE == assert.GetType())) {
+ FatalError("AddAssert:Trying to assert a non-formula:",assert);
+ }
+
+ ASTVec * v;
+ //if the stack of ASTVec is not empty, then take the top ASTVec
+ //and add the input assert to it
+ if(!_asserts.empty()) {
+ v = _asserts.back();
+ //v->push_back(TransformFormula(assert));
+ v->push_back(assert);
+ }
+ else {
+ //else create a logical context, and add it to the top of the
+ //stack
+ v = new ASTVec();
+ //v->push_back(TransformFormula(assert));
+ v->push_back(assert);
+ _asserts.push_back(v);
+ }
+ }
+
+ void BeevMgr::Push(void) {
+ ASTVec * v;
+ v = new ASTVec();
+ _asserts.push_back(v);
+ }
+
+ void BeevMgr::Pop(void) {
+ if(!_asserts.empty()) {
+ ASTVec * c = _asserts.back();
+ //by calling the clear function we ensure that the ref count is
+ //decremented for the ASTNodes stored in c
+ c->clear();
+ delete c;
+ _asserts.pop_back();
+ }
+ }
+
+ void BeevMgr::AddQuery(const ASTNode& q) {
+ //_current_query = TransformFormula(q);
+ //cerr << "\nThe current query is: " << q << endl;
+ _current_query = q;
+ }
+
+ const ASTNode BeevMgr::PopQuery() {
+ ASTNode q = _current_query;
+ _current_query = ASTTrue;
+ return q;
+ }
+
+ const ASTNode BeevMgr::GetQuery() {
+ return _current_query;
+ }
+
+ const ASTVec BeevMgr::GetAsserts(void) {
+ vector<ASTVec *>::iterator it = _asserts.begin();
+ vector<ASTVec *>::iterator itend = _asserts.end();
+
+ ASTVec v;
+ for(;it!=itend;it++) {
+ if(!(*it)->empty())
+ v.insert(v.end(),(*it)->begin(),(*it)->end());
+ }
+ return v;
+ }
+
+ //Create a new variable of ValueWidth 'n'
+ ASTNode BeevMgr::NewArrayVar(unsigned int index, unsigned int value) {
+ std:: string c("v");
+ char d[32];
+ sprintf(d,"%d",_symbol_count++);
+ std::string ccc(d);
+ c += "_writearray_" + ccc;
+
+ ASTNode CurrentSymbol = CreateSymbol(c.c_str());
+ CurrentSymbol.SetValueWidth(value);
+ CurrentSymbol.SetIndexWidth(index);
+ return CurrentSymbol;
+ } //end of NewArrayVar()
+
+
+ //Create a new variable of ValueWidth 'n'
+ ASTNode BeevMgr::NewVar(unsigned int value) {
+ std:: string c("v");
+ char d[32];
+ sprintf(d,"%d",_symbol_count++);
+ std::string ccc(d);
+ c += "_new_stp_var_" + ccc;
+
+ ASTNode CurrentSymbol = CreateSymbol(c.c_str());
+ CurrentSymbol.SetValueWidth(value);
+ CurrentSymbol.SetIndexWidth(0);
+ _introduced_symbols.insert(CurrentSymbol);
+ return CurrentSymbol;
+ } //end of NewVar()
+
+ //prints statistics for the ASTNode
+ void BeevMgr::ASTNodeStats(const char * c, const ASTNode& a){
+ if(!stats)
+ return;
+
+ StatInfoSet.clear();
+ //print node size:
+ cout << endl << "Printing: " << c;
+ if(print_nodes) {
+ //a.PL_Print(cout,0);
+ //cout << endl;
+ cout << a << endl;
+ }
+ cout << "Node size is: ";
+ cout << NodeSize(a) << endl << endl;
+ }
+
+ unsigned int BeevMgr::NodeSize(const ASTNode& a, bool clearStatInfo) {
+ if(clearStatInfo)
+ StatInfoSet.clear();
+
+ ASTNodeSet::iterator it;
+ if((it = StatInfoSet.find(a)) != StatInfoSet.end())
+ //has already been counted
+ return 0;
+
+ //record that you have seen this node already
+ StatInfoSet.insert(a);
+
+ //leaf node has a size of 1
+ if(a.Degree() == 0)
+ return 1;
+
+ unsigned newn = 1;
+ ASTVec c = a.GetChildren();
+ for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++)
+ newn += NodeSize(*it);
+ return newn;
+ }
+
+ void BeevMgr::ClearAllTables(void) {
+ //clear all tables before calling toplevelsat
+ _ASTNode_to_SATVar.clear();
+ _SATVar_to_AST.clear();
+
+ for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(),
+ itend=_ASTNode_to_Bitvector.end();it!=itend;it++) {
+ delete it->second;
+ }
+ _ASTNode_to_Bitvector.clear();
+
+ /* OLD Destructor
+ * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(),
+ ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) {
+ ivec->second.clear();
+ }*/
+
+ /*What should I do here? For ASTNodes?
+ * for(ASTNodeMap::iterator ivec = BBTermMemo.begin(),
+ ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) {
+ ivec->second.clear();
+ }*/
+ BBTermMemo.clear();
+ BBFormMemo.clear();
+ NodeLetVarMap.clear();
+ NodeLetVarMap1.clear();
+ PLPrintNodeSet.clear();
+ AlreadyPrintedSet.clear();
+ SimplifyMap.clear();
+ SimplifyNegMap.clear();
+ SolverMap.clear();
+ AlwaysTrueFormMap.clear();
+ _arrayread_ite.clear();
+ _arrayread_symbol.clear();
+ _introduced_symbols.clear();
+ TransformMap.clear();
+ _letid_expr_map.clear();
+ CounterExampleMap.clear();
+ ComputeFormulaMap.clear();
+ StatInfoSet.clear();
+
+ // for(std::vector<ASTVec *>::iterator it=_asserts.begin(),
+ // itend=_asserts.end();it!=itend;it++) {
+ // (*it)->clear();
+ // }
+ _asserts.clear();
+ for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(),
+ iset_end = _arrayname_readindices.end();
+ iset!=iset_end;iset++) {
+ iset->second.clear();
+ }
+
+ _arrayname_readindices.clear();
+ _interior_unique_table.clear();
+ _symbol_unique_table.clear();
+ _bvconst_unique_table.clear();
+ }
+
+ void BeevMgr::ClearAllCaches(void) {
+ //clear all tables before calling toplevelsat
+ _ASTNode_to_SATVar.clear();
+ _SATVar_to_AST.clear();
+
+
+ for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(),
+ itend=_ASTNode_to_Bitvector.end();it!=itend;it++) {
+ delete it->second;
+ }
+ _ASTNode_to_Bitvector.clear();
+
+ /*OLD destructor
+ * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(),
+ ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) {
+ ivec->second.clear();
+ }*/
+
+ /*What should I do here?
+ *for(ASTNodeMap::iterator ivec = BBTermMemo.begin(),
+ ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) {
+ ivec->second.clear();
+ }*/
+ BBTermMemo.clear();
+ BBFormMemo.clear();
+ NodeLetVarMap.clear();
+ NodeLetVarMap1.clear();
+ PLPrintNodeSet.clear();
+ AlreadyPrintedSet.clear();
+ SimplifyMap.clear();
+ SimplifyNegMap.clear();
+ SolverMap.clear();
+ AlwaysTrueFormMap.clear();
+ _arrayread_ite.clear();
+ _arrayread_symbol.clear();
+ _introduced_symbols.clear();
+ TransformMap.clear();
+ _letid_expr_map.clear();
+ CounterExampleMap.clear();
+ ComputeFormulaMap.clear();
+ StatInfoSet.clear();
+
+ for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(),
+ iset_end = _arrayname_readindices.end();
+ iset!=iset_end;iset++) {
+ iset->second.clear();
+ }
+
+ _arrayname_readindices.clear();
+ //_interior_unique_table.clear();
+ //_symbol_unique_table.clear();
+ //_bvconst_unique_table.clear();
+ }
+
+ void BeevMgr::CopySolverMap_To_CounterExample(void) {
+ if(!SolverMap.empty()) {
+ CounterExampleMap.insert(SolverMap.begin(),SolverMap.end());
+ }
+ }
+
+ void FatalError(const char * str, const ASTNode& a, int w) {
+ if(a.GetKind() != UNDEFINED) {
+ cerr << "Fatal Error: " << str << endl << a << endl;
+ cerr << w << endl;
+ }
+ else {
+ cerr << "Fatal Error: " << str << endl;
+ cerr << w << endl;
+ }
+ if (vc_error_hdlr)
+ vc_error_hdlr(str);
+ exit(-1);
+ //assert(0);
+ }
+
+ void FatalError(const char * str) {
+ cerr << "Fatal Error: " << str << endl;
+ if (vc_error_hdlr)
+ vc_error_hdlr(str);
+ exit(-1);
+ //assert(0);
+ }
+
+ //Variable Order Printer: A global function which converts a MINISAT
+ //var into a ASTNODE var. It then prints this var along with
+ //variable order dcisions taken by MINISAT.
+ void Convert_MINISATVar_To_ASTNode_Print(int minisat_var,
+ int decision_level, int polarity) {
+ BEEV::ASTNode vv = globalBeevMgr_for_parser->_SATVar_to_AST[minisat_var];
+ cout << spaces(decision_level);
+ if(polarity) {
+ cout << "!";
+ }
+ vv.PL_Print(cout,0);
+ cout << endl;
+ }
+
+ void SortByExprNum(ASTVec& v) {
+ sort(v.begin(), v.end(), exprless);
+ }
+
+ bool isAtomic(Kind kind) {
+ if(TRUE == kind ||
+ FALSE == kind ||
+ EQ == kind ||
+ NEQ == kind ||
+ BVLT == kind ||
+ BVLE == kind ||
+ BVGT == kind ||
+ BVGE == kind ||
+ BVSLT == kind ||
+ BVSLE == kind ||
+ BVSGT == kind ||
+ BVSGE == kind ||
+ SYMBOL == kind ||
+ BVGETBIT == kind)
+ return true;
+ return false;
+ }
+
+ BeevMgr::~BeevMgr() {
+ ClearAllTables();
+ }
+}; // end namespace
+
Added: klee/trunk/stp/AST/AST.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/AST.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/AST.h (added)
+++ klee/trunk/stp/AST/AST.h Wed May 20 23:36:41 2009
@@ -0,0 +1,1805 @@
+// -*- c++ -*-
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+
+#ifndef AST_H
+#define AST_H
+#include <vector>
+#ifdef EXT_HASH_MAP
+#include <ext/hash_set>
+#include <ext/hash_map>
+#else
+#include <hash_set>
+#include <hash_map>
+#endif
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+#include <set>
+#include "ASTUtil.h"
+#include "ASTKind.h"
+#include "../sat/Solver.h"
+#include "../sat/SolverTypes.h"
+#include <cstdlib>
+#ifndef NATIVE_C_ARITH
+#include "../constantbv/constantbv.h"
+#endif
+/*****************************************************************************
+ * LIST OF CLASSES DECLARED IN THIS FILE:
+ *
+ * class BeevMgr;
+ * class ASTNode;
+ * class ASTInternal;
+ * class ASTInterior;
+ * class ASTSymbol;
+ * class ASTBVConst;
+ *****************************************************************************/
+namespace BEEV {
+ using namespace std;
+ using namespace MINISAT;
+#ifdef EXT_HASH_MAP
+ using namespace __gnu_cxx;
+#endif
+
+ //return types for the GetType() function in ASTNode class
+ enum types {
+ BOOLEAN_TYPE = 0,
+ BITVECTOR_TYPE,
+ ARRAY_TYPE,
+ UNKNOWN_TYPE
+ };
+
+ class BeevMgr;
+ class ASTNode;
+ class ASTInternal;
+ class ASTInterior;
+ class ASTSymbol;
+ class ASTBVConst;
+ class BVSolver;
+
+ //Vector of ASTNodes, used for child nodes among other things.
+ typedef vector<ASTNode> ASTVec;
+ extern ASTVec _empty_ASTVec;
+ extern BeevMgr * globalBeevMgr_for_parser;
+
+ typedef unsigned int * CBV;
+
+ /***************************************************************************/
+ /* Class ASTNode: Smart pointer to actual ASTNode internal datastructure. */
+ /***************************************************************************/
+ class ASTNode {
+ friend class BeevMgr;
+ friend class vector<ASTNode>;
+ //Print the arguments in lisp format.
+ friend ostream &LispPrintVec(ostream &os,
+ const ASTVec &v, int indentation = 0);
+
+ private:
+ // FIXME: make this into a reference?
+ ASTInternal * _int_node_ptr; // The real data.
+
+ // Usual constructor.
+ ASTNode(ASTInternal *in);
+
+ //Check if it points to a null node
+ bool IsNull () const { return _int_node_ptr == NULL; }
+
+ //Equal iff ASTIntNode pointers are the same.
+ friend bool operator==(const ASTNode node1, const ASTNode node2){
+ return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr);
+ }
+
+ /* FIXME: Nondeterministic code *** */
+ /** questionable pointer comparison function */
+ friend bool operator<(const ASTNode node1, const ASTNode node2){
+ return ((size_t) node1._int_node_ptr) < ((size_t) node2._int_node_ptr);
+ }
+
+ public:
+ // This is for sorting by expression number (used in Boolean
+ //optimization)
+ friend bool exprless(const ASTNode n1, const ASTNode n2) {
+ Kind k1 = n1.GetKind();
+ Kind k2 = n2.GetKind();
+
+ if(BVCONST == k1 && BVCONST != k2){
+ return true;
+ }
+ if(BVCONST != k1 && BVCONST == k2){
+ return false;
+ }
+
+ if(SYMBOL == k1 && SYMBOL != k2) {
+ return true;
+ }
+
+ if(SYMBOL != k1 && SYMBOL == k2) {
+ return false;
+ }
+
+ return (n1.GetNodeNum() < n2.GetNodeNum());
+ }//end of exprless
+
+ // Internal lisp-form printer that does not clear _node_print_table
+ ostream &LispPrint1(ostream &os, int indentation) const;
+
+ ostream &LispPrint_indent(ostream &os, int indentation) const;
+
+ // For lisp DAG printing. Has it been printed already, so we can
+ // just print the node number?
+ bool IsAlreadyPrinted() const;
+ void MarkAlreadyPrinted() const;
+
+ public:
+ // Default constructor. This gets used when declaring an ASTVec
+ // of a given size, in the hash table, etc. For faster
+ // refcounting, create a symbol node for NULL. Give it a big
+ // initial refcount. Never free it. also check, for ref-count
+ // overflow?
+ ASTNode() : _int_node_ptr(NULL) { };
+
+ // Copy constructor
+ ASTNode(const ASTNode &n);
+
+ // Destructor
+ ~ASTNode();
+
+ // Assignment (for ref counting)
+ ASTNode& operator=(const ASTNode& n);
+
+ BeevMgr &GetBeevMgr() const;
+
+ // Access node number
+ int GetNodeNum() const;
+
+ // Access kind. Inlined later because of declaration ordering problems.
+ Kind GetKind() const;
+
+ // access Children
+ const ASTVec &GetChildren() const;
+
+ // Return the number of child nodes
+ size_t Degree() const{
+ return GetChildren().size();
+ };
+
+ // Get indexth childNode.
+ const ASTNode operator[](size_t index) const {
+ return GetChildren()[index];
+ };
+
+ // Get begin() iterator for child nodes
+ ASTVec::const_iterator begin() const{
+ return GetChildren().begin();
+ };
+
+ // Get end() iterator for child nodes
+ ASTVec::const_iterator end() const{
+ return GetChildren().end();
+ };
+
+ //Get back() element for child nodes
+ const ASTNode back() const{
+ return GetChildren().back();
+ };
+
+ // Get the name from a symbol (char *). It's an error if kind != SYMBOL
+ const char * const GetName() const;
+
+ //Get the BVCONST value
+#ifndef NATIVE_C_ARITH
+ const CBV GetBVConst() const;
+#else
+ unsigned long long int GetBVConst() const;
+#endif
+
+ /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0))
+ *
+ *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0))
+ *
+ *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0))
+ *
+ *both indexwidth and valuewidth should never be less than 0
+ */
+ unsigned int GetIndexWidth () const;
+
+ // FIXME: This function is dangerous. Try to eliminate it's use.
+ void SetIndexWidth (unsigned int iw) const;
+
+ unsigned int GetValueWidth () const;
+
+ // FIXME: This function is dangerous. Try to eliminate it's use.
+ void SetValueWidth (unsigned int vw) const;
+
+ //return the type of the ASTNode
+ //0 iff BOOLEAN
+ //1 iff BITVECTOR
+ //2 iff ARRAY
+
+ /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0))
+ *
+ *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0))
+ *
+ *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0))
+ *
+ *both indexwidth and valuewidth should never be less than 0
+ */
+ types GetType(void) const;
+
+ // Hash is pointer value of _int_node_ptr.
+ const size_t Hash() const{
+ return (size_t) _int_node_ptr;
+ //return GetNodeNum();
+ }
+
+ // lisp-form printer
+ ostream& LispPrint(ostream &os, int indentation = 0) const;
+
+ //Presentation Language Printer
+ ostream& PL_Print(ostream &os, int indentation = 0) const;
+
+ void PL_Print1(ostream &os, int indentation = 0, bool b = false) const;
+
+ //Construct let variables for shared subterms
+ void LetizeNode(void) const;
+
+ // Attempt to define something that will work in the gdb
+ friend void lp(ASTNode &node);
+ friend void lpvec(const ASTVec &vec);
+
+ friend ostream &operator<<(ostream &os, const ASTNode &node) {
+ node.LispPrint(os, 0);
+ return os;
+ };
+
+ // Check whether the ASTNode points to anything. Undefined nodes
+ // are created by the default constructor. In binding table (for
+ // lambda args, etc.), undefined nodes are used to represent
+ // deleted entries.
+ bool IsDefined() const { return _int_node_ptr != NULL; }
+
+ /* Hasher class for STL hash_maps and hash_sets that use ASTNodes
+ * as keys. Needs to be public so people can define hash tables
+ * (and use ASTNodeMap class)*/
+ class ASTNodeHasher {
+ public:
+ size_t operator() (const ASTNode& n) const{
+ return (size_t) n._int_node_ptr;
+ //return (size_t)n.GetNodeNum();
+ };
+ }; //End of ASTNodeHasher
+
+ /* Equality for ASTNode hash_set and hash_map. Returns true iff
+ * internal pointers are the same. Needs to be public so people
+ * can define hash tables (and use ASTNodeSet class)*/
+ class ASTNodeEqual {
+ public:
+ bool operator()(const ASTNode& n1, const ASTNode& n2) const{
+ return (n1._int_node_ptr == n2._int_node_ptr);
+ }
+ }; //End of ASTNodeEqual
+ }; //End of Class ASTNode
+
+ void FatalError(const char * str, const ASTNode& a, int w = 0);
+ void FatalError(const char * str);
+ void SortByExprNum(ASTVec& c);
+ bool exprless(const ASTNode n1, const ASTNode n2);
+ bool isAtomic(Kind k);
+
+ /***************************************************************************/
+ /* Class ASTInternal:Abstract base class for internal node representation.*/
+ /* Requires Kind and ChildNodes so same traversal works */
+ /* on all nodes. */
+ /***************************************************************************/
+ class ASTInternal {
+
+ friend class ASTNode;
+
+ protected:
+
+ // reference count.
+ int _ref_count;
+
+ // Kind. It's a type tag and the operator.
+ Kind _kind;
+
+ // The vector of children (*** should this be in ASTInterior? ***)
+ ASTVec _children;
+
+ // Manager object. Having this backpointer means it's easy to
+ // find the manager when we need it.
+ BeevMgr &_bm;
+
+ //Nodenum is a unique positive integer for the node. The nodenum
+ //of a node should always be greater than its descendents (which
+ //is easily achieved by incrementing the number each time a new
+ //node is created).
+ int _node_num;
+
+ // Length of bitvector type for array index. The term is an
+ // array iff this is positive. Otherwise, the term is a bitvector
+ // or a bit.
+ unsigned int _index_width;
+
+ // Length of bitvector type for scalar value or array element.
+ // If this is one, the term represents a single bit (same as a bitvector
+ // of length 1). It must be 1 or greater.
+ unsigned int _value_width;
+
+ // Increment refcount.
+#ifndef SMTLIB
+ void IncRef() { ++_ref_count; }
+#else
+ void IncRef() { }
+#endif
+
+ // DecRef is a potentially expensive, because it has to delete
+ // the node from the unique table, in addition to freeing it.
+ // FIXME: Consider putting in a backpointer (iterator) to the hash
+ // table entry so it can be deleted without looking it up again.
+ void DecRef();
+
+ virtual const Kind GetKind() const { return _kind; }
+
+ virtual ASTVec const &GetChildren() const { return _children; }
+
+ int GetNodeNum() const { return _node_num; }
+
+ void SetNodeNum(int nn) { _node_num = nn; };
+
+ // Constructor (bm only)
+ ASTInternal(BeevMgr &bm, int nodenum = 0) :
+ _ref_count(0),
+ _kind(UNDEFINED),
+ _bm(bm),
+ _node_num(nodenum),
+ _index_width(0),
+ _value_width(0) { }
+
+ // Constructor (kind only, empty children, int nodenum)
+ ASTInternal(Kind kind, BeevMgr &bm, int nodenum = 0) :
+ _ref_count(0),
+ _kind(kind),
+ _bm(bm),
+ _node_num(nodenum),
+ _index_width(0),
+ _value_width(0) { }
+
+ // Constructor (kind and children). This copies the contents of
+ // the child nodes.
+ // FIXME: is there a way to avoid repeating these?
+ ASTInternal(Kind kind, const ASTVec &children, BeevMgr &bm, int nodenum = 0) :
+ _ref_count(0),
+ _kind(kind),
+ _children(children),
+ _bm(bm),
+ _node_num(nodenum),
+ _index_width(0),
+ _value_width(0) { }
+
+ // Copy constructor. This copies the contents of the child nodes
+ // array, along with everything else. Assigning the smart pointer,
+ // ASTNode, does NOT invoke this; This should only be used for
+ // temporary hash keys before uniquefication.
+ // FIXME: I don't think children need to be copied.
+ ASTInternal(const ASTInternal &int_node, int nodenum = 0) :
+ _ref_count(0),
+ _kind(int_node._kind),
+ _children(int_node._children),
+ _bm(int_node._bm),
+ _node_num(int_node._node_num),
+ _index_width(int_node._index_width),
+ _value_width(int_node._value_width) { }
+
+ // Copying assign operator. Also copies contents of children.
+ ASTInternal& operator=(const ASTInternal &int_node);
+
+ // Cleanup function for removing from hash table
+ virtual void CleanUp() = 0;
+
+ // Destructor (does nothing, but is declared virtual here.
+ virtual ~ASTInternal();
+
+ // Abstract virtual print function for internal node.
+ virtual void nodeprint(ostream& os) { os << "*"; };
+ }; //End of Class ASTInternal
+
+ // FIXME: Should children be only in interior node type?
+ /***************************************************************************
+ Class ASTInterior: Internal representation of an interior
+ ASTNode. Generally, these nodes should have at least one
+ child
+ ***************************************************************************/
+ class ASTInterior : public ASTInternal {
+
+ friend class BeevMgr;
+ friend class ASTNodeHasher;
+ friend class ASTNodeEqual;
+
+ private:
+
+ // Hasher for ASTInterior pointer nodes
+ class ASTInteriorHasher {
+ public:
+ size_t operator()(const ASTInterior *int_node_ptr) const;
+ };
+
+ // Equality for ASTInterior nodes
+ class ASTInteriorEqual {
+ public:
+ bool operator()(const ASTInterior *int_node_ptr1,
+ const ASTInterior *int_node_ptr2) const{
+ return (*int_node_ptr1 == *int_node_ptr2);
+ }
+ };
+
+ // Used in Equality class for hash tables
+ friend bool operator==(const ASTInterior &int_node1,
+ const ASTInterior &int_node2){
+ return (int_node1._kind == int_node2._kind) &&
+ (int_node1._children == int_node2._children);
+ }
+
+ // Call this when deleting a node that has been stored in the
+ // the unique table
+ virtual void CleanUp();
+
+ // Returns kinds. "lispprinter" handles printing of parenthesis
+ // and childnodes.
+ virtual void nodeprint(ostream& os) {
+ os << _kind_names[_kind];
+ }
+ public:
+
+ // FIXME: This should not be public, but has to be because the
+ // ASTInterior hash table insists on it. I can't seem to make the
+ // private destructor visible to hash_set. It does not even work
+ // to put "friend class hash_set<ASTInterior, ...>" in here.
+
+ // Basic constructors
+ ASTInterior(Kind kind, BeevMgr &bm) :
+ ASTInternal(kind, bm) { }
+
+ ASTInterior(Kind kind, ASTVec &children, BeevMgr &bm) :
+ ASTInternal(kind, children, bm) { }
+
+ //Copy constructor. This copies the contents of the child nodes
+ //array, along with everything else. Assigning the smart pointer,
+ //ASTNode, does NOT invoke this.
+ ASTInterior(const ASTInterior &int_node) : ASTInternal(int_node) { }
+
+ // Destructor (does nothing, but is declared virtual here.
+ virtual ~ASTInterior();
+
+ }; //End of ASTNodeInterior
+
+
+ /***************************************************************************/
+ /* Class ASTSymbol: Class to represent internals of Symbol node. */
+ /***************************************************************************/
+ class ASTSymbol : public ASTInternal{
+ friend class BeevMgr;
+ friend class ASTNode;
+ friend class ASTNodeHasher;
+ friend class ASTNodeEqual;
+
+ private:
+ // The name of the symbol
+ const char * const _name;
+
+ class ASTSymbolHasher{
+ public:
+ size_t operator() (const ASTSymbol *sym_ptr) const{
+ hash<char*> h;
+ return h(sym_ptr->_name);
+ };
+ };
+
+ // Equality for ASTInternal nodes
+ class ASTSymbolEqual{
+ public:
+ bool operator()(const ASTSymbol *sym_ptr1, const ASTSymbol *sym_ptr2) const{
+ return (*sym_ptr1 == *sym_ptr2);
+ }
+ };
+
+ friend bool operator==(const ASTSymbol &sym1, const ASTSymbol &sym2){
+ return (strcmp(sym1._name, sym2._name) == 0);
+ }
+
+ const char * const GetName() const{return _name;}
+
+ // Print function for symbol -- return name */
+ virtual void nodeprint(ostream& os) { os << _name;}
+
+ // Call this when deleting a node that has been stored in the
+ // the unique table
+ virtual void CleanUp();
+
+ public:
+
+ // Default constructor
+ ASTSymbol(BeevMgr &bm) : ASTInternal(bm), _name(NULL) { }
+
+ // Constructor. This does NOT copy its argument.
+ ASTSymbol(const char * const name, BeevMgr &bm) : ASTInternal(SYMBOL, bm),
+ _name(name) { }
+
+ // Destructor (does nothing, but is declared virtual here.
+ virtual ~ASTSymbol();
+
+ // Copy constructor
+ // FIXME: seems to be calling default constructor for astinternal
+ ASTSymbol(const ASTSymbol &sym) :
+ ASTInternal(sym._kind, sym._children, sym._bm),
+ _name(sym._name) { }
+ }; //End of ASTSymbol
+
+
+ /***************************************************************************/
+ /* Class ASTBVConst: Class to represent internals of a bitvectorconst */
+ /***************************************************************************/
+
+#ifndef NATIVE_C_ARITH
+
+ class ASTBVConst : public ASTInternal {
+ friend class BeevMgr;
+ friend class ASTNode;
+ friend class ASTNodeHasher;
+ friend class ASTNodeEqual;
+
+ private:
+ //This is the private copy of a bvconst currently
+ //This should not be changed at any point
+ CBV _bvconst;
+
+ class ASTBVConstHasher{
+ public:
+ size_t operator() (const ASTBVConst * bvc) const {
+ return CONSTANTBV::BitVector_Hash(bvc->_bvconst);
+ };
+ };
+
+ class ASTBVConstEqual{
+ public:
+ bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const {
+ if( bvc1->_value_width != bvc2->_value_width){
+ return false;
+ }
+ return (0==CONSTANTBV::BitVector_Compare(bvc1->_bvconst,bvc2->_bvconst));
+ }
+ };
+
+ //FIXME Keep an eye on this function
+ ASTBVConst(CBV bv, unsigned int width, BeevMgr &bm) :
+ ASTInternal(BVCONST, bm)
+ {
+ _bvconst = CONSTANTBV::BitVector_Clone(bv);
+ _value_width = width;
+ }
+
+ friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){
+ if(bvc1._value_width != bvc2._value_width)
+ return false;
+ return (0==CONSTANTBV::BitVector_Compare(bvc1._bvconst,bvc2._bvconst));
+ }
+ // Call this when deleting a node that has been stored in the
+ // the unique table
+ virtual void CleanUp();
+
+ // Print function for bvconst -- return _bvconst value in bin format
+ virtual void nodeprint(ostream& os) {
+ unsigned char *res;
+ const char *prefix;
+
+ if (_value_width%4 == 0) {
+ res = CONSTANTBV::BitVector_to_Hex(_bvconst);
+ prefix = "0hex";
+ } else {
+ res = CONSTANTBV::BitVector_to_Bin(_bvconst);
+ prefix = "0bin";
+ }
+ if (NULL == res) {
+ os << "nodeprint: BVCONST : could not convert to string" << _bvconst;
+ FatalError("");
+ }
+ os << prefix << res;
+ CONSTANTBV::BitVector_Dispose(res);
+ }
+
+ // Copy constructor.
+ ASTBVConst(const ASTBVConst &sym) :
+ ASTInternal(sym._kind, sym._children, sym._bm)
+ {
+ _bvconst = CONSTANTBV::BitVector_Clone(sym._bvconst);
+ _value_width = sym._value_width;
+ }
+
+ public:
+ virtual ~ASTBVConst(){
+ CONSTANTBV::BitVector_Destroy(_bvconst);
+ }
+
+ CBV GetBVConst() const {return _bvconst;}
+ }; //End of ASTBVConst
+
+ //FIXME This function is DEPRICATED
+ //Do not use in the future
+ inline unsigned int GetUnsignedConst(const ASTNode n) {
+ if(32 < n.GetValueWidth())
+ FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:");
+
+ return (unsigned int) *((unsigned int *)n.GetBVConst());
+ }
+#else
+ class ASTBVConst : public ASTInternal {
+ friend class BeevMgr;
+ friend class ASTNode;
+ friend class ASTNodeHasher;
+ friend class ASTNodeEqual;
+
+ private:
+ // the bitvector contents. bitvector contents will be in two
+ // modes. one mode where all bitvectors are NATIVE and in this
+ // mode we use native unsigned long long int to represent the
+ // 32/64 bitvectors. The other for arbitrary length bitvector
+ // operations.
+ const unsigned long long int _bvconst;
+
+ class ASTBVConstHasher{
+ public:
+ size_t operator() (const ASTBVConst * bvc) const{
+ //Thomas Wang's 64 bit Mix Function
+ unsigned long long int key(bvc->_bvconst);
+ key += ~(key << 32);
+ key ^= (key >> 22);
+ key += ~(key << 13);
+ key ^= (key >> 8);
+ key += (key << 3);
+ key ^= (key >> 15);
+ key += ~(key << 27);
+ key ^= (key >> 31);
+
+ size_t return_key = key;
+ return return_key;
+ };
+ };
+
+ class ASTBVConstEqual{
+ public:
+ bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const {
+ return ((bvc1->_bvconst == bvc2->_bvconst)
+ && (bvc1->_value_width == bvc2->_value_width));
+ }
+ };
+
+ // Call this when deleting a node that has been stored in the
+ // the unique table
+ virtual void CleanUp();
+ public:
+ // Default constructor
+ ASTBVConst(const unsigned long long int bv, BeevMgr &bm) :
+ ASTInternal(BVCONST, bm), _bvconst(bv) {
+ }
+
+ // Copy constructor. FIXME: figure out how this is supposed to
+ // work.
+ ASTBVConst(const ASTBVConst &sym) :
+ ASTInternal(sym._kind, sym._children, sym._bm),
+ _bvconst(sym._bvconst) {
+ _value_width = sym._value_width;
+ }
+
+ // Destructor (does nothing, but is declared virtual here)
+ virtual ~ASTBVConst() { }
+
+ friend bool operator==(const ASTBVConst &sym1, const ASTBVConst &sym2){
+ return ((sym1._bvconst == sym2._bvconst) &&
+ (sym1._value_width == sym2._value_width));
+ }
+
+ // Print function for bvconst -- return _bvconst value in binary format
+ virtual void nodeprint(ostream& os) {
+ string s = "0bin";
+ unsigned long long int bitmask = 0x8000000000000000LL;
+ bitmask = bitmask >> (64-_value_width);
+
+ for (; bitmask > 0; bitmask >>= 1)
+ s += (_bvconst & bitmask) ? '1' : '0';
+ os << s;
+ }
+
+ unsigned long long int GetBVConst() const {return _bvconst;}
+ }; //End of ASTBVConst
+
+ //return value of bvconst
+ inline unsigned int GetUnsignedConst(const ASTNode n) {
+ if(32 < n.GetValueWidth())
+ FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:");
+ return (unsigned int)n.GetBVConst();
+ }
+#endif
+/*
+#else
+ // the bitvector contents. bitvector contents will be in two
+ // modes. one mode where all bitvectors are NATIVE and in this mode
+ // we use native unsigned long long int to represent the 32/64
+ // bitvectors. The other for arbitrary length bitvector operations.
+
+ //BVCONST defined for arbitrary length bitvectors
+ class ASTBVConst : public ASTInternal{
+ friend class BeevMgr;
+ friend class ASTNode;
+ friend class ASTNodeHasher;
+ friend class ASTNodeEqual;
+
+ private:
+ const char * const _bvconst;
+
+ class ASTBVConstHasher{
+ public:
+ size_t operator() (const ASTBVConst * bvc) const{
+ hash<char*> h;
+ return h(bvc->_bvconst);
+ };
+ };
+
+ class ASTBVConstEqual{
+ public:
+ bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const {
+ if(bvc1->_value_width != bvc2->_value_width)
+ return false;
+ return (0 == strncmp(bvc1->_bvconst,bvc2->_bvconst,bvc1->_value_width));
+ }
+ };
+
+ ASTBVConst(const char * bv, BeevMgr &bm) :
+ ASTInternal(BVCONST, bm), _bvconst(bv) {
+ //_value_width = strlen(bv);
+ }
+
+ friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){
+ if(bvc1._value_width != bvc2._value_width)
+ return false;
+ return (0 == strncmp(bvc1._bvconst,bvc2._bvconst,bvc1._value_width));
+ }
+
+ // Call this when deleting a node that has been stored in the
+ // the unique table
+ virtual void CleanUp();
+
+ // Print function for bvconst -- return _bvconst value in binary format
+ virtual void nodeprint(ostream& os) {
+ if(_value_width%4 == 0) {
+ unsigned int * iii = CONSTANTBV::BitVector_Create(_value_width,true);
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,(unsigned char*)_bvconst);
+ //error printing
+ if(0 != e) {
+ os << "nodeprint: BVCONST : wrong hex value: " << BitVector_Error(e);
+ FatalError("");
+ }
+ unsigned char * ccc = CONSTANTBV::BitVector_to_Hex(iii);
+ os << "0hex" << ccc;
+ CONSTANTBV::BitVector_Destroy(iii);
+ }
+ else {
+ std::string s(_bvconst,_value_width);
+ s = "0bin" + s;
+ os << s;
+ }
+ }
+
+ // Copy constructor.
+ ASTBVConst(const ASTBVConst &sym) : ASTInternal(sym._kind, sym._children, sym._bm),_bvconst(sym._bvconst) {
+ //checking if the input is in the correct format
+ for(unsigned int jj=0;jj<sym._value_width;jj++)
+ if(!(sym._bvconst[jj] == '0' || sym._bvconst[jj] == '1')) {
+ cerr << "Fatal Error: wrong input to ASTBVConst copy constructor:" << sym._bvconst << endl;
+ FatalError("");
+ }
+ _value_width = sym._value_width;
+ }
+ public:
+ // Destructor (does nothing, but is declared virtual here)
+ virtual ~ASTBVConst(){}
+
+ const char * const GetBVConst() const {return _bvconst;}
+ }; //End of ASTBVConst
+
+ unsigned int * ConvertToCONSTANTBV(const char * s);
+
+ //return value of bvconst
+ inline unsigned int GetUnsignedConst(const ASTNode n) {
+ if(32 < n.GetValueWidth())
+ FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:");
+ std::string s(n.GetBVConst(), n.GetValueWidth());
+ unsigned int output = strtoul(s.c_str(),NULL,2);
+ return output;
+ } //end of ASTBVConst class
+#endif
+*/
+ /***************************************************************************
+ * Typedef ASTNodeMap: This is a hash table from ASTNodes to ASTNodes.
+ * It is very convenient for attributes that are not speed-critical
+ **************************************************************************/
+ // These are generally useful for storing ASTNodes or attributes thereof
+ // Hash table from ASTNodes to ASTNodes
+ typedef hash_map<ASTNode, ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeMap;
+
+ // Function to dump contents of ASTNodeMap
+ ostream &operator<<(ostream &os, const ASTNodeMap &nmap);
+
+ /***************************************************************************
+ Typedef ASTNodeSet: This is a hash set of ASTNodes. Very useful
+ for representing things like "visited nodes"
+ ***************************************************************************/
+ typedef hash_set<ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeSet;
+
+ typedef hash_multiset<ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeMultiSet;
+
+ //external parser table for declared symbols.
+ //FIXME: move to a more appropriate place
+ extern ASTNodeSet _parser_symbol_table;
+
+ /***************************************************************************
+ Class LispPrinter: iomanipulator for printing ASTNode or ASTVec
+ ***************************************************************************/
+ class LispPrinter {
+
+ public:
+ ASTNode _node;
+
+ // number of spaces to print before first real character of
+ // object.
+ int _indentation;
+
+ // FIXME: pass ASTNode by reference
+ // Constructor to build the LispPrinter object
+ LispPrinter(ASTNode node, int indentation): _node(node), _indentation(indentation) { }
+
+ friend ostream &operator<<(ostream &os, const LispPrinter &lp){
+ return lp._node.LispPrint(os, lp._indentation);
+ };
+
+ }; //End of ListPrinter
+
+ //This is the IO manipulator. It builds an object of class
+ //"LispPrinter" that has a special overloaded "<<" operator.
+ inline LispPrinter lisp(const ASTNode &node, int indentation = 0){
+ LispPrinter lp(node, indentation);
+ return lp;
+ }
+
+ /***************************************************************************/
+ /* Class LispVecPrinter:iomanipulator for printing vector of ASTNodes */
+ /***************************************************************************/
+ class LispVecPrinter {
+
+ public:
+ const ASTVec * _vec;
+ // number of spaces to print before first real
+ // character of object.
+ int _indentation;
+
+ // Constructor to build the LispPrinter object
+ LispVecPrinter(const ASTVec &vec, int indentation){
+ _vec = &vec; _indentation = indentation;
+ }
+
+ friend ostream &operator<<(ostream &os, const LispVecPrinter &lvp){
+ LispPrintVec(os, *lvp._vec, lvp._indentation);
+ return os;
+ };
+ }; //End of Class ListVecPrinter
+
+ //iomanipulator. builds an object of class "LisPrinter" that has a
+ //special overloaded "<<" operator.
+ inline LispVecPrinter lisp(const ASTVec &vec, int indentation = 0){
+ LispVecPrinter lvp(vec, indentation);
+ return lvp;
+ }
+
+
+ /*****************************************************************
+ * INLINE METHODS from various classed, declared here because of
+ * dependencies on classes that are declared later.
+ *****************************************************************/
+ // ASTNode accessor function.
+ inline Kind ASTNode::GetKind() const {
+ //cout << "GetKind: " << _int_node_ptr;
+ return _int_node_ptr->GetKind();
+ }
+
+ // FIXME: should be const ASTVec const?
+ // Declared here because of same ordering problem as GetKind.
+ inline const ASTVec &ASTNode::GetChildren() const {
+ return _int_node_ptr->GetChildren();
+ }
+
+ // Access node number
+ inline int ASTNode::GetNodeNum() const {
+ return _int_node_ptr->_node_num;
+ }
+
+ inline unsigned int ASTNode::GetIndexWidth () const {
+ return _int_node_ptr->_index_width;
+ }
+
+ inline void ASTNode::SetIndexWidth (unsigned int iw) const {
+ _int_node_ptr->_index_width = iw;
+ }
+
+ inline unsigned int ASTNode::GetValueWidth () const {
+ return _int_node_ptr->_value_width;
+ }
+
+ inline void ASTNode::SetValueWidth (unsigned int vw) const {
+ _int_node_ptr->_value_width = vw;
+ }
+
+ //return the type of the ASTNode: 0 iff BOOLEAN; 1 iff BITVECTOR; 2
+ //iff ARRAY; 3 iff UNKNOWN;
+ inline types ASTNode::GetType() const {
+ if((GetIndexWidth() == 0) && (GetValueWidth() == 0)) //BOOLEAN
+ return BOOLEAN_TYPE;
+ if((GetIndexWidth() == 0) && (GetValueWidth() > 0)) //BITVECTOR
+ return BITVECTOR_TYPE;
+ if((GetIndexWidth() > 0) && (GetValueWidth() > 0)) //ARRAY
+ return ARRAY_TYPE;
+ return UNKNOWN_TYPE;
+ }
+
+ // Constructor; creates a new pointer, increments refcount of
+ // pointed-to object.
+#ifndef SMTLIB
+ inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) {
+ if (in) in->IncRef();
+ }
+#else
+ inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) { };
+#endif
+
+ // Assignment. Increment refcount of new value, decrement refcount
+ // of old value and destroy if this was the last pointer. FIXME:
+ // accelerate this by creating an intnode with a ref counter instead
+ // of pointing to NULL. Need a special check in CleanUp to make
+ // sure the null node never gets freed.
+
+#ifndef SMTLIB
+ inline ASTNode& ASTNode::operator=(const ASTNode& n) {
+ if (n._int_node_ptr) {
+ n._int_node_ptr->IncRef();
+ }
+ if (_int_node_ptr) {
+ _int_node_ptr->DecRef();
+ }
+ _int_node_ptr = n._int_node_ptr;
+ return *this;
+ }
+#else
+ inline ASTNode& ASTNode::operator=(const ASTNode& n) {
+ _int_node_ptr = n._int_node_ptr;
+ return *this;
+ }
+#endif
+
+#ifndef SMTLIB
+ inline void ASTInternal::DecRef()
+ {
+ if (--_ref_count == 0) {
+ // Delete node from unique table and kill it.
+ CleanUp();
+ }
+ }
+
+ // Destructor
+ inline ASTNode::~ASTNode()
+ {
+ if (_int_node_ptr) {
+ _int_node_ptr->DecRef();
+ }
+ };
+#else
+ // No refcounting
+ inline void ASTInternal::DecRef()
+ {
+ }
+
+ // Destructor
+ inline ASTNode::~ASTNode()
+ {
+ };
+#endif
+
+ inline BeevMgr& ASTNode::GetBeevMgr() const { return _int_node_ptr->_bm; }
+
+ /***************************************************************************
+ * Class BeevMgr. This holds all "global" variables for the system, such as
+ * unique tables for the various kinds of nodes.
+ ***************************************************************************/
+ class BeevMgr {
+ friend class ASTNode; // ASTNode modifies AlreadyPrintedSet
+ // in BeevMgr
+ friend class ASTInterior;
+ friend class ASTBVConst;
+ friend class ASTSymbol;
+
+ // FIXME: The values appear to be the same regardless of the value of SMTLIB
+ // initial hash table sizes, to save time on resizing.
+#ifdef SMTLIB
+ static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100;
+ static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100;
+
+ static const int INITIAL_SIMPLIFY_MAP_SIZE = 100;
+ static const int INITIAL_SOLVER_MAP_SIZE = 100;
+ static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100;
+ static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100;
+#else
+ // these are the STL defaults
+ static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100;
+ static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100;
+ static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100;
+
+ static const int INITIAL_SIMPLIFY_MAP_SIZE = 100;
+ static const int INITIAL_SOLVER_MAP_SIZE = 100;
+ static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100;
+ static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100;
+#endif
+
+ private:
+ // Typedef for unique Interior node table.
+ typedef hash_set<ASTInterior *,
+ ASTInterior::ASTInteriorHasher,
+ ASTInterior::ASTInteriorEqual> ASTInteriorSet;
+
+ // Typedef for unique Symbol node (leaf) table.
+ typedef hash_set<ASTSymbol *,
+ ASTSymbol::ASTSymbolHasher,
+ ASTSymbol::ASTSymbolEqual> ASTSymbolSet;
+
+ // Unique tables to share nodes whenever possible.
+ ASTInteriorSet _interior_unique_table;
+ //The _symbol_unique_table is also the symbol table to be used
+ //during parsing/semantic analysis
+ ASTSymbolSet _symbol_unique_table;
+
+ //Typedef for unique BVConst node (leaf) table.
+ typedef hash_set<ASTBVConst *,
+ ASTBVConst::ASTBVConstHasher,
+ ASTBVConst::ASTBVConstEqual> ASTBVConstSet;
+
+ //table to uniquefy bvconst
+ ASTBVConstSet _bvconst_unique_table;
+
+ // type of memo table.
+ typedef hash_map<ASTNode, ASTVec,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeToVecMap;
+
+ typedef hash_map<ASTNode,ASTNodeSet,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeToSetMap;
+
+ // Memo table for bit blasted terms. If a node has already been
+ // bitblasted, it is mapped to a vector of Boolean formulas for
+ // the bits.
+
+ //OLD: ASTNodeToVecMap BBTermMemo;
+ ASTNodeMap BBTermMemo;
+
+ // Memo table for bit blasted formulas. If a node has already
+ // been bitblasted, it is mapped to a node representing the
+ // bitblasted equivalent
+ ASTNodeMap BBFormMemo;
+
+ //public:
+ // Get vector of Boolean formulas for sum of two
+ // vectors of Boolean formulas
+ void BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin);
+ // Increment
+ ASTVec BBInc(ASTVec& x);
+ // Add one bit to a vector of bits.
+ ASTVec BBAddOneBit(ASTVec& x, ASTNode cin);
+ // Bitwise complement
+ ASTVec BBNeg(const ASTVec& x);
+ // Unary minus
+ ASTVec BBUminus(const ASTVec& x);
+ // Multiply.
+ ASTVec BBMult(const ASTVec& x, const ASTVec& y);
+ // AND each bit of vector y with single bit b and return the result.
+ // (used in BBMult)
+ ASTVec BBAndBit(const ASTVec& y, ASTNode b);
+ // Returns ASTVec for result - y. This destroys "result".
+ void BBSub(ASTVec& result, const ASTVec& y);
+ // build ITE's (ITE cond then[i] else[i]) for each i.
+ ASTVec BBITE(const ASTNode& cond,
+ const ASTVec& thn, const ASTVec& els);
+ // Build a vector of zeros.
+ ASTVec BBfill(unsigned int width, ASTNode fillval);
+ // build an EQ formula
+ ASTNode BBEQ(const ASTVec& left, const ASTVec& right);
+
+ // This implements a variant of binary long division.
+ // q and r are "out" parameters. rwidth puts a bound on the
+ // recursion depth. Unsigned only, for now.
+ void BBDivMod(const ASTVec &y,
+ const ASTVec &x,
+ ASTVec &q,
+ ASTVec &r,
+ unsigned int rwidth);
+
+ // Return formula for majority function of three formulas.
+ ASTNode Majority(const ASTNode& a, const ASTNode& b, const ASTNode& c);
+
+ // Internal bit blasting routines.
+ ASTNode BBBVLE(const ASTVec& x, const ASTVec& y, bool is_signed);
+
+ // Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc.
+ ASTNode BBcompare(const ASTNode& form);
+
+ // Left and right shift one. Writes into x.
+ void BBLShift(ASTVec& x);
+ void BBRShift(ASTVec& x);
+
+ public:
+ // Simplifying create functions
+ ASTNode CreateSimpForm(Kind kind, ASTVec &children);
+ ASTNode CreateSimpForm(Kind kind, const ASTNode& child0);
+ ASTNode CreateSimpForm(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1);
+ ASTNode CreateSimpForm(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2);
+
+ ASTNode CreateSimpNot(const ASTNode& form);
+
+ // These are for internal use only.
+ // FIXME: Find a way to make this local to SimpBool, so they're
+ // not in AST.h
+ ASTNode CreateSimpXor(const ASTNode& form1,
+ const ASTNode& form2);
+ ASTNode CreateSimpXor(ASTVec &children);
+ ASTNode CreateSimpAndOr(bool isAnd,
+ const ASTNode& form1,
+ const ASTNode& form2);
+ ASTNode CreateSimpAndOr(bool IsAnd, ASTVec &children);
+ ASTNode CreateSimpFormITE(const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2);
+
+
+ // Declarations of BitBlaster functions (BitBlast.cpp)
+ public:
+ // Adds or removes a NOT as necessary to negate a literal.
+ ASTNode Negate(const ASTNode& form);
+
+ // Bit blast a bitvector term. The term must have a kind for a
+ // bitvector term. Result is a ref to a vector of formula nodes
+ // representing the boolean formula.
+ const ASTNode BBTerm(const ASTNode& term);
+
+ const ASTNode BBForm(const ASTNode& formula);
+
+ // Declarations of CNF conversion (ToCNF.cpp)
+ public:
+ // ToCNF converts a bit-blasted Boolean formula to Conjunctive
+ // Normal Form, suitable for many SAT solvers. Our CNF representation
+ // is an STL vector of STL vectors, for independence from any particular
+ // SAT solver's representation. There needs to be a separate driver to
+ // convert our clauselist to the representation used by the SAT solver.
+ // Currently, there is only one such solver and its driver is "ToSAT"
+
+ // Datatype for clauses
+ typedef ASTVec * ClausePtr;
+
+ // Datatype for Clauselists
+ typedef vector<ClausePtr> ClauseList;
+
+ // Convert a Boolean formula to an equisatisfiable CNF formula.
+ ClauseList *ToCNF(const ASTNode& form);
+
+ // Print function for debugging
+ void PrintClauseList(ostream& os, ClauseList& cll);
+
+ // Free the clause list and all its clauses.
+ void DeleteClauseList(BeevMgr::ClauseList *cllp);
+
+ // Map from formulas to representative literals, for debugging.
+ ASTNodeMap RepLitMap;
+
+ private:
+ // Global for assigning new node numbers.
+ int _max_node_num;
+
+ const ASTNode ASTFalse, ASTTrue, ASTUndefined;
+
+ // I just did this so I could put it in as a fake return value in
+ // methods that return a ASTNode &, to make -Wall shut up.
+ ASTNode dummy_node;
+
+ //BeevMgr Constructor, Destructor and other misc. functions
+ public:
+
+ int NewNodeNum() { _max_node_num += 2; return _max_node_num; }
+
+ // Table for DAG printing.
+ ASTNodeSet AlreadyPrintedSet;
+
+ //Tables for Presentation language printing
+
+ //Nodes seen so far
+ ASTNodeSet PLPrintNodeSet;
+
+ //Map from ASTNodes to LetVars
+ ASTNodeMap NodeLetVarMap;
+
+ //This is a vector which stores the Node to LetVars pairs. It
+ //allows for sorted printing, as opposed to NodeLetVarMap
+ std::vector<pair<ASTNode,ASTNode> > NodeLetVarVec;
+
+ //a partial Map from ASTNodes to LetVars. Needed in order to
+ //correctly print shared subterms inside the LET itself
+ ASTNodeMap NodeLetVarMap1;
+
+ //functions to lookup nodes from the memo tables. these should be
+ //private.
+ private:
+ //Destructively appends back_child nodes to front_child nodes.
+ //If back_child nodes is NULL, no appending is done. back_child
+ //nodes are not modified. Then it returns the hashed copy of the
+ //node, which is created if necessary.
+ ASTInterior *CreateInteriorNode(Kind kind,
+ ASTInterior *new_node,
+ // this is destructively modified.
+ const ASTVec & back_children = _empty_ASTVec);
+
+ // Create unique ASTInterior node.
+ ASTInterior *LookupOrCreateInterior(ASTInterior *n);
+
+ // Create unique ASTSymbol node.
+ ASTSymbol *LookupOrCreateSymbol(ASTSymbol& s);
+
+ // Called whenever we want to make sure that the Symbol is
+ // declared during semantic analysis
+ bool LookupSymbol(ASTSymbol& s);
+
+ // Called by ASTNode constructors to uniqueify ASTBVConst
+ ASTBVConst *LookupOrCreateBVConst(ASTBVConst& s);
+
+ //Public functions for CreateNodes and Createterms
+ public:
+ // Create and return an ASTNode for a symbol
+ ASTNode CreateSymbol(const char * const name);
+
+ // Create and return an ASTNode for a symbol
+ // Width is number of bits.
+ ASTNode CreateBVConst(unsigned int width, unsigned long long int bvconst);
+ ASTNode CreateZeroConst(unsigned int width);
+ ASTNode CreateOneConst(unsigned int width);
+ ASTNode CreateTwoConst(unsigned int width);
+ ASTNode CreateMaxConst(unsigned int width);
+
+ // Create and return an ASTNode for a symbol
+ // Optional base was a problem because 0 could be an int or char *,
+ // so CreateBVConst was ambiguous.
+ ASTNode CreateBVConst(const char *strval, int base);
+
+ //FIXME This is a dangerous function
+ ASTNode CreateBVConst(CBV bv, unsigned width);
+
+ // Create and return an interior ASTNode
+ ASTNode CreateNode(Kind kind, const ASTVec &children = _empty_ASTVec);
+
+ ASTNode CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTVec &children = _empty_ASTVec);
+
+ ASTNode CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTVec &children = _empty_ASTVec);
+
+ ASTNode CreateNode(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2,
+ const ASTVec &children = _empty_ASTVec);
+
+ // Create and return an ASTNode for a term
+ inline ASTNode CreateTerm(Kind kind,
+ unsigned int width,
+ const ASTVec &children = _empty_ASTVec) {
+ if(!is_Term_kind(kind))
+ FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind);
+ ASTNode n = CreateNode(kind, children);
+ n.SetValueWidth(width);
+
+ //by default we assume that the term is a Bitvector. If
+ //necessary the indexwidth can be changed later
+ n.SetIndexWidth(0);
+ return n;
+ }
+
+ inline ASTNode CreateTerm(Kind kind,
+ unsigned int width,
+ const ASTNode& child0,
+ const ASTVec &children = _empty_ASTVec) {
+ if(!is_Term_kind(kind))
+ FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind);
+ ASTNode n = CreateNode(kind, child0, children);
+ n.SetValueWidth(width);
+ return n;
+ }
+
+ inline ASTNode CreateTerm(Kind kind,
+ unsigned int width,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTVec &children = _empty_ASTVec) {
+ if(!is_Term_kind(kind))
+ FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind);
+ ASTNode n = CreateNode(kind, child0, child1, children);
+ n.SetValueWidth(width);
+ return n;
+ }
+
+ inline ASTNode CreateTerm(Kind kind,
+ unsigned int width,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2,
+ const ASTVec &children = _empty_ASTVec) {
+ if(!is_Term_kind(kind))
+ FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind);
+ ASTNode n = CreateNode(kind, child0, child1, child2, children);
+ n.SetValueWidth(width);
+ return n;
+ }
+
+ ASTNode SimplifyFormula_NoRemoveWrites(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyTerm_TopLevel(const ASTNode& b);
+ ASTNode SimplifyTerm(const ASTNode& a);
+ void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output);
+ private:
+ //memo table for simplifcation
+ ASTNodeMap SimplifyMap;
+ ASTNodeMap SimplifyNegMap;
+ ASTNodeMap SolverMap;
+ ASTNodeSet AlwaysTrueFormMap;
+ ASTNodeMap MultInverseMap;
+
+ public:
+ ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg);
+ ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2);
+ ASTNode ITEOpt_InEqs(const ASTNode& in1);
+ ASTNode CreateSimplifiedTermITE(const ASTNode& t1, const ASTNode& t2, const ASTNode& t3);
+ ASTNode CreateSimplifiedINEQ(Kind k, const ASTNode& a0, const ASTNode& a1, bool pushNeg);
+ ASTNode SimplifyNotFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg);
+ ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg);
+ ASTNode FlattenOneLevel(const ASTNode& a);
+ ASTNode FlattenAndOr(const ASTNode& a);
+ ASTNode CombineLikeTerms(const ASTNode& a);
+ ASTNode LhsMinusRhs(const ASTNode& eq);
+ ASTNode DistributeMultOverPlus(const ASTNode& a,
+ bool startdistribution=false);
+ ASTNode ConvertBVSXToITE(const ASTNode& a);
+ //checks if the input constant is odd or not
+ bool BVConstIsOdd(const ASTNode& c);
+ //computes the multiplicatve inverse of the input
+ ASTNode MultiplicativeInverse(const ASTNode& c);
+
+ void ClearAllTables(void);
+ void ClearAllCaches(void);
+ int BeforeSAT_ResultCheck(const ASTNode& q);
+ int CallSAT_ResultCheck(MINISAT::Solver& newS,
+ const ASTNode& q, const ASTNode& orig_input);
+ int SATBased_ArrayReadRefinement(MINISAT::Solver& newS,
+ const ASTNode& q, const ASTNode& orig_input);
+ int SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input);
+ //creates array write axiom only for the input term or formula, if
+ //necessary. If there are no axioms to produce then it simply
+ //generates TRUE
+ ASTNode Create_ArrayWriteAxioms(const ASTNode& array_readoverwrite_term, const ASTNode& array_newname);
+ ASTVec ArrayWrite_RemainingAxioms;
+ //variable indicates that counterexample will now be checked by
+ //the counterexample checker, and hence simplifyterm must switch
+ //off certain optimizations. In particular, array write
+ //optimizations
+ bool start_abstracting;
+ bool Begin_RemoveWrites;
+ bool SimplifyWrites_InPlace_Flag;
+
+ void CopySolverMap_To_CounterExample(void);
+ //int LinearSearch(const ASTNode& orig_input);
+ //Datastructures and functions needed for counterexample
+ //generation, and interface with MINISAT
+ private:
+ /* MAP: This is a map from ASTNodes to MINISAT::Vars.
+ *
+ * The map is populated while ASTclauses are read from the AST
+ * ClauseList returned by CNF converter. For every new boolean
+ * variable in ASTClause a new MINISAT::Var is created (these vars
+ * typedefs for ints)
+ */
+ typedef hash_map<ASTNode, MINISAT::Var,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTtoSATMap;
+ ASTtoSATMap _ASTNode_to_SATVar;
+
+ public:
+ //converts the clause to SAT and calls SAT solver
+ bool toSATandSolve(MINISAT::Solver& S, ClauseList& cll);
+
+ ///print SAT solver statistics
+ void PrintStats(MINISAT::SolverStats& stats);
+
+ //accepts query and returns the answer. if query is valid, return
+ //true, else return false. Automatically constructs counterexample
+ //for invalid queries, and prints them upon request.
+ int TopLevelSAT(const ASTNode& query, const ASTNode& asserts);
+
+ // Debugging function to find problems in BitBlast and ToCNF.
+ // See body in ToSAT.cpp for more explanation.
+ ASTNode CheckBBandCNF(MINISAT::Solver& newS, ASTNode form);
+
+ // Internal recursive body of above.
+ ASTNode CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form);
+
+ // Helper function for CheckBBandCNF
+ ASTNode SymbolTruthValue(MINISAT::Solver &newS, ASTNode form);
+
+ //looksup a MINISAT var from the minisat-var memo-table. if none
+ //exists, then creates one.
+ const MINISAT::Var LookupOrCreateSATVar(MINISAT::Solver& S, const ASTNode& n);
+
+ // Memo table for CheckBBandCNF debugging function
+ ASTNodeMap CheckBBandCNFMemo;
+
+
+ //Data structures for Array Read Transformations
+ private:
+ /* MAP: This is a map from Array Names to list of array-read
+ * indices in the input. This map is used by the TransformArray()
+ * function
+ *
+ * This map is useful in converting array reads into nested ITE
+ * constructs. Suppose there are two array reads in the input
+ * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a
+ * symbolic constant, say v1, and Read(A,j) is replaced with the
+ * following ITE:
+ *
+ * ITE(i=j,v1,v2)
+ */
+ //CAUTION: I tried using a set instead of vector for
+ //readindicies. for some odd reason the performance went down
+ //considerably. this is totally inexplicable.
+ ASTNodeToVecMap _arrayname_readindices;
+
+ /* MAP: This is a map from Array Names to nested ITE constructs,
+ * which are built as described below. This map is used by the
+ * TransformArray() function
+ *
+ * This map is useful in converting array reads into nested ITE
+ * constructs. Suppose there are two array reads in the input
+ * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a
+ * symbolic constant, say v1, and Read(A,j) is replaced with the
+ * following ITE:
+ *
+ * ITE(i=j,v1,v2)
+ */
+ ASTNodeMap _arrayread_ite;
+
+ /*MAP: This is a map from array-reads to symbolic constants. This
+ *map is used by the TransformArray()
+ */
+ ASTNodeMap _arrayread_symbol;
+
+ ASTNodeSet _introduced_symbols;
+
+ /*Memoization map for TransformFormula/TransformTerm/TransformArray function
+ */
+ ASTNodeMap TransformMap;
+
+ //count to keep track of new symbolic constants introduced
+ //corresponding to Array Reads
+ unsigned int _symbol_count;
+
+ //Formula/Term Transformers. Let Expr Manager, Type Checker
+ public:
+ //Functions that Transform ASTNodes
+ ASTNode TransformFormula(const ASTNode& query);
+ ASTNode TransformTerm(const ASTNode& term);
+ ASTNode TransformArray(const ASTNode& term);
+ ASTNode TranslateSignedDivMod(const ASTNode& term);
+
+ //LET Management
+ private:
+ // MAP: This map is from bound IDs that occur in LETs to
+ // expression. The map is useful in checking replacing the IDs
+ // with the corresponding expressions.
+ ASTNodeMap _letid_expr_map;
+ public:
+
+ ASTNode ResolveID(const ASTNode& var);
+
+ //Functions that are used to manage LET expressions
+ void LetExprMgr(const ASTNode& var, const ASTNode& letExpr);
+
+ //Delete Letid Map
+ void CleanupLetIDMap(void);
+
+ //Allocate LetID map
+ void InitializeLetIDMap(void);
+
+ //Substitute Let-vars with LetExprs
+ ASTNode SubstituteLetExpr(ASTNode inExpr);
+
+ /* MAP: This is a map from MINISAT::Vars to ASTNodes
+ *
+ * This is a reverse map, useful in constructing
+ * counterexamples. MINISAT returns a model in terms of MINISAT
+ * Vars, and this map helps us convert it to a model over ASTNode
+ * variables.
+ */
+ vector<ASTNode> _SATVar_to_AST;
+
+ private:
+ /* MAP: This is a map from ASTNodes to vectors of bits
+ *
+ * This map is used in constructing and printing
+ * counterexamples. MINISAT returns values for each bit (a
+ * BVGETBIT Node), and this maps allows us to assemble the bits
+ * into bitvectors.
+ */
+ typedef hash_map<ASTNode, hash_map<unsigned int, bool> *,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTtoBitvectorMap;
+ ASTtoBitvectorMap _ASTNode_to_Bitvector;
+
+ //Data structure that holds the counter-model
+ ASTNodeMap CounterExampleMap;
+
+ //Checks if the counter_example is ok. In order for the
+ //counter_example to be ok, Every assert must evaluate to true
+ //w.r.t couner_example and the query must evaluate to
+ //false. Otherwise the counter_example is bogus.
+ void CheckCounterExample(bool t);
+
+ //Converts a vector of bools to a BVConst
+ ASTNode BoolVectoBVConst(hash_map<unsigned,bool> * w, unsigned int l);
+
+ //accepts a term and turns it into a constant-term w.r.t counter_example
+ ASTNode TermToConstTermUsingModel(const ASTNode& term, bool ArrayReadFlag = true);
+ ASTNode Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool ArrayReadFlag = true);
+ //Computes the truth value of a formula w.r.t counter_example
+ ASTNode ComputeFormulaUsingModel(const ASTNode& form);
+
+ //Replaces WRITE(Arr,i,val) with ITE(j=i, val, READ(Arr,j))
+ ASTNode RemoveWrites_TopLevel(const ASTNode& term);
+ ASTNode RemoveWrites(const ASTNode& term);
+ ASTNode SimplifyWrites_InPlace(const ASTNode& term);
+ ASTNode ReadOverWrite_To_ITE(const ASTNode& term);
+
+ ASTNode NewArrayVar(unsigned int index, unsigned int value);
+ ASTNode NewVar(unsigned int valuewidth);
+ //For ArrayWrite Abstraction: map from read-over-write term to
+ //newname.
+ ASTNodeMap ReadOverWrite_NewName_Map;
+ //For ArrayWrite Refinement: Map new arraynames to Read-Over-Write
+ //terms
+ ASTNodeMap NewName_ReadOverWrite_Map;
+
+ public:
+ //print the STP solver output
+ void PrintOutput(bool true_iff_valid);
+
+ //Converts MINISAT counterexample into an AST memotable (i.e. the
+ //function populates the datastructure CounterExampleMap)
+ void ConstructCounterExample(MINISAT::Solver& S);
+
+ //Prints the counterexample to stdout
+ void PrintCounterExample(bool t,std::ostream& os=cout);
+
+ //Prints the counterexample to stdout
+ void PrintCounterExample_InOrder(bool t);
+
+ //queries the counterexample, and returns the value corresponding
+ //to e
+ ASTNode GetCounterExample(bool t, const ASTNode& e);
+
+ int CounterExampleSize(void) const {return CounterExampleMap.size();}
+
+ //FIXME: This is bloody dangerous function. Hack attack to take
+ //care of requests from users who want to store complete
+ //counter-examples in their own data structures.
+ ASTNodeMap GetCompleteCounterExample() {return CounterExampleMap;}
+
+ // prints MINISAT assigment one bit at a time, for debugging.
+ void PrintSATModel(MINISAT::Solver& S);
+
+ //accepts constant input and normalizes it.
+ ASTNode BVConstEvaluator(const ASTNode& t);
+
+ //FUNCTION TypeChecker: Assumes that the immediate Children of the
+ //input ASTNode have been typechecked. This function is suitable
+ //in scenarios like where you are building the ASTNode Tree, and
+ //you typecheck as you go along. It is not suitable as a general
+ //typechecker
+ void BVTypeCheck(const ASTNode& n);
+
+ private:
+ //stack of Logical Context. each entry in the stack is a logical
+ //context. A logical context is a vector of assertions. The
+ //logical context is represented by a ptr to a vector of
+ //assertions in that logical context. Logical contexts are created
+ //by PUSH/POP
+ std::vector<ASTVec *> _asserts;
+ //The query for the current logical context.
+ ASTNode _current_query;
+
+ //this flag, when true, indicates that counterexample is being
+ //checked by the counterexample checker
+ bool counterexample_checking_during_refinement;
+
+ //this flag indicates as to whether the input has been determined to
+ //be valid or not by this tool
+ bool ValidFlag;
+
+ //this flag, when true, indicates that a BVDIV divide by zero
+ //exception occured. However, the program must not exit with a
+ //fatalerror. Instead, it should evaluate the whole formula (which
+ //contains the BVDIV term) to be FALSE.
+ bool bvdiv_exception_occured;
+
+ public:
+ //set of functions that manipulate Logical Contexts.
+ //
+ //add an assertion to the current logical context
+ void AddAssert(const ASTNode& assert);
+ void Push(void);
+ void Pop(void);
+ void AddQuery(const ASTNode& q);
+ const ASTNode PopQuery();
+ const ASTNode GetQuery();
+ const ASTVec GetAsserts(void);
+
+ //reports node size. Second arg is "clearstatinfo", whatever that is.
+ unsigned int NodeSize(const ASTNode& a, bool t = false);
+
+ private:
+ //This memo map is used by the ComputeFormulaUsingModel()
+ ASTNodeMap ComputeFormulaMap;
+ //Map for statiscal purposes
+ ASTNodeSet StatInfoSet;
+
+
+ ASTNodeMap TermsAlreadySeenMap;
+ ASTNode CreateSubstitutionMap(const ASTNode& a);
+ public:
+ //prints statistics for the ASTNode. can add a prefix string c
+ void ASTNodeStats(const char * c, const ASTNode& a);
+
+ //substitution
+ bool CheckSubstitutionMap(const ASTNode& a, ASTNode& output);
+ bool CheckSubstitutionMap(const ASTNode& a);
+ bool UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1);
+ //if (a > b) in the termorder, then return 1
+ //elseif (a < b) in the termorder, then return -1
+ //else return 0
+ int TermOrder(const ASTNode& a, const ASTNode& b);
+ //fill the arrayname_readindices vector if e0 is a READ(Arr,index)
+ //and index is a BVCONST
+ void FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1);
+ bool VarSeenInTerm(const ASTNode& var, const ASTNode& term);
+
+ //functions for checking and updating simplifcation map
+ bool CheckSimplifyMap(const ASTNode& key, ASTNode& output, bool pushNeg);
+ void UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg);
+ bool CheckAlwaysTrueFormMap(const ASTNode& key);
+ void UpdateAlwaysTrueFormMap(const ASTNode& val);
+ bool CheckMultInverseMap(const ASTNode& key, ASTNode& output);
+ void UpdateMultInverseMap(const ASTNode& key, const ASTNode& value);
+
+ //Map for solved variables
+ bool CheckSolverMap(const ASTNode& a, ASTNode& output);
+ bool CheckSolverMap(const ASTNode& a);
+ bool UpdateSolverMap(const ASTNode& e0, const ASTNode& e1);
+ public:
+ //FIXME: HACK_ATTACK. this vector was hacked into the code to
+ //support a special request by Dawson' group. They want the
+ //counterexample to be printed in the order of variables declared.
+ //TO BE COMMENTED LATER (say by 1st week of march,2006)
+ ASTVec _special_print_set;
+
+ //prints the initial activity levels of variables
+ void PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS);
+
+ //this function biases the activity levels of MINISAT variables.
+ void ChangeActivityLevels_Of_SATVars(MINISAT::Solver& n);
+
+ // Constructor
+ BeevMgr() : _interior_unique_table(INITIAL_INTERIOR_UNIQUE_TABLE_SIZE),
+ _symbol_unique_table(INITIAL_SYMBOL_UNIQUE_TABLE_SIZE),
+ _bvconst_unique_table(INITIAL_BVCONST_UNIQUE_TABLE_SIZE),
+ BBTermMemo(INITIAL_BBTERM_MEMO_TABLE_SIZE),
+ BBFormMemo(INITIAL_BBFORM_MEMO_TABLE_SIZE),
+ _max_node_num(0),
+ ASTFalse(CreateNode(FALSE)),
+ ASTTrue(CreateNode(TRUE)),
+ ASTUndefined(CreateNode(UNDEFINED)),
+ SimplifyMap(INITIAL_SIMPLIFY_MAP_SIZE),
+ SimplifyNegMap(INITIAL_SIMPLIFY_MAP_SIZE),
+ SolverMap(INITIAL_SOLVER_MAP_SIZE),
+ _arrayread_symbol(INITIAL_ARRAYREAD_SYMBOL_SIZE),
+ _introduced_symbols(INITIAL_INTRODUCED_SYMBOLS_SIZE),
+ _symbol_count(0) {
+ _current_query = ASTUndefined;
+ ValidFlag = false;
+ bvdiv_exception_occured = false;
+ counterexample_checking_during_refinement = false;
+ start_abstracting = false;
+ Begin_RemoveWrites = false;
+ SimplifyWrites_InPlace_Flag = false;
+ };
+
+ //destructor
+ ~BeevMgr();
+ }; //End of Class BeevMgr
+
+
+ class CompleteCounterExample {
+ ASTNodeMap counterexample;
+ BeevMgr * bv;
+ public:
+ CompleteCounterExample(ASTNodeMap a, BeevMgr* beev) : counterexample(a), bv(beev){}
+ ASTNode GetCounterExample(ASTNode e) {
+ if(BOOLEAN_TYPE == e.GetType() && SYMBOL != e.GetKind()) {
+ FatalError("You must input a term or propositional variables\n",e);
+ }
+ if(counterexample.find(e) != counterexample.end()) {
+ return counterexample[e];
+ }
+ else {
+ if(SYMBOL == e.GetKind() && BOOLEAN_TYPE == e.GetType()) {
+ return bv->CreateNode(BEEV::FALSE);
+ }
+
+ if(SYMBOL == e.GetKind()) {
+ ASTNode z = bv->CreateZeroConst(e.GetValueWidth());
+ return z;
+ }
+
+ return e;
+ }
+ }
+ };
+
+}; // end namespace BEEV
+#endif
Added: klee/trunk/stp/AST/ASTKind.kinds
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/ASTKind.kinds?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/ASTKind.kinds (added)
+++ klee/trunk/stp/AST/ASTKind.kinds Wed May 20 23:36:41 2009
@@ -0,0 +1,71 @@
+#Please refer LICENSE FILE in the home directory for licensing information
+# name minkids maxkids cat1 cat2 ...
+Categories: Term Form
+
+# Leaf nodes.
+UNDEFINED 0 0
+SYMBOL 0 0 Term Form
+
+# These always produce terms
+BVCONST 0 0 Term
+BVNEG 1 1 Term
+BVCONCAT 2 - Term
+BVOR 1 - Term
+BVAND 1 - Term
+BVXOR 1 - Term
+BVNAND 1 - Term
+BVNOR 1 - Term
+BVXNOR 1 - Term
+BVEXTRACT 3 3 Term
+BVLEFTSHIFT 3 3 Term
+BVRIGHTSHIFT 3 3 Term
+BVSRSHIFT 3 3 Term
+BVVARSHIFT 3 3 Term
+BVPLUS 1 - Term
+BVSUB 2 2 Term
+BVUMINUS 1 1 Term
+BVMULTINVERSE 1 1 Term
+BVMULT 1 - Term
+BVDIV 2 2 Term
+BVMOD 2 2 Term
+SBVDIV 2 2 Term
+SBVMOD 2 2 Term
+BVSX 1 1 Term
+BOOLVEC 0 - Term
+
+# Formula OR term, depending on context
+ITE 3 3 Term Form
+
+# These produce formulas.
+BVGETBIT 2 2 Form
+BVLT 2 2 Form
+BVLE 2 2 Form
+BVGT 2 2 Form
+BVGE 2 2 Form
+BVSLT 2 2 Form
+BVSLE 2 2 Form
+BVSGT 2 2 Form
+BVSGE 2 2 Form
+EQ 2 2 Form
+NEQ 2 2 Form
+FALSE 0 0 Form
+TRUE 0 0 Form
+NOT 1 1 Form
+AND 1 - Form
+OR 1 - Form
+NAND 1 - Form
+NOR 1 - Form
+XOR 1 - Form
+IFF 1 - Form
+IMPLIES 2 2 Form
+
+# array operations
+READ 2 2 Term
+WRITE 3 3 Term
+
+#Types: These kinds are used only in the API. Once processed inside
+#the API, they are never used again in the system
+ARRAY 0 0
+BITVECTOR 0 0
+BOOLEAN 0 0
+
Added: klee/trunk/stp/AST/ASTUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/ASTUtil.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/ASTUtil.cpp (added)
+++ klee/trunk/stp/AST/ASTUtil.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,45 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+#include "ASTUtil.h"
+#include <ostream>
+
+namespace BEEV {
+ ostream &operator<<(ostream &os, const Spacer &sp) {
+ // Instead of wrapping lines with hundreds of spaces, prints
+ // a "+" at the beginning of the line for each wrap-around.
+ // so lines print like: +14+ (XOR ...
+ int blanks = sp._spaces % 60;
+ int wraps = sp._spaces / 60;
+ if (wraps > 0) {
+ os << "+" << wraps;
+ }
+ for (int i = 0; i < blanks; i++)
+ os << " ";
+ return os;
+ }
+
+ //this function accepts the name of a function (as a char *), and
+ //records some stats about it. if the input is "print_func_stats",
+ //the function will then print the stats that it has collected.
+ void CountersAndStats(const char * functionname) {
+ if(!stats)
+ return;
+ static function_counters s;
+
+ if(!strcmp(functionname,"print_func_stats")) {
+ cout << endl;
+ for(hash_map<const char*,int,hash<const char*>,eqstr>::iterator it=s.begin(),itend=s.end();
+ it!=itend;it++)
+ cout << "Number of times the function: " << it->first << ": is called: " << it->second << endl;
+ return;
+ }
+ s[functionname] += 1;
+ }
+};// end of namespace
Added: klee/trunk/stp/AST/ASTUtil.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/ASTUtil.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/ASTUtil.h (added)
+++ klee/trunk/stp/AST/ASTUtil.h Wed May 20 23:36:41 2009
@@ -0,0 +1,107 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+#ifndef ASTUTIL_H
+#define ASTUTIL_H
+
+#include <cstring>
+#include <iostream>
+#include <vector>
+#ifdef EXT_HASH_MAP
+#include <ext/hash_set>
+#include <ext/hash_map>
+#else
+#include <hash_set>
+#include <hash_map>
+#endif
+
+using namespace std;
+namespace BEEV {
+#ifdef EXT_HASH_MAP
+ using namespace __gnu_cxx;
+#endif
+ //some global variables that are set through commandline options. it
+ //is best that these variables remain global. Default values set
+ //here
+ //
+ //collect statistics on certain functions
+ extern bool stats;
+ //print DAG nodes
+ extern bool print_nodes;
+ //tentative global var to allow for variable activity optimization
+ //in the SAT solver. deprecated.
+ extern bool variable_activity_optimize;
+ //run STP in optimized mode
+ extern bool optimize;
+ //do sat refinement, i.e. underconstraint the problem, and feed to
+ //SAT. if this works, great. else, add a set of suitable constraints
+ //to re-constraint the problem correctly, and call SAT again, until
+ //all constraints have been added.
+ extern bool arrayread_refinement;
+ //switch to control write refinements
+ extern bool arraywrite_refinement;
+ //check the counterexample against the original input to STP
+ extern bool check_counterexample;
+ //construct the counterexample in terms of original variable based
+ //on the counterexample returned by SAT solver
+ extern bool construct_counterexample;
+ extern bool print_counterexample;
+ //if this option is true then print the way dawson wants using a
+ //different printer. do not use this printer.
+ extern bool print_arrayval_declaredorder;
+ //flag to decide whether to print "valid/invalid" or not
+ extern bool print_output;
+ //do linear search in the array values of an input array. experimental
+ extern bool linear_search;
+ //print the variable order chosen by the sat solver while it is
+ //solving.
+ extern bool print_sat_varorder;
+ //turn on word level bitvector solver
+ extern bool wordlevel_solve;
+ //XOR flattening optimizations.
+ extern bool xor_flatten;
+ //this flag indicates that the BVSolver() succeeded
+ extern bool toplevel_solved;
+ //the smtlib parser has been turned on
+ extern bool smtlib_parser_enable;
+ //print the input back
+ extern bool print_STPinput_back;
+
+ extern void (*vc_error_hdlr)(const char* err_msg);
+ /*Spacer class is basically just an int, but the new class allows
+ overloading of << with a special definition that prints the int as
+ that many spaces. */
+ class Spacer {
+ public:
+ int _spaces;
+ Spacer(int spaces) { _spaces = spaces; }
+ friend ostream& operator<<(ostream& os, const Spacer &ind);
+ };
+
+ inline Spacer spaces(int width) {
+ Spacer sp(width);
+ return sp;
+ }
+
+ struct eqstr {
+ bool operator()(const char* s1, const char* s2) const {
+ return strcmp(s1, s2) == 0;
+ }
+ };
+
+ typedef hash_map<const char*,int,
+ hash<const char *>,eqstr> function_counters;
+ void CountersAndStats(const char * functionname);
+
+ //global function which accepts an integer and looks up the
+ //corresponding ASTNode and prints a char* of that ASTNode
+ void Convert_MINISATVar_To_ASTNode_Print(int minisat_var,
+ int decision, int polarity=0);
+}; // end namespace.
+#endif
Added: klee/trunk/stp/AST/BitBlast.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/BitBlast.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/BitBlast.cpp (added)
+++ klee/trunk/stp/AST/BitBlast.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,812 @@
+/********************************************************************
+ * AUTHORS: David L. Dill, Vijay Ganesh
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+// BitBlast -- convert bitvector terms and formulas to boolean
+// formulas. A term is something that can represent a multi-bit
+// bitvector, such as BVPLUS or BVXOR (or a BV variable or constant).
+// A formula (form) represents a boolean value, such as EQ or BVLE.
+// Bit blasting a term representing an n-bit bitvector with BBTerm
+// yields a vector of n boolean formulas (returning ASTVec).
+// Bit blasting a formula returns a single boolean formula (type ASTNode).
+
+// A bitblasted term is a vector of ASTNodes for formulas.
+// The 0th element of the vector corresponds to bit 0 -- the low-order bit.
+
+#include "AST.h"
+namespace BEEV {
+ // extern void lpvec(ASTVec &vec);
+
+// FIXME: Assert no zero-length bit vectors!!!
+// FIXME: Need top-level functions that create and destroy the memo tables.
+// FIXME: Check resource limits and generate an exception when exceeded.
+// FIXME: THis does a lot of unnecessary copying of vectors.
+// Had to be careful not to modify memoized vectors!
+// FIXME: Might be some redundant variables.
+
+// accepts a term, and returns a vector of bitblasted bits(ASTVec)
+
+ASTNode ASTJunk;
+const ASTNode BeevMgr::BBTerm(const ASTNode& term) {
+ //CHANGED TermMemo is now an ASTNodeMap. Based on BBFormMemo
+ ASTNodeMap::iterator it = BBTermMemo.find(term);
+ if (it != BBTermMemo.end()) {
+ // already there. Just return it.
+ return it->second;
+ }
+
+// ASTNode& result = ASTJunk;
+ ASTNode result;
+
+ Kind k = term.GetKind();
+ if (!is_Term_kind(k))
+ FatalError("BBTerm: Illegal kind to BBTerm",term);
+
+ ASTVec::const_iterator kids_end = term.end();
+ unsigned int num_bits = term.GetValueWidth();
+ switch (k) {
+ case BVNEG: {
+ // bitwise complement
+ // bitblast the child.
+ //FIXME Uses a tempory const ASTNode
+ const ASTNode& bbkids = BBTerm(term[0]);
+ result = CreateNode(BOOLVEC, BBNeg(bbkids.GetChildren()));
+ break;
+ }
+ case BVSRSHIFT:
+ case BVVARSHIFT:
+ FatalError("BBTerm: These kinds have not been implemented in the BitBlaster: ", term);
+ break;
+ case ITE: {
+ // Term version of ITE.
+
+ // Blast the args
+ // FIXME Uses temporary const ASTNodes and an ASTVec&
+ const ASTNode& cond = BBForm(term[0]);
+ const ASTNode& thn = BBTerm(term[1]);
+ const ASTNode& els = BBTerm(term[2]);
+ result =
+ CreateNode(BOOLVEC, BBITE(cond, thn.GetChildren(), els.GetChildren()));
+ break;
+ }
+ case BVSX: {
+ // Replicate high-order bit as many times as necessary.
+ // Arg 0 is expression to be sign extended.
+ const ASTNode& arg = term[0];
+ unsigned long result_width = term.GetValueWidth();
+ unsigned long arg_width = arg.GetValueWidth();
+ //FIXME Uses a temporary const ASTNode reference
+ const ASTNode& bbarg = BBTerm(arg);
+
+ if (result_width == arg_width) {
+ //nothing to sign extend
+ break;
+ }
+ else {
+ //we need to sign extend
+ const ASTNode& msbX = bbarg.back();
+ //const ASTNode& msb1 = msbX;
+
+ ASTVec ccc = msbX.GetChildren();
+ const ASTNode& msb = CreateSimpForm(msbX.GetKind(),ccc);
+
+ // Old version
+ // ASTNode msb = bbarg.back();
+ // const ASTNode msb1 = msb;
+
+ // ASTVec ccc = msb.GetChildren();
+ // msb = CreateSimpForm(msb.GetKind(),ccc);
+
+ // DD 1/14/07 Simplify silently drops all but first two args of XOR.
+ // I expanded XOR to N args with flattening optimization.
+ // This bug took 2 days to track down!
+
+ // msb = SimplifyFormula(msb,false);
+
+ // cout << "!!!!!!!!!!!!!!!!" << endl
+ // << "Simplify msb:" << msb2 << endl
+ // << "Simplify result:" << msb << endl;
+
+ //FIXME Dynamically allocate the result vector?
+ //Is this doing multiple copies?
+ //ASTVec& tmp_res = *(new ASTVec(result_width));
+ ASTVec tmp_res(result_width);
+
+ //FIXME Should these be gotten from result?
+ ASTVec::const_iterator bb_it = bbarg.begin();
+ ASTVec::iterator res_it = tmp_res.begin();
+ ASTVec::iterator res_ext = res_it+arg_width; // first bit of extended part
+ ASTVec::iterator res_end = tmp_res.end();
+ // copy LSBs directly from bbvec
+ for( ; res_it < res_ext; (res_it++, bb_it++)) {
+ *res_it = *bb_it;
+ }
+ // repeat MSB to fill up rest of result.
+ for( ; res_it < res_end; (res_it++, bb_it++)) {
+ *res_it = msb;
+ }
+
+ //Temporary debugging code
+ // cout << "Sign extending:" << endl
+ // << " Vec ";
+ // lpvec( bbarg.GetChildren() );
+ // cout << " Extended to ";
+ // lp(result);
+ // cout << endl;
+
+ result = CreateNode(BOOLVEC, tmp_res);
+
+ break;
+ }
+ }
+ case BVEXTRACT: {
+ // bitblast the child, then extract the relevant bits.
+ // Note: This could be optimized by not bitblasting the bits
+ // that aren't fetched. But that would be tricky, especially
+ // with memo-ization.
+
+ //FIXME Using const ASTNode w/out reference
+ const ASTNode& bbkids = BBTerm(term[0]);
+ unsigned int high = GetUnsignedConst(term[1]);
+ unsigned int low = GetUnsignedConst(term[2]);
+
+ ASTVec::const_iterator bbkfit = bbkids.begin();
+ // I should have used pointers to ASTVec, to avoid this crock
+
+ //FIXME Creates a new local ASTVec and does the CreateNode from that
+ result = CreateNode(BOOLVEC, ASTVec(bbkfit+low, bbkfit+high+1));
+ break;
+ }
+ case BVCONCAT: {
+ //FIXME Using temporary const ASTNodes
+ const ASTNode& vec1 = BBTerm(term[0]);
+ const ASTNode& vec2 = BBTerm(term[1]);
+
+ //FIXME This has to be an unnessecary copy and a memory leak
+ //Leaking ASTVec tmp_res = *(new ASTVec(vec2.GetChildren()));
+ ASTVec tmp_res(vec2.GetChildren());
+ tmp_res.insert(tmp_res.end(), vec1.begin(), vec1.end());
+ result = CreateNode(BOOLVEC, tmp_res);
+ break;
+ }
+ case BVPLUS: {
+ // ASSERT: at least one child.
+ // ASSERT: all children and result are the same size.
+ // Previous phase must make sure this is true.
+ // Add children pairwise and accumulate in BBsum
+
+ // FIXME: Unnecessary array copies.
+ ASTVec::const_iterator it = term.begin();
+ ASTVec tmp_res = BBTerm(*it).GetChildren();
+ for (++it; it < kids_end; it++) {
+ const ASTVec& tmp = BBTerm(*it).GetChildren();
+ BBPlus2(tmp_res, tmp, ASTFalse);
+ }
+
+ result = CreateNode(BOOLVEC, tmp_res);
+ break;
+ }
+ case BVUMINUS: {
+ //FIXME Using const ASTNode reference
+ const ASTNode& bbkid = BBTerm(term[0]);
+ result = CreateNode(BOOLVEC, BBUminus(bbkid.GetChildren()));
+ break;
+ }
+ case BVSUB: {
+ // complement of subtrahend
+ // copy, since BBSub writes into it.
+
+ //FIXME: Unnecessary array copies?
+ ASTVec tmp_res = BBTerm(term[0]).GetChildren();
+
+ const ASTVec& bbkid1 = BBTerm(term[1]).GetChildren();
+ BBSub(tmp_res, bbkid1);
+ result = CreateNode(BOOLVEC, tmp_res);
+ break;
+ }
+ case BVMULT: {
+ // ASSERT 2 arguments, same length, result is same length.
+
+ const ASTNode& t0 = term[0];
+ const ASTNode& t1 = term[1];
+
+ const ASTNode& mpcd1 = BBTerm(t0);
+ const ASTNode& mpcd2 = BBTerm(t1);
+ //Reverese the order of the nodes w/out the need for temporaries
+ //This is needed because t0 an t1 must be const
+ if ((BVCONST != t0.GetKind()) && (BVCONST == t1.GetKind())) {
+ result = CreateNode(BOOLVEC,
+ BBMult(mpcd2.GetChildren(), mpcd1.GetChildren()) );
+ }else{
+ result = CreateNode(BOOLVEC,
+ BBMult(mpcd1.GetChildren(), mpcd2.GetChildren()) );
+ }
+ break;
+ }
+ case BVDIV:
+ case BVMOD: {
+ const ASTNode& dvdd = BBTerm(term[0]);
+ const ASTNode& dvsr = BBTerm(term[1]);
+ unsigned int width = dvdd.Degree();
+ ASTVec q(width);
+ ASTVec r(width);
+ BBDivMod(dvdd.GetChildren(), dvsr.GetChildren(), q, r, width);
+ if (k == BVDIV)
+ result = CreateNode(BOOLVEC, q);
+ else
+ result = CreateNode(BOOLVEC, r);
+ break;
+ }
+ // n-ary bitwise operators.
+ case BVXOR:
+ case BVXNOR:
+ case BVAND:
+ case BVOR:
+ case BVNOR:
+ case BVNAND: {
+ // Add children pairwise and accumulate in BBsum
+ ASTVec::const_iterator it = term.begin();
+ Kind bk = UNDEFINED; // Kind of individual bit op.
+ switch (k) {
+ case BVXOR: bk = XOR; break;
+ case BVXNOR: bk = IFF; break;
+ case BVAND: bk = AND; break;
+ case BVOR: bk = OR; break;
+ case BVNOR: bk = NOR; break;
+ case BVNAND: bk = NAND; break;
+ default:
+ FatalError("BBTerm: Illegal kind to BBTerm",term);
+ break;
+ }
+
+ // Sum is destructively modified in the loop, so make a copy of value
+ // returned by BBTerm.
+ ASTNode temp = BBTerm(*it);
+ ASTVec sum(temp.GetChildren()); // First operand.
+
+ // Iterate over remaining bitvector term operands
+ for (++it; it < kids_end; it++) {
+ //FIXME FIXME FIXME: Why does using a temp. var change the behavior?
+ temp = BBTerm(*it);
+ const ASTVec& y = temp.GetChildren();
+
+ // Iterate over bits
+ // FIXME: Why is this not using an iterator???
+ int n = y.size();
+ for (int i = 0; i < n; i++) {
+ sum[i] = CreateSimpForm(bk, sum[i], y[i]);
+ }
+ }
+ result = CreateNode(BOOLVEC, sum);
+ break;
+ }
+ case SYMBOL: {
+ // ASSERT: IndexWidth = 0? Semantic analysis should check.
+ //Leaking ASTVec& bbvec = *(new ASTVec);
+
+ //FIXME Why is isn't this ASTVEC bbvec(num_bits) ?
+ ASTVec bbvec;
+ for (unsigned int i = 0; i < num_bits; i++) {
+ ASTNode bit_node =
+ CreateNode(BVGETBIT, term, CreateBVConst(32,i));
+ bbvec.push_back(bit_node);
+ }
+ result = CreateNode(BOOLVEC, bbvec);
+ break;
+ }
+ case BVCONST: {
+ ASTVec tmp_res(num_bits);
+#ifndef NATIVE_C_ARITH
+ CBV bv = term.GetBVConst();
+ for(unsigned int i = 0; i < num_bits; i++){
+ tmp_res[i] = CONSTANTBV::BitVector_bit_test(bv,i) ? ASTTrue : ASTFalse;
+ }
+#else
+ const unsigned long long int c = term.GetBVConst();
+ unsigned long long int bitmask = 0x00000000000000001LL;
+ for (unsigned int i = 0; i < num_bits; i++, bitmask <<= 1)
+ tmp_res[i] = ((c & (bitmask)) ? ASTTrue : ASTFalse);
+#endif
+ result = CreateNode(BOOLVEC, tmp_res);
+ break;
+ }
+ case BOOLVEC: {
+ cerr << "Hit a boolvec! what to do?" << endl;
+ break;
+ }
+ default:
+ FatalError("BBTerm: Illegal kind to BBTerm",term);
+ }
+
+ //if(result == ASTJunk)
+ // cout<<"result does not change"<<endl;
+ // cout << "================" << endl << "BBTerm:" << term << endl;
+ // cout << "----------------" << endl << "BBTerm result:";
+ // lpvec(result);
+ // cout << endl;
+
+ return (BBTermMemo[term] = result);
+
+}
+
+// bit blast a formula (boolean term). Result is one bit wide,
+// so it returns a single ASTNode.
+// FIXME: Add IsNegated flag.
+const ASTNode BeevMgr::BBForm(const ASTNode& form)
+{
+
+ ASTNodeMap::iterator it = BBFormMemo.find(form);
+ if (it != BBFormMemo.end()) {
+ // already there. Just return it.
+ return it->second;
+ }
+
+ ASTNode result = ASTUndefined;
+
+ Kind k = form.GetKind();
+ if (!is_Form_kind(k)) {
+ FatalError("BBForm: Illegal kind: ",form);
+ }
+
+ // Not returning until end, and memoizing everything, makes it easier
+ // to trace coherently.
+
+ // Various special cases
+ switch (k) {
+ case TRUE:
+ case FALSE: {
+ result = form;
+ break;
+ }
+
+ case SYMBOL:
+ if (form.GetType() != BOOLEAN_TYPE) {
+ FatalError("BBForm: Symbol represents more than one bit", form);
+ }
+
+ result = form;
+ break;
+
+ case BVGETBIT: {
+ // exactly two children
+ const ASTNode bbchild = BBTerm(form[0]);
+ unsigned int index = GetUnsignedConst(form[1]);
+ result = bbchild[index];
+ break;
+ }
+
+ case NOT:
+ result = CreateSimpNot(BBForm(form[0]));
+ break;
+
+ case ITE:
+ // FIXME: SHould this be CreateSimpITE?
+ result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2]));
+ break;
+
+ case AND:
+ case OR:
+ case NAND:
+ case NOR:
+ case IFF:
+ case XOR:
+ case IMPLIES: {
+ ASTVec bbkids; // bit-blasted children (formulas)
+
+ // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES
+ ASTVec::const_iterator kids_end = form.end();
+ for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) {
+ bbkids.push_back(BBForm(*it));
+ }
+ result = CreateSimpForm(k, bbkids);
+ break;
+ }
+
+ case NEQ: {
+ ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren()));
+ result = CreateSimpNot(bbkid);
+ break;
+ }
+
+ case EQ: {
+ // Common code for binary operations
+ // FIXME: This ought to be in a semantic analysis phase.
+ const ASTNode left = BBTerm(form[0]);
+ const ASTNode right = BBTerm(form[1]);
+ if (left.Degree() != right.Degree()) {
+ cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl;
+ FatalError("",ASTUndefined);
+ }
+ result = BBEQ(left.GetChildren(), right.GetChildren());
+ break;
+ }
+
+ case BVLE:
+ case BVGE:
+ case BVGT:
+ case BVLT:
+ case BVSLE:
+ case BVSGE:
+ case BVSGT:
+ case BVSLT: {
+ result = BBcompare(form);
+ break;
+ }
+ default:
+ FatalError("BBForm: Illegal kind: ", form);
+ break;
+ }
+
+ // cout << "================" << endl
+ // << "BBForm: " << form << endl
+ // << "----------------" << endl
+ // << "BBForm Result: " << result << endl;
+
+ return (BBFormMemo[form] = result);
+}
+
+// Bit blast a sum of two equal length BVs.
+// Update sum vector destructively with new sum.
+void BeevMgr::BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin)
+{
+// cout << "Bitblasting plus. Operand 1: " << endl;
+// lpvec(sum);
+// cout << endl << " operand 2: " << endl;
+// lpvec(y);
+// cout << endl << "carry: " << endl << cin << endl;
+
+
+ int n = sum.size();
+ // ASSERT: y.size() == x.size()
+ // FIXME: Don't bother computing i+1 carry, which is discarded.
+ for (int i = 0; i < n; i++) {
+ ASTNode nextcin = Majority(sum[i], y[i], cin);
+ sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin);
+ cin = nextcin;
+ }
+
+// cout << "----------------" << endl << "Result: " << endl;
+// lpvec(sum);
+// cout << endl;
+
+}
+
+// Stores result - x in result, destructively
+void BeevMgr::BBSub(ASTVec& result, const ASTVec& y)
+{
+ ASTVec compsubtrahend = BBNeg(y);
+ BBPlus2(result, compsubtrahend, ASTTrue);
+}
+
+// Add one bit
+ASTVec BeevMgr::BBAddOneBit(ASTVec& x, ASTNode cin)
+{
+ ASTVec result = ASTVec(0);
+ ASTVec::const_iterator itend = x.end();
+ for (ASTVec::const_iterator it = x.begin(); it < itend; it++) {
+ ASTNode nextcin = CreateSimpForm(AND, *it, cin);
+ result.push_back(CreateSimpForm(XOR, *it, cin));
+ cin = nextcin;
+ }
+ // FIXME: unnecessary array copy on return?
+ return result;
+}
+
+// Increment bit-blasted vector and return result.
+ASTVec BeevMgr::BBInc(ASTVec& x)
+{
+ return BBAddOneBit(x, ASTTrue);
+}
+
+// Return formula for majority function of three bits.
+// Pass arguments by reference to reduce refcounting.
+ASTNode BeevMgr::Majority(const ASTNode& a, const ASTNode& b,const ASTNode& c)
+{
+ // Checking explicitly for constant a, b and c could
+ // be more efficient, because they are repeated in the logic.
+ if (ASTTrue == a) {
+ return CreateSimpForm(OR, b, c);
+ }
+ else if (ASTFalse == a) {
+ return CreateSimpForm(AND, b, c);
+ }
+ else if (ASTTrue == b) {
+ return CreateSimpForm(OR, a, c);
+ }
+ else if (ASTFalse == b) {
+ return CreateSimpForm(AND, a, c);
+ }
+ else if (ASTTrue == c) {
+ return CreateSimpForm(OR, a, b);
+ }
+ else if (ASTFalse == c) {
+ return CreateSimpForm(AND, a, b);
+ }
+ // there are lots more simplifications, but I'm not sure they're
+ // worth doing explicitly (e.g., a = b, a = ~b, etc.)
+ else {
+ return
+ CreateSimpForm(OR,
+ CreateSimpForm(AND, a, b),
+ CreateSimpForm(AND, b, c),
+ CreateSimpForm(AND, a, c));
+ }
+}
+
+
+// Bitwise complement
+ASTVec BeevMgr::BBNeg(const ASTVec& x)
+{
+ ASTVec result = ASTVec(0); // FIXME: faster to preallocate n entries?
+ // Negate each bit.
+ ASTVec::const_iterator xend = x.end();
+ for (ASTVec::const_iterator it = x.begin(); it < xend; it++) {
+ result.push_back(CreateSimpNot(*it));
+ }
+ // FIXME: unecessary array copy when it returns?
+ return result;
+}
+
+// Compute unary minus
+ASTVec BeevMgr::BBUminus(const ASTVec& x)
+{
+ ASTVec xneg = BBNeg(x);
+ return BBInc(xneg);
+}
+
+// Multiply two bitblasted numbers
+ASTVec BeevMgr::BBMult(const ASTVec& x, const ASTVec& y)
+{
+ ASTVec ycopy(y);
+ ASTVec::const_iterator xend = x.end();
+ ASTVec::const_iterator xit = x.begin();
+ // start prod with first partial product.
+ // FIXME: This is unnecessary. Clean it up.
+ ASTVec prod = ASTVec(BBAndBit(y, *xit));
+ // start loop at next bit.
+ for(xit++; xit < xend; xit++) {
+ // shift first
+ BBLShift(ycopy);
+
+ if (ASTFalse == *xit) {
+ // If this bit is zero, the partial product will
+ // be zero. No reason to add that in.
+ continue;
+ }
+
+ ASTVec pprod = BBAndBit(ycopy, *xit);
+ // accumulate in the product.
+ BBPlus2(prod, pprod, ASTFalse);
+ }
+ return prod;
+}
+
+// This implements a variant of binary long division.
+// q and r are "out" parameters. rwidth puts a bound on the
+// recursion depth.
+void BeevMgr::BBDivMod(const ASTVec &y, const ASTVec &x, ASTVec &q, ASTVec &r, unsigned int rwidth)
+{
+ unsigned int width = y.size();
+ if (rwidth == 0) {
+ // When we have shifted the entire width, y is guaranteed to be 0.
+ q = BBfill(width, ASTFalse);
+ r = BBfill(width, ASTFalse);
+ }
+ else {
+ ASTVec q1, r1;
+ ASTVec yrshift1(y);
+ BBRShift(yrshift1);
+
+ // recursively divide y/2 by x.
+ BBDivMod(yrshift1, x, q1, r1, rwidth-1);
+
+ ASTVec q1lshift1(q1);
+ BBLShift(q1lshift1);
+
+ ASTVec r1lshift1(r1);
+ BBLShift(r1lshift1);
+
+ ASTVec r1lshift1plusyodd = BBAddOneBit(r1lshift1, y[0]);
+ ASTVec rminusx(r1lshift1plusyodd);
+ BBSub(rminusx, x);
+
+ // Adjusted q, r values when when r is too large.
+ ASTNode rtoolarge = BBBVLE(x, r1lshift1plusyodd, false);
+ ASTVec ygtrxqval = BBITE(rtoolarge, BBInc(q1lshift1), q1lshift1);
+ ASTVec ygtrxrval = BBITE(rtoolarge, rminusx, r1lshift1plusyodd);
+
+ // q & r values when y >= x
+ ASTNode yeqx = BBEQ(y, x);
+ // *** Problem: the bbfill for qval is wrong. Should be 1, not -1.
+ ASTVec one = BBfill(width, ASTFalse);
+ one[0] = ASTTrue;
+ ASTVec notylessxqval = BBITE(yeqx, one, ygtrxqval);
+ ASTVec notylessxrval = BBITE(yeqx, BBfill(width, ASTFalse), ygtrxrval);
+ // y < x <=> not x >= y.
+ ASTNode ylessx = CreateSimpNot(BBBVLE(x, y, false));
+ // final values of q and r
+ q = BBITE(ylessx, BBfill(width, ASTFalse), notylessxqval);
+ r = BBITE(ylessx, y, notylessxrval);
+ }
+}
+
+// build ITE's (ITE cond then[i] else[i]) for each i.
+ASTVec BeevMgr::BBITE(const ASTNode& cond, const ASTVec& thn, const ASTVec& els)
+{
+ // Fast exits.
+ if (ASTTrue == cond) {
+ return thn;
+ }
+ else if (ASTFalse == cond) {
+ return els;
+ }
+
+ ASTVec result(0);
+ ASTVec::const_iterator th_it_end = thn.end();
+ ASTVec::const_iterator el_it = els.begin();
+ for (ASTVec::const_iterator th_it = thn.begin(); th_it < th_it_end; th_it++, el_it++) {
+ result.push_back(CreateSimpForm(ITE, cond, *th_it, *el_it));
+ }
+ return result;
+}
+// AND each bit of vector y with single bit b and return the result.
+ASTVec BeevMgr::BBAndBit(const ASTVec& y, ASTNode b)
+{
+ ASTVec result(0);
+
+ if (ASTTrue == b) {
+ return y;
+ }
+ // FIXME: put in fast exits when b is constant 0.
+
+ ASTVec::const_iterator yend = y.end();
+ for(ASTVec::const_iterator yit = y.begin(); yit < yend; yit++) {
+ result.push_back(CreateSimpForm(AND, *yit, b));
+ }
+ return result;
+}
+
+
+// Workhorse for comparison routines. This does a signed BVLE if is_signed
+// is true, else it's unsigned. All other comparison operators can be reduced
+// to this by swapping args or complementing the result bit.
+// FIXME: If this were done MSB first, it would enable a fast exit sometimes
+// when the MSB is constant, deciding the result without looking at the rest
+// of the bits.
+ASTNode BeevMgr::BBBVLE(const ASTVec& left, const ASTVec& right, bool is_signed)
+{
+ // "thisbit" represents BVLE of the suffixes of the BVs
+ // from that position . if R < L, return TRUE, else if L < R
+ // return FALSE, else return BVLE of lower-order bits. MSB is
+ // treated separately, because signed comparison is done by
+ // complementing the MSB of each BV, then doing an unsigned
+ // comparison.
+ ASTVec::const_iterator lit = left.begin();
+ ASTVec::const_iterator litend = left.end();
+ ASTVec::const_iterator rit = right.begin();
+ ASTNode prevbit = ASTTrue;
+ for ( ; lit < litend-1; lit++, rit++) {
+ ASTNode neglit = CreateSimpNot(*lit);
+ ASTNode thisbit =
+ CreateSimpForm(OR,
+ CreateSimpForm(AND,neglit,*rit), // TRUE if l < r
+ CreateSimpForm(AND,
+ CreateSimpForm(OR, neglit, *rit), // false if not equal
+ prevbit)); // else prevbit
+ prevbit = thisbit;
+ }
+
+ // Handle MSB -- negate MSBs if signed comparison
+ // FIXME: make into refs after it's debugged.
+ ASTNode lmsb = *lit;
+ ASTNode rmsb = *rit;
+ if (is_signed) {
+ lmsb = CreateSimpNot(*lit);
+ rmsb = CreateSimpNot(*rit);
+ }
+
+ ASTNode neglmsb = CreateSimpNot(lmsb);
+ ASTNode msb =
+ CreateSimpForm(OR,
+ CreateSimpForm(AND,neglmsb, rmsb), // TRUE if l < r
+ CreateSimpForm(AND,
+ CreateSimpForm(OR, neglmsb, rmsb), // false if not equal
+ prevbit)); // else prevbit
+ return msb;
+}
+
+// Left shift by 1 within fixed field inserting zeros at LSB.
+// Writes result into first argument.
+// Fixme: generalize to n bits
+void BeevMgr::BBLShift(ASTVec& x)
+{
+ // left shift x (destructively) within width.
+ // loop backwards so that copy to self works correctly. (DON'T use STL insert!)
+ ASTVec::iterator xbeg = x.begin();
+ for(ASTVec::iterator xit = x.end()-1; xit > xbeg; xit--) {
+ *xit = *(xit-1);
+ }
+ *xbeg = ASTFalse; // new LSB is zero.
+ // cout << "Shifted result" << endl;
+ // lpvec(x);
+}
+
+// Right shift by 1 within fixed field, inserting new zeros at MSB.
+// Writes result into first argument.
+// Fixme: generalize to n bits.
+void BeevMgr::BBRShift(ASTVec& x)
+{
+ ASTVec::iterator xend = x.end() - 1;
+ ASTVec::iterator xit = x.begin();
+ for( ; xit < xend; xit++) {
+ *xit = *(xit+1);
+ }
+ *xit = ASTFalse; // new MSB is zero.
+}
+
+
+// Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc.
+ASTNode BeevMgr::BBcompare(const ASTNode& form) {
+ const ASTNode lnode = BBTerm(form[0]);
+ const ASTNode rnode = BBTerm(form[1]);
+ const ASTVec& left = lnode.GetChildren();
+ const ASTVec& right = rnode.GetChildren();
+
+ //const ASTVec& left = BBTerm(form[0]).GetChildren();
+ //const ASTVec& right = BBTerm(form[1]).GetChildren();
+
+ Kind k = form.GetKind();
+ switch(k) {
+ case BVLE: { return BBBVLE(left, right, false); break; }
+ case BVGE: { return BBBVLE(right, left, false); break; }
+ case BVGT: { return CreateSimpNot(BBBVLE(left, right, false)); break; }
+ case BVLT: { return CreateSimpNot(BBBVLE(right, left, false)); break; }
+ case BVSLE: { return BBBVLE(left, right, true); break; }
+ case BVSGE: { return BBBVLE(right, left, true); break; }
+ case BVSGT: { return CreateSimpNot(BBBVLE(left, right, true)); break; }
+ case BVSLT: { return CreateSimpNot(BBBVLE(right, left, true)); break; }
+ default:
+ cerr << "BBCompare: Illegal kind" << form << endl;
+ FatalError("",ASTUndefined);
+ }
+ return ASTUndefined;
+}
+
+
+// return a vector with n copies of fillval
+ASTVec BeevMgr::BBfill(unsigned int width, ASTNode fillval)
+{
+ ASTVec zvec(width, fillval);
+ return zvec;
+}
+
+ASTNode BeevMgr::BBEQ(const ASTVec& left, const ASTVec& right)
+{
+ ASTVec andvec;
+ ASTVec::const_iterator lit = left.begin();
+ ASTVec::const_iterator litend = left.end();
+ ASTVec::const_iterator rit = right.begin();
+
+ if(left.size() > 1) {
+ for(; lit != litend; lit++, rit++) {
+ ASTNode biteq = CreateSimpForm(IFF, *lit, *rit);
+ // fast path exit
+ if (biteq == ASTFalse) {
+ return ASTFalse;
+ }
+ else {
+ andvec.push_back(biteq);
+ }
+ }
+ ASTNode n = CreateSimpForm(AND, andvec);
+ return n;
+ }
+ else
+ return CreateSimpForm(IFF,*lit,*rit);
+}
+} // BEEV namespace
Added: klee/trunk/stp/AST/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/Makefile (added)
+++ klee/trunk/stp/AST/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,54 @@
+include ../Makefile.common
+
+SRCS = AST.cpp ASTKind.cpp ASTUtil.cpp BitBlast.cpp SimpBool.cpp ToCNF.cpp ToSAT.cpp Transform.cpp
+OBJS = $(SRCS:.cpp=.o)
+
+#Make the ast library for use by other modules
+libast.a: $(OBJS)
+ -rm -rf $@
+ $(AR) rc libast.a $(OBJS)
+ $(RANLIB) libast.a
+
+ASTKind.o: ASTKind.h ASTKind.cpp
+ $(CXX) $(CXXFLAGS) -c -o ASTKind.o ASTKind.cpp
+
+# ASTKind.h and ASTKind.cpp are automatically generated
+ASTKind.h ASTKind.cpp: ASTKind.kinds genkinds.pl
+ ./genkinds.pl
+
+# cnftest: cnftest.o ToCNF.o AST.o ASTUtil.o ASTKind.o BitBlast.o AST.h
+# $(CC) $(LDFLAGS) ToCNF.o BitBlast.o ASTKind.o ASTUtil.o AST.o cnftest.o -o cnftest
+
+# bbtest: $(OBJS)
+# $(CC) $(LDFLAGS) BitBlast.o ASTKind.o ASTUtil.o AST.o bbtest.o -o bbtest
+
+# asttest: $(OBJS)
+# $(CC) $(LDFLAGS) ASTKind.o ASTUtil.o AST.o asttest.o -lstdc++ -o asttest
+
+clean:
+ rm -rf *.o *~ bbtest asttest cnftest *.a ASTKind.h ASTKind.cpp .#*
+
+depend:
+ makedepend -Y -- $(CFLAGS) -- $(SRCS)
+# DO NOT DELETE
+
+AST.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+AST.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+AST.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
+ASTUtil.o: ASTUtil.h
+BitBlast.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+BitBlast.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+BitBlast.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
+SimpBool.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+SimpBool.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+SimpBool.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
+ToCNF.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+ToCNF.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+ToCNF.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
+ToSAT.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+ToSAT.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+ToSAT.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
+ToSAT.o: ../simplifier/bvsolver.h ../AST/AST.h
+Transform.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h
+Transform.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h
+Transform.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h
Added: klee/trunk/stp/AST/STLport_config.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/STLport_config.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/STLport_config.h (added)
+++ klee/trunk/stp/AST/STLport_config.h Wed May 20 23:36:41 2009
@@ -0,0 +1,20 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+// STLport debug checking, if we use STLport threads flag is to get
+// rid of link errors, since iostreams compiles with threads. alloc
+// and uninitialized are extra checks Later on, if used with Purify or
+// Valgrind, may want to set flags to prevent reporting of false
+// leaks. For some reason, _STLP_THREADS works on the command line
+// but not here (?)
+#define _STLP_THREADS
+#define _STLP_DEBUG 1
+#define _STLP_DEBUG_LEVEL _STLP_STANDARD_DBG_LEVEL
+#define _STLP_DEBUG_ALLOC 1
+#define _STLP_DEBUG_UNINITIALIZED 1
Added: klee/trunk/stp/AST/SimpBool.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/SimpBool.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/SimpBool.cpp (added)
+++ klee/trunk/stp/AST/SimpBool.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,408 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: April, 2006
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+
+// -*- c++ -*-
+
+// Simplifying create methods for Boolean operations.
+// These are only very simple local simplifications.
+
+// This is somewhat redundant with Vijay's simplifier code. They
+// need to be merged.
+// FIXME: control with optimize flag.
+
+static bool _trace_simpbool = 0;
+static bool _disable_simpbool = 0;
+
+#include "AST.h"
+
+// SMTLIB experimental hack. Try allocating a single stack here for
+// children to reduce growing of vectors.
+//BEEV::ASTVec child_stack;
+
+namespace BEEV {
+
+ ASTNode BeevMgr::CreateSimpForm(Kind kind, ASTVec &children = _empty_ASTVec) {
+ if (_disable_simpbool) {
+ return CreateNode(kind, children);
+ }
+ else {
+ switch (kind) {
+ case NOT: return CreateSimpNot(children[0]); break;
+ case AND: return CreateSimpAndOr(1, children); break;
+ case OR: return CreateSimpAndOr(0, children); break;
+ case NAND: return CreateSimpNot(CreateSimpAndOr(1, children)); break;
+ case NOR: return CreateSimpNot(CreateSimpAndOr(0, children)); break;
+ case IFF: {
+ // Not sure children can ever be empty, but what the heck.
+ // if (children.size() == 0) {
+ // return ASTTrue;
+ // }
+ // Convert IFF to XOR ASAP. IFF is not associative, so this makes
+ // flattening much easier.
+ children[0] = CreateSimpNot(children[0]);
+ return CreateSimpXor(children); break;
+ }
+ case XOR:
+ return CreateSimpXor(children); break;
+ // FIXME: Earlier, check that this only has two arguments
+ case IMPLIES: return CreateSimpAndOr(0, CreateSimpNot(children[0]), children[1]); break;
+ case ITE: return CreateSimpFormITE(children[0], children[1], children[2]);
+ default: return CreateNode(kind, children);
+ }
+ }
+ }
+
+ // specialized versions
+
+ ASTNode BeevMgr::CreateSimpForm(Kind kind,
+ const ASTNode& child0) {
+ ASTVec children;
+ //child_stack.clear(); // could just reset top pointer.
+ children.push_back(child0);
+ //child_stack.push_back(child0);
+ return CreateSimpForm(kind, children);
+ //return CreateSimpForm(kind, child_stack);
+ }
+
+ ASTNode BeevMgr::CreateSimpForm(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1) {
+ ASTVec children;
+ //child_stack.clear(); // could just reset top pointer.
+ children.push_back(child0);
+ //child_stack.push_back(child0);
+ children.push_back(child1);
+ //child_stack.push_back(child1);
+ return CreateSimpForm(kind, children);
+ //return CreateSimpForm(kind, child_stack);
+ }
+
+
+ ASTNode BeevMgr::CreateSimpForm(Kind kind,
+ const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2) {
+ ASTVec children;
+ //child_stack.clear(); // could just reset top pointer.
+ children.push_back(child0);
+ //child_stack.push_back(child0);
+ children.push_back(child1);
+ //child_stack.push_back(child1);
+ children.push_back(child2);
+ //child_stack.push_back(child2);
+ return CreateSimpForm(kind, children);
+ //return CreateSimpForm(kind, child_stack);
+ }
+
+ ASTNode BeevMgr::CreateSimpNot(const ASTNode& form) {
+ Kind k = form.GetKind();
+ switch (k) {
+ case FALSE: { return ASTTrue; }
+ case TRUE: { return ASTFalse; }
+ case NOT: { return form[0]; } // NOT NOT cancellation
+ case XOR: {
+ // Push negation down in this case.
+ // FIXME: Separate pre-pass to push negation down?
+ // CreateSimp should be local, and this isn't.
+ // It isn't memoized. Arg.
+ ASTVec children = form.GetChildren();
+ children[0] = CreateSimpNot(children[0]);
+ return CreateSimpXor(children);
+ }
+ default: { return CreateNode(NOT, form); }
+ }
+ }
+
+ // I don't think this is even called, since it called
+ // CreateSimpAndOr instead of CreateSimpXor until 1/9/07 with no
+ // ill effects. Calls seem to go to the version that takes a vector
+ // of children.
+ ASTNode BeevMgr::CreateSimpXor(const ASTNode& form1, const ASTNode& form2) {
+ ASTVec children;
+ children.push_back(form1);
+ children.push_back(form2);
+ return CreateSimpXor(children);
+ }
+
+
+ ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, const ASTNode& form1, const ASTNode& form2) {
+ ASTVec children;
+ children.push_back(form1);
+ children.push_back(form2);
+ return CreateSimpAndOr(IsAnd, children);
+ }
+
+ ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, ASTVec &children) {
+
+ if (_trace_simpbool) {
+ cout << "========" << endl << "CreateSimpAndOr " << (IsAnd ? "AND " : "OR ") ;
+ lpvec(children);
+ cout << endl;
+ }
+
+ ASTVec new_children;
+
+ // sort so that identical nodes occur in sequential runs, followed by
+ // their negations.
+
+ SortByExprNum(children);
+
+ ASTNode annihilator = (IsAnd ? ASTFalse : ASTTrue);
+ ASTNode identity = (IsAnd ? ASTTrue : ASTFalse);
+
+ ASTNode retval;
+
+ ASTVec::const_iterator it_end = children.end();
+ ASTVec::const_iterator next_it;
+ for(ASTVec::const_iterator it = children.begin(); it != it_end; it = next_it) {
+ next_it = it + 1;
+ bool nextexists = (next_it < it_end);
+
+ if (*it == annihilator) {
+ retval = annihilator;
+ if (_trace_simpbool) {
+ cout << "returns " << retval << endl;
+ }
+ return retval;
+ }
+ else if (*it == identity) {
+ // just drop it
+ }
+ else if (nextexists && (*next_it == *it)) {
+ // drop it
+ // cout << "Dropping [" << it->GetNodeNum() << "]" << endl;
+ }
+ else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) {
+ // form and negation -- return FALSE for AND, TRUE for OR.
+ retval = annihilator;
+ // cout << "X and/or NOT X" << endl;
+ if (_trace_simpbool) {
+ cout << "returns " << retval << endl;
+ }
+ return retval;
+ }
+ else {
+ // add to children
+ new_children.push_back(*it);
+ }
+ }
+
+ // If we get here, we saw no annihilators, and children should
+ // be only the non-True nodes.
+ if (new_children.size() < 2) {
+ if (0 == new_children.size()) {
+ retval = identity;
+ }
+ else {
+ // there is just one child
+ retval = new_children[0];
+ }
+ }
+ else {
+ // 2 or more children. Create a new node.
+ retval = CreateNode(IsAnd ? AND : OR, new_children);
+ }
+ if (_trace_simpbool) {
+ cout << "returns " << retval << endl;
+ }
+ return retval;
+ }
+
+
+ // Constant children are accumulated in "accumconst".
+ ASTNode BeevMgr::CreateSimpXor(ASTVec &children) {
+
+ if (_trace_simpbool) {
+ cout << "========" << endl
+ << "CreateSimpXor ";
+ lpvec(children);
+ cout << endl;
+ }
+
+ // Change this not to init to children if flattening code is present.
+ // ASTVec flat_children = children; // empty vector
+
+ ASTVec flat_children; // empty vector
+
+ ASTVec::const_iterator it_end = children.end();
+
+ if (xor_flatten) {
+
+ bool fflag = 0; // ***Temp debugging
+
+ // Experimental flattening code.
+
+ for(ASTVec::iterator it = children.begin(); it != it_end; it++) {
+ Kind ck = it->GetKind();
+ const ASTVec &gchildren = it->GetChildren();
+ if (XOR == ck) {
+ fflag = 1;
+ // append grandchildren to children
+ flat_children.insert(flat_children.end(), gchildren.begin(), gchildren.end());
+ }
+ else {
+ flat_children.push_back(*it);
+ }
+ }
+
+ if (_trace_simpbool && fflag) {
+ cout << "========" << endl;
+ cout << "Flattening: " << endl;
+ lpvec(children);
+
+ cout << "--------" << endl;
+ cout << "Flattening result: " << endl;
+ lpvec(flat_children);
+ }
+ }
+ else {
+ flat_children = children;
+ }
+
+
+ // sort so that identical nodes occur in sequential runs, followed by
+ // their negations.
+ SortByExprNum(flat_children);
+
+ ASTNode retval;
+
+ // This is the C Boolean value of all constant args seen. It is initially
+ // 0. TRUE children cause it to change value.
+ bool accumconst = 0;
+
+ ASTVec new_children;
+
+ it_end = flat_children.end();
+ ASTVec::iterator next_it;
+ for(ASTVec::iterator it = flat_children.begin(); it != it_end; it++) {
+ next_it = it + 1;
+ bool nextexists = (next_it < it_end);
+
+ if (ASTTrue == *it) {
+ accumconst = !accumconst;
+ }
+ else if (ASTFalse == *it) {
+ // Ignore it
+ }
+ else if (nextexists && (*next_it == *it)) {
+ // x XOR x = FALSE. Skip current, write "false" into next_it
+ // so that it gets tossed, too.
+ *next_it = ASTFalse;
+ }
+ else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) {
+ // x XOR NOT x = TRUE. Skip current, write "true" into next_it
+ // so that it gets tossed, too.
+ *next_it = ASTTrue;
+ }
+ else if (NOT == it->GetKind()) {
+ // If child is (NOT alpha), we can flip accumconst and use alpha.
+ // This is ok because (NOT alpha) == TRUE XOR alpha
+ accumconst = !accumconst;
+ // CreateSimpNot just takes child of not.
+ new_children.push_back(CreateSimpNot(*it));
+ }
+ else {
+ new_children.push_back(*it);
+ }
+ }
+
+ // Children should be non-constant.
+ if (new_children.size() < 2) {
+ if (0 == new_children.size()) {
+ // XOR(TRUE, FALSE) -- accumconst will be 1.
+ if (accumconst) {
+ retval = ASTTrue;
+ }
+ else {
+ retval = ASTFalse;
+ }
+ }
+ else {
+ // there is just one child
+ // XOR(x, TRUE) -- accumconst will be 1.
+ if (accumconst) {
+ retval = CreateSimpNot(new_children[0]);
+ }
+ else {
+ retval = new_children[0];
+ }
+ }
+ }
+ else {
+ // negate first child if accumconst == 1
+ if (accumconst) {
+ new_children[0] = CreateSimpNot(new_children[0]);
+ }
+ retval = CreateNode(XOR, new_children);
+ }
+
+ if (_trace_simpbool) {
+ cout << "returns " << retval << endl;
+ }
+ return retval;
+ }
+
+ // FIXME: How do I know whether ITE is a formula or not?
+ ASTNode BeevMgr::CreateSimpFormITE(const ASTNode& child0,
+ const ASTNode& child1,
+ const ASTNode& child2) {
+
+ ASTNode retval;
+
+ if (_trace_simpbool) {
+ cout << "========" << endl << "CreateSimpFormITE "
+ << child0
+ << child1
+ << child2 << endl;
+ }
+
+ if (ASTTrue == child0) {
+ retval = child1;
+ }
+ else if (ASTFalse == child0) {
+ retval = child2;
+ }
+ else if (child1 == child2) {
+ retval = child1;
+ }
+ // ITE(x, TRUE, y ) == x OR y
+ else if (ASTTrue == child1) {
+ retval = CreateSimpAndOr(0, child0, child2);
+ }
+ // ITE(x, FALSE, y ) == (!x AND y)
+ else if (ASTFalse == child1) {
+ retval = CreateSimpAndOr(1, CreateSimpNot(child0), child2);
+ }
+ // ITE(x, y, TRUE ) == (!x OR y)
+ else if (ASTTrue == child2) {
+ retval = CreateSimpAndOr(0, CreateSimpNot(child0), child1);
+ }
+ // ITE(x, y, FALSE ) == (x AND y)
+ else if (ASTFalse == child2) {
+ retval = CreateSimpAndOr(1, child0, child1);
+ }
+ // ITE (x, !y, y) == x XOR y
+// else if (NOT == child1.GetKind() && (child1[0] == child2)) {
+// retval = CreateSimpXor(child0, child2);
+// }
+// // ITE (x, y, !y) == x IFF y. I think other cases are covered
+// // by XOR/IFF optimizations
+// else if (NOT == child2.GetKind() && (child2[0] == child1)) {
+// retval = CreateSimpXor(CreateSimpNot(child0), child2);
+// }
+ else {
+ retval = CreateNode(ITE, child0, child1, child2);
+ }
+
+ if (_trace_simpbool) {
+ cout << "returns " << retval << endl;
+ }
+
+ return retval;
+ }
+} // BEEV namespace
Added: klee/trunk/stp/AST/ToCNF.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/ToCNF.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/ToCNF.cpp (added)
+++ klee/trunk/stp/AST/ToCNF.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,506 @@
+/********************************************************************
+ * AUTHORS: David L. Dill, Vijay Ganesh
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+// THEORY: This code translates an arbitrary Boolean DAG, generated by
+// the BitBlast.cpp, to an equi-satisfiable CNF formula. There are
+// four kinds of variables in the CNF formula: (1) propositional
+// variables from the original formula; (2) BVGETBIT formulas from the
+// original formula (a precondition is that the BVGETBIT can only be
+// applied to bitvector-valued variables, array reads, or
+// uninterpreted functions); (3) TRUE; or (4) representative variables
+// (see below). Each literal in the CNF formula is one of these or
+// its negation.
+
+// It is convenient (though not perfectly efficient) to be able to add
+// TRUE and FALSE constants to clauses, which is not allowed in CNF.
+// So, there is a "dummy variable" representing TRUE, which is used in
+// its place (so FALSE is represented by the negation of the dummy
+// var). The CNF formula has a unit clause containing this dummy
+// variable, so that any satisfying assignment must make the dummy var
+// TRUE.
+
+// Every sub-formula of the input formula has a "representative
+// literal." A truth assignment satisfies the CNF formula iff the
+// restriction of that assignment to the original variables satisfies
+// the original formula, AND the rep lits have the same truth values
+// as the subformulas they represent in the original formula. In the
+// trivial cases, the representative literal is the input variable, or
+// dummy true var, or its negation. Representative literals may be
+// negated variables -- essentially, only AND formulas are translated,
+// and everything else is handled by rewriting or negating formulas.
+// The representative for (NOT alpha) is the negation of the
+// representative for alpha.
+
+// The translation is performed by ToCNF_int, which traverses the original
+// formula. ToCNF adds clauses that constrain the representative variables
+// to be equal to the truth values of the formulas they represent.
+// ToCNF always returns a literal whose value must be equivalent to the formula
+// it translated. In trivial cases, this literal is a literal from the original
+// formula, or the dummy true/false literals. If the formula is of the form
+// (not alpha), ToCNF_int negates the literal representing alpha (which may
+// itself be a negative literal) and returns it. Otherwise, ToCNF_int assigns
+// a new rep var, adds the clauses, and returns the new var. ToCNF_int is
+// memoized so that it doesn't assign more than one variable to a subformula,
+// and to prevent exponential numbers of redundant visits to shared subformulas.
+
+// In reality, only AND/OR/NOT formulas are translated directly. Everything
+// else (XOR, IFF, IMPLIES) is rewritten on-the-fly into these forms. I
+// could have done that in bit-blasting, but I thought that, in the future,
+// we might be able to translate these operations differently in different
+// contexts to optimize the CNF formula.
+
+// FIXME: Inspection of the clauses is kind of horrifying. In
+// addition to true/false, there are duplicate literals and duplicate
+// clauses all over the place.
+#include "AST.h"
+static bool CNF_trace = false;
+namespace BEEV {
+/** Statistics class. Total number of variables is best tracked in
+ ToSAT. Number of clauses is just cll.size() */
+
+class CNFstats {
+public:
+ int _num_new_rep_vars;
+ int _num_clauses;
+
+ // constructor
+ CNFstats() : _num_new_rep_vars(0), _num_clauses(0) {}
+
+ void printStats() {
+ if(stats) {
+ cout << "ToCNF statistics:" << endl;
+ cout << "Number of new representative variables: "
+ << _num_new_rep_vars << endl;
+ cout << "Number of new clauses: "
+ << _num_clauses << endl;
+ }
+ }
+
+};
+
+
+/** This class contains private data and function members for the
+ CNF conversion */
+class CNFMgr {
+
+ friend class BeevMgr;
+
+public:
+
+ // Needed in the body of BeevMgr::ToCNF. It's not visible outside
+ // this file, though.
+ ASTNode dummy_true_var;
+
+ // CNF Pre-pass
+ ASTNodeMap ToCNFPrePassMemo;
+
+ // CNF Memo Table.
+ ASTNodeMap CNFMemo;
+
+
+private:
+
+ // Pointer back to BeevMgr with the node tables, etc.
+ BeevMgr *bm;
+
+ // For ToCNF conversion. This holds a dummy variable representing
+ // "True". It is added as a unit clause, so that it will be assigned
+ // to true and propagated immediately by any CNF solver.
+
+ ASTNode dummy_false_var; // not of dummy_true_var
+
+ CNFstats stats;
+
+ // constructor
+ CNFMgr(BeevMgr *bmgr)
+ {
+ bm = bmgr;
+
+ // Dummy variable so TRUE can be a literal.
+ dummy_true_var = bm->CreateSymbol("*TrueDummy*");
+ dummy_false_var = bm->CreateSimpNot(dummy_true_var);
+ }
+
+ // Returns true iff result has been memoized.
+ // if it returns true, result is returned in by-ref parameter "result"
+ // Consider just putitng this in-line.
+ bool CNFIsMemoized(ASTNode &form, ASTNode &result)
+ {
+ ASTNodeMap::iterator it = CNFMemo.find(form);
+ if (it != CNFMemo.end()) {
+ result = it->second; //already there. Just return it.
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+
+ // Convert a big XOR to a bunch of AND/ORs. Assumes subformulas have
+ // already been converted.
+ ASTNode convertXORs(ASTVec children)
+ {
+ ASTNode accum = children[0];
+ ASTVec::iterator itend = children.end();
+ for (ASTVec::iterator it = children.begin()+1; it < itend; it++) {
+ // a XOR b -> (a | b) & (!a | !b)
+
+ // For each XOR node with k children, creates approximately
+ // 5*(k-1) nodes. AND + 2 OR + 2 NOT.
+
+ ASTNode or1 = bm->CreateNode(OR, accum, *it);
+ ASTNode or2 = bm->CreateNode(OR, bm->CreateSimpNot(accum), bm->CreateSimpNot(*it));
+ accum = bm->CreateNode(AND, or1, or2);
+
+ }
+
+ return accum;
+ }
+
+
+ // Do preliminary transformations on bitblasted formula to make
+ // CNF conversion easier.
+ // Converts XORs to AND/OR form.
+ ASTNode ToCNFPrePass(const ASTNode &form)
+ {
+
+ // Check memo table
+ ASTNodeMap::iterator mem_it = ToCNFPrePassMemo.find(form);
+ if (mem_it != ToCNFPrePassMemo.end()) {
+ return mem_it->second;
+ }
+
+ ASTNode result;
+
+ ASTVec new_children;
+ ASTVec::const_iterator endit = form.end();
+ for (ASTVec::const_iterator it = form.begin(); it != endit; it++) {
+ ASTNode ch = ToCNFPrePass(*it);
+ new_children.push_back(ch);
+ }
+
+ Kind k = form.GetKind();
+
+ switch (k) {
+ case FALSE:
+ case TRUE:
+ case SYMBOL:
+ case BVGETBIT: {
+ result = form;
+ break;
+ }
+ case XOR: {
+ // convertXORs can only be called once per XOR node.
+ result = convertXORs(new_children);
+
+ // cout << "convertXORs num args: " << new_children.size() << endl;
+ // temporary node for node count.
+ // ASTNode tmp = bm->CreateNode(XOR, new_children );
+ // cout << "convertXORs size of [" << form.GetNodeNum() << "] " << bm->NodeSize(form, true) << endl;
+ // cout << "convertXORs before size: " << bm->NodeSize(tmp, true) << endl;
+ // cout << "convertXORs after size: " << bm->NodeSize(result, true) << endl;
+ break;
+ }
+ default: {
+ // Be cautious about using CreateSimpForm -- It makes big xors!
+ result = bm->CreateNode(k, new_children);
+ }
+ }
+
+// cout << "================" << endl
+// << "ToCNFPrePass:" << form << endl
+// << "----------------" << endl
+// << "ToCNFPrePass Result:" << result << endl;
+
+ return (ToCNFPrePassMemo[form] = result);
+
+ }
+
+ // Memoize and return formula value
+ ASTNode CNFMemoize(ASTNode& form, ASTNode result)
+ {
+ CNFMemo[form] = result;
+ return result;
+ }
+
+
+ // Create a representative variable for an original formula.
+ // The convention is that the variable will have the same truth
+ // value as the expression numbered "num."
+ ASTNode RepLit(const char *name, int exprnum)
+ {
+ // FIXME: can this be done more efficiently with string type?
+ ostringstream oss;
+ oss << name << "{" << exprnum << "}";
+ ASTNode t = bm->CreateSymbol(oss.str().c_str());
+
+ // Track how many we're generating.
+ stats._num_new_rep_vars++;
+
+ //ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0))
+ t.SetIndexWidth(0);
+ t.SetValueWidth(0);
+ return t;
+ }
+
+ // Handle the cases where it's necessary to do n children.
+ // This code translates ANDs, and converts NAND, NOR, OR by negating
+ // the inputs or outputs of the AND.
+ ASTNode ToCNF_AndLike(Kind k, BeevMgr::ClauseList& cll, ASTNode form)
+ {
+ // Build vectors of positive and negative rep lits for children
+ ASTVec kidlits(0);
+ ASTVec negkidlits(0);
+ ASTVec::const_iterator kids_end = form.end();
+ for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) {
+ ASTNode kidreplit = ToCNF_int(cll, *it);
+ kidlits.push_back(kidreplit);
+ negkidlits.push_back(bm->CreateSimpNot(kidreplit));
+ }
+
+ ASTNode replit;
+ // translate the AND, negating inputs as appropriate.
+ if (k == OR || k == NOR) {
+ replit = ToCNF_AND(cll, form.GetNodeNum(), negkidlits, kidlits);
+ }
+ else {
+ replit = ToCNF_AND(cll, form.GetNodeNum(), kidlits, negkidlits);
+ }
+
+ // Reduce NAND/OR to AND by negating result.
+ if (k == NAND || k == OR) {
+ return CNFMemoize(form, bm->CreateSimpNot(replit));
+ }
+ else {
+ return CNFMemoize(form, replit);
+ }
+ }
+
+ ASTNode ToCNF_AND(BeevMgr::ClauseList& cll, int nodenum, ASTVec& kidlits, ASTVec& negkidlits)
+ {
+ // Translate an AND, given rep lits for children
+ // Build clauses for (replit <-> a AND b AND c)
+
+ ASTNode replit = RepLit("cnf", nodenum);
+ ASTNode notreplit = bm->CreateSimpNot(replit);
+
+ if (CNF_trace) {
+ cout << "Translating AND" << endl << "-----------------------" << endl
+ << "Rep lit =" << replit << endl
+ << "-----------------------";
+ }
+
+ // (a AND b AND c -> replit) == (~a OR ~b OR ~c OR replit)
+ BeevMgr::ClausePtr clp = new ASTVec(negkidlits);
+ clp->push_back(replit);
+
+ if (CNF_trace) {
+ LispPrintVec(cout, *clp, 0);
+ cout << endl << "-----------------------" << endl;
+ }
+
+ cll.push_back(clp);
+
+ // (replit -> (a AND b AND c)) ==
+ // (~replit OR a) AND (~replit OR b) AND (~replit OR c)
+ ASTVec::const_iterator kidlits_end = kidlits.end();
+ for (ASTVec::iterator it = kidlits.begin(); it != kidlits_end; it++) {
+ clp = new ASTVec();
+ clp->push_back(notreplit);
+ clp->push_back(*it);
+
+ if (CNF_trace) {
+ LispPrintVec(cout, *clp, 0);
+ cout << endl << "-----------------------" << endl;
+ }
+
+ cll.push_back(clp);
+ }
+
+ return replit;
+ }
+
+public:
+
+ /** Builds clauses globally and returns a literal.
+ The literal can be a leaf from the expression, or a rep var
+ made up to represent the subexpression. */
+ ASTNode ToCNF_int(BeevMgr::BeevMgr::ClauseList& cll, ASTNode form) {
+ // FIXME: assert indexwidth= 0, valuewidth = 1
+
+ // FIXME: rewriting is top-down, which is not efficient.
+ // It rewrites the top node of the tree, then does the children.
+ // Either rewrite in a separate pass, or translate children
+ // before rewriting somehow (might require handling rep lits
+ // as though they were real lits, which is probably ok).
+
+ // Return memoized value if seen before.
+ ASTNode result;
+ Kind k = form.GetKind();
+
+ if (CNFIsMemoized(form, result)) {
+ return result;
+ }
+
+ switch (k) {
+ // handle the trivial cases here. If none apply, call the
+ // heavy-duty function. If a constant or literal, just return
+ // without creating a clause.
+ case FALSE: {
+ result = dummy_false_var;
+ break;
+ }
+ case TRUE: {
+ result = dummy_true_var;
+ break;
+ }
+ case SYMBOL:
+ case BVGETBIT: {
+ result = form;
+ break;
+ }
+
+ case NOT: {
+ ASTNode replit = ToCNF_int(cll, form[0]);
+ result = bm->CreateSimpNot(replit);
+ break;
+ }
+
+ // For these, I can't think of anything better than expanding into ANDs/ORs
+ case ITE: {
+ // (ite a b c) == (~a OR b) AND (a OR c)
+ ASTNode l = bm->CreateNode(OR, bm->CreateSimpNot(form[0]), form[1]);
+ ASTNode r = bm->CreateNode(OR, form[0], form[2]);
+ ASTNode andor = bm->CreateNode(AND, l, r);
+ if (CNF_trace) {
+ cout << "Rewriting " << form << endl
+ << "to" << andor << endl
+ << "-------------------" << endl;
+ }
+ result = ToCNF_int(cll, andor);
+ break;
+ }
+ case IMPLIES: {
+ // Just rewrite into (~a OR b)
+ ASTNode l = bm->CreateSimpNot(form[0]);
+ ASTNode andor = bm->CreateNode(OR, l, form[1]);
+ if (CNF_trace) {
+ cout << "Rewriting " << form << endl
+ << "to" << andor << endl
+ << "-------------------" << endl;
+ }
+ result = ToCNF_int(cll, andor);
+ break;
+ }
+ case XOR: {
+ FatalError("ToCNF_int: XORs should have been converted to AND/OR by this point.");
+ break;
+ }
+
+ case IFF: {
+ FatalError("BitBlaster failed to eliminate all IFFs.");
+ break;
+ }
+
+ case AND:
+ case OR:
+ case NOR:
+ case NAND: {
+ result = ToCNF_AndLike(k, cll, form);
+ break;
+ }
+ default:
+ cerr << "ToCNF: can't handle this kind: " << k << endl;
+ FatalError("");
+ }
+
+ if (CNF_trace) {
+ cout << "ToCNF_int: Literal " << result << " represents formula " <<
+ form << endl << "---------------" << endl;
+ }
+
+ return CNFMemoize(form, result);
+ } //end of ToCNF_int()
+
+
+}; // end of CNFMgr class
+
+ // These are the bodies of functions in the BeevMgr that are part of
+ // the public interface.
+
+ // Debug printing function.
+ void BeevMgr::PrintClauseList(ostream& os, BeevMgr::ClauseList& cll)
+ {
+ int num_clauses = cll.size();
+ os << "Clauses: " << endl << "=========================================" << endl;
+ for(int i=0; i < num_clauses; i++) {
+ os << "Clause " << i << endl
+ << "-------------------------------------------" << endl;
+ LispPrintVec(os, *cll[i], 0);
+ os << endl
+ << "-------------------------------------------" << endl;
+ }
+ }
+
+ void BeevMgr::DeleteClauseList(BeevMgr::ClauseList *cllp)
+ {
+ BeevMgr::ClauseList::const_iterator iend = cllp->end();
+ for (BeevMgr::ClauseList::const_iterator i = cllp->begin(); i < iend; i++) {
+ delete *i;
+ }
+ delete cllp;
+ }
+
+ // Top level conversion function
+ BeevMgr::ClauseList *BeevMgr::ToCNF(const ASTNode& form)
+ {
+
+ // FIXME: This is leaked as well.
+ CNFMgr *cm = new CNFMgr(this);
+
+ // Prepass
+ ASTNode form1 = cm->ToCNFPrePass(form);
+
+ // cout << "Number of nodes after ToCNFPrePass" << NodeSize(form1, true) << endl;
+
+ // cout << "ToCNF: After ToCNFPrePass" << form1 << endl;
+
+ // FIXME: Assert CNFMemo is empty.
+
+ // The clause list we will be building up.
+ // FIXME: This is never freed.
+ ClauseList *cllp = new ClauseList();
+
+ BeevMgr::ClausePtr dummy_true_unit_clause = new ASTVec();
+ dummy_true_unit_clause->push_back(cm->dummy_true_var);
+ cllp->push_back(dummy_true_unit_clause);
+
+ // This is where the translation happens.
+ ASTNode toplit = cm->ToCNF_int(*cllp, form1);
+
+ // Add the top literal as a unit clause, since it must
+ // be true when original formula is satsfied.
+ BeevMgr::ClausePtr clp = new ASTVec(0);
+ clp->push_back(toplit);
+ cllp->push_back(clp);
+
+ cm->stats._num_clauses = cllp->size();
+ cm->stats.printStats();
+
+ RepLitMap = cm->CNFMemo; // Save memo table for debugging (DD 1/13/07).
+
+ cm->CNFMemo.clear(); // Important to do this so nodes get freed.
+
+ delete cm;
+
+ return cllp;
+ }
+
+} // end namespace
Added: klee/trunk/stp/AST/ToSAT.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/ToSAT.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/ToSAT.cpp (added)
+++ klee/trunk/stp/AST/ToSAT.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1385 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+#include "AST.h"
+#include "ASTUtil.h"
+#include "../simplifier/bvsolver.h"
+#include <math.h>
+
+
+namespace BEEV {
+ /* FUNCTION: lookup or create a new MINISAT literal
+ * lookup or create new MINISAT Vars from the global MAP
+ * _ASTNode_to_SATVar.
+ */
+ const MINISAT::Var BeevMgr::LookupOrCreateSATVar(MINISAT::Solver& newS, const ASTNode& n) {
+ ASTtoSATMap::iterator it;
+ MINISAT::Var v;
+
+ //look for the symbol in the global map from ASTNodes to ints. if
+ //not found, create a S.newVar(), else use the existing one.
+ if((it = _ASTNode_to_SATVar.find(n)) == _ASTNode_to_SATVar.end()) {
+ v = newS.newVar();
+ _ASTNode_to_SATVar[n] = v;
+
+ //ASSUMPTION: I am assuming that the newS.newVar() call increments v
+ //by 1 each time it is called, and the initial value of a
+ //MINISAT::Var is 0.
+ _SATVar_to_AST.push_back(n);
+ }
+ else
+ v = it->second;
+ return v;
+ }
+
+ /* FUNCTION: convert ASTClauses to MINISAT clauses and solve.
+ * Accepts ASTClauses and converts them to MINISAT clauses. Then adds
+ * the newly minted MINISAT clauses to the local SAT instance, and
+ * calls solve(). If solve returns unsat, then stop and return
+ * unsat. else continue.
+ */
+ // FIXME: Still need to deal with TRUE/FALSE in clauses!
+ bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll)
+ {
+ CountersAndStats("SAT Solver");
+
+ //iterate through the list (conjunction) of ASTclauses cll
+ BeevMgr::ClauseList::const_iterator i = cll.begin(), iend = cll.end();
+
+ if(i == iend)
+ FatalError("toSATandSolve: Nothing to Solve",ASTUndefined);
+
+ //turnOffSubsumption
+ newS.turnOffSubsumption();
+
+ // (*i) is an ASTVec-ptr which denotes an ASTclause
+ for(; i!=iend; i++) {
+ //Clause for the SATSolver
+ MINISAT::vec<MINISAT::Lit> satSolverClause;
+
+ //now iterate through the internals of the ASTclause itself
+ ASTVec::const_iterator j = (*i)->begin(), jend = (*i)->end();
+ //j is a disjunct in the ASTclause (*i)
+ for(;j!=jend;j++) {
+
+ bool negate = (NOT == j->GetKind()) ? true : false;
+ ASTNode n = negate ? (*j)[0] : *j;
+
+ //Lookup or create the MINISAT::Var corresponding to the Booelan
+ //ASTNode Variable, and push into sat Solver clause
+ MINISAT::Var v = LookupOrCreateSATVar(newS,n);
+ MINISAT::Lit l(v, negate);
+ satSolverClause.push(l);
+ }
+ newS.addClause(satSolverClause);
+ // clause printing.
+ // (printClause<MINISAT::vec<MINISAT::Lit> >)(satSolverClause);
+ // cout << " 0 ";
+ // cout << endl;
+
+ if(newS.okay()) {
+ continue;
+ }
+ else {
+ PrintStats(newS.stats);
+ return false;
+ }
+
+ if(!newS.simplifyDB(false)) {
+ PrintStats(newS.stats);
+ return false;
+ }
+ }
+
+ // if input is UNSAT return false, else return true
+ if(!newS.simplifyDB(false)) {
+ PrintStats(newS.stats);
+ return false;
+ }
+
+ //PrintActivityLevels_Of_SATVars("Before SAT:",newS);
+ //ChangeActivityLevels_Of_SATVars(newS);
+ //PrintActivityLevels_Of_SATVars("Before SAT and after initial bias:",newS);
+ newS.solve();
+ //PrintActivityLevels_Of_SATVars("After SAT",newS);
+
+ PrintStats(newS.stats);
+ if (newS.okay())
+ return true;
+ else
+ return false;
+ }
+
+ // GLOBAL FUNCTION: Prints statistics from the MINISAT Solver
+ void BeevMgr::PrintStats(MINISAT::SolverStats& s) {
+ if(!stats)
+ return;
+ double cpu_time = MINISAT::cpuTime();
+ MINISAT::int64 mem_used = MINISAT::memUsed();
+ reportf("restarts : %"I64_fmt"\n", s.starts);
+ reportf("conflicts : %-12"I64_fmt" (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time);
+ reportf("decisions : %-12"I64_fmt" (%.0f /sec)\n", s.decisions , s.decisions /cpu_time);
+ reportf("propagations : %-12"I64_fmt" (%.0f /sec)\n", s.propagations, s.propagations/cpu_time);
+ reportf("conflict literals : %-12"I64_fmt" (%4.2f %% deleted)\n",
+ s.tot_literals,
+ (s.max_literals - s.tot_literals)*100 / (double)s.max_literals);
+ if (mem_used != 0) reportf("Memory used : %.2f MB\n", mem_used / 1048576.0);
+ reportf("CPU time : %g s\n", cpu_time);
+ }
+
+ // Prints Satisfying assignment directly, for debugging.
+ void BeevMgr::PrintSATModel(MINISAT::Solver& newS) {
+ if(!newS.okay())
+ FatalError("PrintSATModel: NO COUNTEREXAMPLE TO PRINT",ASTUndefined);
+ // FIXME: Don't put tests like this in the print functions. The print functions
+ // should print unconditionally. Put a conditional around the call if you don't
+ // want them to print
+ if(!(stats && print_nodes))
+ return;
+
+ int num_vars = newS.nVars();
+ cout << "Satisfying assignment: " << endl;
+ for (int i = 0; i < num_vars; i++) {
+ if (newS.model[i] == MINISAT::l_True) {
+ ASTNode s = _SATVar_to_AST[i];
+ cout << s << endl;
+ }
+ else if (newS.model[i] == MINISAT::l_False) {
+ ASTNode s = _SATVar_to_AST[i];
+ cout << CreateNode(NOT, s) << endl;
+ }
+ }
+ }
+
+
+ // Looks up truth value of ASTNode SYMBOL in MINISAT satisfying assignment.
+ // Returns ASTTrue if true, ASTFalse if false or undefined.
+ ASTNode BeevMgr::SymbolTruthValue(MINISAT::Solver &newS, ASTNode form)
+ {
+ MINISAT::Var satvar = _ASTNode_to_SATVar[form];
+ if (newS.model[satvar] == MINISAT::l_True) {
+ return ASTTrue;
+ }
+ else if (newS.model[satvar] == MINISAT::l_False){
+ // False
+ return ASTFalse;
+ }
+ else {
+ return (rand() > 4096) ? ASTTrue : ASTFalse;
+ }
+ }
+
+
+ // This function is for debugging problems with BitBlast and especially
+ // ToCNF. It evaluates the bit-blasted formula in the satisfying
+ // assignment. While doing that, it checks that every subformula has
+ // the same truth value as its representative literal, if it has one.
+ // If this condition is violated, it halts immediately (on the leftmost
+ // lowest term).
+ // Use CreateSimpForm to evaluate, even though it's expensive, so that
+ // we can use the partial truth assignment.
+ ASTNode BeevMgr::CheckBBandCNF(MINISAT::Solver& newS, ASTNode form)
+ {
+ // Clear memo table (in case newS has changed).
+ CheckBBandCNFMemo.clear();
+ // Call recursive version that does the work.
+ return CheckBBandCNF_int(newS, form);
+ }
+
+ // Recursive body CheckBBandCNF
+ // FIXME: Modify this to just check if result is true, and print mismatch
+ // if not. Might have a trace flag for the other stuff.
+ ASTNode BeevMgr::CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form)
+ {
+
+ // cout << "++++++++++++++++" << endl << "CheckBBandCNF_int form = " <<
+ // form << endl;
+
+ ASTNodeMap::iterator memoit = CheckBBandCNFMemo.find(form);
+ if (memoit != CheckBBandCNFMemo.end()) {
+ // found it. Return memoized value.
+ return memoit->second;
+ }
+
+ ASTNode result; // return value, to memoize.
+
+ Kind k = form.GetKind();
+ switch (k) {
+ case TRUE:
+ case FALSE: {
+ return form;
+ break;
+ }
+ case SYMBOL:
+ case BVGETBIT: {
+ // Look up the truth value
+ // ASTNode -> Sat -> Truthvalue -> ASTTrue or ASTFalse;
+ // FIXME: Could make up a fresh var in undefined case.
+
+ result = SymbolTruthValue(newS, form);
+
+ cout << "================" << endl << "Checking BB formula:" << form << endl;
+ cout << "----------------" << endl << "Result:" << result << endl;
+
+ break;
+ }
+ default: {
+ // Evaluate the children recursively.
+ ASTVec eval_children;
+ ASTVec ch = form.GetChildren();
+ ASTVec::iterator itend = ch.end();
+ for(ASTVec::iterator it = ch.begin(); it < itend; it++) {
+ eval_children.push_back(CheckBBandCNF_int(newS, *it));
+ }
+ result = CreateSimpForm(k, eval_children);
+
+ cout << "================" << endl << "Checking BB formula:" << form << endl;
+ cout << "----------------" << endl << "Result:" << result << endl;
+
+ ASTNode replit_eval;
+ // Compare with replit, if there is one.
+ ASTNodeMap::iterator replit_it = RepLitMap.find(form);
+ if (replit_it != RepLitMap.end()) {
+ ASTNode replit = RepLitMap[form];
+ // Replit is symbol or not symbol.
+ if (SYMBOL == replit.GetKind()) {
+ replit_eval = SymbolTruthValue(newS, replit);
+ }
+ else {
+ // It's (NOT sym). Get value of sym and complement.
+ replit_eval = CreateSimpNot(SymbolTruthValue(newS, replit[0]));
+ }
+
+ cout << "----------------" << endl << "Rep lit: " << replit << endl;
+ cout << "----------------" << endl << "Rep lit value: " << replit_eval << endl;
+
+ if (result != replit_eval) {
+ // Hit the panic button.
+ FatalError("Truth value of BitBlasted formula disagrees with representative literal in CNF.");
+ }
+ }
+ else {
+ cout << "----------------" << endl << "No rep lit" << endl;
+ }
+
+ }
+ }
+
+ return (CheckBBandCNFMemo[form] = result);
+ }
+
+ /*FUNCTION: constructs counterexample from MINISAT counterexample
+ * step1 : iterate through MINISAT counterexample and assemble the
+ * bits for each AST term. Store it in a map from ASTNode to vector
+ * of bools (bits).
+ *
+ * step2: Iterate over the map from ASTNodes->Vector-of-Bools and
+ * populate the CounterExampleMap data structure (ASTNode -> BVConst)
+ */
+ void BeevMgr::ConstructCounterExample(MINISAT::Solver& newS) {
+ //iterate over MINISAT counterexample and construct a map from AST
+ //terms to vector of bools. We need this iteration step because
+ //MINISAT might return the various bits of a term out of
+ //order. Therfore, we need to collect all the bits and assemble
+ //them properly
+
+ if(!newS.okay())
+ return;
+ if(!construct_counterexample)
+ return;
+
+ CopySolverMap_To_CounterExample();
+ for (int i = 0; i < newS.nVars(); i++) {
+ //Make sure that the MINISAT::Var is defined
+ if (newS.model[i] != MINISAT::l_Undef) {
+
+ //mapping from MINISAT::Vars to ASTNodes. We do not need to
+ //print MINISAT vars or CNF vars.
+ ASTNode s = _SATVar_to_AST[i];
+
+ //assemble the counterexample here
+ if(s.GetKind() == BVGETBIT && s[0].GetKind() == SYMBOL) {
+ ASTNode symbol = s[0];
+ unsigned int symbolWidth = symbol.GetValueWidth();
+
+ //'v' is the map from bit-index to bit-value
+ hash_map<unsigned,bool> * v;
+ if(_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end())
+ _ASTNode_to_Bitvector[symbol] = new hash_map<unsigned,bool>(symbolWidth);
+
+ //v holds the map from bit-index to bit-value
+ v = _ASTNode_to_Bitvector[symbol];
+
+ //kk is the index of BVGETBIT
+ unsigned int kk = GetUnsignedConst(s[1]);
+
+ //Collect the bits of 'symbol' and store in v. Store in reverse order.
+ if(newS.model[i]==MINISAT::l_True)
+ (*v)[(symbolWidth-1) - kk] = true;
+ else
+ (*v)[(symbolWidth-1) - kk] = false;
+ }
+ else {
+ if(s.GetKind() == SYMBOL && s.GetType() == BOOLEAN_TYPE) {
+ const char * zz = s.GetName();
+ //if the variables are not cnf variables then add them to the counterexample
+ if(0 != strncmp("cnf",zz,3) && 0 != strcmp("*TrueDummy*",zz)) {
+ if(newS.model[i]==MINISAT::l_True)
+ CounterExampleMap[s] = ASTTrue;
+ else
+ CounterExampleMap[s] = ASTFalse;
+ }
+ }
+ }
+ }
+ }
+
+ //iterate over the ASTNode_to_Bitvector data-struct and construct
+ //the the aggregate value of the bitvector, and populate the
+ //CounterExampleMap datastructure
+ for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(),itend=_ASTNode_to_Bitvector.end();
+ it!=itend;it++) {
+ ASTNode var = it->first;
+ //debugging
+ //cerr << var;
+ if(SYMBOL != var.GetKind())
+ FatalError("ConstructCounterExample: error while constructing counterexample: not a variable: ",var);
+
+ //construct the bitvector value
+ hash_map<unsigned,bool> * w = it->second;
+ ASTNode value = BoolVectoBVConst(w, var.GetValueWidth());
+ //debugging
+ //cerr << value;
+
+ //populate the counterexample datastructure. add only scalars
+ //variables which were declared in the input and newly
+ //introduced variables for array reads
+ CounterExampleMap[var] = value;
+ }
+
+ //In this loop, we compute the value of each array read, the
+ //corresponding ITE against the counterexample generated above.
+ for(ASTNodeMap::iterator it=_arrayread_ite.begin(),itend=_arrayread_ite.end();
+ it!=itend;it++){
+ //the array read
+ ASTNode arrayread = it->first;
+ ASTNode value_ite = _arrayread_ite[arrayread];
+
+ //convert it to a constant array-read and store it in the
+ //counter-example. First convert the index into a constant. then
+ //construct the appropriate array-read and store it in the
+ //counterexample
+ ASTNode arrayread_index = TermToConstTermUsingModel(arrayread[1]);
+ ASTNode key = CreateTerm(READ,arrayread.GetValueWidth(),arrayread[0],arrayread_index);
+
+ //Get the ITE corresponding to the array-read and convert it
+ //to a constant against the model
+ ASTNode value = TermToConstTermUsingModel(value_ite);
+ //save the result in the counter_example
+ if(!CheckSubstitutionMap(key))
+ CounterExampleMap[key] = value;
+ }
+ } //End of ConstructCounterExample
+
+ // FUNCTION: accepts a non-constant term, and returns the
+ // corresponding constant term with respect to a model.
+ //
+ // term READ(A,i) is treated as follows:
+ //
+ //1. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead
+ //1. has value in counterexample), then return the value of the
+ //1. arrayread.
+ //
+ //2. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead
+ //2. doesn't have value in counterexample), then return the
+ //2. arrayread itself (normalized such that arrayread has a constant
+ //2. index)
+ //
+ //3. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead
+ //3. has a value in the counterexample then return the value of the
+ //3. arrayread.
+ //
+ //4. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead
+ //4. doesn't have a value in the counterexample then return 0 as the
+ //4. value of the arrayread.
+ ASTNode BeevMgr::TermToConstTermUsingModel(const ASTNode& t, bool ArrayReadFlag) {
+ Begin_RemoveWrites = false;
+ SimplifyWrites_InPlace_Flag = false;
+ //ASTNode term = SimplifyTerm(t);
+ ASTNode term = t;
+ Kind k = term.GetKind();
+
+
+ //cerr << "Input to TermToConstTermUsingModel: " << term << endl;
+ if(!is_Term_kind(k)) {
+ FatalError("TermToConstTermUsingModel: The input is not a term: ",term);
+ }
+ if(k == WRITE) {
+ FatalError("TermToConstTermUsingModel: The input has wrong kind: WRITE : ",term);
+ }
+ if(k == SYMBOL && BOOLEAN_TYPE == term.GetType()) {
+ FatalError("TermToConstTermUsingModel: The input has wrong kind: Propositional variable : ",term);
+ }
+
+ ASTNodeMap::iterator it1;
+ if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) {
+ ASTNode val = it1->second;
+ if(BVCONST != val.GetKind()) {
+ //CounterExampleMap has two maps rolled into
+ //one. SubstitutionMap and SolverMap.
+ //
+ //recursion is fine here. There are two maps that are checked
+ //here. One is the substitutionmap. We garuntee that the value
+ //of a key in the substitutionmap is always a constant.
+ //
+ //in the SolverMap we garuntee that "term" does not occur in
+ //the value part of the map
+ if(term == val) {
+ FatalError("TermToConstTermUsingModel: The input term is stored as-is "
+ "in the CounterExample: Not ok: ",term);
+ }
+ return TermToConstTermUsingModel(val,ArrayReadFlag);
+ }
+ else {
+ return val;
+ }
+ }
+
+ ASTNode output;
+ switch(k) {
+ case BVCONST:
+ output = term;
+ break;
+ case SYMBOL: {
+ if(term.GetType() == ARRAY_TYPE) {
+ return term;
+ }
+
+ //when all else fails set symbol values to some constant by
+ //default. if the variable is queried the second time then add 1
+ //to and return the new value.
+ ASTNode zero = CreateZeroConst(term.GetValueWidth());
+ output = zero;
+ break;
+ }
+ case READ: {
+ ASTNode arrName = term[0];
+ ASTNode index = term[1];
+ if(0 == arrName.GetIndexWidth()) {
+ FatalError("TermToConstTermUsingModel: array has 0 index width: ",arrName);
+ }
+
+ //READ over a WRITE
+ if(WRITE == arrName.GetKind()) {
+ ASTNode wrtterm = Expand_ReadOverWrite_UsingModel(term, ArrayReadFlag);
+ if(wrtterm == term) {
+ FatalError("TermToConstTermUsingModel: Read_Over_Write term must be expanded into an ITE", term);
+ }
+ ASTNode rtterm = TermToConstTermUsingModel(wrtterm,ArrayReadFlag);
+ return rtterm;
+ }
+ //READ over an ITE
+ if(ITE == arrName.GetKind()) {
+ arrName = TermToConstTermUsingModel(arrName,ArrayReadFlag);
+ }
+
+ ASTNode modelentry;
+ if(CounterExampleMap.find(index) != CounterExampleMap.end()) {
+ //index has a const value in the CounterExampleMap
+ ASTNode indexVal = CounterExampleMap[index];
+ modelentry = CreateTerm(READ, arrName.GetValueWidth(), arrName, indexVal);
+ }
+ else {
+ //index does not have a const value in the CounterExampleMap. compute it.
+ ASTNode indexconstval = TermToConstTermUsingModel(index,ArrayReadFlag);
+ //update model with value of the index
+ //CounterExampleMap[index] = indexconstval;
+ modelentry = CreateTerm(READ,arrName.GetValueWidth(), arrName,indexconstval);
+ }
+ //modelentry is now an arrayread over a constant index
+ BVTypeCheck(modelentry);
+
+ //if a value exists in the CounterExampleMap then return it
+ if(CounterExampleMap.find(modelentry) != CounterExampleMap.end()) {
+ output = TermToConstTermUsingModel(CounterExampleMap[modelentry],ArrayReadFlag);
+ }
+ else if(ArrayReadFlag) {
+ //return the array read over a constantindex
+ output = modelentry;
+ }
+ else {
+ //when all else fails set symbol values to some constant by
+ //default. if the variable is queried the second time then add 1
+ //to and return the new value.
+ ASTNode zero = CreateZeroConst(modelentry.GetValueWidth());
+ output = zero;
+ }
+ break;
+ }
+ case ITE: {
+ ASTNode condcompute = ComputeFormulaUsingModel(term[0]);
+ if(ASTTrue == condcompute) {
+ output = TermToConstTermUsingModel(term[1],ArrayReadFlag);
+ }
+ else if(ASTFalse == condcompute) {
+ output = TermToConstTermUsingModel(term[2],ArrayReadFlag);
+ }
+ else {
+ cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl;
+ FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ",term);
+ }
+ break;
+ }
+ default: {
+ ASTVec c = term.GetChildren();
+ ASTVec o;
+ for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
+ ASTNode ff = TermToConstTermUsingModel(*it,ArrayReadFlag);
+ o.push_back(ff);
+ }
+ output = CreateTerm(k,term.GetValueWidth(),o);
+ //output is a CONST expression. compute its value and store it
+ //in the CounterExampleMap
+ ASTNode oo = BVConstEvaluator(output);
+ //the return value
+ output = oo;
+ break;
+ }
+ }
+
+ //when this flag is false, we should compute the arrayread to a
+ //constant. this constant is stored in the counter_example
+ //datastructure
+ if(!ArrayReadFlag) {
+ CounterExampleMap[term] = output;
+ }
+
+ //cerr << "Output to TermToConstTermUsingModel: " << output << endl;
+ return output;
+ } //End of TermToConstTermUsingModel
+
+ //Expands read-over-write by evaluating (readIndex=writeIndex) for
+ //every writeindex until, either it evaluates to TRUE or all
+ //(readIndex=writeIndex) evaluate to FALSE
+ ASTNode BeevMgr::Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool arrayread_flag) {
+ if(READ != term.GetKind() &&
+ WRITE != term[0].GetKind()) {
+ FatalError("RemovesWrites: Input must be a READ over a WRITE",term);
+ }
+
+ ASTNode output;
+ ASTNodeMap::iterator it1;
+ if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) {
+ ASTNode val = it1->second;
+ if(BVCONST != val.GetKind()) {
+ //recursion is fine here. There are two maps that are checked
+ //here. One is the substitutionmap. We garuntee that the value
+ //of a key in the substitutionmap is always a constant.
+ if(term == val) {
+ FatalError("TermToConstTermUsingModel: The input term is stored as-is "
+ "in the CounterExample: Not ok: ",term);
+ }
+ return TermToConstTermUsingModel(val,arrayread_flag);
+ }
+ else {
+ return val;
+ }
+ }
+
+ unsigned int width = term.GetValueWidth();
+ ASTNode writeA = ASTTrue;
+ ASTNode newRead = term;
+ ASTNode readIndex = TermToConstTermUsingModel(newRead[1],false);
+ //iteratively expand read-over-write, and evaluate against the
+ //model at every iteration
+ do {
+ ASTNode write = newRead[0];
+ writeA = write[0];
+ ASTNode writeIndex = TermToConstTermUsingModel(write[1],false);
+ ASTNode writeVal = TermToConstTermUsingModel(write[2],false);
+
+ ASTNode cond = ComputeFormulaUsingModel(CreateSimplifiedEQ(writeIndex,readIndex));
+ if(ASTTrue == cond) {
+ //found the write-value. return it
+ output = writeVal;
+ CounterExampleMap[term] = output;
+ return output;
+ }
+
+ newRead = CreateTerm(READ,width,writeA,readIndex);
+ } while(READ == newRead.GetKind() && WRITE == newRead[0].GetKind());
+
+ output = TermToConstTermUsingModel(newRead,arrayread_flag);
+
+ //memoize
+ CounterExampleMap[term] = output;
+ return output;
+ } //Exand_ReadOverWrite_To_ITE_UsingModel()
+
+ /* FUNCTION: accepts a non-constant formula, and checks if the
+ * formula is ASTTrue or ASTFalse w.r.t to a model
+ */
+ ASTNode BeevMgr::ComputeFormulaUsingModel(const ASTNode& form) {
+ ASTNode in = form;
+ Kind k = form.GetKind();
+ if(!(is_Form_kind(k) && BOOLEAN_TYPE == form.GetType())) {
+ FatalError(" ComputeConstFormUsingModel: The input is a non-formula: ", form);
+ }
+
+ //cerr << "Input to ComputeFormulaUsingModel:" << form << endl;
+ ASTNodeMap::iterator it1;
+ if((it1 = ComputeFormulaMap.find(form)) != ComputeFormulaMap.end()) {
+ ASTNode res = it1->second;
+ if(ASTTrue == res || ASTFalse == res) {
+ return res;
+ }
+ else {
+ FatalError("ComputeFormulaUsingModel: The value of a formula must be TRUE or FALSE:", form);
+ }
+ }
+
+ ASTNode t0,t1;
+ ASTNode output = ASTFalse;
+ switch(k) {
+ case TRUE:
+ case FALSE:
+ output = form;
+ break;
+ case SYMBOL:
+ if(BOOLEAN_TYPE != form.GetType())
+ FatalError(" ComputeFormulaUsingModel: Non-Boolean variables are not formulas",form);
+ if(CounterExampleMap.find(form) != CounterExampleMap.end()) {
+ ASTNode counterexample_val = CounterExampleMap[form];
+ if(!VarSeenInTerm(form,counterexample_val)) {
+ output = ComputeFormulaUsingModel(counterexample_val);
+ }
+ else {
+ output = counterexample_val;
+ }
+ }
+ else
+ output = ASTFalse;
+ break;
+ case EQ:
+ case NEQ:
+ case BVLT:
+ case BVLE:
+ case BVGT:
+ case BVGE:
+ case BVSLT:
+ case BVSLE:
+ case BVSGT:
+ case BVSGE:
+ //convert form[0] into a constant term
+ t0 = TermToConstTermUsingModel(form[0],false);
+ //convert form[0] into a constant term
+ t1 = TermToConstTermUsingModel(form[1],false);
+ output = BVConstEvaluator(CreateNode(k,t0,t1));
+
+ //evaluate formula to false if bvdiv execption occurs while
+ //counterexample is being checked during refinement.
+ if(bvdiv_exception_occured &&
+ counterexample_checking_during_refinement) {
+ output = ASTFalse;
+ }
+ break;
+ case NAND: {
+ ASTNode o = ASTTrue;
+ for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++)
+ if(ASTFalse == ComputeFormulaUsingModel(*it)) {
+ o = ASTFalse;
+ break;
+ }
+ if(o == ASTTrue)
+ output = ASTFalse;
+ else
+ output = ASTTrue;
+ break;
+ }
+ case NOR: {
+ ASTNode o = ASTFalse;
+ for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++)
+ if(ASTTrue == ComputeFormulaUsingModel(*it)) {
+ o = ASTTrue;
+ break;
+ }
+ if(o == ASTTrue)
+ output = ASTFalse;
+ else
+ output = ASTTrue;
+ break;
+ }
+ case NOT:
+ if(ASTTrue == ComputeFormulaUsingModel(form[0]))
+ output = ASTFalse;
+ else
+ output = ASTTrue;
+ break;
+ case OR:
+ for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++)
+ if(ASTTrue == ComputeFormulaUsingModel(*it))
+ output = ASTTrue;
+ break;
+ case AND:
+ output = ASTTrue;
+ for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) {
+ if(ASTFalse == ComputeFormulaUsingModel(*it)) {
+ output = ASTFalse;
+ break;
+ }
+ }
+ break;
+ case XOR:
+ t0 = ComputeFormulaUsingModel(form[0]);
+ t1 = ComputeFormulaUsingModel(form[1]);
+ if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1))
+ output = ASTFalse;
+ else
+ output = ASTTrue;
+ break;
+ case IFF:
+ t0 = ComputeFormulaUsingModel(form[0]);
+ t1 = ComputeFormulaUsingModel(form[1]);
+ if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1))
+ output = ASTTrue;
+ else
+ output = ASTFalse;
+ break;
+ case IMPLIES:
+ t0 = ComputeFormulaUsingModel(form[0]);
+ t1 = ComputeFormulaUsingModel(form[1]);
+ if((ASTFalse == t0) || (ASTTrue == t0 && ASTTrue == t1))
+ output = ASTTrue;
+ else
+ output = ASTFalse;
+ break;
+ case ITE:
+ t0 = ComputeFormulaUsingModel(form[0]);
+ if(ASTTrue == t0)
+ output = ComputeFormulaUsingModel(form[1]);
+ else if(ASTFalse == t0)
+ output = ComputeFormulaUsingModel(form[2]);
+ else
+ FatalError("ComputeFormulaUsingModel: ITE: something is wrong with the formula: ",form);
+ break;
+ default:
+ FatalError(" ComputeFormulaUsingModel: the kind has not been implemented", ASTUndefined);
+ break;
+ }
+
+ //cout << "ComputeFormulaUsingModel output is:" << output << endl;
+ ComputeFormulaMap[form] = output;
+ return output;
+ }
+
+ void BeevMgr::CheckCounterExample(bool t) {
+ // FIXME: Code is more useful if enable flags are check OUTSIDE the method.
+ // If I want to check a counterexample somewhere, I don't want to have to set
+ // the flag in order to make it actualy happen!
+
+ if(!check_counterexample) {
+ return;
+ }
+
+ //input is valid, no counterexample to check
+ if(ValidFlag)
+ return;
+
+ //t is true if SAT solver generated a counterexample, else it is false
+ if(!t)
+ FatalError("CheckCounterExample: No CounterExample to check", ASTUndefined);
+ const ASTVec c = GetAsserts();
+ for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++)
+ if(ASTFalse == ComputeFormulaUsingModel(*it))
+ FatalError("CheckCounterExample:counterexample bogus:"\
+ "assert evaluates to FALSE under counterexample: NOT OK",*it);
+
+ if(ASTTrue == ComputeFormulaUsingModel(_current_query))
+ FatalError("CheckCounterExample:counterexample bogus:"\
+ "query evaluates to TRUE under counterexample: NOT OK",_current_query);
+ }
+
+ /* FUNCTION: prints a counterexample for INVALID inputs. iterate
+ * through the CounterExampleMap data structure and print it to
+ * stdout
+ */
+ void BeevMgr::PrintCounterExample(bool t, std::ostream& os) {
+ //global command-line option
+ // FIXME: This should always print the counterexample. If you want
+ // to turn it off, check the switch at the point of call.
+ if(!print_counterexample)
+ return;
+
+ //input is valid, no counterexample to print
+ if(ValidFlag)
+ return;
+
+ //if this option is true then print the way dawson wants using a
+ //different printer. do not use this printer.
+ if(print_arrayval_declaredorder)
+ return;
+
+ //t is true if SAT solver generated a counterexample, else it is
+ //false
+ if(!t) {
+ cerr << "PrintCounterExample: No CounterExample to print: " << endl;
+ return;
+ }
+
+ //os << "\nCOUNTEREXAMPLE: \n" << endl;
+ ASTNodeMap::iterator it = CounterExampleMap.begin();
+ ASTNodeMap::iterator itend = CounterExampleMap.end();
+ for(;it!=itend;it++) {
+ ASTNode f = it->first;
+ ASTNode se = it->second;
+
+ if(ARRAY_TYPE == se.GetType()) {
+ FatalError("TermToConstTermUsingModel: entry in counterexample is an arraytype. bogus:",se);
+ }
+
+ //skip over introduced variables
+ if(f.GetKind() == SYMBOL && (_introduced_symbols.find(f) != _introduced_symbols.end()))
+ continue;
+ if(f.GetKind() == SYMBOL ||
+ (f.GetKind() == READ && f[0].GetKind() == SYMBOL && f[1].GetKind() == BVCONST)) {
+ os << "ASSERT( ";
+ f.PL_Print(os,0);
+ os << " = ";
+ if(BITVECTOR_TYPE == se.GetType()) {
+ TermToConstTermUsingModel(se,false).PL_Print(os,0);
+ }
+ else {
+ se.PL_Print(os,0);
+ }
+ os << " );" << endl;
+ }
+ }
+ //os << "\nEND OF COUNTEREXAMPLE" << endl;
+ } //End of PrintCounterExample
+
+ /* iterate through the CounterExampleMap data structure and print it
+ * to stdout. this function prints only the declared array variables
+ * IN the ORDER in which they were declared. It also assumes that
+ * the variables are of the form 'varname_number'. otherwise it will
+ * not print anything. This function was specifically written for
+ * Dawson Engler's group (bug finding research group at Stanford)
+ */
+ void BeevMgr::PrintCounterExample_InOrder(bool t) {
+ //global command-line option to print counterexample. we do not
+ //want both counterexample printers to print at the sametime.
+ // FIXME: This should always print the counterexample. If you want
+ // to turn it off, check the switch at the point of call.
+ if(print_counterexample)
+ return;
+
+ //input is valid, no counterexample to print
+ if(ValidFlag)
+ return;
+
+ //print if the commandline option is '-q'. allows printing the
+ //counterexample in order.
+ if(!print_arrayval_declaredorder)
+ return;
+
+ //t is true if SAT solver generated a counterexample, else it is
+ //false
+ if(!t) {
+ cerr << "PrintCounterExample: No CounterExample to print: " << endl;
+ return;
+ }
+
+ //vector to store the integer values
+ std::vector<int> out_int;
+ cout << "% ";
+ for(ASTVec::iterator it=_special_print_set.begin(),itend=_special_print_set.end();
+ it!=itend;it++) {
+ if(ARRAY_TYPE == it->GetType()) {
+ //get the name of the variable
+ const char * c = it->GetName();
+ std::string ss(c);
+ if(!(0 == strncmp(ss.c_str(),"ini_",4)))
+ continue;
+ reverse(ss.begin(),ss.end());
+
+ //cout << "debugging: " << ss;
+ size_t pos = ss.find('_',0);
+ if(!(0 < pos && pos < ss.size()))
+ continue;
+
+ //get the associated length
+ std::string sss = ss.substr(0,pos);
+ reverse(sss.begin(),sss.end());
+ int n = atoi(sss.c_str());
+
+ it->PL_Print(cout,2);
+ for(int j=0;j < n; j++) {
+ ASTNode index = CreateBVConst(it->GetIndexWidth(),j);
+ ASTNode readexpr = CreateTerm(READ,it->GetValueWidth(),*it,index);
+ ASTNode val = GetCounterExample(t, readexpr);
+ //cout << "ASSERT( ";
+ //cout << " = ";
+ out_int.push_back(GetUnsignedConst(val));
+ //cout << "\n";
+ }
+ }
+ }
+ cout << endl;
+ for(unsigned int jj=0; jj < out_int.size();jj++)
+ cout << out_int[jj] << endl;
+ cout << endl;
+ } //End of PrintCounterExample_InOrder
+
+ /* FUNCTION: queries the CounterExampleMap object with 'expr' and
+ * returns the corresponding counterexample value.
+ */
+ ASTNode BeevMgr::GetCounterExample(bool t, const ASTNode& expr) {
+ //input is valid, no counterexample to get
+ if(ValidFlag)
+ return ASTUndefined;
+
+ if(BOOLEAN_TYPE == expr.GetType()) {
+ return ComputeFormulaUsingModel(expr);
+ }
+
+ if(BVCONST == expr.GetKind()) {
+ return expr;
+ }
+
+ ASTNodeMap::iterator it;
+ ASTNode output;
+ if((it = CounterExampleMap.find(expr)) != CounterExampleMap.end())
+ output = TermToConstTermUsingModel(CounterExampleMap[expr],false);
+ else
+ output = CreateZeroConst(expr.GetValueWidth());
+ return output;
+ } //End of GetCounterExample
+
+ // FIXME: Don't use numeric codes. Use an enum type!
+ //Acceps a query, calls the SAT solver and generates Valid/InValid.
+ //if returned 0 then input is INVALID
+ //if returned 1 then input is VALID
+ //if returned 2 then ERROR
+ int BeevMgr::TopLevelSAT( const ASTNode& inputasserts, const ASTNode& query) {
+ /******start solving**********/
+ ASTNode q = CreateNode(AND, inputasserts, CreateNode(NOT,query));
+ ASTNode orig_input = q;
+ ASTNodeStats("input asserts and query: ", q);
+
+ ASTNode newq = q;
+ //round of substitution, solving, and simplification. ensures that
+ //DAG is minimized as much as possibly, and ideally should
+ //garuntee that all liketerms in BVPLUSes have been combined.
+ BVSolver bvsolver(this);
+ SimplifyWrites_InPlace_Flag = false;
+ Begin_RemoveWrites = false;
+ start_abstracting = false;
+ TermsAlreadySeenMap.clear();
+ do {
+ q = newq;
+ newq = CreateSubstitutionMap(newq);
+ //ASTNodeStats("after pure substitution: ", newq);
+ newq = SimplifyFormula_TopLevel(newq,false);
+ //ASTNodeStats("after simplification: ", newq);
+ //newq = bvsolver.TopLevelBVSolve(newq);
+ //ASTNodeStats("after solving: ", newq);
+ }while(q!=newq);
+
+ ASTNodeStats("Before SimplifyWrites_Inplace begins: ", newq);
+ SimplifyWrites_InPlace_Flag = true;
+ Begin_RemoveWrites = false;
+ start_abstracting = false;
+ TermsAlreadySeenMap.clear();
+ do {
+ q = newq;
+ //newq = CreateSubstitutionMap(newq);
+ //ASTNodeStats("after pure substitution: ", newq);
+ newq = SimplifyFormula_TopLevel(newq,false);
+ //ASTNodeStats("after simplification: ", newq);
+ newq = bvsolver.TopLevelBVSolve(newq);
+ //ASTNodeStats("after solving: ", newq);
+ }while(q!=newq);
+ ASTNodeStats("After SimplifyWrites_Inplace: ", newq);
+
+ start_abstracting = (arraywrite_refinement) ? true : false;
+ SimplifyWrites_InPlace_Flag = false;
+ Begin_RemoveWrites = (start_abstracting) ? false : true;
+ if(start_abstracting) {
+ ASTNodeStats("before abstraction round begins: ", newq);
+ }
+
+ TermsAlreadySeenMap.clear();
+ do {
+ q = newq;
+ //newq = CreateSubstitutionMap(newq);
+ //Begin_RemoveWrites = true;
+ //ASTNodeStats("after pure substitution: ", newq);
+ newq = SimplifyFormula_TopLevel(newq,false);
+ //ASTNodeStats("after simplification: ", newq);
+ //newq = bvsolver.TopLevelBVSolve(newq);
+ //ASTNodeStats("after solving: ", newq);
+ }while(q!=newq);
+
+ if(start_abstracting) {
+ ASTNodeStats("After abstraction: ", newq);
+ }
+ start_abstracting = false;
+ SimplifyWrites_InPlace_Flag = false;
+ Begin_RemoveWrites = false;
+
+ newq = TransformFormula(newq);
+ ASTNodeStats("after transformation: ", newq);
+ TermsAlreadySeenMap.clear();
+
+ int res;
+ //solver instantiated here
+ MINISAT::Solver newS;
+ if(arrayread_refinement) {
+ counterexample_checking_during_refinement = true;
+ }
+
+ //call SAT and check the result
+ res = CallSAT_ResultCheck(newS,newq,orig_input);
+ if(2 != res) {
+ CountersAndStats("print_func_stats");
+ return res;
+ }
+
+ res = SATBased_ArrayReadRefinement(newS,newq,orig_input);
+ if(2 != res) {
+ CountersAndStats("print_func_stats");
+ return res;
+ }
+
+ res = SATBased_ArrayWriteRefinement(newS,orig_input);
+ if(2 != res) {
+ CountersAndStats("print_func_stats");
+ return res;
+ }
+
+ res = SATBased_ArrayReadRefinement(newS,newq,orig_input);
+ if(2 != res) {
+ CountersAndStats("print_func_stats");
+ return res;
+ }
+
+ FatalError("TopLevelSAT: reached the end without proper conclusion:"
+ "either a divide by zero in the input or a bug in STP");
+ //bogus return to make the compiler shut up
+ return 2;
+ } //End of TopLevelSAT
+
+ //go over the list of indices for each array, and generate Leibnitz
+ //axioms. Then assert these axioms into the SAT solver. Check if the
+ //addition of the new constraints has made the bogus counterexample
+ //go away. if yes, return the correct answer. if no, continue adding
+ //Leibnitz axioms systematically.
+ // FIXME: What it really does is, for each array, loop over each index i.
+ // inside that loop, it finds all the true and false axioms with i as first
+ // index. When it's got them all, it adds the false axioms to the formula
+ // and re-solves, and returns if the result is correct. Otherwise, it
+ // goes on to the next index.
+ // If it gets through all the indices without a correct result (which I think
+ // is impossible, but this is pretty confusing), it then solves with all
+ // the true axioms, too.
+ // This is not the most obvious way to do it, and I don't know how it
+ // compares with other approaches (e.g., one false axiom at a time or
+ // all the false axioms each time).
+ int BeevMgr::SATBased_ArrayReadRefinement(MINISAT::Solver& newS,
+ const ASTNode& q, const ASTNode& orig_input) {
+ if(!arrayread_refinement)
+ FatalError("SATBased_ArrayReadRefinement: Control should not reach here");
+
+ ASTVec FalseAxiomsVec, RemainingAxiomsVec;
+ RemainingAxiomsVec.push_back(ASTTrue);
+ FalseAxiomsVec.push_back(ASTTrue);
+
+ //in these loops we try to construct Leibnitz axioms and add it to
+ //the solve(). We add only those axioms that are false in the
+ //current counterexample. we keep adding the axioms until there
+ //are no more axioms to add
+ //
+ //for each array, fetch its list of indices seen so far
+ for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end();
+ iset!=iset_end;iset++) {
+ ASTVec listOfIndices = iset->second;
+ //loop over the list of indices for the array and create LA, and add to q
+ for(ASTVec::iterator it=listOfIndices.begin(),itend=listOfIndices.end();it!=itend;it++) {
+ if(BVCONST == it->GetKind()) {
+ continue;
+ }
+
+ ASTNode the_index = *it;
+ //get the arrayname
+ ASTNode ArrName = iset->first;
+ // if(SYMBOL != ArrName.GetKind())
+ // FatalError("SATBased_ArrayReadRefinement: arrname is not a SYMBOL",ArrName);
+ ASTNode arr_read1 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, the_index);
+ //get the variable corresponding to the array_read1
+ ASTNode arrsym1 = _arrayread_symbol[arr_read1];
+ if(!(SYMBOL == arrsym1.GetKind() || BVCONST == arrsym1.GetKind()))
+ FatalError("TopLevelSAT: refinementloop:term arrsym1 corresponding to READ must be a var", arrsym1);
+
+ //we have nonconst index here. create Leibnitz axiom for it
+ //w.r.t every index in listOfIndices
+ for(ASTVec::iterator it1=listOfIndices.begin(),itend1=listOfIndices.end();
+ it1!=itend1;it1++) {
+ ASTNode compare_index = *it1;
+ //do not compare with yourself
+ if(the_index == compare_index)
+ continue;
+
+ //prepare for SAT LOOP
+ //first construct the antecedent for the LA axiom
+ ASTNode eqOfIndices =
+ (exprless(the_index,compare_index)) ?
+ CreateSimplifiedEQ(the_index,compare_index) : CreateSimplifiedEQ(compare_index,the_index);
+
+ ASTNode arr_read2 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, compare_index);
+ //get the variable corresponding to the array_read2
+ ASTNode arrsym2 = _arrayread_symbol[arr_read2];
+ if(!(SYMBOL == arrsym2.GetKind() || BVCONST == arrsym2.GetKind()))
+ FatalError("TopLevelSAT: refinement loop:"
+ "term arrsym2 corresponding to READ must be a var", arrsym2);
+
+ ASTNode eqOfReads = CreateSimplifiedEQ(arrsym1,arrsym2);
+ //construct appropriate Leibnitz axiom
+ ASTNode LeibnitzAxiom = CreateNode(IMPLIES, eqOfIndices, eqOfReads);
+ if(ASTFalse == ComputeFormulaUsingModel(LeibnitzAxiom))
+ //FalseAxioms = CreateNode(AND,FalseAxioms,LeibnitzAxiom);
+ FalseAxiomsVec.push_back(LeibnitzAxiom);
+ else
+ //RemainingAxioms = CreateNode(AND,RemainingAxioms,LeibnitzAxiom);
+ RemainingAxiomsVec.push_back(LeibnitzAxiom);
+ }
+ ASTNode FalseAxioms = (FalseAxiomsVec.size()>1) ? CreateNode(AND,FalseAxiomsVec) : FalseAxiomsVec[0];
+ ASTNodeStats("adding false readaxioms to SAT: ", FalseAxioms);
+ int res2 = CallSAT_ResultCheck(newS,FalseAxioms,orig_input);
+ if(2!=res2) {
+ return res2;
+ }
+ }
+ }
+ ASTNode RemainingAxioms = (RemainingAxiomsVec.size()>1) ? CreateNode(AND,RemainingAxiomsVec):RemainingAxiomsVec[0];
+ ASTNodeStats("adding remaining readaxioms to SAT: ", RemainingAxioms);
+ return CallSAT_ResultCheck(newS,RemainingAxioms,orig_input);
+ } //end of SATBased_ArrayReadRefinement
+
+ ASTNode BeevMgr::Create_ArrayWriteAxioms(const ASTNode& term, const ASTNode& newvar) {
+ if(READ != term.GetKind() && WRITE != term[0].GetKind()) {
+ FatalError("Create_ArrayWriteAxioms: Input must be a READ over a WRITE",term);
+ }
+
+ ASTNode lhs = newvar;
+ ASTNode rhs = term;
+ ASTNode arraywrite_axiom = CreateSimplifiedEQ(lhs,rhs);
+ return arraywrite_axiom;
+ }//end of Create_ArrayWriteAxioms()
+
+ int BeevMgr::SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input) {
+ ASTNode writeAxiom;
+ ASTNodeMap::iterator it = ReadOverWrite_NewName_Map.begin();
+ ASTNodeMap::iterator itend = ReadOverWrite_NewName_Map.end();
+ //int count = 0;
+ //int num_write_axioms = ReadOverWrite_NewName_Map.size();
+
+ ASTVec FalseAxioms, RemainingAxioms;
+ FalseAxioms.push_back(ASTTrue);
+ RemainingAxioms.push_back(ASTTrue);
+ for(;it!=itend;it++) {
+ //Guided refinement starts here
+ ComputeFormulaMap.clear();
+ writeAxiom = Create_ArrayWriteAxioms(it->first,it->second);
+ if(ASTFalse == ComputeFormulaUsingModel(writeAxiom)) {
+ writeAxiom = TransformFormula(writeAxiom);
+ FalseAxioms.push_back(writeAxiom);
+ }
+ else {
+ writeAxiom = TransformFormula(writeAxiom);
+ RemainingAxioms.push_back(writeAxiom);
+ }
+ }
+
+ writeAxiom = (FalseAxioms.size() != 1) ? CreateNode(AND,FalseAxioms) : FalseAxioms[0];
+ ASTNodeStats("adding false writeaxiom to SAT: ", writeAxiom);
+ int res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input);
+ if(2!=res2) {
+ return res2;
+ }
+
+ writeAxiom = (RemainingAxioms.size() != 1) ? CreateNode(AND,RemainingAxioms) : RemainingAxioms[0];
+ ASTNodeStats("adding remaining writeaxiom to SAT: ", writeAxiom);
+ res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input);
+ if(2!=res2) {
+ return res2;
+ }
+
+ return 2;
+ } //end of SATBased_ArrayWriteRefinement
+
+ //Check result after calling SAT FIXME: Document arguments in
+ //comments, and give them meaningful names. How is anyone supposed
+ //to know what "q" is?
+ int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS,
+ const ASTNode& q, const ASTNode& orig_input) {
+ //Bitblast, CNF, call SAT now
+ ASTNode BBFormula = BBForm(q);
+ //ASTNodeStats("after bitblasting", BBFormula);
+ ClauseList *cllp = ToCNF(BBFormula);
+ // if(stats && print_nodes) {
+ // cout << "\nClause list" << endl;
+ // PrintClauseList(cout, *cllp);
+ // cerr << "\n finished printing clauselist\n";
+ // }
+
+ bool sat = toSATandSolve(newS,*cllp);
+ // Temporary debugging call.
+ // CheckBBandCNF(newS, BBFormula);
+
+ DeleteClauseList(cllp);
+ if(!sat) {
+ PrintOutput(true);
+ return 1;
+ }
+ else if(newS.okay()) {
+ CounterExampleMap.clear();
+ ConstructCounterExample(newS);
+ if (stats && print_nodes) {
+ PrintSATModel(newS);
+ }
+ //check if the counterexample is good or not
+ ComputeFormulaMap.clear();
+ if(counterexample_checking_during_refinement)
+ bvdiv_exception_occured = false;
+ ASTNode orig_result = ComputeFormulaUsingModel(orig_input);
+ if(!(ASTTrue == orig_result || ASTFalse == orig_result))
+ FatalError("TopLevelSat: Original input must compute to true or false against model");
+
+// if(!arrayread_refinement && !(ASTTrue == orig_result)) {
+// print_counterexample = true;
+// PrintCounterExample(true);
+// FatalError("counterexample bogus : arrayread_refinement is switched off: "
+// "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()"
+// "or satsolver() or counterexamplechecker() have a bug");
+// }
+
+ // if the counterexample is indeed a good one, then return
+ // invalid
+ if(ASTTrue == orig_result) {
+ CheckCounterExample(newS.okay());
+ PrintOutput(false);
+ PrintCounterExample(newS.okay());
+ PrintCounterExample_InOrder(newS.okay());
+ return 0;
+ }
+ // counterexample is bogus: flag it
+ else {
+ if(stats && print_nodes) {
+ cout << "Supposedly bogus one: \n";
+ bool tmp = print_counterexample;
+ print_counterexample = true;
+ PrintCounterExample(true);
+ print_counterexample = tmp;
+ }
+
+ return 2;
+ }
+ }
+ else {
+ PrintOutput(true);
+ return -100;
+ }
+ } //end of CALLSAT_ResultCheck
+
+
+ //FUNCTION: this function accepts a boolvector and returns a BVConst
+ ASTNode BeevMgr::BoolVectoBVConst(hash_map<unsigned,bool> * w, unsigned int l) {
+ unsigned len = w->size();
+ if(l < len)
+ FatalError("BoolVectorBVConst : length of bitvector does not match hash_map size:",ASTUndefined,l);
+ std::string cc;
+ for(unsigned int jj = 0; jj < l; jj++) {
+ if((*w)[jj] == true)
+ cc += '1';
+ else if((*w)[jj] == false)
+ cc += '0';
+ else
+ cc += '0';
+ }
+ return CreateBVConst(cc.c_str(),2);
+ }
+
+ void BeevMgr::PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS) {
+ if(!print_sat_varorder)
+ return;
+
+ ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin();
+ ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end();
+
+ cout << init_msg;
+ cout << ": Printing activity levels of variables\n";
+ for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){
+ cout << (it->second) << " : ";
+ (it->first).PL_Print(cout,0);
+ cout << " : ";
+ cout << newS.returnActivity(it->second) << endl;
+ }
+ }
+
+ //this function biases the activity levels of MINISAT variables.
+ void BeevMgr::ChangeActivityLevels_Of_SATVars(MINISAT::Solver& newS) {
+ if(!variable_activity_optimize)
+ return;
+
+ ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin();
+ ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end();
+
+ unsigned int index=1;
+ double base = 2;
+ for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){
+ ASTNode n = it->first;
+
+ if(BVGETBIT == n.GetKind() || NOT == n.GetKind()) {
+ if(BVGETBIT == n.GetKind())
+ index = GetUnsignedConst(n[1]);
+ else if (NOT == n.GetKind() && BVGETBIT == n[0].GetKind())
+ index = GetUnsignedConst(n[0][1]);
+ else
+ index = 0;
+ double initial_activity = pow(base,(double)index);
+ newS.updateInitialActivity(it->second,initial_activity);
+ }
+ else {
+ double initial_activity = pow(base,pow(base,(double)index));
+ newS.updateInitialActivity(it->second,initial_activity);
+ }
+ }
+ }
+
+ //This function prints the output of the STP solver
+ void BeevMgr::PrintOutput(bool true_iff_valid) {
+ //self-explanatory
+ if(true_iff_valid) {
+ ValidFlag = true;
+ if(print_output) {
+ if(smtlib_parser_enable)
+ cout << "unsat\n";
+ else
+ cout << "Valid.\n";
+ }
+ }
+ else {
+ ValidFlag = false;
+ if(print_output) {
+ if(smtlib_parser_enable)
+ cout << "sat\n";
+ else
+ cout << "Invalid.\n";
+ }
+ }
+ }
+}; //end of namespace BEEV
Added: klee/trunk/stp/AST/Transform.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/Transform.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/Transform.cpp (added)
+++ klee/trunk/stp/AST/Transform.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,492 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+#include "AST.h"
+#include <stdlib.h>
+#include <stdio.h>
+namespace BEEV {
+
+ //Translates signed BVDIV/BVMOD into unsigned variety
+ ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) {
+ if(!(SBVMOD == in.GetKind() || SBVDIV == in.GetKind())) {
+ FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n",in);
+ }
+
+ ASTNode dividend = in[0];
+ ASTNode divisor = in[1];
+ unsigned len = in.GetValueWidth();
+ if(SBVMOD == in.GetKind()) {
+ //if(TopBit(dividend)==1)
+ //
+ //then -BVMOD(-dividend,abs(divisor))
+ //
+ //else BVMOD(dividend,abs(divisor))
+
+ //create the condition for the dividend
+ ASTNode hi1 = CreateBVConst(32,len-1);
+ ASTNode one = CreateOneConst(1);
+ ASTNode cond = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1));
+
+ //create the condition and conditional for the divisor
+ ASTNode cond_divisor = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1));
+ ASTNode pos_divisor = CreateTerm(ITE,len,cond_divisor,CreateTerm(BVUMINUS,len,divisor),divisor);
+
+ //create the modulus term for each case
+ ASTNode modnode = CreateTerm(BVMOD,len,dividend,pos_divisor);
+ ASTNode minus_modnode = CreateTerm(BVMOD,len,CreateTerm(BVUMINUS,len,dividend),pos_divisor);
+ minus_modnode = CreateTerm(BVUMINUS,len,minus_modnode);
+
+ //put everything together, simplify, and return
+ ASTNode n = CreateTerm(ITE,len,cond,minus_modnode,modnode);
+ return SimplifyTerm_TopLevel(n);
+ }
+
+ //now handle the BVDIV case
+ //if topBit(dividend) is 1 and topBit(divisor) is 0
+ //
+ //then output is -BVDIV(-dividend,divisor)
+ //
+ //elseif topBit(dividend) is 0 and topBit(divisor) is 1
+ //
+ //then output is -BVDIV(dividend,-divisor)
+ //
+ //elseif topBit(dividend) is 1 and topBit(divisor) is 1
+ //
+ // then output is BVDIV(-dividend,-divisor)
+ //
+ //else simply output BVDIV(dividend,divisor)
+ ASTNode hi1 = CreateBVConst(32,len-1);
+ ASTNode zero = CreateZeroConst(1);
+ ASTNode one = CreateOneConst(1);
+ ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor);
+
+ ASTNode cond1 = CreateNode(AND,
+ CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)),
+ CreateNode(EQ,one, CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)));
+ ASTNode minus_divnode1 = CreateTerm(BVDIV,len,
+ dividend,
+ CreateTerm(BVUMINUS,len,divisor));
+ minus_divnode1 = CreateTerm(BVUMINUS,len,minus_divnode1);
+
+ ASTNode cond2 = CreateNode(AND,
+ CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)),
+ CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)));
+ ASTNode minus_divnode2 = CreateTerm(BVDIV,len,
+ CreateTerm(BVUMINUS,len,dividend),
+ divisor);
+ minus_divnode2 = CreateTerm(BVUMINUS,len,minus_divnode2);
+
+ ASTNode cond3 = CreateNode(AND,
+ CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)),
+ CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)));
+ ASTNode minus_divnode3 = CreateTerm(BVDIV,len,
+ CreateTerm(BVUMINUS,len,dividend),
+ CreateTerm(BVUMINUS,len,divisor));
+ ASTNode n = CreateTerm(ITE,len,
+ cond1,
+ minus_divnode1,
+ CreateTerm(ITE,len,
+ cond2,
+ minus_divnode2,
+ CreateTerm(ITE,len,
+ cond3,
+ minus_divnode3,
+ divnode)));
+ return SimplifyTerm_TopLevel(n);
+ }//end of TranslateSignedDivMod()
+
+ ASTNode BeevMgr::TransformFormula(const ASTNode& form) {
+ ASTNode result;
+
+ ASTNode simpleForm = form;
+ Kind k = simpleForm.GetKind();
+ if(!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType())) {
+ //FIXME: "You have inputted a NON-formula"?
+ FatalError("TransformFormula: You have input a NON-formula",simpleForm);
+ }
+
+ ASTNodeMap::iterator iter;
+ if((iter = TransformMap.find(simpleForm)) != TransformMap.end())
+ return iter->second;
+
+ switch(k) {
+ case TRUE:
+ case FALSE: {
+ result = simpleForm;
+ break;
+ }
+ case NOT: {
+ ASTVec c;
+ c.push_back(TransformFormula(simpleForm[0]));
+ result = CreateNode(NOT,c);
+ break;
+ }
+ case BVLT:
+ case BVLE:
+ case BVGT:
+ case BVGE:
+ case BVSLT:
+ case BVSLE:
+ case BVSGT:
+ case BVSGE:
+ case NEQ: {
+ ASTVec c;
+ c.push_back(TransformTerm(simpleForm[0]));
+ c.push_back(TransformTerm(simpleForm[1]));
+ result = CreateNode(k,c);
+ break;
+ }
+ case EQ: {
+ ASTNode term1 = TransformTerm(simpleForm[0]);
+ ASTNode term2 = TransformTerm(simpleForm[1]);
+ result = CreateSimplifiedEQ(term1,term2);
+ break;
+ }
+ case AND:
+ case OR:
+ case NAND:
+ case NOR:
+ case IFF:
+ case XOR:
+ case ITE:
+ case IMPLIES: {
+ ASTVec vec;
+ ASTNode o;
+ for (ASTVec::const_iterator it = simpleForm.begin(),itend=simpleForm.end(); it != itend; it++){
+ o = TransformFormula(*it);
+ vec.push_back(o);
+ }
+
+ result = CreateNode(k, vec);
+ break;
+ }
+ default:
+ if(k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType())
+ result = simpleForm;
+ else {
+ cerr << "The input is: " << simpleForm << endl;
+ cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << endl;
+ FatalError("TransformFormula: Illegal kind: ",ASTUndefined, k);
+ }
+ break;
+ }
+ //BVTypeCheck(result);
+ TransformMap[simpleForm] = result;
+ return result;
+ } //End of TransformFormula
+
+ ASTNode BeevMgr::TransformTerm(const ASTNode& inputterm) {
+ ASTNode result;
+ ASTNode term = inputterm;
+
+ Kind k = term.GetKind();
+ if(!is_Term_kind(k))
+ FatalError("TransformTerm: Illegal kind: You have input a nonterm:", inputterm, k);
+ ASTNodeMap::iterator iter;
+ if((iter = TransformMap.find(term)) != TransformMap.end())
+ return iter->second;
+ switch(k) {
+ case SYMBOL: {
+ // ASTNodeMap::iterator itsym;
+// if((itsym = CounterExampleMap.find(term)) != CounterExampleMap.end())
+// result = itsym->second;
+// else
+ result = term;
+ break;
+ }
+ case BVCONST:
+ result = term;
+ break;
+ case WRITE:
+ FatalError("TransformTerm: this kind is not supported",term);
+ break;
+ case READ:
+ result = TransformArray(term);
+ break;
+ case ITE: {
+ ASTNode cond = term[0];
+ ASTNode thn = term[1];
+ ASTNode els = term[2];
+ cond = TransformFormula(cond);
+ thn = TransformTerm(thn);
+ els = TransformTerm(els);
+ //result = CreateTerm(ITE,term.GetValueWidth(),cond,thn,els);
+ result = CreateSimplifiedTermITE(cond,thn,els);
+ result.SetIndexWidth(term.GetIndexWidth());
+ break;
+ }
+ default: {
+ ASTVec c = term.GetChildren();
+ ASTVec::iterator it = c.begin();
+ ASTVec::iterator itend = c.end();
+ unsigned width = term.GetValueWidth();
+ unsigned indexwidth = term.GetIndexWidth();
+ ASTVec o;
+ for(;it!=itend;it++) {
+ o.push_back(TransformTerm(*it));
+ }
+
+ result = CreateTerm(k,width,o);
+ result.SetIndexWidth(indexwidth);
+
+ if(SBVDIV == result.GetKind() || SBVMOD == result.GetKind()) {
+ result = TranslateSignedDivMod(result);
+ }
+ break;
+ }
+ }
+
+ TransformMap[term] = result;
+ if(term.GetValueWidth() != result.GetValueWidth())
+ FatalError("TransformTerm: result and input terms are of different length", result);
+ if(term.GetIndexWidth() != result.GetIndexWidth()) {
+ cerr << "TransformTerm: input term is : " << term << endl;
+ FatalError("TransformTerm: result and input terms have different index length", result);
+ }
+ return result;
+ } //End of TransformTerm
+
+ /* This function transforms Array Reads, Read over Writes, Read over
+ * ITEs into flattened form.
+ *
+ * Transform1: Suppose there are two array reads in the input
+ * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is
+ * replaced with a symbolic constant, say v1, and Read(A,j) is
+ * replaced with the following ITE:
+ *
+ * ITE(i=j,v1,v2)
+ *
+ * Transform2:
+ *
+ * Transform3:
+ */
+ ASTNode BeevMgr::TransformArray(const ASTNode& term) {
+ ASTNode result = term;
+
+ unsigned int width = term.GetValueWidth();
+ Kind k = term.GetKind();
+ if (!is_Term_kind(k))
+ FatalError("TransformArray: Illegal kind: You have input a nonterm:", ASTUndefined, k);
+ ASTNodeMap::iterator iter;
+ if((iter = TransformMap.find(term)) != TransformMap.end())
+ return iter->second;
+
+ switch(k) {
+ //'term' is of the form READ(arrName, readIndex)
+ case READ: {
+ ASTNode arrName = term[0];
+ switch (arrName.GetKind()) {
+ case SYMBOL: {
+ /* input is of the form: READ(A, readIndex)
+ *
+ * output is of the from: A1, if this is the first READ over A
+ *
+ * ITE(previous_readIndex=readIndex,A1,A2)
+ *
+ * .....
+ */
+
+ // Recursively transform read index, which may also contain reads.
+ ASTNode readIndex = TransformTerm(term[1]);
+ ASTNode processedTerm = CreateTerm(READ,width,arrName,readIndex);
+
+ //check if the 'processedTerm' has a corresponding ITE construct
+ //already. if so, return it. else continue processing.
+ ASTNodeMap::iterator it;
+ if((it = _arrayread_ite.find(processedTerm)) != _arrayread_ite.end()) {
+ result = it->second;
+ break;
+ }
+ //Constructing Symbolic variable corresponding to 'processedTerm'
+ ASTNode CurrentSymbol;
+ ASTNodeMap::iterator it1;
+ // First, check if read index is constant and it has a constant value in the substitution map.
+ if(CheckSubstitutionMap(processedTerm,CurrentSymbol)) {
+ _arrayread_symbol[processedTerm] = CurrentSymbol;
+ }
+ // Check if it already has an abstract variable.
+ else if((it1 = _arrayread_symbol.find(processedTerm)) != _arrayread_symbol.end()) {
+ CurrentSymbol = it1->second;
+ }
+ else {
+ // Make up a new abstract variable.
+ // FIXME: Make this into a method (there already may BE a method) and
+ // get rid of the fixed-length buffer!
+ //build symbolic name corresponding to array read. The symbolic
+ //name has 2 components: stringname, and a count
+ const char * b = arrName.GetName();
+ std::string c(b);
+ char d[32];
+ sprintf(d,"%d",_symbol_count++);
+ std::string ccc(d);
+ c += "array_" + ccc;
+
+ CurrentSymbol = CreateSymbol(c.c_str());
+ CurrentSymbol.SetValueWidth(processedTerm.GetValueWidth());
+ CurrentSymbol.SetIndexWidth(processedTerm.GetIndexWidth());
+ _arrayread_symbol[processedTerm] = CurrentSymbol;
+ }
+
+ //list of array-read indices corresponding to arrName, seen while
+ //traversing the AST tree. we need this list to construct the ITEs
+ // Dill: we hope to make this irrelevant. Harmless for now.
+ ASTVec readIndices = _arrayname_readindices[arrName];
+
+ //construct the ITE structure for this array-read
+ ASTNode ite = CurrentSymbol;
+ _introduced_symbols.insert(CurrentSymbol);
+ BVTypeCheck(ite);
+
+ if(arrayread_refinement) {
+ // ite is really a variable here; it is an ite in the
+ // else-branch
+ result = ite;
+ }
+ else {
+ // Full Seshia transform if we're not doing read refinement.
+ //do not loop if the current readIndex is a BVCONST
+ // if(BVCONST == term[1].GetKind() && !SeenNonConstReadIndex && optimize) {
+ // result = ite;
+ // }
+ // else {
+ //else part: SET the SeenNonConstReadIndex var, and do the hard work
+ //SeenNonConstReadIndex = true;
+ ASTVec::reverse_iterator it2=readIndices.rbegin();
+ ASTVec::reverse_iterator it2end=readIndices.rend();
+ for(;it2!=it2end;it2++) {
+ ASTNode cond = CreateSimplifiedEQ(readIndex,*it2);
+ if(ASTFalse == cond)
+ continue;
+
+ ASTNode arrRead = CreateTerm(READ,width,arrName,*it2);
+ //Good idea to TypeCheck internally constructed nodes
+ BVTypeCheck(arrRead);
+
+ ASTNode arrayreadSymbol = _arrayread_symbol[arrRead];
+ if(arrayreadSymbol.IsNull())
+ FatalError("TransformArray:symbolic variable for processedTerm, p,"
+ "does not exist:p = ",arrRead);
+ ite = CreateSimplifiedTermITE(cond,arrayreadSymbol,ite);
+ }
+ result = ite;
+ //}
+ }
+
+ _arrayname_readindices[arrName].push_back(readIndex);
+ //save the ite corresponding to 'processedTerm'
+ _arrayread_ite[processedTerm] = result;
+ break;
+ } //end of READ over a SYMBOL
+ case WRITE:{
+ /* The input to this case is: READ((WRITE A i val) j)
+ *
+ * The output of this case is: ITE( (= i j) val (READ A i))
+ */
+
+ /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression
+ *
+ * 2. term[1] is the read-index j
+ *
+ * 3. arrName[0] is the new arrName i.e. A. A can be either a
+ SYMBOL or a nested WRITE. no other possibility
+ *
+ * 4. arrName[1] is the WRITE index i.e. i
+ *
+ * 5. arrName[2] is the WRITE value i.e. val (val can inturn
+ * be an array read)
+ */
+ ASTNode readIndex = TransformTerm(term[1]);
+ ASTNode writeIndex = TransformTerm(arrName[1]);
+ ASTNode writeVal = TransformTerm(arrName[2]);
+
+ if(!(SYMBOL == arrName[0].GetKind() ||
+ WRITE == arrName[0].GetKind()))
+ FatalError("TransformArray: An array write is being attempted on a non-array:",term);
+ if(ARRAY_TYPE != arrName[0].GetType())
+ FatalError("TransformArray: An array write is being attempted on a non-array:",term);
+
+ ASTNode cond = CreateSimplifiedEQ(writeIndex,readIndex);
+ //TypeCheck internally created node
+ BVTypeCheck(cond);
+ ASTNode readTerm = CreateTerm(READ,width,arrName[0],readIndex);
+ //TypeCheck internally created node
+ BVTypeCheck(readTerm);
+ ASTNode readPushedIn = TransformArray(readTerm);
+ //TypeCheck internally created node
+ BVTypeCheck(readPushedIn);
+ //result = CreateTerm(ITE, arrName[0].GetValueWidth(),cond,writeVal,readPushedIn);
+ result = CreateSimplifiedTermITE(cond,writeVal,readPushedIn);
+
+ //Good idea to typecheck terms created inside the system
+ BVTypeCheck(result);
+ break;
+ } //end of READ over a WRITE
+ case ITE: {
+ /* READ((ITE cond thn els) j)
+ *
+ * is transformed into
+ *
+ * (ITE cond (READ thn j) (READ els j))
+ */
+
+ //(ITE cond thn els)
+ ASTNode term0 = term[0];
+ //READINDEX j
+ ASTNode j = TransformTerm(term[1]);
+
+ ASTNode cond = term0[0];
+ //first array
+ ASTNode t01 = term0[1];
+ //second array
+ ASTNode t02 = term0[2];
+
+ cond = TransformFormula(cond);
+ ASTNode thn = TransformTerm(t01);
+ ASTNode els = TransformTerm(t02);
+
+ if(!(t01.GetValueWidth() == t02.GetValueWidth() &&
+ t01.GetValueWidth() == thn.GetValueWidth() &&
+ t01.GetValueWidth() == els.GetValueWidth()))
+ FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term);
+
+ if(!(t01.GetIndexWidth() == t02.GetIndexWidth() &&
+ t01.GetIndexWidth() == thn.GetIndexWidth() &&
+ t01.GetIndexWidth() == els.GetIndexWidth()))
+ FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term);
+
+ //(READ thn j)
+ ASTNode thnRead = CreateTerm(READ,width,thn,j);
+ BVTypeCheck(thnRead);
+ thnRead = TransformArray(thnRead);
+
+ //(READ els j)
+ ASTNode elsRead = CreateTerm(READ,width,els,j);
+ BVTypeCheck(elsRead);
+ elsRead = TransformArray(elsRead);
+
+ //(ITE cond (READ thn j) (READ els j))
+ result = CreateSimplifiedTermITE(cond,thnRead,elsRead);
+ BVTypeCheck(result);
+ break;
+ }
+ default:
+ FatalError("TransformArray: The READ is NOT over SYMBOL/WRITE/ITE",term);
+ break;
+ }
+ break;
+ } //end of READ switch
+ default:
+ FatalError("TransformArray: input term is of wrong kind: ",ASTUndefined);
+ break;
+ }
+
+ TransformMap[term] = result;
+ return result;
+ } //end of TransformArray()
+} //end of namespace BEEV
Added: klee/trunk/stp/AST/asttest.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/asttest.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/asttest.cpp (added)
+++ klee/trunk/stp/AST/asttest.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,29 @@
+#include "AST.h"
+
+using namespace BEEV;
+
+int main()
+{
+
+ BeevMgr * bm = new BeevMgr();
+ ASTNode s1 = bm->CreateSymbol("foo");
+ s1 = bm->CreateSymbol("foo1");
+ s1 = bm->CreateSymbol("foo2");
+ ASTNode s2 = bm->CreateSymbol("bar");
+ cout << "s1" << s1 << endl;
+ cout << "s2" << s2 << endl;
+
+ ASTNode b1 = bm->CreateBVConst(5,12);
+ ASTNode b2 = bm->CreateBVConst(6,36);
+ cout << "b1: " << b1 << endl;
+ cout << "b2: " << b2 << endl;
+
+ ASTNode a1 = bm->CreateNode(EQ, s1, s2);
+ ASTNode a2 = bm->CreateNode(AND, s1, s2);
+ a1 = bm->CreateNode(OR, s1, s2);
+ ASTNode a3 = bm->CreateNode(IMPLIES, a1, a2);
+ ASTNode a4 = bm->CreateNode(IMPLIES, s1, a2);
+ cout << "a3" << a3 << endl;
+ cout << "a4" << a4 << endl;
+ return 0;
+}
Added: klee/trunk/stp/AST/bbtest.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/bbtest.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/bbtest.cpp (added)
+++ klee/trunk/stp/AST/bbtest.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,96 @@
+#include "AST.h"
+
+using namespace BEEV;
+
+int main()
+{
+ const int size = 32;
+
+ BeevMgr *bm = new BeevMgr();
+ ASTNode s1 = bm->CreateSymbol("x");
+ s1.SetValueWidth(size);
+ cout << "s1" << s1 << endl;
+ ASTNode s2 = bm->CreateSymbol("y");
+ s2.SetValueWidth(size);
+ cout << "s2" << s2 << endl;
+ ASTNode s3 = bm->CreateSymbol("z");
+ s3.SetValueWidth(size);
+ cout << "s3" << s3 << endl;
+
+ ASTNode c1 = bm->CreateBVConst(size,0);
+ cout << "c1" << c1 << endl;
+ ASTVec bbc1 = bm->BBTerm(c1);
+ cout << "bitblasted c1 " << endl;
+ LispPrintVec(cout, bbc1, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode c2 = bm->CreateBVConst(size,1);
+ c2.SetValueWidth(size);
+ cout << "c2" << c2 << endl;
+ ASTVec bbc2 = bm->BBTerm(c2);
+ cout << "bitblasted c2 " << endl;
+ LispPrintVec(cout, bbc2, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode c3 = bm->CreateBVConst(size, 0xFFFFFFFF);
+ c3.SetValueWidth(size);
+ cout << "c3" << c3 << endl;
+ ASTVec bbc3 = bm->BBTerm(c3);
+ cout << "bitblasted c3 " << endl;
+ LispPrintVec(cout, bbc3, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode c4 = bm->CreateBVConst(size, 0xAAAAAAAA);
+ c4.SetValueWidth(size);
+ cout << "c4" << c4 << endl;
+ ASTVec bbc4 = bm->BBTerm(c4);
+ cout << "bitblasted c4 " << endl;
+ LispPrintVec(cout, bbc4, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+// ASTNode b1 = bm->CreateBVConst(12);
+// ASTNode b2 = bm->CreateBVConst(36);
+// cout << "b1: " << b1 << endl;
+// cout << "b2: " << b2 << endl;
+
+ ASTNode a1 = bm->CreateNode(BVPLUS, s1, s2);
+ a1.SetValueWidth(size);
+
+ ASTVec& bba1 = bm->BBTerm(a1);
+ cout << "bitblasted a1 " << endl;
+ LispPrintVec(cout, bba1, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode a2 = bm->CreateNode(BVPLUS, s1, s2, s3);
+ a1.SetValueWidth(2);
+
+ ASTVec& bba2 = bm->BBTerm(a2);
+ cout << "bitblasted a2 " << endl;
+ LispPrintVec(cout, bba2, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode a3 = bm->CreateNode(BVXOR, s1, s2);
+ a3.SetValueWidth(2);
+
+ ASTVec& bba3 = bm->BBTerm(a3);
+ cout << "bitblasted a3 " << endl;
+ LispPrintVec(cout, bba3, 0);
+ cout << endl;
+ bm->AlreadyPrintedSet.clear();
+
+ ASTNode a4 = bm->CreateNode(EQ, s1, s2);
+ ASTNode bba4 = bm->BBForm(a4);
+ cout << "bitblasted a4 " << endl << bba4 << endl;
+
+ ASTNode a5 = bm->CreateNode(BVLE, s1, s2);
+ ASTNode bba5 = bm->BBForm(a5);
+ cout << "bitblasted a5 " << endl << bba5 << endl;
+
+ return 0;
+}
Added: klee/trunk/stp/AST/cnftest.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/cnftest.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/cnftest.cpp (added)
+++ klee/trunk/stp/AST/cnftest.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,47 @@
+// -*- c++ -*-
+
+// Test program for CNF conversion.
+
+#include "AST.h"
+
+using namespace BEEV;
+
+int main()
+{
+ const int size = 1;
+
+ BeevMgr *bm = new BeevMgr();
+ ASTNode s1 = bm->CreateSymbol("x");
+ s1.SetValueWidth(size);
+
+ cout << "s1" << s1 << endl;
+ ASTNode s2 = bm->CreateSymbol("y");
+ s2.SetValueWidth(size);
+
+ cout << "s2" << s2 << endl;
+ ASTNode s3 = bm->CreateSymbol("z");
+ s3.SetValueWidth(size);
+
+ cout << "s3" << s3 << endl;
+
+ ASTNode bbs1 = bm->BBForm(s1);
+ cout << "bitblasted s1" << endl << bbs1 << endl;
+ bm->PrintClauseList(cout, bm->ToCNF(bbs1));
+
+ ASTNode a2 = bm->CreateNode(AND, s1, s2);
+ ASTNode bba2 = bm->BBForm(a2);
+ cout << "bitblasted a2" << endl << bba2 << endl;
+ bm->PrintClauseList(cout, bm->ToCNF(bba2));
+
+ ASTNode a3 = bm->CreateNode(OR, s1, s2);
+ ASTNode bba3 = bm->BBForm(a3);
+ cout << "bitblasted a3" << endl << bba3 << endl;
+ bm->PrintClauseList(cout, bm->ToCNF(bba3));
+
+ ASTNode a4 = bm->CreateNode(EQ, s1, s2);
+ ASTNode bba4 = bm->BBForm(a4);
+ cout << "bitblasted a4 " << endl << bba4 << endl;
+
+ bm->PrintClauseList(cout, bm->ToCNF(bba4));
+
+}
Added: klee/trunk/stp/AST/genkinds.pl
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/AST/genkinds.pl?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/AST/genkinds.pl (added)
+++ klee/trunk/stp/AST/genkinds.pl Wed May 20 23:36:41 2009
@@ -0,0 +1,123 @@
+#!/usr/bin/perl -w
+
+#AUTHORS: Vijay Ganesh, David L. Dill BEGIN DATE: November, 2005
+#LICENSE: Please view LICENSE file in the home dir of this Program
+#given a file containing kind names, one per line produces .h and .cpp
+#files for the kinds.
+
+#globals
+ at kindnames = ();
+$minkids = 0;
+$maxkids = 0;
+ at cat_bits = ();
+ at category_names = ();
+%cat_index = ();
+
+$now = localtime time;
+
+sub read_kind_defs {
+ open(KFILE, "< ASTKind.kinds") || die "Cannot open .kinds file: $!\n";
+ @kindlines = <KFILE>;
+ close(KFILE)
+}
+
+# create lists of things indexed by kinds.
+sub split_fields {
+ my $kind_cat_bits;
+ # matches anything with three whitespace-delimited alphanumeric fields,
+ # followed by rest of line. Automatically ignores lines beginning with '#' and blank lines.
+ for (@kindlines) {
+ if (/Categories:\s+(.*)/) {
+ @category_names = split(/\s+/, $1);
+ $i = 0;
+ for (@category_names) {
+ $cat_index{$_} = $i++;
+ # print "cat_index{$_} = $i\n";
+ }
+ }
+ elsif (/^(\w+)\s+(\w+)\s+(\w+|-)\s+(.*)/) {
+ push(@kindnames, $1);
+ push(@minkids, $2);
+ push(@maxkids, $3);
+ @kind_cats = split(/\s+/, $4);
+ # build a bit vector of categories.
+ $kind_cat_bits = 0;
+ for (@kind_cats) {
+ $kind_cat_bits |= (1 << int($cat_index{$_}));
+ }
+ push(@cat_bits, $kind_cat_bits);
+ }
+ }
+}
+
+sub gen_h_file {
+ open(HFILE, "> ASTKind.h") || die "Cannot open .h file: $!\n";
+
+ print HFILE
+ "// -*- c++ -*-\n",
+ "#ifndef TESTKINDS_H\n",
+ "#define TESTKINDS_H\n",
+ "// Generated automatically by genkinds.pl from ASTKind.kinds $now.\n",
+ "// Do not edit\n",
+ "namespace BEEV {\n typedef enum {\n";
+
+ for (@kindnames) {
+ print HFILE " $_,\n";
+ }
+
+ print HFILE
+ "} Kind;\n\n",
+ "extern unsigned char _kind_categories[];\n\n";
+
+ # For category named "cat", generate functions "bool is_cat_kind(k);"
+
+
+ for (@category_names) {
+ my $catname = $_;
+ my $kind_cat_bit = (1 << int($cat_index{$catname}));
+ print HFILE "inline bool is_", $catname, "_kind(Kind k) { return (_kind_categories[k] & $kind_cat_bit); }\n\n"
+ }
+
+ print HFILE
+ "extern const char *_kind_names[];\n\n",
+ "/** Prints symbolic name of kind */\n",
+ "inline ostream& operator<<(ostream &os, const Kind &kind) { os << _kind_names[kind]; return os; }\n",
+ "\n\n",
+ "}; // end namespace\n",
+ "\n\n#endif\n";
+
+ close(HFILE);
+}
+
+# generate the .cpp file
+
+sub gen_cpp_file {
+ open(CPPFILE, "> ASTKind.cpp") || die "Cannot open .h file: $!\n";
+
+ print CPPFILE
+ "// Generated automatically by genkinds.h from ASTKind.kinds $now.\n",
+ "// Do not edit\n",
+ "namespace BEEV {\n",
+ "const char * _kind_names[] = {\n";
+ for (@kindnames) {
+ print CPPFILE " \"$_\",\n";
+ }
+ print CPPFILE "};\n\n";
+
+ # category bits
+ print CPPFILE
+ "unsigned char _kind_categories[] = {\n";
+ for (@cat_bits) {
+ print CPPFILE " $_,\n";
+ }
+ print CPPFILE
+ "};\n",
+ "\n}; // end namespace\n";
+
+ close(CPPFILE);
+}
+
+&read_kind_defs;
+&split_fields;
+&gen_h_file;
+&gen_cpp_file;
Propchange: klee/trunk/stp/AST/genkinds.pl
------------------------------------------------------------------------------
svn:executable = *
Added: klee/trunk/stp/INSTALL
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/INSTALL?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/INSTALL (added)
+++ klee/trunk/stp/INSTALL Wed May 20 23:36:41 2009
@@ -0,0 +1,10 @@
+1. To install STP perform the following steps on your Unix/GNU-Linux/MacOS X commandline:
+
+./configure --with-prefix=$HOME (or another installation directory)
+make clean
+make
+make install
+
+2. To test the system after installation:
+
+make regressall
\ No newline at end of file
Added: klee/trunk/stp/LICENSE
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/LICENSE?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/LICENSE (added)
+++ klee/trunk/stp/LICENSE Wed May 20 23:36:41 2009
@@ -0,0 +1,17 @@
+/*****************************************************************************/
+/* AUTHORS: Vijay Ganesh, David L. Dill DATE: Nov 2005 */
+/*****************************************************************************/
+/* Copyright (C) 2005 by the Board of Trustees of Leland Stanford */
+/* Junior University. */
+/* */
+/* License to use, copy, modify, sell and/or distribute this software */
+/* and its documentation for any purpose is hereby granted without */
+/* royalty, subject to the terms and conditions defined in the \ref */
+/* LICENSE file provided with this distribution. In particular: */
+/* */
+/* - The above copyright notice and this permission notice must appear */
+/* in all copies of the software and related documentation. */
+/* */
+/* - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, */
+/* EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. */
+/*****************************************************************************/
Added: klee/trunk/stp/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/Makefile (added)
+++ klee/trunk/stp/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,64 @@
+ # STP (Simple Theorem Prover) top level makefile
+ #
+ # To make in debug mode, type 'make "CLFAGS=-ggdb"
+ # To make in optimized mode, type 'make "CFLAGS=-O2"
+
+include Makefile.common
+
+BINARIES=bin/stp
+LIBS=AST/libast.a sat/libsatsolver.a simplifier/libsimplifier.a bitvec/libconsteval.a constantbv/libconstantbv.a c_interface/libcinterface.a
+DIRS=AST sat simplifier bitvec c_interface constantbv parser
+
+# NB: the TAGS target is a hack to get around this recursive make nonsense
+# we want all the source and header files generated before we make tags
+.PHONY: all
+all: lib/libstp.a bin/stp include/stp/c_interface.h
+
+AST/libast.a:
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+sat/libsatsolver.a: AST/libast.a
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+simplifier/libsimplifier.a: AST/libast.a
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+bitvec/libconsteval.a: AST/libast.a
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+constantbv/libconstantbv.a: AST/libast.a
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+c_interface/libcinterface.a: AST/libast.a
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+parser/parser: $(LIBS)
+ @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@`
+
+lib/libstp.a: parser/parser $(LIBS)
+ @mkdir -p lib
+ rm -f $@
+ @for dir in $(DIRS); do \
+ $(AR) rc $@ $$dir/*.o; \
+ done
+ $(RANLIB) $@
+
+bin/stp: parser/parser $(LIBS)
+ @mkdir -p bin
+ @cp parser/parser $@
+
+include/stp/c_interface.h: $(LIBS)
+ @mkdir -p include/stp
+ @cp c_interface/c_interface.h $@
+
+.PHONY: clean
+clean:
+ rm -rf *~
+ rm -rf *.a
+ rm -rf lib/*.a
+ rm -rf bin/*~
+ rm -rf bin/stp
+ rm -rf *.log
+ rm -f TAGS
+ $(MAKE) clean -C AST
+ $(MAKE) clean -C sat
+ $(MAKE) clean -C simplifier
+ $(MAKE) clean -C bitvec
+ $(MAKE) clean -C parser
+ $(MAKE) clean -C c_interface
+ $(MAKE) clean -C constantbv
+
Added: klee/trunk/stp/Makefile.common.in
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/Makefile.common.in?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/Makefile.common.in (added)
+++ klee/trunk/stp/Makefile.common.in Wed May 20 23:36:41 2009
@@ -0,0 +1,16 @@
+# -*- Makefile -*-
+
+CFLAGS := @CFLAGS@
+CXXFLAGS := @CXXFLAGS@ -O2
+LDFLAGS := @LDFLAGS@ -lstdc++
+
+# use the darmin test as a proxy for detecting Mac OS X
+ifneq ($(shell uname -s), Darwin)
+ CFLAGS += -static
+endif
+
+CXXFLAGS += -Wall -DEXT_HASH_MAP
+
+LEX := flex
+YACC := bison -d -y --debug -v
+RANLIB := ranlib
Added: klee/trunk/stp/README
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/README?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/README (added)
+++ klee/trunk/stp/README Wed May 20 23:36:41 2009
@@ -0,0 +1,26 @@
+/********************************************************************
+ * PROGRAM NAME: STP (Simple Theorem Prover)
+ *
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+
+Install
+-------
+See INSTALL file in the home dir of this program
+
+Authors
+-------
+Vijay Ganesh, Stanford University, Stanford, CA, USA
+David L. Dill, Stanford University, Stanford, CA, USA
+Tim King, Stanford University, Stanford, CA, USA
+
+Makefiles and configuration scripts
+------------------------------------
+Cristian Cadar, Stanford University, Stanford, CA, USA
+Paul Twohey, Stanford University, Stanford, CA, USA
+Sergey Berezin, ATG Synopsys, Mountain View, CA, USA
+Clark Barrett, New York University, New York, NY, USA
Added: klee/trunk/stp/bitvec/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/bitvec/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/bitvec/Makefile (added)
+++ klee/trunk/stp/bitvec/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,11 @@
+include ../Makefile.common
+
+SRCS = consteval.cpp
+OBJS = $(SRCS:.cpp=.o)
+
+libconsteval.a: $(OBJS)
+ $(AR) rc $@ $^
+ $(RANLIB) $@
+
+clean:
+ rm -rf *.o *~ *.a .#*
Added: klee/trunk/stp/bitvec/consteval.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/bitvec/consteval.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/bitvec/consteval.cpp (added)
+++ klee/trunk/stp/bitvec/consteval.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1044 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+#include "../AST/AST.h"
+#include "../AST/ASTUtil.h"
+namespace BEEV {
+
+ //error printing
+ static void BVConstEvaluatorError(CONSTANTBV::ErrCode e, const ASTNode& t){
+ std::string ss("BVConstEvaluator:");
+ ss += (const char*)BitVector_Error(e);
+ FatalError(ss.c_str(), t);
+ }
+
+#ifndef NATIVE_C_ARITH
+ ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) {
+ ASTNode OutputNode;
+ Kind k = t.GetKind();
+
+ if(CheckSolverMap(t,OutputNode))
+ return OutputNode;
+ OutputNode = t;
+
+ unsigned int inputwidth = t.GetValueWidth();
+ unsigned int outputwidth = inputwidth;
+ CBV output = NULL;
+
+ CBV tmp0 = NULL;
+ CBV tmp1 = NULL;
+
+ //saving some typing. BVPLUS does not use these variables. if the
+ //input BVPLUS has two nodes, then we want to avoid setting these
+ //variables.
+ if(1 == t.Degree() ){
+ tmp0 = BVConstEvaluator(t[0]).GetBVConst();
+ }else if(2 == t.Degree() && k != BVPLUS ) {
+ tmp0 = BVConstEvaluator(t[0]).GetBVConst();
+ tmp1 = BVConstEvaluator(t[1]).GetBVConst();
+ }
+
+ switch(k) {
+ case UNDEFINED:
+ case READ:
+ case WRITE:
+ case SYMBOL:
+ FatalError("BVConstEvaluator: term is not a constant-term",t);
+ break;
+ case BVCONST:
+ //FIXME Handle this special case better
+ OutputNode = t;
+ break;
+ case BVNEG:{
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::Set_Complement(output,tmp0);
+ OutputNode = CreateBVConst(output,outputwidth);
+ break;
+ }
+ case BVSX: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ //unsigned * out0 = BVConstEvaluator(t[0]).GetBVConst();
+ unsigned t0_width = t[0].GetValueWidth();
+ if(inputwidth == t0_width) {
+ CONSTANTBV::BitVector_Copy(output, tmp0);
+ OutputNode = CreateBVConst(output, outputwidth);
+ }
+ else {
+ bool topbit_sign = (CONSTANTBV::BitVector_Sign(tmp0) < 0 );
+
+ if(topbit_sign){
+ CONSTANTBV::BitVector_Fill(output);
+ }
+ CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width);
+ OutputNode = CreateBVConst(output, outputwidth);
+ }
+ break;
+ }
+ case BVAND: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::Set_Intersection(output,tmp0,tmp1);
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ case BVOR: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::Set_Union(output,tmp0,tmp1);
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ case BVXOR: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::Set_ExclusiveOr(output,tmp0,tmp1);
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ case BVSUB: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ bool carry = false;
+ CONSTANTBV::BitVector_sub(output,tmp0,tmp1,&carry);
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ case BVUMINUS: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::BitVector_Negate(output, tmp0);
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ case BVEXTRACT: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ tmp0 = BVConstEvaluator(t[0]).GetBVConst();
+ unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1]));
+ unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2]));
+ unsigned int len = hi-low+1;
+
+ CONSTANTBV::BitVector_Destroy(output);
+ output = CONSTANTBV::BitVector_Create(len, false);
+ CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, low, len);
+ outputwidth = len;
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ //FIXME Only 2 inputs?
+ case BVCONCAT: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ unsigned t0_width = t[0].GetValueWidth();
+ unsigned t1_width = t[1].GetValueWidth();
+ CONSTANTBV::BitVector_Destroy(output);
+
+ output = CONSTANTBV::BitVector_Concat(tmp0, tmp1);
+ outputwidth = t0_width + t1_width;
+ OutputNode = CreateBVConst(output, outputwidth);
+
+ break;
+ }
+ case BVMULT: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CBV tmp = CONSTANTBV::BitVector_Create(2*inputwidth,true);
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(tmp,tmp0,tmp1);
+
+ if(0 != e) {
+ BVConstEvaluatorError(e,t);
+ }
+ //FIXME WHAT IS MY OUTPUT???? THE SECOND HALF of tmp?
+ //CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, inputwidth, inputwidth);
+ CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, 0, inputwidth);
+ OutputNode = CreateBVConst(output, outputwidth);
+ CONSTANTBV::BitVector_Destroy(tmp);
+ break;
+ }
+ case BVPLUS: {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ bool carry = false;
+ ASTVec c = t.GetChildren();
+ for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
+ CBV kk = BVConstEvaluator(*it).GetBVConst();
+ CONSTANTBV::BitVector_add(output,output,kk,&carry);
+ carry = false;
+ //CONSTANTBV::BitVector_Destroy(kk);
+ }
+ OutputNode = CreateBVConst(output, outputwidth);
+ break;
+ }
+ //FIXME ANOTHER SPECIAL CASE
+ case SBVDIV:
+ case SBVMOD:{
+ OutputNode = BVConstEvaluator(TranslateSignedDivMod(t));
+ break;
+ }
+ case BVDIV:
+ case BVMOD: {
+ CBV quotient = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CBV remainder = CONSTANTBV::BitVector_Create(inputwidth,true);
+
+ // tmp0 is dividend, tmp1 is the divisor
+ //All parameters to BitVector_Div_Pos must be distinct unlike BitVector_Divide
+ //FIXME the contents of the second parameter to Div_Pos is destroyed
+ //As tmp0 is currently the same as the copy belonging to an ASTNode t[0]
+ //this must be copied.
+ tmp0 = CONSTANTBV::BitVector_Clone(tmp0);
+ CONSTANTBV::ErrCode e= CONSTANTBV::BitVector_Div_Pos(quotient,tmp0,tmp1,remainder);
+ CONSTANTBV::BitVector_Destroy(tmp0);
+
+ if(0 != e) {
+ //error printing
+ if(counterexample_checking_during_refinement) {
+ output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ OutputNode = CreateBVConst(output, outputwidth);
+ bvdiv_exception_occured = true;
+
+ // CONSTANTBV::BitVector_Destroy(output);
+ break;
+ }
+ else {
+ BVConstEvaluatorError(e,t);
+ }
+ } //end of error printing
+
+ //FIXME Not very standard in the current scheme
+ if(BVDIV == k){
+ OutputNode = CreateBVConst(quotient, outputwidth);
+ CONSTANTBV::BitVector_Destroy(remainder);
+ }else{
+ OutputNode = CreateBVConst(remainder, outputwidth);
+ CONSTANTBV::BitVector_Destroy(quotient);
+ }
+
+ break;
+ }
+ case ITE:
+ if(ASTTrue == t[0])
+ OutputNode = BVConstEvaluator(t[1]);
+ else if(ASTFalse == t[0])
+ OutputNode = BVConstEvaluator(t[2]);
+ else
+ FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t);
+ break;
+ case EQ:
+ if(CONSTANTBV::BitVector_equal(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case NEQ:
+ if(!CONSTANTBV::BitVector_equal(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVLT:
+ if(-1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVLE: {
+ int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1);
+ if(comp <= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVGT:
+ if(1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVGE: {
+ int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1);
+ if(comp >= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSLT:
+ if(-1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVSLE: {
+ signed int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1);
+ if(comp <= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSGT:
+ if(1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVSGE: {
+ int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1);
+ if(comp >= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ default:
+ FatalError("BVConstEvaluator: The input kind is not supported yet:",t);
+ break;
+ }
+/*
+ if(BVCONST != k){
+ cerr<<inputwidth<<endl;
+ cerr<<"------------------------"<<endl;
+ t.LispPrint(cerr);
+ cerr<<endl;
+ OutputNode.LispPrint(cerr);
+ cerr<<endl<<"------------------------"<<endl;
+ }
+*/
+ UpdateSolverMap(t,OutputNode);
+ //UpdateSimplifyMap(t,OutputNode,false);
+ return OutputNode;
+ }
+#else
+ //accepts 64 bit BVConst and sign extends it
+ static unsigned long long int SXBVConst64(const ASTNode& t) {
+ unsigned long long int c = t.GetBVConst();
+ unsigned int len = t.GetValueWidth();
+
+ unsigned long long int mask = 1;
+ mask = mask << len-1;
+
+ bool TopBit = (c & mask) ? true : false;
+ if(!TopBit) return c;
+
+ unsigned long long int sign = 0xffffffffffffffffLL;
+ sign = sign << len-1;
+
+ return (c | sign);
+ }
+
+ //FIXME: Ideally I would like the ASTNodes to be able to operate on
+ //themselves (add, sub, concat, etc.) rather than doing a
+ //GetBVConst() and then do the operation externally. For now,
+ //this is the fastest path to completion.
+ ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) {
+ //cerr << "inside begin bcconstevaluator: " << t << endl;
+
+ ASTNode OutputNode;
+ if(CheckSolverMap(t,OutputNode))
+ return OutputNode;
+ OutputNode = ASTUndefined;
+
+ Kind k = t.GetKind();
+ unsigned long long int output = 0;
+ unsigned inputwidth = t.GetValueWidth();
+ ASTNode t0 = ASTUndefined;
+ ASTNode t1 = ASTUndefined;
+ if(2 == t.Degree()) {
+ t0 = BVConstEvaluator(t[0]);
+ t1 = BVConstEvaluator(t[1]);
+ }
+ switch(k) {
+ case READ:
+ case UNDEFINED:
+ case WRITE:
+ case SYMBOL:
+ cerr << t;
+ FatalError("BVConstEvaluator: term is not a constant-term",t);
+ break;
+ case BVCONST:
+ return t;
+ break;
+ case BVNEG:
+ //compute bitwise negation in C
+ output = ~(BVConstEvaluator(t[0]).GetBVConst());
+ break;
+ case BVSX:
+ output = SXBVConst64(BVConstEvaluator(t[0]));
+ break;
+ case BVAND:
+ output = t0.GetBVConst() & t1.GetBVConst();
+ break;
+ case BVOR:
+ output = t0.GetBVConst() | t1.GetBVConst();
+ break;
+ case BVXOR:
+ output = t0.GetBVConst() ^ t1.GetBVConst();
+ break;
+ case BVSUB:
+ output = t0.GetBVConst() - t1.GetBVConst();
+ break;
+ case BVUMINUS:
+ output = ~(BVConstEvaluator(t[0]).GetBVConst()) + 1;
+ break;
+ case BVEXTRACT: {
+ unsigned long long int val = BVConstEvaluator(t[0]).GetBVConst();
+ unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1]));
+ unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2]));
+
+ if(!(0 <= hi <= 64))
+ FatalError("ConstantEvaluator: hi bit in BVEXTRACT is > 32bits",t);
+ if(!(0 <= low <= hi <= 64))
+ FatalError("ConstantEvaluator: low bit in BVEXTRACT is > 32bits or hi",t);
+
+ //64 bit mask.
+ unsigned long long int mask1 = 0xffffffffffffffffLL;
+ mask1 >>= 64-(hi+1);
+
+ //extract val[hi:0]
+ val &= mask1;
+ //extract val[hi:low]
+ val >>= low;
+ output = val;
+ break;
+ }
+ case BVCONCAT: {
+ unsigned long long int q = BVConstEvaluator(t0).GetBVConst();
+ unsigned long long int r = BVConstEvaluator(t1).GetBVConst();
+
+ unsigned int qlen = t[0].GetValueWidth();
+ unsigned int rlen = t[1].GetValueWidth();
+ unsigned int slen = t.GetValueWidth();
+ if(!(0 < qlen + rlen <= 64))
+ FatalError("BVConstEvaluator:"
+ "lengths of childnodes of BVCONCAT are > 64:",t);
+
+ //64 bit mask for q
+ unsigned long long int qmask = 0xffffffffffffffffLL;
+ qmask >>= 64-qlen;
+ //zero the useless bits of q
+ q &= qmask;
+
+ //64 bit mask for r
+ unsigned long long int rmask = 0xffffffffffffffffLL;
+ rmask >>= 64-rlen;
+ //zero the useless bits of r
+ r &= rmask;
+
+ //concatenate
+ q <<= rlen;
+ q |= r;
+
+ //64 bit mask for output s
+ unsigned long long int smask = 0xffffffffffffffffLL;
+ smask >>= 64-slen;
+
+ //currently q has the output
+ output = q;
+ output &= smask;
+ break;
+ }
+ case BVMULT: {
+ output = t0.GetBVConst() * t1.GetBVConst();
+
+ //64 bit mask
+ unsigned long long int mask = 0xffffffffffffffffLL;
+ mask = mask >> (64 - inputwidth);
+ output &= mask;
+ break;
+ }
+ case BVPLUS: {
+ ASTVec c = t.GetChildren();
+ for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++)
+ output += BVConstEvaluator(*it).GetBVConst();
+
+ //64 bit mask
+ unsigned long long int mask = 0xffffffffffffffffLL;
+ mask = mask >> (64 -inputwidth);
+ output &= mask;
+ break;
+ }
+ case SBVDIV:
+ case SBVMOD: {
+ output = BVConstEvaluator(TranslateSignedDivMod(t)).GetBVConst();
+ break;
+ }
+ case BVDIV: {
+ if(0 == t1.GetBVConst()) {
+ //if denominator is 0 then
+ // (if refinement is ON then output is set to 0)
+ // (else produce a fatal error)
+ if(counterexample_checking_during_refinement) {
+ output = 0;
+ bvdiv_exception_occured = true;
+ break;
+ }
+ else {
+ FatalError("BVConstEvaluator: divide by zero not allowed:",t);
+ }
+ }
+
+ output = t0.GetBVConst() / t1.GetBVConst();
+ //64 bit mask
+ unsigned long long int mask = 0xffffffffffffffffLL;
+ mask = mask >> (64 - inputwidth);
+ output &= mask;
+ break;
+ }
+ case BVMOD: {
+ if(0 == t1.GetBVConst()) {
+ //if denominator is 0 then
+ // (if refinement is ON then output is set to 0)
+ // (else produce a fatal error)
+ if(counterexample_checking_during_refinement) {
+ output = 0;
+ bvdiv_exception_occured = true;
+ break;
+ }
+ else {
+ FatalError("BVConstEvaluator: divide by zero not allowed:",t);
+ }
+ }
+
+ output = t0.GetBVConst() % t1.GetBVConst();
+ //64 bit mask
+ unsigned long long int mask = 0xffffffffffffffffLL;
+ mask = mask >> (64 - inputwidth);
+ output &= mask;
+ break;
+ }
+ case ITE:
+ if(ASTTrue == t[0])
+ OutputNode = BVConstEvaluator(t[1]);
+ else if(ASTFalse == t[0])
+ OutputNode = BVConstEvaluator(t[2]);
+ else
+ FatalError("BVConstEvaluator:"
+ "ITE condiional must be either TRUE or FALSE:",t);
+ break;
+ case EQ:
+ if(t0.GetBVConst() == t1.GetBVConst())
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case NEQ:
+ if(t0.GetBVConst() != t1.GetBVConst())
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ break;
+ case BVLT: {
+ unsigned long long n0 = t0.GetBVConst();
+ unsigned long long n1 = t1.GetBVConst();
+ if(n0 < n1)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVLE:
+ if(t0.GetBVConst() <= t1.GetBVConst())
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVGT:
+ if(t0.GetBVConst() > t1.GetBVConst())
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVGE:
+ if(t0.GetBVConst() >= t1.GetBVConst())
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVSLT: {
+ signed long long int n0 = SXBVConst64(t0);
+ signed long long int n1 = SXBVConst64(t1);
+ if(n0 < n1)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSLE: {
+ signed long long int n0 = SXBVConst64(t0);
+ signed long long int n1 = SXBVConst64(t1);
+ if(n0 <= n1)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSGT: {
+ signed long long int n0 = SXBVConst64(t0);
+ signed long long int n1 = SXBVConst64(t1);
+ if(n0 > n1)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSGE: {
+ signed long long int n0 = SXBVConst64(t0);
+ signed long long int n1 = SXBVConst64(t1);
+ if(n0 >= n1)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ default:
+ FatalError("BVConstEvaluator: The input kind is not supported yet:",t);
+ break;
+ }
+
+ if(ASTTrue != OutputNode && ASTFalse != OutputNode)
+ OutputNode = CreateBVConst(inputwidth, output);
+ UpdateSolverMap(t,OutputNode);
+ //UpdateSimplifyMap(t,OutputNode,false);
+ return OutputNode;
+ } //End of BVConstEvaluator
+#endif
+//In the block below is the old string based version
+//It is included here as an easy reference while the current code is being worked on.
+
+/*
+ ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) {
+ ASTNode OutputNode;
+ Kind k = t.GetKind();
+
+ if(CheckSolverMap(t,OutputNode))
+ return OutputNode;
+ OutputNode = t;
+
+ unsigned int inputwidth = t.GetValueWidth();
+ unsigned * output = CONSTANTBV::BitVector_Create(inputwidth,true);
+ unsigned * One = CONSTANTBV::BitVector_Create(inputwidth,true);
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(One, (unsigned char*)"1");
+ //error printing
+ if(0 != e) {
+ std::string ss("BVConstEvaluator:");
+ ss += (const char*)BitVector_Error(e);
+ FatalError(ss.c_str(), t);
+ }
+
+ unsigned * Zero = CONSTANTBV::BitVector_Create(inputwidth,true);
+ unsigned int * iii = One;
+ unsigned int * jjj = Zero;
+
+ //saving some typing. BVPLUS does not use these variables. if the
+ //input BVPLUS has two nodes, then we want to avoid setting these
+ //variables.
+ if(2 == t.Degree() && k != BVPLUS && k != BVCONCAT) {
+ iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst());
+ jjj = ConvertToCONSTANTBV(BVConstEvaluator(t[1]).GetBVConst());
+ }
+
+ char * cccc;
+ switch(k) {
+ case UNDEFINED:
+ case READ:
+ case WRITE:
+ case SYMBOL:
+ FatalError("BVConstEvaluator: term is not a constant-term",t);
+ break;
+ case BVCONST:
+ OutputNode = t;
+ break;
+ case BVNEG:{
+ //AARON
+ if (iii != One) free(iii);
+ //AARON
+
+ iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst());
+ CONSTANTBV::Set_Complement(output,iii);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+ break;
+ }
+ case BVSX: {
+ unsigned * out0 = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst());
+ unsigned t0_width = t[0].GetValueWidth();
+ if(inputwidth == t0_width) {
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(out0);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ CONSTANTBV::BitVector_Destroy(out0);
+ }
+ else {
+ // FIXME: (Dill) I'm guessing that BitVector sign returns 1 if the
+ // number is positive, 0 if 0, and -1 if negative. But I'm only
+ // guessing.
+ signed int topbit_sign = (CONSTANTBV::BitVector_Sign(out0) < 0);
+ //out1 is the sign-extension bits
+ unsigned * out1 = CONSTANTBV::BitVector_Create(inputwidth-t0_width,true);
+ if(topbit_sign)
+ CONSTANTBV::BitVector_Fill(out1);
+
+ //AARON
+ CONSTANTBV::BitVector_Destroy(output);
+ //AARON
+
+ output = CONSTANTBV::BitVector_Concat(out1,out0);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ CONSTANTBV::BitVector_Destroy(out0);
+ CONSTANTBV::BitVector_Destroy(out1);
+ }
+ break;
+ }
+ case BVAND: {
+ CONSTANTBV::Set_Intersection(output,iii,jjj);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case BVOR: {
+ CONSTANTBV::Set_Union(output,iii,jjj);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case BVXOR: {
+ CONSTANTBV::Set_ExclusiveOr(output,iii,jjj);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case BVSUB: {
+ bool carry = false;
+ CONSTANTBV::BitVector_sub(output,iii,jjj,&carry);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case BVUMINUS: {
+ bool carry = false;
+
+ //AARON
+ if (iii != One) free(iii);
+ //AARON
+
+ iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst());
+ CONSTANTBV::Set_Complement(output,iii);
+ CONSTANTBV::BitVector_add(output,output,One,&carry);
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case BVEXTRACT: {
+ string s(BVConstEvaluator(t[0]).GetBVConst());
+ unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1]));
+ unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2]));
+
+ //length of substr to chop
+ unsigned int len = hi-low+1;
+ //distance from MSB
+ hi = s.size()-1 - hi;
+ string ss = s.substr(hi,len);
+ OutputNode = CreateBVConst(ss.c_str(),2);
+ break;
+ }
+ case BVCONCAT: {
+ string s(BVConstEvaluator(t[0]).GetBVConst());
+ string r(BVConstEvaluator(t[1]).GetBVConst());
+
+ string q(s+r);
+ OutputNode = CreateBVConst(q.c_str(),2);
+ break;
+ }
+ case BVMULT: {
+ unsigned * output1 = CONSTANTBV::BitVector_Create(2*inputwidth,true);
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(output1,iii,jjj);
+ //error printing
+ if(0 != e) {
+ std::string ss("BVConstEvaluator:");
+ ss += (const char*)BitVector_Error(e);
+ //destroy all the CONSTANTBV bitvectors
+ CONSTANTBV::BitVector_Destroy(iii);
+ CONSTANTBV::BitVector_Destroy(jjj);
+ CONSTANTBV::BitVector_Destroy(One);
+ CONSTANTBV::BitVector_Destroy(Zero);
+ FatalError(ss.c_str(), t);
+ }
+
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output1);
+ std::string s(cccc);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ s = s.substr(inputwidth,inputwidth);
+ OutputNode = CreateBVConst(s.c_str(),2);
+ CONSTANTBV::BitVector_Destroy(output1);
+ break;
+ }
+ case BVPLUS: {
+ bool carry = false;
+ ASTVec c = t.GetChildren();
+ for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
+ unsigned int * kk = ConvertToCONSTANTBV(BVConstEvaluator(*it).GetBVConst());
+ CONSTANTBV::BitVector_add(output,output,kk,&carry);
+ carry = false;
+ CONSTANTBV::BitVector_Destroy(kk);
+ }
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(output);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ //AARON
+
+ break;
+ }
+ case SBVDIV:
+ case SBVMOD: {
+ OutputNode = BVConstEvaluator(TranslateSignedDivMod(t));
+ break;
+ }
+ case BVDIV: {
+ unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true);
+ unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true);
+ // iii is dividend, jjj is the divisor
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder);
+
+ if(0 != e) {
+ //error printing
+ if(counterexample_checking_during_refinement) {
+ OutputNode = CreateZeroConst(inputwidth);
+ bvdiv_exception_occured = true;
+ break;
+ }
+ else {
+ std::string ss("BVConstEvaluator:");
+ ss += (const char*)BitVector_Error(e);
+ //destroy all the CONSTANTBV bitvectors
+ CONSTANTBV::BitVector_Destroy(iii);
+ CONSTANTBV::BitVector_Destroy(jjj);
+ CONSTANTBV::BitVector_Destroy(One);
+ CONSTANTBV::BitVector_Destroy(Zero);
+
+ //AARON
+ iii = jjj = One = Zero = NULL;
+ //AARON
+
+ FatalError(ss.c_str(), t);
+ }
+ } //end of error printing
+
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(quotient);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ CONSTANTBV::BitVector_Destroy(quotient);
+ CONSTANTBV::BitVector_Destroy(remainder);
+ //AARON
+
+ break;
+ }
+ case BVMOD: {
+ unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true);
+ unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true);
+ // iii is dividend, jjj is the divisor
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder);
+
+ if(0 != e) {
+ //error printing
+ if(counterexample_checking_during_refinement) {
+ OutputNode = CreateZeroConst(inputwidth);
+ bvdiv_exception_occured = true;
+ break;
+ }
+ else {
+ std::string ss("BVConstEvaluator:");
+ ss += (const char*)BitVector_Error(e);
+ //destroy all the CONSTANTBV bitvectors
+ CONSTANTBV::BitVector_Destroy(iii);
+ CONSTANTBV::BitVector_Destroy(jjj);
+ CONSTANTBV::BitVector_Destroy(One);
+ CONSTANTBV::BitVector_Destroy(Zero);
+
+ //AARON
+ iii = jjj = One = Zero = NULL;
+ //AARON
+
+ FatalError(ss.c_str(), t);
+ }
+ } //end of errory printing
+
+ cccc = (char *)CONSTANTBV::BitVector_to_Bin(remainder);
+ OutputNode = CreateBVConst(cccc,2);
+
+ //AARON
+ free(cccc);
+ CONSTANTBV::BitVector_Destroy(quotient);
+ CONSTANTBV::BitVector_Destroy(remainder);
+ //AARON
+
+ break;
+ }
+ case ITE:
+ if(ASTTrue == t[0])
+ OutputNode = BVConstEvaluator(t[1]);
+ else if(ASTFalse == t[0])
+ OutputNode = BVConstEvaluator(t[2]);
+ else
+ FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t);
+ break;
+ case EQ:
+ if(CONSTANTBV::BitVector_equal(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case NEQ:
+ if(!CONSTANTBV::BitVector_equal(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVLT:
+ if(-1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVLE: {
+ int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj);
+ if(comp <= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVGT:
+ if(1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVGE: {
+ int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj);
+ if(comp >= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSLT:
+ if(-1 == CONSTANTBV::BitVector_Compare(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVSLE: {
+ signed int comp = CONSTANTBV::BitVector_Compare(iii,jjj);
+ if(comp <= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ case BVSGT:
+ if(1 == CONSTANTBV::BitVector_Compare(iii,jjj))
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ case BVSGE: {
+ int comp = CONSTANTBV::BitVector_Compare(iii,jjj);
+ if(comp >= 0)
+ OutputNode = ASTTrue;
+ else
+ OutputNode = ASTFalse;
+ break;
+ }
+ default:
+ FatalError("BVConstEvaluator: The input kind is not supported yet:",t);
+ break;
+ }
+
+
+
+ // //destroy all the CONSTANTBV bitvectors
+// CONSTANTBV::BitVector_Destroy(iii);
+// CONSTANTBV::BitVector_Destroy(jjj);
+// CONSTANTBV::BitVector_Destroy(output);
+
+// if(k == BVNEG || k == BVUMINUS)
+// CONSTANTBV::BitVector_Destroy(One);
+// else if(k == BVAND || k == BVOR || k == BVXOR || k == BVSUB ||
+// k == BVMULT || k == EQ || k == NEQ || k == BVLT ||
+// k == BVLE || k == BVGT || k == BVGE || k == BVSLT ||
+// k == BVSLE || k == BVSGT || k == BVSGE) {
+// CONSTANTBV::BitVector_Destroy(One);
+// CONSTANTBV::BitVector_Destroy(Zero);
+// }
+
+ //AARON
+ if (output != NULL) CONSTANTBV::BitVector_Destroy(output);
+ if (One != NULL) CONSTANTBV::BitVector_Destroy(One);
+ if (Zero != NULL) CONSTANTBV::BitVector_Destroy(Zero);
+ if (iii != NULL && iii != One) CONSTANTBV::BitVector_Destroy(iii);
+ if (jjj != NULL && jjj != Zero) CONSTANTBV::BitVector_Destroy(jjj);
+ //AARON
+
+ UpdateSolverMap(t,OutputNode);
+ //UpdateSimplifyMap(t,OutputNode,false);
+ return OutputNode;
+ }
+
+
+ unsigned int * ConvertToCONSTANTBV(const char * s) {
+ unsigned int length = strlen(s);
+ unsigned char * ccc = (unsigned char *)s;
+ unsigned * iii = CONSTANTBV::BitVector_Create(length,true);
+ CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,ccc);
+ //error printing
+ if(0 != e) {
+ cerr << "ConverToCONSTANTBV: wrong bin value: " << BitVector_Error(e);
+ FatalError("");
+ }
+
+ return iii;
+ }
+*/
+}; //end of namespace BEEV
Added: klee/trunk/stp/c_interface/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/c_interface/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/c_interface/Makefile (added)
+++ klee/trunk/stp/c_interface/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,13 @@
+include ../Makefile.common
+
+SRCS = c_interface.cpp
+OBJS = $(SRCS:.cpp=.o)
+
+libcinterface.a: $(OBJS)
+ $(AR) rc $@ $^
+ $(RANLIB) $@
+
+clean:
+ rm -rf *.o *~ *.a .#*
+
+c_interface.o: c_interface.h
Added: klee/trunk/stp/c_interface/c_interface.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/c_interface/c_interface.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/c_interface/c_interface.cpp (added)
+++ klee/trunk/stp/c_interface/c_interface.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,1548 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+#include "c_interface.h"
+
+#include <cstdlib>
+#include <cassert>
+#include <ostream>
+#include <iostream>
+#include "fdstream.h"
+#include "../AST/AST.h"
+
+//These typedefs lower the effort of using the keyboard to type (too
+//many overloaded meanings of the word type)
+typedef BEEV::ASTNode node;
+typedef BEEV::ASTNode* nodestar;
+typedef BEEV::BeevMgr* bmstar;
+typedef BEEV::ASTVec nodelist;
+typedef BEEV::CompleteCounterExample* CompleteCEStar;
+BEEV::ASTVec *decls = NULL;
+//vector<BEEV::ASTNode *> created_exprs;
+bool cinterface_exprdelete_on = false;
+
+void vc_setFlags(char c) {
+ std::string helpstring = "Usage: stp [-option] [infile]\n\n";
+ helpstring += "-r : switch refinement off (optimizations are ON by default)\n";
+ helpstring += "-w : switch wordlevel solver off (optimizations are ON by default)\n";
+ helpstring += "-a : switch optimizations off (optimizations are ON by default)\n";
+ helpstring += "-s : print function statistics\n";
+ helpstring += "-v : print nodes \n";
+ helpstring += "-c : construct counterexample\n";
+ helpstring += "-d : check counterexample\n";
+ helpstring += "-p : print counterexample\n";
+ helpstring += "-h : help\n";
+
+ switch(c) {
+ case 'a' :
+ BEEV::optimize = false;
+ BEEV::wordlevel_solve = false;
+ break;
+ case 'b':
+ BEEV::print_STPinput_back = true;
+ break;
+ case 'c':
+ BEEV::construct_counterexample = true;
+ break;
+ case 'd':
+ BEEV::construct_counterexample = true;
+ BEEV::check_counterexample = true;
+ break;
+ case 'e':
+ BEEV::variable_activity_optimize = true;
+ break;
+ case 'f':
+ BEEV::smtlib_parser_enable = true;
+ break;
+ case 'h':
+ cout << helpstring;
+ BEEV::FatalError("");
+ break;
+ case 'l' :
+ BEEV::linear_search = true;
+ break;
+ case 'n':
+ BEEV::print_output = true;
+ break;
+ case 'p':
+ BEEV::print_counterexample = true;
+ break;
+ case 'q':
+ BEEV::print_arrayval_declaredorder = true;
+ break;
+ case 'r':
+ BEEV::arrayread_refinement = false;
+ break;
+ case 's' :
+ BEEV::stats = true;
+ break;
+ case 'u':
+ BEEV::arraywrite_refinement = true;
+ break;
+ case 'v' :
+ BEEV::print_nodes = true;
+ break;
+ case 'w':
+ BEEV::wordlevel_solve = false;
+ break;
+ case 'x':
+ cinterface_exprdelete_on = true;
+ break;
+ case 'z':
+ BEEV::print_sat_varorder = true;
+ break;
+ default:
+ std::string s = "C_interface: vc_setFlags: Unrecognized commandline flag:\n";
+ s += helpstring;
+ BEEV::FatalError(s.c_str());
+ break;
+ }
+}
+
+//Create a validity Checker. This is the global BeevMgr
+VC vc_createValidityChecker(void) {
+ vc_setFlags('d');
+#ifdef NATIVE_C_ARITH
+#else
+ CONSTANTBV::ErrCode c = CONSTANTBV::BitVector_Boot();
+ if(0 != c) {
+ cout << CONSTANTBV::BitVector_Error(c) << endl;
+ return 0;
+ }
+#endif
+ bmstar bm = new BEEV::BeevMgr();
+ decls = new BEEV::ASTVec();
+ //created_exprs.clear();
+ return (VC)bm;
+}
+
+// Expr I/O
+void vc_printExpr(VC vc, Expr e) {
+ //do not print in lisp mode
+ //bmstar b = (bmstar)vc;
+ BEEV::ASTNode q = (*(nodestar)e);
+ // b->Begin_RemoveWrites = true;
+ // BEEV::ASTNode q = b->SimplifyFormula_TopLevel(*((nodestar)e),false);
+ // b->Begin_RemoveWrites = false;
+ q.PL_Print(cout);
+}
+
+void vc_printExprFile(VC vc, Expr e, int fd) {
+ fdostream os(fd);
+ ((nodestar)e)->PL_Print(os);
+ //os.flush();
+}
+
+static void vc_printVarDeclsToStream(VC vc, ostream &os) {
+ for(BEEV::ASTVec::iterator i = decls->begin(),iend=decls->end();i!=iend;i++) {
+ node a = *i;
+ switch(a.GetType()) {
+ case BEEV::BITVECTOR_TYPE:
+ a.PL_Print(os);
+ os << " : BITVECTOR(" << a.GetValueWidth() << ");" << endl;
+ break;
+ case BEEV::ARRAY_TYPE:
+ a.PL_Print(os);
+ os << " : ARRAY " << "BITVECTOR(" << a.GetIndexWidth() << ") OF ";
+ os << "BITVECTOR(" << a.GetValueWidth() << ");" << endl;
+ break;
+ case BEEV::BOOLEAN_TYPE:
+ a.PL_Print(os);
+ os << " : BOOLEAN;" << endl;
+ break;
+ default:
+ BEEV::FatalError("vc_printDeclsToStream: Unsupported type",a);
+ break;
+ }
+ }
+}
+
+void vc_printVarDecls(VC vc) {
+ vc_printVarDeclsToStream(vc, cout);
+}
+
+static void vc_printAssertsToStream(VC vc, ostream &os, int simplify_print) {
+ bmstar b = (bmstar)vc;
+ BEEV::ASTVec v = b->GetAsserts();
+ for(BEEV::ASTVec::iterator i=v.begin(),iend=v.end();i!=iend;i++) {
+ b->Begin_RemoveWrites = true;
+ BEEV::ASTNode q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(*i,false) : *i;
+ q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(q,false) : q;
+ b->Begin_RemoveWrites = false;
+ os << "ASSERT( ";
+ q.PL_Print(os);
+ os << ");" << endl;
+ }
+}
+
+void vc_printAsserts(VC vc, int simplify_print) {
+ vc_printAssertsToStream(vc, cout, simplify_print);
+}
+
+void vc_printQueryStateToBuffer(VC vc, Expr e, char **buf, unsigned long *len, int simplify_print){
+ assert(vc);
+ assert(e);
+ assert(buf);
+ assert(len);
+ bmstar b = (bmstar)vc;
+
+ // formate the state of the query
+ stringstream os;
+ vc_printVarDeclsToStream(vc, os);
+ os << "%----------------------------------------------------" << endl;
+ vc_printAssertsToStream(vc, os, simplify_print);
+ os << "%----------------------------------------------------" << endl;
+ os << "QUERY( ";
+ b->Begin_RemoveWrites = true;
+ BEEV::ASTNode q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(*((nodestar)e),false) : *(nodestar)e;
+ b->Begin_RemoveWrites = false;
+ q.PL_Print(os);
+ os << " );" << endl;
+
+ // convert to a c buffer
+ string s = os.str();
+ const char *cstr = s.c_str();
+ unsigned long size = s.size() + 1; // number of chars + terminating null
+ *buf = (char *)malloc(size);
+ if (!(*buf)) {
+ fprintf(stderr, "malloc(%lu) failed.", size);
+ assert(*buf);
+ }
+ *len = size;
+ memcpy(*buf, cstr, size);
+}
+
+void vc_printCounterExampleToBuffer(VC vc, char **buf, unsigned long *len) {
+ assert(vc);
+ assert(buf);
+ assert(len);
+ bmstar b = (bmstar)vc;
+
+ // formate the state of the query
+ std::ostringstream os;
+ BEEV::print_counterexample = true;
+ os << "COUNTEREXAMPLE BEGIN: \n";
+ b->PrintCounterExample(true,os);
+ os << "COUNTEREXAMPLE END: \n";
+
+ // convert to a c buffer
+ string s = os.str();
+ const char *cstr = s.c_str();
+ unsigned long size = s.size() + 1; // number of chars + terminating null
+ *buf = (char *)malloc(size);
+ if (!(*buf)) {
+ fprintf(stderr, "malloc(%lu) failed.", size);
+ assert(*buf);
+ }
+ *len = size;
+ memcpy(*buf, cstr, size);
+}
+
+void vc_printExprToBuffer(VC vc, Expr e, char **buf, unsigned long * len) {
+ stringstream os;
+ //bmstar b = (bmstar)vc;
+ BEEV::ASTNode q = *((nodestar)e);
+ // b->Begin_RemoveWrites = true;
+ // BEEV::ASTNode q = b->SimplifyFormula_TopLevel(*((nodestar)e),false);
+ // b->Begin_RemoveWrites = false;
+ q.PL_Print(os);
+ //((nodestar)e)->PL_Print(os);
+ string s = os.str();
+ const char * cstr = s.c_str();
+ unsigned long size = s.size() + 1; // number of chars + terminating null
+ *buf = (char *)malloc(size);
+ *len = size;
+ memcpy(*buf, cstr, size);
+}
+
+void vc_printQuery(VC vc){
+ ostream& os = std::cout;
+ bmstar b = (bmstar)vc;
+ os << "QUERY(";
+ //b->Begin_RemoveWrites = true;
+ //BEEV::ASTNode q = b->SimplifyFormula_TopLevel(b->GetQuery(),false);
+ BEEV::ASTNode q = b->GetQuery();
+ //b->Begin_RemoveWrites = false;
+ q.PL_Print(os);
+ // b->GetQuery().PL_Print(os);
+ os << ");" << endl;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Array-related methods //
+/////////////////////////////////////////////////////////////////////////////
+//! Create an array type
+Type vc_arrayType(VC vc, Type typeIndex, Type typeData) {
+ bmstar b = (bmstar)vc;
+ nodestar ti = (nodestar)typeIndex;
+ nodestar td = (nodestar)typeData;
+
+ if(!(ti->GetKind() == BEEV::BITVECTOR && (*ti)[0].GetKind() == BEEV::BVCONST))
+ BEEV::FatalError("Tyring to build array whose indextype i is not a BITVECTOR, where i = ",*ti);
+ if(!(td->GetKind() == BEEV::BITVECTOR && (*td)[0].GetKind() == BEEV::BVCONST))
+ BEEV::FatalError("Trying to build an array whose valuetype v is not a BITVECTOR. where a = ",*td);
+ nodestar output = new node(b->CreateNode(BEEV::ARRAY,(*ti)[0],(*td)[0]));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return (Type)output;
+}
+
+//! Create an expression for the value of array at the given index
+Expr vc_readExpr(VC vc, Expr array, Expr index) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)array;
+ nodestar i = (nodestar)index;
+
+ b->BVTypeCheck(*a);
+ b->BVTypeCheck(*i);
+ node o = b->CreateTerm(BEEV::READ,a->GetValueWidth(),*a,*i);
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+// //! Array update; equivalent to "array WITH [index] := newValue"
+Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)array;
+ nodestar i = (nodestar)index;
+ nodestar n = (nodestar)newValue;
+
+ b->BVTypeCheck(*a);
+ b->BVTypeCheck(*i);
+ b->BVTypeCheck(*n);
+ node o = b->CreateTerm(BEEV::WRITE,a->GetValueWidth(),*a,*i,*n);
+ o.SetIndexWidth(a->GetIndexWidth());
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Context-related methods //
+/////////////////////////////////////////////////////////////////////////////
+//! Assert a new formula in the current context.
+/*! The formula must have Boolean type. */
+void vc_assertFormula(VC vc, Expr e) {
+ nodestar a = (nodestar)e;
+ bmstar b = (bmstar)vc;
+
+ if(!BEEV::is_Form_kind(a->GetKind()))
+ BEEV::FatalError("Trying to assert a NON formula: ",*a);
+
+ b->BVTypeCheck(*a);
+ b->AddAssert(*a);
+}
+
+//! Check validity of e in the current context.
+/*! If the result is true, then the resulting context is the same as
+ * the starting context. If the result is false, then the resulting
+ * context is a context in which e is false. e must have Boolean
+ * type. */
+int vc_query(VC vc, Expr e) {
+ nodestar a = (nodestar)e;
+ bmstar b = (bmstar)vc;
+
+ if(!BEEV::is_Form_kind(a->GetKind()))
+ BEEV::FatalError("CInterface: Trying to QUERY a NON formula: ",*a);
+
+ b->BVTypeCheck(*a);
+ b->AddQuery(*a);
+
+ const BEEV::ASTVec v = b->GetAsserts();
+ node o;
+ if(!v.empty()) {
+ if(v.size()==1)
+ return b->TopLevelSAT(v[0],*a);
+ else
+ return b->TopLevelSAT(b->CreateNode(BEEV::AND,v),*a);
+ }
+ else
+ return b->TopLevelSAT(b->CreateNode(BEEV::TRUE),*a);
+}
+
+void vc_push(VC vc) {
+ bmstar b = (bmstar)vc;
+ b->ClearAllCaches();
+ b->Push();
+}
+
+void vc_pop(VC vc) {
+ bmstar b = (bmstar)vc;
+ b->Pop();
+}
+
+void vc_printCounterExample(VC vc) {
+ bmstar b = (bmstar)vc;
+ BEEV::print_counterexample = true;
+ cout << "COUNTEREXAMPLE BEGIN: \n";
+ b->PrintCounterExample(true);
+ cout << "COUNTEREXAMPLE END: \n";
+}
+
+// //! Return the counterexample after a failed query.
+// /*! This method should only be called after a query which returns
+// * false. It will try to return the simplest possible set of
+// * assertions which are sufficient to make the queried expression
+// * false. The caller is responsible for freeing the array when
+// * finished with it.
+// */
+
+Expr vc_getCounterExample(VC vc, Expr e) {
+ nodestar a = (nodestar)e;
+ bmstar b = (bmstar)vc;
+
+ bool t = false;
+ if(b->CounterExampleSize())
+ t = true;
+ nodestar output = new node(b->GetCounterExample(t, *a));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+int vc_counterexample_size(VC vc) {
+ bmstar b = (bmstar)vc;
+ return b->CounterExampleSize();
+}
+
+WholeCounterExample vc_getWholeCounterExample(VC vc) {
+ bmstar b = (bmstar)vc;
+ CompleteCEStar c =
+ new BEEV::CompleteCounterExample(b->GetCompleteCounterExample(), b);
+ return c;
+}
+
+Expr vc_getTermFromCounterExample(VC vc, Expr e, CompleteCEStar cc) {
+ //bmstar b = (bmstar)vc;
+ nodestar n = (nodestar)e;
+ CompleteCEStar c = (CompleteCEStar)cc;
+
+ nodestar output = new node(c->GetCounterExample(*n));
+ return output;
+}
+
+int vc_getBVLength(VC vc, Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ if(BEEV::BITVECTOR_TYPE != e->GetType()) {
+ BEEV::FatalError("c_interface: vc_GetBVLength: Input expression must be a bit-vector");
+ }
+
+ return e->GetValueWidth();
+} // end of vc_getBVLength
+
+/////////////////////////////////////////////////////////////////////////////
+// Expr Creation methods //
+/////////////////////////////////////////////////////////////////////////////
+//! Create a variable with a given name and type
+/*! The type cannot be a function type. */
+Expr vc_varExpr1(VC vc, char* name,
+ int indexwidth, int valuewidth) {
+ bmstar b = (bmstar)vc;
+
+ node o = b->CreateSymbol(name);
+ o.SetIndexWidth(indexwidth);
+ o.SetValueWidth(valuewidth);
+
+ nodestar output = new node(o);
+ ////if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ b->BVTypeCheck(*output);
+
+ //store the decls in a vector for printing purposes
+ decls->push_back(o);
+ return output;
+}
+
+Expr vc_varExpr(VC vc, char * name, Type type) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)type;
+
+ node o = b->CreateSymbol(name);
+ switch(a->GetKind()) {
+ case BEEV::BITVECTOR:
+ o.SetIndexWidth(0);
+ o.SetValueWidth(GetUnsignedConst((*a)[0]));
+ break;
+ case BEEV::ARRAY:
+ o.SetIndexWidth(GetUnsignedConst((*a)[0]));
+ o.SetValueWidth(GetUnsignedConst((*a)[1]));
+ break;
+ case BEEV::BOOLEAN:
+ o.SetIndexWidth(0);
+ o.SetValueWidth(0);
+ break;
+ default:
+ BEEV::FatalError("CInterface: vc_varExpr: Unsupported type",*a);
+ break;
+ }
+ nodestar output = new node(o);
+ ////if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ b->BVTypeCheck(*output);
+
+ //store the decls in a vector for printing purposes
+ decls->push_back(o);
+ return output;
+}
+
+//! Create an equality expression. The two children must have the
+//same type.
+Expr vc_eqExpr(VC vc, Expr ccc0, Expr ccc1) {
+ bmstar b = (bmstar)vc;
+
+ nodestar a = (nodestar)ccc0;
+ nodestar aa = (nodestar)ccc1;
+ b->BVTypeCheck(*a);
+ b->BVTypeCheck(*aa);
+ node o = b->CreateNode(BEEV::EQ,*a,*aa);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_boolType(VC vc) {
+ bmstar b = (bmstar)vc;
+
+ node o = b->CreateNode(BEEV::BOOLEAN);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// BOOLEAN EXPR Creation methods //
+/////////////////////////////////////////////////////////////////////////////
+// The following functions create Boolean expressions. The children
+// provided as arguments must be of type Boolean.
+Expr vc_trueExpr(VC vc) {
+ bmstar b = (bmstar)vc;
+ node c = b->CreateNode(BEEV::TRUE);
+
+ nodestar d = new node(c);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(d);
+ return d;
+}
+
+Expr vc_falseExpr(VC vc) {
+ bmstar b = (bmstar)vc;
+ node c = b->CreateNode(BEEV::FALSE);
+
+ nodestar d = new node(c);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(d);
+ return d;
+}
+
+Expr vc_notExpr(VC vc, Expr ccc) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+
+ node o = b->CreateNode(BEEV::NOT,*a);
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_andExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ node o = b->CreateNode(BEEV::AND,*l,*r);
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_orExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ node o = b->CreateNode(BEEV::OR,*l,*r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_andExprN(VC vc, Expr* cc, int n) {
+ bmstar b = (bmstar)vc;
+ nodestar * c = (nodestar *)cc;
+ nodelist d;
+
+ for(int i =0; i < n; i++)
+ d.push_back(*c[i]);
+
+ node o = b->CreateNode(BEEV::AND,d);
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+
+Expr vc_orExprN(VC vc, Expr* cc, int n) {
+ bmstar b = (bmstar)vc;
+ nodestar * c = (nodestar *)cc;
+ nodelist d;
+
+ for(int i =0; i < n; i++)
+ d.push_back(*c[i]);
+
+ node o = b->CreateNode(BEEV::OR,d);
+ b->BVTypeCheck(o);
+
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_iteExpr(VC vc, Expr cond, Expr thenpart, Expr elsepart){
+ bmstar b = (bmstar)vc;
+ nodestar c = (nodestar)cond;
+ nodestar t = (nodestar)thenpart;
+ nodestar e = (nodestar)elsepart;
+
+ b->BVTypeCheck(*c);
+ b->BVTypeCheck(*t);
+ b->BVTypeCheck(*e);
+ node o;
+ //if the user asks for a formula then produce a formula, else
+ //prodcue a term
+ if(BEEV::BOOLEAN_TYPE == t->GetType())
+ o = b->CreateNode(BEEV::ITE,*c,*t,*e);
+ else {
+ o = b->CreateTerm(BEEV::ITE,t->GetValueWidth(),*c,*t,*e);
+ o.SetIndexWidth(t->GetIndexWidth());
+ }
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_impliesExpr(VC vc, Expr antecedent, Expr consequent){
+ bmstar b = (bmstar)vc;
+ nodestar c = (nodestar)antecedent;
+ nodestar t = (nodestar)consequent;
+
+ b->BVTypeCheck(*c);
+ b->BVTypeCheck(*t);
+ node o;
+
+ o = b->CreateNode(BEEV::IMPLIES,*c,*t);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_iffExpr(VC vc, Expr e0, Expr e1){
+ bmstar b = (bmstar)vc;
+ nodestar c = (nodestar)e0;
+ nodestar t = (nodestar)e1;
+
+ b->BVTypeCheck(*c);
+ b->BVTypeCheck(*t);
+ node o;
+
+ o = b->CreateNode(BEEV::IFF,*c,*t);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_boolToBVExpr(VC vc, Expr form) {
+ bmstar b = (bmstar)vc;
+ nodestar c = (nodestar)form;
+
+ b->BVTypeCheck(*c);
+ if(!is_Form_kind(c->GetKind()))
+ BEEV::FatalError("CInterface: vc_BoolToBVExpr: You have input a NON formula:",*c);
+
+ node o;
+ node one = b->CreateOneConst(1);
+ node zero = b->CreateZeroConst(1);
+ o = b->CreateTerm(BEEV::ITE,1,*c,one,zero);
+
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// BITVECTOR EXPR Creation methods //
+/////////////////////////////////////////////////////////////////////////////
+Type vc_bvType(VC vc, int num_bits) {
+ bmstar b = (bmstar)vc;
+
+ if(!(0 < num_bits))
+ BEEV::FatalError("CInterface: number of bits in a bvtype must be a positive integer:",
+ b->CreateNode(BEEV::UNDEFINED));
+
+ node e = b->CreateBVConst(32, num_bits);
+ nodestar output = new node(b->CreateNode(BEEV::BITVECTOR,e));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Type vc_bv32Type(VC vc) {
+ return vc_bvType(vc,32);
+}
+
+
+Expr vc_bvConstExprFromStr(VC vc, char* binary_repr) {
+ bmstar b = (bmstar)vc;
+
+ node n = b->CreateBVConst(binary_repr,2);
+ b->BVTypeCheck(n);
+ nodestar output = new node(n);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvConstExprFromInt(VC vc,
+ int n_bits,
+ unsigned int value) {
+ bmstar b = (bmstar)vc;
+
+ unsigned long long int v = (unsigned long long int)value;
+ node n = b->CreateBVConst(n_bits, v);
+ b->BVTypeCheck(n);
+ nodestar output = new node(n);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvConstExprFromLL(VC vc,
+ int n_bits,
+ unsigned long long value) {
+ bmstar b = (bmstar)vc;
+
+ node n = b->CreateBVConst(n_bits, value);
+ b->BVTypeCheck(n);
+ nodestar output = new node(n);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvConcatExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o =
+ b->CreateTerm(BEEV::BVCONCAT,
+ l->GetValueWidth()+ r->GetValueWidth(),*l,*r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right){
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVPLUS,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+
+Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right) {
+ return vc_bvPlusExpr(vc, 32, left, right);
+}
+
+
+Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVSUB,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+
+Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right) {
+ return vc_bvMinusExpr(vc, 32, left, right);
+}
+
+
+Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVMULT,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvDivExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVDIV,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvModExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVMOD,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_sbvDivExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::SBVDIV,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_sbvModExpr(VC vc, int n_bits, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::SBVMOD,n_bits, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bv32MultExpr(VC vc, Expr left, Expr right) {
+ return vc_bvMultExpr(vc, 32, left, right);
+}
+
+
+// unsigned comparators
+Expr vc_bvLtExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVLT, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvLeExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVLE, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvGtExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVGT, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvGeExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVGE, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+// signed comparators
+Expr vc_sbvLtExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVSLT, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_sbvLeExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVSLE, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_sbvGtExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVSGT, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_sbvGeExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateNode(BEEV::BVSGE, *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvUMinusExpr(VC vc, Expr ccc) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+ b->BVTypeCheck(*a);
+
+ node o = b->CreateTerm(BEEV::BVUMINUS, a->GetValueWidth(), *a);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+// bitwise operations: these are terms not formulas
+Expr vc_bvAndExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVAND, (*l).GetValueWidth(), *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvOrExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVOR, (*l).GetValueWidth(), *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvXorExpr(VC vc, Expr left, Expr right) {
+ bmstar b = (bmstar)vc;
+ nodestar l = (nodestar)left;
+ nodestar r = (nodestar)right;
+
+ b->BVTypeCheck(*l);
+ b->BVTypeCheck(*r);
+ node o = b->CreateTerm(BEEV::BVXOR, (*l).GetValueWidth(), *l, *r);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvNotExpr(VC vc, Expr ccc) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+
+ b->BVTypeCheck(*a);
+ node o = b->CreateTerm(BEEV::BVNEG, a->GetValueWidth(), *a);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr ccc) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+ b->BVTypeCheck(*a);
+
+ //convert leftshift to bvconcat
+ if(0 != sh_amt) {
+ node len = b->CreateBVConst(sh_amt, 0);
+ node o = b->CreateTerm(BEEV::BVCONCAT, a->GetValueWidth() + sh_amt, *a, len);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+ }
+ else
+ return a;
+}
+
+Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr ccc) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+ b->BVTypeCheck(*a);
+
+ unsigned int w = a->GetValueWidth();
+ //the amount by which you are rightshifting
+ //is less-than/equal-to the length of input
+ //bitvector
+ if(0 < (unsigned)sh_amt && (unsigned)sh_amt <= w) {
+ node len = b->CreateBVConst(sh_amt, 0);
+ node hi = b->CreateBVConst(32,w-1);
+ node low = b->CreateBVConst(32,sh_amt);
+ node extract = b->CreateTerm(BEEV::BVEXTRACT,w-sh_amt,*a,hi,low);
+
+ node n = b->CreateTerm(BEEV::BVCONCAT, w,len, extract);
+ b->BVTypeCheck(n);
+ nodestar output = new node(n);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+ }
+ else if(sh_amt == 0)
+ return a;
+ else {
+ if(0== w)
+ BEEV::FatalError("CInterface: vc_bvRightShiftExpr: cannot have a bitvector of length 0:",*a);
+ nodestar output = new node(b->CreateBVConst(w,0));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+ }
+}
+
+/* Same as vc_bvLeftShift only that the answer in 32 bits long */
+Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child) {
+ return vc_bvExtract(vc, vc_bvLeftShiftExpr(vc, sh_amt, child), 31, 0);
+}
+
+/* Same as vc_bvRightShift only that the answer in 32 bits long */
+Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child) {
+ return vc_bvExtract(vc, vc_bvRightShiftExpr(vc, sh_amt, child), 31, 0);
+}
+
+
+Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child) {
+ Expr ifpart;
+ Expr thenpart;
+ Expr elsepart = vc_trueExpr(vc);
+ Expr ite = vc_trueExpr(vc);
+
+ for(int count=32; count >= 0; count--){
+ if(count != 32) {
+ ifpart = vc_eqExpr(vc, sh_amt,
+ vc_bvConstExprFromInt(vc, 32, count));
+ thenpart = vc_bvExtract(vc,
+ vc_bvLeftShiftExpr(vc, count, child),
+ 31, 0);
+
+ ite = vc_iteExpr(vc,ifpart,thenpart,elsepart);
+ elsepart = ite;
+ }
+ else
+ elsepart = vc_bvConstExprFromInt(vc,32, 0);
+ }
+ return ite;
+}
+
+Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs) {
+ Expr ifpart;
+ Expr thenpart;
+ Expr elsepart = vc_trueExpr(vc);
+ Expr ite = vc_trueExpr(vc);
+
+ for(int count=32; count >= 0; count--){
+ if(count != 32) {
+ ifpart = vc_eqExpr(vc, rhs,
+ vc_bvConstExprFromInt(vc, 32, 1 << count));
+ thenpart = vc_bvRightShiftExpr(vc, count, child);
+ ite = vc_iteExpr(vc,ifpart,thenpart,elsepart);
+ elsepart = ite;
+ } else {
+ elsepart = vc_bvConstExprFromInt(vc,32, 0);
+ }
+ }
+ return ite;
+}
+
+Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child) {
+ Expr ifpart;
+ Expr thenpart;
+ Expr elsepart = vc_trueExpr(vc);
+ Expr ite = vc_trueExpr(vc);
+
+ for(int count=32; count >= 0; count--){
+ if(count != 32) {
+ ifpart = vc_eqExpr(vc, sh_amt,
+ vc_bvConstExprFromInt(vc, 32, count));
+ thenpart = vc_bvRightShiftExpr(vc, count, child);
+ ite = vc_iteExpr(vc,ifpart,thenpart,elsepart);
+ elsepart = ite;
+ } else {
+ elsepart = vc_bvConstExprFromInt(vc,32, 0);
+ }
+ }
+ return ite;
+}
+
+Expr vc_bvExtract(VC vc, Expr ccc, int hi_num, int low_num) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+ b->BVTypeCheck(*a);
+
+ node hi = b->CreateBVConst(32,hi_num);
+ node low = b->CreateBVConst(32,low_num);
+ node o = b->CreateTerm(BEEV::BVEXTRACT,hi_num-low_num+1,*a,hi,low);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvBoolExtract(VC vc, Expr ccc, int bit_num) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+ b->BVTypeCheck(*a);
+
+ node bit = b->CreateBVConst(32,bit_num);
+ //node o = b->CreateNode(BEEV::BVGETBIT,*a,bit);
+ node zero = b->CreateBVConst(1,0);
+ node oo = b->CreateTerm(BEEV::BVEXTRACT,1,*a,bit,bit);
+ node o = b->CreateNode(BEEV::EQ,oo,zero);
+ b->BVTypeCheck(o);
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+Expr vc_bvSignExtend(VC vc, Expr ccc, int nbits) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)ccc;
+
+ //width of the expr which is being sign extended. nbits is the
+ //resulting length of the signextended expr
+ b->BVTypeCheck(*a);
+
+ unsigned exprlen = a->GetValueWidth();
+ unsigned outputlen = nbits;
+ node n;
+ if(exprlen >= outputlen) {
+ //extract
+ node hi = b->CreateBVConst(32,outputlen-1);
+ node low = b->CreateBVConst(32,0);
+ n = b->CreateTerm(BEEV::BVEXTRACT,nbits,*a,hi,low);
+ b->BVTypeCheck(n);
+ }
+ else {
+ //sign extend
+ BEEV::ASTNode width = b->CreateBVConst(32,nbits);
+ n = b->CreateTerm(BEEV::BVSX,nbits,*a, width);
+ }
+
+ b->BVTypeCheck(n);
+ nodestar output = new node(n);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+}
+
+//! Return an int from a constant bitvector expression
+int getBVInt(Expr e) {
+ //bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)e;
+
+ if(BEEV::BVCONST != a->GetKind())
+ BEEV::FatalError("CInterface: getBVInt: Attempting to extract int value from a NON-constant BITVECTOR: ",*a);
+ return (int)GetUnsignedConst(*a);
+}
+
+//! Return an unsigned int from a constant bitvector expression
+unsigned int getBVUnsigned(Expr e) {
+ //bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)e;
+
+ if(BEEV::BVCONST != a->GetKind())
+ BEEV::FatalError("getBVUnsigned: Attempting to extract int value from a NON-constant BITVECTOR: ",*a);
+ return (unsigned int)GetUnsignedConst(*a);
+}
+
+//! Return an unsigned long long int from a constant bitvector expression
+unsigned long long int getBVUnsignedLongLong(Expr e) {
+ //bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)e;
+
+ if(BEEV::BVCONST != a->GetKind())
+ BEEV::FatalError("getBVUnsigned: Attempting to extract int value from a NON-constant BITVECTOR: ",*a);
+#ifdef NATIVE_C_ARITH
+ return (unsigned long long int)a->GetBVConst();
+#else
+ unsigned* bv = a->GetBVConst();
+
+ char * str_bv = (char *)CONSTANTBV::BitVector_to_Bin(bv);
+ unsigned long long int tmp = strtoull(str_bv,NULL,2);
+ CONSTANTBV::BitVector_Dispose((unsigned char *)str_bv);
+ return tmp;
+#endif
+}
+
+
+Expr vc_simplify(VC vc, Expr e) {
+ bmstar b = (bmstar)vc;
+ nodestar a = (nodestar)e;
+
+ if(BEEV::BOOLEAN_TYPE == a->GetType()) {
+ nodestar output = new node(b->SimplifyFormula_TopLevel(*a,false));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ b->Begin_RemoveWrites = true;
+ output = new node(b->SimplifyFormula_TopLevel(*output,false));
+ b->Begin_RemoveWrites = false;
+ return output;
+ }
+ else {
+ nodestar output = new node(b->SimplifyTerm(*a));
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ b->Begin_RemoveWrites = true;
+ output = new node(b->SimplifyTerm(*output));
+ b->Begin_RemoveWrites = false;
+ return output;
+ }
+}
+
+/* C pointer support: C interface to support C memory arrays in CVCL */
+Expr vc_bvCreateMemoryArray(VC vc, char * arrayName) {
+ Type bv8 = vc_bvType(vc,8);
+ Type bv32 = vc_bvType(vc,32);
+
+ Type malloced_mem0 = vc_arrayType(vc,bv32,bv8);
+ return vc_varExpr(vc, arrayName, malloced_mem0);
+}
+
+Expr vc_bvReadMemoryArray(VC vc,
+ Expr array,
+ Expr byteIndex, int numOfBytes) {
+ if(!(numOfBytes > 0))
+ BEEV::FatalError("numOfBytes must be greater than 0");
+
+ if(numOfBytes == 1)
+ return vc_readExpr(vc,array,byteIndex);
+ else {
+ int count = 1;
+ Expr a = vc_readExpr(vc,array,byteIndex);
+ while(--numOfBytes > 0) {
+ Expr b = vc_readExpr(vc,array,
+ /*vc_simplify(vc, */
+ vc_bvPlusExpr(vc, 32,
+ byteIndex,
+ vc_bvConstExprFromInt(vc,32,count)))/*)*/;
+ a = vc_bvConcatExpr(vc,b,a);
+ count++;
+ }
+ return a;
+ }
+}
+
+Expr vc_bvWriteToMemoryArray(VC vc,
+ Expr array, Expr byteIndex,
+ Expr element, int numOfBytes) {
+ if(!(numOfBytes > 0))
+ BEEV::FatalError("numOfBytes must be greater than 0");
+
+ int newBitsPerElem = numOfBytes*8;
+ if(numOfBytes == 1)
+ return vc_writeExpr(vc, array, byteIndex, element);
+ else {
+ int count = 1;
+ int hi = newBitsPerElem - 1;
+ int low = newBitsPerElem - 8;
+ int low_elem = 0;
+ int hi_elem = low_elem + 7;
+ Expr c = vc_bvExtract(vc, element, hi_elem, low_elem);
+ Expr newarray = vc_writeExpr(vc, array, byteIndex, c);
+ while(--numOfBytes > 0) {
+ hi = low-1;
+ low = low-8;
+
+ low_elem = low_elem + 8;
+ hi_elem = low_elem + 7;
+
+ c = vc_bvExtract(vc, element, hi_elem, low_elem);
+ newarray =
+ vc_writeExpr(vc, newarray,
+ vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)),
+ c);
+ count++;
+ }
+ return newarray;
+ }
+}
+
+Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value){
+ return vc_bvConstExprFromInt(vc, 32, value);
+}
+
+
+#if 0
+static char *val_to_binary_str(unsigned nbits, unsigned long long val) {
+ char s[65];
+
+ assert(nbits < sizeof s);
+ strcpy(s, "");
+ while(nbits-- > 0) {
+ if((val >> nbits) & 1)
+ strcat(s, "1");
+ else
+ strcat(s, "0");
+ }
+ return strdup(s);
+}
+#endif
+
+char* exprString(Expr e){
+ stringstream ss;
+ ((nodestar)e)->PL_Print(ss,0);
+ string s = ss.str();
+ char *copy = strdup(s.c_str());
+ return copy;
+}
+
+char* typeString(Type t){
+ stringstream ss;
+ ((nodestar)t)->PL_Print(ss,0);
+
+ string s = ss.str();
+ char *copy = strdup(s.c_str());
+ return copy;
+}
+
+Expr getChild(Expr e, int i){
+ nodestar a = (nodestar)e;
+
+ BEEV::ASTVec c = a->GetChildren();
+ if(0 <= (unsigned)i && (unsigned)i < c.size()) {
+ BEEV::ASTNode o = c[i];
+ nodestar output = new node(o);
+ //if(cinterface_exprdelete_on) created_exprs.push_back(output);
+ return output;
+ }
+ else
+ BEEV::FatalError("getChild: Error accessing childNode in expression: ",*a);
+ return a;
+}
+
+void vc_registerErrorHandler(void (*error_hdlr)(const char* err_msg)) {
+ BEEV::vc_error_hdlr = error_hdlr;
+}
+
+
+int vc_getHashQueryStateToBuffer(VC vc, Expr query) {
+ assert(vc);
+ assert(query);
+ bmstar b = (bmstar)vc;
+ nodestar qry = (nodestar)query;
+ BEEV::ASTVec v = b->GetAsserts();
+ BEEV::ASTNode out = b->CreateNode(BEEV::AND,b->CreateNode(BEEV::NOT,*qry),v);
+ return out.Hash();
+}
+
+Type vc_getType(VC vc, Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ switch(e->GetType()) {
+ case BEEV::BOOLEAN_TYPE:
+ return vc_boolType(vc);
+ break;
+ case BEEV::BITVECTOR_TYPE:
+ return vc_bvType(vc,e->GetValueWidth());
+ break;
+ case BEEV::ARRAY_TYPE: {
+ Type typeindex = vc_bvType(vc,e->GetIndexWidth());
+ Type typedata = vc_bvType(vc,e->GetValueWidth());
+ return vc_arrayType(vc,typeindex,typedata);
+ break;
+ }
+ default:
+ BEEV::FatalError("c_interface: vc_GetType: expression with bad typing: please check your expression construction");
+ return vc_boolType(vc);
+ break;
+ }
+}// end of vc_gettype()
+
+//!if e is TRUE then return 1; if e is FALSE then return 0; otherwise
+//return -1
+int vc_isBool(Expr e) {
+ nodestar input = (nodestar)e;
+ if(BEEV::TRUE == input->GetKind()) {
+ return 1;
+ }
+
+ if(BEEV::FALSE == input->GetKind()) {
+ return 0;
+ }
+
+ return -1;
+}
+
+void vc_Destroy(VC vc) {
+ bmstar b = (bmstar)vc;
+ // for(std::vector<BEEV::ASTNode *>::iterator it=created_exprs.begin(),
+ // itend=created_exprs.end();it!=itend;it++) {
+ // BEEV::ASTNode * aaa = *it;
+ // delete aaa;
+ // }
+ delete decls;
+ delete b;
+}
+
+void vc_DeleteExpr(Expr e) {
+ nodestar input = (nodestar)e;
+ //bmstar b = (bmstar)vc;
+ delete input;
+}
+
+exprkind_t getExprKind(Expr e) {
+ nodestar input = (nodestar)e;
+ return (exprkind_t)(input->GetKind());
+}
+
+int getDegree (Expr e) {
+ nodestar input = (nodestar)e;
+ return input->Degree();
+}
+
+int getBVLength(Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ if(BEEV::BITVECTOR_TYPE != e->GetType()) {
+ BEEV::FatalError("c_interface: vc_GetBVLength: Input expression must be a bit-vector");
+ }
+
+ return e->GetValueWidth();
+}
+
+type_t getType (Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ return (type_t)(e->GetType());
+}
+
+int getVWidth (Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ return e->GetValueWidth();
+}
+
+int getIWidth (Expr ex) {
+ nodestar e = (nodestar)ex;
+
+ return e->GetIndexWidth();
+}
+
+void vc_printCounterExampleFile(VC vc, int fd) {
+ fdostream os(fd);
+ bmstar b = (bmstar)vc;
+ BEEV::print_counterexample = true;
+ os << "COUNTEREXAMPLE BEGIN: \n";
+ b->PrintCounterExample(true, os);
+ os << "COUNTEREXAMPLE END: \n";
+}
+
+const char* exprName(Expr e){
+ return ((nodestar)e)->GetName();
+}
+
+int getExprID (Expr ex) {
+ BEEV::ASTNode q = (*(nodestar)ex);
+
+ return q.GetNodeNum();
+}
Added: klee/trunk/stp/c_interface/c_interface.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/c_interface/c_interface.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/c_interface/c_interface.h (added)
+++ klee/trunk/stp/c_interface/c_interface.h Wed May 20 23:36:41 2009
@@ -0,0 +1,401 @@
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * License to use, copy, modify, sell and/or distribute this software
+ * and its documentation for any purpose is hereby granted without
+ * royalty, subject to the terms and conditions defined in the \ref
+ * LICENSE file provided with this distribution. In particular:
+ *
+ * - The above copyright notice and this permission notice must appear
+ * in all copies of the software and related documentation.
+ *
+ * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
+ * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK.
+ ********************************************************************/
+// -*- c++ -*-
+#ifndef _cvcl__include__c_interface_h_
+#define _cvcl__include__c_interface_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STP_STRONG_TYPING
+#else
+ //This gives absolutely no pointer typing at compile-time. Most C
+ //users prefer this over stronger typing. User is the king. A
+ //stronger typed interface is in the works.
+ typedef void* VC;
+ typedef void* Expr;
+ typedef void* Type;
+ typedef void* WholeCounterExample;
+#endif
+
+ // o : optimizations
+ // c : check counterexample
+ // p : print counterexample
+ // h : help
+ // s : stats
+ // v : print nodes
+ void vc_setFlags(char c);
+
+ //! Flags can be NULL
+ VC vc_createValidityChecker(void);
+
+ // Basic types
+ Type vc_boolType(VC vc);
+
+ //! Create an array type
+ Type vc_arrayType(VC vc, Type typeIndex, Type typeData);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Expr manipulation methods //
+ /////////////////////////////////////////////////////////////////////////////
+
+ //! Create a variable with a given name and type
+ /*! The type cannot be a function type. The var name can contain
+ only variables, numerals and underscore. If you use any other
+ symbol, you will get a segfault. */
+ Expr vc_varExpr(VC vc, char * name, Type type);
+
+ //The var name can contain only variables, numerals and
+ //underscore. If you use any other symbol, you will get a segfault.
+ Expr vc_varExpr1(VC vc, char* name,
+ int indexwidth, int valuewidth);
+
+ //! Get the expression and type associated with a name.
+ /*! If there is no such Expr, a NULL Expr is returned. */
+ //Expr vc_lookupVar(VC vc, char* name, Type* type);
+
+ //! Get the type of the Expr.
+ Type vc_getType(VC vc, Expr e);
+
+ int vc_getBVLength(VC vc, Expr e);
+
+ //! Create an equality expression. The two children must have the same type.
+ Expr vc_eqExpr(VC vc, Expr child0, Expr child1);
+
+ // Boolean expressions
+
+ // The following functions create Boolean expressions. The children
+ // provided as arguments must be of type Boolean (except for the
+ // function vc_iteExpr(). In the case of vc_iteExpr() the
+ // conditional must always be Boolean, but the ifthenpart
+ // (resp. elsepart) can be bit-vector or Boolean type. But, the
+ // ifthenpart and elsepart must be both of the same type)
+ Expr vc_trueExpr(VC vc);
+ Expr vc_falseExpr(VC vc);
+ Expr vc_notExpr(VC vc, Expr child);
+ Expr vc_andExpr(VC vc, Expr left, Expr right);
+ Expr vc_andExprN(VC vc, Expr* children, int numOfChildNodes);
+ Expr vc_orExpr(VC vc, Expr left, Expr right);
+ Expr vc_orExprN(VC vc, Expr* children, int numOfChildNodes);
+ Expr vc_impliesExpr(VC vc, Expr hyp, Expr conc);
+ Expr vc_iffExpr(VC vc, Expr left, Expr right);
+ //The output type of vc_iteExpr can be Boolean (formula-level ite)
+ //or bit-vector (word-level ite)
+ Expr vc_iteExpr(VC vc, Expr conditional, Expr ifthenpart, Expr elsepart);
+
+ //Boolean to single bit BV Expression
+ Expr vc_boolToBVExpr(VC vc, Expr form);
+
+ // Arrays
+
+ //! Create an expression for the value of array at the given index
+ Expr vc_readExpr(VC vc, Expr array, Expr index);
+
+ //! Array update; equivalent to "array WITH [index] := newValue"
+ Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue);
+
+ // Expr I/O
+ //! Expr vc_parseExpr(VC vc, char* s);
+
+ //! Prints 'e' to stdout.
+ void vc_printExpr(VC vc, Expr e);
+
+ //! Prints 'e' into an open file descriptor 'fd'
+ void vc_printExprFile(VC vc, Expr e, int fd);
+
+ //! Prints state of 'vc' into malloc'd buffer '*buf' and stores the
+ // length into '*len'. It is the responsibility of the caller to
+ // free the buffer.
+ //void vc_printStateToBuffer(VC vc, char **buf, unsigned long *len);
+
+ //! Prints 'e' to malloc'd buffer '*buf'. Sets '*len' to the length of
+ // the buffer. It is the responsibility of the caller to free the buffer.
+ void vc_printExprToBuffer(VC vc, Expr e, char **buf, unsigned long * len);
+
+ //! Prints counterexample to stdout.
+ void vc_printCounterExample(VC vc);
+
+ //! Prints variable declarations to stdout.
+ void vc_printVarDecls(VC vc);
+
+ //! Prints asserts to stdout. The flag simplify_print must be set to
+ //"1" if you wish simplification to occur dring printing. It must be
+ //set to "0" otherwise
+ void vc_printAsserts(VC vc, int simplify_print);
+
+ //! Prints the state of the query to malloc'd buffer '*buf' and
+ //stores ! the length of the buffer to '*len'. It is the
+ //responsibility of the caller to free the buffer. The flag
+ //simplify_print must be set to "1" if you wish simplification to
+ //occur dring printing. It must be set to "0" otherwise
+ void vc_printQueryStateToBuffer(VC vc, Expr e,
+ char **buf, unsigned long *len, int simplify_print);
+
+ //! Similar to vc_printQueryStateToBuffer()
+ void vc_printCounterExampleToBuffer(VC vc, char **buf,unsigned long *len);
+
+ //! Prints query to stdout.
+ void vc_printQuery(VC vc);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Context-related methods //
+ /////////////////////////////////////////////////////////////////////////////
+
+ //! Assert a new formula in the current context.
+ /*! The formula must have Boolean type. */
+ void vc_assertFormula(VC vc, Expr e);
+
+ //! Simplify e with respect to the current context
+ Expr vc_simplify(VC vc, Expr e);
+
+ //! Check validity of e in the current context. e must be a FORMULA
+ //
+ //if returned 0 then input is INVALID.
+ //
+ //if returned 1 then input is VALID
+ //
+ //if returned 2 then ERROR
+ int vc_query(VC vc, Expr e);
+
+ //! Return the counterexample after a failed query.
+ Expr vc_getCounterExample(VC vc, Expr e);
+
+ //! get size of counterexample, i.e. the number of variables/array
+ //locations in the counterexample.
+ int vc_counterexample_size(VC vc);
+
+ //! Checkpoint the current context and increase the scope level
+ void vc_push(VC vc);
+
+ //! Restore the current context to its state at the last checkpoint
+ void vc_pop(VC vc);
+
+ //! Return an int from a constant bitvector expression
+ int getBVInt(Expr e);
+ //! Return an unsigned int from a constant bitvector expression
+ unsigned int getBVUnsigned(Expr e);
+ //! Return an unsigned long long int from a constant bitvector expressions
+ unsigned long long int getBVUnsignedLongLong(Expr e);
+
+ /**************************/
+ /* BIT VECTOR OPERATIONS */
+ /**************************/
+ Type vc_bvType(VC vc, int no_bits);
+ Type vc_bv32Type(VC vc);
+
+ Expr vc_bvConstExprFromStr(VC vc, char* binary_repr);
+ Expr vc_bvConstExprFromInt(VC vc, int n_bits, unsigned int value);
+ Expr vc_bvConstExprFromLL(VC vc, int n_bits, unsigned long long value);
+ Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value);
+
+ Expr vc_bvConcatExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right);
+ Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right);
+ Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right);
+ Expr vc_bv32MultExpr(VC vc, Expr left, Expr right);
+ // left divided by right i.e. left/right
+ Expr vc_bvDivExpr(VC vc, int n_bits, Expr left, Expr right);
+ // left modulo right i.e. left%right
+ Expr vc_bvModExpr(VC vc, int n_bits, Expr left, Expr right);
+ // signed left divided by right i.e. left/right
+ Expr vc_sbvDivExpr(VC vc, int n_bits, Expr left, Expr right);
+ // signed left modulo right i.e. left%right
+ Expr vc_sbvModExpr(VC vc, int n_bits, Expr left, Expr right);
+
+ Expr vc_bvLtExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvLeExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvGtExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvGeExpr(VC vc, Expr left, Expr right);
+
+ Expr vc_sbvLtExpr(VC vc, Expr left, Expr right);
+ Expr vc_sbvLeExpr(VC vc, Expr left, Expr right);
+ Expr vc_sbvGtExpr(VC vc, Expr left, Expr right);
+ Expr vc_sbvGeExpr(VC vc, Expr left, Expr right);
+
+ Expr vc_bvUMinusExpr(VC vc, Expr child);
+
+ // bitwise operations: these are terms not formulas
+ Expr vc_bvAndExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvOrExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvXorExpr(VC vc, Expr left, Expr right);
+ Expr vc_bvNotExpr(VC vc, Expr child);
+
+ Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr child);
+ Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr child);
+ /* Same as vc_bvLeftShift only that the answer in 32 bits long */
+ Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child);
+ /* Same as vc_bvRightShift only that the answer in 32 bits long */
+ Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child);
+ Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child);
+ Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child);
+ Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs);
+
+ Expr vc_bvExtract(VC vc, Expr child, int high_bit_no, int low_bit_no);
+
+ //accepts a bitvector and position, and returns a boolean
+ //corresponding to that position. More precisely, it return the
+ //equation (x[bit_no:bit_no] = 0)
+ //FIXME = 1 ?
+ Expr vc_bvBoolExtract(VC vc, Expr x, int bit_no);
+ Expr vc_bvSignExtend(VC vc, Expr child, int nbits);
+
+ /*C pointer support: C interface to support C memory arrays in CVCL */
+ Expr vc_bvCreateMemoryArray(VC vc, char * arrayName);
+ Expr vc_bvReadMemoryArray(VC vc,
+ Expr array, Expr byteIndex, int numOfBytes);
+ Expr vc_bvWriteToMemoryArray(VC vc,
+ Expr array, Expr byteIndex,
+ Expr element, int numOfBytes);
+ Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value);
+
+ // return a string representation of the Expr e. The caller is responsible
+ // for deallocating the string with free()
+ char* exprString(Expr e);
+
+ // return a string representation of the Type t. The caller is responsible
+ // for deallocating the string with free()
+ char* typeString(Type t);
+
+ Expr getChild(Expr e, int i);
+
+ //1.if input expr is TRUE then the function returns 1;
+ //
+ //2.if input expr is FALSE then function returns 0;
+ //
+ //3.otherwise the function returns -1
+ int vc_isBool(Expr e);
+
+ /* Register the given error handler to be called for each fatal error.*/
+ void vc_registerErrorHandler(void (*error_hdlr)(const char* err_msg));
+
+ int vc_getHashQueryStateToBuffer(VC vc, Expr query);
+
+ //destroys the STP instance, and removes all the created expressions
+ void vc_Destroy(VC vc);
+
+ //deletes the expression e
+ void vc_DeleteExpr(Expr e);
+
+ //Get the whole counterexample from the current context
+ WholeCounterExample vc_getWholeCounterExample(VC vc);
+
+ //Get the value of a term expression from the CounterExample
+ Expr vc_getTermFromCounterExample(VC vc, Expr e, WholeCounterExample c);
+
+ //Kinds of Expr
+ enum exprkind_t{
+ UNDEFINED,
+ SYMBOL,
+ BVCONST,
+ BVNEG,
+ BVCONCAT,
+ BVOR,
+ BVAND,
+ BVXOR,
+ BVNAND,
+ BVNOR,
+ BVXNOR,
+ BVEXTRACT,
+ BVLEFTSHIFT,
+ BVRIGHTSHIFT,
+ BVSRSHIFT,
+ BVVARSHIFT,
+ BVPLUS,
+ BVSUB,
+ BVUMINUS,
+ BVMULTINVERSE,
+ BVMULT,
+ BVDIV,
+ BVMOD,
+ SBVDIV,
+ SBVMOD,
+ BVSX,
+ BOOLVEC,
+ ITE,
+ BVGETBIT,
+ BVLT,
+ BVLE,
+ BVGT,
+ BVGE,
+ BVSLT,
+ BVSLE,
+ BVSGT,
+ BVSGE,
+ EQ,
+ NEQ,
+ FALSE,
+ TRUE,
+ NOT,
+ AND,
+ OR,
+ NAND,
+ NOR,
+ XOR,
+ IFF,
+ IMPLIES,
+ READ,
+ WRITE,
+ ARRAY,
+ BITVECTOR,
+ BOOLEAN
+ };
+
+ // type of expression
+ enum type_t {
+ BOOLEAN_TYPE = 0,
+ BITVECTOR_TYPE,
+ ARRAY_TYPE,
+ UNKNOWN_TYPE
+ };
+
+ // get the kind of the expression
+ exprkind_t getExprKind (Expr e);
+
+ // get the number of children nodes
+ int getDegree (Expr e);
+
+ // get the bv length
+ int getBVLength(Expr e);
+
+ // get expression type
+ type_t getType (Expr e);
+
+ // get value bit width
+ int getVWidth (Expr e);
+
+ // get index bit width
+ int getIWidth (Expr e);
+
+ // Prints counterexample to an open file descriptor 'fd'
+ void vc_printCounterExampleFile(VC vc, int fd);
+
+ // get name of expression. must be a variable.
+ const char* exprName(Expr e);
+
+ // get the node ID of an Expr.
+ int getExprID (Expr ex);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
Added: klee/trunk/stp/c_interface/fdstream.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/c_interface/fdstream.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/c_interface/fdstream.h (added)
+++ klee/trunk/stp/c_interface/fdstream.h Wed May 20 23:36:41 2009
@@ -0,0 +1,186 @@
+/*! @brief The following code declares classes to read from and write to
+ * file descriptore or file handles.
+ *
+ * See
+ * http://www.josuttis.com/cppcode
+ * for details and the latest version.
+ *
+ * - open:
+ * - integrating BUFSIZ on some systems?
+ * - optimized reading of multiple characters
+ * - stream for reading AND writing
+ * - i18n
+ *
+ * (C) Copyright Nicolai M. Josuttis 2001.
+ * Permission to copy, use, modify, sell and distribute this software
+ * is granted provided this copyright notice appears in all copies.
+ * This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ *
+ * Version: Jul 28, 2002
+ * History:
+ * Jul 28, 2002: bugfix memcpy() => memmove()
+ * fdinbuf::underflow(): cast for return statements
+ * Aug 05, 2001: first public version
+ */
+#ifndef BOOST_FDSTREAM_HPP
+#define BOOST_FDSTREAM_HPP
+
+#include <istream>
+#include <ostream>
+#include <streambuf>
+
+
+// for EOF:
+#include <cstdio>
+// for memmove():
+#include <cstring>
+
+
+// low-level read and write functions
+#ifdef _MSC_VER
+# include <io.h>
+#else
+# include <unistd.h>
+//extern "C" {
+// int write (int fd, const char* buf, int num);
+// int read (int fd, char* buf, int num);
+//}
+#endif
+
+
+// BEGIN namespace BOOST
+namespace std {
+
+
+/************************************************************
+ * fdostream
+ * - a stream that writes on a file descriptor
+ ************************************************************/
+
+
+class fdoutbuf : public std::streambuf {
+ protected:
+ int fd; // file descriptor
+ public:
+ // constructor
+ fdoutbuf (int _fd) : fd(_fd) {
+ }
+ protected:
+ // write one character
+ virtual int_type overflow (int_type c) {
+ if (c != EOF) {
+ char z = c;
+ if (write (fd, &z, 1) != 1) {
+ return EOF;
+ }
+ }
+ return c;
+ }
+ // write multiple characters
+ virtual
+ std::streamsize xsputn (const char* s,
+ std::streamsize num) {
+ return write(fd,s,num);
+ }
+};
+
+class fdostream : public std::ostream {
+ protected:
+ fdoutbuf buf;
+ public:
+ fdostream (int fd) : std::ostream(0), buf(fd) {
+ rdbuf(&buf);
+ }
+};
+
+
+/************************************************************
+ * fdistream
+ * - a stream that reads on a file descriptor
+ ************************************************************/
+
+class fdinbuf : public std::streambuf {
+ protected:
+ int fd; // file descriptor
+ protected:
+ /* data buffer:
+ * - at most, pbSize characters in putback area plus
+ * - at most, bufSize characters in ordinary read buffer
+ */
+ static const int pbSize = 4; // size of putback area
+ static const int bufSize = 1024; // size of the data buffer
+ char buffer[bufSize+pbSize]; // data buffer
+
+ public:
+ /* constructor
+ * - initialize file descriptor
+ * - initialize empty data buffer
+ * - no putback area
+ * => force underflow()
+ */
+ fdinbuf (int _fd) : fd(_fd) {
+ setg (buffer+pbSize, // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize); // end position
+ }
+
+ protected:
+ // insert new characters into the buffer
+ virtual int_type underflow () {
+#ifndef _MSC_VER
+ using std::memmove;
+#endif
+
+ // is read position before end of buffer?
+ if (gptr() < egptr()) {
+ return traits_type::to_int_type(*gptr());
+ }
+
+ /* process size of putback area
+ * - use number of characters read
+ * - but at most size of putback area
+ */
+ int numPutback;
+ numPutback = gptr() - eback();
+ if (numPutback > pbSize) {
+ numPutback = pbSize;
+ }
+
+ /* copy up to pbSize characters previously read into
+ * the putback area
+ */
+ memmove (buffer+(pbSize-numPutback), gptr()-numPutback,
+ numPutback);
+
+ // read at most bufSize new characters
+ int num;
+ num = read (fd, buffer+pbSize, bufSize);
+ if (num <= 0) {
+ // ERROR or EOF
+ return EOF;
+ }
+
+ // reset buffer pointers
+ setg (buffer+(pbSize-numPutback), // beginning of putback area
+ buffer+pbSize, // read position
+ buffer+pbSize+num); // end of buffer
+
+ // return next character
+ return traits_type::to_int_type(*gptr());
+ }
+};
+
+class fdistream : public std::istream {
+ protected:
+ fdinbuf buf;
+ public:
+ fdistream (int fd) : std::istream(0), buf(fd) {
+ rdbuf(&buf);
+ }
+};
+
+
+} // END namespace boost
+
+#endif /*BOOST_FDSTREAM_HPP*/
Added: klee/trunk/stp/constantbv/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/constantbv/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/constantbv/Makefile (added)
+++ klee/trunk/stp/constantbv/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,13 @@
+include ../Makefile.common
+
+SRCS = constantbv.cpp
+OBJS = $(SRCS:.cpp=.o)
+
+libconstantbv.a: $(OBJS)
+ $(AR) rc $@ $^
+ $(RANLIB) $@
+
+clean:
+ rm -rf *.o *~ *.a .#*
+
+constantbv.o: constantbv.h
Added: klee/trunk/stp/constantbv/constantbv.cpp
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/constantbv/constantbv.cpp?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/constantbv/constantbv.cpp (added)
+++ klee/trunk/stp/constantbv/constantbv.cpp Wed May 20 23:36:41 2009
@@ -0,0 +1,3571 @@
+/*****************************************************************************/
+/* AUTHOR: */
+/*****************************************************************************/
+/* */
+/* Steffen Beyer */
+/* mailto:sb at engelschall.com */
+/* http://www.engelschall.com/u/sb/download/ */
+/* */
+/*****************************************************************************/
+/* COPYRIGHT: */
+/*****************************************************************************/
+/* */
+/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
+/* All rights reserved. */
+/* */
+/*****************************************************************************/
+/* LICENSE: */
+/*****************************************************************************/
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, || (at your option) any later version. */
+/* */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY || FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* Library General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Library General Public */
+/* License along with this library; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/* || download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* MODULE NAME: constantbv.cpp MODULE TYPE:constantbv*/
+/*****************************************************************************/
+/* MODULE IMPORTS: */
+/*****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h> /* MODULE TYPE: (sys) */
+#include <limits.h> /* MODULE TYPE: (sys) */
+#include <string.h> /* MODULE TYPE: (sys) */
+#include <ctype.h> /* MODULE TYPE: (sys) */
+#include "constantbv.h"
+
+namespace CONSTANTBV {
+/*****************************************************************************/
+/* MODULE IMPLEMENTATION: */
+/*****************************************************************************/
+ /**********************************************/
+ /* global implementation-intrinsic constants: */
+ /**********************************************/
+
+#define BIT_VECTOR_HIDDEN_WORDS 3
+
+ /*****************************************************************/
+ /* global machine-dependent constants (set by "BitVector_Boot"): */
+ /*****************************************************************/
+
+static unsigned int BITS; /* = # of bits in machine word (must be power of 2) */
+static unsigned int MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */
+static unsigned int LOGBITS; /* = ld(BITS) (logarithmus dualis) */
+static unsigned int FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */
+
+static unsigned int LSB = 1; /* = mask for least significant bit */
+static unsigned int MSB; /* = mask for most significant bit */
+
+static unsigned int LONGBITS; /* = # of bits in unsigned long */
+
+static unsigned int LOG10; /* = logarithm to base 10 of BITS - 1 */
+static unsigned int EXP10; /* = largest possible power of 10 in signed int */
+
+ /********************************************************************/
+ /* global bit mask table for fast access (set by "BitVector_Boot"): */
+ /********************************************************************/
+
+static unsigned int * BITMASKTAB;
+
+ /*****************************/
+ /* global macro definitions: */
+ /*****************************/
+
+#define BIT_VECTOR_ZERO_WORDS(target,count) \
+ while (count-- > 0) *target++ = 0;
+
+#define BIT_VECTOR_FILL_WORDS(target,fill,count) \
+ while (count-- > 0) *target++ = fill;
+
+#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \
+ while (count-- > 0) *target++ ^= flip;
+
+#define BIT_VECTOR_COPY_WORDS(target,source,count) \
+ while (count-- > 0) *target++ = *source++;
+
+#define BIT_VECTOR_BACK_WORDS(target,source,count) \
+ { target += count; source += count; while (count-- > 0) *--target = *--source; }
+
+#define BIT_VECTOR_CLR_BIT(address,index) \
+ *(address+(index>>LOGBITS)) &= ~ BITMASKTAB[index & MODMASK];
+
+#define BIT_VECTOR_SET_BIT(address,index) \
+ *(address+(index>>LOGBITS)) |= BITMASKTAB[index & MODMASK];
+
+#define BIT_VECTOR_TST_BIT(address,index) \
+ ((*(address+(index>>LOGBITS)) & BITMASKTAB[index & MODMASK]) != 0)
+
+#define BIT_VECTOR_FLP_BIT(address,index,mask) \
+ (mask = BITMASKTAB[index & MODMASK]), \
+ (((*(addr+(index>>LOGBITS)) ^= mask) & mask) != 0)
+
+#define BIT_VECTOR_DIGITIZE(type,value,digit) \
+ value = (type) ((digit = value) / 10); \
+ digit -= value * 10; \
+ digit += (type) '0';
+
+ /*********************************************************/
+ /* private low-level functions (potentially dangerous!): */
+ /*********************************************************/
+
+static unsigned int power10(unsigned int x) {
+ unsigned int y = 1;
+
+ while (x-- > 0) y *= 10;
+ return(y);
+}
+
+static void BIT_VECTOR_zro_words(unsigned int * addr, unsigned int count) {
+ BIT_VECTOR_ZERO_WORDS(addr,count)
+}
+
+static void BIT_VECTOR_cpy_words(unsigned int * target,
+ unsigned int * source, unsigned int count) {
+ BIT_VECTOR_COPY_WORDS(target,source,count)
+}
+
+static void BIT_VECTOR_mov_words(unsigned int * target,
+ unsigned int * source, unsigned int count) {
+ if (target != source) {
+ if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count)
+ else BIT_VECTOR_BACK_WORDS(target,source,count)
+ }
+}
+
+static void BIT_VECTOR_ins_words(unsigned int * addr,
+ unsigned int total, unsigned int count, boolean clear) {
+ unsigned int length;
+
+ if ((total > 0) && (count > 0)) {
+ if (count > total) count = total;
+ length = total - count;
+ if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length);
+ if (clear) BIT_VECTOR_zro_words(addr,count);
+ }
+}
+
+static void BIT_VECTOR_del_words(unsigned int * addr,
+ unsigned int total, unsigned int count, boolean clear) {
+ unsigned int length;
+
+ if ((total > 0) && (count > 0)) {
+ if (count > total) count = total;
+ length = total - count;
+ if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length);
+ if (clear) BIT_VECTOR_zro_words(addr+length,count);
+ }
+}
+
+static void BIT_VECTOR_reverse(unsigned char * string, unsigned int length) {
+ unsigned char * last;
+ unsigned char temp;
+
+ if (length > 1) {
+ last = string + length - 1;
+ while (string < last) {
+ temp = *string;
+ *string = *last;
+ *last = temp;
+ string++;
+ last--;
+ }
+ }
+}
+
+static unsigned int BIT_VECTOR_int2str(unsigned char * string, unsigned int value) {
+ unsigned int length;
+ unsigned int digit;
+ unsigned char * work;
+
+ work = string;
+ if (value > 0) {
+ length = 0;
+ while (value > 0) {
+ BIT_VECTOR_DIGITIZE(unsigned int,value,digit)
+ *work++ = (unsigned char) digit;
+ length++;
+ }
+ BIT_VECTOR_reverse(string,length);
+ }
+ else {
+ length = 1;
+ *work++ = (unsigned char) '0';
+ }
+ return(length);
+}
+
+static unsigned int BIT_VECTOR_str2int(unsigned char * string, unsigned int *value) {
+ unsigned int length;
+ unsigned int digit;
+
+ *value = 0;
+ length = 0;
+ digit = (unsigned int) *string++;
+ /* separate because isdigit() is likely a macro! */
+ while (isdigit((int)digit) != 0) {
+ length++;
+ digit -= (unsigned int) '0';
+ if (*value) *value *= 10;
+ *value += digit;
+ digit = (unsigned int) *string++;
+ }
+ return(length);
+}
+
+ /********************************************/
+ /* routine to convert error code to string: */
+ /********************************************/
+
+unsigned char * BitVector_Error(ErrCode error) {
+ switch (error) {
+ case ErrCode_Ok: return( (unsigned char *) NULL ); break;
+ case ErrCode_Type: return( (unsigned char *) ERRCODE_TYPE ); break;
+ case ErrCode_Bits: return( (unsigned char *) ERRCODE_BITS ); break;
+ case ErrCode_Word: return( (unsigned char *) ERRCODE_WORD ); break;
+ case ErrCode_Long: return( (unsigned char *) ERRCODE_LONG ); break;
+ case ErrCode_Powr: return( (unsigned char *) ERRCODE_POWR ); break;
+ case ErrCode_Loga: return( (unsigned char *) ERRCODE_LOGA ); break;
+ case ErrCode_Null: return( (unsigned char *) ERRCODE_NULL ); break;
+ case ErrCode_Indx: return( (unsigned char *) ERRCODE_INDX ); break;
+ case ErrCode_Ordr: return( (unsigned char *) ERRCODE_ORDR ); break;
+ case ErrCode_Size: return( (unsigned char *) ERRCODE_SIZE ); break;
+ case ErrCode_Pars: return( (unsigned char *) ERRCODE_PARS ); break;
+ case ErrCode_Ovfl: return( (unsigned char *) ERRCODE_OVFL ); break;
+ case ErrCode_Same: return( (unsigned char *) ERRCODE_SAME ); break;
+ case ErrCode_Expo: return( (unsigned char *) ERRCODE_EXPO ); break;
+ case ErrCode_Zero: return( (unsigned char *) ERRCODE_ZERO ); break;
+ default: return( (unsigned char *) ERRCODE_OOPS ); break;
+ }
+}
+
+ /*****************************************/
+ /* automatic self-configuration routine: */
+ /*****************************************/
+
+ /*******************************************************/
+ /* */
+ /* MUST be called once prior to any other function */
+ /* to initialize the machine dependent constants */
+ /* of this package! (But call only ONCE, or you */
+ /* will suffer memory leaks!) */
+ /* */
+ /*******************************************************/
+
+ErrCode BitVector_Boot(void) {
+ unsigned long longsample = 1L;
+ unsigned int sample = LSB;
+ unsigned int lsb;
+
+ if (sizeof(unsigned int) > sizeof(size_t)) return(ErrCode_Type);
+
+ BITS = 1;
+ while (sample <<= 1) BITS++; /* determine # of bits in a machine word */
+
+ if (BITS != (sizeof(unsigned int) << 3)) return(ErrCode_Bits);
+
+ if (BITS < 16) return(ErrCode_Word);
+
+ LONGBITS = 1;
+ while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */
+
+ if (BITS > LONGBITS) return(ErrCode_Long);
+
+ LOGBITS = 0;
+ sample = BITS;
+ lsb = (sample & LSB);
+ while ((sample >>= 1) && (! lsb)) {
+ LOGBITS++;
+ lsb = (sample & LSB);
+ }
+
+ if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */
+
+ if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga);
+
+ MODMASK = BITS - 1;
+ FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */
+ MSB = (LSB << MODMASK);
+
+ BITMASKTAB = (unsigned int * ) malloc((size_t) (BITS << FACTOR));
+
+ if (BITMASKTAB == NULL) return(ErrCode_Null);
+
+ for ( sample = 0; sample < BITS; sample++ ) {
+ BITMASKTAB[sample] = (LSB << sample);
+ }
+
+ LOG10 = (unsigned int) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */
+ EXP10 = power10(LOG10);
+
+ return(ErrCode_Ok);
+}
+
+unsigned int BitVector_Size(unsigned int bits) { /* bit vector size (# of words) */
+ unsigned int size;
+
+ size = bits >> LOGBITS;
+ if (bits & MODMASK) size++;
+ return(size);
+}
+
+unsigned int BitVector_Mask(unsigned int bits) /* bit vector mask (unused bits) */
+{
+ unsigned int mask;
+
+ mask = bits & MODMASK;
+ if (mask) mask = (unsigned int) ~(~0L << mask); else mask = (unsigned int) ~0L;
+ return(mask);
+}
+
+unsigned char * BitVector_Version(void)
+{
+ return((unsigned char *)"6.4");
+}
+
+unsigned int BitVector_Word_Bits(void)
+{
+ return(BITS);
+}
+
+unsigned int BitVector_Long_Bits(void)
+{
+ return(LONGBITS);
+}
+
+/********************************************************************/
+/* */
+/* WARNING: Do not "free()" constant character strings, i.e., */
+/* don't call "BitVector_Dispose()" for strings returned */
+/* by "BitVector_Error()" or "BitVector_Version()"! */
+/* */
+/* ONLY call this function for strings allocated with "malloc()", */
+/* i.e., the strings returned by the functions "BitVector_to_*()" */
+/* and "BitVector_Block_Read()"! */
+/* */
+/********************************************************************/
+
+void BitVector_Dispose(unsigned char * string) /* free string */
+{
+ if (string != NULL) free((void *) string);
+}
+
+void BitVector_Destroy(unsigned int * addr) /* free bitvec */
+{
+ if (addr != NULL)
+ {
+ addr -= BIT_VECTOR_HIDDEN_WORDS;
+ free((void *) addr);
+ }
+}
+
+void BitVector_Destroy_List(unsigned int * * list, unsigned int count) /* free list */
+{
+ unsigned int * * slot;
+
+ if (list != NULL)
+ {
+ slot = list;
+ while (count-- > 0)
+ {
+ BitVector_Destroy(*slot++);
+ }
+ free((void *) list);
+ }
+}
+
+unsigned int * BitVector_Create(unsigned int bits, boolean clear) /* malloc */
+{
+ unsigned int size;
+ unsigned int mask;
+ unsigned int bytes;
+ unsigned int * addr;
+ unsigned int * zero;
+
+ size = BitVector_Size(bits);
+ mask = BitVector_Mask(bits);
+ bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
+ addr = (unsigned int * ) malloc((size_t) bytes);
+ if (addr != NULL)
+ {
+ *addr++ = bits;
+ *addr++ = size;
+ *addr++ = mask;
+ if (clear)
+ {
+ zero = addr;
+ BIT_VECTOR_ZERO_WORDS(zero,size)
+ }
+ }
+ return(addr);
+}
+
+unsigned int * * BitVector_Create_List(unsigned int bits, boolean clear, unsigned int count)
+{
+ unsigned int * * list = NULL;
+ unsigned int * * slot;
+ unsigned int * addr;
+ unsigned int i;
+
+ if (count > 0)
+ {
+ list = (unsigned int * * ) malloc(sizeof(unsigned int * ) * count);
+ if (list != NULL)
+ {
+ slot = list;
+ for ( i = 0; i < count; i++ )
+ {
+ addr = BitVector_Create(bits,clear);
+ if (addr == NULL)
+ {
+ BitVector_Destroy_List(list,i);
+ return(NULL);
+ }
+ *slot++ = addr;
+ }
+ }
+ }
+ return(list);
+}
+
+unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) /* realloc */
+{
+ unsigned int bytes;
+ unsigned int oldsize;
+ unsigned int oldmask;
+ unsigned int newsize;
+ unsigned int newmask;
+ unsigned int * newaddr;
+ unsigned int * source;
+ unsigned int * target;
+
+ oldsize = size_(oldaddr);
+ oldmask = mask_(oldaddr);
+ newsize = BitVector_Size(bits);
+ newmask = BitVector_Mask(bits);
+ if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask;
+ if (newsize <= oldsize)
+ {
+ newaddr = oldaddr;
+ bits_(newaddr) = bits;
+ size_(newaddr) = newsize;
+ mask_(newaddr) = newmask;
+ if (newsize > 0) *(newaddr+newsize-1) &= newmask;
+ }
+ else
+ {
+ bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
+ newaddr = (unsigned int * ) malloc((size_t) bytes);
+ if (newaddr != NULL)
+ {
+ *newaddr++ = bits;
+ *newaddr++ = newsize;
+ *newaddr++ = newmask;
+ target = newaddr;
+ source = oldaddr;
+ newsize -= oldsize;
+ BIT_VECTOR_COPY_WORDS(target,source,oldsize)
+ BIT_VECTOR_ZERO_WORDS(target,newsize)
+ }
+ BitVector_Destroy(oldaddr);
+ }
+ return(newaddr);
+}
+
+unsigned int * BitVector_Shadow(unsigned int * addr) /* makes new, same size but empty */
+{
+ return( BitVector_Create(bits_(addr),true) );
+}
+
+unsigned int * BitVector_Clone(unsigned int * addr) /* makes exact duplicate */
+{
+ unsigned int bits;
+ unsigned int * twin;
+
+ bits = bits_(addr);
+ twin = BitVector_Create(bits,false);
+ if ((twin != NULL) && (bits > 0))
+ BIT_VECTOR_cpy_words(twin,addr,size_(addr));
+ return(twin);
+}
+
+unsigned int * BitVector_Concat(unsigned int * X, unsigned int * Y) /* returns concatenation */
+{
+ /* BEWARE that X = most significant part, Y = least significant part! */
+
+ unsigned int bitsX;
+ unsigned int bitsY;
+ unsigned int bitsZ;
+ unsigned int * Z;
+
+ bitsX = bits_(X);
+ bitsY = bits_(Y);
+ bitsZ = bitsX + bitsY;
+ Z = BitVector_Create(bitsZ,false);
+ if ((Z != NULL) && (bitsZ > 0))
+ {
+ BIT_VECTOR_cpy_words(Z,Y,size_(Y));
+ BitVector_Interval_Copy(Z,X,bitsY,0,bitsX);
+ *(Z+size_(Z)-1) &= mask_(Z);
+ }
+ return(Z);
+}
+
+void BitVector_Copy(unsigned int * X, unsigned int * Y) /* X = Y */
+{
+ unsigned int sizeX = size_(X);
+ unsigned int sizeY = size_(Y);
+ unsigned int maskX = mask_(X);
+ unsigned int maskY = mask_(Y);
+ unsigned int fill = 0;
+ unsigned int * lastX;
+ unsigned int * lastY;
+
+ if ((X != Y) && (sizeX > 0))
+ {
+ lastX = X + sizeX - 1;
+ if (sizeY > 0)
+ {
+ lastY = Y + sizeY - 1;
+ if ( (*lastY & (maskY & ~ (maskY >> 1))) == 0 ) *lastY &= maskY;
+ else
+ {
+ fill = (unsigned int) ~0L;
+ *lastY |= ~ maskY;
+ }
+ while ((sizeX > 0) && (sizeY > 0))
+ {
+ *X++ = *Y++;
+ sizeX--;
+ sizeY--;
+ }
+ *lastY &= maskY;
+ }
+ while (sizeX-- > 0) *X++ = fill;
+ *lastX &= maskX;
+ }
+}
+
+void BitVector_Empty(unsigned int * addr) /* X = {} clr all */
+{
+ unsigned int size = size_(addr);
+
+ BIT_VECTOR_ZERO_WORDS(addr,size)
+}
+
+void BitVector_Fill(unsigned int * addr) /* X = ~{} set all */
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int fill = (unsigned int) ~0L;
+
+ if (size > 0)
+ {
+ BIT_VECTOR_FILL_WORDS(addr,fill,size)
+ *(--addr) &= mask;
+ }
+}
+
+void BitVector_Flip(unsigned int * addr) /* X = ~X flip all */
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int flip = (unsigned int) ~0L;
+
+ if (size > 0)
+ {
+ BIT_VECTOR_FLIP_WORDS(addr,flip,size)
+ *(--addr) &= mask;
+ }
+}
+
+void BitVector_Primes(unsigned int * addr)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int * work;
+ unsigned int temp;
+ unsigned int i,j;
+
+ if (size > 0)
+ {
+ temp = 0xAAAA;
+ i = BITS >> 4;
+ while (--i > 0)
+ {
+ temp <<= 16;
+ temp |= 0xAAAA;
+ }
+ i = size;
+ work = addr;
+ *work++ = temp ^ 0x0006;
+ while (--i > 0) *work++ = temp;
+ for ( i = 3; (j = i * i) < bits; i += 2 )
+ {
+ for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j)
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Reverse(unsigned int * X, unsigned int * Y)
+{
+ unsigned int bits = bits_(X);
+ unsigned int mask;
+ unsigned int bit;
+ unsigned int value;
+
+ if (bits > 0)
+ {
+ if (X == Y) BitVector_Interval_Reverse(X,0,bits-1);
+ else if (bits == bits_(Y))
+ {
+/* mask = mask_(Y); */
+/* mask &= ~ (mask >> 1); */
+ mask = BITMASKTAB[(bits-1) & MODMASK];
+ Y += size_(Y) - 1;
+ value = 0;
+ bit = LSB;
+ while (bits-- > 0)
+ {
+ if ((*Y & mask) != 0)
+ {
+ value |= bit;
+ }
+ if (! (mask >>= 1))
+ {
+ Y--;
+ mask = MSB;
+ }
+ if (! (bit <<= 1))
+ {
+ *X++ = value;
+ value = 0;
+ bit = LSB;
+ }
+ }
+ if (bit > LSB) *X = value;
+ }
+ }
+}
+
+void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned int upper)
+{ /* X = X \ [lower..upper] */
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int * loaddr;
+ unsigned int * hiaddr;
+ unsigned int lobase;
+ unsigned int hibase;
+ unsigned int lomask;
+ unsigned int himask;
+ unsigned int diff;
+
+ if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (unsigned int) (~0L << (lower & MODMASK));
+ himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr &= ~ (lomask & himask);
+ }
+ else
+ {
+ *loaddr++ &= ~ lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ = 0;
+ }
+ *hiaddr &= ~ himask;
+ }
+ }
+}
+
+void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned int upper)
+{ /* X = X + [lower..upper] */
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int fill = (unsigned int) ~0L;
+ unsigned int * loaddr;
+ unsigned int * hiaddr;
+ unsigned int lobase;
+ unsigned int hibase;
+ unsigned int lomask;
+ unsigned int himask;
+ unsigned int diff;
+
+ if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (unsigned int) (~0L << (lower & MODMASK));
+ himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr |= (lomask & himask);
+ }
+ else
+ {
+ *loaddr++ |= lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ = fill;
+ }
+ *hiaddr |= himask;
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned int upper)
+{ /* X = X ^ [lower..upper] */
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int flip = (unsigned int) ~0L;
+ unsigned int * loaddr;
+ unsigned int * hiaddr;
+ unsigned int lobase;
+ unsigned int hibase;
+ unsigned int lomask;
+ unsigned int himask;
+ unsigned int diff;
+
+ if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
+ {
+ lobase = lower >> LOGBITS;
+ hibase = upper >> LOGBITS;
+ diff = hibase - lobase;
+ loaddr = addr + lobase;
+ hiaddr = addr + hibase;
+
+ lomask = (unsigned int) (~0L << (lower & MODMASK));
+ himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1);
+
+ if (diff == 0)
+ {
+ *loaddr ^= (lomask & himask);
+ }
+ else
+ {
+ *loaddr++ ^= lomask;
+ while (--diff > 0)
+ {
+ *loaddr++ ^= flip;
+ }
+ *hiaddr ^= himask;
+ }
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+void BitVector_Interval_Reverse(unsigned int * addr, unsigned int lower, unsigned int upper)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int * loaddr;
+ unsigned int * hiaddr;
+ unsigned int lomask;
+ unsigned int himask;
+
+ if ((bits > 0) && (lower < bits) && (upper < bits) && (lower < upper))
+ {
+ loaddr = addr + (lower >> LOGBITS);
+ hiaddr = addr + (upper >> LOGBITS);
+ lomask = BITMASKTAB[lower & MODMASK];
+ himask = BITMASKTAB[upper & MODMASK];
+ for ( bits = upper - lower + 1; bits > 1; bits -= 2 )
+ {
+ if (((*loaddr & lomask) != 0) ^ ((*hiaddr & himask) != 0))
+ {
+ *loaddr ^= lomask; /* swap bits only if they differ! */
+ *hiaddr ^= himask;
+ }
+ if (! (lomask <<= 1))
+ {
+ lomask = LSB;
+ loaddr++;
+ }
+ if (! (himask >>= 1))
+ {
+ himask = MSB;
+ hiaddr--;
+ }
+ }
+ }
+}
+
+boolean BitVector_interval_scan_inc(unsigned int * addr, unsigned int start,
+ unsigned int * min, unsigned int * max)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int offset;
+ unsigned int bitmask;
+ unsigned int value;
+ boolean empty;
+
+ if ((size == 0) || (start >= bits_(addr))) return(false);
+
+ *min = start;
+ *max = start;
+
+ offset = start >> LOGBITS;
+
+ *(addr+size-1) &= mask;
+
+ addr += offset;
+ size -= offset;
+
+ bitmask = BITMASKTAB[start & MODMASK];
+ mask = ~ (bitmask | (bitmask - 1));
+
+ value = *addr++;
+ if ((value & bitmask) == 0)
+ {
+ value &= mask;
+ if (value == 0)
+ {
+ offset++;
+ empty = true;
+ while (empty && (--size > 0))
+ {
+ if ((value = *addr++)) empty = false; else offset++;
+ }
+ if (empty) return(false);
+ }
+ start = offset << LOGBITS;
+ bitmask = LSB;
+ mask = value;
+ while (! (mask & LSB))
+ {
+ bitmask <<= 1;
+ mask >>= 1;
+ start++;
+ }
+ mask = ~ (bitmask | (bitmask - 1));
+ *min = start;
+ *max = start;
+ }
+ value = ~ value;
+ value &= mask;
+ if (value == 0)
+ {
+ offset++;
+ empty = true;
+ while (empty && (--size > 0))
+ {
+ if ((value = ~ *addr++)) empty = false; else offset++;
+ }
+ if (empty) value = LSB;
+ }
+ start = offset << LOGBITS;
+ while (! (value & LSB))
+ {
+ value >>= 1;
+ start++;
+ }
+ *max = --start;
+ return(true);
+}
+
+boolean BitVector_interval_scan_dec(unsigned int * addr, unsigned int start,
+ unsigned int * min, unsigned int * max)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int offset;
+ unsigned int bitmask;
+ unsigned int value;
+ boolean empty;
+
+ if ((size == 0) || (start >= bits_(addr))) return(false);
+
+ *min = start;
+ *max = start;
+
+ offset = start >> LOGBITS;
+
+ if (offset >= size) return(false);
+
+ *(addr+size-1) &= mask;
+
+ addr += offset;
+ size = ++offset;
+
+ bitmask = BITMASKTAB[start & MODMASK];
+ mask = (bitmask - 1);
+
+ value = *addr--;
+ if ((value & bitmask) == 0)
+ {
+ value &= mask;
+ if (value == 0)
+ {
+ offset--;
+ empty = true;
+ while (empty && (--size > 0))
+ {
+ if ((value = *addr--)) empty = false; else offset--;
+ }
+ if (empty) return(false);
+ }
+ start = offset << LOGBITS;
+ bitmask = MSB;
+ mask = value;
+ while (! (mask & MSB))
+ {
+ bitmask >>= 1;
+ mask <<= 1;
+ start--;
+ }
+ mask = (bitmask - 1);
+ *max = --start;
+ *min = start;
+ }
+ value = ~ value;
+ value &= mask;
+ if (value == 0)
+ {
+ offset--;
+ empty = true;
+ while (empty && (--size > 0))
+ {
+ if ((value = ~ *addr--)) empty = false; else offset--;
+ }
+ if (empty) value = MSB;
+ }
+ start = offset << LOGBITS;
+ while (! (value & MSB))
+ {
+ value <<= 1;
+ start--;
+ }
+ *min = start;
+ return(true);
+}
+
+void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int Xoffset,
+ unsigned int Yoffset, unsigned int length)
+{
+ unsigned int bitsX = bits_(X);
+ unsigned int bitsY = bits_(Y);
+ unsigned int source = 0; /* silence compiler warning */
+ unsigned int target = 0; /* silence compiler warning */
+ unsigned int s_lo_base;
+ unsigned int s_hi_base;
+ unsigned int s_lo_bit;
+ unsigned int s_hi_bit;
+ unsigned int s_base;
+ unsigned int s_lower = 0; /* silence compiler warning */
+ unsigned int s_upper = 0; /* silence compiler warning */
+ unsigned int s_bits;
+ unsigned int s_min;
+ unsigned int s_max;
+ unsigned int t_lo_base;
+ unsigned int t_hi_base;
+ unsigned int t_lo_bit;
+ unsigned int t_hi_bit;
+ unsigned int t_base;
+ unsigned int t_lower = 0; /* silence compiler warning */
+ unsigned int t_upper = 0; /* silence compiler warning */
+ unsigned int t_bits;
+ unsigned int t_min;
+ unsigned int mask;
+ unsigned int bits;
+ unsigned int select;
+ boolean ascending;
+ boolean notfirst;
+ unsigned int * Z = X;
+
+ if ((length > 0) && (Xoffset < bitsX) && (Yoffset < bitsY))
+ {
+ if ((Xoffset + length) > bitsX) length = bitsX - Xoffset;
+ if ((Yoffset + length) > bitsY) length = bitsY - Yoffset;
+
+ ascending = (Xoffset <= Yoffset);
+
+ s_lo_base = Yoffset >> LOGBITS;
+ s_lo_bit = Yoffset & MODMASK;
+ Yoffset += --length;
+ s_hi_base = Yoffset >> LOGBITS;
+ s_hi_bit = Yoffset & MODMASK;
+
+ t_lo_base = Xoffset >> LOGBITS;
+ t_lo_bit = Xoffset & MODMASK;
+ Xoffset += length;
+ t_hi_base = Xoffset >> LOGBITS;
+ t_hi_bit = Xoffset & MODMASK;
+
+ if (ascending)
+ {
+ s_base = s_lo_base;
+ t_base = t_lo_base;
+ }
+ else
+ {
+ s_base = s_hi_base;
+ t_base = t_hi_base;
+ }
+ s_bits = 0;
+ t_bits = 0;
+ Y += s_base;
+ X += t_base;
+ notfirst = false;
+ while (true)
+ {
+ if (t_bits == 0)
+ {
+ if (notfirst)
+ {
+ *X = target;
+ if (ascending)
+ {
+ if (t_base == t_hi_base) break;
+ t_base++;
+ X++;
+ }
+ else
+ {
+ if (t_base == t_lo_base) break;
+ t_base--;
+ X--;
+ }
+ }
+ select = ((t_base == t_hi_base) << 1) | (t_base == t_lo_base);
+ switch (select)
+ {
+ case 0:
+ t_lower = 0;
+ t_upper = BITS - 1;
+ t_bits = BITS;
+ target = 0;
+ break;
+ case 1:
+ t_lower = t_lo_bit;
+ t_upper = BITS - 1;
+ t_bits = BITS - t_lo_bit;
+ mask = (unsigned int) (~0L << t_lower);
+ target = *X & ~ mask;
+ break;
+ case 2:
+ t_lower = 0;
+ t_upper = t_hi_bit;
+ t_bits = t_hi_bit + 1;
+ mask = (unsigned int) ((~0L << t_upper) << 1);
+ target = *X & mask;
+ break;
+ case 3:
+ t_lower = t_lo_bit;
+ t_upper = t_hi_bit;
+ t_bits = t_hi_bit - t_lo_bit + 1;
+ mask = (unsigned int) (~0L << t_lower);
+ mask &= (unsigned int) ~((~0L << t_upper) << 1);
+ target = *X & ~ mask;
+ break;
+ }
+ }
+ if (s_bits == 0)
+ {
+ if (notfirst)
+ {
+ if (ascending)
+ {
+ if (s_base == s_hi_base) break;
+ s_base++;
+ Y++;
+ }
+ else
+ {
+ if (s_base == s_lo_base) break;
+ s_base--;
+ Y--;
+ }
+ }
+ source = *Y;
+ select = ((s_base == s_hi_base) << 1) | (s_base == s_lo_base);
+ switch (select)
+ {
+ case 0:
+ s_lower = 0;
+ s_upper = BITS - 1;
+ s_bits = BITS;
+ break;
+ case 1:
+ s_lower = s_lo_bit;
+ s_upper = BITS - 1;
+ s_bits = BITS - s_lo_bit;
+ break;
+ case 2:
+ s_lower = 0;
+ s_upper = s_hi_bit;
+ s_bits = s_hi_bit + 1;
+ break;
+ case 3:
+ s_lower = s_lo_bit;
+ s_upper = s_hi_bit;
+ s_bits = s_hi_bit - s_lo_bit + 1;
+ break;
+ }
+ }
+ notfirst = true;
+ if (s_bits > t_bits)
+ {
+ bits = t_bits - 1;
+ if (ascending)
+ {
+ s_min = s_lower;
+ s_max = s_lower + bits;
+ }
+ else
+ {
+ s_max = s_upper;
+ s_min = s_upper - bits;
+ }
+ t_min = t_lower;
+ }
+ else
+ {
+ bits = s_bits - 1;
+ if (ascending) t_min = t_lower;
+ else t_min = t_upper - bits;
+ s_min = s_lower;
+ s_max = s_upper;
+ }
+ bits++;
+ mask = (unsigned int) (~0L << s_min);
+ mask &= (unsigned int) ~((~0L << s_max) << 1);
+ if (s_min == t_min) target |= (source & mask);
+ else
+ {
+ if (s_min < t_min) target |= (source & mask) << (t_min-s_min);
+ else target |= (source & mask) >> (s_min-t_min);
+ }
+ if (ascending)
+ {
+ s_lower += bits;
+ t_lower += bits;
+ }
+ else
+ {
+ s_upper -= bits;
+ t_upper -= bits;
+ }
+ s_bits -= bits;
+ t_bits -= bits;
+ }
+ *(Z+size_(Z)-1) &= mask_(Z);
+ }
+}
+
+
+unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y,
+ unsigned int Xoffset, unsigned int Xlength,
+ unsigned int Yoffset, unsigned int Ylength)
+{
+ unsigned int Xbits = bits_(X);
+ unsigned int Ybits = bits_(Y);
+ unsigned int limit;
+ unsigned int diff;
+
+ if ((Xoffset <= Xbits) && (Yoffset <= Ybits))
+ {
+ limit = Xoffset + Xlength;
+ if (limit > Xbits)
+ {
+ limit = Xbits;
+ Xlength = Xbits - Xoffset;
+ }
+ if ((Yoffset + Ylength) > Ybits)
+ {
+ Ylength = Ybits - Yoffset;
+ }
+ if (Xlength == Ylength)
+ {
+ if ((Ylength > 0) && ((X != Y) || (Xoffset != Yoffset)))
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ }
+ else /* Xlength != Ylength */
+ {
+ if (Xlength > Ylength)
+ {
+ diff = Xlength - Ylength;
+ if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,false);
+ if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL);
+ }
+ else /* Ylength > Xlength ==> Ylength > 0 */
+ {
+ diff = Ylength - Xlength;
+ if (X != Y)
+ {
+ if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
+ if (limit < Xbits) BitVector_Insert(X,limit,diff,false);
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* in-place */
+ {
+ if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
+ if (limit >= Xbits)
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* limit < Xbits */
+ {
+ BitVector_Insert(X,limit,diff,false);
+ if ((Yoffset+Ylength) <= limit)
+ {
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* overlaps or lies above critical area */
+ {
+ if (limit <= Yoffset)
+ {
+ Yoffset += diff;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ else /* Yoffset < limit */
+ {
+ Xlength = limit - Yoffset;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength);
+ Yoffset = Xoffset + Ylength; /* = limit + diff */
+ Xoffset += Xlength;
+ Ylength -= Xlength;
+ BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return(X);
+}
+
+boolean BitVector_is_empty(unsigned int * addr) /* X == {} ? */
+{
+ unsigned int size = size_(addr);
+ boolean r = true;
+
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (r && (size-- > 0)) r = ( *addr++ == 0 );
+ }
+ return(r);
+}
+
+boolean BitVector_is_full(unsigned int * addr) /* X == ~{} ? */
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ boolean r = false;
+ unsigned int * last;
+
+ if (size > 0)
+ {
+ r = true;
+ last = addr + size - 1;
+ *last |= ~ mask;
+ while (r && (size-- > 0)) r = ( ~ *addr++ == 0 );
+ *last &= mask;
+ }
+ return(r);
+}
+
+boolean BitVector_equal(unsigned int * X, unsigned int * Y) /* X == Y ? */
+{
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+ boolean r = false;
+
+ if (bits_(X) == bits_(Y))
+ {
+ r = true;
+ if (size > 0)
+ {
+ *(X+size-1) &= mask;
+ *(Y+size-1) &= mask;
+ while (r && (size-- > 0)) r = (*X++ == *Y++);
+ }
+ }
+ return(r);
+}
+
+/* X <,=,> Y ? : unsigned */
+signed int BitVector_Lexicompare(unsigned int * X, unsigned int * Y) {
+ unsigned int bitsX = bits_(X);
+ unsigned int bitsY = bits_(Y);
+ unsigned int size = size_(X);
+ boolean r = true;
+
+ if (bitsX == bitsY) {
+ if (size > 0) {
+ X += size;
+ Y += size;
+ while (r && (size-- > 0)) r = (*(--X) == *(--Y));
+ }
+ if (r) return((signed int) 0);
+ else {
+ if (*X < *Y) return((signed int) -1); else return((signed int) 1);
+ }
+ }
+ else {
+ if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1);
+ }
+}
+
+signed int BitVector_Compare(unsigned int * X, unsigned int * Y) /* X <,=,> Y ? */
+{ /* signed */
+ unsigned int bitsX = bits_(X);
+ unsigned int bitsY = bits_(Y);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+ unsigned int sign;
+ boolean r = true;
+
+ if (bitsX == bitsY)
+ {
+ if (size > 0)
+ {
+ X += size;
+ Y += size;
+ mask &= ~ (mask >> 1);
+ if ((sign = (*(X-1) & mask)) != (*(Y-1) & mask))
+ {
+ if (sign) return((signed int) -1); else return((signed int) 1);
+ }
+ while (r && (size-- > 0)) r = (*(--X) == *(--Y));
+ }
+ if (r) return((signed int) 0);
+ else
+ {
+ if (*X < *Y) return((signed int) -1); else return((signed int) 1);
+ }
+ }
+ else
+ {
+ if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1);
+ }
+}
+
+size_t BitVector_Hash(unsigned int * addr)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int value;
+ unsigned int count;
+ unsigned int digit;
+ unsigned int length;
+
+ size_t result = 0;
+
+ length = bits >> 2;
+ if (bits & 0x0003) length++;
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while ((size-- > 0) && (length > 0))
+ {
+ value = *addr++;
+ count = BITS >> 2;
+ while ((count-- > 0) && (length > 0))
+ {
+ digit = value & 0x000F;
+ if (digit > 9) digit += (unsigned int) 'A' - 10;
+ else digit += (unsigned int) '0';
+ result = 5*result + digit; length--;
+ if ((count > 0) && (length > 0)) value >>= 4;
+ }
+ }
+ }
+ return result;
+}
+
+
+unsigned char * BitVector_to_Hex(unsigned int * addr)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int size = size_(addr);
+ unsigned int value;
+ unsigned int count;
+ unsigned int digit;
+ unsigned int length;
+ unsigned char * string;
+
+ length = bits >> 2;
+ if (bits & 0x0003) length++;
+ string = (unsigned char *) malloc((size_t) (length+1));
+ if (string == NULL) return(NULL);
+ string += length;
+ *string = (unsigned char) '\0';
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while ((size-- > 0) && (length > 0))
+ {
+ value = *addr++;
+ count = BITS >> 2;
+ while ((count-- > 0) && (length > 0))
+ {
+ digit = value & 0x000F;
+ if (digit > 9) digit += (unsigned int) 'A' - 10;
+ else digit += (unsigned int) '0';
+ *(--string) = (unsigned char) digit; length--;
+ if ((count > 0) && (length > 0)) value >>= 4;
+ }
+ }
+ }
+ return(string);
+}
+
+ErrCode BitVector_from_Hex(unsigned int * addr, unsigned char * string)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ boolean ok = true;
+ unsigned int length;
+ unsigned int value;
+ unsigned int count;
+ int digit;
+
+ if (size > 0)
+ {
+ length = strlen((char *) string);
+ string += length;
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (ok && (length > 0) && (count < BITS)); count += 4 )
+ {
+ digit = (int) *(--string); length--;
+ /* separate because toupper() is likely a macro! */
+ digit = toupper(digit);
+ if ((ok = (isxdigit(digit) != 0)))
+ {
+ if (digit >= (int) 'A') digit -= (int) 'A' - 10;
+ else digit -= (int) '0';
+ value |= (((unsigned int) digit) << count);
+ }
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+ if (ok) return(ErrCode_Ok);
+ else return(ErrCode_Pars);
+}
+
+unsigned char * BitVector_to_Bin(unsigned int * addr)
+{
+ unsigned int size = size_(addr);
+ unsigned int value;
+ unsigned int count;
+ unsigned int digit;
+ unsigned int length;
+ unsigned char * string;
+
+ length = bits_(addr);
+ string = (unsigned char *) malloc((size_t) (length+1));
+ if (string == NULL) return(NULL);
+ string += length;
+ *string = (unsigned char) '\0';
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (size-- > 0)
+ {
+ value = *addr++;
+ count = BITS;
+ if (count > length) count = length;
+ while (count-- > 0)
+ {
+ digit = value & 0x0001;
+ digit += (unsigned int) '0';
+ *(--string) = (unsigned char) digit; length--;
+ if (count > 0) value >>= 1;
+ }
+ }
+ }
+ return(string);
+}
+
+ErrCode BitVector_from_Bin(unsigned int * addr, unsigned char * string)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ boolean ok = true;
+ unsigned int length;
+ unsigned int value;
+ unsigned int count;
+ int digit;
+
+ if (size > 0)
+ {
+ length = strlen((char *) string);
+ string += length;
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (ok && (length > 0) && (count < BITS)); count++ )
+ {
+ digit = (int) *(--string); length--;
+ switch (digit)
+ {
+ case (int) '0':
+ break;
+ case (int) '1':
+ value |= BITMASKTAB[count];
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+ if (ok) return(ErrCode_Ok);
+ else return(ErrCode_Pars);
+}
+
+unsigned char * BitVector_to_Dec(unsigned int * addr)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int length;
+ unsigned int digits;
+ unsigned int count;
+ unsigned int q;
+ unsigned int r;
+ boolean loop;
+ unsigned char * result;
+ unsigned char * string;
+ unsigned int * quot;
+ unsigned int * rest;
+ unsigned int * temp;
+ unsigned int * base;
+ signed int sign;
+
+ length = (unsigned int) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */
+ length += 2; /* compensate for truncating & provide space for minus sign */
+ result = (unsigned char *) malloc((size_t) (length+1)); /* remember the '\0'! */
+ if (result == NULL) return(NULL);
+ string = result;
+ sign = BitVector_Sign(addr);
+ if ((bits < 4) || (sign == 0))
+ {
+ if (bits > 0) digits = *addr; else digits = (unsigned int) 0;
+ if (sign < 0) digits = ((unsigned int)(-((signed int)digits))) & mask_(addr);
+ *string++ = (unsigned char) digits + (unsigned char) '0';
+ digits = 1;
+ }
+ else
+ {
+ quot = BitVector_Create(bits,false);
+ if (quot == NULL)
+ {
+ BitVector_Dispose(result);
+ return(NULL);
+ }
+ rest = BitVector_Create(bits,false);
+ if (rest == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ return(NULL);
+ }
+ temp = BitVector_Create(bits,false);
+ if (temp == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ return(NULL);
+ }
+ base = BitVector_Create(bits,true);
+ if (base == NULL)
+ {
+ BitVector_Dispose(result);
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ BitVector_Destroy(temp);
+ return(NULL);
+ }
+ if (sign < 0) BitVector_Negate(quot,addr);
+ else BitVector_Copy(quot,addr);
+ digits = 0;
+ *base = EXP10;
+ loop = (bits >= BITS);
+ do
+ {
+ if (loop)
+ {
+ BitVector_Copy(temp,quot);
+ if (BitVector_Div_Pos(quot,temp,base,rest))
+ {
+ BitVector_Dispose(result); /* emergency exit */
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest); /* should never occur */
+ BitVector_Destroy(temp); /* under normal operation */
+ BitVector_Destroy(base);
+ return(NULL);
+ }
+ loop = ! BitVector_is_empty(quot);
+ q = *rest;
+ }
+ else q = *quot;
+ count = LOG10;
+ while (((loop && (count-- > 0)) || ((! loop) && (q != 0))) &&
+ (digits < length))
+ {
+ if (q != 0)
+ {
+ BIT_VECTOR_DIGITIZE(unsigned int,q,r)
+ }
+ else r = (unsigned int) '0';
+ *string++ = (unsigned char) r;
+ digits++;
+ }
+ }
+ while (loop && (digits < length));
+ BitVector_Destroy(quot);
+ BitVector_Destroy(rest);
+ BitVector_Destroy(temp);
+ BitVector_Destroy(base);
+ }
+ if ((sign < 0) && (digits < length))
+ {
+ *string++ = (unsigned char) '-';
+ digits++;
+ }
+ *string = (unsigned char) '\0';
+ BIT_VECTOR_reverse(result,digits);
+ return(result);
+}
+
+ErrCode BitVector_from_Dec(unsigned int * addr, unsigned char * string)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(addr);
+ unsigned int mask = mask_(addr);
+ boolean init = (bits > BITS);
+ boolean minus;
+ boolean shift;
+ boolean carry;
+ unsigned int * term;
+ unsigned int * base;
+ unsigned int * prod;
+ unsigned int * rank;
+ unsigned int * temp;
+ unsigned int accu;
+ unsigned int powr;
+ unsigned int count;
+ unsigned int length;
+ int digit;
+
+ if (bits > 0)
+ {
+ length = strlen((char *) string);
+ if (length == 0) return(ErrCode_Pars);
+ digit = (int) *string;
+ if ((minus = (digit == (int) '-')) ||
+ (digit == (int) '+'))
+ {
+ string++;
+ if (--length == 0) return(ErrCode_Pars);
+ }
+ string += length;
+ term = BitVector_Create(BITS,false);
+ if (term == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ base = BitVector_Create(BITS,false);
+ if (base == NULL)
+ {
+ BitVector_Destroy(term);
+ return(ErrCode_Null);
+ }
+ prod = BitVector_Create(bits,init);
+ if (prod == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ return(ErrCode_Null);
+ }
+ rank = BitVector_Create(bits,init);
+ if (rank == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ return(ErrCode_Null);
+ }
+ temp = BitVector_Create(bits,false);
+ if (temp == NULL)
+ {
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ BitVector_Destroy(rank);
+ return(ErrCode_Null);
+ }
+ BitVector_Empty(addr);
+ *base = EXP10;
+ shift = false;
+ while ((! error) && (length > 0))
+ {
+ accu = 0;
+ powr = 1;
+ count = LOG10;
+ while ((! error) && (length > 0) && (count-- > 0))
+ {
+ digit = (int) *(--string); length--;
+ /* separate because isdigit() is likely a macro! */
+ if (isdigit(digit) != 0)
+ {
+ accu += ((unsigned int) digit - (unsigned int) '0') * powr;
+ powr *= 10;
+ }
+ else error = ErrCode_Pars;
+ }
+ if (! error)
+ {
+ if (shift)
+ {
+ *term = accu;
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(prod,temp,term,false);
+ }
+ else
+ {
+ *prod = accu;
+ if ((! init) && ((accu & ~ mask) != 0)) error = ErrCode_Ovfl;
+ }
+ if (! error)
+ {
+ carry = false;
+ BitVector_compute(addr,addr,prod,false,&carry);
+ /* ignores sign change (= overflow) but ! */
+ /* numbers too large (= carry) for resulting bit vector */
+ if (carry) error = ErrCode_Ovfl;
+ else
+ {
+ if (length > 0)
+ {
+ if (shift)
+ {
+ BitVector_Copy(temp,rank);
+ error = BitVector_Mul_Pos(rank,temp,base,false);
+ }
+ else
+ {
+ *rank = *base;
+ shift = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ BitVector_Destroy(term);
+ BitVector_Destroy(base);
+ BitVector_Destroy(prod);
+ BitVector_Destroy(rank);
+ BitVector_Destroy(temp);
+ if (! error && minus)
+ {
+ BitVector_Negate(addr,addr);
+ if ((*(addr + size_(addr) - 1) & mask & ~ (mask >> 1)) == 0)
+ error = ErrCode_Ovfl;
+ }
+ }
+ return(error);
+}
+
+unsigned char * BitVector_to_Enum(unsigned int * addr)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int sample;
+ unsigned int length;
+ unsigned int digits;
+ unsigned int factor;
+ unsigned int power;
+ unsigned int start;
+ unsigned int min;
+ unsigned int max;
+ unsigned char * string;
+ unsigned char * target;
+ boolean comma;
+
+ if (bits > 0)
+ {
+ sample = bits - 1; /* greatest possible index */
+ length = 2; /* account for index 0 && terminating '\0' */
+ digits = 1; /* account for intervening dashes && commas */
+ factor = 1;
+ power = 10;
+ while (sample >= (power-1))
+ {
+ length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */
+ factor = power;
+ power *= 10;
+ }
+ if (sample > --factor)
+ {
+ sample -= factor;
+ factor = (unsigned int) ( sample / 3 );
+ factor = (factor << 1) + (sample - (factor * 3));
+ length += ++digits * factor;
+ }
+ }
+ else length = 1;
+ string = (unsigned char *) malloc((size_t) length);
+ if (string == NULL) return(NULL);
+ start = 0;
+ comma = false;
+ target = string;
+ while ((start < bits) && BitVector_interval_scan_inc(addr,start,&min,&max))
+ {
+ start = max + 2;
+ if (comma) *target++ = (unsigned char) ',';
+ if (min == max)
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ }
+ else
+ {
+ if (min+1 == max)
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ *target++ = (unsigned char) ',';
+ target += BIT_VECTOR_int2str(target,max);
+ }
+ else
+ {
+ target += BIT_VECTOR_int2str(target,min);
+ *target++ = (unsigned char) '-';
+ target += BIT_VECTOR_int2str(target,max);
+ }
+ }
+ comma = true;
+ }
+ *target = (unsigned char) '\0';
+ return(string);
+}
+
+ErrCode BitVector_from_Enum(unsigned int * addr, unsigned char * string)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(addr);
+ unsigned int state = 1;
+ unsigned int token;
+ unsigned int index = 0;
+ unsigned int start = 0; /* silence compiler warning */
+
+ if (bits > 0)
+ {
+ BitVector_Empty(addr);
+ while ((! error) && (state != 0))
+ {
+ token = (unsigned int) *string;
+ /* separate because isdigit() is likely a macro! */
+ if (isdigit((int)token) != 0)
+ {
+ string += BIT_VECTOR_str2int(string,&index);
+ if (index < bits) token = (unsigned int) '0';
+ else error = ErrCode_Indx;
+ }
+ else string++;
+ if (! error)
+ switch (state)
+ {
+ case 1:
+ switch (token)
+ {
+ case (unsigned int) '0':
+ state = 2;
+ break;
+ case (unsigned int) '\0':
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 2:
+ switch (token)
+ {
+ case (unsigned int) '-':
+ start = index;
+ state = 3;
+ break;
+ case (unsigned int) ',':
+ BIT_VECTOR_SET_BIT(addr,index)
+ state = 5;
+ break;
+ case (unsigned int) '\0':
+ BIT_VECTOR_SET_BIT(addr,index)
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 3:
+ switch (token)
+ {
+ case (unsigned int) '0':
+ if (start < index)
+ BitVector_Interval_Fill(addr,start,index);
+ else if (start == index)
+ BIT_VECTOR_SET_BIT(addr,index)
+ else error = ErrCode_Ordr;
+ state = 4;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 4:
+ switch (token)
+ {
+ case (unsigned int) ',':
+ state = 5;
+ break;
+ case (unsigned int) '\0':
+ state = 0;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ case 5:
+ switch (token)
+ {
+ case (unsigned int) '0':
+ state = 2;
+ break;
+ default:
+ error = ErrCode_Pars;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ return(error);
+}
+
+void BitVector_Bit_Off(unsigned int * addr, unsigned int index) /* X = X \ {x} */
+{
+ if (index < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,index)
+}
+
+void BitVector_Bit_On(unsigned int * addr, unsigned int index) /* X = X + {x} */
+{
+ if (index < bits_(addr)) BIT_VECTOR_SET_BIT(addr,index)
+}
+
+boolean BitVector_bit_flip(unsigned int * addr, unsigned int index) /* X=(X+{x})\(X*{x}) */
+{
+ unsigned int mask;
+
+ if (index < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,index,mask) );
+ else return( false );
+}
+
+boolean BitVector_bit_test(unsigned int * addr, unsigned int index) /* {x} in X ? */
+{
+ if (index < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,index) );
+ else return( false );
+}
+
+void BitVector_Bit_Copy(unsigned int * addr, unsigned int index, boolean bit)
+{
+ if (index < bits_(addr))
+ {
+ if (bit) BIT_VECTOR_SET_BIT(addr,index)
+ else BIT_VECTOR_CLR_BIT(addr,index)
+ }
+}
+
+void BitVector_LSB(unsigned int * addr, boolean bit)
+{
+ if (bits_(addr) > 0)
+ {
+ if (bit) *addr |= LSB;
+ else *addr &= ~ LSB;
+ }
+}
+
+void BitVector_MSB(unsigned int * addr, boolean bit)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+
+ if (size-- > 0)
+ {
+ if (bit) *(addr+size) |= mask & ~ (mask >> 1);
+ else *(addr+size) &= ~ mask | (mask >> 1);
+ }
+}
+
+boolean BitVector_lsb_(unsigned int * addr)
+{
+ if (size_(addr) > 0) return( (*addr & LSB) != 0 );
+ else return( false );
+}
+
+boolean BitVector_msb_(unsigned int * addr)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+
+ if (size-- > 0)
+ return( (*(addr+size) & (mask & ~ (mask >> 1))) != 0 );
+ else
+ return( false );
+}
+
+boolean BitVector_rotate_left(unsigned int * addr)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int msb;
+ boolean carry_in;
+ boolean carry_out = false;
+
+ if (size > 0)
+ {
+ msb = mask & ~ (mask >> 1);
+ carry_in = ((*(addr+size-1) & msb) != 0);
+ while (size-- > 1)
+ {
+ carry_out = ((*addr & MSB) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ carry_in = carry_out;
+ addr++;
+ }
+ carry_out = ((*addr & msb) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ *addr &= mask;
+ }
+ return(carry_out);
+}
+
+boolean BitVector_rotate_right(unsigned int * addr)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int msb;
+ boolean carry_in;
+ boolean carry_out = false;
+
+ if (size > 0)
+ {
+ msb = mask & ~ (mask >> 1);
+ carry_in = ((*addr & LSB) != 0);
+ addr += size-1;
+ *addr &= mask;
+ carry_out = ((*addr & LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= msb;
+ carry_in = carry_out;
+ addr--;
+ size--;
+ while (size-- > 0)
+ {
+ carry_out = ((*addr & LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= MSB;
+ carry_in = carry_out;
+ addr--;
+ }
+ }
+ return(carry_out);
+}
+
+boolean BitVector_shift_left(unsigned int * addr, boolean carry_in)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int msb;
+ boolean carry_out = carry_in;
+
+ if (size > 0)
+ {
+ msb = mask & ~ (mask >> 1);
+ while (size-- > 1)
+ {
+ carry_out = ((*addr & MSB) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ carry_in = carry_out;
+ addr++;
+ }
+ carry_out = ((*addr & msb) != 0);
+ *addr <<= 1;
+ if (carry_in) *addr |= LSB;
+ *addr &= mask;
+ }
+ return(carry_out);
+}
+
+boolean BitVector_shift_right(unsigned int * addr, boolean carry_in)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int msb;
+ boolean carry_out = carry_in;
+
+ if (size > 0)
+ {
+ msb = mask & ~ (mask >> 1);
+ addr += size-1;
+ *addr &= mask;
+ carry_out = ((*addr & LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= msb;
+ carry_in = carry_out;
+ addr--;
+ size--;
+ while (size-- > 0)
+ {
+ carry_out = ((*addr & LSB) != 0);
+ *addr >>= 1;
+ if (carry_in) *addr |= MSB;
+ carry_in = carry_out;
+ addr--;
+ }
+ }
+ return(carry_out);
+}
+
+void BitVector_Move_Left(unsigned int * addr, unsigned int bits)
+{
+ unsigned int count;
+ unsigned int words;
+
+ if (bits > 0)
+ {
+ count = bits & MODMASK;
+ words = bits >> LOGBITS;
+ if (bits >= bits_(addr)) BitVector_Empty(addr);
+ else
+ {
+ while (count-- > 0) BitVector_shift_left(addr,0);
+ BitVector_Word_Insert(addr,0,words,true);
+ }
+ }
+}
+
+void BitVector_Move_Right(unsigned int * addr, unsigned int bits)
+{
+ unsigned int count;
+ unsigned int words;
+
+ if (bits > 0)
+ {
+ count = bits & MODMASK;
+ words = bits >> LOGBITS;
+ if (bits >= bits_(addr)) BitVector_Empty(addr);
+ else
+ {
+ while (count-- > 0) BitVector_shift_right(addr,0);
+ BitVector_Word_Delete(addr,0,words,true);
+ }
+ }
+}
+
+void BitVector_Insert(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int last;
+
+ if ((count > 0) && (offset < bits))
+ {
+ last = offset + count;
+ if (last < bits)
+ {
+ BitVector_Interval_Copy(addr,addr,last,offset,(bits-last));
+ }
+ else last = bits;
+ if (clear) BitVector_Interval_Empty(addr,offset,(last-1));
+ }
+}
+
+void BitVector_Delete(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int last;
+
+ if ((count > 0) && (offset < bits))
+ {
+ last = offset + count;
+ if (last < bits)
+ {
+ BitVector_Interval_Copy(addr,addr,offset,last,(bits-last));
+ }
+ else count = bits - offset;
+ if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1));
+ }
+}
+
+boolean BitVector_increment(unsigned int * addr) /* X++ */
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int * last = addr + size - 1;
+ boolean carry = true;
+
+ if (size > 0)
+ {
+ *last |= ~ mask;
+ while (carry && (size-- > 0))
+ {
+ carry = (++(*addr++) == 0);
+ }
+ *last &= mask;
+ }
+ return(carry);
+}
+
+boolean BitVector_decrement(unsigned int * addr) /* X-- */
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int * last = addr + size - 1;
+ boolean carry = true;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ while (carry && (size-- > 0))
+ {
+ carry = (*addr == 0);
+ --(*addr++);
+ }
+ *last &= mask;
+ }
+ return(carry);
+}
+
+boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean minus, boolean *carry)
+{
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+ unsigned int vv = 0;
+ unsigned int cc;
+ unsigned int mm;
+ unsigned int yy;
+ unsigned int zz;
+ unsigned int lo;
+ unsigned int hi;
+
+ if (size > 0)
+ {
+ if (minus) cc = (*carry == 0);
+ else cc = (*carry != 0);
+ /* deal with (size-1) least significant full words first: */
+ while (--size > 0)
+ {
+ yy = *Y++;
+ if (minus) zz = (unsigned int) ~ ( Z ? *Z++ : 0 );
+ else zz = (unsigned int) ( Z ? *Z++ : 0 );
+ lo = (yy & LSB) + (zz & LSB) + cc;
+ hi = (yy >> 1) + (zz >> 1) + (lo >> 1);
+ cc = ((hi & MSB) != 0);
+ *X++ = (hi << 1) | (lo & LSB);
+ }
+ /* deal with most significant word (may be used only partially): */
+ yy = *Y & mask;
+ if (minus) zz = (unsigned int) ~ ( Z ? *Z : 0 );
+ else zz = (unsigned int) ( Z ? *Z : 0 );
+ zz &= mask;
+ if (mask == LSB) /* special case, only one bit used */
+ {
+ vv = cc;
+ lo = yy + zz + cc;
+ cc = (lo >> 1);
+ vv ^= cc;
+ *X = lo & LSB;
+ }
+ else
+ {
+ if (~ mask) /* not all bits are used, but more than one */
+ {
+ mm = (mask >> 1);
+ vv = (yy & mm) + (zz & mm) + cc;
+ mm = mask & ~ mm;
+ lo = yy + zz + cc;
+ cc = (lo >> 1);
+ vv ^= cc;
+ vv &= mm;
+ cc &= mm;
+ *X = lo & mask;
+ }
+ else /* other special case, all bits are used */
+ {
+ mm = ~ MSB;
+ lo = (yy & mm) + (zz & mm) + cc;
+ vv = lo & MSB;
+ hi = ((yy & MSB) >> 1) + ((zz & MSB) >> 1) + (vv >> 1);
+ cc = hi & MSB;
+ vv ^= cc;
+ *X = (hi << 1) | (lo & mm);
+ }
+ }
+ if (minus) *carry = (cc == 0);
+ else *carry = (cc != 0);
+ }
+ return(vv != 0);
+}
+
+boolean BitVector_add(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry)
+{
+ return(BitVector_compute(X,Y,Z,false,carry));
+}
+
+boolean BitVector_sub(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry)
+{
+ return(BitVector_compute(X,Y,Z,true,carry));
+}
+
+boolean BitVector_inc(unsigned int * X, unsigned int * Y)
+{
+ boolean carry = true;
+
+ return(BitVector_compute(X,Y,NULL,false,&carry));
+}
+
+boolean BitVector_dec(unsigned int * X, unsigned int * Y)
+{
+ boolean carry = true;
+
+ return(BitVector_compute(X,Y,NULL,true,&carry));
+}
+
+void BitVector_Negate(unsigned int * X, unsigned int * Y)
+{
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+ boolean carry = true;
+
+ if (size > 0)
+ {
+ while (size-- > 0)
+ {
+ *X = ~ *Y++;
+ if (carry)
+ {
+ carry = (++(*X) == 0);
+ }
+ X++;
+ }
+ *(--X) &= mask;
+ }
+}
+
+void BitVector_Absolute(unsigned int * X, unsigned int * Y)
+{
+ unsigned int size = size_(Y);
+ unsigned int mask = mask_(Y);
+
+ if (size > 0)
+ {
+ if (*(Y+size-1) & (mask & ~ (mask >> 1))) BitVector_Negate(X,Y);
+ else BitVector_Copy(X,Y);
+ }
+}
+
+// FIXME: What the hell does the return value of this mean?
+// It returns 0, 1, or -1 under mysterious circumstances.
+signed int BitVector_Sign(unsigned int * addr)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int * last = addr + size - 1;
+ boolean r = true;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ while (r && (size-- > 0)) r = ( *addr++ == 0 );
+ }
+ if (r) return((signed int) 0);
+ else
+ {
+ if (*last & (mask & ~ (mask >> 1))) return((signed int) -1);
+ else return((signed int) 1);
+ }
+}
+
+ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean strict)
+{
+ unsigned int mask;
+ unsigned int limit;
+ unsigned int count;
+ signed long last;
+ unsigned int * sign;
+ boolean carry;
+ boolean overflow;
+ boolean ok = true;
+
+ /*
+ Requirements:
+ - X, Y && Z must be distinct
+ - X && Y must have equal sizes (whereas Z may be any size!)
+ - Z should always contain the SMALLER of the two factors Y && Z
+ Constraints:
+ - The contents of Y (&& of X, of course) are destroyed
+ (only Z is preserved!)
+ */
+
+ if ((X == Y) || (X == Z) || (Y == Z)) return(ErrCode_Same);
+ if (bits_(X) != bits_(Y)) return(ErrCode_Size);
+ BitVector_Empty(X);
+ if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */
+ if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok);
+ limit = (unsigned int) last;
+ sign = Y + size_(Y) - 1;
+ mask = mask_(Y);
+ *sign &= mask;
+ mask &= ~ (mask >> 1);
+ for ( count = 0; (ok && (count <= limit)); count++ )
+ {
+ if ( BIT_VECTOR_TST_BIT(Z,count) )
+ {
+ carry = false;
+ overflow = BitVector_compute(X,X,Y,false,&carry);
+ if (strict) ok = ! (carry || overflow);
+ else ok = ! carry;
+ }
+ if (ok && (count < limit))
+ {
+ carry = BitVector_shift_left(Y,0);
+ if (strict)
+ {
+ overflow = ((*sign & mask) != 0);
+ ok = ! (carry || overflow);
+ }
+ else ok = ! carry;
+ }
+ }
+ if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl);
+}
+
+ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * Z)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bit_x = bits_(X);
+ unsigned int bit_y = bits_(Y);
+ unsigned int bit_z = bits_(Z);
+ unsigned int size;
+ unsigned int mask;
+ unsigned int msb;
+ unsigned int * ptr_y;
+ unsigned int * ptr_z;
+ boolean sgn_x;
+ boolean sgn_y;
+ boolean sgn_z;
+ boolean zero;
+ unsigned int * A;
+ unsigned int * B;
+
+ /*
+ Requirements:
+ - Y && Z must have equal sizes
+ - X must have at least the same size as Y && Z but may be larger (!)
+ Features:
+ - The contents of Y && Z are preserved
+ - X may be identical with Y or Z (or both!)
+ (in-place multiplication is possible!)
+ */
+
+ if ((bit_y != bit_z) || (bit_x < bit_y)) return(ErrCode_Size);
+ if (BitVector_is_empty(Y) || BitVector_is_empty(Z))
+ {
+ BitVector_Empty(X);
+ }
+ else
+ {
+ A = BitVector_Create(bit_y,false);
+ if (A == NULL) return(ErrCode_Null);
+ B = BitVector_Create(bit_z,false);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ size = size_(Y);
+ mask = mask_(Y);
+ msb = (mask & ~ (mask >> 1));
+ sgn_y = (((*(Y+size-1) &= mask) & msb) != 0);
+ sgn_z = (((*(Z+size-1) &= mask) & msb) != 0);
+ sgn_x = sgn_y ^ sgn_z;
+ if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
+ if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
+ ptr_y = A + size;
+ ptr_z = B + size;
+ zero = true;
+ while (zero && (size-- > 0))
+ {
+ zero &= (*(--ptr_y) == 0);
+ zero &= (*(--ptr_z) == 0);
+ }
+ if (*ptr_y > *ptr_z)
+ {
+ if (bit_x > bit_y)
+ {
+ A = BitVector_Resize(A,bit_x);
+ if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); }
+ }
+ error = BitVector_Mul_Pos(X,A,B,true);
+ }
+ else
+ {
+ if (bit_x > bit_z)
+ {
+ B = BitVector_Resize(B,bit_x);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ }
+ error = BitVector_Mul_Pos(X,B,A,true);
+ }
+ if ((! error) && sgn_x) BitVector_Negate(X,X);
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ }
+ return(error);
+}
+
+ErrCode BitVector_Div_Pos(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R)
+{
+ unsigned int bits = bits_(Q);
+ unsigned int mask;
+ unsigned int * addr;
+ signed long last;
+ boolean flag;
+ boolean copy = false; /* flags whether valid rest is in R (0) || X (1) */
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - Q, X, Y && R must all be distinct bit vectors
+ - Y must be non-zero (of course!)
+ Constraints:
+ - The contents of X (&& Q && R, of course) are destroyed
+ (only Y is preserved!)
+ */
+
+ if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R)))
+ return(ErrCode_Size);
+ if ((Q == X) || (Q == Y) || (Q == R) || (X == Y) || (X == R) || (Y == R))
+ return(ErrCode_Same);
+ if (BitVector_is_empty(Y))
+ return(ErrCode_Zero);
+
+ BitVector_Empty(R);
+ BitVector_Copy(Q,X);
+ if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok);
+ bits = (unsigned int) ++last;
+ while (bits-- > 0)
+ {
+ addr = Q + (bits >> LOGBITS);
+ mask = BITMASKTAB[bits & MODMASK];
+ flag = ((*addr & mask) != 0);
+ if (copy)
+ {
+ BitVector_shift_left(X,flag);
+ flag = false;
+ BitVector_compute(R,X,Y,true,&flag);
+ }
+ else
+ {
+ BitVector_shift_left(R,flag);
+ flag = false;
+ BitVector_compute(X,R,Y,true,&flag);
+ }
+ if (flag) *addr &= ~ mask;
+ else
+ {
+ *addr |= mask;
+ copy = ! copy;
+ }
+ }
+ if (copy) BitVector_Copy(R,X);
+ return(ErrCode_Ok);
+}
+
+ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(Q);
+ unsigned int size = size_(Q);
+ unsigned int mask = mask_(Q);
+ unsigned int msb = (mask & ~ (mask >> 1));
+ boolean sgn_q;
+ boolean sgn_x;
+ boolean sgn_y;
+ unsigned int * A;
+ unsigned int * B;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - Q && R must be two distinct bit vectors
+ - Y must be non-zero (of course!)
+ Features:
+ - The contents of X && Y are preserved
+ - Q may be identical with X || Y (or both)
+ (in-place division is possible!)
+ - R may be identical with X || Y (or both)
+ (but not identical with Q!)
+ */
+
+ if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R)))
+ return(ErrCode_Size);
+ if (Q == R)
+ return(ErrCode_Same);
+ if (BitVector_is_empty(Y))
+ return(ErrCode_Zero);
+
+ if (BitVector_is_empty(X))
+ {
+ BitVector_Empty(Q);
+ BitVector_Empty(R);
+ }
+ else
+ {
+ A = BitVector_Create(bits,false);
+ if (A == NULL) return(ErrCode_Null);
+ B = BitVector_Create(bits,false);
+ if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
+ size--;
+ sgn_x = (((*(X+size) &= mask) & msb) != 0);
+ sgn_y = (((*(Y+size) &= mask) & msb) != 0);
+ sgn_q = sgn_x ^ sgn_y;
+ if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X);
+ if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
+ if (! (error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ if (sgn_q) BitVector_Negate(Q,Q);
+ if (sgn_x) BitVector_Negate(R,R);
+ }
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ }
+ return(error);
+}
+
+ErrCode BitVector_GCD(unsigned int * X, unsigned int * Y, unsigned int * Z)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(X);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+ unsigned int msb = (mask & ~ (mask >> 1));
+ boolean sgn_a;
+ boolean sgn_b;
+ boolean sgn_r;
+ unsigned int * Q;
+ unsigned int * R;
+ unsigned int * A;
+ unsigned int * B;
+ unsigned int * T;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ Features:
+ - The contents of Y && Z are preserved
+ - X may be identical with Y || Z (or both)
+ (in-place is possible!)
+ - GCD(0,z) == GCD(z,0) == z
+ - negative values are h&&led correctly
+ */
+
+ if ((bits != bits_(Y)) || (bits != bits_(Z))) return(ErrCode_Size);
+ if (BitVector_is_empty(Y))
+ {
+ if (X != Z) BitVector_Copy(X,Z);
+ return(ErrCode_Ok);
+ }
+ if (BitVector_is_empty(Z))
+ {
+ if (X != Y) BitVector_Copy(X,Y);
+ return(ErrCode_Ok);
+ }
+ Q = BitVector_Create(bits,false);
+ if (Q == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ R = BitVector_Create(bits,false);
+ if (R == NULL)
+ {
+ BitVector_Destroy(Q);
+ return(ErrCode_Null);
+ }
+ A = BitVector_Create(bits,false);
+ if (A == NULL)
+ {
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ return(ErrCode_Null);
+ }
+ B = BitVector_Create(bits,false);
+ if (B == NULL)
+ {
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ BitVector_Destroy(A);
+ return(ErrCode_Null);
+ }
+ size--;
+ sgn_a = (((*(Y+size) &= mask) & msb) != 0);
+ sgn_b = (((*(Z+size) &= mask) & msb) != 0);
+ if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
+ if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
+ while (! error)
+ {
+ if (! (error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ if (BitVector_is_empty(R)) break;
+ T = A; sgn_r = sgn_a;
+ A = B; sgn_a = sgn_b;
+ B = R; sgn_b = sgn_r;
+ R = T;
+ }
+ }
+ if (! error)
+ {
+ if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B);
+ }
+ BitVector_Destroy(Q);
+ BitVector_Destroy(R);
+ BitVector_Destroy(A);
+ BitVector_Destroy(B);
+ return(error);
+}
+
+ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, unsigned int * X, unsigned int * Y)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(U);
+ unsigned int size = size_(U);
+ unsigned int mask = mask_(U);
+ unsigned int msb = (mask & ~ (mask >> 1));
+ boolean minus;
+ boolean carry;
+ boolean sgn_q;
+ boolean sgn_r;
+ boolean sgn_a;
+ boolean sgn_b;
+ boolean sgn_x;
+ boolean sgn_y;
+ unsigned int * * L;
+ unsigned int * Q;
+ unsigned int * R;
+ unsigned int * A;
+ unsigned int * B;
+ unsigned int * T;
+ unsigned int * X1;
+ unsigned int * X2;
+ unsigned int * X3;
+ unsigned int * Y1;
+ unsigned int * Y2;
+ unsigned int * Y3;
+ unsigned int * Z;
+
+ /*
+ Requirements:
+ - All bit vectors must have equal sizes
+ - U, V, && W must all be distinct bit vectors
+ Features:
+ - The contents of X && Y are preserved
+ - U, V && W may be identical with X || Y (or both,
+ provided that U, V && W are mutually distinct)
+ (i.e., in-place is possible!)
+ - GCD(0,z) == GCD(z,0) == z
+ - negative values are h&&led correctly
+ */
+
+ if ((bits != bits_(V)) ||
+ (bits != bits_(W)) ||
+ (bits != bits_(X)) ||
+ (bits != bits_(Y)))
+ {
+ return(ErrCode_Size);
+ }
+ if ((U == V) || (U == W) || (V == W))
+ {
+ return(ErrCode_Same);
+ }
+ if (BitVector_is_empty(X))
+ {
+ if (U != Y) BitVector_Copy(U,Y);
+ BitVector_Empty(V);
+ BitVector_Empty(W);
+ *W = 1;
+ return(ErrCode_Ok);
+ }
+ if (BitVector_is_empty(Y))
+ {
+ if (U != X) BitVector_Copy(U,X);
+ BitVector_Empty(V);
+ BitVector_Empty(W);
+ *V = 1;
+ return(ErrCode_Ok);
+ }
+ if ((L = BitVector_Create_List(bits,false,11)) == NULL)
+ {
+ return(ErrCode_Null);
+ }
+ Q = L[0];
+ R = L[1];
+ A = L[2];
+ B = L[3];
+ X1 = L[4];
+ X2 = L[5];
+ X3 = L[6];
+ Y1 = L[7];
+ Y2 = L[8];
+ Y3 = L[9];
+ Z = L[10];
+ size--;
+ sgn_a = (((*(X+size) &= mask) & msb) != 0);
+ sgn_b = (((*(Y+size) &= mask) & msb) != 0);
+ if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X);
+ if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
+ BitVector_Empty(X1);
+ BitVector_Empty(X2);
+ *X1 = 1;
+ BitVector_Empty(Y1);
+ BitVector_Empty(Y2);
+ *Y2 = 1;
+ sgn_x = false;
+ sgn_y = false;
+ while (! error)
+ {
+ if ((error = BitVector_Div_Pos(Q,A,B,R)))
+ {
+ break;
+ }
+ if (BitVector_is_empty(R))
+ {
+ break;
+ }
+ sgn_q = sgn_a ^ sgn_b;
+
+ if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2);
+ if ((error = BitVector_Mul_Pos(X3,Z,Q,true)))
+ {
+ break;
+ }
+ minus = ! (sgn_x ^ sgn_q);
+ carry = 0;
+ if (BitVector_compute(X3,X1,X3,minus,&carry))
+ {
+ error = ErrCode_Ovfl;
+ break;
+ }
+ sgn_x = (((*(X3+size) &= mask) & msb) != 0);
+
+ if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2);
+ if ((error = BitVector_Mul_Pos(Y3,Z,Q,true)))
+ {
+ break;
+ }
+ minus = ! (sgn_y ^ sgn_q);
+ carry = 0;
+ if (BitVector_compute(Y3,Y1,Y3,minus,&carry))
+ {
+ error = ErrCode_Ovfl;
+ break;
+ }
+ sgn_y = (((*(Y3+size) &= mask) & msb) != 0);
+
+ T = A; sgn_r = sgn_a;
+ A = B; sgn_a = sgn_b;
+ B = R; sgn_b = sgn_r;
+ R = T;
+
+ T = X1;
+ X1 = X2;
+ X2 = X3;
+ X3 = T;
+
+ T = Y1;
+ Y1 = Y2;
+ Y2 = Y3;
+ Y3 = T;
+ }
+ if (! error)
+ {
+ if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B);
+ BitVector_Copy(V,X2);
+ BitVector_Copy(W,Y2);
+ }
+ BitVector_Destroy_List(L,11);
+ return(error);
+}
+
+ErrCode BitVector_Power(unsigned int * X, unsigned int * Y, unsigned int * Z)
+{
+ ErrCode error = ErrCode_Ok;
+ unsigned int bits = bits_(X);
+ boolean first = true;
+ signed long last;
+ unsigned int limit;
+ unsigned int count;
+ unsigned int * T;
+
+ /*
+ Requirements:
+ - X must have at least the same size as Y but may be larger (!)
+ - X may not be identical with Z
+ - Z must be positive
+ Features:
+ - The contents of Y && Z are preserved
+ */
+
+ if (X == Z) return(ErrCode_Same);
+ if (bits < bits_(Y)) return(ErrCode_Size);
+ if (BitVector_msb_(Z)) return(ErrCode_Expo);
+ if ((last = Set_Max(Z)) < 0L)
+ {
+ if (bits < 2) return(ErrCode_Ovfl);
+ BitVector_Empty(X);
+ *X |= LSB;
+ return(ErrCode_Ok); /* anything ^ 0 == 1 */
+ }
+ if (BitVector_is_empty(Y))
+ {
+ if (X != Y) BitVector_Empty(X);
+ return(ErrCode_Ok); /* 0 ^ anything ! zero == 0 */
+ }
+ T = BitVector_Create(bits,false);
+ if (T == NULL) return(ErrCode_Null);
+ limit = (unsigned int) last;
+ for ( count = 0; ((!error) && (count <= limit)); count++ )
+ {
+ if ( BIT_VECTOR_TST_BIT(Z,count) )
+ {
+ if (first)
+ {
+ first = false;
+ if (count) { BitVector_Copy(X,T); }
+ else { if (X != Y) BitVector_Copy(X,Y); }
+ }
+ else error = BitVector_Multiply(X,T,X); /* order important because T > X */
+ }
+ if ((!error) && (count < limit))
+ {
+ if (count) error = BitVector_Multiply(T,T,T);
+ else error = BitVector_Multiply(T,Y,Y);
+ }
+ }
+ BitVector_Destroy(T);
+ return(error);
+}
+
+void BitVector_Block_Store(unsigned int * addr, unsigned char * buffer, unsigned int length)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int value;
+ unsigned int count;
+
+ /* provide translation for independence of endian-ness: */
+ if (size > 0)
+ {
+ while (size-- > 0)
+ {
+ value = 0;
+ for ( count = 0; (length > 0) && (count < BITS); count += 8 )
+ {
+ value |= (((unsigned int) *buffer++) << count); length--;
+ }
+ *addr++ = value;
+ }
+ *(--addr) &= mask;
+ }
+}
+
+unsigned char * BitVector_Block_Read(unsigned int * addr, unsigned int * length)
+{
+ unsigned int size = size_(addr);
+ unsigned int value;
+ unsigned int count;
+ unsigned char * buffer;
+ unsigned char * target;
+
+ /* provide translation for independence of endian-ness: */
+ *length = size << FACTOR;
+ buffer = (unsigned char *) malloc((size_t) ((*length)+1));
+ if (buffer == NULL) return(NULL);
+ target = buffer;
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ while (size-- > 0)
+ {
+ value = *addr++;
+ count = BITS >> 3;
+ while (count-- > 0)
+ {
+ *target++ = (unsigned char) (value & 0x00FF);
+ if (count > 0) value >>= 8;
+ }
+ }
+ }
+ *target = (unsigned char) '\0';
+ return(buffer);
+}
+
+void BitVector_Word_Store(unsigned int * addr, unsigned int offset, unsigned int value)
+{
+ unsigned int size = size_(addr);
+
+ if (size > 0)
+ {
+ if (offset < size) *(addr+offset) = value;
+ *(addr+size-1) &= mask_(addr);
+ }
+}
+
+unsigned int BitVector_Word_Read(unsigned int * addr, unsigned int offset)
+{
+ unsigned int size = size_(addr);
+
+ if (size > 0)
+ {
+ *(addr+size-1) &= mask_(addr);
+ if (offset < size) return( *(addr+offset) );
+ }
+ return( (unsigned int) 0 );
+}
+
+void BitVector_Word_Insert(unsigned int * addr, unsigned int offset, unsigned int count,
+ boolean clear)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int * last = addr+size-1;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ if (offset > size) offset = size;
+ BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear);
+ *last &= mask;
+ }
+}
+
+void BitVector_Word_Delete(unsigned int * addr, unsigned int offset, unsigned int count,
+ boolean clear)
+{
+ unsigned int size = size_(addr);
+ unsigned int mask = mask_(addr);
+ unsigned int * last = addr+size-1;
+
+ if (size > 0)
+ {
+ *last &= mask;
+ if (offset > size) offset = size;
+ BIT_VECTOR_del_words(addr+offset,size-offset,count,clear);
+ *last &= mask;
+ }
+}
+
+void BitVector_Chunk_Store(unsigned int * addr, unsigned int chunksize, unsigned int offset,
+ unsigned long value)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int mask;
+ unsigned int temp;
+
+ if ((chunksize > 0) && (offset < bits))
+ {
+ if (chunksize > LONGBITS) chunksize = LONGBITS;
+ if ((offset + chunksize) > bits) chunksize = bits - offset;
+ addr += offset >> LOGBITS;
+ offset &= MODMASK;
+ while (chunksize > 0)
+ {
+ mask = (unsigned int) (~0L << offset);
+ bits = offset + chunksize;
+ if (bits < BITS)
+ {
+ mask &= (unsigned int) ~(~0L << bits);
+ bits = chunksize;
+ }
+ else bits = BITS - offset;
+ temp = (unsigned int) (value << offset);
+ temp &= mask;
+ *addr &= ~ mask;
+ *addr++ |= temp;
+ value >>= bits;
+ chunksize -= bits;
+ offset = 0;
+ }
+ }
+}
+
+unsigned long BitVector_Chunk_Read(unsigned int * addr, unsigned int chunksize, unsigned int offset)
+{
+ unsigned int bits = bits_(addr);
+ unsigned int chunkbits = 0;
+ unsigned long value = 0L;
+ unsigned long temp;
+ unsigned int mask;
+
+ if ((chunksize > 0) && (offset < bits))
+ {
+ if (chunksize > LONGBITS) chunksize = LONGBITS;
+ if ((offset + chunksize) > bits) chunksize = bits - offset;
+ addr += offset >> LOGBITS;
+ offset &= MODMASK;
+ while (chunksize > 0)
+ {
+ bits = offset + chunksize;
+ if (bits < BITS)
+ {
+ mask = (unsigned int) ~(~0L << bits);
+ bits = chunksize;
+ }
+ else
+ {
+ mask = (unsigned int) ~0L;
+ bits = BITS - offset;
+ }
+ temp = (unsigned long) ((*addr++ & mask) >> offset);
+ value |= temp << chunkbits;
+ chunkbits += bits;
+ chunksize -= bits;
+ offset = 0;
+ }
+ }
+ return(value);
+}
+
+ /*******************/
+ /* set operations: */
+ /*******************/
+
+void Set_Union(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y + Z */
+{
+ unsigned int bits = bits_(X);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+
+ if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ | *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Intersection(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y * Z */
+{
+ unsigned int bits = bits_(X);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+
+ if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ & *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Difference(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y \ Z */
+{
+ unsigned int bits = bits_(X);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+
+ if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ & ~ *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_ExclusiveOr(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X=(Y+Z)\(Y*Z) */
+{
+ unsigned int bits = bits_(X);
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+
+ if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z)))
+ {
+ while (size-- > 0) *X++ = *Y++ ^ *Z++;
+ *(--X) &= mask;
+ }
+}
+
+void Set_Complement(unsigned int * X, unsigned int * Y) /* X = ~Y */
+{
+ unsigned int size = size_(X);
+ unsigned int mask = mask_(X);
+
+ if ((size > 0) && (bits_(X) == bits_(Y)))
+ {
+ while (size-- > 0) *X++ = ~ *Y++;
+ *(--X) &= mask;
+ }
+}
+
+ /******************/
+ /* set functions: */
+ /******************/
+
+boolean Set_subset(unsigned int * X, unsigned int * Y) /* X subset Y ? */
+{
+ unsigned int size = size_(X);
+ boolean r = false;
+
+ if ((size > 0) && (bits_(X) == bits_(Y)))
+ {
+ r = true;
+ while (r && (size-- > 0)) r = ((*X++ & ~ *Y++) == 0);
+ }
+ return(r);
+}
+
+unsigned int Set_Norm(unsigned int * addr) /* = | X | */
+{
+ unsigned char * byte;
+ unsigned int bytes;
+ unsigned int n;
+
+ byte = (unsigned char *) addr;
+ bytes = size_(addr) << FACTOR;
+ n = 0;
+ while (bytes-- > 0)
+ {
+ n += BitVector_BYTENORM[*byte++];
+ }
+ return(n);
+}
+
+unsigned int Set_Norm2(unsigned int * addr) /* = | X | */
+{
+ unsigned int size = size_(addr);
+ unsigned int w0,w1;
+ unsigned int n,k;
+
+ n = 0;
+ while (size-- > 0)
+ {
+ k = 0;
+ w1 = ~ (w0 = *addr++);
+ while (w0 && w1)
+ {
+ w0 &= w0 - 1;
+ w1 &= w1 - 1;
+ k++;
+ }
+ if (w0 == 0) n += k;
+ else n += BITS - k;
+ }
+ return(n);
+}
+
+unsigned int Set_Norm3(unsigned int * addr) /* = | X | */
+{
+ unsigned int size = size_(addr);
+ unsigned int count = 0;
+ unsigned int c;
+
+ while (size-- > 0)
+ {
+ c = *addr++;
+ while (c)
+ {
+ c &= c - 1;
+ count++;
+ }
+ }
+ return(count);
+}
+
+signed long Set_Min(unsigned int * addr) /* = min(X) */
+{
+ boolean empty = true;
+ unsigned int size = size_(addr);
+ unsigned int i = 0;
+ unsigned int c = 0; /* silence compiler warning */
+
+ while (empty && (size-- > 0))
+ {
+ if ((c = *addr++)) empty = false; else i++;
+ }
+ if (empty) return((signed long) LONG_MAX); /* plus infinity */
+ i <<= LOGBITS;
+ while (! (c & LSB))
+ {
+ c >>= 1;
+ i++;
+ }
+ return((signed long) i);
+}
+
+signed long Set_Max(unsigned int * addr) /* = max(X) */
+{
+ boolean empty = true;
+ unsigned int size = size_(addr);
+ unsigned int i = size;
+ unsigned int c = 0; /* silence compiler warning */
+
+ addr += size-1;
+ while (empty && (size-- > 0))
+ {
+ if ((c = *addr--)) empty = false; else i--;
+ }
+ if (empty) return((signed long) LONG_MIN); /* minus infinity */
+ i <<= LOGBITS;
+ while (! (c & MSB))
+ {
+ c <<= 1;
+ i--;
+ }
+ return((signed long) --i);
+}
+
+ /**********************************/
+ /* matrix-of-booleans operations: */
+ /**********************************/
+
+void Matrix_Multiplication(unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY,
+ unsigned int * Z, unsigned int rowsZ, unsigned int colsZ)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+ unsigned int indxX;
+ unsigned int indxY;
+ unsigned int indxZ;
+ unsigned int termX;
+ unsigned int termY;
+ unsigned int sum;
+
+ if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) &&
+ (bits_(X) == rowsX*colsX) &&
+ (bits_(Y) == rowsY*colsY) &&
+ (bits_(Z) == rowsZ*colsZ))
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termX = i * colsX;
+ termY = i * colsY;
+ for ( j = 0; j < colsZ; j++ )
+ {
+ indxX = termX + j;
+ sum = 0;
+ for ( k = 0; k < colsY; k++ )
+ {
+ indxY = termY + k;
+ indxZ = k * colsZ + j;
+ if ( BIT_VECTOR_TST_BIT(Y,indxY) &
+ BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1;
+ }
+ if (sum) BIT_VECTOR_SET_BIT(X,indxX)
+ else BIT_VECTOR_CLR_BIT(X,indxX)
+ }
+ }
+ }
+}
+
+void Matrix_Product(unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY,
+ unsigned int * Z, unsigned int rowsZ, unsigned int colsZ)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+ unsigned int indxX;
+ unsigned int indxY;
+ unsigned int indxZ;
+ unsigned int termX;
+ unsigned int termY;
+ unsigned int sum;
+
+ if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) &&
+ (bits_(X) == rowsX*colsX) &&
+ (bits_(Y) == rowsY*colsY) &&
+ (bits_(Z) == rowsZ*colsZ))
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termX = i * colsX;
+ termY = i * colsY;
+ for ( j = 0; j < colsZ; j++ )
+ {
+ indxX = termX + j;
+ sum = 0;
+ for ( k = 0; k < colsY; k++ )
+ {
+ indxY = termY + k;
+ indxZ = k * colsZ + j;
+ if ( BIT_VECTOR_TST_BIT(Y,indxY) &
+ BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1;
+ }
+ if (sum) BIT_VECTOR_SET_BIT(X,indxX)
+ else BIT_VECTOR_CLR_BIT(X,indxX)
+ }
+ }
+ }
+}
+
+void Matrix_Closure(unsigned int * addr, unsigned int rows, unsigned int cols)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+ unsigned int ii;
+ unsigned int ij;
+ unsigned int ik;
+ unsigned int kj;
+ unsigned int termi;
+ unsigned int termk;
+
+ if ((rows == cols) && (bits_(addr) == rows*cols))
+ {
+ for ( i = 0; i < rows; i++ )
+ {
+ ii = i * cols + i;
+ BIT_VECTOR_SET_BIT(addr,ii)
+ }
+ for ( k = 0; k < rows; k++ )
+ {
+ termk = k * cols;
+ for ( i = 0; i < rows; i++ )
+ {
+ termi = i * cols;
+ ik = termi + k;
+ for ( j = 0; j < rows; j++ )
+ {
+ ij = termi + j;
+ kj = termk + j;
+ if ( BIT_VECTOR_TST_BIT(addr,ik) &
+ BIT_VECTOR_TST_BIT(addr,kj) )
+ BIT_VECTOR_SET_BIT(addr,ij)
+ }
+ }
+ }
+ }
+}
+
+void Matrix_Transpose(unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int ii;
+ unsigned int ij;
+ unsigned int ji;
+ unsigned int addii;
+ unsigned int addij;
+ unsigned int addji;
+ unsigned int bitii;
+ unsigned int bitij;
+ unsigned int bitji;
+ unsigned int termi;
+ unsigned int termj;
+ boolean swap;
+
+ /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */
+
+ if ((rowsX == colsY) && (colsX == rowsY) &&
+ (bits_(X) == rowsX*colsX) &&
+ (bits_(Y) == rowsY*colsY))
+ {
+ if (rowsY == colsY) /* in-place is possible! */
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termi = i * colsY;
+ for ( j = 0; j < i; j++ )
+ {
+ termj = j * colsX;
+ ij = termi + j;
+ ji = termj + i;
+ addij = ij >> LOGBITS;
+ addji = ji >> LOGBITS;
+ bitij = BITMASKTAB[ij & MODMASK];
+ bitji = BITMASKTAB[ji & MODMASK];
+ swap = ((*(Y+addij) & bitij) != 0);
+ if ((*(Y+addji) & bitji) != 0)
+ *(X+addij) |= bitij;
+ else
+ *(X+addij) &= ~ bitij;
+ if (swap)
+ *(X+addji) |= bitji;
+ else
+ *(X+addji) &= ~ bitji;
+ }
+ ii = termi + i;
+ addii = ii >> LOGBITS;
+ bitii = BITMASKTAB[ii & MODMASK];
+ if ((*(Y+addii) & bitii) != 0)
+ *(X+addii) |= bitii;
+ else
+ *(X+addii) &= ~ bitii;
+ }
+ }
+ else /* rowsX != colsX, in-place is ~ possible! */
+ {
+ for ( i = 0; i < rowsY; i++ )
+ {
+ termi = i * colsY;
+ for ( j = 0; j < colsY; j++ )
+ {
+ termj = j * colsX;
+ ij = termi + j;
+ ji = termj + i;
+ addij = ij >> LOGBITS;
+ addji = ji >> LOGBITS;
+ bitij = BITMASKTAB[ij & MODMASK];
+ bitji = BITMASKTAB[ji & MODMASK];
+ if ((*(Y+addij) & bitij) != 0)
+ *(X+addji) |= bitji;
+ else
+ *(X+addji) &= ~ bitji;
+ }
+ }
+ }
+ }
+}
+}; //end of namespace CONSTANTBV
Added: klee/trunk/stp/constantbv/constantbv.h
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/constantbv/constantbv.h?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/constantbv/constantbv.h (added)
+++ klee/trunk/stp/constantbv/constantbv.h Wed May 20 23:36:41 2009
@@ -0,0 +1,316 @@
+#ifndef MODULE_BIT_VECTOR
+#define MODULE_BIT_VECTOR
+/*****************************************************************************/
+/* AUTHOR: */
+/*****************************************************************************/
+/* */
+/* Steffen Beyer */
+/* mailto:sb at engelschall.com */
+/* http://www.engelschall.com/u/sb/download/ */
+/* */
+/*****************************************************************************/
+/* COPYRIGHT: */
+/*****************************************************************************/
+/* */
+/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
+/* All rights reserved. */
+/* */
+/*****************************************************************************/
+/* LICENSE: */
+/*****************************************************************************/
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later version. */
+/* */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* Library General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Library General Public */
+/* License along with this library; if not, write to the */
+/* Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
+/* */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */
+/*****************************************************************************/
+/* MODULE IMPORTS: */
+/*****************************************************************************/
+#include <stdlib.h> /* MODULE TYPE: (sys) */
+#include <limits.h> /* MODULE TYPE: (sys) */
+#include <string.h> /* MODULE TYPE: (sys) */
+#include <ctype.h> /* MODULE TYPE: (sys) */
+/*****************************************************************************/
+/* MODULE INTERFACE: */
+/*****************************************************************************/
+
+namespace CONSTANTBV {
+
+#ifdef __cplusplus
+ extern "C" {
+ typedef bool boolean;
+#else
+ typedef enum { false = (0!=0), true = (0==0) } boolean;
+#endif
+
+ typedef enum {
+ ErrCode_Ok = 0, /* everything went allright */
+ ErrCode_Type, /* types word and size_t have incompatible sizes */
+ ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */
+ ErrCode_Word, /* size of word is less than 16 bits */
+ ErrCode_Long, /* size of word is greater than size of long */
+ ErrCode_Powr, /* number of bits of word is not a power of two */
+ ErrCode_Loga, /* error in calculation of logarithm */
+ ErrCode_Null, /* unable to allocate memory */
+ ErrCode_Indx, /* index out of range */
+ ErrCode_Ordr, /* minimum > maximum index */
+ ErrCode_Size, /* bit vector size mismatch */
+ ErrCode_Pars, /* input string syntax error */
+ ErrCode_Ovfl, /* numeric overflow error */
+ ErrCode_Same, /* operands must be distinct */
+ ErrCode_Expo, /* exponent must be positive */
+ ErrCode_Zero /* division by zero error */
+ } ErrCode;
+
+
+ /* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */
+ unsigned char * BitVector_Error(ErrCode error); /* return string for err code */
+ ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */
+ unsigned int BitVector_Size(unsigned int bits); /* bit vector size (# of words) */
+ unsigned int BitVector_Mask(unsigned int bits); /* bit vector mask (unused bits) */
+
+ /* ===> CLASS METHODS: <=== */
+ unsigned char * BitVector_Version(void); /* return version string */
+ unsigned int BitVector_Word_Bits(void); /* return # of bits in machine word */
+ unsigned int BitVector_Long_Bits(void); /* return # of bits in unsigned long */
+
+ /* ===> CONSTRUCTOR METHODS: <=== */
+ unsigned int * BitVector_Create (unsigned int bits, boolean clear); /* malloc */
+ unsigned int ** BitVector_Create_List (unsigned int bits, boolean clear, unsigned int count);
+ unsigned int * BitVector_Resize (unsigned int * oldaddr, unsigned int bits); /* realloc */
+ unsigned int * BitVector_Shadow (unsigned int * addr); /* make new same size but empty */
+ unsigned int * BitVector_Clone (unsigned int * addr); /* make exact duplicate */
+ unsigned int * BitVector_Concat (unsigned int * X, unsigned int * Y); /* return concatenation */
+
+ /* ===> DESTRUCTOR METHODS: <=== */
+ void BitVector_Dispose (unsigned char * string); /* string */
+ void BitVector_Destroy (unsigned int * addr); /* bitvec */
+ void BitVector_Destroy_List (unsigned int * * list, unsigned int count); /* list */
+
+ /* ===> OBJECT METHODS: <=== */
+
+ /* ===> bit vector hash: */
+ size_t BitVector_Hash (unsigned int * X);
+
+ /* ===> bit vector copy function: */
+ void BitVector_Copy (unsigned int * X, unsigned int * Y); /* X := Y */
+
+ /* ===> bit vector initialization: */
+ void BitVector_Empty (unsigned int * addr); /* X = {} */
+ void BitVector_Fill (unsigned int * addr); /* X = ~{} */
+ void BitVector_Flip (unsigned int * addr); /* X = ~X */
+ void BitVector_Primes (unsigned int * addr);
+
+ /* ===> miscellaneous functions: */
+ void BitVector_Reverse (unsigned int * X, unsigned int * Y);
+
+ /* ===> bit vector interval operations and functions: */
+ void BitVector_Interval_Empty (unsigned int * addr, unsigned int lower, unsigned int upper);
+ void BitVector_Interval_Fill (unsigned int * addr, unsigned int lower, unsigned int upper);
+ void BitVector_Interval_Flip (unsigned int * addr, unsigned int lower, unsigned int upper);
+ void BitVector_Interval_Reverse (unsigned int * addr, unsigned int lower, unsigned int upper);
+
+ boolean BitVector_interval_scan_inc (unsigned int * addr, unsigned int start,
+ unsigned int * min, unsigned int * max);
+ boolean BitVector_interval_scan_dec (unsigned int * addr, unsigned int start,
+ unsigned int * min, unsigned int * max);
+ void BitVector_Interval_Copy (unsigned int * X, unsigned int * Y,
+ unsigned int Xoffset, unsigned int Yoffset, unsigned int length);
+ unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y,
+ unsigned int Xoffset, unsigned int Xlength,
+ unsigned int Yoffset, unsigned int Ylength);
+
+ /* ===> bit vector test functions: */
+ boolean BitVector_is_empty (unsigned int * addr); /* X == {} ? */
+ boolean BitVector_is_full (unsigned int * addr); /* X == ~{} ? */
+ boolean BitVector_equal (unsigned int * X, unsigned int * Y); /* X == Y ? */
+ signed int BitVector_Lexicompare (unsigned int * X, unsigned int * Y); /* X <,=,> Y ? */
+ signed int BitVector_Compare (unsigned int * X, unsigned int * Y); /* X <,=,> Y ? */
+
+ /* ===> bit vector string conversion functions: */
+ unsigned char * BitVector_to_Hex (unsigned int * addr);
+ ErrCode BitVector_from_Hex (unsigned int * addr, unsigned char * string);
+ unsigned char * BitVector_to_Bin (unsigned int * addr);
+ ErrCode BitVector_from_Bin (unsigned int * addr, unsigned char * string);
+ unsigned char * BitVector_to_Dec (unsigned int * addr);
+ ErrCode BitVector_from_Dec (unsigned int * addr, unsigned char * string);
+ unsigned char * BitVector_to_Enum (unsigned int * addr);
+ ErrCode BitVector_from_Enum (unsigned int * addr, unsigned char * string);
+
+ /* ===> bit vector bit operations, functions & tests: */
+ void BitVector_Bit_Off (unsigned int * addr, unsigned int index); /* X = X \ {x} */
+ void BitVector_Bit_On (unsigned int * addr, unsigned int index); /* X = X + {x} */
+ boolean BitVector_bit_flip (unsigned int * addr, unsigned int index); /* (X+{x})\(X*{x}) */
+ boolean BitVector_bit_test (unsigned int * addr, unsigned int index); /* {x} in X ? */
+ void BitVector_Bit_Copy (unsigned int * addr, unsigned int index, boolean bit);
+
+ /* ===> bit vector bit shift & rotate functions: */
+ void BitVector_LSB (unsigned int * addr, boolean bit);
+ void BitVector_MSB (unsigned int * addr, boolean bit);
+ boolean BitVector_lsb_ (unsigned int * addr);
+ boolean BitVector_msb_ (unsigned int * addr);
+ boolean BitVector_rotate_left (unsigned int * addr);
+ boolean BitVector_rotate_right (unsigned int * addr);
+ boolean BitVector_shift_left (unsigned int * addr, boolean carry_in);
+ boolean BitVector_shift_right (unsigned int * addr, boolean carry_in);
+ void BitVector_Move_Left (unsigned int * addr, unsigned int bits);
+ void BitVector_Move_Right (unsigned int * addr, unsigned int bits);
+
+ /* ===> bit vector insert/delete bits: */
+ void BitVector_Insert (unsigned int * addr,
+ unsigned int offset, unsigned int count, boolean clear);
+ void BitVector_Delete (unsigned int * addr,
+ unsigned int offset, unsigned int count, boolean clear);
+
+ /* ===> bit vector arithmetic: */
+ boolean BitVector_increment (unsigned int * addr); /* X++ */
+ boolean BitVector_decrement (unsigned int * addr); /* X-- */
+ boolean BitVector_compute (unsigned int * X, unsigned int * Y,
+ unsigned int * Z, boolean minus, boolean *carry);
+ boolean BitVector_add (unsigned int * X,
+ unsigned int * Y, unsigned int * Z, boolean *carry);
+ boolean BitVector_sub (unsigned int * X,
+ unsigned int * Y, unsigned int * Z, boolean *carry); /* X = Y-Z*/
+ boolean BitVector_inc (unsigned int * X, unsigned int * Y);
+ boolean BitVector_dec (unsigned int * X, unsigned int * Y);
+
+ void BitVector_Negate (unsigned int * X, unsigned int * Y);
+ void BitVector_Absolute (unsigned int * X, unsigned int * Y);
+ signed int BitVector_Sign (unsigned int * addr);
+ ErrCode BitVector_Mul_Pos (unsigned int * X,
+ unsigned int * Y, unsigned int * Z, boolean strict);
+ ErrCode BitVector_Multiply (unsigned int * X, unsigned int * Y, unsigned int * Z);
+ ErrCode BitVector_Div_Pos (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R);
+ ErrCode BitVector_Divide (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R);
+ ErrCode BitVector_GCD (unsigned int * X, unsigned int * Y, unsigned int * Z);
+ ErrCode BitVector_GCD2 (unsigned int * U, unsigned int * V, unsigned int * W, /* O */
+ unsigned int * X, unsigned int * Y); /* I */
+ ErrCode BitVector_Power (unsigned int * X, unsigned int * Y, unsigned int * Z);
+
+ /* ===> direct memory access functions: */
+ void BitVector_Block_Store (unsigned int * addr,
+ unsigned char * buffer, unsigned int length);
+ unsigned char * BitVector_Block_Read (unsigned int * addr, unsigned int * length);
+
+ /* ===> word array functions: */
+ void BitVector_Word_Store (unsigned int * addr, unsigned int offset, unsigned int value);
+ unsigned int BitVector_Word_Read (unsigned int * addr, unsigned int offset);
+ void BitVector_Word_Insert (unsigned int * addr,
+ unsigned int offset, unsigned int count, boolean clear);
+ void BitVector_Word_Delete (unsigned int * addr,
+ unsigned int offset, unsigned int count, boolean clear);
+
+ /* ===> arbitrary size chunk functions: */
+ void BitVector_Chunk_Store (unsigned int * addr, unsigned int chunksize,
+ unsigned int offset, unsigned long value);
+ unsigned long BitVector_Chunk_Read (unsigned int * addr,
+ unsigned int chunksize,unsigned int offset);
+
+ /* ===> set operations: */
+ void Set_Union (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y + Z */
+ void Set_Intersection (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y * Z */
+ void Set_Difference (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y \ Z */
+ void Set_ExclusiveOr (unsigned int * X, unsigned int * Y, unsigned int * Z); /*(Y+Z)\(Y*Z)*/
+ void Set_Complement (unsigned int * X, unsigned int * Y); /* X = ~Y */
+
+ /* ===> set functions: */
+ boolean Set_subset (unsigned int * X, unsigned int * Y); /* X in Y ? */
+ unsigned int Set_Norm (unsigned int * addr); /* = | X | */
+ unsigned int Set_Norm2 (unsigned int * addr); /* = | X | */
+ unsigned int Set_Norm3 (unsigned int * addr); /* = | X | */
+ signed long Set_Min (unsigned int * addr); /* = min(X) */
+ signed long Set_Max (unsigned int * addr); /* = max(X) */
+
+ /* ===> matrix-of-booleans operations: */
+ void Matrix_Multiplication (unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY,
+ unsigned int * Z, unsigned int rowsZ, unsigned int colsZ);
+ void Matrix_Product (unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY,
+ unsigned int * Z, unsigned int rowsZ, unsigned int colsZ);
+ void Matrix_Closure (unsigned int * addr, unsigned int rows, unsigned int cols);
+ void Matrix_Transpose (unsigned int * X, unsigned int rowsX, unsigned int colsX,
+ unsigned int * Y, unsigned int rowsY, unsigned int colsY);
+
+ /*****************************************************************************/
+ /* MODULE RESOURCES: */
+ /*****************************************************************************/
+#define bits_(BitVector) *(BitVector-3)
+#define size_(BitVector) *(BitVector-2)
+#define mask_(BitVector) *(BitVector-1)
+
+#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)"
+#define ERRCODE_BITS "bits(word) != sizeof(word)*8"
+#define ERRCODE_WORD "bits(word) < 16"
+#define ERRCODE_LONG "bits(word) > bits(long)"
+#define ERRCODE_POWR "bits(word) != 2^x"
+#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))"
+#define ERRCODE_NULL "unable to allocate memory"
+#define ERRCODE_INDX "index out of range"
+#define ERRCODE_ORDR "minimum > maximum index"
+#define ERRCODE_SIZE "bit vector size mismatch"
+#define ERRCODE_PARS "input string syntax error"
+#define ERRCODE_OVFL "numeric overflow error"
+#define ERRCODE_SAME "result vector(s) must be distinct"
+#define ERRCODE_EXPO "exponent must be positive"
+#define ERRCODE_ZERO "division by zero error"
+#define ERRCODE_OOPS "unexpected internal error - please contact author"
+
+ const unsigned int BitVector_BYTENORM[256] = {
+ 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */
+ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */
+ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */
+ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */
+ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
+ 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */
+ };
+#ifdef __cplusplus
+ };
+#endif
+}; //end of namespace CONSTANTBV
+#endif
+
Added: klee/trunk/stp/parser/Makefile
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/parser/Makefile?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/parser/Makefile (added)
+++ klee/trunk/stp/parser/Makefile Wed May 20 23:36:41 2009
@@ -0,0 +1,27 @@
+include ../Makefile.common
+
+SRCS = lexPL.cpp parsePL.cpp let-funcs.cpp main.cpp
+OBJS = $(SRCS:.cpp=.o)
+LIBS = -L../AST -last -L../sat -lsatsolver -L../simplifier -lsimplifier -L../bitvec -lconsteval -L../constantbv -lconstantbv
+
+all: parser
+
+parser: lexPL.o parsePL.o let-funcs.o main.o
+ $(CXX) $(CFLAGS) $(LDFLAGS) lexPL.o parsePL.o main.o let-funcs.o $(LIBS) -o parser
+
+main.o: parsePL_defs.h
+
+lexPL.cpp: PL.lex parsePL_defs.h ../AST/AST.h
+ $(LEX) -o lexPL.cpp PL.lex
+
+parsePL_defs.h: y.tab.h
+ @cp y.tab.h parsePL_defs.h
+parsePL.cpp: y.tab.c
+ @cp y.tab.c parsePL.cpp
+
+y.tab.c y.tab.h: PL.y
+ $(YACC) PL.y
+
+
+clean:
+ rm -rf *.o parsePL_defs.h *~ lexPL.cpp parsePL.cpp *.output parser y.tab.* lex.yy.c .#*
Added: klee/trunk/stp/parser/PL.lex
URL: http://llvm.org/viewvc/llvm-project/klee/trunk/stp/parser/PL.lex?rev=72205&view=auto
==============================================================================
--- klee/trunk/stp/parser/PL.lex (added)
+++ klee/trunk/stp/parser/PL.lex Wed May 20 23:36:41 2009
@@ -0,0 +1,128 @@
+%{
+/********************************************************************
+ * AUTHORS: Vijay Ganesh, David L. Dill
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+#include <iostream>
+#include "../AST/AST.h"
+#include "parsePL_defs.h"
+
+extern char *yytext;
+extern int yyerror (const char *msg);
+%}
+
+%option noyywrap
+%option nounput
+%option noreject
+%option noyymore
+%option yylineno
+%x COMMENT
+%x STRING_LITERAL
+LETTER ([a-zA-Z])
+HEX ([0-9a-fA-F])
+BITS ([0-1])
+DIGIT ([0-9])
+OPCHAR (['?\_$])
+ANYTHING ({LETTER}|{DIGIT}|{OPCHAR})
+%%
+
+[()[\]{},.;:'!#?_=] { return yytext[0];}
+
+[\n] { /*Skip new line */ }
+[ \t\r\f] { /* skip whitespace */ }
+0b{BITS}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+2, 2)); return BVCONST_TOK;}
+0bin{BITS}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+4, 2)); return BVCONST_TOK;}
+0h{HEX}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+2, 16)); return BVCONST_TOK;}
+0hex{HEX}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+4, 16)); return BVCONST_TOK;}
+{DIGIT}+ { yylval.uintval = strtoul(yytext, NULL, 10); return NUMERAL_TOK;}
+
+"%" { BEGIN COMMENT;}
+<COMMENT>"\n" { BEGIN INITIAL; /* return to normal mode */}
+<COMMENT>. { /* stay in comment mode */}
+
+"ARRAY" { return ARRAY_TOK; }
+"OF" { return OF_TOK; }
+"WITH" { return WITH_TOK; }
+"AND" { return AND_TOK;}
+"NAND" { return NAND_TOK;}
+"NOR" { return NOR_TOK;}
+"NOT" { return NOT_TOK; }
+"OR" { return OR_TOK; }
+"/=" { return NEQ_TOK; }
+ ":=" { return ASSIGN_TOK;}
+"=>" { return IMPLIES_TOK; }
+"<=>" { return IFF_TOK; }
+"XOR" { return XOR_TOK; }
+"IF" { return IF_TOK; }
+"THEN" { return THEN_TOK; }
+"ELSE" { return ELSE_TOK; }
+"ELSIF" { return ELSIF_TOK; }
+"END" { return END_TOK; }
+"ENDIF" { return ENDIF_TOK; }
+"BV" { return BV_TOK;}
+"BITVECTOR" { return BV_TOK;}
+"BOOLEAN" { return BOOLEAN_TOK;}
+"<<" { return BVLEFTSHIFT_TOK;}
+">>" { return BVRIGHTSHIFT_TOK;}
+"BVPLUS" { return BVPLUS_TOK;}
+"BVSUB" { return BVSUB_TOK;}
+"BVUMINUS" { return BVUMINUS_TOK;}
+"BVMULT" { return BVMULT_TOK;}
+"BVDIV" { return BVDIV_TOK;}
+"BVMOD" { return BVMOD_TOK;}
+"SBVDIV" { return SBVDIV_TOK;}
+"SBVMOD" { return SBVMOD_TOK;}
+"~" { return BVNEG_TOK;}
+"&" { return BVAND_TOK;}
+"|" { return BVOR_TOK;}
+"BVXOR" { return BVXOR_TOK;}
+"BVNAND" { return BVNAND_TOK;}
+"BVNOR" { return BVNOR_TOK;}
+"BVXNOR" { return BVXNOR_TOK;}
+"@" { return BVCONCAT_TOK;}
+"BVLT" { return BVLT_TOK;}
+"BVGT" { return BVGT_TOK;}
+"BVLE" { return BVLE_TOK;}
+"BVGE" { return BVGE_TOK;}
+"BVSLT" { return BVSLT_TOK;}
+"BVSGT" { return BVSGT_TOK;}
+"BVSLE" { return BVSLE_TOK;}
+"BVSGE" { return BVSGE_TOK;}
+"BVSX" { return BVSX_TOK;}
+"SBVLT" { return BVSLT_TOK;}
+"SBVGT" { return BVSGT_TOK;}
+"SBVLE" { return BVSLE_TOK;}
+"SBVGE" { return BVSGE_TOK;}
+"SX" { return BVSX_TOK;}
+"BOOLEXTRACT" { return BOOLEXTRACT_TOK;}
+"BOOLBV" { return BOOL_TO_BV_TOK;}
+"ASSERT" { return ASSERT_TOK; }
+"QUERY" { return QUERY_TOK; }
+"FALSE" { return FALSELIT_TOK;}
+"TRUE" { return TRUELIT_TOK;}
+"IN" { return IN_TOK;}
+"LET" { return LET_TOK;}
+"COUNTEREXAMPLE" { return COUNTEREXAMPLE_TOK;}
+"COUNTERMODEL" { return COUNTEREXAMPLE_TOK;}
+ "PUSH" { return PUSH_TOK;}
+ "POP" { return POP_TOK;}
+
+(({LETTER})|(_)({ANYTHING}))({ANYTHING})* {
+ BEEV::ASTNode nptr = BEEV::globalBeevMgr_for_parser->CreateSymbol(yytext);
+
+ // Check valuesize to see if it's a prop var. I don't like doing
+ // type determination in the lexer, but it's easier than rewriting
+ // the whole grammar to eliminate the term/formula distinction.
+ yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(nptr));
+ //yylval.node = new BEEV::ASTNode(nptr);
+ if ((yylval.node)->GetType() == BEEV::BOOLEAN_TYPE)
+ return FORMID_TOK;
+ else
+ return TERMID_TOK;
+}
+
+. { yyerror("Illegal input character."); }
+%%
More information about the llvm-commits
mailing list