From 0310d53339a21de091dddd9569214d2e18e23bdd Mon Sep 17 00:00:00 2001 From: Matteo Rizzo Date: Fri, 28 Sep 2018 20:09:11 +0200 Subject: [PATCH 1/2] BitfieldSimplifier: use llvm::APInt for bit masks Still limited to 64-bit masks. Signed-off-by: Matteo Rizzo --- include/klee/BitfieldSimplifier.h | 17 +++--- include/klee/Common.h | 4 ++ lib/Core/AddressSpace.cpp | 4 +- lib/Expr/BitfieldSimplifier.cpp | 93 ++++++++++++++++--------------- lib/Expr/Expr.cpp | 2 +- 5 files changed, 64 insertions(+), 56 deletions(-) diff --git a/include/klee/BitfieldSimplifier.h b/include/klee/BitfieldSimplifier.h index e1e37c5..6c966aa 100644 --- a/include/klee/BitfieldSimplifier.h +++ b/include/klee/BitfieldSimplifier.h @@ -32,17 +32,18 @@ #include "klee/Expr.h" #include "klee/util/ExprHashMap.h" +#include "llvm/ADT/APInt.h" namespace klee { class BitfieldSimplifier { protected: struct BitsInfo { - uint64_t ignoredBits; ///< Bits that can be ignored because they - ///< are not used by higher-level expressions - ///< (passed top-down) - uint64_t knownOneBits; ///< Bits known to be one (passed bottom-up) - uint64_t knownZeroBits; ///< Bits known to be zero (passed bottom-up) + llvm::APInt ignoredBits; ///< Bits that can be ignored because they + ///< are not used by higher-level expressions + ///< (passed top-down) + llvm::APInt knownOneBits; ///< Bits known to be one (passed bottom-up) + llvm::APInt knownZeroBits; ///< Bits known to be zero (passed bottom-up) }; typedef std::pair, BitsInfo> ExprBitsInfo; @@ -51,14 +52,14 @@ class BitfieldSimplifier { ExprHashMap m_simplifiedExpressions; - ref replaceWithConstant(ref e, uint64_t value); + ref replaceWithConstant(ref e, const llvm::APInt& value); - ExprBitsInfo doSimplifyBits(ref e, uint64_t ignoredBits); + ExprBitsInfo doSimplifyBits(ref e, const llvm::APInt& ignoredBits); public: uint64_t m_cacheHits, m_cacheMisses; - ref simplify(ref e, uint64_t *knownZeroBits = NULL); + ref simplify(ref e, llvm::APInt *knownZeroBits = NULL); BitfieldSimplifier() { m_cacheHits = 0; diff --git a/include/klee/Common.h b/include/klee/Common.h index 25783d8..b8fedc2 100644 --- a/include/klee/Common.h +++ b/include/klee/Common.h @@ -21,6 +21,8 @@ #include #include +#include "llvm/ADT/APInt.h" + // XXX ugh namespace klee { class Solver; @@ -75,6 +77,8 @@ struct hexval { } hexval(void *_value, int _width = 0) : value((uint64_t) _value), width(_width) { } + hexval(const llvm::APInt& _value) : value(_value.getLimitedValue()), width(_value.getBitWidth()) { + } }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const hexval &h) { diff --git a/lib/Core/AddressSpace.cpp b/lib/Core/AddressSpace.cpp index aacbc38..946cb89 100644 --- a/lib/Core/AddressSpace.cpp +++ b/lib/Core/AddressSpace.cpp @@ -188,13 +188,13 @@ bool AddressSpace::resolveOneFast(BitfieldSimplifier &simplifier, ref addr } ref offset = add->getRight(); - uint64_t knownZeroBits; + llvm::APInt knownZeroBits; simplifier.simplify(offset, &knownZeroBits); uint64_t inBoundsSize; // Only handle 8-bits sized objects for now. // TODO: make it work for arbitrary consecutive numbers of 1s. - if ((knownZeroBits & ~(uint64_t) 0xff) == ~(uint64_t) 0xff) { + if ((knownZeroBits & ~llvm::APInt(64, 0xff)) == ~llvm::APInt(64, 0xff)) { inBoundsSize = 1 << 8; } else { return false; diff --git a/lib/Expr/BitfieldSimplifier.cpp b/lib/Expr/BitfieldSimplifier.cpp index 058e05f..30263f1 100644 --- a/lib/Expr/BitfieldSimplifier.cpp +++ b/lib/Expr/BitfieldSimplifier.cpp @@ -38,21 +38,21 @@ using namespace klee; using namespace llvm; namespace { -inline uint64_t zeroMask(uint64_t w) { +inline APInt zeroMask(unsigned w) { if (w < 64) - return (((uint64_t)(int64_t) -1) << w); + return (APInt::getAllOnesValue(64)) << w; else - return 0; + return APInt::getNullValue(64); } cl::opt DebugSimplifier("debug-expr-simplifier", cl::init(false)); cl::opt PrintSimplifier("print-expr-simplifier", cl::init(false)); -} +} // namespace -ref BitfieldSimplifier::replaceWithConstant(ref e, uint64_t value) { +ref BitfieldSimplifier::replaceWithConstant(ref e, const APInt &value) { ConstantExpr *ce = dyn_cast(e); - if (ce && ce->getZExtValue() == value) + if (ce && ce->getAPValue().zextOrSelf(64) == value) return e; // Remove kids from cache @@ -63,10 +63,10 @@ ref BitfieldSimplifier::replaceWithConstant(ref e, uint64_t value) { // Remove e from cache m_bitsInfoCache.erase(e); - return ConstantExpr::create(value & ~zeroMask(e->getWidth()), e->getWidth()); + return ConstantExpr::create((value.zextOrSelf(64) & ~zeroMask(e->getWidth())).getLimitedValue(), e->getWidth()); } -BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, uint64_t ignoredBits) { +BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, const APInt &ignoredBits) { ExprHashMap::iterator it = m_bitsInfoCache.find(e); if (it != m_bitsInfoCache.end()) { return *it; @@ -74,7 +74,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, ref kids[8]; BitsInfo bits[8]; - uint64_t oldIgnoredBits[8]; + APInt oldIgnoredBits[8]; BitsInfo rbits; rbits.ignoredBits = ignoredBits; @@ -84,7 +84,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < numKids; ++i) { /* By setting ignoredBits to zero we disable any ignoredBits-related optimization. Only optimizations based on knownBits will be done */ - ExprBitsInfo r = doSimplifyBits(e->getKid(i), 0); + ExprBitsInfo r = doSimplifyBits(e->getKid(i), APInt::getNullValue(64)); kids[i] = r.first; bits[i] = r.second; @@ -99,7 +99,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, /* Apply kind-specific knowledge to obtain knownBits for e and ignoredBits for kids of e, then to optimize e */ switch (e->getKind()) { - // TODO: Concat, Read, AShr + // TODO: Concat, Read, AShr case Expr::And: rbits.knownOneBits = bits[0].knownOneBits & bits[1].knownOneBits; @@ -112,8 +112,8 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < 2; ++i) { if (~(bits[i].knownOneBits | bits[i].ignoredBits) == 0) { /* All bits of this kid is either one or ignored */ - bits[i].knownOneBits = (uint64_t) -1; - bits[i].knownZeroBits = 0; + bits[i].knownOneBits = APInt::getAllOnesValue(64); + bits[i].knownZeroBits = APInt::getNullValue(64); } } @@ -130,8 +130,8 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < 2; ++i) { if (~(bits[i].knownZeroBits | bits[i].ignoredBits) == 0) { /* All bits of this kid is either zero or ignored */ - bits[i].knownOneBits = 0; - bits[i].knownZeroBits = (uint64_t) -1; + bits[i].knownOneBits = APInt::getNullValue(64); + bits[i].knownZeroBits = APInt::getAllOnesValue(64); } } @@ -159,23 +159,24 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, case Expr::Shl: if (ConstantExpr *c1 = dyn_cast(kids[1])) { // We can simplify only if the shift is known - uint64_t shift = c1->getZExtValue(); - uint64_t width = e->getWidth(); + unsigned shift = c1->getLimitedValue(std::numeric_limits::max()); + unsigned width = e->getWidth(); assert(width == kids[0]->getWidth()); if (shift < width) { rbits.knownOneBits = (bits[0].knownOneBits << shift) & ~zeroMask(width); rbits.knownZeroBits = (bits[0].knownZeroBits << shift) | zeroMask(width) | ~zeroMask(shift); - bits[0].ignoredBits = ((ignoredBits & ~zeroMask(width)) >> shift) | zeroMask(e->getWidth() - shift); + bits[0].ignoredBits = + ((ignoredBits & ~zeroMask(width)).lshr(shift)) | zeroMask(e->getWidth() - shift); } else { - rbits.knownOneBits = 0; - rbits.knownZeroBits = (uint64_t) -1; - bits[0].ignoredBits = (uint64_t) -1; + rbits.knownOneBits = APInt::getNullValue(64); + rbits.knownZeroBits = APInt::getAllOnesValue(64); + bits[0].ignoredBits = APInt::getAllOnesValue(64); } } else { // This is the most general assumption - rbits.knownOneBits = 0; + rbits.knownOneBits = APInt::getNullValue(64); rbits.knownZeroBits = zeroMask(e->getWidth()); } break; @@ -183,23 +184,23 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, case Expr::LShr: if (ConstantExpr *c1 = dyn_cast(kids[1])) { // We can simplify only if the shift is known - uint64_t shift = c1->getZExtValue(); - uint64_t width = e->getWidth(); + unsigned shift = c1->getLimitedValue(std::numeric_limits::max()); + unsigned width = e->getWidth(); assert(width == kids[0]->getWidth()); if (shift < width) { - rbits.knownOneBits = bits[0].knownOneBits >> shift; - rbits.knownZeroBits = (bits[0].knownZeroBits >> shift) | zeroMask(width - shift); + rbits.knownOneBits = bits[0].knownOneBits.lshr(shift); + rbits.knownZeroBits = (bits[0].knownZeroBits.lshr(shift)) | zeroMask(width - shift); bits[0].ignoredBits = (ignoredBits << shift) | ~zeroMask(shift) | zeroMask(width); } else { - rbits.knownOneBits = 0; - rbits.knownZeroBits = (uint64_t) -1; - bits[0].ignoredBits = (uint64_t) -1; + rbits.knownOneBits = APInt::getNullValue(64); + rbits.knownZeroBits = APInt::getAllOnesValue(64); + bits[0].ignoredBits = APInt::getAllOnesValue(64); } } else { // This is the most general assumption - rbits.knownOneBits = 0; + rbits.knownOneBits = APInt::getNullValue(64); rbits.knownZeroBits = zeroMask(e->getWidth()); } break; @@ -208,20 +209,22 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, ExtractExpr *ee = cast(e); // Calculate mask - bits that are kept by Extract - uint64_t mask = zeroMask(ee->getWidth()); - rbits.knownOneBits = (bits[0].knownOneBits >> ee->getOffset()) & ~mask; - rbits.knownZeroBits = (bits[0].knownZeroBits >> ee->getOffset()) | mask; + APInt mask = zeroMask(ee->getWidth()); + rbits.knownOneBits = (bits[0].knownOneBits.lshr(ee->getOffset())) & ~mask; + rbits.knownZeroBits = (bits[0].knownZeroBits.lshr(ee->getOffset())) | mask; bits[0].ignoredBits = (ignoredBits << ee->getOffset()) | ~((~mask) << ee->getOffset()); } break; case Expr::Concat: { - uint64_t shift = kids[1]->getWidth(); + // Shifting by more than the width of the expression is not allowed + unsigned shift = std::min(kids[1]->getWidth(), 64U); + rbits.knownOneBits = (bits[0].knownOneBits << shift) | bits[1].knownOneBits; rbits.knownZeroBits = (bits[0].knownZeroBits << shift) | (bits[1].knownZeroBits & ~zeroMask(kids[1]->getWidth())); - bits[0].ignoredBits = (ignoredBits >> shift) | zeroMask(kids[0]->getWidth()); + bits[0].ignoredBits = (ignoredBits.lshr(shift)) | zeroMask(kids[0]->getWidth()); bits[1].ignoredBits = ignoredBits | zeroMask(kids[1]->getWidth()); } break; @@ -244,34 +247,34 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, case Expr::SExt: { // Mask of bits determined by the sign - uint64_t mask = zeroMask(kids[0]->getWidth()) & ~zeroMask(e->getWidth()); + APInt mask = zeroMask(kids[0]->getWidth()) & ~zeroMask(e->getWidth()); rbits.knownOneBits = bits[0].knownOneBits; rbits.knownZeroBits = bits[0].knownZeroBits & ~mask; - if (bits[0].knownOneBits & (1UL << (kids[0]->getWidth() - 1))) { + if ((bits[0].knownOneBits & APInt(64, 1UL << (kids[0]->getWidth() - 1))) != 0) { // kid[0] is negative rbits.knownOneBits = bits[0].knownOneBits | mask; - } else if (bits[0].knownZeroBits & (1UL << (kids[0]->getWidth() - 1))) { + } else if ((bits[0].knownZeroBits & APInt(64, 1UL << (kids[0]->getWidth() - 1))) != 0) { // kid[0] is positive rbits.knownZeroBits = bits[0].knownZeroBits | mask; } bits[0].ignoredBits = ignoredBits; - if (mask & ~ignoredBits) { + if ((mask & ~ignoredBits) != 0) { /* Some of sign-dependend bits are not ignored */ - bits[0].ignoredBits &= ~(1UL << (kids[0]->getWidth() - 1)); + bits[0].ignoredBits &= APInt(64, ~(1UL << (kids[0]->getWidth() - 1))); } } break; case Expr::Constant: - rbits.knownOneBits = cast(e)->getZExtValue(); + rbits.knownOneBits = cast(e)->getAPValue().zextOrSelf(64); rbits.knownZeroBits = ~rbits.knownOneBits; break; default: // This is the most general assumption - rbits.knownOneBits = 0; + rbits.knownOneBits = APInt::getNullValue(64); rbits.knownZeroBits = zeroMask(e->getWidth()); break; } @@ -301,7 +304,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, kids[i] = replaceWithConstant(kids[i], bits[i].knownOneBits); - } else if (bits[i].ignoredBits & ~oldIgnoredBits[i]) { + } else if ((bits[i].ignoredBits & ~oldIgnoredBits[i]) != 0) { /* We have new information about ignoredBits */ kids[i] = doSimplifyBits(kids[i], bits[i].ignoredBits).first; } @@ -324,7 +327,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, return std::make_pair(e, rbits); } -ref BitfieldSimplifier::simplify(ref e, uint64_t *knownZeroBits) { +ref BitfieldSimplifier::simplify(ref e, APInt *knownZeroBits) { bool cste = isa(e); if (PrintSimplifier && !cste && klee_message_stream) *klee_message_stream << "BEFORE SIMPL: " << e << '\n'; @@ -344,7 +347,7 @@ ref BitfieldSimplifier::simplify(ref e, uint64_t *knownZeroBits) { ++m_cacheMisses; - ExprBitsInfo ret = doSimplifyBits(e, 0); + ExprBitsInfo ret = doSimplifyBits(e, APInt::getNullValue(64)); m_simplifiedExpressions[e] = ret; diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp index b1c35b1..37e89d1 100644 --- a/lib/Expr/Expr.cpp +++ b/lib/Expr/Expr.cpp @@ -148,7 +148,7 @@ static ref SimplifyExtractLShr(const ref &e) { return e; } - auto offset = shift->getZExtValue(); + auto offset = shift->getLimitedValue(); if (offset % 8) { return e; } From d60fbe1c0c5ec4339aa3b8c1a059c4288c415cf4 Mon Sep 17 00:00:00 2001 From: Matteo Rizzo Date: Mon, 1 Oct 2018 16:33:08 +0200 Subject: [PATCH 2/2] BitfieldSimplifier: support for wide expressions Use llvm::APInt to support expressions of arbitrary width. Signed-off-by: Matteo Rizzo --- lib/Expr/BitfieldSimplifier.cpp | 185 +++++++++++++++++--------------- 1 file changed, 101 insertions(+), 84 deletions(-) diff --git a/lib/Expr/BitfieldSimplifier.cpp b/lib/Expr/BitfieldSimplifier.cpp index 30263f1..d3c496b 100644 --- a/lib/Expr/BitfieldSimplifier.cpp +++ b/lib/Expr/BitfieldSimplifier.cpp @@ -38,13 +38,6 @@ using namespace klee; using namespace llvm; namespace { -inline APInt zeroMask(unsigned w) { - if (w < 64) - return (APInt::getAllOnesValue(64)) << w; - else - return APInt::getNullValue(64); -} - cl::opt DebugSimplifier("debug-expr-simplifier", cl::init(false)); cl::opt PrintSimplifier("print-expr-simplifier", cl::init(false)); @@ -52,7 +45,7 @@ cl::opt PrintSimplifier("print-expr-simplifier", cl::init(false)); ref BitfieldSimplifier::replaceWithConstant(ref e, const APInt &value) { ConstantExpr *ce = dyn_cast(e); - if (ce && ce->getAPValue().zextOrSelf(64) == value) + if (ce && ce->getAPValue() == value) return e; // Remove kids from cache @@ -63,7 +56,7 @@ ref BitfieldSimplifier::replaceWithConstant(ref e, const APInt &valu // Remove e from cache m_bitsInfoCache.erase(e); - return ConstantExpr::create((value.zextOrSelf(64) & ~zeroMask(e->getWidth())).getLimitedValue(), e->getWidth()); + return ConstantExpr::alloc(value); } BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, const APInt &ignoredBits) { @@ -84,7 +77,7 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < numKids; ++i) { /* By setting ignoredBits to zero we disable any ignoredBits-related optimization. Only optimizations based on knownBits will be done */ - ExprBitsInfo r = doSimplifyBits(e->getKid(i), APInt::getNullValue(64)); + ExprBitsInfo r = doSimplifyBits(e->getKid(i), APInt::getNullValue(e->getKid(i)->getWidth())); kids[i] = r.first; bits[i] = r.second; @@ -112,8 +105,8 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < 2; ++i) { if (~(bits[i].knownOneBits | bits[i].ignoredBits) == 0) { /* All bits of this kid is either one or ignored */ - bits[i].knownOneBits = APInt::getAllOnesValue(64); - bits[i].knownZeroBits = APInt::getNullValue(64); + bits[i].knownOneBits = APInt::getAllOnesValue(e->getWidth()); + bits[i].knownZeroBits = APInt::getNullValue(e->getWidth()); } } @@ -130,8 +123,8 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, for (unsigned i = 0; i < 2; ++i) { if (~(bits[i].knownZeroBits | bits[i].ignoredBits) == 0) { /* All bits of this kid is either zero or ignored */ - bits[i].knownOneBits = APInt::getNullValue(64); - bits[i].knownZeroBits = APInt::getAllOnesValue(64); + bits[i].knownOneBits = APInt::getNullValue(e->getWidth()); + bits[i].knownZeroBits = APInt::getAllOnesValue(e->getWidth()); } } @@ -149,139 +142,163 @@ BitfieldSimplifier::ExprBitsInfo BitfieldSimplifier::doSimplifyBits(ref e, break; case Expr::Not: - rbits.knownOneBits = bits[0].knownZeroBits & ~zeroMask(e->getWidth()); - rbits.knownZeroBits = bits[0].knownOneBits | zeroMask(e->getWidth()); + rbits.knownOneBits = bits[0].knownZeroBits; + rbits.knownZeroBits = bits[0].knownOneBits; bits[0].ignoredBits = ignoredBits; break; - case Expr::Shl: + case Expr::Shl: { + unsigned width = e->getWidth(); + assert(width == kids[0]->getWidth()); + if (ConstantExpr *c1 = dyn_cast(kids[1])) { // We can simplify only if the shift is known - unsigned shift = c1->getLimitedValue(std::numeric_limits::max()); - unsigned width = e->getWidth(); - assert(width == kids[0]->getWidth()); + + // We need getLimitedValue because shift amounts must be unsigned + unsigned shift = c1->getLimitedValue(width); if (shift < width) { - rbits.knownOneBits = (bits[0].knownOneBits << shift) & ~zeroMask(width); - rbits.knownZeroBits = (bits[0].knownZeroBits << shift) | zeroMask(width) | ~zeroMask(shift); + rbits.knownOneBits = bits[0].knownOneBits << shift; + // The low bits are zero after shifting + rbits.knownZeroBits = (bits[0].knownZeroBits << shift) | APInt::getLowBitsSet(width, shift); - bits[0].ignoredBits = - ((ignoredBits & ~zeroMask(width)).lshr(shift)) | zeroMask(e->getWidth() - shift); + // The high bits of kid 0 are ignored because they got shifted out + bits[0].ignoredBits = ignoredBits.lshr(shift) | APInt::getHighBitsSet(width, shift); } else { - rbits.knownOneBits = APInt::getNullValue(64); - rbits.knownZeroBits = APInt::getAllOnesValue(64); - bits[0].ignoredBits = APInt::getAllOnesValue(64); + // When the shift amount is >= the expression's width, the result is always 0 + rbits.knownOneBits = APInt::getNullValue(width); + rbits.knownZeroBits = APInt::getAllOnesValue(width); + bits[0].ignoredBits = APInt::getAllOnesValue(width); } } else { // This is the most general assumption - rbits.knownOneBits = APInt::getNullValue(64); - rbits.knownZeroBits = zeroMask(e->getWidth()); + rbits.knownOneBits = APInt::getNullValue(width); + rbits.knownZeroBits = APInt::getNullValue(width); } - break; + } break; + + case Expr::LShr: { + unsigned width = e->getWidth(); + assert(width == kids[0]->getWidth()); - case Expr::LShr: if (ConstantExpr *c1 = dyn_cast(kids[1])) { // We can simplify only if the shift is known - unsigned shift = c1->getLimitedValue(std::numeric_limits::max()); - unsigned width = e->getWidth(); - assert(width == kids[0]->getWidth()); + + // We need getLimitedValue because shift amounts must be unsigned + unsigned shift = c1->getLimitedValue(width); if (shift < width) { rbits.knownOneBits = bits[0].knownOneBits.lshr(shift); - rbits.knownZeroBits = (bits[0].knownZeroBits.lshr(shift)) | zeroMask(width - shift); + // The high bits are zero after shifting + rbits.knownZeroBits = bits[0].knownZeroBits.lshr(shift) | APInt::getHighBitsSet(width, shift); - bits[0].ignoredBits = (ignoredBits << shift) | ~zeroMask(shift) | zeroMask(width); + // The low bits of kid 0 are ignored because they got shifted out + bits[0].ignoredBits = (ignoredBits << shift) | APInt::getLowBitsSet(width, shift); } else { - rbits.knownOneBits = APInt::getNullValue(64); - rbits.knownZeroBits = APInt::getAllOnesValue(64); - bits[0].ignoredBits = APInt::getAllOnesValue(64); + // When the shift amout is >= the expression's width, the result is always 0 + rbits.knownOneBits = APInt::getNullValue(width); + rbits.knownZeroBits = APInt::getAllOnesValue(width); + bits[0].ignoredBits = APInt::getAllOnesValue(width); } } else { // This is the most general assumption - rbits.knownOneBits = APInt::getNullValue(64); - rbits.knownZeroBits = zeroMask(e->getWidth()); + rbits.knownOneBits = APInt::getNullValue(width); + rbits.knownZeroBits = APInt::getNullValue(width); } - break; + } break; case Expr::Extract: { ExtractExpr *ee = cast(e); - // Calculate mask - bits that are kept by Extract - APInt mask = zeroMask(ee->getWidth()); - rbits.knownOneBits = (bits[0].knownOneBits.lshr(ee->getOffset())) & ~mask; - rbits.knownZeroBits = (bits[0].knownZeroBits.lshr(ee->getOffset())) | mask; - - bits[0].ignoredBits = (ignoredBits << ee->getOffset()) | ~((~mask) << ee->getOffset()); + unsigned offset = ee->getOffset(); + unsigned width = ee->getWidth(); + unsigned kidWidth = kids[0]->getWidth(); + + // KnownOne(Extract(K, off, width)) == Extract(KnownOne(K), off, width), same thing for KnownZero + // Since we always want the masks to be as wide as the corresponding expression, we also have to + // truncate them + rbits.knownOneBits = bits[0].knownOneBits.lshr(offset).trunc(width); + rbits.knownZeroBits = bits[0].knownZeroBits.lshr(offset).trunc(width); + + // Bits from the lsb until offset are ignored because they're discarded by extract + // Bits from (offset + width) to the msb are also ignored for the same reason + // The parent's ignored bits mask has to be zero-extended for the same reason why we're truncating the kid's + // masks above + bits[0].ignoredBits = APInt::getLowBitsSet(kidWidth, offset) | + APInt::getHighBitsSet(kidWidth, kidWidth - width - offset) | + (ignoredBits.zext(kidWidth) << offset); } break; case Expr::Concat: { // Shifting by more than the width of the expression is not allowed - unsigned shift = std::min(kids[1]->getWidth(), 64U); + unsigned shift = kids[1]->getWidth(); + unsigned width = e->getWidth(); - rbits.knownOneBits = (bits[0].knownOneBits << shift) | bits[1].knownOneBits; - rbits.knownZeroBits = - (bits[0].knownZeroBits << shift) | (bits[1].knownZeroBits & ~zeroMask(kids[1]->getWidth())); + // Since we always want the masks to be as wide as the corresponding expression, we have to zero-extend + // the two kids' masks before combining them + rbits.knownOneBits = (bits[0].knownOneBits.zext(width) << shift) | bits[1].knownOneBits.zext(width); + rbits.knownZeroBits = (bits[0].knownZeroBits.zext(width) << shift) | bits[1].knownZeroBits.zext(width); - bits[0].ignoredBits = (ignoredBits.lshr(shift)) | zeroMask(kids[0]->getWidth()); - bits[1].ignoredBits = ignoredBits | zeroMask(kids[1]->getWidth()); + // The parent's ignored bits mask has to be truncated for the same reason as above. + bits[0].ignoredBits = (ignoredBits.lshr(shift)).trunc(kids[0]->getWidth()); + bits[1].ignoredBits = ignoredBits.trunc(shift); } break; case Expr::Select: rbits.knownOneBits = bits[1].knownOneBits & bits[2].knownOneBits; - rbits.knownZeroBits = (bits[1].knownZeroBits & bits[2].knownZeroBits) | zeroMask(e->getWidth()); + rbits.knownZeroBits = bits[1].knownZeroBits & bits[2].knownZeroBits; bits[1].ignoredBits = ignoredBits; bits[2].ignoredBits = ignoredBits; break; - case Expr::ZExt: - rbits.knownOneBits = bits[0].knownOneBits; - // zeroMask of e is less restrictive - rbits.knownZeroBits = bits[0].knownZeroBits; + case Expr::ZExt: { + unsigned width = e->getWidth(); + unsigned kidWidth = kids[0]->getWidth(); - bits[0].ignoredBits = ignoredBits; + // The bits in the zero-extended region are all zero so they should be set them in the known zero mask + rbits.knownOneBits = bits[0].knownOneBits.zext(width); + rbits.knownZeroBits = bits[0].knownZeroBits.zext(width) | APInt::getHighBitsSet(width, width - kidWidth); - break; + bits[0].ignoredBits = ignoredBits.trunc(kidWidth); + + } break; case Expr::SExt: { - // Mask of bits determined by the sign - APInt mask = zeroMask(kids[0]->getWidth()) & ~zeroMask(e->getWidth()); - - rbits.knownOneBits = bits[0].knownOneBits; - rbits.knownZeroBits = bits[0].knownZeroBits & ~mask; - - if ((bits[0].knownOneBits & APInt(64, 1UL << (kids[0]->getWidth() - 1))) != 0) { - // kid[0] is negative - rbits.knownOneBits = bits[0].knownOneBits | mask; - } else if ((bits[0].knownZeroBits & APInt(64, 1UL << (kids[0]->getWidth() - 1))) != 0) { - // kid[0] is positive - rbits.knownZeroBits = bits[0].knownZeroBits | mask; - } + unsigned width = e->getWidth(); + unsigned kidWidth = kids[0]->getWidth(); - bits[0].ignoredBits = ignoredBits; - if ((mask & ~ignoredBits) != 0) { - /* Some of sign-dependend bits are not ignored */ - bits[0].ignoredBits &= APInt(64, ~(1UL << (kids[0]->getWidth() - 1))); + // If the msb of one of the masks is set then the high bits of this + // expression are known and they should be set in the corresponding mask + rbits.knownOneBits = bits[0].knownOneBits.sext(width); + rbits.knownZeroBits = bits[0].knownZeroBits.sext(width); + + bits[0].ignoredBits = ignoredBits.trunc(kidWidth); + + // If any of the bits in the region that got sign-extended are not ignored + // then the msb of kid 0 cannot be ignored + if (ignoredBits.countLeadingOnes() < width - kidWidth) { + bits[0].ignoredBits.clearBit(bits[0].ignoredBits.getBitWidth() - 1); } } break; case Expr::Constant: - rbits.knownOneBits = cast(e)->getAPValue().zextOrSelf(64); + rbits.knownOneBits = cast(e)->getAPValue(); rbits.knownZeroBits = ~rbits.knownOneBits; break; default: // This is the most general assumption - rbits.knownOneBits = APInt::getNullValue(64); - rbits.knownZeroBits = zeroMask(e->getWidth()); + rbits.knownOneBits = APInt::getNullValue(e->getWidth()); + rbits.knownZeroBits = APInt::getNullValue(e->getWidth()); break; } assert((rbits.knownOneBits & rbits.knownZeroBits) == 0); - assert((rbits.knownOneBits & zeroMask(e->getWidth())) == 0); - assert((rbits.knownZeroBits & zeroMask(e->getWidth())) == zeroMask(e->getWidth())); + // The masks should be exactly as wide as the value itself + assert((rbits.knownOneBits.getBitWidth() == e->getWidth()) && (rbits.knownZeroBits.getBitWidth() == e->getWidth())); if (!isa(e) && (~(rbits.knownOneBits | rbits.knownZeroBits | ignoredBits)) == 0) { @@ -347,7 +364,7 @@ ref BitfieldSimplifier::simplify(ref e, APInt *knownZeroBits) { ++m_cacheMisses; - ExprBitsInfo ret = doSimplifyBits(e, APInt::getNullValue(64)); + ExprBitsInfo ret = doSimplifyBits(e, APInt::getNullValue(e->getWidth())); m_simplifiedExpressions[e] = ret;