void btor_extract_lambdas (Btor * btor) { assert (btor); unsigned num_lambdas; double start, delta; BtorPtrHashTable *map_value_index, *map_lambda_base; BtorMemMgr *mm; start = btor_time_stamp (); mm = btor->mm; /* maps for each array values to stacks of indices */ map_value_index = btor_new_ptr_hash_table (mm, 0, 0); /* contains the base array for each write chain */ map_lambda_base = btor_new_ptr_hash_table (mm, 0, 0); btor_init_substitutions (btor); /* collect lambdas that are at the top of lambda chains */ collect_indices_writes (btor, map_value_index, map_lambda_base); /* top level equality pre-initialization */ collect_indices_top_eqs (btor, map_value_index); num_lambdas = extract_lambdas (btor, map_value_index, map_lambda_base); btor_delete_ptr_hash_table (map_lambda_base); btor_delete_ptr_hash_table (map_value_index); btor_substitute_and_rebuild (btor, btor->substitutions, 0); btor_delete_substitutions (btor); delta = btor_time_stamp () - start; BTOR_MSG (btor->msg, 1, "extracted %u lambdas in %.3f seconds", num_lambdas, delta); }
static void add_to_index_map (Btor * btor, BtorPtrHashTable * map_value_index, BtorNode * lambda, BtorNode * index, BtorNode * value) { BtorMemMgr *mm; BtorPtrHashBucket *b; BtorPtrHashTable *t; BtorNodePtrStack *indices; BtorNode *offset; mm = btor->mm; if (!(b = btor_find_in_ptr_hash_table (map_value_index, lambda))) { b = btor_insert_in_ptr_hash_table (map_value_index, lambda); t = btor_new_ptr_hash_table (mm, 0, 0); b->data.asPtr = t; } else t = b->data.asPtr; assert (t); if (!(b = btor_find_in_ptr_hash_table (t, value))) { b = btor_insert_in_ptr_hash_table (t, value); BTOR_NEW (mm, indices); BTOR_INIT_STACK (*indices); b->data.asPtr = indices; } else indices = (BtorNodePtrStack *) b->data.asPtr; assert (indices); if (BTOR_IS_BV_CONST_NODE (BTOR_REAL_ADDR_NODE (index))) offset = index; else { assert (BTOR_IS_REGULAR_NODE (index)); assert (BTOR_IS_ADD_NODE (index)); extract_base_addr_offset (index, 0, &offset); assert (BTOR_IS_BV_CONST_NODE (BTOR_REAL_ADDR_NODE (offset))); } /* generate inverted bit string for constants if required */ if (BTOR_IS_INVERTED_NODE (offset) && !btor_const_get_invbits (offset)) btor_const_set_invbits ( offset, btor_not_bv (mm, btor_const_get_bits (offset))); BTOR_PUSH_STACK (mm, *indices, index); }
static void get_children (BtorSMTDumpContext * sdc, BtorNode * exp, BtorNodePtrStack * children) { assert (children); assert (BTOR_EMPTY_STACK (*children)); int i, is_and = 0; BtorNode *cur, *real_cur; BtorPtrHashTable *mark; BtorNodePtrQueue visit; BtorPtrHashBucket *b; mark = btor_new_ptr_hash_table (sdc->btor->mm, 0, 0); if (BTOR_IS_AND_NODE (BTOR_REAL_ADDR_NODE (exp))) is_and = 1; BTOR_INIT_QUEUE (visit); for (i = 0; i < BTOR_REAL_ADDR_NODE (exp)->arity; i++) BTOR_ENQUEUE (sdc->btor->mm, visit, BTOR_REAL_ADDR_NODE (exp)->e[i]); /* get children of multi-input and/or */ while (!BTOR_EMPTY_QUEUE (visit)) { cur = BTOR_DEQUEUE (visit); real_cur = BTOR_REAL_ADDR_NODE (cur); if (btor_find_in_ptr_hash_table (mark, real_cur)) continue; b = btor_find_in_ptr_hash_table (sdc->dump, real_cur); btor_insert_in_ptr_hash_table (mark, real_cur); if (!BTOR_IS_AND_NODE (real_cur) || (b && b->data.asInt > 1) || (is_and && BTOR_IS_INVERTED_NODE (cur))) { BTOR_PUSH_STACK (sdc->btor->mm, *children, cur); continue; } assert (!btor_find_in_ptr_hash_table (sdc->dumped, real_cur)); btor_insert_in_ptr_hash_table (sdc->dumped, real_cur); for (i = 0; i < real_cur->arity; i++) BTOR_ENQUEUE (sdc->btor->mm, visit, real_cur->e[i]); } BTOR_RELEASE_QUEUE (sdc->btor->mm, visit); btor_delete_ptr_hash_table (mark); }
BtorAIGMap * btor_new_aig_map (Btor * btor, BtorAIGMgr * amgr_src, BtorAIGMgr * amgr_dst) { assert (btor); assert (amgr_src); assert (amgr_dst); BtorAIGMap *res; BTOR_NEW (btor->mm, res); res->btor = btor; res->amgr_src = amgr_src; res->amgr_dst = amgr_dst; res->table = btor_new_ptr_hash_table (btor->mm, 0, 0); return res; }
BtorNodeMap * btor_new_node_map (Btor * btor) { BtorNodeMap *res; assert (btor); BTOR_NEW (btor->mm, res); res->btor = btor; res->table = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); res->simplify = 0; return res; }
static BtorSMTDumpContext * new_smt_dump_context (Btor * btor, FILE * file) { BtorSMTDumpContext * sdc; BTOR_CNEW (btor->mm, sdc); sdc->btor = btor; sdc->dump = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); sdc->dumped = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); sdc->boolean = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); sdc->stores = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); sdc->idtab = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); sdc->const_cache = btor_new_ptr_hash_table (btor->mm, (BtorHashPtr) btor_hash_str, (BtorCmpPtr) strcmp); /* use pointer for hashing and comparison */ sdc->roots = btor_new_ptr_hash_table (btor->mm, 0, 0); sdc->file = file; sdc->maxid = 1; sdc->pretty_print = btor->options.pretty_print.val; return sdc; }
static void dump_fun_smt2 (BtorSMTDumpContext * sdc, BtorNode * fun) { assert (fun); assert (sdc); assert (BTOR_IS_REGULAR_NODE (fun)); assert (BTOR_IS_LAMBDA_NODE (fun)); assert (!fun->parameterized); assert (!btor_find_in_ptr_hash_table (sdc->dumped, fun)); int i, refs; BtorNode *cur, *param, *fun_body, *p; BtorMemMgr *mm = sdc->btor->mm; BtorNodePtrStack visit, shared; BtorNodeIterator it, iit; BtorPtrHashTable *mark; BtorPtrHashBucket *b; mark = btor_new_ptr_hash_table (mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); BTOR_INIT_STACK (visit); BTOR_INIT_STACK (shared); #if 0 extract_store (sdc, fun, &index, &value, &array); if (index) { assert (value); assert (array); btor_insert_in_ptr_hash_table (sdc->stores, fun); return; } #endif /* collect shared parameterized expressions in function body */ fun_body = btor_lambda_get_body (fun); BTOR_PUSH_STACK (mm, visit, fun_body); while (!BTOR_EMPTY_STACK (visit)) { cur = BTOR_REAL_ADDR_NODE (BTOR_POP_STACK (visit)); if (btor_find_in_ptr_hash_table (mark, cur) || btor_find_in_ptr_hash_table (sdc->dumped, cur) || BTOR_IS_LAMBDA_NODE (cur)) continue; b = btor_find_in_ptr_hash_table (sdc->dump, cur); assert (b); refs = b->data.asInt; /* args and params are handled differently */ /* collect shared parameterized expressions in function body. * arguments, parameters, and constants are excluded. */ if (!BTOR_IS_ARGS_NODE (cur) && !BTOR_IS_PARAM_NODE (cur) /* constants are always printed */ && !BTOR_IS_BV_CONST_NODE (cur) && cur->parameterized && refs > 1) BTOR_PUSH_STACK (mm, shared, cur); btor_insert_in_ptr_hash_table (mark, cur); for (i = 0; i < cur->arity; i++) BTOR_PUSH_STACK (mm, visit, cur->e[i]); } /* dump function signature */ fputs ("(define-fun ", sdc->file); dump_smt_id (sdc, fun); fputs (" (", sdc->file); btor_init_lambda_iterator (&it, fun); while (btor_has_next_lambda_iterator (&it)) { cur = btor_next_lambda_iterator (&it); param = cur->e[0]; if (!btor_find_in_ptr_hash_table (mark, cur)) btor_insert_in_ptr_hash_table (mark, cur); if (!btor_find_in_ptr_hash_table (mark, param)) btor_insert_in_ptr_hash_table (mark, param); btor_insert_in_ptr_hash_table (sdc->dumped, cur); btor_insert_in_ptr_hash_table (sdc->dumped, param); if (fun != cur) fputc (' ', sdc->file); fputc ('(', sdc->file); dump_smt_id (sdc, param); fputc (' ', sdc->file); btor_dump_sort_smt_node (param, sdc->file); fputc (')', sdc->file); } fputs (") ", sdc->file); // TODO (ma): again wait for aina merge for dump_sort_smt if (is_boolean (sdc, fun_body)) fputs ("Bool", sdc->file); else btor_dump_sort_smt_node (fun_body, sdc->file); fputc (' ', sdc->file); assert (sdc->open_lets == 0); /* dump expressions that are shared in 'fun' */ if (shared.start) qsort (shared.start, BTOR_COUNT_STACK (shared), sizeof (BtorNode *), cmp_node_id); for (i = 0; i < BTOR_COUNT_STACK (shared); i++) { cur = BTOR_PEEK_STACK (shared, i); assert (BTOR_IS_REGULAR_NODE (cur)); assert (cur->parameterized); dump_let_smt (sdc, cur); fputc (' ', sdc->file); } recursively_dump_exp_smt (sdc, fun_body, !is_boolean (sdc, fun_body), 0); /* close lets */ for (i = 0; i < sdc->open_lets; i++) fputc (')', sdc->file); sdc->open_lets = 0; /* close define-fun */ fputs (")\n", sdc->file); /* due to lambda hashing it is possible that a lambda in 'fun' is shared in * different functions. hence, we have to check if all lambda parents of * the resp. lambda have already been dumped as otherwise all expressions * below have to be removed from 'sdc->dumped' as they will be dumped * again in a different function definition. */ btor_init_lambda_iterator (&it, fun); while (btor_has_next_lambda_iterator (&it)) { cur = btor_next_lambda_iterator (&it); btor_init_parent_iterator (&iit, cur); while (btor_has_next_parent_iterator (&iit)) { p = btor_next_parent_iterator (&iit); /* find lambda parent that needs to be dumped but has not yet been * dumped */ if (btor_find_in_ptr_hash_table (sdc->dump, p) && !btor_find_in_ptr_hash_table (sdc->dumped, p) && BTOR_IS_LAMBDA_NODE (p)) { BTOR_PUSH_STACK (mm, visit, cur); while (!BTOR_EMPTY_STACK (visit)) { cur = BTOR_REAL_ADDR_NODE (BTOR_POP_STACK (visit)); assert (BTOR_IS_REGULAR_NODE (cur)); if (!cur->parameterized && (!btor_find_in_ptr_hash_table (mark, cur) || !btor_find_in_ptr_hash_table (sdc->dumped, cur))) continue; if (btor_find_in_ptr_hash_table (sdc->dumped, cur)) btor_remove_from_ptr_hash_table (sdc->dumped, cur, 0, 0); for (i = 0; i < cur->arity; i++) BTOR_PUSH_STACK (mm, visit, cur->e[i]); } break; } } } BTOR_RELEASE_STACK (mm, shared); BTOR_RELEASE_STACK (mm, visit); btor_delete_ptr_hash_table (mark); }
static void recursively_dump_exp_smt (BtorSMTDumpContext * sdc, BtorNode * exp, int expect_bv, unsigned depth_limit) { assert (sdc); assert (exp); assert (btor_find_in_ptr_hash_table (sdc->dump, BTOR_REAL_ADDR_NODE (exp))); unsigned depth; int pad, i, is_bool, add_space, zero_extend, expect_bool; BtorBitVector *bitsbv; char *bits; const char *op, *fmt; BtorNode *arg, *real_exp; BtorArgsIterator it; BtorNodePtrStack dump, args; BtorIntStack expect_bv_stack, expect_bool_stack, depth_stack; BtorIntStack add_space_stack, zero_extend_stack; BtorPtrHashTable *visited; BtorMemMgr *mm; mm = sdc->btor->mm; visited = btor_new_ptr_hash_table (mm, 0, 0); BTOR_INIT_STACK (args); BTOR_INIT_STACK (dump); BTOR_INIT_STACK (expect_bv_stack); BTOR_INIT_STACK (expect_bool_stack); BTOR_INIT_STACK (add_space_stack); BTOR_INIT_STACK (zero_extend_stack); BTOR_INIT_STACK (depth_stack); PUSH_DUMP_NODE (exp, expect_bv, 0, 0, 0, 0); while (!BTOR_EMPTY_STACK (dump)) { assert (!BTOR_EMPTY_STACK (expect_bv_stack)); assert (!BTOR_EMPTY_STACK (expect_bool_stack)); assert (!BTOR_EMPTY_STACK (add_space_stack)); assert (!BTOR_EMPTY_STACK (zero_extend_stack)); assert (!BTOR_EMPTY_STACK (depth_stack)); depth = BTOR_POP_STACK (depth_stack); exp = BTOR_POP_STACK (dump); expect_bv = BTOR_POP_STACK (expect_bv_stack); expect_bool = BTOR_POP_STACK (expect_bool_stack); add_space = BTOR_POP_STACK (add_space_stack); zero_extend = BTOR_POP_STACK (zero_extend_stack); real_exp = BTOR_REAL_ADDR_NODE (exp); is_bool = is_boolean (sdc, real_exp); assert (!expect_bv || !expect_bool); assert (!expect_bool || !expect_bv); /* open s-expression */ if (!btor_find_in_ptr_hash_table (visited, real_exp)) { if (add_space) fputc (' ', sdc->file); /* wrap node with zero_extend */ if (zero_extend) { fmt = " ((_ zero_extend %d) "; fprintf (sdc->file, fmt, zero_extend); } /* always print constants */ if (BTOR_IS_BV_CONST_NODE (real_exp)) { if (exp == sdc->btor->true_exp && !expect_bv) fputs ("true", sdc->file); else if (exp == BTOR_INVERT_NODE (sdc->btor->true_exp) && !expect_bv) fputs ("false", sdc->file); else if (BTOR_IS_INVERTED_NODE (exp)) { bitsbv = btor_not_bv ( sdc->btor->mm, btor_const_get_bits (real_exp)); bits = btor_bv_to_char_bv (sdc->btor->mm, bitsbv); dump_const_value_aux_smt (sdc, bits); btor_free_bv (sdc->btor->mm, bitsbv); btor_freestr (sdc->btor->mm, bits); } else { bits = btor_bv_to_char_bv ( sdc->btor->mm, btor_const_get_bits (real_exp)); dump_const_value_aux_smt (sdc, bits); btor_freestr (sdc->btor->mm, bits); } /* close zero extend */ if (zero_extend) fputc (')', sdc->file); continue; } /* wrap non-bool node and make it bool */ if (expect_bool && !is_bool) { fputs ("(= ", sdc->file); dump_const_value_aux_smt (sdc, "1"); fputc (' ', sdc->file); } /* wrap node with bvnot/not */ if (BTOR_IS_INVERTED_NODE (exp)) fputs (expect_bv || !is_bool ? "(bvnot " : "(not ", sdc->file); /* wrap bool node and make it a bit vector expression */ if (is_bool && expect_bv) fputs ("(ite ", sdc->file); if (btor_find_in_ptr_hash_table (sdc->dumped, real_exp) || BTOR_IS_LAMBDA_NODE (real_exp) || BTOR_IS_UF_NODE (real_exp)) { #ifndef NDEBUG BtorPtrHashBucket *b; b = btor_find_in_ptr_hash_table (sdc->dump, real_exp); assert (b); /* functions and variables are declared separately */ assert (BTOR_IS_LAMBDA_NODE (real_exp) || BTOR_IS_UF_NODE (real_exp) || BTOR_IS_BV_VAR_NODE (real_exp) || BTOR_IS_PARAM_NODE (real_exp) || b->data.asInt > 1); #endif dump_smt_id (sdc, exp); goto CLOSE_WRAPPER; } if (depth_limit && depth >= depth_limit) { fprintf (sdc->file, "%s_%d", g_kind2smt[real_exp->kind], real_exp->id); goto CLOSE_WRAPPER; } PUSH_DUMP_NODE (exp, expect_bv, expect_bool, 0, zero_extend, depth); btor_insert_in_ptr_hash_table (visited, real_exp); op = ""; switch (real_exp->kind) { case BTOR_SLL_NODE: case BTOR_SRL_NODE: assert (!is_bool); op = real_exp->kind == BTOR_SRL_NODE ? "bvlshr" : "bvshl"; assert (btor_get_exp_width (sdc->btor, real_exp) > 1); pad = btor_get_exp_width (sdc->btor, real_exp) - btor_get_exp_width (sdc->btor, real_exp->e[1]); PUSH_DUMP_NODE (real_exp->e[1], 1, 0, 1, pad, depth + 1); PUSH_DUMP_NODE (real_exp->e[0], 1, 0, 1, 0, depth + 1); break; case BTOR_BCOND_NODE: op = "ite"; PUSH_DUMP_NODE (real_exp->e[2], !is_bool, 0, 1, 0, depth + 1); PUSH_DUMP_NODE (real_exp->e[1], !is_bool, 0, 1, 0, depth + 1); PUSH_DUMP_NODE (real_exp->e[0], 0, 1, 1, 0, depth + 1); break; case BTOR_APPLY_NODE: /* we need the arguments in reversed order */ btor_init_args_iterator (&it, real_exp->e[1]); while (btor_has_next_args_iterator (&it)) { arg = btor_next_args_iterator (&it); BTOR_PUSH_STACK (mm, args, arg); } while (!BTOR_EMPTY_STACK (args)) { arg = BTOR_POP_STACK (args); // TODO (ma): what about bool arguments/indices PUSH_DUMP_NODE (arg, 1, 0, 1, 0, depth + 1); } PUSH_DUMP_NODE (real_exp->e[0], 1, 0, 0, 0, depth + 1); break; #if 0 case BTOR_LAMBDA_NODE: extract_store (sdc, exp, &index, &value, &array); assert (index); assert (value); assert (array); fputs ("(store ", sdc->file); DUMP_EXP_SMT (array); fputc (' ', sdc->file); DUMP_EXP_SMT (index); fputc (' ', sdc->file); DUMP_EXP_SMT (value); fputc (')', sdc->file); break; #endif default: expect_bv = 1; switch (real_exp->kind) { case BTOR_FEQ_NODE: case BTOR_BEQ_NODE: op = "="; expect_bv = 1; break; case BTOR_ULT_NODE: op = "bvult"; expect_bv = 1; break; case BTOR_SLICE_NODE: assert (!is_bool); op = "(_ extract "; break; case BTOR_AND_NODE: op = is_bool ? "and" : "bvand"; expect_bv = !is_bool; break; case BTOR_ADD_NODE: assert (!is_bool); op = "bvadd"; break; case BTOR_MUL_NODE: assert (!is_bool); op = "bvmul"; break; case BTOR_UDIV_NODE: assert (!is_bool); op = "bvudiv"; break; case BTOR_UREM_NODE: assert (!is_bool); op = "bvurem"; break; case BTOR_CONCAT_NODE: assert (!is_bool); op = "concat"; break; default: assert (0); op = "unknown"; } if (BTOR_IS_AND_NODE (real_exp) && is_bool) { assert (BTOR_EMPTY_STACK (args)); get_children (sdc, exp, &args); for (i = 0; i < BTOR_COUNT_STACK (args); i++) { arg = BTOR_PEEK_STACK (args, i); PUSH_DUMP_NODE (arg, expect_bv, 0, 1, 0, depth + 1); } BTOR_RESET_STACK (args); } else for (i = real_exp->arity - 1; i >= 0; i--) PUSH_DUMP_NODE (real_exp->e[i], expect_bv, 0, 1, 0, depth + 1); } /* open s-expression */ assert (op); fprintf (sdc->file, "(%s", op); if (BTOR_IS_SLICE_NODE (real_exp)) { fmt = "%d %d)"; fprintf (sdc->file, fmt, btor_slice_get_upper (real_exp), btor_slice_get_lower (real_exp)); } } /* close s-expression */ else { if (!btor_find_in_ptr_hash_table (sdc->dumped, real_exp)) btor_insert_in_ptr_hash_table (sdc->dumped, real_exp); /* close s-expression */ if (real_exp->arity > 0) fputc (')', sdc->file); CLOSE_WRAPPER: /* close wrappers */ /* wrap boolean expressions in bit vector expression */ if (is_bool && expect_bv && !BTOR_IS_BV_CONST_NODE (real_exp)) { fputc (' ', sdc->file); dump_const_value_aux_smt (sdc, "1"); fputc (' ', sdc->file); dump_const_value_aux_smt (sdc, "0"); fputc (')', sdc->file); } /* close bvnot for non-constants */ if (BTOR_IS_INVERTED_NODE (exp) && !BTOR_IS_BV_CONST_NODE (real_exp)) fputc (')', sdc->file); /* close bool wrapper */ if (expect_bool && !is_boolean (sdc, real_exp)) fputc (')', sdc->file); /* close zero extend wrapper */ if (zero_extend) fputc (')', sdc->file); } } assert (BTOR_EMPTY_STACK (expect_bv_stack)); BTOR_RELEASE_STACK (mm, args); BTOR_RELEASE_STACK (mm, dump); BTOR_RELEASE_STACK (mm, expect_bv_stack); BTOR_RELEASE_STACK (mm, expect_bool_stack); BTOR_RELEASE_STACK (mm, add_space_stack); BTOR_RELEASE_STACK (mm, zero_extend_stack); BTOR_RELEASE_STACK (mm, depth_stack); btor_delete_ptr_hash_table (visited); }
static void collect_indices_writes (Btor * btor, BtorPtrHashTable * map_value_index, BtorPtrHashTable * map_lambda_base) { int is_top; BtorNode *lambda, *cur, *array, *index, *value, *tmp, *array_if, *array_else; BtorNode *prev_index, *prev_value; BtorHashTableIterator it; BtorNodeIterator pit; BtorNodePtrStack lambdas; BtorPtrHashTable *index_cache, *visit_cache; BtorMemMgr *mm; mm = btor->mm; BTOR_INIT_STACK (lambdas); visit_cache = btor_new_ptr_hash_table (mm, 0, 0); /* collect lambdas that are at the top of lambda chains */ btor_init_reversed_hash_table_iterator (&it, btor->lambdas); while (btor_has_next_node_hash_table_iterator (&it)) { lambda = btor_next_node_hash_table_iterator (&it); assert (BTOR_IS_REGULAR_NODE (lambda)); /* already visited */ if (btor_find_in_ptr_hash_table (map_value_index, lambda)) continue; /* we only consider writes */ if (btor_get_fun_arity (btor, lambda) > 1) continue; is_top = 0; btor_init_apply_parent_iterator (&pit, lambda); while (btor_has_next_apply_parent_iterator (&pit)) { tmp = btor_next_apply_parent_iterator (&pit); if (!tmp->parameterized) { is_top = 1; break; } } if (!is_top) continue; BTOR_PUSH_STACK (mm, lambdas, lambda); while (!BTOR_EMPTY_STACK (lambdas)) { lambda = BTOR_POP_STACK (lambdas); /* already visited */ if (btor_find_in_ptr_hash_table (visit_cache, lambda)) continue; btor_insert_in_ptr_hash_table (visit_cache, lambda); cur = lambda; index_cache = btor_new_ptr_hash_table (mm, 0, 0); prev_index = prev_value = 0; while (is_write_exp (cur, &array, &index, &value)) { assert (BTOR_IS_REGULAR_NODE (array)); assert (BTOR_IS_FUN_NODE (array)); /* index already cached, this index will be overwritten anyways, * so we can skip it */ if (btor_find_in_ptr_hash_table (index_cache, index)) { cur = array; continue; } /* collect index/value pairs for absolute set patterns */ if (is_abs_set_pattern (index, prev_index)) { btor_insert_in_ptr_hash_table (index_cache, index); add_to_index_map (btor, map_value_index, lambda, index, value); } // TODO (ma): is there a way to recognize base_addr + 0 as // relative? // -> only if its the last index // - prev_index->base_addr == index else if (is_rel_set_pattern (index, prev_index)) { /* collect index/value pairs for memcopy pattern if 'index' * and 'value' still belong to current memcopy pattern */ if (is_copy_pattern (index, value, prev_index, prev_value, array)) { /* optimization for memcopy: do not visit lambdas that * are only accessed via this lambda (reduces number of * redundant memcopy patterns) */ if (value->e[0] == array && array->parents == 2) btor_insert_in_ptr_hash_table (visit_cache, array); btor_insert_in_ptr_hash_table (index_cache, index); add_to_index_map (btor, map_value_index, lambda, index, value); } /* collect index/value pairs for relative set patterns */ else { btor_insert_in_ptr_hash_table (index_cache, index); add_to_index_map (btor, map_value_index, lambda, index, value); } } /* use array as new start point */ else { BTOR_PUSH_STACK (mm, lambdas, array); break; } cur = array; prev_index = index; prev_value = value; } if (btor_find_in_ptr_hash_table (map_value_index, lambda)) { assert (!btor_find_in_ptr_hash_table (map_lambda_base, lambda)); btor_insert_in_ptr_hash_table ( map_lambda_base, lambda)->data.asPtr = cur; } btor_delete_ptr_hash_table (index_cache); // TODO (ma): can only be ite now if (is_array_ite_exp (cur, &array_if, &array_else)) { BTOR_PUSH_STACK (mm, lambdas, array_if); BTOR_PUSH_STACK (mm, lambdas, array_else); } } } btor_delete_ptr_hash_table (visit_cache); BTOR_RELEASE_STACK (mm, lambdas); }
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)); }
int main (int argc, char ** argv) { int i, j, verbosity, close_input, close_output, binary, merge; const char * input_name, * output_name; FILE * input_file, * output_file, * file; BtorAIG * aig, * tmp, * merged, ** p; BtorPtrHashTable * back_annotation; const char * parse_error; BtorPtrHashBucket *b; BtorParseResult model; BtorAIGVecMgr * avmgr; BtorAIGPtrStack regs; BtorAIGPtrStack nexts; BtorAIGPtrStack aigs; BtorParser * parser; BtorAIGMgr * amgr; BtorMemMgr * mem; BtorAIGVec * av; Btor * btor; verbosity = 0; close_input = 0; close_output = 0; binary = 0; merge = 0; input_name = "<stdin>"; output_name = "<stdout>"; input_file = stdin; output_file = stdout; for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "-h")) { printf ("usage: synthebor [-h][-v][-m][<input>[<output>]]\n"); exit (0); } else if (!strcmp (argv[i], "-v")) verbosity++; else if (!strcmp (argv[i], "-m")) merge = 1; else if (argv[i][0] == '-') die (1, "invalid command line option '%s'", argv[i]); else if (close_output) die (1, "too many files"); else if (close_input) { if (!strcmp (argv[i], input_name)) die (1, "input and output are the same"); if (!(file = fopen (argv[i], "w"))) die (1, "can not write '%s'", argv[i]); output_file = file; output_name = argv[i]; close_output = 1; } else if (!(file = fopen (argv[i], "r"))) die (1, "can not read '%s'", argv[i]); else { input_file = file; input_name = argv[i]; close_input = 1; } } btor = btor_new_btor (); btor_set_verbosity_btor (btor, verbosity); btor_set_rewrite_level_btor (btor, 1); parser = btor_btor_parser_api ()->init (btor, verbosity); parse_error = btor_btor_parser_api()->parse (parser, input_file, input_name, &model); if (parse_error) die (0, parse_error); if (!model.noutputs) die (1, "no roots in '%s'", input_name); if (model.nregs && merge) die (1, "can not merge registers"); mem = btor->mm; avmgr = btor->avmgr; amgr = btor_get_aig_mgr_aigvec_mgr (avmgr); back_annotation = btor_new_ptr_hash_table (mem, 0, 0); BTOR_INIT_STACK (regs); BTOR_INIT_STACK (nexts); for (i = 0; i < model.nregs; i++) { if (btor_is_array_exp (btor, model.regs[i])) die (1, "can not synthesize memories (yet)"); av = btor_exp_to_aigvec (btor, model.regs[i], back_annotation); for (j = 0; j < av->len; j++) { aig = btor_copy_aig (amgr, av->aigs[j]); BTOR_PUSH_STACK (mem, regs, aig); } btor_release_delete_aigvec (avmgr, av); av = btor_exp_to_aigvec (btor, model.nexts[i], back_annotation); for (j = 0; j < av->len; j++) { aig = btor_copy_aig (amgr, av->aigs[j]); BTOR_PUSH_STACK (mem, nexts, aig); } btor_release_delete_aigvec (avmgr, av); } BTOR_INIT_STACK (aigs); merged = BTOR_AIG_TRUE; for (i = 0; i < model.noutputs; i++) { av = btor_exp_to_aigvec (btor, model.outputs[i], back_annotation); for (j = 0; j < av->len; j++) { aig = av->aigs[j]; if (merge) { tmp = btor_and_aig (amgr, merged, aig); btor_release_aig (amgr, merged); merged = tmp; } else { aig = btor_copy_aig (amgr, aig); BTOR_PUSH_STACK (mem, aigs, aig); } } btor_release_delete_aigvec (avmgr, av); } if (merge) BTOR_PUSH_STACK (mem, aigs, merged); #ifdef BTOR_HAVE_ISATTY if (close_output || !isatty (1)) binary = 1; #endif assert (BTOR_COUNT_STACK (regs) == BTOR_COUNT_STACK (nexts)); btor_dump_aiger (amgr, binary, output_file, BTOR_COUNT_STACK (aigs), aigs.start, BTOR_COUNT_STACK (regs), regs.start, nexts.start, back_annotation); for (p = aigs.start; p < aigs.top; p++) btor_release_aig (amgr, *p); BTOR_RELEASE_STACK (mem, aigs); for (p = regs.start; p < regs.top; p++) btor_release_aig (amgr, *p); BTOR_RELEASE_STACK (mem, regs); for (p = nexts.start; p < nexts.top; p++) btor_release_aig (amgr, *p); BTOR_RELEASE_STACK (mem, nexts); for (b = back_annotation->first; b; b = b->next) btor_freestr (mem, b->data.asStr); btor_delete_ptr_hash_table (back_annotation); btor_btor_parser_api()->reset (parser); btor_delete_btor (btor); if (close_input) fclose (input_file); if (close_output) fclose (output_file); return 0; }
void btor_process_skeleton (Btor * btor) { BtorPtrHashTable * ids; BtorNodePtrStack unmark_stack; int count, fixed; BtorNodePtrStack work_stack; BtorMemMgr * mm = btor->mm; BtorHashTableIterator it; double start, delta; int res, lit, val; BtorNode * exp; LGL * lgl; start = btor_time_stamp (); ids = btor_new_ptr_hash_table (mm, (BtorHashPtr) btor_hash_exp_by_id, (BtorCmpPtr) btor_compare_exp_by_id); lgl = lglinit (); lglsetprefix (lgl, "[lglskel] "); if (btor->options.verbosity.val >= 2) { lglsetopt (lgl, "verbose", btor->options.verbosity.val - 1); lglbnr ("Lingeling", "[lglskel] ", stdout); fflush (stdout); } else lglsetopt (lgl, "verbose", -1); count = 0; BTOR_INIT_STACK (work_stack); BTOR_INIT_STACK (unmark_stack); btor_init_node_hash_table_iterator (&it, btor->synthesized_constraints); btor_queue_node_hash_table_iterator (&it, btor->unsynthesized_constraints); while (btor_has_next_node_hash_table_iterator (&it)) { count++; exp = btor_next_node_hash_table_iterator (&it); assert (btor_get_exp_width (btor, exp) == 1); process_skeleton_tseitin (btor, lgl, &work_stack, &unmark_stack, ids, exp); lgladd (lgl, process_skeleton_tseitin_lit (ids, exp)); lgladd (lgl, 0); } BTOR_RELEASE_STACK (mm, work_stack); while (!BTOR_EMPTY_STACK (unmark_stack)) { exp = BTOR_POP_STACK (unmark_stack); assert (!BTOR_IS_INVERTED_NODE (exp)); assert (exp->mark); exp->mark = 0; } BTOR_RELEASE_STACK (mm, unmark_stack); BTOR_MSG (btor->msg, 1, "found %u skeleton literals in %d constraints", ids->count, count); res = lglsimp (lgl, 0); if (btor->options.verbosity.val) { BTOR_MSG (btor->msg, 1, "skeleton preprocessing result %d", res); lglstats (lgl); } fixed = 0; if (res == 20) { BTOR_MSG (btor->msg, 1, "skeleton inconsistent"); btor->inconsistent = 1; } else { assert (res == 0 || res == 10); btor_init_node_hash_table_iterator (&it, ids); while (btor_has_next_node_hash_table_iterator (&it)) { exp = btor_next_node_hash_table_iterator (&it); assert (!BTOR_IS_INVERTED_NODE (exp)); lit = process_skeleton_tseitin_lit (ids, exp); val = lglfixed (lgl, lit); if (val) { if (!btor_find_in_ptr_hash_table ( btor->synthesized_constraints, exp) && !btor_find_in_ptr_hash_table ( btor->unsynthesized_constraints, exp)) { if (val < 0) exp = BTOR_INVERT_NODE (exp); btor_assert_exp (btor, exp); btor->stats.skeleton_constraints++; fixed++; } } else { assert (!btor_find_in_ptr_hash_table ( btor->synthesized_constraints, exp)); assert (!btor_find_in_ptr_hash_table ( btor->unsynthesized_constraints, exp)); } } } btor_delete_ptr_hash_table (ids); lglrelease (lgl); delta = btor_time_stamp () - start; btor->time.skel += delta; BTOR_MSG (btor->msg, 1, "skeleton preprocessing produced %d new constraints in %.1f seconds", fixed, delta); assert (btor_check_id_table_mark_unset_dbg (btor)); }