{
bm->GetRunTimes()->start(RunTimes::ApplyingSubstitutions);
ASTNodeMap cache;
- ASTNode result = replace(n,*SolverMap,cache,nf, false);
+ ASTNode result = replace(n,*SolverMap,cache,nf, false,false);
// NB. This is an expensive check. Remove it after it's been idempotent
// for a while.
#ifndef NDEBUG
cache.clear();
- assert( result == replace(result,*SolverMap,cache,nf, false));
+ assert( result == replace(result,*SolverMap,cache,nf, false,false));
#endif
bm->GetRunTimes()->stop(RunTimes::ApplyingSubstitutions);
{
bm->GetRunTimes()->start(RunTimes::ApplyingSubstitutions);
ASTNodeMap cache;
- ASTNode result = replace(n,*SolverMap,cache,nf, true);
+ ASTNode result = replace(n,*SolverMap,cache,nf, true,false);
bm->GetRunTimes()->stop(RunTimes::ApplyingSubstitutions);
return result;
}
ASTNode SubstitutionMap::replace(const ASTNode& n, ASTNodeMap& fromTo,
ASTNodeMap& cache, NodeFactory * nf)
{
- return replace(n,fromTo,cache,nf,false);
+ return replace(n,fromTo,cache,nf,false,false);
}
// NOTE the fromTo map is changed as we traverse downwards.
// It's optimised for the symbol to something case.
ASTNode SubstitutionMap::replace(const ASTNode& n, ASTNodeMap& fromTo,
- ASTNodeMap& cache, NodeFactory * nf, bool stopAtArrays)
+ ASTNodeMap& cache, NodeFactory * nf, bool stopAtArrays , bool preventInfinite)
{
const Kind k = n.GetKind();
if (k == BVCONST || k == TRUE || k == FALSE)
{
const ASTNode& r = it->second;
assert(r.GetIndexWidth() == n.GetIndexWidth());
- ASTNode replaced = replace(r, fromTo, cache,nf,stopAtArrays);
+ ASTNode replaced = replace(r, fromTo, cache,nf,stopAtArrays,preventInfinite);
if (replaced != r)
fromTo[n] = replaced;
for (ASTVec::const_iterator it = children.begin(); it != children.end(); it++)
{
- new_children.push_back(replace(*it, fromTo, cache,nf,stopAtArrays));
+ new_children.push_back(replace(*it, fromTo, cache,nf,stopAtArrays,preventInfinite));
}
assert(new_children.size() == children.size());
// I hope that this makes it idempotent.
if (fromTo.find(result) != fromTo.end())
- result = replace(result, fromTo, cache,nf,stopAtArrays);
+ {
+ // map n->result, if running replace() on result gives us 'n', it will not infinite loop.
+ // This is only currently required for the bitblast equivalence stuff.
+ if (preventInfinite)
+ cache.insert(make_pair(n,result));
+
+ result = replace(result, fromTo, cache,nf,stopAtArrays,preventInfinite);
+ }
assert(result.GetValueWidth() == valueWidth);
assert(result.GetIndexWidth() == indexWidth);
+ // If there is already an "n" element in the cache, the maps semantics are to ignore the next insertion.
+ if (preventInfinite)
+ cache.erase(n);
+
cache.insert(make_pair(n,result));
return result;
}
return (loops);
}
-
-ASTNode
-SubstitutionMap::simple_replace(const ASTNode& n, ASTNodeMap& fromTo, ASTNodeMap& cache, NodeFactory * nf)
-{
- const Kind k = n.GetKind();
- if (k == BVCONST || k == TRUE || k == FALSE)
- return n;
-
- ASTNodeMap::const_iterator it;
-
- if ((it = cache.find(n)) != cache.end())
- return it->second;
-
- if ((it = fromTo.find(n)) != fromTo.end())
- {
- const ASTNode& r = it->second;
- assert(r.GetIndexWidth() == n.GetIndexWidth());
- cache.insert(make_pair(n, r));
- return r;
- }
-
- // These can't be created like regular nodes are
- if (k == SYMBOL)
- return n;
-
- const unsigned int indexWidth = n.GetIndexWidth();
-
- const ASTVec& children = n.GetChildren();
- assert(children.size() > 0);
- // Should have no leaves left here.
-
- ASTVec new_children;
- new_children.reserve(children.size());
-
- for (ASTVec::const_iterator it = children.begin(); it != children.end(); it++)
- {
- new_children.push_back(simple_replace(*it, fromTo, cache, nf));
- }
-
- assert(new_children.size() == children.size());
-
- // This code short-cuts if the children are the same. Nodes with the same children,
- // won't have necessarily given the same node if the simplifyingNodeFactory is enabled
- // now, but wasn't enabled when the node was created. Shortcutting saves lots of time.
- if (new_children == children)
- {
- cache.insert(make_pair(n, n));
- return n;
- }
-
- ASTNode result;
- const unsigned int valueWidth = n.GetValueWidth();
-
- if (valueWidth == 0) // n.GetType() == BOOLEAN_TYPE
- {
- result = nf->CreateNode(k, new_children);
- }
- else
- {
- // If the index and value width aren't saved, they are reset sometimes (??)
- result = nf->CreateArrayTerm(k, indexWidth, valueWidth, new_children);
- }
-
- // We may have created something that should be mapped. For instance,
- // if n is READ(A, x), and the fromTo is: {x==0, READ(A,0) == 1}, then
- // by here the result will be READ(A,0). Which needs to be mapped again..
- // I hope that this makes it idempotent.
-
- assert(result.GetValueWidth() == valueWidth);
- assert(result.GetIndexWidth() == indexWidth);
-
- cache.insert(make_pair(n, result));
- return result;
-}
-
};