19#include "llvm/ADT/Hashing.h"
20#if LLVM_VERSION_CODE >= LLVM_VERSION(13, 0)
21#include "llvm/ADT/StringExtras.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/raw_ostream.h"
32llvm::cl::OptionCategory
33 ExprCat(
"Expression building and printing options",
34 "These options impact the way expressions are build and printed.");
38cl::opt<bool> ConstArrayOpt(
39 "const-array-opt", cl::init(
false),
41 "Enable an optimization involving all-constant arrays (default=false)"),
47unsigned Expr::count = 0;
53 default: assert(0 &&
"invalid width");
104 if (
this == &b)
return 0;
113 if (equivs.count(std::make_pair(ap, bp)))
118 return (ak < bk) ? -1 : 1;
127 for (
unsigned i=0; i<aN; i++)
131 equivs.insert(std::make_pair(ap, bp));
137#define X(C) case C: os << #C; break
172 assert(0 &&
"invalid kind");
186 for (
int i = 0; i < n; i++) {
231 unsigned numArgs = args.size();
239 assert(0 &&
"invalid kind");
242 assert(numArgs == 1 && args[0].isExpr() &&
243 "invalid args array for given opcode");
247 assert(numArgs == 3 && args[0].isExpr() &&
248 args[1].isExpr() && args[2].isExpr() &&
249 "invalid args array for Select opcode");
255 assert(numArgs == 2 && args[0].isExpr() && args[1].isExpr() &&
256 "invalid args array for Concat opcode");
261#define CAST_EXPR_CASE(T) \
263 assert(numArgs == 2 && \
264 args[0].isExpr() && args[1].isWidth() && \
265 "invalid args array for given opcode"); \
266 return T ## Expr::create(args[0].expr, args[1].width); \
268#define BINARY_EXPR_CASE(T) \
270 assert(numArgs == 2 && \
271 args[0].isExpr() && args[1].isExpr() && \
272 "invalid args array for given opcode"); \
273 return T ## Expr::create(args[0].expr, args[1].expr); \
314 default: os <<
"<invalid type: " << (unsigned) width <<
">";
348 (width + llvm::APFloatBase::integerPartWidth - 1) /
349 llvm::APFloatBase::integerPartWidth,
350 (
const uint64_t *)address));
356 default: assert(0 &&
"invalid type");
364 *((
long double*) address) = *(
const long double*)
value.getRawData();
370#if LLVM_VERSION_CODE >= LLVM_VERSION(13, 0)
371 Res = llvm::toString(
value, radix,
false);
373 Res =
value.toString(radix,
false);
381 Tmp <<= RHS->getWidth();
382 Tmp |= APInt(RHS->value).zext(W);
511 : name(_name), size(_size), domain(_domain), range(_range),
512 constantValues(constantValuesBegin, constantValuesEnd) {
515 "Invalid size for constant array!");
519 it != constantValuesEnd; ++it)
520 assert((*it)->getWidth() ==
getRange() &&
521 "Invalid initial constant value!");
530 for (
unsigned i = 0, e =
name.size(); i != e; ++i)
545 auto un = ul.
head.get();
546 bool updateListHasSymbolicWrites =
false;
547 for (; un; un = un->next.get()) {
555 updateListHasSymbolicWrites =
true;
563 assert(CE->getWidth() <= 64 &&
"Index too large");
564 uint64_t concreteIndex = CE->getZExtValue();
566 if (concreteIndex < size) {
575 assert(CE->getWidth() <= 64 &&
"Index too large");
576 uint64_t concreteIndex = CE->getZExtValue();
578 if (concreteIndex < size) {
596 assert(kt==f->
getWidth() &&
"type mismatch");
599 return CE->isTrue() ? t : f;
605 return OrExpr::create(c, f);
609 }
else if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(f)) {
613 return AndExpr::create(c, t);
631 return lCE->Concat(rCE);
634 if (
ExtractExpr *ee_left = dyn_cast<ExtractExpr>(l)) {
635 if (
ExtractExpr *ee_right = dyn_cast<ExtractExpr>(r)) {
636 if (ee_left->expr == ee_right->expr &&
637 ee_right->offset + ee_right->width == ee_left->offset) {
653 for (
int i=n_kids-3; i>=0; i--)
677 assert(w > 0 && off + w <= kw &&
"invalid extract");
687 if (off >= ce->getRight()->getWidth())
691 if (off + w <= ce->getRight()->
getWidth())
719 }
else if (w < kBits) {
721 }
else if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(e)) {
724 return ZExtExpr::alloc(e, w);
732 }
else if (w < kBits) {
734 }
else if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(e)) {
737 return SExtExpr::alloc(e, w);
756 }
else if (cl->isZero()) {
761 return AddExpr::create(AddExpr::create(cl, r->
getKid(0)),
764 return SubExpr::create(AddExpr::create(cl, r->
getKid(0)),
767 return AddExpr::alloc(cl, r);
782 return AddExpr::create(l->
getKid(0),
783 AddExpr::create(l->
getKid(1), r));
785 return AddExpr::create(l->
getKid(0),
786 SubExpr::create(r, l->
getKid(1)));
788 return AddExpr::create(r->
getKid(0),
789 AddExpr::create(l, r->
getKid(1)));
791 return AddExpr::create(r->
getKid(0),
792 SubExpr::create(l, r->
getKid(1)));
794 return AddExpr::alloc(l, r);
807 return SubExpr::create(SubExpr::create(cl, r->
getKid(0)),
810 return AddExpr::create(SubExpr::create(cl, r->
getKid(0)),
813 return SubExpr::alloc(cl, r);
832 return AddExpr::create(l->
getKid(0),
833 SubExpr::create(l->
getKid(1), r));
835 return SubExpr::create(l->
getKid(0),
836 AddExpr::create(l->
getKid(1), r));
838 return SubExpr::create(SubExpr::create(l, r->
getKid(1)),
841 return SubExpr::create(AddExpr::create(l, r->
getKid(1)),
844 return SubExpr::alloc(l, r);
854 }
else if (cl->isOne()) {
856 }
else if (cl->isZero()) {
859 return MulExpr::alloc(cl, r);
869 return AndExpr::alloc(l, r);
871 return MulExpr::alloc(l, r);
876 if (cr->isAllOnes()) {
878 }
else if (cr->isZero()) {
881 return AndExpr::alloc(l, cr);
888 return AndExpr::alloc(l, r);
892 if (cr->isAllOnes()) {
894 }
else if (cr->isZero()) {
897 return OrExpr::alloc(l, cr);
904 return OrExpr::alloc(l, r);
913 return XorExpr::alloc(cl, r);
921 return XorExpr::alloc(l, r);
928 return UDivExpr::alloc(l, r);
936 return SDivExpr::alloc(l, r);
944 return URemExpr::alloc(l, r);
952 return SRemExpr::alloc(l, r);
960 return ShlExpr::alloc(l, r);
968 return LShrExpr::alloc(l, r);
976 return AShrExpr::alloc(l, r);
980#define BCREATE_R(_e_op, _op, partialL, partialR) \
981ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
982 assert(l->getWidth()==r->getWidth() && "type mismatch"); \
983 if (ConstantExpr *cl = dyn_cast<ConstantExpr>(l)) { \
984 if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) \
985 return cl->_op(cr); \
986 return _e_op ## _createPartialR(cl, r.get()); \
987 } else if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) { \
988 return _e_op ## _createPartial(l.get(), cr); \
990 return _e_op ## _create(l.get(), r.get()); \
993#define BCREATE(_e_op, _op) \
994ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
995 assert(l->getWidth()==r->getWidth() && "type mismatch"); \
996 if (ConstantExpr *cl = dyn_cast<ConstantExpr>(l)) \
997 if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) \
998 return cl->_op(cr); \
999 return _e_op ## _create(l, r); \
1016#define CMPCREATE(_e_op, _op) \
1017ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
1018 assert(l->getWidth()==r->getWidth() && "type mismatch"); \
1019 if (ConstantExpr *cl = dyn_cast<ConstantExpr>(l)) \
1020 if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) \
1021 return cl->_op(cr); \
1022 return _e_op ## _create(l, r); \
1025#define CMPCREATE_T(_e_op, _op, _reflexive_e_op, partialL, partialR) \
1026ref<Expr> _e_op ::create(const ref<Expr> &l, const ref<Expr> &r) { \
1027 assert(l->getWidth()==r->getWidth() && "type mismatch"); \
1028 if (ConstantExpr *cl = dyn_cast<ConstantExpr>(l)) { \
1029 if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) \
1030 return cl->_op(cr); \
1031 return partialR(cl, r.get()); \
1032 } else if (ConstantExpr *cr = dyn_cast<ConstantExpr>(r)) { \
1033 return partialL(l.get(), cr); \
1035 return _e_op ## _create(l.get(), r.get()); \
1044 return EqExpr::alloc(l, r);
1059 unsigned numMatches = 0;
1067 if (++numMatches > 100)
1073 res = OrExpr::create(res, mayBe);
1091 const EqExpr *ree = cast<EqExpr>(r);
1094 if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(ree->left)) {
1101 const OrExpr *roe = cast<OrExpr>(r);
1110 const SExtExpr *see = cast<SExtExpr>(r);
1116 if (cl ==
trunc->SExt(width)) {
1117 return EqExpr::create(see->src,
trunc);
1123 const ZExtExpr *zee = cast<ZExtExpr>(r);
1129 if (cl ==
trunc->ZExt(width)) {
1130 return EqExpr::create(zee->src,
trunc);
1135 const AddExpr *ae = cast<AddExpr>(r);
1136 if (isa<ConstantExpr>(ae->left)) {
1143 const SubExpr *se = cast<SubExpr>(r);
1144 if (isa<ConstantExpr>(se->left)) {
1150 }
else if (rk ==
Expr::Read && ConstArrayOpt) {
1163 EqExpr::create(l, r));
1167 return UltExpr::create(r, l);
1170 return UleExpr::create(r, l);
1174 return SltExpr::create(r, l);
1177 return SleExpr::create(r, l);
1185 return UltExpr::alloc(l, r);
1193 return UleExpr::alloc(l, r);
1201 return SltExpr::alloc(l, r);
1209 return SleExpr::alloc(l, r);
static ref< Expr > EqExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > OrExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > XorExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > SubExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > MulExpr_create(Expr *l, Expr *r)
static ref< Expr > AddExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > UleExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > AddExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > TryConstArrayOpt(const ref< ConstantExpr > &cl, ReadExpr *rd)
static ref< Expr > EqExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > MulExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
#define CMPCREATE_T(_e_op, _op, _reflexive_e_op, partialL, partialR)
static ref< Expr > UDivExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > OrExpr_create(Expr *l, Expr *r)
static ref< Expr > URemExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > SubExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > OrExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
#define CMPCREATE(_e_op, _op)
static ref< Expr > AndExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > SDivExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > SltExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > EqExpr_create(const ref< Expr > &l, const ref< Expr > &r)
#define BCREATE(_e_op, _op)
static ref< Expr > MulExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > ShlExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > AddExpr_create(Expr *l, Expr *r)
#define BINARY_EXPR_CASE(T)
static ref< Expr > SleExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > XorExpr_createPartialR(const ref< ConstantExpr > &cl, Expr *r)
static ref< Expr > XorExpr_create(Expr *l, Expr *r)
#define CAST_EXPR_CASE(T)
static ref< Expr > AndExpr_createPartial(Expr *l, const ref< ConstantExpr > &cr)
static ref< Expr > UltExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > LShrExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > AndExpr_create(Expr *l, Expr *r)
static ref< Expr > SubExpr_create(Expr *l, Expr *r)
#define BCREATE_R(_e_op, _op, partialL, partialR)
static ref< Expr > AShrExpr_create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > SRemExpr_create(const ref< Expr > &l, const ref< Expr > &r)
Array(const Array &array)
Expr::Width getRange() const
bool isConstantArray() const
bool isSymbolicArray() const
const std::vector< ref< ConstantExpr > > constantValues
unsigned computeHash()
ComputeHash must take into account the name, the size, the domain, and the range.
virtual unsigned computeHash()
static ref< Expr > createN(unsigned nKids, const ref< Expr > kids[])
Shortcuts to create larger concats. The chain returned is unbalanced to the right.
static ref< Expr > alloc(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > create(const ref< Expr > &l, const ref< Expr > &r)
static ref< Expr > 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)
Shortcut to concat 8 kids. The chain returned is unbalanced to the right.
static ref< Expr > create4(const ref< Expr > &kid1, const ref< Expr > &kid2, const ref< Expr > &kid3, const ref< Expr > &kid4)
Shortcut to concat 4 kids. The chain returned is unbalanced to the right.
ref< ConstantExpr > Not()
void toMemory(void *address)
virtual unsigned computeHash()
static ref< ConstantExpr > create(uint64_t v, Width w)
static ref< ConstantExpr > alloc(const llvm::APInt &v)
uint64_t getZExtValue(unsigned bits=64) const
ref< ConstantExpr > Neg()
static ref< Expr > fromMemory(void *address, Width w)
void toString(std::string &Res, unsigned radix=10) const
static void printSingleExpr(llvm::raw_ostream &os, const ref< Expr > &e)
Class representing symbolic expressions.
static const unsigned MAGIC_HASH_CONSTANT
virtual unsigned computeHash()
virtual Kind getKind() const =0
virtual void print(llvm::raw_ostream &os) const
int compare(const Expr &b) const
static ref< Expr > createIsZero(ref< Expr > e)
virtual int compareContents(const Expr &b) const =0
virtual unsigned hash() const
Returns the pre-computed hash of the current expression.
virtual Width getWidth() const =0
virtual unsigned getNumKids() const =0
static void printWidth(llvm::raw_ostream &os, Expr::Width w)
@ Sge
Not used in canonical form.
@ Ne
Not used in canonical form.
@ Ugt
Not used in canonical form.
@ Sgt
Not used in canonical form.
@ Uge
Not used in canonical form.
unsigned Width
The type of an expression is simply its width, in bits.
llvm::DenseSet< std::pair< const Expr *, const Expr * > > ExprEquivSet
static ref< Expr > createFromKind(Kind k, std::vector< CreateArg > args)
virtual ref< Expr > getKid(unsigned i) const =0
static ref< Expr > createImplies(ref< Expr > hyp, ref< Expr > conc)
static void printKind(llvm::raw_ostream &os, Kind k)
void dump() const
dump - Print the expression to stderr.
static ref< Expr > create(const ref< Expr > &e)
static ref< Expr > alloc(const ref< Expr > &e)
virtual unsigned computeHash()
static ref< Expr > create(ref< Expr > src)
static ref< Expr > alloc(const ref< Expr > &src)
Class representing a one byte read from an array.
virtual unsigned computeHash()
int compareContents(const Expr &b) const
static ref< Expr > alloc(const UpdateList &updates, const ref< Expr > &index)
static ref< Expr > create(const UpdateList &updates, ref< Expr > i)
static ref< Expr > create(ref< Expr > c, ref< Expr > t, ref< Expr > f)
static ref< Expr > alloc(const ref< Expr > &c, const ref< Expr > &t, const ref< Expr > &f)
Class representing a complete list of updates into an array.
ref< UpdateNode > head
pointer to the most recent update node
unsigned getSize() const
size of this update list
int compare(const UpdateList &b) const
uint64_t trunc(uint64_t l, unsigned outWidth, unsigned inWidth)
llvm::cl::OptionCategory ExprCat