Beispiel #1
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;
  }
Beispiel #2
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;
} 
Beispiel #3
0
ASTNode ArrayTransformer::TransformTerm(const ASTNode& term)
{
  assert(TransformMap != NULL);

  const Kind k = term.GetKind();
  if (!is_Term_kind(k))
    FatalError("TransformTerm: Illegal kind: You have input a nonterm:", term,
               k);
  ASTNodeMap::const_iterator iter;
  if ((iter = TransformMap->find(term)) != TransformMap->end())
    return iter->second;

  ASTNode result;
  switch (k)
  {
    case SYMBOL:
    case BVCONST:
    {
      result = term;
      break;
    }
    case WRITE:
      FatalError("TransformTerm: this kind is not supported", term);
      break;
    case READ:
      result = TransformArrayRead(term);
      break;
    case ITE:
    {
      ASTNode cond = term[0];
      ASTNode thn = term[1];
      ASTNode els = term[2];
      cond = TransformFormula(cond);
      if (ASTTrue == cond)
        result = TransformTerm(thn);
      else if (ASTFalse == cond)
        result = TransformTerm(els);
      else
      {
        thn = TransformTerm(thn);
        els = TransformTerm(els);
        if (bm->UserFlags.optimize_flag)
          result = simp->CreateSimplifiedTermITE(cond, thn, els);
        else
          result = nf->CreateTerm(ITE, thn.GetValueWidth(), cond, thn, els);
      }
      assert(result.GetIndexWidth() == term.GetIndexWidth());
      break;
    }
    default:
    {
      const ASTVec& c = term.GetChildren();
      ASTVec::const_iterator it = c.begin();
      ASTVec::const_iterator itend = c.end();
      const unsigned width = term.GetValueWidth();
      const unsigned indexwidth = term.GetIndexWidth();
      ASTVec o;
      o.reserve(c.size());
      for (; it != itend; it++)
      {
        o.push_back(TransformTerm(*it));
      }

      if (c != o)
      {
        result = nf->CreateArrayTerm(k, indexwidth, width, o);
      }
      else
        result = term;
    }
    break;
  }

  if (term.Degree() > 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())
  {
    std::cerr << "TransformTerm: input term is : " << term << std::endl;
    FatalError("TransformTerm: "
               "result & input terms have different index length",
               result);
  }
  return result;
} 
Beispiel #4
0
  ASTNode ArrayTransformer::TransformTerm(const ASTNode& term)
  {
    assert(TransformMap != NULL);

    const Kind k = term.GetKind();
    if (!is_Term_kind(k))
      FatalError("TransformTerm: Illegal kind: You have input a nonterm:", 
                 term, k);
    ASTNodeMap::const_iterator iter;
    if ((iter = TransformMap->find(term)) != TransformMap->end())
      return iter->second;

    ASTNode result;
    switch (k)
      {
      case SYMBOL:
      case BVCONST:
      {
          result = term;
          break;
        }
      case WRITE:
        FatalError("TransformTerm: this kind is not supported", term);
        break;
      case READ:
        result = TransformArrayRead(term);
        break;
      case ITE:
        {
          ASTNode cond = term[0];
          ASTNode thn = term[1];
          ASTNode els = term[2];
          cond = TransformFormula(cond);
          if (ASTTrue == cond)
        	  result = TransformTerm(thn);
          else if (ASTFalse == cond)
        	  result = TransformTerm(els);
          else
          {
        	  thn = TransformTerm(thn);
        	  els = TransformTerm(els);
        	  result = simp->CreateSimplifiedTermITE(cond, thn, els);
          }
          assert(result.GetIndexWidth() ==term.GetIndexWidth());
          break;
        }
      default:
        {
          const ASTVec& c = term.GetChildren();
          ASTVec::const_iterator it = c.begin();
          ASTVec::const_iterator itend = c.end();
          const unsigned width = term.GetValueWidth();
          const unsigned indexwidth = term.GetIndexWidth();
          ASTVec o;
          o.reserve(c.size());
          for (; it != itend; it++)
            {
              o.push_back(TransformTerm(*it));
            }

          if (c!=o)
          {
        	  result = nf->CreateArrayTerm(k,indexwidth, width, o);
          }
          else
        	  result = term;

          const Kind k = result.GetKind();

          if (BVDIV == k 
              || BVMOD == k 
              || SBVDIV == k 
              || SBVREM == k 
              || SBVMOD == k)
            {

              // I had this as a reference, but that was wrong. Because
              // "result" gets over-written in the next block, result[1], may
              // get a reference count of zero, so be garbage collected.
              const ASTNode bottom = result[1];

              if (SBVDIV == result.GetKind() 
                  || SBVREM == result.GetKind() 
                  || SBVMOD == result.GetKind())
                {
                  result = TranslateSignedDivModRem(result);
                }

              if (bm->UserFlags.division_by_zero_returns_one_flag)
                {
                  // This is a difficult rule to introduce in other
                  // places because it's recursive. i.e.  result is
                  // embedded unchanged inside the result.

                  unsigned inputValueWidth = result.GetValueWidth();
                  ASTNode zero = bm->CreateZeroConst(inputValueWidth);
                  ASTNode one = bm->CreateOneConst(inputValueWidth);
                  result = 
                    nf->CreateTerm(ITE, inputValueWidth,
                                   nf->CreateNode(EQ, zero, bottom),
                                   one, result);

                  //return result;
                  if (bm->UserFlags.optimize_flag)
                      return simp->SimplifyTerm_TopLevel(result);
                  else
                  	return result;

                }
            }
        }
        break;
      }

    if (term.Degree() > 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())
      {
        cerr << "TransformTerm: input term is : " << term << endl;
        FatalError("TransformTerm: "\
                   "result & input terms have different index length", result);
      }
    return result;
  } //End of TransformTerm