// If the bits are totally fixed, then return a new matching ASTNode.
    ASTNode
    bitsToNode(const ASTNode& node, const FixedBits& bits)
    {
      ASTNode result;
      STPMgr & beev = *node.GetSTPMgr();

      assert (bits.isTotallyFixed());
      assert (!node.isConstant()); // Peformance. Shouldn't waste time calling it on constants.

      if (node.GetType() == BOOLEAN_TYPE)
        {
          if (bits.getValue(0))
            {
              result = beev.CreateNode(TRUE);
            }
          else
            {
              result = beev.CreateNode(FALSE);
            }
        }
      else if (node.GetType() == BITVECTOR_TYPE)
        {
          result = beev.CreateBVConst(bits.GetBVConst(), node.GetValueWidth());
        }
      else
        FatalError("sadf234s");

      assert(result.isConstant());
      return result;
    }
Example #2
0
// Build the polarities, then iterate through fixing them.
bool FindPureLiterals::topLevel(ASTNode& n, Simplifier* simplifier,
                                STPMgr* stpMgr)
{
  stpMgr->GetRunTimes()->start(RunTimes::PureLiterals);

  build(n, truePolarity);
  bool changed = false;

  map<ASTNode, polarity_type>::const_iterator it = nodeToPolarity.begin();
  while (it != nodeToPolarity.end())
  {
    const ASTNode& n = it->first;
    const polarity_type polarity = it->second;
    if (n.GetType() == BOOLEAN_TYPE && n.GetKind() == SYMBOL &&
        polarity != bothPolarity)
    {
      if (polarity == truePolarity)
        simplifier->UpdateSubstitutionMap(n, stpMgr->ASTTrue);
      else
      {
        assert(polarity == falsePolarity);
        simplifier->UpdateSubstitutionMap(n, stpMgr->ASTFalse);
      }
      changed = true;
    }
    it++;
  }
  stpMgr->GetRunTimes()->stop(RunTimes::PureLiterals);
  return changed;
}
Example #3
0
bool containsArrayOps(const ASTNode& n, ASTNodeSet& visited)
{
	if (visited.find(n) != visited.end())
		return false;
	if (n.GetType() == ARRAY_TYPE)
		return true;

	for (int i =0; i < n.Degree();i++)
		if (containsArrayOps(n[i],visited))
			return true;

	visited.insert(n);
	return false;
}
    // Propagates. No writing in of values. Doesn't assume the top is true.
    ConstantBitPropagation::ConstantBitPropagation(BEEV::Simplifier* _sm, NodeFactory* _nf,const ASTNode & top)
    {
      assert (BOOLEAN_TYPE == top.GetType());
      assert (top.GetSTPMgr()->UserFlags.bitConstantProp_flag);

      status = NO_CHANGE;
      simplifier = _sm;
      nf = _nf;
      fixedMap = new NodeToFixedBitsMap(1000); // better to use the function that returns the number of nodes.. whatever that is.
      workList = new WorkList(top);
      dependents = new Dependencies(top); // List of the parents of a node.
      msm = new MultiplicationStatsMap();


      // not fixing the topnode.
      propagate();

      if (debug_cBitProp_messages)
        {
          cerr << "status:" << status <<endl;
          cerr << "ended propagation" << endl;
          printNodeWithFixings();
        }

      // is there are good reason to clear out some of them??
#if 0
      // remove constants, and things with nothing fixed.
      NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it =
          fixedMap->map->begin();
      NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it_end =
          fixedMap->map->end();
      while (it != it_end)
        {
          // No constants, nothing completely unfixed.
          if (  (it->second)->countFixed() == 0 )
            {
              delete it->second;
              // making this a reference causes reading from freed memory.
              const ASTNode n = it->first;
              it++;
              fixedMap->map->erase(n);
            }
          else
            it++;
        }
#endif

      topFixed = false;
    }
  /* FUNCTION: Typechecker for terms and formulas
   *
   * TypeChecker: Assumes that the immediate Children of the input
   * ASTNode have been typechecked. This function is suitable in
   * scenarios like where you are building the ASTNode Tree, and you
   * typecheck as you go along. It is not suitable as a general
   * typechecker.
   *
   * If this returns, this ALWAYS returns true. If there is an error it
   * will call FatalError() and abort.
   */
  bool BVTypeCheck(const ASTNode& n)
  {
    Kind k = n.GetKind();
    //The children of bitvector terms are in turn bitvectors.
    const ASTVec& v = n.GetChildren();
    if (is_Term_kind(k))
      {
        switch (k)
          {
          case BVCONST:
            if (BITVECTOR_TYPE != n.GetType())
              FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n);
            break;
          case SYMBOL:
            return true;
          case ITE:
  			if (n.Degree() != 3)
  				FatalError("BVTypeCheck: should have exactly 3 args\n", n);
        	if (BOOLEAN_TYPE != n[0].GetType() || (n[1].GetType() != n[2].GetType()))
              FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n);
            if (n[1].GetValueWidth() != n[2].GetValueWidth())
              FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n);
            if (n[1].GetIndexWidth() != n[2].GetIndexWidth())
              FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n);
            break;
          case READ:
            if (n.GetChildren().size() !=2)
              FatalError("2 params to read.");
            if (n[0].GetIndexWidth() != n[1].GetValueWidth())
              {
                cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl;
                cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl;
                FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n);
              }
            if (ARRAY_TYPE != n[0].GetType())
              FatalError("First parameter to read should be an array", n[0]);
            if (BITVECTOR_TYPE != n[1].GetType())
              FatalError("Second parameter to read should be a bitvector", n[1]);
            break;
          case WRITE:
            if (n.GetChildren().size() !=3)
              FatalError("3 params to write.");
            if (n[0].GetIndexWidth() != n[1].GetValueWidth())
              FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n);
            if (n[0].GetValueWidth() != n[2].GetValueWidth())
              FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n", n);
            if (ARRAY_TYPE != n[0].GetType())
              FatalError("First parameter to read should be an array", n[0]);
            if (BITVECTOR_TYPE != n[1].GetType())
              FatalError("Second parameter to read should be a bitvector", n[1]);
            if (BITVECTOR_TYPE != n[2].GetType())
              FatalError("Third parameter to read should be a bitvector", n[2]);

            break;

          case BVDIV:
          case BVMOD:
          case BVSUB:

          case SBVDIV:
          case SBVREM:
          case SBVMOD:

          case BVLEFTSHIFT:
          case BVRIGHTSHIFT:
          case BVSRSHIFT:
          case BVVARSHIFT:
        	  if (n.Degree() != 2)
        		  FatalError("BVTypeCheck: should have exactly 2 args\n", n);
        	  // run on.
          case BVOR:
          case BVAND:
          case BVXOR:
          case BVNOR:
          case BVNAND:
          case BVXNOR:

          case BVPLUS:
          case BVMULT:
            {
              if (!(v.size() >= 2))
                FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have at least two arguments\n", n);
              unsigned int width = n.GetValueWidth();
              for (ASTVec::const_iterator it = v.begin(), itend = v.end(); it != itend; it++)
                {
                  if (width != it->GetValueWidth())
                    {
                      cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n";
                      cerr << n << endl;
                      cerr << "width of term:" << width << endl;
                      cerr << "width of offending operand:" << it->GetValueWidth() << endl;
                      FatalError("BVTypeCheck:Offending operand:\n", *it);
                    }
                  if (BITVECTOR_TYPE != it->GetType())
                    FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n", n);
                }
              break;
            }
          case BVSX:
          case BVZX:
			//in BVSX(n[0],len), the length of the BVSX term must be
			//greater than the length of n[0]
			if (n[0].GetValueWidth() > n.GetValueWidth()) {
				FatalError(
						"BVTypeCheck: BV[SZ]X(t,bv[sz]x_len) : length of 't' must be <= bv[sz]x_len\n",
						n);
			}
			if ((v.size() != 2))
				FatalError(
						"BVTypeCheck:BV[SZ]X must have two arguments. The second is the new width\n",
						n);
			break;

		case BVCONCAT:
			checkChildrenAreBV(v, n);
			if (n.Degree() != 2)
				FatalError("BVTypeCheck: should have exactly 2 args\n", n);
			if (n.GetValueWidth() != n[0].GetValueWidth()
					+ n[1].GetValueWidth())
				FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n", n);
			break;
		case BVUMINUS:
		case BVNEG:
			checkChildrenAreBV(v, n);
			if (n.Degree() != 1)
				FatalError("BVTypeCheck: should have exactly 1 args\n", n);
			break;
		case BVEXTRACT:
			checkChildrenAreBV(v, n);
			if (n.Degree() != 3)
				FatalError("BVTypeCheck: should have exactly 3 args\n", n);
			if (!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind()))
				FatalError("BVTypeCheck: indices should be BVCONST\n", n);
			if (n.GetValueWidth() != n[1].GetUnsignedConst()
					- n[2].GetUnsignedConst() + 1)
				FatalError("BVTypeCheck: length mismatch\n", n);
			if (n[1].GetUnsignedConst() >= n[0].GetValueWidth())
				FatalError(
						"BVTypeCheck: Top index of select is greater or equal to the bitwidth.\n",
						n);
			break;
		default:
			cerr << _kind_names[k];
			FatalError("No type checking for type");
			break;
		}
      }
    else
      {
        if (!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType()))
          FatalError("BVTypeCheck: not a formula:", n);
        switch (k)
          {
          case TRUE:
          case FALSE:
          case SYMBOL:
            return true;
          case BOOLEXTRACT:
            checkChildrenAreBV(v, n);
            if (n.Degree() != 2)
              FatalError("BVTypeCheck: should have exactly 2 args\n", n);
            if (!(BVCONST == n[1].GetKind()))
              FatalError("BVTypeCheck: index should be BVCONST\n", n);
            if (n[1].GetUnsignedConst() >= n[0].GetValueWidth())
              FatalError("BVTypeCheck: index is greater or equal to the bitwidth.\n", n);
            break;
          case PARAMBOOL:
            if(2 != n.Degree())
              FatalError("BVTypeCheck: PARAMBOOL formula can have exactly two childNodes", n);
            break;
          case EQ:
  			if (n.Degree() != 2)
  				FatalError("BVTypeCheck: should have exactly 2 args\n", n);
        	if (!(n[0].GetValueWidth() == n[1].GetValueWidth() && n[0].GetIndexWidth() == n[1].GetIndexWidth()))
              {
                cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl;
                cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl;
                cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl;
                cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl;
                FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n);
              }
            break;
          case BVLT:
          case BVLE:
          case BVGT:
          case BVGE:
          case BVSLT:
          case BVSLE:
          case BVSGT:
          case BVSGE:
  			if (n.Degree() != 2)
  				FatalError("BVTypeCheck: should have exactly 2 args\n", n);
            if (BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType())
              FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors", n);
            if (n[0].GetValueWidth() != n[1].GetValueWidth())
              FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n);
            if (n[0].GetIndexWidth() != n[1].GetIndexWidth())
              FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n);
            break;
          case NOT:
            if (1 != n.Degree())
              FatalError("BVTypeCheck: NOT formula can have exactly one childNode", n);
            break;
          case AND:
          case OR:
          case XOR:
          case NAND:
          case NOR:
            if (2 > n.Degree())
              FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes", n);
            break;
          case IFF:
          case IMPLIES:
            if (2 != n.Degree())
              FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes", n);
            break;
          case ITE:
            if (3 != n.Degree())
              FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes", n);
            break;
          default:
            FatalError("BVTypeCheck: Unrecognized kind: ");
            break;
          }
      }
    return true;
  } //End of TypeCheck function
