#include <algorithm>
#include "ASTUtil.h"
#include "ASTKind.h"
+#include <stdint.h>
#include "../sat/core/Solver.h"
//#include "../sat/simp/SimpSolver.h"
//#include "../sat/unsound/UnsoundSimpSolver.h"
// Hash table from ASTNodes to ASTNodes
typedef hash_map<ASTNode, ASTNode, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeMap;
+typedef hash_map<ASTNode, int32_t, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeCountMap;
+
+
// Function to dump contents of ASTNodeMap
ostream &operator<<(ostream &os, const ASTNodeMap &nmap);
ASTNode SimplifyTerm(const ASTNode& a);
ASTNode SimplifyTermAux(const ASTNode& a);
void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output);
+ void BuildReferenceCountMap(const ASTNode& b);
+
private:
//memo table for simplifcation
ASTNodeMap *SimplifyMap;
ASTNodeSet AlwaysTrueFormMap;
ASTNodeMap MultInverseMap;
+
+ // The number of direct parents of each node. i.e. the number of times the pointer is in "children".
+ // When we simplify we want to be careful sometimes about using the context of a node. For example,
+ // given ((x + 23) = 2), the obvious simplification is to join the constants. However, if there are
+ // lots of references to the plus node. Then each time we simplify, we'll create an additional plus.
+ // nextpoweroftwo064.smt is the motivating benchmark. The splitting increased the number of pluses
+ // from 1 to 65.
+ ASTNodeCountMap *ReferenceCount;
+
public:
ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg);
ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2);
///print SAT solver statistics
void PrintStats(MINISAT::Solver& stats);
+ void printCacheStatus();
+
//from v8
int TopLevelSATAux(const ASTNode& query);
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);
+ //Functions that Transform ASTNodes. TransformArray should be a non-member function,
+ // but it accesses private elements. Move it later.
+ ASTNode TransformFormula_TopLevel(const ASTNode& form);
ASTNode TransformArray(const ASTNode& term);
ASTNode TransformFiniteFor(const ASTNode& form);
- ASTNode TranslateSignedDivModRem(const ASTNode& term);
- void assertTransformPostConditions(const ASTNode & term);
+
//LET Management
private:
SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE);
SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE);
_letid_expr_map = new ASTNodeMap(INITIAL_INTRODUCED_SYMBOLS_SIZE);
+ ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_SIZE);
}
;
// -*- c++ -*-
-/* Transform:
+/* Transform:
*
* Converts signed Div/signed remainder/signed modulus into their
* unsigned counterparts. Removes array selects and stores from
* formula. Arrays are replaced by equivalent bit-vector variables
*/
+
#include "AST.h"
#include <stdlib.h>
#include <stdio.h>
namespace BEEV
{
+ASTNode TransformFormula(const ASTNode& form);
+ASTNode TranslateSignedDivModRem(const ASTNode& in);
+ASTNode TransformTerm(const ASTNode& inputterm);
+void assertTransformPostConditions(const ASTNode & term);
+
+ASTNodeMap* TransformMap;
+
+const bool debug_transform = false;
+
+// NB: This is the only function that should be called externally. It sets
+// up the cache that the others use.
+ASTNode BeevMgr::TransformFormula_TopLevel(const ASTNode& form)
+{
+ assert(TransformMap == NULL);
+ TransformMap = new ASTNodeMap(100);
+ ASTNode result = TransformFormula(form);
+ if (debug_transform)
+ assertTransformPostConditions(result);
+ TransformMap->clear();
+ delete TransformMap;
+ TransformMap = NULL;
+ return result;
+}
+
//Translates signed BVDIV,BVMOD and BVREM into unsigned variety
-ASTNode BeevMgr::TranslateSignedDivModRem(const ASTNode& in)
+ASTNode TranslateSignedDivModRem(const ASTNode& in)
{
+ BeevMgr& bm = in.GetBeevMgr();
assert(in.GetChildren().size() ==2);
ASTNode dividend = in[0];
ASTNode divisor = in[1];
unsigned len = in.GetValueWidth();
- ASTNode hi1 = CreateBVConst(32, len - 1);
- ASTNode one = CreateOneConst(1);
- ASTNode zero = CreateZeroConst(1);
+ ASTNode hi1 = bm.CreateBVConst(32, len - 1);
+ ASTNode one = bm.CreateOneConst(1);
+ ASTNode zero = bm.CreateZeroConst(1);
// create the condition for the dividend
- ASTNode cond_dividend = CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1));
+ ASTNode cond_dividend = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1));
// create the condition for the divisor
- ASTNode cond_divisor = CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1));
+ ASTNode cond_divisor = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1));
if (SBVREM == in.GetKind())
{
//BVMOD is an expensive operation. So have the fewest bvmods possible. Just one.
//Take absolute value.
- ASTNode pos_dividend = CreateTerm(ITE, len, cond_dividend, CreateTerm(BVUMINUS, len, dividend), dividend);
- ASTNode pos_divisor = CreateTerm(ITE, len, cond_divisor, CreateTerm(BVUMINUS, len, divisor), divisor);
+ ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend);
+ ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor);
//create the modulus term
- ASTNode modnode = CreateTerm(BVMOD, len, pos_dividend, pos_divisor);
+ ASTNode modnode = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor);
//If the dividend is <0 take the unary minus.
- ASTNode n = CreateTerm(ITE, len, cond_dividend, CreateTerm(BVUMINUS, len, modnode), modnode);
+ ASTNode n = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, modnode), modnode);
//put everything together, simplify, and return
- return SimplifyTerm_TopLevel(n);
+ return bm.SimplifyTerm_TopLevel(n);
}
// This is the modulus of dividing rounding to -infinity.
// (bvneg (bvurem (bvneg s) (bvneg t)))))))
//Take absolute value.
- ASTNode pos_dividend = CreateTerm(ITE, len, cond_dividend, CreateTerm(BVUMINUS, len, dividend), dividend);
- ASTNode pos_divisor = CreateTerm(ITE, len, cond_divisor, CreateTerm(BVUMINUS, len, divisor), divisor);
+ ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend);
+ ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor);
- ASTNode urem_node = CreateTerm(BVMOD, len, pos_dividend, pos_divisor);
+ ASTNode urem_node = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor);
// If the dividend is <0, then we negate the whole thing.
- ASTNode rev_node = CreateTerm(ITE, len, cond_dividend, CreateTerm(BVUMINUS, len, urem_node), urem_node);
+ ASTNode rev_node = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, urem_node), urem_node);
// if It's XOR <0 then add t (not its absolute value).
- ASTNode xor_node = CreateNode(XOR, cond_dividend, cond_divisor);
- ASTNode n = CreateTerm(ITE, len, xor_node, CreateTerm(BVPLUS, len, rev_node, divisor), rev_node);
+ ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor);
+ ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVPLUS, len, rev_node, divisor), rev_node);
- return SimplifyTerm_TopLevel(n);
+ return bm.SimplifyTerm_TopLevel(n);
}
else if (SBVDIV == in.GetKind())
{
//else simply output BVDIV(dividend,divisor)
//Take absolute value.
- ASTNode pos_dividend = CreateTerm(ITE, len, cond_dividend, CreateTerm(BVUMINUS, len, dividend), dividend);
- ASTNode pos_divisor = CreateTerm(ITE, len, cond_divisor, CreateTerm(BVUMINUS, len, divisor), divisor);
+ ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend);
+ ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor);
- ASTNode divnode = CreateTerm(BVDIV, len, pos_dividend, pos_divisor);
+ ASTNode divnode = bm.CreateTerm(BVDIV, len, pos_dividend, pos_divisor);
// A little confusing. Only negate the result if they are XOR <0.
- ASTNode xor_node = CreateNode(XOR, cond_dividend, cond_divisor);
- ASTNode n = CreateTerm(ITE, len, xor_node, CreateTerm(BVUMINUS, len, divnode), divnode);
+ ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor);
+ ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVUMINUS, len, divnode), divnode);
- return SimplifyTerm_TopLevel(n);
+ return bm.SimplifyTerm_TopLevel(n);
}
FatalError("TranslateSignedDivModRem: input must be signed DIV/MOD/REM", in);
- return ASTUndefined;
+ return bm.CreateNode(UNDEFINED);
}//end of TranslateSignedDivModRem()
// Check that the transformations have occurred.
-void BeevMgr::assertTransformPostConditions(const ASTNode & term)
+void assertTransformPostConditions(const ASTNode & term)
{
const Kind k = term.GetKind();
}
}
-ASTNode BeevMgr::TransformFormula(const ASTNode& form)
+ASTNode TransformFormula(const ASTNode& form)
{
+ BeevMgr& bm = form.GetBeevMgr();
+
+ assert(TransformMap != null);
+
ASTNode result;
ASTNode simpleForm = form;
}
ASTNodeMap::iterator iter;
- if ((iter = TransformMap.find(simpleForm)) != TransformMap.end())
+ if ((iter = TransformMap->find(simpleForm)) != TransformMap->end())
return iter->second;
switch (k)
{
ASTVec c;
c.push_back(TransformFormula(simpleForm[0]));
- result = CreateNode(NOT, c);
+ result = bm.CreateNode(NOT, c);
break;
}
case BVLT:
ASTVec c;
c.push_back(TransformTerm(simpleForm[0]));
c.push_back(TransformTerm(simpleForm[1]));
- result = CreateNode(k, c);
+ result = bm.CreateNode(k, c);
break;
}
case EQ:
{
ASTNode term1 = TransformTerm(simpleForm[0]);
ASTNode term2 = TransformTerm(simpleForm[1]);
- result = CreateSimplifiedEQ(term1, term2);
+ result = bm.CreateSimplifiedEQ(term1, term2);
break;
}
case AND:
vec.push_back(o);
}
- result = CreateNode(k, vec);
+ result = bm.CreateNode(k, vec);
break;
}
default:
{
cerr << "The input is: " << simpleForm << endl;
cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << endl;
- FatalError("TransformFormula: Illegal kind: ", ASTUndefined, k);
+ FatalError("TransformFormula: Illegal kind: ", bm.CreateNode(UNDEFINED), k);
}
break;
}
- //assert(BVTypeCheckRecursive(result));
- TransformMap[simpleForm] = result;
+
+ if (simpleForm.GetChildren().size() > 0)
+ (*TransformMap)[simpleForm] = result;
return result;
} //End of TransformFormula
-ASTNode BeevMgr::TransformTerm(const ASTNode& inputterm)
+ASTNode TransformTerm(const ASTNode& inputterm)
{
+ assert(TransformMap != null);
+
+ BeevMgr& bm = inputterm.GetBeevMgr();
+
ASTNode result;
ASTNode term = inputterm;
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())
+ if ((iter = TransformMap->find(term)) != TransformMap->end())
return iter->second;
switch (k)
{
FatalError("TransformTerm: this kind is not supported", term);
break;
case READ:
- result = TransformArray(term);
+ result = bm.TransformArray(term);
break;
case ITE:
{
thn = TransformTerm(thn);
els = TransformTerm(els);
//result = CreateTerm(ITE,term.GetValueWidth(),cond,thn,els);
- result = CreateSimplifiedTermITE(cond, thn, els);
+ result = bm.CreateSimplifiedTermITE(cond, thn, els);
result.SetIndexWidth(term.GetIndexWidth());
break;
}
o.push_back(TransformTerm(*it));
}
- result = CreateTerm(k, width, o);
+ result = bm.CreateTerm(k, width, o);
result.SetIndexWidth(indexwidth);
Kind k = result.GetKind();
// result is embedded unchanged inside the result.
unsigned inputValueWidth = result.GetValueWidth();
- ASTNode zero = CreateZeroConst(inputValueWidth);
- ASTNode one = CreateOneConst(inputValueWidth);
- result = CreateTerm(ITE, inputValueWidth, CreateNode(EQ, zero, bottom), one, result);
+ ASTNode zero = bm.CreateZeroConst(inputValueWidth);
+ ASTNode one = bm.CreateOneConst(inputValueWidth);
+ result = bm.CreateTerm(ITE, inputValueWidth, bm.CreateNode(EQ, zero, bottom), one, result);
}
}
}
break;
}
- TransformMap[term] = result;
+ if (term.GetChildren().size() > 0)
+ (*TransformMap)[term] = result;
if (term.GetValueWidth() != result.GetValueWidth())
FatalError("TransformTerm: result and input terms are of different length", result);
if (term.GetIndexWidth() != result.GetIndexWidth())
*/
ASTNode BeevMgr::TransformArray(const ASTNode& term)
{
+ assert(TransformMap != null);
+
ASTNode result = term;
const unsigned int width = term.GetValueWidth();
FatalError("TransformArray: input term is of wrong kind: ", ASTUndefined);
ASTNodeMap::iterator iter;
- if ((iter = TransformMap.find(term)) != TransformMap.end())
+ if ((iter = TransformMap->find(term)) != TransformMap->end())
return iter->second;
//'term' is of the form READ(arrName, readIndex)
break;
}
- TransformMap[term] = result;
+ (*TransformMap)[term] = result;
return result;
} //end of TransformArray()
-/********************************************************************
+ /********************************************************************
* AUTHORS: Vijay Ganesh
*
* BEGIN DATE: November, 2005
return false;
}
+// Push any reference count used by the key to the value.
void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg)
{
+ // If there are references to the key, add them to the references of the value.
+ ASTNodeCountMap::const_iterator itKey, itValue;
+ itKey = ReferenceCount->find(key);
+ if (itKey != ReferenceCount->end())
+ {
+ itValue = ReferenceCount->find(value);
+ if (itValue != ReferenceCount->end())
+ (*ReferenceCount)[value] = itValue->second + itKey->second;
+ else
+ (*ReferenceCount)[value] = itKey->second;
+ }
+
+
if (pushNeg)
(*SimplifyNegMap)[key] = value;
else
//a is of the form READ(Arr,const), and b is const, or
//a is of the form var, and b is const
- if ((k1 == READ && a[0].GetKind() == SYMBOL && a[1].GetKind() == BVCONST &&
- (k2 == BVCONST)))
- // ||
-// k2 == READ && b[0].GetKind() == SYMBOL && b[1].GetKind() == BVCONST)))
+ if ((k1 == READ && a[0].GetKind() == SYMBOL && a[1].GetKind() == BVCONST && (k2 == BVCONST)))
+ // ||
+ // k2 == READ && b[0].GetKind() == SYMBOL && b[1].GetKind() == BVCONST)))
return 1;
if (SYMBOL == k1 && (BVCONST == k2 || TRUE == k2 || FALSE == k2))
return out;
}
+void BeevMgr::BuildReferenceCountMap(const ASTNode& b)
+{
+ if (b.GetChildren().size() == 0)
+ return;
+
+ ASTNodeCountMap::iterator it, itend;
+
+ it = ReferenceCount->find(b);
+ if (it == ReferenceCount->end())
+ {
+ (*ReferenceCount)[b] = 1;
+ }
+ else
+ {
+ (*ReferenceCount)[b] = it->second + 1;
+ return;
+ }
+
+ const ASTVec& c = b.GetChildren();
+ ASTVec::const_iterator itC = c.begin();
+ ASTVec::const_iterator itendC = c.end();
+ for (; itC != itendC; itC++)
+ {
+ BuildReferenceCountMap(*itC);
+ }
+}
+
ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg)
{
ResetSimplifyMaps();
+ BuildReferenceCountMap(b);
ASTNode out = SimplifyFormula(b, pushNeg);
ResetSimplifyMaps();
return out;
ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg)
{
- if (!optimize_flag)
- return b;
+ if (!optimize_flag)
+ return b;
Kind kind = b.GetKind();
if (BOOLEAN_TYPE != b.GetType())
ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg)
{
if (!optimize_flag)
- return a;
-
+ return a;
ASTNode output;
if (CheckSimplifyMap(a, output, pushNeg))
return result;
}
-
//takes care of some simple ITE Optimizations in the context of equations
ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in)
{
Kind k2 = in2.GetKind();
// if (!optimize_flag)
-// {
-// return CreateNode(EQ, in1, in2);
-// }
+ // {
+ // return CreateNode(EQ, in1, in2);
+ // }
if (in1 == in2)
//terms are syntactically the same
ASTNode BeevMgr::SimplifyIteFormula(const ASTNode& b, bool pushNeg)
{
if (!optimize_flag)
- return b;
+ return b;
ASTNode output;
if (CheckSimplifyMap(b, output, pushNeg))
//cout << "SimplifyTerm: input: " << a << endl;
if (!optimize_flag)
{
- return inputterm;
+ return inputterm;
}
-
ASTNode output;
assert(BVTypeCheck(inputterm));
//########################################
swap_flag = true;
}
+ ASTNodeCountMap::const_iterator it;
+ it = ReferenceCount->find(lhs);
+ if (it != ReferenceCount->end())
+ {
+ if (it->second > 1)
+ return eq;
+ }
+
unsigned int len = lhs.GetValueWidth();
ASTNode zero = CreateZeroConst(len);
//right is -1*(rhs): Simplify(-1*rhs)
//The big substitution function
ASTNode BeevMgr::CreateSubstitutionMap(const ASTNode& a)
{
- if (!wordlevel_solve_flag)
- return a;
+ if (!wordlevel_solve_flag)
+ return a;
ASTNode output = a;
//if the variable has been solved for, then simply return it
// clears() in particular.
void BeevMgr::ResetSimplifyMaps()
{
+ SimplifyMap->clear();
delete SimplifyMap;
SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE);
+ SimplifyNegMap->clear();
delete SimplifyNegMap;
SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE);
+
+ ReferenceCount->clear();
+ delete ReferenceCount;
+ ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_SIZE);
}
}