Example #1
0
void 
btor_map_node (BtorNodeMap * map, BtorNode * src, BtorNode * dst)
{
  BtorPtrHashBucket * bucket;

  assert (map);
  assert (src);
  assert (dst);

  if (map->simplify)
    {
      src = btor_simplify_exp (BTOR_REAL_ADDR_NODE (src)->btor, src);
      dst = btor_simplify_exp (BTOR_REAL_ADDR_NODE (dst)->btor, dst);
    }

  if (BTOR_IS_INVERTED_NODE (src))
    {
      src = BTOR_INVERT_NODE (src);
      dst = BTOR_INVERT_NODE (dst);
    }
  assert (!btor_find_in_ptr_hash_table (map->table, src));
  bucket = btor_insert_in_ptr_hash_table (map->table, src);
  assert (bucket);
  assert (bucket->key == src);
  bucket->key = btor_copy_exp (BTOR_REAL_ADDR_NODE (src)->btor, src);
  assert (!bucket->data.asPtr);
  bucket->data.asPtr = btor_copy_exp (BTOR_REAL_ADDR_NODE (dst)->btor, dst);
}
Example #2
0
BtorNode *
boolector_copy (Btor * btor, BtorNode * exp)
{
  BTOR_ABORT_ARG_NULL_BOOLECTOR (btor);
  BTOR_ABORT_ARG_NULL_BOOLECTOR (exp);
  BTOR_ABORT_REFS_NOT_POS_BOOLECTOR (exp);
  btor->external_refs++;
  return btor_copy_exp (btor, exp);
}
Example #3
0
static BtorNode *
parse_exp (BtorBTORParser * parser, int expected_len, int can_be_array)
{
  int lit, idx, len_res;
  BtorNode *res;

  lit = 0;
  if (parse_non_zero_int (parser, &lit))
    return 0;

  idx = abs (lit);
  assert (idx);

  if (idx >= BTOR_COUNT_STACK (parser->exps) ||
      !(res = parser->exps.start[idx]))
    {
      (void) btor_perr_btor (parser, "literal '%d' undefined", lit);
      return 0;
    }

  if (!can_be_array && btor_is_array_exp (parser->btor, res))
    {
      (void)
      btor_perr_btor (parser,
		   "literal '%d' refers to an unexpected array expression",
		   lit);
      return 0;
    }

  if (expected_len)
    {
      len_res = btor_get_exp_len (parser->btor, res);

      if (expected_len != len_res)
	{
	  (void)
	    btor_perr_btor (parser,
			 "literal '%d' has length '%d' but expected '%d'",
			 lit, len_res, expected_len);

	  return 0;
	}
    }

  if (lit < 0)
    res = btor_not_exp (parser->btor, res);
  else
    res = btor_copy_exp (parser->btor, res);

  return res;
}
BtorParamCacheTuple *
btor_copy_param_cache_tuple (Btor * btor, BtorParamCacheTuple * t)
{
  assert (btor);
  assert (t);

  BtorParamCacheTuple *result;

  BTOR_NEW (btor->mm, result);
  BTOR_CLR (result);

  result->exp = btor_copy_exp (btor, t->exp);
  result->hash = t->hash;
  result->num_args = t->num_args;

  BTOR_NEWN (btor->mm, result->args, result->num_args);
  memcpy (result->args, t->args, t->num_args * sizeof (*result->args));

  return result;
}
Example #5
0
static BtorNode *
btor_map_node_internal (Btor * btor, BtorNodeMap * map, BtorNode * exp)
{
  assert (btor);
  assert (exp);
  assert (BTOR_IS_REGULAR_NODE (exp));

  BtorNode * m[3], * src, * dst, * real_exp;
  int i;

  m[0] = m[1] = m[2] = 0;

  for (i = 0; i < exp->arity; i++)
    {
      src = exp->e[i];
      dst = btor_mapped_node (map, src);
      m[i] = dst ? dst : src;
      assert (BTOR_REAL_ADDR_NODE (m[i])->btor == btor);
    }

  assert (exp->kind != BTOR_PROXY_NODE);

  switch (exp->kind)
    {
      case BTOR_BV_CONST_NODE:

        // FIXME real_exp = exp weil BTOR_IS_REGULAR_NODE (exp)
        real_exp = BTOR_REAL_ADDR_NODE (exp);
        if (real_exp->btor != btor)
          {
            BtorNode * res = btor_const_exp (btor, btor_const_get_bits (exp));
            if (real_exp != exp)
              res = BTOR_INVERT_NODE (res);
            return res;
          }

        // ELSE FALL THROUGH!!!

      case BTOR_BV_VAR_NODE:
      case BTOR_UF_NODE:
        return btor_copy_exp (btor, exp);
      case BTOR_SLICE_NODE:
        return btor_slice_exp (btor, m[0],
                               btor_slice_get_upper (exp),
                               btor_slice_get_lower (exp));
      case BTOR_AND_NODE:
        return btor_and_exp (btor, m[0], m[1]);
      case BTOR_BEQ_NODE:
      case BTOR_FEQ_NODE:
        return btor_eq_exp (btor, m[0], m[1]);
      case BTOR_ADD_NODE:
        return btor_add_exp (btor, m[0], m[1]);
      case BTOR_MUL_NODE:
        return btor_mul_exp (btor, m[0], m[1]);
      case BTOR_ULT_NODE:
        return btor_ult_exp (btor, m[0], m[1]);
      case BTOR_SLL_NODE:
        return btor_sll_exp (btor, m[0], m[1]);
      case BTOR_SRL_NODE:
        return btor_srl_exp (btor, m[0], m[1]);
      case BTOR_UDIV_NODE:
        return btor_udiv_exp (btor, m[0], m[1]);
      case BTOR_UREM_NODE:
        return btor_urem_exp (btor, m[0], m[1]);
      case BTOR_CONCAT_NODE:
        return btor_concat_exp (btor, m[0], m[1]);
      case BTOR_LAMBDA_NODE:
        return btor_lambda_exp (btor, m[0], m[1]);
      default:
        assert (BTOR_IS_BV_COND_NODE (exp));
        return btor_cond_exp (btor, m[0], m[1], m[2]);
    }
}
static void
add_root_to_smt_dump_context (BtorSMTDumpContext * sdc, BtorNode * root)
{
  if (!btor_find_in_ptr_hash_table (sdc->roots, root))
    btor_insert_in_ptr_hash_table (sdc->roots, btor_copy_exp (sdc->btor, root));
}
/*
 *
 * diff: d
 * l,....,u
 * l <= i && i <= u && (u - i) % d == 0
 *
 * optimization if d is power of two
 *   l <= i && i <= u && (u - i) & (d - 1) = 0
 *   
 *   l <= i && i <= u && (u - i)[bits(d) - 1 - 1: 0] = 0
 *   
 *   d: 1
 *   l <= i && i <= u 
 *   
 *   d: 2
 *   l <= i && i <= u && (u - i)[0:0] = 0
 *   
 *   d: 4
 *   l <= i && i <= u && (u - i)[1:0] = 0
 *   
 *   d: 8
 *   l <= i && i <= u && (u - i)[2:0] = 0
*/
static inline BtorNode *
create_range (Btor * btor,
              BtorNode * lower,
              BtorNode * upper,
              BtorNode * param,
              BtorBitVector * offset)
{
  assert (lower);
  assert (upper);
  assert (param);
  assert (BTOR_IS_REGULAR_NODE (param));
  assert (BTOR_IS_PARAM_NODE (param));
  assert (BTOR_IS_BV_CONST_NODE (BTOR_REAL_ADDR_NODE (lower))
          || BTOR_IS_ADD_NODE (BTOR_REAL_ADDR_NODE (lower)));
  assert (BTOR_IS_BV_CONST_NODE (BTOR_REAL_ADDR_NODE (upper))
          || BTOR_IS_ADD_NODE (BTOR_REAL_ADDR_NODE (upper)));
  assert (BTOR_REAL_ADDR_NODE (lower)->sort_id
          == BTOR_REAL_ADDR_NODE (upper)->sort_id);
  assert (offset);

  int pos;
  BtorNode *res, *le0, *le1, *and, *off, *sub, *rem, *eq, *zero, *slice;

  le0 = btor_ulte_exp (btor, lower, param);
  le1 = btor_ulte_exp (btor, param, upper);
  and = btor_and_exp (btor, le0, le1);

  /* increment by one */
  if (btor_is_one_bv (offset))
    res = btor_copy_exp (btor, and);
  /* increment by power of two */
  else if ((pos = btor_is_power_of_two_bv (offset)) > -1)
    {
      assert (pos > 0);
      sub = btor_sub_exp (btor, upper, param);
      slice = btor_slice_exp (btor, sub, pos - 1, 0);
      zero = btor_zero_exp (btor, btor_get_exp_width (btor, slice));
      eq = btor_eq_exp (btor, slice, zero);
      res = btor_and_exp (btor, and, eq);

      btor_release_exp (btor, zero);
      btor_release_exp (btor, slice);
      btor_release_exp (btor, sub);
      btor_release_exp (btor, eq);
    }
  /* increment by some arbitrary value */
  else
    {
      zero = btor_zero_exp (btor, btor_get_exp_width (btor, lower));
      off = btor_const_exp (btor, offset);
      assert (BTOR_REAL_ADDR_NODE (off)->sort_id
              == BTOR_REAL_ADDR_NODE (lower)->sort_id);
      sub = btor_sub_exp (btor, upper, param);
      rem = btor_urem_exp (btor, sub, off);
      eq = btor_eq_exp (btor, rem, zero); 
      res = btor_and_exp (btor, and, eq);

      btor_release_exp (btor, zero);
      btor_release_exp (btor, off);
      btor_release_exp (btor, sub);
      btor_release_exp (btor, rem);
      btor_release_exp (btor, eq);
    }
  btor_release_exp (btor, le0);
  btor_release_exp (btor, le1);
  btor_release_exp (btor, and);
  return res;
}
static unsigned 
extract_lambdas (Btor * btor, BtorPtrHashTable * map_value_index,
                 BtorPtrHashTable * map_lambda_base)
{
  assert (btor);
  assert (map_value_index);
  assert (map_lambda_base);

  bool is_top_eq;
  BtorBitVector *inc;
  unsigned i_range, i_index, i_value, i_inc;
  BtorNode *subst, *base, *tmp, *array, *value, *lower, *upper; 
  BtorNode *src_array, *src_addr, *dst_addr;
  BtorHashTableIterator it, iit;
  BtorPtrHashTable *t, *index_value_map;
  BtorPtrHashBucket *b;
  BtorNodePtrStack ranges, indices, values, indices_itoi, indices_itoip1;
  BtorNodePtrStack indices_cpy, indices_rem, *stack;
  BtorBitVectorPtrStack increments;
  BtorMemMgr *mm;

  /* statistics */
  unsigned num_total = 0, num_writes = 0;
  unsigned num_set = 0, num_set_inc = 0, num_set_itoi = 0, num_set_itoip1 = 0;
  unsigned num_cpy = 0, size_set = 0, size_set_inc = 0, size_set_itoi = 0;
  unsigned size_set_itoip1 = 0, size_cpy = 0;

  mm = btor->mm;
  BTOR_INIT_STACK (ranges);
  BTOR_INIT_STACK (indices);
  BTOR_INIT_STACK (increments);
  BTOR_INIT_STACK (values);
  BTOR_INIT_STACK (indices_itoi);
  BTOR_INIT_STACK (indices_itoip1);
  BTOR_INIT_STACK (indices_cpy);
  BTOR_INIT_STACK (indices_rem);
  btor_init_node_hash_table_iterator (&it, map_value_index);
  while (btor_has_next_node_hash_table_iterator (&it))
    {
      t = it.bucket->data.asPtr;
      array = btor_next_node_hash_table_iterator (&it);
      assert (t);

      /* find memset patterns, the remaining unused indices are pushed onto
       * stack 'indices' */
      btor_init_node_hash_table_iterator (&iit, t);
      while (btor_has_next_node_hash_table_iterator (&iit))
        {
          stack = iit.bucket->data.asPtr;
          value = btor_next_node_hash_table_iterator (&iit);
          assert (stack);
          find_ranges (btor, stack, &ranges, &increments, &indices,
                       &num_set, &num_set_inc, &size_set, &size_set_inc);
          BTOR_RELEASE_STACK (mm, *stack);
          BTOR_DELETE (mm, stack);
          BTOR_PUSH_STACK (mm, ranges, 0);
          BTOR_PUSH_STACK (mm, indices, 0);
          BTOR_PUSH_STACK (mm, values, value);
          assert (BTOR_COUNT_STACK (ranges) - BTOR_COUNT_STACK (values) > 0
                  || BTOR_COUNT_STACK (indices) -
                         BTOR_COUNT_STACK (values) > 0);
          assert ((BTOR_COUNT_STACK (ranges) -
                       BTOR_COUNT_STACK (values)) % 2 == 0);
          assert ((BTOR_COUNT_STACK (ranges) -
                       BTOR_COUNT_STACK (values)) / 2 ==
                           BTOR_COUNT_STACK (increments)); 
        }

      /* choose base array for patterns/writes:
       *  1) write chains: base array of the write chains
       *  2) top eqs: a new UF symbol */
      if ((b = btor_find_in_ptr_hash_table (map_lambda_base, array)))
        {
          assert (BTOR_IS_LAMBDA_NODE (array));
          b = btor_find_in_ptr_hash_table (map_lambda_base, array);
          assert (b);
          subst = btor_copy_exp (btor, b->data.asPtr);
          is_top_eq = false;
        }
      else
        {
          assert (BTOR_IS_UF_ARRAY_NODE (array));
          subst = btor_array_exp (btor,
                                  btor_get_fun_exp_width (btor, array),
                                  btor_get_index_exp_width (btor, array),
                                  0);

          is_top_eq = true;
        }

      index_value_map = btor_new_ptr_hash_table (mm, 0, 0);
      base = subst;
      i_range = i_index = i_inc = 0;
      for (i_value = 0; i_value < BTOR_COUNT_STACK (values); i_value++)
        {
          value = BTOR_PEEK_STACK (values, i_value);

          /* create memset regions */
          for (; i_range < BTOR_COUNT_STACK (ranges) - 1; i_range += 2)
            {
              lower = BTOR_PEEK_STACK (ranges, i_range);
              /* next value */
              if (!lower)
                {
                  i_range++;
                  break;
                }
              upper = BTOR_PEEK_STACK (ranges, i_range + 1);
              assert (i_inc < BTOR_COUNT_STACK (increments));
              inc = BTOR_PEEK_STACK (increments, i_inc);
              tmp = create_pattern_memset (btor, lower, upper, value, subst,
                                           inc);
              tmp->is_array = 1;
              btor_release_exp (btor, subst);
              subst = tmp;
              btor_free_bv (mm, inc);
              i_inc++;
            }

          /* find patterns that are dependent on the current index */
          for (; i_index < BTOR_COUNT_STACK (indices); i_index++)
            {
              lower = BTOR_PEEK_STACK (indices, i_index);
              /* next value */
              if (!lower)
                {
                  i_index++;
                  break;
                }
              assert (!btor_find_in_ptr_hash_table (index_value_map,
                                                    lower));
              /* save index value pairs for later */
              btor_insert_in_ptr_hash_table (index_value_map,
                                             lower)->data.asPtr = value;

              /* pattern 1: index -> index */
              if (is_itoi_pattern (lower, value))
                BTOR_PUSH_STACK (mm, indices_itoi, lower);
              /* pattern 2: index -> index + 1 */
              else if (is_itoip1_pattern (lower, value))
                BTOR_PUSH_STACK (mm, indices_itoip1, lower);
              /* pattern 3: memcopy pattern */
              else if (is_cpy_pattern (lower, value))
                BTOR_PUSH_STACK (mm, indices_cpy, lower);
              else /* no pattern found */
                BTOR_PUSH_STACK (mm, indices_rem, lower);
            }
        }

      /* pattern: index -> index */
      BTOR_RESET_STACK (ranges);
      BTOR_RESET_STACK (increments);
      find_ranges (btor, &indices_itoi, &ranges, &increments, &indices_rem,
                   &num_set_itoi, 0, &size_set_itoi, 0);
      if (!BTOR_EMPTY_STACK (ranges))
        {
          assert (BTOR_COUNT_STACK (ranges) % 2 == 0);
          for (i_range = 0, i_inc = 0;
               i_range < BTOR_COUNT_STACK (ranges) - 1;
               i_range += 2, i_inc++)
            {
              lower = BTOR_PEEK_STACK (ranges, i_range);
              upper = BTOR_PEEK_STACK (ranges, i_range + 1);
              assert (i_inc < BTOR_COUNT_STACK (increments));
              inc = BTOR_PEEK_STACK (increments, i_inc);
              tmp = create_pattern_itoi (btor, lower, upper, subst, inc);
              tmp->is_array = 1;
              btor_release_exp (btor, subst);
              subst = tmp;
              btor_free_bv (mm, inc);
            }
        }

      /* pattern: index -> index + 1 */
      BTOR_RESET_STACK (ranges);
      BTOR_RESET_STACK (increments);
      find_ranges (btor, &indices_itoip1, &ranges, &increments, &indices_rem,
                   &num_set_itoip1, 0, &size_set_itoip1, 0);
      if (!BTOR_EMPTY_STACK (ranges))
        {
          assert (BTOR_COUNT_STACK (ranges) % 2 == 0);
          for (i_range = 0, i_inc = 0;
               i_range < BTOR_COUNT_STACK (ranges) - 1;
               i_range += 2, i_inc++)
            {
              lower = BTOR_PEEK_STACK (ranges, i_range);
              upper = BTOR_PEEK_STACK (ranges, i_range + 1);
              assert (i_inc < BTOR_COUNT_STACK (increments));
              inc = BTOR_PEEK_STACK (increments, i_inc);
              tmp = create_pattern_itoip1 (btor, lower, upper, subst, inc);
              tmp->is_array = 1;
              btor_release_exp (btor, subst);
              subst = tmp;
              btor_free_bv (mm, inc);
            }
        }

      /* pattern: memcopy */
      BTOR_RESET_STACK (ranges);
      BTOR_RESET_STACK (increments);
      find_ranges (btor, &indices_cpy, &ranges, &increments, &indices_rem,
                   &num_cpy, 0, &size_cpy, 0);
      if (!BTOR_EMPTY_STACK (ranges))
        {
          assert (base == subst);
          assert (BTOR_COUNT_STACK (ranges) % 2 == 0);
          for (i_range = 0, i_inc = 0;
               i_range < BTOR_COUNT_STACK (ranges) - 1;
               i_range += 2, i_inc++)
            {
              lower = BTOR_PEEK_STACK (ranges, i_range);
              upper = BTOR_PEEK_STACK (ranges, i_range + 1);
              assert (i_inc < BTOR_COUNT_STACK (increments));
              inc = BTOR_PEEK_STACK (increments, i_inc);
              b = btor_find_in_ptr_hash_table (index_value_map, lower);
              value = b->data.asPtr; 
              extract_cpy_src_dst_info (lower, value,
                                        &src_array, &src_addr, &dst_addr, 0);
              /* 'subst' == destination array */
              tmp = create_pattern_cpy (btor, lower, upper,
                                        src_array, subst,
                                        src_addr, dst_addr, inc);
              tmp->is_array = 1;
              btor_release_exp (btor, subst);
              subst = tmp;
              btor_free_bv (mm, inc);
            }
        }

      num_total = num_set + num_set_inc + num_set_itoi + num_set_itoip1 +
                  num_cpy;

      /* we can skip creating writes if we did not find any pattern in a write
       * chain, and thus can leave the write chain as-is.
       * for the top equality case we always have to create writes since we
       * convert top level equalities to writes. */
      if (is_top_eq || num_total > 0)
        {
          /* no pattern found for indices in 'indices_rem'. create writes */
          for (i_index = 0; i_index < BTOR_COUNT_STACK (indices_rem); i_index++)
            {
              lower = BTOR_PEEK_STACK (indices_rem, i_index);
              b = btor_find_in_ptr_hash_table (index_value_map, lower);
              assert (b);
              value = b->data.asPtr;
              tmp = btor_write_exp (btor, subst, lower, value);
              btor_release_exp (btor, subst);
              subst = tmp;
              num_writes++;
            }
        }

      assert ((is_top_eq || num_total > 0) || base == subst);
      if (base != subst)
        btor_insert_substitution (btor, array, subst, 0);
      btor_release_exp (btor, subst);

      btor_delete_ptr_hash_table (index_value_map);
      btor_delete_ptr_hash_table (t);
      BTOR_RESET_STACK (ranges);
      BTOR_RESET_STACK (indices);
      BTOR_RESET_STACK (values);
      BTOR_RESET_STACK (increments);
      BTOR_RESET_STACK (indices_itoi);
      BTOR_RESET_STACK (indices_itoip1);
      BTOR_RESET_STACK (indices_cpy);
      BTOR_RESET_STACK (indices_rem);
    }
  BTOR_RELEASE_STACK (mm, ranges);
  BTOR_RELEASE_STACK (mm, indices);
  BTOR_RELEASE_STACK (mm, values);
  BTOR_RELEASE_STACK (mm, increments);
  BTOR_RELEASE_STACK (mm, indices_itoi);
  BTOR_RELEASE_STACK (mm, indices_itoip1);
  BTOR_RELEASE_STACK (mm, indices_cpy);
  BTOR_RELEASE_STACK (mm, indices_rem);

  BTOR_MSG (btor->msg, 1,
            "set: %u (%u), "
            "set_inc: %u (%u), "
            "set_itoi: %u (%u), "
            "set_itoip1: %u (%u), "
            "cpy: %u (%u)",
            num_set, size_set,
            num_set_inc, size_set_inc,
            num_set_itoi, size_set_itoi,
            num_set_itoip1, size_set_itoip1,
            num_cpy, size_cpy);
  return num_total;
}
void
btor_eliminate_applies (Btor * btor)
{
  assert (btor);

  int num_applies, num_applies_total = 0, round;
  double start, delta;
  BtorPtrHashTable *apps;
  BtorNode *app, *fun;
  BtorNodeIterator it;
  BtorHashTableIterator h_it;
  BtorMemMgr *mm;

  if (btor->lambdas->count == 0)
    return;

  start = btor_time_stamp ();

  mm = btor->mm;
  round = 1;

  /* NOTE: in some cases substitute_and_rebuild creates applies that can be
   * beta-reduced. this can happen when parameterized applies become not
   * parameterized. hence, we beta-reduce applies until fix point.
   */
  do
    {
      apps = btor_new_ptr_hash_table (mm,
                                      (BtorHashPtr) btor_hash_exp_by_id,
                                      (BtorCmpPtr) btor_compare_exp_by_id);

      /* collect function applications */
      btor_init_node_hash_table_iterator (&h_it, btor->lambdas);
      while (btor_has_next_node_hash_table_iterator (&h_it))
        {
          fun = btor_next_node_hash_table_iterator (&h_it);

          btor_init_apply_parent_iterator (&it, fun);
          while (btor_has_next_apply_parent_iterator (&it))
            {
              app = btor_next_apply_parent_iterator (&it);

              if (btor_find_in_ptr_hash_table (apps, app))
                continue;

              if (app->parameterized)
                continue;

              btor_insert_in_ptr_hash_table (apps, btor_copy_exp (btor, app));
            }
        }

      num_applies = apps->count;
      num_applies_total += num_applies;
      BTOR_MSG (btor->msg, 1, "eliminate %d applications in round %d",
                num_applies, round);

      btor_substitute_and_rebuild (btor, apps, -1);

      btor_init_node_hash_table_iterator (&h_it, apps);
      while (btor_has_next_node_hash_table_iterator (&h_it))
        btor_release_exp (btor, btor_next_node_hash_table_iterator (&h_it));
      btor_delete_ptr_hash_table (apps);
      round++;
    }
  while (num_applies > 0);

#ifndef NDEBUG
  btor_init_node_hash_table_iterator (&h_it, btor->lambdas);
  while (btor_has_next_node_hash_table_iterator (&h_it))
    {
      fun = btor_next_node_hash_table_iterator (&h_it);

      btor_init_apply_parent_iterator (&it, fun);
      while (btor_has_next_apply_parent_iterator (&it))
        {
          app = btor_next_apply_parent_iterator (&it);
          assert (app->parameterized);
        }
    }
#endif

  delta = btor_time_stamp () - start;
  btor->time.betareduce += delta;
  BTOR_MSG (btor->msg, 1, "eliminated %d function applications in %.1f seconds",
            num_applies_total, delta);
  assert (btor_check_all_hash_tables_proxy_free_dbg (btor));
  assert (btor_check_all_hash_tables_simp_free_dbg (btor));
  assert (btor_check_unique_table_children_proxy_free_dbg (btor));
}
BtorParamCacheTuple *
btor_new_param_cache_tuple (Btor * btor, BtorNode * exp)
{
  assert (btor);
  assert (exp);
  assert (BTOR_IS_REGULAR_NODE (exp));

  int i;
  unsigned int hash;
  BtorNode *param, *arg, *cur;
  BtorParamCacheTuple *t;
  BtorParameterizedIterator it;
  BtorNodeIterator pit;

  BTOR_NEW (btor->mm, t);
  BTOR_CLR (t);
  t->exp = btor_copy_exp (btor, exp);

  btor_init_parameterized_iterator (&it, btor, exp);

  hash = BTOR_REAL_ADDR_NODE (exp)->id;
  if (btor_has_next_parameterized_iterator (&it))
    {
      t->num_args = it.num_params; 
      if (BTOR_IS_LAMBDA_NODE (exp))
        t->num_args += btor_get_fun_arity (btor, exp);

      BTOR_NEWN (btor->mm, t->args, t->num_args);

      i = 0;
      if (BTOR_IS_LAMBDA_NODE (exp))
        {
          btor_init_lambda_iterator (&pit, exp);
          while (btor_has_next_lambda_iterator (&pit))
            {
              cur = btor_next_lambda_iterator (&pit);
              arg = btor_param_cur_assignment (cur->e[0]);
              if (!arg)
                arg = cur->e[0];
              assert (arg);
              t->args[i++] = btor_copy_exp (btor, arg);
              hash += (unsigned int) BTOR_GET_ID_NODE (arg);
            }
        }

      do
        {
          param = btor_next_parameterized_iterator (&it);
          assert (BTOR_IS_REGULAR_NODE (param));
          assert (BTOR_IS_PARAM_NODE (param));
          arg = btor_param_cur_assignment (param);
          if (!arg)
            arg = param;
          assert (arg);
          t->args[i++] = btor_copy_exp (btor, arg);
          hash += (unsigned int) BTOR_GET_ID_NODE (arg);
        }
      while (btor_has_next_parameterized_iterator (&it));
    }
  else if (BTOR_IS_LAMBDA_NODE (exp))
    {
      btor_init_lambda_iterator (&pit, exp);
      t->num_args = btor_get_fun_arity (btor, exp);
      BTOR_NEWN (btor->mm, t->args, t->num_args);

      i = 0;
      while (btor_has_next_lambda_iterator (&pit))
        {
          cur = btor_next_lambda_iterator (&pit);
          arg = btor_param_cur_assignment (cur->e[0]);
          if (!arg)
            arg = cur->e[0];
          assert (arg);
          t->args[i++] = btor_copy_exp (btor, arg);
          hash += (unsigned int) BTOR_GET_ID_NODE (arg);
        }
    }
  hash *= 7334147u;
  t->hash = hash;

  return t;
}