Example #6
0
bool BVTypeCheck_nonterm_kind(const ASTNode& n, const Kind& k)
{
  // The children of bitvector terms are in turn bitvectors.
  const ASTVec& v = n.GetChildren();

  if (!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType()))
    FatalError("BVTypeCheck: not a formula:", n);

  switch (k)
  {
    case TRUE:
    case FALSE:
    case SYMBOL:
      return true;

    case BOOLEXTRACT:
      checkChildrenAreBV(v, n);

      if (n.Degree() != 2)
        FatalError("BVTypeCheck: should have exactly 2 args\n", n);
      if (!(BVCONST == n[1].GetKind()))
        FatalError("BVTypeCheck: index should be BVCONST\n", n);
      if (n[1].GetUnsignedConst() >= n[0].GetValueWidth())
      {
        FatalError(
            "BVTypeCheck: index is greater or equal to the bitwidth.\n", n);
      }
      break;

    case PARAMBOOL:
      if (2 != n.Degree())
      {
        FatalError(
            "BVTypeCheck: PARAMBOOL formula can have exactly two childNodes",
            n);
      }
      break;

    case EQ:
      if (n.Degree() != 2)
        FatalError("BVTypeCheck: should have exactly 2 args\n", n);

      if (!(n[0].GetValueWidth() == n[1].GetValueWidth() &&
            n[0].GetIndexWidth() == n[1].GetIndexWidth()))
      {
        cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl;
        cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl;
        cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl;
        cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl;
        FatalError(
            "BVTypeCheck: terms in atomic formulas must be of equal length",
            n);
      }
      break;

    case BVLT:
    case BVLE:
    case BVGT:
    case BVGE:
    case BVSLT:
    case BVSLE:
    case BVSGT:
    case BVSGE:
      if (n.Degree() != 2)
        FatalError("BVTypeCheck: should have exactly 2 args\n", n);
      if (BITVECTOR_TYPE != n[0].GetType() &&
          BITVECTOR_TYPE != n[1].GetType())
      {
        FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors"
                   ,n);
      }
      if (n[0].GetValueWidth() != n[1].GetValueWidth())
        FatalError(
            "BVTypeCheck: terms in atomic formulas must be of equal length",
            n);
      if (n[0].GetIndexWidth() != n[1].GetIndexWidth())
      {
        FatalError(
            "BVTypeCheck: terms in atomic formulas must be of equal length",
            n);
      }
      break;

    case NOT:
      if (1 != n.Degree())
      {
        FatalError("BVTypeCheck: NOT formula can have exactly one childNode",
                   n);
      }
      break;

    case AND:
    case OR:
    case XOR:
    case NAND:
    case NOR:
      if (2 > n.Degree())
      {
        FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 "
                   "ChildNodes",
                   n);
      }
      break;

    case IFF:
    case IMPLIES:
      if (2 != n.Degree())
      {
        FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes",
                   n);
      }
      break;

    case ITE:
      if (3 != n.Degree())
        FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes", n);
      break;

    default:
      FatalError("BVTypeCheck: Unrecognized kind: ");
      break;
  }
  return true;
}
Example #7
0
bool BVTypeCheck_term_kind(const ASTNode& n, const Kind& k)
{
  // The children of bitvector terms are in turn bitvectors.
  const ASTVec& v = n.GetChildren();

  switch (k)
  {
    case BVCONST:
      if (BITVECTOR_TYPE != n.GetType())
        FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",
                   n);
      break;

    case SYMBOL:
      return true;

    case ITE:
      if (n.Degree() != 3)
        FatalError("BVTypeCheck: should have exactly 3 args\n", n);
      if (BOOLEAN_TYPE != n[0].GetType() ||
          (n[1].GetType() != n[2].GetType()))
        FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",
                   n);
      if (n[1].GetValueWidth() != n[2].GetValueWidth())
        FatalError("BVTypeCheck: length of THENbranch != length of "
                   "ELSEbranch in the term t = \n",
                   n);
      if (n[1].GetIndexWidth() != n[2].GetIndexWidth())
        FatalError("BVTypeCheck: length of THENbranch != length of "
                   "ELSEbranch in the term t = \n",
                   n);
      break;

    case READ:
      if (n.GetChildren().size() != 2)
        FatalError("2 params to read.");
      if (n[0].GetIndexWidth() != n[1].GetValueWidth())
      {
        cerr << "Length of indexwidth of array: " << n[0]
             << " is : " << n[0].GetIndexWidth() << endl;
        cerr << "Length of the actual index is: " << n[1]
             << " is : " << n[1].GetValueWidth() << endl;
        FatalError("BVTypeCheck: length of indexwidth of array != length of "
                   "actual index in the term t = \n",
                   n);
      }
      if (ARRAY_TYPE != n[0].GetType())
        FatalError("First parameter to read should be an array", n[0]);
      if (BITVECTOR_TYPE != n[1].GetType())
        FatalError("Second parameter to read should be a bitvector", n[1]);
      break;

    case WRITE:
      if (n.GetChildren().size() != 3)
        FatalError("3 params to write.");
      if (n[0].GetIndexWidth() != n[1].GetValueWidth())
        FatalError("BVTypeCheck: length of indexwidth of array != length of "
                   "actual index in the term t = \n",
                   n);
      if (n[0].GetValueWidth() != n[2].GetValueWidth())
        FatalError("BVTypeCheck: valuewidth of array != length of actual "
                   "value in the term t = \n",
                   n);
      if (ARRAY_TYPE != n[0].GetType())
        FatalError("First parameter to read should be an array", n[0]);
      if (BITVECTOR_TYPE != n[1].GetType())
        FatalError("Second parameter to read should be a bitvector", n[1]);
      if (BITVECTOR_TYPE != n[2].GetType())
        FatalError("Third parameter to read should be a bitvector", n[2]);
      break;

    case BVDIV:
    case BVMOD:
    case BVSUB:

    case SBVDIV:
    case SBVREM:
    case SBVMOD:

    case BVLEFTSHIFT:
    case BVRIGHTSHIFT:
    case BVSRSHIFT:
    case BVVARSHIFT:
      if (n.Degree() != 2)
        FatalError("BVTypeCheck: should have exactly 2 args\n", n);
    // run on.
    case BVOR:
    case BVAND:
    case BVXOR:
    case BVNOR:
    case BVNAND:
    case BVXNOR:

    case BVPLUS:
    case BVMULT:
    {
      if (!(v.size() >= 2))
        FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must "
                   "have at least two arguments\n",n);

      unsigned int width = n.GetValueWidth();
      for (ASTVec::const_iterator it = v.begin(), itend = v.end();
           it != itend; it++)
      {
        if (width != it->GetValueWidth())
        {
          cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith "
                  "operators must be of equal length\n";
          cerr << n << endl;
          cerr << "width of term:" << width << endl;
          cerr << "width of offending operand:" << it->GetValueWidth()
               << endl;
          FatalError("BVTypeCheck:Offending operand:\n", *it);
        }
        if (BITVECTOR_TYPE != it->GetType())
          FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be "
                     "bitvectors\n", n);
      }
      break;
    }
    case BVSX:
    case BVZX:
      // in BVSX(n[0],len), the length of the BVSX term must be
      // greater than the length of n[0]
      if (n[0].GetValueWidth() > n.GetValueWidth())
      {
        FatalError("BVTypeCheck: BV[SZ]X(t,bv[sz]x_len) : length of 't' must "
                   "be <= bv[sz]x_len\n", n);
      }
      if ((v.size() != 2))
        FatalError("BVTypeCheck:BV[SZ]X must have two arguments. The second "
                   "is the new width\n", n);
      break;

    case BVCONCAT:
      checkChildrenAreBV(v, n);
      if (n.Degree() != 2)
        FatalError("BVTypeCheck: should have exactly 2 args\n", n);
      if (n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth())
        FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n", n);
      break;

    case BVUMINUS:
    case BVNEG:
      checkChildrenAreBV(v, n);
      if (n.Degree() != 1)
        FatalError("BVTypeCheck: should have exactly 1 args\n", n);
      if (n.GetValueWidth() != n[0].GetValueWidth())
        FatalError("BVTypeCheck: should have same value width\n", n);
      break;

    case BVEXTRACT:
      checkChildrenAreBV(v, n);
      if (n.Degree() != 3)
        FatalError("BVTypeCheck: should have exactly 3 args\n", n);
      if (!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind()))
        FatalError("BVTypeCheck: indices should be BVCONST\n", n);
      if (n.GetValueWidth() !=
          n[1].GetUnsignedConst() - n[2].GetUnsignedConst() + 1)
        FatalError("BVTypeCheck: length mismatch\n", n);
      if (n[1].GetUnsignedConst() >= n[0].GetValueWidth())
        FatalError("BVTypeCheck: Top index of select is greater or equal to "
                   "the bitwidth.\n",
                   n);
      break;

    default:
      cerr << _kind_names[k];
      FatalError("No type checking for type");
      break;
  }
  return true;
}
// This doesn't rewrite changes through properly so needs to have a substitution
// applied to its output.
ASTNode PropagateEqualities::propagate(const ASTNode& a, ArrayTransformer* at)
{
  ASTNode output;
  // if the variable has been solved for, then simply return it
  if (simp->InsideSubstitutionMap(a, output))
    return output;

  if (!alreadyVisited.insert(a.GetNodeNum()).second)
  {
    return a;
  }

  output = a;

  // traverse a and populate the SubstitutionMap
  const Kind k = a.GetKind();
  if (SYMBOL == k && BOOLEAN_TYPE == a.GetType())
  {
    bool updated = simp->UpdateSubstitutionMap(a, ASTTrue);
    output = updated ? ASTTrue : a;
  }
  else if (NOT == k)
  {
    bool updated = searchXOR(a[0], ASTFalse);
    output = updated ? ASTTrue : a;
  }
  else if (IFF == k || EQ == k)
  {
    const ASTVec& c = a.GetChildren();

    if (c[0] == c[1])
      return ASTTrue;

    bool updated = simp->UpdateSubstitutionMap(c[0], c[1]);

    if (updated)
    {
      // fill the arrayname readindices vector if e0 is a
      // READ(Arr,index) and index is a BVCONST
      int to;
      if ((to = TermOrder(c[0], c[1])) == 1 && c[0].GetKind() == READ)
        at->FillUp_ArrReadIndex_Vec(c[0], c[1]);
      else if (to == -1 && c[1].GetKind() == READ)
        at->FillUp_ArrReadIndex_Vec(c[1], c[0]);
    }

    if (!updated)
      updated = searchTerm(c[0], c[1]);

    if (!updated)
      updated = searchTerm(c[1], c[0]);

    output = updated ? ASTTrue : a;
  }
  else if (XOR == k)
  {
    bool updated = searchXOR(a, ASTTrue);
    output = updated ? ASTTrue : a;

    if (updated)
      return output;

// The below block should be subsumed by the searchXOR function which
// generalises it.
// So the below block should never do anything..
#ifndef NDEBUG
    if (a.Degree() != 2)
      return output;

    int to = TermOrder(a[0], a[1]);
    if (0 == to)
    {
      if (a[0].GetKind() == NOT && a[0][0].GetKind() == EQ &&
          a[0][0][0].GetValueWidth() == 1 && a[0][0][1].GetKind() == SYMBOL)
      {
        // (XOR (NOT(= (1 v)))  ... )
        const ASTNode& symbol = a[0][0][1];
        const ASTNode newN = nf->CreateTerm(
            ITE, 1, a[1], a[0][0][0], nf->CreateTerm(BVNEG, 1, a[0][0][0]));

        if (simp->UpdateSolverMap(symbol, newN))
        {
          assert(false);
          output = ASTTrue;
        }
      }
      else if (a[1].GetKind() == NOT && a[1][0].GetKind() == EQ &&
               a[1][0][0].GetValueWidth() == 1 &&
               a[1][0][1].GetKind() == SYMBOL)
      {
        const ASTNode& symbol = a[1][0][1];
        const ASTNode newN = nf->CreateTerm(
            ITE, 1, a[0], a[1][0][0], nf->CreateTerm(BVNEG, 1, a[1][0][0]));

        if (simp->UpdateSolverMap(symbol, newN))
        {
          assert(false);
          output = ASTTrue;
        }
      }
      else if (a[0].GetKind() == EQ && a[0][0].GetValueWidth() == 1 &&
               a[0][1].GetKind() == SYMBOL)
      {
        // XOR ((= 1 v) ... )

        const ASTNode& symbol = a[0][1];
        const ASTNode newN = nf->CreateTerm(
            ITE, 1, a[1], nf->CreateTerm(BVNEG, 1, a[0][0]), a[0][0]);

        if (simp->UpdateSolverMap(symbol, newN))
        {
          assert(false);
          output = ASTTrue;
        }
      }
      else if (a[1].GetKind() == EQ && a[1][0].GetValueWidth() == 1 &&
               a[1][1].GetKind() == SYMBOL)
      {
        const ASTNode& symbol = a[1][1];
        const ASTNode newN = nf->CreateTerm(
            ITE, 1, a[0], nf->CreateTerm(BVNEG, 1, a[1][0]), a[1][0]);

        if (simp->UpdateSolverMap(symbol, newN))
        {
          assert(false);
          output = ASTTrue;
        }
      }
      else
        return output;
    }
    else
    {
      ASTNode symbol, rhs;
      if (to == 1)
      {
        symbol = a[0];
        rhs = a[1];
      }
      else
      {
        symbol = a[1];
        rhs = a[0];
      }

      assert(symbol.GetKind() == SYMBOL);

      if (simp->UpdateSolverMap(symbol, nf->CreateNode(NOT, rhs)))
      {
        assert(false);
        output = ASTTrue;
      }
    }
#endif
  }
  else if (AND == k)
  {
    const ASTVec& c = a.GetChildren();
    ASTVec o;
    o.reserve(c.size());

    for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend;
         it++)
    {
      if (always_true)
        simp->UpdateAlwaysTrueFormSet(*it);
      ASTNode aaa = propagate(*it, at);

      if (ASTTrue != aaa)
      {
        if (ASTFalse == aaa)
          return ASTFalse;
        else
          o.push_back(aaa);
      }
    }
    if (o.size() == 0)
      output = ASTTrue;
    else if (o.size() == 1)
      output = o[0];
    else if (o != c)
      output = nf->CreateNode(AND, o);
    else
      output = a;
  }

  return output;
}
Example #9
0
/* This function transforms Array Reads, Read over Writes, Read over
 * ITEs into flattened form.
 *
 * Transform1: Suppose there are two array reads in the input
 * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is
 * replaced with a symbolic constant, say v1, and Read(A,j) is
 * replaced with the following ITE:
 *
 * ITE(i=j,v1,v2)
 *
 */
