{
static vector<MutableASTNode*> all;
+ public:
typedef set<MutableASTNode *> ParentsType;
ParentsType parents;
-
+private:
MutableASTNode(const MutableASTNode&); // No definition
MutableASTNode&
operator=(const MutableASTNode &); // No definition
}
}
+ // Variables that have >1 disjoint extract parents.
+ static void
+ getDisjointExtractVariables(vector<MutableASTNode*> & result)
+ {
+ const int size = all.size();
+ for (int i = size-1; i >=0 ; i--)
+ {
+ if (!all[i]->isSymbol())
+ continue;
+
+ ParentsType* p = &(all[i]->parents);
+
+ if (p->size() ==1 )
+ continue; // the regular case. Don't consider here.
+
+ ASTNode& node = all[i]->n;
+ bool found[node.GetValueWidth()];
+ for (int j=0; j <node.GetValueWidth();j++)
+ found[j] = false;
+
+ ParentsType::const_iterator it;
+ for (it = p->begin(); it!= p->end();it++)
+ {
+ ASTNode& parent_node = (*it)->n;
+ if (parent_node.GetKind() != BVEXTRACT)
+ break;
+
+ const int lb = parent_node[2].GetUnsignedConst();
+ const int ub = parent_node[1].GetUnsignedConst();
+ assert(lb<=ub);
+
+ int j;
+ for (j =lb ; j <=ub;j++)
+ {
+ if (found[j])
+ break;
+ found[j] = true;
+ }
+
+ // if didn't make it to the finish. Then it overlaps.
+ if (j<= ub)
+ {
+ break;
+ }
+ }
+
+ if (it != p->end())
+ continue;
+
+ // All are extracts that don't overlap.
+ result.push_back(all[i]);
+ }
+ return;
+ }
+
// Visit the parent before children. So that we hopefully prune parts of the
// tree. Ie given ( F(x_1,... x_10000) = v), where v is unconstrained,
// we don't spend time exploring F(..), but chop it out.
- void
+ static void
getAllUnconstrainedVariables(vector<MutableASTNode*> & result)
{
const int size = all.size();
* Robert Bruttomesso's & Robert Brummayer's dissertations describe this.
*
* Nb. this isn't finished. It doesn't do READS, left shift, implies.
-* I don't think anything can be done for : bvsx, bvzx, write, bvmod.
+ * I don't think anything can be done for : bvsx, bvzx, write, bvmod.
*/
#include "RemoveUnconstrained.h"
simplifier->haveAppliedSubstitutionMap();
result = topLevel_other(result, simplifier);
- #ifndef NDEBUG
+
+ // It is idempotent if there are no big ANDS (we have a special hack), and,
+ // if we don't introduced any new "disjoint extracts."
+
+ #if 0
ASTNode result2 = topLevel_other(result, simplifier);
if (result2 != result)
{
RemoveUnconstrained::replace(const ASTNode& from, const ASTNode to)
{
assert(from.GetKind() == SYMBOL);
+ assert(from.GetValueWidth() == to.GetValueWidth());
simplifier_convenient->UpdateSubstitutionMapFewChecks(from, to);
return;
}
+ /* The most complicated handling is for EXTRACTS. If a variable has parents that
+ * are all extracts and each of those extracts is disjoint (i.e. reads different bits)
+ * Then each of the extracts are replaced by a fresh variable. This is the only case
+ * where a variable with multiple distinct parents is replaced by a fresh variable.
+ * + We perform this check upfront, so will miss any extra cases the the unconstrained
+ * variable elimination introduces.
+ * + It's all or nothing. So even if there's an extract of [0:2] [1:2] and [3:5], we wont
+ * replace the [3:5] (even though it could be).
+ */
+ void
+ RemoveUnconstrained::
+ splitExtractOnly(vector<MutableASTNode*> extracts)
+ {
+ assert(extracts.size() >0);
+
+ // Going to be rebuilt later anyway, so discard.
+ vector<MutableASTNode*> variables;
+
+ for (int i =0; i <extracts.size(); i++)
+ {
+ ASTNode& var = extracts[i]->n;
+ assert(var.GetKind() == SYMBOL);
+ const int size = var.GetValueWidth();
+ ASTNode toVar[size];
+
+ // Create a mutable copy that we can iterate over.
+ vector <MutableASTNode*> mut;
+ mut.insert(mut.end(), extracts[i]->parents.begin(), extracts[i]->parents.end());
+
+ for (vector<MutableASTNode*>::iterator it = mut.begin(); it != mut.end(); it++)
+ {
+ ASTNode parent_node = (*it)->n;
+ assert(((**it)).children[0] == extracts[i]);
+ assert(!parent_node.IsNull());
+ assert(parent_node.GetKind() == BVEXTRACT);
+
+ int lb = parent_node[2].GetUnsignedConst();
+ // Replace each parent with a fresh.
+ toVar[lb] = replaceParentWithFresh(**it,variables);
+ }
+
+ ASTVec concatVec;
+ int empty =0;
+ for (int j=0; j < size;j++)
+ {
+ if (toVar[j].IsNull())
+ {
+ empty++;
+ continue;
+ }
+
+ if (empty > 0)
+ {
+ concatVec.push_back(bm.CreateFreshVariable(0, empty, "extract_unc"));
+ empty = 0;
+ }
+
+ concatVec.push_back(toVar[j]);
+ //cout << toVar[j];
+ assert(toVar[j].GetValueWidth() > 0);
+ j+=toVar[j].GetValueWidth()-1;
+ }
+
+ if (empty> 0)
+ {
+ concatVec.push_back(bm.CreateFreshVariable(0, empty, "extract_unc"));
+ }
+
+ ASTNode concat = concatVec[0];
+ for (int i=1; i < concatVec.size();i++)
+ {
+ assert(!concat.IsNull());
+ concat = bm.CreateTerm(BVCONCAT, concat.GetValueWidth() + concatVec[i].GetValueWidth(),concatVec[i], concat);
+ }
+
+ replace(var,concat);
+ }
+ }
+
ASTNode
RemoveUnconstrained::topLevel_other(const ASTNode &n, Simplifier *simplifier)
{
vector<MutableASTNode*> variable_array;
MutableASTNode* topMutable = MutableASTNode::build(n);
+
+ vector<MutableASTNode*> extracts;
+ topMutable->getDisjointExtractVariables(extracts);
+ if (extracts.size() > 0)
+ {
+ splitExtractOnly(extracts);
+ }
+
topMutable->getAllUnconstrainedVariables(variable_array);
for (int i =0; i < variable_array.size() ; i++)