ASTNode ArrayTransformer::TransformArrayRead(const ASTNode& term)
{
  assert(TransformMap != NULL);

  const unsigned int width = term.GetValueWidth();

  if (READ != term.GetKind())
    return term;

  ASTNodeMap::const_iterator iter;
  if ((iter = TransformMap->find(term)) != TransformMap->end())
    return iter->second;

  //'term' is of the form READ(arrName, readIndex)
  const ASTNode& arrName = term[0];
  const ASTNode& readIndex = TransformTerm(term[1]);

  ASTNode result;

  switch (arrName.GetKind())
  {
    case SYMBOL:
    {
      /* input is of the form: READ(A, readIndex)
       *
       * output is of the from: A1, if this is the first READ over A
       *
       *                        ITE(previous_readIndex=readIndex,A1,A2)
       *
       *                        .....
       */

      {
        ArrType::const_iterator it;
        if ((it = arrayToIndexToRead.find(arrName)) != arrayToIndexToRead.end())
        {
          std::map<ASTNode, ArrayRead>::const_iterator it2;
          if ((it2 = it->second.find(readIndex)) != it->second.end())
          {
            result = it2->second.ite;
            break;
          }
        }
      }

      // Make up a new abstract variable. Build symbolic name
      // corresponding to array read. The symbolic name has 2
      // components: stringname, and a count

      ASTNode CurrentSymbol =
          bm->CreateFreshVariable(term.GetIndexWidth(), term.GetValueWidth(),
                                  "array_" + std::string(arrName.GetName()));

      result = CurrentSymbol;

      if (!bm->UserFlags.ackermannisation)
      {
        // result is a variable here; it is an ite in the
        // else-branch
      }
      else if (bm->UserFlags.isSet("old_ack", "0"))
      {

        /* oops.
         * This version of ack. doesn't do what I thought it did. The STP 0.1
         * version of Ack. produces simpler
         * expressions. I've put that in the next block. Trevor's thesis
         * measures AckITE using this implementation,
         * rather than the next one like it should have!!!!
         */

        // Full Array transform if we're not doing read refinement.

        // list of array-read indices corresponding to arrName, seen while
        // traversing the AST tree. we need this list to construct the ITEs
        const arrTypeMap& new_read_Indices = arrayToIndexToRead[arrName];

        arrTypeMap::const_iterator it2 = new_read_Indices.begin();
        arrTypeMap::const_iterator it2end = new_read_Indices.end();
        for (; it2 != it2end; it2++)
        {
          ASTNode cond = simp->CreateSimplifiedEQ(readIndex, it2->first);
          if (ASTFalse == cond)
            continue;

          if (ASTTrue == cond)
          {
            result = it2->second.ite;
            break;
          }

          result = simp->CreateSimplifiedTermITE(cond, it2->second.ite, result);
        }
      }
      else
      {
        // Full Array transform if we're not doing read refinement.

        // list of array-read indices corresponding to arrName, seen while
        // traversing the AST tree. we need this list to construct the ITEs
        vector<std::pair<ASTNode, ASTNode>> p = ack_pair[arrName];

        vector<std::pair<ASTNode, ASTNode>>::const_reverse_iterator it2 =
            p.rbegin();
        vector<std::pair<ASTNode, ASTNode>>::const_reverse_iterator it2end =
            p.rend();
        for (; it2 != it2end; it2++)
        {
          ASTNode cond = simp->CreateSimplifiedEQ(readIndex, it2->first);
          if (ASTFalse == cond)
            continue;

          if (ASTTrue == cond)
          {
            result = it2->second;
            break;
          }

          result = simp->CreateSimplifiedTermITE(cond, it2->second, result);
        }

        ack_pair[arrName].push_back(make_pair(readIndex, CurrentSymbol));
      }

      assert(arrName.GetType() == ARRAY_TYPE);
      arrayToIndexToRead[arrName].insert(
          make_pair(readIndex, ArrayRead(result, CurrentSymbol)));
      break;
    }
    case WRITE:
    {
      /* The input to this case is: READ((WRITE A i val) j)
       *
       * The output of this case is: ITE( (= i j) val (READ A j))
       */

      /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression
       *
       * 2. term[1] is the read-index j
       *
       * 3. arrName[0] is the new arrName i.e. A. A can be either a
       SYMBOL or a nested WRITE. no other possibility
       *
       * 4. arrName[1] is the WRITE index i.e. i
       *
       * 5. arrName[2] is the WRITE value i.e. val (val can inturn
       *    be an array read)
       */

      ASTNode writeIndex = TransformTerm(arrName[1]);
      ASTNode writeVal = TransformTerm(arrName[2]);

      if (ARRAY_TYPE != arrName[0].GetType())
        FatalError("TransformArray: "
                   "An array write is being attempted on a non-array:",
                   term);

      // if ((SYMBOL == arrName[0].GetKind()
      //|| WRITE == arrName[0].GetKind()))
      {
        ASTNode cond = simp->CreateSimplifiedEQ(writeIndex, readIndex);
        assert(BVTypeCheck(cond));

        // If the condition is true, it saves iteratively transforming through
        // all the (possibly nested) arrays.
        if (ASTTrue == cond)
        {
          result = writeVal;
        }
        else
        {
          ASTNode readTerm = nf->CreateTerm(READ, width, arrName[0], readIndex);
          assert(BVTypeCheck(readTerm));

          // The simplifying node factory may have produced
          // something that's not a READ.
          ASTNode readPushedIn = TransformTerm(readTerm);
          assert(BVTypeCheck(readPushedIn));

          result = simp->CreateSimplifiedTermITE(cond, writeVal, readPushedIn);
        }
      }

// Trevor: I've removed this code because I don't see the advantage in working
// inside out. i.e. transforming read(write(ite(p,A,B),i,j),k), into
// read(ite(p,write(A,i,j),write(B,i,j),k). That is bringing up the ite.
// Without this code it will become: ite(i=k, j, read(ite(p,A,B),k))

#if 0
          else if (ITE == arrName[0].GetKind())
            {
              // pull out the ite from the write // pushes the write
              // through.
              ASTNode writeTrue =
                nf->CreateNode(WRITE, (arrName[0][1]), writeIndex, writeVal);
              writeTrue.SetIndexWidth(writeIndex.GetValueWidth());
              writeTrue.SetValueWidth(writeVal.GetValueWidth());
              assert(ARRAY_TYPE == writeTrue.GetType());

              ASTNode writeFalse = 
                nf->CreateNode(WRITE, (arrName[0][2]), writeIndex, writeVal);
              writeFalse.SetIndexWidth(writeIndex.GetValueWidth());
              writeFalse.SetValueWidth(writeVal.GetValueWidth());
              assert(ARRAY_TYPE == writeFalse.GetType());

              result =  (writeTrue == writeFalse) ?
                writeTrue : simp->CreateSimplifiedTermITE(TransformFormula(arrName[0][0]),
                                              writeTrue, writeFalse);
              result.SetIndexWidth(writeIndex.GetValueWidth());
              result.SetValueWidth(writeVal.GetValueWidth());
              assert(ARRAY_TYPE == result.GetType());

              result = 
                nf->CreateTerm(READ, writeVal.GetValueWidth(),
                               result, readIndex);
              BVTypeCheck(result);
              result = TransformArrayRead(result);
            }
          else
            FatalError("TransformArray: Write over bad type.");
#endif
      break;
    }
    case ITE:
    {
      /* READ((ITE cond thn els) j)
       *
       * is transformed into
       *
       * (ITE cond (READ thn j) (READ els j))
       */

      // pull out the ite from the read // pushes the read through.

      //(ITE cond thn els)

      ASTNode cond = arrName[0];
      cond = TransformFormula(cond);

      const ASTNode& thn = arrName[1];
      const ASTNode& els = arrName[2];

      //(READ thn j)
      ASTNode thnRead = nf->CreateTerm(READ, width, thn, readIndex);
      assert(BVTypeCheck(thnRead));

      //(READ els j)
      ASTNode elsRead = nf->CreateTerm(READ, width, els, readIndex);
      assert(BVTypeCheck(elsRead));

      /* We try to call TransformTerm only if necessary, because it
       * introduces a new symbol for each read. The amount of work we
       * need to do later is based on the square of the number of symbols.
       */
      if (ASTTrue == cond)
      {
        result = TransformTerm(thnRead);
      }
      else if (ASTFalse == cond)
      {
        result = TransformTerm(elsRead);
      }
      else
      {
        thnRead = TransformTerm(thnRead);
        elsRead = TransformTerm(elsRead);

        //(ITE cond (READ thn j) (READ els j))
        result = simp->CreateSimplifiedTermITE(cond, thnRead, elsRead);
      }
      break;
    }
    default:
      FatalError("TransformArray: "
                 "The READ is NOT over SYMBOL/WRITE/ITE",
                 term);
      break;
  }
Example #10
0
/********************************************************
 * TransformFormula()
 *
 * Get rid of DIV/MODs, ARRAY read/writes, FOR constructs
 ********************************************************/
ASTNode ArrayTransformer::TransformFormula(const ASTNode& simpleForm)
{
  assert(TransformMap != NULL);

  const Kind k = simpleForm.GetKind();
  if (!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType()))
  {
    // FIXME: "You have inputted a NON-formula"?
    FatalError("TransformFormula:"
               "You have input a NON-formula",
               simpleForm);
  }

  ASTNodeMap::const_iterator iter;
  if ((iter = TransformMap->find(simpleForm)) != TransformMap->end())
    return iter->second;

  ASTNode result;

  switch (k)
  {
    case TRUE:
    case FALSE:
    {
      result = simpleForm;
      break;
    }
    case NOT:
    {
      ASTVec c;
      c.push_back(TransformFormula(simpleForm[0]));
      result = nf->CreateNode(NOT, c);
      break;
    }
    case BOOLEXTRACT:
    {
      ASTVec c;
      c.push_back(TransformTerm(simpleForm[0]));
      c.push_back(simpleForm[1]);
      result = nf->CreateNode(BOOLEXTRACT, c);
      break;
    }
    case BVLT:
    case BVLE:
    case BVGT:
    case BVGE:
    case BVSLT:
    case BVSLE:
    case BVSGT:
    case BVSGE:
    {
      ASTVec c;
      c.push_back(TransformTerm(simpleForm[0]));
      c.push_back(TransformTerm(simpleForm[1]));
      result = nf->CreateNode(k, c);
      break;
    }
    case EQ:
    {
      ASTNode term1 = TransformTerm(simpleForm[0]);
      ASTNode term2 = TransformTerm(simpleForm[1]);
      if (bm->UserFlags.optimize_flag)
        result = simp->CreateSimplifiedEQ(term1, term2);
      else
        result = nf->CreateNode(EQ, term1, term2);
      break;
    }
    case AND: // These could shortcut. Not sure if the extra effort is
              // justified.
    case OR:
    case NAND:
    case NOR:
    case IFF:
    case XOR:
    case ITE:
    case IMPLIES:
    {
      ASTVec vec;
      vec.reserve(simpleForm.Degree());

      for (ASTVec::const_iterator it = simpleForm.begin(),
                                  itend = simpleForm.end();
           it != itend; it++)
      {
        vec.push_back(TransformFormula(*it));
      }

      result = nf->CreateNode(k, vec);
      break;
    }
    case PARAMBOOL:
    {
      // If the parameteric boolean variable is of the form
      // VAR(const), then convert it into a Boolean variable of the
      // form "VAR(const)".
      //
      // Else if the paramteric boolean variable is of the form
      // VAR(expression), then simply return it
      if (BVCONST == simpleForm[1].GetKind())
      {
        result = bm->NewParameterized_BooleanVar(simpleForm[0], simpleForm[1]);
      }
      else
      {
        result = simpleForm;
      }
      break;
    }
    default:
    {
      if (k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType())
        result = simpleForm;
      else
      {
        FatalError("TransformFormula: Illegal kind: ", ASTUndefined, k);
        std::cerr << "The input is: " << simpleForm << std::endl;
        std::cerr << "The valuewidth of input is : "
                  << simpleForm.GetValueWidth() << std::endl;
      }
      break;
    }
  }

  assert(!result.IsNull());
  if (simpleForm.Degree() > 0)
    (*TransformMap)[simpleForm] = result;
  return result;
} 
    // NB: This expects that the constructor was called with teh same node. Sorry.
    ASTNode
    ConstantBitPropagation::topLevelBothWays(const ASTNode& top)
    {
      assert(top.GetSTPMgr()->UserFlags.bitConstantProp_flag);
      assert (BOOLEAN_TYPE == top.GetType());

      propagate();
      status = NO_CHANGE;

      //Determine what must always be true.
      ASTNodeMap fromTo = getAllFixed();

      if (debug_cBitProp_messages)
        {
          cerr << "Number removed by bottom UP:" << fromTo.size() << endl;
        }

      setNodeToTrue(top);

      if (debug_cBitProp_messages)
        {
          cerr << "starting propagation" << endl;
          printNodeWithFixings();
          cerr << "Initial Tree:" << endl;
          cerr << top;
        }

      propagate();

      if (debug_cBitProp_messages)
        {
          cerr << "status:" << status <<endl;
          cerr << "ended propagation" << endl;
          printNodeWithFixings();
        }

      // propagate may have stopped with a conflict.
      if (CONFLICT == status)
          return top.GetSTPMgr()->CreateNode(FALSE);

      ASTVec toConjoin;

      // go through the fixedBits. If a node is entirely fixed.
      // "and" it onto the top. Creates redundancy. Check that the
      // node doesn't already depend on "top" directly.

      for (NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it = fixedMap->map->begin(); it != fixedMap->map->end(); it++) // iterates through all the pairs of node->fixedBits.
        {
          const FixedBits& bits = *it->second;

          if (!bits.isTotallyFixed())
            continue;

          const ASTNode& node = (it->first);

          // Don't constrain nodes we already know all about.
          if (node.isConstant())
            continue;

          // other nodes will contain the same information (the extract doesn't change the fixings).
          if (BVEXTRACT == node.GetKind() || BVCONCAT == node.GetKind())
            continue;

          // toAssign: conjoin it with the top level.
          // toReplace: replace all references to it (except the one conjoined to the top) with this.
          ASTNode propositionToAssert;
          ASTNode constantToReplaceWith;
          // skip the assigning and replacing.
          bool doAssign = true;

            {
              // If it is already contained in the fromTo map, then it's one of the values
              // that have fully been determined (previously). Not conjoined.
              if (fromTo.find(node) != fromTo.end())
                continue;

              ASTNode constNode = bitsToNode(node,bits);

              if (node.GetType() == BOOLEAN_TYPE)
                {
                  if (SYMBOL == node.GetKind())
                    {
                      bool r = simplifier->UpdateSubstitutionMap(node, constNode);
                      assert(r);
                      doAssign = false;
                    }
                  else if (bits.getValue(0))
                    {
                      propositionToAssert = node;
                      constantToReplaceWith = constNode;
                    }
                  else
                    {
                      propositionToAssert = nf->CreateNode(NOT, node);
                      constantToReplaceWith = constNode;
                    }
                }
              else if (node.GetType() == BITVECTOR_TYPE)
                {
                  assert(((unsigned)bits.getWidth()) == node.GetValueWidth());
                  if (SYMBOL == node.GetKind())
                    {
                      bool r = simplifier->UpdateSubstitutionMap(node, constNode);
                      assert(r);
                      doAssign = false;
                    }
                  else
                    {
                      propositionToAssert = nf->CreateNode(EQ, node, constNode);
                      constantToReplaceWith = constNode;
                    }
                }
              else
                FatalError("sadf234s");
            }

          if (doAssign && top != propositionToAssert
              && !dependents->nodeDependsOn(top, propositionToAssert))
            {
              assert(!constantToReplaceWith.IsNull());
              assert(constantToReplaceWith.isConstant());
              assert(propositionToAssert.GetType() == BOOLEAN_TYPE);
              assert(node.GetValueWidth() == constantToReplaceWith.GetValueWidth());

              fromTo.insert(make_pair(node, constantToReplaceWith));
              toConjoin.push_back(propositionToAssert);
            }
        }

     // Write the constants into the main graph.
      ASTNodeMap cache;
      ASTNode result = SubstitutionMap::replace(top, fromTo, cache,nf);

      if (0 != toConjoin.size())
        {
          // It doesn't happen very often. But the "toConjoin" might contain a variable
          // that was added to the substitution map (because the value was determined just now
          // during propagation.
          ASTNode conjunct = (1 == toConjoin.size())? toConjoin[0]: nf->CreateNode(AND,toConjoin);
          conjunct = simplifier->applySubstitutionMap(conjunct);

          result = nf->CreateNode(AND, result, conjunct); // conjoin the new conditions.
        }


  	if (debug_print_graph_after)
		{
			ofstream file;
			file.open("afterCbitp.gdl");
			PrintingHackfixedMap = fixedMap;
			printer::GDL_Print(file,top,&toString);
			file.close();
		}


      assert(BVTypeCheck(result));
      assert(status != CONFLICT); // conflict should have been seen earlier.
      return result;
    }