diff --git a/OPTYap/tab.tries.h b/OPTYap/tab.tries.h new file mode 100644 index 000000000..3c7eea8ce --- /dev/null +++ b/OPTYap/tab.tries.h @@ -0,0 +1,2045 @@ +/************************************************************************ +** ** +** The YapTab/YapOr/OPTYap systems ** +** ** +** YapTab extends the Yap Prolog engine to support sequential tabling ** +** YapOr extends the Yap Prolog engine to support or-parallelism ** +** OPTYap extends the Yap Prolog engine to support or-parallel tabling ** +** ** +** ** +** Yap Prolog was developed at University of Porto, Portugal ** +** ** +************************************************************************/ + +/********************* +** Macros ** +*********************/ + +#ifdef MODE_GLOBAL_TRIE_ENTRY +#define INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY) \ + { register gt_node_ptr entry_node = (gt_node_ptr) (ENTRY); \ + TrNode_child(entry_node) = (gt_node_ptr) ((UInt) TrNode_child(entry_node) + 1); \ + } +#define NEW_SUBGOAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \ + INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \ + new_subgoal_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) +#define NEW_ANSWER_TRIE_NODE(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) \ + INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \ + new_answer_trie_node(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) +#define NEW_GLOBAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \ + INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \ + new_global_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) +#else +#define NEW_SUBGOAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \ + new_subgoal_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) +#define NEW_ANSWER_TRIE_NODE(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) \ + new_answer_trie_node(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) +#define NEW_GLOBAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \ + new_global_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + + +#ifdef MODE_GLOBAL_TRIE_LOOP +#define SUBGOAL_CHECK_INSERT_ENTRY(TAB_ENT, NODE, ENTRY) \ + NODE = global_trie_check_insert_entry(NODE, ENTRY PASS_REGS) +#define ANSWER_CHECK_INSERT_ENTRY(SG_FR, NODE, ENTRY, INSTR) \ + NODE = global_trie_check_insert_entry(NODE, ENTRY PASS_REGS) +#else +#define SUBGOAL_CHECK_INSERT_ENTRY(TAB_ENT, NODE, ENTRY) \ + NODE = subgoal_trie_check_insert_entry(TAB_ENT, NODE, ENTRY PASS_REGS) +#define ANSWER_CHECK_INSERT_ENTRY(SG_FR, NODE, ENTRY, INSTR) \ + NODE = answer_trie_check_insert_entry(SG_FR, NODE, ENTRY, INSTR PASS_REGS) +#endif /* MODE_GLOBAL_TRIE_LOOP */ + + +#ifdef INCLUDE_ANSWER_SEARCH_MODE_DIRECTED +#define ANSWER_SAFE_INSERT_ENTRY(NODE, ENTRY, INSTR) \ + { ans_node_ptr new_node; \ + NEW_ANSWER_TRIE_NODE(new_node, INSTR, ENTRY, NULL, NODE, NULL); \ + TrNode_child(NODE) = new_node; \ + NODE = new_node; \ + } +#ifdef THREADS +#define INVALIDATE_ANSWER_TRIE_NODE(NODE, SG_FR) \ + TrNode_next(NODE) = SgFr_invalid_chain(SG_FR); \ + SgFr_invalid_chain(SG_FR) = NODE +#else +#define INVALIDATE_ANSWER_TRIE_NODE(NODE, SG_FR) \ + FREE_ANSWER_TRIE_NODE(NODE) +#endif /* THREADS */ +#define INVALIDATE_ANSWER_TRIE_LEAF_NODE(NODE, SG_FR) \ + TAG_AS_ANSWER_INVALID_NODE(NODE); \ + TrNode_next(NODE) = SgFr_invalid_chain(SG_FR); \ + SgFr_invalid_chain(SG_FR) = NODE +#endif /* INCLUDE_ANSWER_SEARCH_MODE_DIRECTED */ + + + +/************************************************************************ +** subgoal_trie_check_insert_(gt)_entry ** +************************************************************************/ + +#ifdef INCLUDE_SUBGOAL_TRIE_CHECK_INSERT +#ifndef SUBGOAL_TRIE_LOCK_AT_WRITE_LEVEL /* SUBGOAL_TRIE_LOCK_AT_ENTRY_LEVEL || SUBGOAL_TRIE_LOCK_AT_NODE_LEVEL || ! YAPOR */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline sg_node_ptr subgoal_trie_check_insert_gt_entry(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t USES_REGS) { +#else +static inline sg_node_ptr subgoal_trie_check_insert_entry(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + sg_node_ptr child_node; + + LOCK_SUBGOAL_NODE(parent_node); + child_node = TrNode_child(parent_node); + if (child_node == NULL) { + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); + TrNode_child(parent_node) = child_node; + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + + if (! IS_SUBGOAL_TRIE_HASH(child_node)) { + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) { + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + sg_hash_ptr hash; + sg_node_ptr chain_node, next_node, *bucket; + new_subgoal_trie_hash(hash, count_nodes, tab_ent); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (sg_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + + { /* trie nodes with hashing */ + sg_hash_ptr hash; + sg_node_ptr *bucket; + int count_nodes = 0; + hash = (sg_hash_ptr) child_node; + bucket = Hash_buckets(hash) + HASH_ENTRY(t, Hash_num_buckets(hash)); + child_node = *bucket; + while (child_node) { + if (TrNode_entry(child_node) == t) { + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket); + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + sg_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + int num_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } +} +#else /* SUBGOAL_TRIE_LOCK_AT_WRITE_LEVEL */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline sg_node_ptr subgoal_trie_check_insert_gt_entry(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t USES_REGS) { +#else +static inline sg_node_ptr subgoal_trie_check_insert_entry(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + sg_node_ptr child_node; + sg_hash_ptr hash; + + child_node = TrNode_child(parent_node); + if (child_node == NULL) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_SUBGOAL_NODE(parent_node); + if (TrNode_child(parent_node)) { + sg_node_ptr chain_node = TrNode_child(parent_node); + if (IS_SUBGOAL_TRIE_HASH(chain_node)) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + hash = (sg_hash_ptr) chain_node; + goto subgoal_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + return chain_node; + } + chain_node = TrNode_next(chain_node); + } while (chain_node); +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + } + TrNode_child(parent_node) = child_node; + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + + if (! IS_SUBGOAL_TRIE_HASH(child_node)) { + sg_node_ptr first_node = child_node; + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_SUBGOAL_NODE(parent_node); + if (first_node != TrNode_child(parent_node)) { + sg_node_ptr chain_node = TrNode_child(parent_node); + if (IS_SUBGOAL_TRIE_HASH(chain_node)) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + hash = (sg_hash_ptr) chain_node; + goto subgoal_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + } + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + sg_node_ptr chain_node, next_node, *bucket; + new_subgoal_trie_hash(hash, count_nodes, tab_ent); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (sg_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } + + hash = (sg_hash_ptr) child_node; +subgoal_trie_hash: + { /* trie nodes with hashing */ + sg_node_ptr *bucket, first_node; + int num_buckets, count_nodes = 0; + + do { + num_buckets = Hash_num_buckets(hash); + // __sync_synchronize(); + bucket = Hash_buckets(hash) + HASH_ENTRY(t, num_buckets); + first_node = child_node = *bucket; + } while (num_buckets != Hash_num_buckets(hash)); + while (child_node) { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_SUBGOAL_NODE(parent_node); + if (num_buckets != Hash_num_buckets(hash)) { + /* the hash has been expanded */ +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + goto subgoal_trie_hash; + } + if (first_node != *bucket) { + sg_node_ptr chain_node = *bucket; + do { + if (TrNode_entry(chain_node) == t) { +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + FREE_SUBGOAL_TRIE_NODE(child_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_SUBGOAL_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef SUBGOAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = *bucket; +#else + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket); + } else { + NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* SUBGOAL_TRIE_ALLOC_BEFORE_CHECK */ + } + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + sg_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_SUBGOAL_NODE(parent_node); + return child_node; + } +} +#endif /* SUBGOAL_TRIE_LOCK_LEVEL */ +#endif /* INCLUDE_SUBGOAL_TRIE_CHECK_INSERT */ + + + +/************************************************************************ +** answer_trie_check_insert_(gt)_entry ** +************************************************************************/ + +#ifdef INCLUDE_ANSWER_TRIE_CHECK_INSERT +#ifndef ANSWER_TRIE_LOCK_AT_WRITE_LEVEL /* ANSWER_TRIE_LOCK_AT_ENTRY_LEVEL || ANSWER_TRIE_LOCK_AT_NODE_LEVEL || ! YAPOR */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline ans_node_ptr answer_trie_check_insert_gt_entry(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr USES_REGS) { +#else +static inline ans_node_ptr answer_trie_check_insert_entry(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + ans_node_ptr child_node; + + TABLING_ERROR_CHECKING(answer_trie_check_insert_(gt)_entry, IS_ANSWER_LEAF_NODE(parent_node)); + LOCK_ANSWER_NODE(parent_node); + child_node = TrNode_child(parent_node); + if (child_node == NULL) { + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL); + TrNode_child(parent_node) = child_node; + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + + if (! IS_ANSWER_TRIE_HASH(child_node)) { + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) { + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node)); + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + ans_hash_ptr hash; + ans_node_ptr chain_node, next_node, *bucket; + new_answer_trie_hash(hash, count_nodes, sg_fr); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (ans_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + + { /* trie nodes with hashing */ + ans_hash_ptr hash; + ans_node_ptr *bucket; + int count_nodes = 0; + hash = (ans_hash_ptr) child_node; + bucket = Hash_buckets(hash) + HASH_ENTRY(t, Hash_num_buckets(hash)); + child_node = *bucket; + while (child_node) { + if (TrNode_entry(child_node) == t) { + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, *bucket); + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + ans_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + int num_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } +} +#else /* ANSWER_TRIE_LOCK_AT_WRITE_LEVEL */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline ans_node_ptr answer_trie_check_insert_gt_entry(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr USES_REGS) { +#else +static inline ans_node_ptr answer_trie_check_insert_entry(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + ans_node_ptr child_node; + ans_hash_ptr hash; + + TABLING_ERROR_CHECKING(answer_trie_check_insert_(gt)_entry, IS_ANSWER_LEAF_NODE(parent_node)); + child_node = TrNode_child(parent_node); + if (child_node == NULL) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_ANSWER_NODE(parent_node); + if (TrNode_child(parent_node)) { + ans_node_ptr chain_node = TrNode_child(parent_node); + if (IS_ANSWER_TRIE_HASH(chain_node)) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + hash = (ans_hash_ptr) chain_node; + goto answer_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + return chain_node; + } + chain_node = TrNode_next(chain_node); + } while (chain_node); +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + } + TrNode_child(parent_node) = child_node; + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + + if (! IS_ANSWER_TRIE_HASH(child_node)) { + ans_node_ptr first_node = child_node; + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_ANSWER_NODE(parent_node); + if (first_node != TrNode_child(parent_node)) { + ans_node_ptr chain_node = TrNode_child(parent_node); + if (IS_ANSWER_TRIE_HASH(chain_node)) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + hash = (ans_hash_ptr) chain_node; + goto answer_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + } + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + ans_node_ptr chain_node, next_node, *bucket; + new_answer_trie_hash(hash, count_nodes, sg_fr); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (ans_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } + + hash = (ans_hash_ptr) child_node; +answer_trie_hash: + { /* trie nodes with hashing */ + ans_node_ptr *bucket, first_node; + int num_buckets, count_nodes = 0; + + do { + num_buckets = Hash_num_buckets(hash); + // __sync_synchronize(); + bucket = Hash_buckets(hash) + HASH_ENTRY(t, num_buckets); + first_node = child_node = *bucket; + } while (num_buckets != Hash_num_buckets(hash)); + while (child_node) { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_ANSWER_NODE(parent_node); + if (num_buckets != Hash_num_buckets(hash)) { + /* the hash has been expanded */ +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + goto answer_trie_hash; + } + if (first_node != *bucket) { + ans_node_ptr chain_node = *bucket; + do { + if (TrNode_entry(chain_node) == t) { +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + FREE_ANSWER_TRIE_NODE(child_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_ANSWER_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef ANSWER_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = *bucket; +#else + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, *bucket); + } else { + NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node); +#endif /* ANSWER_TRIE_ALLOC_BEFORE_CHECK */ + } + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + ans_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_ANSWER_NODE(parent_node); + return child_node; + } +} +#endif /* ANSWER_TRIE_LOCK_LEVEL */ +#endif /* INCLUDE_ANSWER_TRIE_CHECK_INSERT */ + + + +/************************************************************************ +** global_trie_check_insert_(gt)_entry ** +************************************************************************/ + +#ifdef INCLUDE_GLOBAL_TRIE_CHECK_INSERT +#ifndef GLOBAL_TRIE_LOCK_AT_WRITE_LEVEL /* GLOBAL_TRIE_LOCK_AT_NODE_LEVEL || ! YAPOR */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline gt_node_ptr global_trie_check_insert_gt_entry(gt_node_ptr parent_node, Term t USES_REGS) { +#else +static inline gt_node_ptr global_trie_check_insert_entry(gt_node_ptr parent_node, Term t USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + gt_node_ptr child_node; + + LOCK_GLOBAL_NODE(parent_node); + child_node = TrNode_child(parent_node); + if (child_node == NULL) { + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); + TrNode_child(parent_node) = child_node; + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + + if (! IS_GLOBAL_TRIE_HASH(child_node)) { + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) { + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + gt_hash_ptr hash; + gt_node_ptr chain_node, next_node, *bucket; + new_global_trie_hash(hash, count_nodes); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (gt_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + + { /* trie nodes with hashing */ + gt_hash_ptr hash; + gt_node_ptr *bucket; + int count_nodes = 0; + hash = (gt_hash_ptr) child_node; + bucket = Hash_buckets(hash) + HASH_ENTRY(t, Hash_num_buckets(hash)); + child_node = *bucket; + while (child_node) { + if (TrNode_entry(child_node) == t) { + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + count_nodes++; + child_node = TrNode_next(child_node); + } + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket); + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + gt_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + int num_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } +} +#else /* GLOBAL_TRIE_LOCK_AT_WRITE_LEVEL */ +#ifdef MODE_GLOBAL_TRIE_ENTRY +static inline gt_node_ptr global_trie_check_insert_gt_entry(gt_node_ptr parent_node, Term t USES_REGS) { +#else +static inline gt_node_ptr global_trie_check_insert_entry(gt_node_ptr parent_node, Term t USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_ENTRY */ + gt_node_ptr child_node; + gt_hash_ptr hash; + + child_node = TrNode_child(parent_node); + if (child_node == NULL) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_GLOBAL_NODE(parent_node); + if (TrNode_child(parent_node)) { + gt_node_ptr chain_node = TrNode_child(parent_node); + if (IS_GLOBAL_TRIE_HASH(chain_node)) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + hash = (gt_hash_ptr) chain_node; + goto global_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + return chain_node; + } + chain_node = TrNode_next(chain_node); + } while (chain_node); +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + } + TrNode_child(parent_node) = child_node; + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + + if (! IS_GLOBAL_TRIE_HASH(child_node)) { + gt_node_ptr first_node = child_node; + int count_nodes = 0; + do { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } while (child_node); +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_GLOBAL_NODE(parent_node); + if (first_node != TrNode_child(parent_node)) { + gt_node_ptr chain_node = TrNode_child(parent_node); + if (IS_GLOBAL_TRIE_HASH(chain_node)) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + hash = (gt_hash_ptr) chain_node; + goto global_trie_hash; + } + do { + if (TrNode_entry(chain_node) == t) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = TrNode_child(parent_node); +#else + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node)); + } else { + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + } + count_nodes++; + if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) { + /* alloc a new hash */ + gt_node_ptr chain_node, next_node, *bucket; + new_global_trie_hash(hash, count_nodes); + chain_node = child_node; + do { + bucket = Hash_buckets(hash) + HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + TrNode_child(parent_node) = (gt_node_ptr) hash; + } else { + TrNode_child(parent_node) = child_node; + } + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } + + hash = (gt_hash_ptr) child_node; +global_trie_hash: + { /* trie nodes with hashing */ + gt_node_ptr *bucket, first_node; + int num_buckets, count_nodes = 0; + + do { + num_buckets = Hash_num_buckets(hash); + // __sync_synchronize(); + bucket = Hash_buckets(hash) + HASH_ENTRY(t, num_buckets); + first_node = child_node = *bucket; + } while (num_buckets != Hash_num_buckets(hash)); + while (child_node) { + if (TrNode_entry(child_node) == t) + return child_node; + count_nodes++; + child_node = TrNode_next(child_node); + } +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + LOCK_GLOBAL_NODE(parent_node); + if (num_buckets != Hash_num_buckets(hash)) { + /* the hash has been expanded */ +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + goto global_trie_hash; + } + if (first_node != *bucket) { + gt_node_ptr chain_node = *bucket; + do { + if (TrNode_entry(chain_node) == t) { +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + FREE_GLOBAL_TRIE_NODE(child_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + UNLOCK_GLOBAL_NODE(parent_node); + return chain_node; + } + count_nodes++; + chain_node = TrNode_next(chain_node); + } while (chain_node != first_node); +#ifdef GLOBAL_TRIE_ALLOC_BEFORE_CHECK + TrNode_next(child_node) = *bucket; +#else + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket); + } else { + NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node); +#endif /* GLOBAL_TRIE_ALLOC_BEFORE_CHECK */ + } + *bucket = child_node; + Hash_num_nodes(hash)++; + count_nodes++; + if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) { + /* expand current hash */ + gt_node_ptr chain_node, next_node, *old_bucket, *old_hash_buckets, *new_hash_buckets; + num_buckets = Hash_num_buckets(hash) * 2; + ALLOC_BUCKETS(new_hash_buckets, num_buckets); + old_hash_buckets = Hash_buckets(hash); + old_bucket = old_hash_buckets + Hash_num_buckets(hash); + do { + if (*--old_bucket) { + chain_node = *old_bucket; + do { + bucket = new_hash_buckets + HASH_ENTRY(TrNode_entry(chain_node), num_buckets); + next_node = TrNode_next(chain_node); + TrNode_next(chain_node) = *bucket; + *bucket = chain_node; + chain_node = next_node; + } while (chain_node); + } + } while (old_bucket != old_hash_buckets); + Hash_buckets(hash) = new_hash_buckets; + Hash_num_buckets(hash) = num_buckets; + FREE_BUCKETS(old_hash_buckets); + } + UNLOCK_GLOBAL_NODE(parent_node); + return child_node; + } +} +#endif /* GLOBAL_TRIE_LOCK_LEVEL */ +#endif /* INCLUDE_GLOBAL_TRIE_CHECK_INSERT */ + + + +/************************************************************************ +** subgoal_search(_global_trie)(_terms)_loop ** +************************************************************************/ + +#ifdef INCLUDE_SUBGOAL_SEARCH_LOOP +#ifdef MODE_GLOBAL_TRIE_LOOP +#ifdef GLOBAL_TRIE_FOR_SUBTERMS +static inline gt_node_ptr subgoal_search_global_trie_terms_loop(Term t, int *subs_arity_ptr, CELL **stack_vars_ptr, CELL *stack_terms USES_REGS) { +#else +static inline gt_node_ptr subgoal_search_global_trie_loop(Term t, int *subs_arity_ptr, CELL **stack_vars_ptr USES_REGS) { +#endif /* GLOBAL_TRIE_FOR_SUBTERMS */ +#else +#ifdef MODE_TERMS_LOOP +static inline sg_node_ptr subgoal_search_terms_loop(tab_ent_ptr tab_ent, sg_node_ptr current_node, Term t, int *subs_arity_ptr, CELL **stack_vars_ptr USES_REGS) { +#else +static inline sg_node_ptr subgoal_search_loop(tab_ent_ptr tab_ent, sg_node_ptr current_node, Term t, int *subs_arity_ptr, CELL **stack_vars_ptr USES_REGS) { +#endif /* MODE_TERMS_LOOP */ +#endif /* MODE_GLOBAL_TRIE_LOOP */ +/************************************************************************ + =========== + | | + | ... | + | | + ----------- + | VAR_N | <-- stack_vars + ----------- * + | ... | /|\ + ----------- | subs_arity (N+1) + | VAR_0 | \|/ + ----------- * + YENV --> | | + ----------- + | | + | ... | + | | + =========== + | | + | ... | + | | + ----------- + TR --> | | <-- stack_terms_limit + ----------- + | | + | ... | + | | + ----------| + | TERM_N | <-- stack_terms + ----------| * + | ... | /|\ + ----------| | + | TERM_1 | | + ----------| | + | NULL | \|/ + =========== * + LOCAL_TrailTop --> | | + ----------- +************************************************************************/ +#ifdef MODE_GLOBAL_TRIE_LOOP + gt_node_ptr current_node = GLOBAL_root_gt; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + int subs_arity = *subs_arity_ptr; + CELL *stack_vars = *stack_vars_ptr; +#if ! defined(MODE_GLOBAL_TRIE_LOOP) || ! defined(GLOBAL_TRIE_FOR_SUBTERMS) + CELL *stack_terms = (CELL *) LOCAL_TrailTop; +#endif /* ! MODE_GLOBAL_TRIE_LOOP || ! GLOBAL_TRIE_FOR_SUBTERMS */ + CELL *stack_terms_limit = (CELL *) TR; + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1); /* + 1 because initially we stiil haven't done any STACK_POP_DOWN */ + STACK_PUSH_UP(NULL, stack_terms); + +#if defined(MODE_GLOBAL_TRIE_LOOP) + /* for the global trie, it is safe to skip the IsVarTerm() and IsAtomOrIntTerm() tests in the first iteration */ + goto subgoal_search_loop_non_atomic; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + +#ifdef TRIE_RATIONAL_TERMS + /* Needed structures, variables to support rational terms */ + term_array Ts; + void* CyclicTerm; + term_array_init(&Ts, 10); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + + do { + if (IsVarTerm(t)) { + if (IsTableVarTerm(t)) { + t = MakeTableVarTerm(VarIndexOfTerm(t)); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, t); + } else { + if (subs_arity == MAX_TABLE_VARS) + Yap_Error(INTERNAL_ERROR, TermNil, "subgoal_search_loop: MAX_TABLE_VARS exceeded"); + STACK_PUSH_UP(t, stack_vars); + *((CELL *)t) = GLOBAL_table_var_enumerator(subs_arity); + t = MakeTableVarTerm(subs_arity); + subs_arity = subs_arity + 1; + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, t); + } + } else if (IsAtomOrIntTerm(t)) { + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, t); +#ifdef MODE_TERMS_LOOP + } else { + gt_node_ptr entry_node; +#ifdef GLOBAL_TRIE_FOR_SUBTERMS + entry_node = subgoal_search_global_trie_terms_loop(t, &subs_arity, &stack_vars, stack_terms PASS_REGS); +#else + entry_node = subgoal_search_global_trie_loop(t, &subs_arity, &stack_vars PASS_REGS); +#endif /* GLOBAL_TRIE_FOR_SUBTERMS */ + current_node = subgoal_trie_check_insert_gt_entry(tab_ent, current_node, (Term) entry_node PASS_REGS); +#else /* ! MODE_TERMS_LOOP */ + } else +#ifdef TRIE_RATIONAL_TERMS + if (IsRationalTerm(t)) { + t = STACK_POP_DOWN(stack_terms); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, t); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ +#if defined(MODE_GLOBAL_TRIE_LOOP) + /* for the global trie, it is safe to start here in the first iteration */ + subgoal_search_loop_non_atomic: +#endif /* MODE_GLOBAL_TRIE_LOOP */ +#ifdef TRIE_COMPACT_PAIRS + if (IsPairTerm(t)) { +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + CELL *aux_pair = RepPair(t); + if (aux_pair == PairTermMark) { + t = STACK_POP_DOWN(stack_terms); +#ifdef TRIE_RATIONAL_TERMS + if (IsPairTerm(t) && ! IsRationalTerm(t)) { + term_array_push(&Ts, (void *) t, (void *) current_node); +#else + if (IsPairTerm(t)) { +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + aux_pair = RepPair(t); + t = Deref(aux_pair[1]); +#ifdef TRIE_RATIONAL_TERMS + if (IsVarTerm(aux_pair[1]) || IsPairTerm(aux_pair[1])) { + CyclicTerm = term_array_member(Ts, (void *) t); + } + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + if (t == TermNil) { + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, CompactPairEndList); + } else { + /* AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 2); */ + /* AUX_STACK_CHECK_EXPAND is not necessary here because the situation of pushing ** + ** up 3 terms has already initially checked for the CompactPairInit term */ + STACK_PUSH_UP(t, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + } +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_pair[0]) || IsPairTerm(aux_pair[0])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_pair[0])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); + } else { + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, CompactPairEndTerm); + STACK_PUSH_UP(t, stack_terms); + } +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + } else if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = subgoal_search_global_trie_terms_loop(t, &subs_arity, &stack_vars, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ + } else { +#ifdef TRIE_RATIONAL_TERMS + term_array_push(&Ts, (void *) t, (void *) current_node); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, CompactPairInit); + t = Deref(aux_pair[1]); +#ifdef TRIE_RATIONAL_TERMS + if (IsVarTerm(aux_pair[1]) || IsPairTerm(aux_pair[1])) { + CyclicTerm = term_array_member(Ts, (void *) t); + } + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + if (t == TermNil) { + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, CompactPairEndList); + } else { + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 2); + STACK_PUSH_UP(t, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + } +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_pair[0]) || IsPairTerm(aux_pair[0])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_pair[0])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); + } +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + } else if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = subgoal_search_global_trie_terms_loop(t, &subs_arity, &stack_vars, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ +#else /* ! TRIE_COMPACT_PAIRS */ +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = subgoal_search_global_trie_terms_loop(t, &subs_arity, &stack_vars, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); + } else +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ + if (IsPairTerm(t)) { + CELL *aux_pair = RepPair(t); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsPair(NULL)); + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1); + STACK_PUSH_UP(Deref(aux_pair[1]), stack_terms); + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); +#endif /* TRIE_COMPACT_PAIRS */ + } else if (IsApplTerm(t)) { + Functor f = FunctorOfTerm(t); + if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.dbl = FloatOfTerm(t); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, u.t_dbl[1]); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, u.t_dbl[0]); +#ifdef MODE_GLOBAL_TRIE_LOOP + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); +#endif /* MODE_GLOBAL_TRIE_LOOP */ + } else if (f == FunctorLongInt) { + Int li = LongIntOfTerm(t); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, li); +#ifdef MODE_GLOBAL_TRIE_LOOP + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); +#endif /* MODE_GLOBAL_TRIE_LOOP */ + } else if (f == FunctorBigInt || f == FunctorString) { + CELL *new = Yap_HeapStoreOpaqueTerm(t); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, (CELL)new); +#ifdef MODE_GLOBAL_TRIE_LOOP + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); +#endif /* MODE_GLOBAL_TRIE_LOOP */ + } else if (f == FunctorDBRef) { + Yap_Error(INTERNAL_ERROR, TermNil, "subgoal_search_loop: unsupported type tag FunctorDBRef"); + } else { +#ifdef TRIE_RATIONAL_TERMS + term_array_push(&Ts, (void *) t, (void *) current_node); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + int i; + CELL *aux_appl = RepAppl(t); + SUBGOAL_CHECK_INSERT_ENTRY(tab_ent, current_node, AbsAppl((Term *)f)); + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + ArityOfFunctor(f) - 1); + for (i = ArityOfFunctor(f); i >= 1; i--) { +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_appl[i]) || IsApplTerm(aux_appl[i])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_appl[i])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_appl[i]), stack_terms); + } + } + } else { + Yap_Error(INTERNAL_ERROR, TermNil, "subgoal_search_loop: unknown type tag"); +#endif /* MODE_TERMS_LOOP */ + } + t = STACK_POP_DOWN(stack_terms); + } while (t); +#ifdef TRIE_RATIONAL_TERMS + term_array_free(&Ts); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + *subs_arity_ptr = subs_arity; + *stack_vars_ptr = stack_vars; + return current_node; +} +#endif /* INCLUDE_SUBGOAL_SEARCH_LOOP */ + + + +/************************************************************************ +** answer_search(_global_trie)(_terms)_loop ** +************************************************************************/ + +#ifdef INCLUDE_ANSWER_SEARCH_LOOP +#ifdef MODE_GLOBAL_TRIE_LOOP +#ifdef GLOBAL_TRIE_FOR_SUBTERMS +static inline gt_node_ptr answer_search_global_trie_terms_loop(Term t, int *vars_arity_ptr, CELL *stack_terms USES_REGS) { +#else +static inline gt_node_ptr answer_search_global_trie_loop(Term t, int *vars_arity_ptr USES_REGS) { +#endif /* GLOBAL_TRIE_FOR_SUBTERMS */ +#else +#ifdef MODE_TERMS_LOOP +static inline ans_node_ptr answer_search_terms_loop(sg_fr_ptr sg_fr, ans_node_ptr current_node, Term t, int *vars_arity_ptr USES_REGS) { +#else +static inline ans_node_ptr answer_search_loop(sg_fr_ptr sg_fr, ans_node_ptr current_node, Term t, int *vars_arity_ptr USES_REGS) { +#endif /* MODE_TERMS_LOOP */ +#endif /* MODE_GLOBAL_TRIE_LOOP */ +/************************************************************************ + =========== + | | + | ... | + | | + ----------- + TR --> | VAR_0 | <-- stack_vars_base + ----------- * + | ... | /|\ + ----------- | vars_arity (N+1) + | VAR_N | \|/ + ----------- * + | | <-- stack_terms_limit + ----------- + | | + | ... | + | | + ----------| + | TERM_N | <-- stack_terms + ----------| * + | ... | /|\ + ----------| | + | TERM_1 | | + ----------| | + | NULL | \|/ + =========== * + LOCAL_TrailTop --> | | + ----------- +************************************************************************/ +#ifdef MODE_GLOBAL_TRIE_LOOP + gt_node_ptr current_node = GLOBAL_root_gt; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + int vars_arity = *vars_arity_ptr; +#if ! defined(MODE_GLOBAL_TRIE_LOOP) || ! defined(GLOBAL_TRIE_FOR_SUBTERMS) + CELL *stack_terms = (CELL *) LOCAL_TrailTop; +#endif /* ! MODE_GLOBAL_TRIE_LOOP || ! GLOBAL_TRIE_FOR_SUBTERMS */ + CELL *stack_vars_base = (CELL *) TR; +#define stack_terms_limit (stack_vars_base + vars_arity) +#ifdef TRIE_COMPACT_PAIRS + int in_pair = 0; +#else +#define in_pair 0 +#endif /* TRIE_COMPACT_PAIRS */ + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1); /* + 1 because initially we stiil haven't done any STACK_POP_DOWN */ + STACK_PUSH_UP(NULL, stack_terms); + +#if defined(MODE_GLOBAL_TRIE_LOOP) + /* for the global trie, it is safe to skip the IsVarTerm() and IsAtomOrIntTerm() tests in the first iteration */ + goto answer_search_loop_non_atomic; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + +#ifdef TRIE_RATIONAL_TERMS + term_array Ts; + void* CyclicTerm; + term_array_init(&Ts, 10); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + + do { + if (IsVarTerm(t)) { + t = Deref(t); + if (IsTableVarTerm(t)) { + t = MakeTableVarTerm(VarIndexOfTerm(t)); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, t, _trie_retry_val + in_pair); + } else { + if (vars_arity == MAX_TABLE_VARS) + Yap_Error(INTERNAL_ERROR, TermNil, "answer_search_loop: MAX_TABLE_VARS exceeded"); + stack_vars_base[vars_arity] = t; + *((CELL *)t) = GLOBAL_table_var_enumerator(vars_arity); + t = MakeTableVarTerm(vars_arity); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, t, _trie_retry_var + in_pair); + vars_arity = vars_arity + 1; + } +#ifdef TRIE_COMPACT_PAIRS + in_pair = 0; +#endif /* TRIE_COMPACT_PAIRS */ + } else if (IsAtomOrIntTerm(t)) { + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, t, _trie_retry_atom + in_pair); +#ifdef TRIE_COMPACT_PAIRS + in_pair = 0; +#endif /* TRIE_COMPACT_PAIRS */ +#ifdef MODE_TERMS_LOOP + } else { + gt_node_ptr entry_node; +#ifdef GLOBAL_TRIE_FOR_SUBTERMS + entry_node = answer_search_global_trie_terms_loop(t, &vars_arity, stack_terms PASS_REGS); +#else + entry_node = answer_search_global_trie_loop(t, &vars_arity PASS_REGS); +#endif /* GLOBAL_TRIE_FOR_SUBTERMS */ + current_node = answer_trie_check_insert_gt_entry(sg_fr, current_node, (Term) entry_node, _trie_retry_gterm + in_pair PASS_REGS); +#else /* ! MODE_TERMS_LOOP */ + } else +#ifdef TRIE_RATIONAL_TERMS + if (IsRationalTerm(t)) { + t = STACK_POP_DOWN(stack_terms); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, t, _trie_retry_var + in_pair); //TODO create _trie_.._rational + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ +#if defined(MODE_GLOBAL_TRIE_LOOP) + /* for the global trie, it is safe to start here in the first iteration */ + answer_search_loop_non_atomic: +#endif /* MODE_GLOBAL_TRIE_LOOP */ +#ifdef TRIE_COMPACT_PAIRS + if (IsPairTerm(t)) { +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + CELL *aux_pair = RepPair(t); + if (aux_pair == PairTermMark) { + t = STACK_POP_DOWN(stack_terms); +#ifdef TRIE_RATIONAL_TERMS + if (IsPairTerm(t) && ! IsRationalTerm(t)) { + term_array_push(&Ts, (void *) t, (void *) current_node); +#else + if (IsPairTerm(t)) { +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + aux_pair = RepPair(t); + t = Deref(aux_pair[1]); +#ifdef TRIE_RATIONAL_TERMS + if (IsVarTerm(aux_pair[1]) || IsPairTerm(aux_pair[1])) { + CyclicTerm = term_array_member(Ts, (void *) t); + } + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); // CyclicTerm + STACK_PUSH_UP((Term) RationalMark, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + in_pair = 4; + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + if (t == TermNil) { + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, CompactPairEndList, _trie_retry_pair); + } else { + /* AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 2); */ + /* AUX_STACK_CHECK_EXPAND is not necessary here because the situation of pushing ** + ** up 3 terms has already initially checked for the CompactPairInit term */ + STACK_PUSH_UP(t, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + in_pair = 4; + } +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_pair[0]) || IsPairTerm(aux_pair[0])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_pair[0])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); + } else { + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, CompactPairEndTerm, _trie_retry_null); + STACK_PUSH_UP(t, stack_terms); + } +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + } else if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = answer_search_global_trie_terms_loop(t, &vars_arity, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ + } else { +#ifdef TRIE_RATIONAL_TERMS + term_array_push(&Ts, (void *) t, (void *) current_node); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, CompactPairInit, _trie_retry_null + in_pair); + t = Deref(aux_pair[1]); +#ifdef TRIE_RATIONAL_TERMS + if (IsVarTerm(aux_pair[1]) || IsPairTerm(aux_pair[1])) { + CyclicTerm = term_array_member(Ts, (void *) t); + } + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + in_pair = 4; + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + if (t == TermNil) { + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, CompactPairEndList, _trie_retry_pair); + in_pair = 0; + } else { + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 2); + STACK_PUSH_UP(t, stack_terms); + STACK_PUSH_UP(AbsPair(PairTermMark), stack_terms); + in_pair = 4; + } +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_pair[0]) || IsPairTerm(aux_pair[0])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_pair[0])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); + } +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + } else if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = answer_search_global_trie_terms_loop(t, &vars_arity, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ +#else /* ! TRIE_COMPACT_PAIRS */ +#if defined(MODE_GLOBAL_TRIE_LOOP) && defined(GLOBAL_TRIE_FOR_SUBTERMS) + if (current_node != GLOBAL_root_gt) { + gt_node_ptr entry_node = answer_search_global_trie_terms_loop(t, &vars_arity, stack_terms PASS_REGS); + current_node = global_trie_check_insert_gt_entry(current_node, (Term) entry_node PASS_REGS); + } else +#endif /* MODE_GLOBAL_TRIE_LOOP && GLOBAL_TRIE_FOR_SUBTERMS */ + if (IsPairTerm(t)) { + CELL *aux_pair = RepPair(t); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsPair(NULL), _trie_retry_pair); + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1); + STACK_PUSH_UP(Deref(aux_pair[1]), stack_terms); + STACK_PUSH_UP(Deref(aux_pair[0]), stack_terms); +#endif /* TRIE_COMPACT_PAIRS */ + } else if (IsApplTerm(t)) { + Functor f = FunctorOfTerm(t); + if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.dbl = FloatOfTerm(t); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_null + in_pair); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, u.t_dbl[1], _trie_retry_extension); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, u.t_dbl[0], _trie_retry_extension); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_double); + } else if (f == FunctorLongInt) { + Int li = LongIntOfTerm (t); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_null + in_pair); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, li, _trie_retry_extension); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_longint); + } else if (f == FunctorBigInt || FunctorString) { + CELL *opq = Yap_HeapStoreOpaqueTerm(t); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_null + in_pair); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, (CELL)opq, _trie_retry_extension); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_bigint); + } else if (f == FunctorDBRef) { + Yap_Error(INTERNAL_ERROR, TermNil, "answer_search_loop: unsupported type tag FunctorDBRef"); + } else { +#ifdef TRIE_RATIONAL_TERMS + term_array_push(&Ts, (void *) t, (void *) current_node); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + int i; + CELL *aux_appl = RepAppl(t); + ANSWER_CHECK_INSERT_ENTRY(sg_fr, current_node, AbsAppl((Term *)f), _trie_retry_appl + in_pair); + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + ArityOfFunctor(f) - 1); + for (i = ArityOfFunctor(f); i >= 1; i--) { +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = NULL; + if (IsVarTerm(aux_appl[i]) || IsApplTerm(aux_appl[i])) + CyclicTerm = term_array_member(Ts, (void *) Deref(aux_appl[i])); + if (CyclicTerm != NULL) { + STACK_PUSH_UP((Term) CyclicTerm, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(Deref(aux_appl[i]), stack_terms); + } + } +#ifdef TRIE_COMPACT_PAIRS + in_pair = 0; +#endif /* TRIE_COMPACT_PAIRS */ + } else { + Yap_Error(INTERNAL_ERROR, TermNil, "answer_search_loop: unknown type tag"); +#endif /* MODE_TERMS_LOOP */ + } + t = STACK_POP_DOWN(stack_terms); + } while (t); +#ifdef TRIE_RATIONAL_TERMS + term_array_free(&Ts); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + *vars_arity_ptr = vars_arity; + return current_node; + +#undef stack_terms_limit +#ifndef TRIE_COMPACT_PAIRS +#undef in_pair +#endif /* TRIE_COMPACT_PAIRS */ +} +#endif /* INCLUDE_ANSWER_SEARCH_LOOP */ + + + +/************************************************************** +** answer_search_min_max ** +**************************************************************/ + +#ifdef INCLUDE_ANSWER_SEARCH_MODE_DIRECTED +static inline ans_node_ptr answer_search_min_max(sg_fr_ptr sg_fr, ans_node_ptr current_node, Term t, int mode USES_REGS) { + ans_node_ptr child_node; + Term child_term; + Term trie_value = 0, term_value = t; + int cmp; + + /* start by computing the current value on the trie (trie_value) */ + child_node = TrNode_child(current_node); + child_term = TrNode_entry(child_node); + if (IsIntTerm(child_term)) { + trie_value = child_term; + } else if (IsApplTerm(child_term)) { + Functor f = (Functor) RepAppl(child_term); + child_node = TrNode_child(child_node); + if (f == FunctorLongInt) { + trie_value = MkLongIntTerm( (Int) TrNode_entry(child_node) ); + } else if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.t_dbl[0] = TrNode_entry(child_node); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + child_node = TrNode_child(child_node); + u.t_dbl[1] = TrNode_entry(child_node); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + trie_value = MkFloatTerm(u.dbl); + } else if (f == FunctorBigInt) { + trie_value = AbsAppl( (CELL *) TrNode_entry(child_node) ); + } else + Yap_Error(INTERNAL_ERROR, TermNil, "answer_search_min_max: invalid arithmetic value"); + child_node = TrNode_child(child_node); + } + + cmp = Yap_acmp( term_value, trie_value PASS_REGS); + /* worse answer */ + if ((mode == MODE_DIRECTED_MIN && cmp > 0) || (mode == MODE_DIRECTED_MAX && cmp < 0)) + return NULL; + /* equal answer */ + if (cmp == 0) + return child_node; + /* better answer */ + if (IsAtomOrIntTerm(t)) { + ANSWER_SAFE_INSERT_ENTRY(current_node, t, _trie_retry_atom); + } else if (IsApplTerm(t)) { + Functor f = FunctorOfTerm(t); + if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.dbl = FloatOfTerm(t); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + ANSWER_SAFE_INSERT_ENTRY(current_node, u.t_dbl[1], _trie_retry_extension); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + ANSWER_SAFE_INSERT_ENTRY(current_node, u.t_dbl[0], _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_double); + } else if (f == FunctorLongInt) { + Int li = LongIntOfTerm(t); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); + ANSWER_SAFE_INSERT_ENTRY(current_node, li, _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_longint); + } else if (f == FunctorBigInt) { + CELL *li = Yap_HeapStoreOpaqueTerm(t); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); + ANSWER_SAFE_INSERT_ENTRY(current_node, (CELL)li, _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_bigint); + } + } + return current_node; +} +#endif /* INCLUDE_ANSWER_SEARCH_MODE_DIRECTED */ + + + +/********************************************************** +** answer_search_sum ** +**********************************************************/ + +#ifdef INCLUDE_ANSWER_SEARCH_MODE_DIRECTED +static inline ans_node_ptr answer_search_sum(sg_fr_ptr sg_fr, ans_node_ptr current_node, Term t USES_REGS) { + ans_node_ptr child_node; + Term child_term; + Term trie_value = 0, term_value = t, sum_value = 0; + + /* start by computing the current value on the trie (trie_value) */ + child_node = TrNode_child(current_node); + child_term = TrNode_entry(child_node); + if (IsIntTerm(child_term)) { + trie_value = child_term; + } else if (IsApplTerm(child_term)) { + Functor f = (Functor) RepAppl(child_term); + child_node = TrNode_child(child_node); + if (f == FunctorLongInt) { + trie_value = MkLongIntTerm( (Int) TrNode_entry(child_node) ); + } else if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.t_dbl[0] = TrNode_entry(child_node); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + child_node = TrNode_child(child_node); + u.t_dbl[1] = TrNode_entry(child_node); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + trie_value = MkFloatTerm(u.dbl); + } else if (f == FunctorBigInt) { + trie_value = AbsAppl( (CELL *) TrNode_entry(child_node) ); + } else + Yap_Error(INTERNAL_ERROR, TermNil, "answer_search_min_max: invalid arithmetic value"); + child_node = TrNode_child(child_node); + } + + sum_value = p_plus(trie_value, term_value PASS_REGS); + if (IsAtomOrIntTerm(sum_value)) { + ANSWER_SAFE_INSERT_ENTRY(current_node, sum_value, _trie_retry_atom); + } else if (IsApplTerm(sum_value)) { + Functor f = FunctorOfTerm(sum_value); + if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + u.dbl = FloatOfTerm(sum_value); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + ANSWER_SAFE_INSERT_ENTRY(current_node, u.t_dbl[1], _trie_retry_extension); +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + ANSWER_SAFE_INSERT_ENTRY(current_node, u.t_dbl[0], _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_double); + } else if (f == FunctorLongInt) { + Int li = LongIntOfTerm(sum_value); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); + ANSWER_SAFE_INSERT_ENTRY(current_node, li, _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_longint); + } else if (f == FunctorBigInt) { + CELL *li = Yap_HeapStoreOpaqueTerm(sum_value); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_null); + ANSWER_SAFE_INSERT_ENTRY(current_node, (CELL)li, _trie_retry_extension); + ANSWER_SAFE_INSERT_ENTRY(current_node, AbsAppl((Term *)f), _trie_retry_bigint); + } + } + return current_node; +} +#endif /* INCLUDE_ANSWER_SEARCH_MODE_DIRECTED */ + + + +/*************************************************************** +** invalidate_answer_trie ** +***************************************************************/ + +#ifdef INCLUDE_ANSWER_SEARCH_MODE_DIRECTED +static void invalidate_answer_trie(ans_node_ptr current_node, sg_fr_ptr sg_fr, int position USES_REGS) { + if (IS_ANSWER_TRIE_HASH(current_node)) { + ans_hash_ptr hash; + ans_node_ptr *bucket, *last_bucket; + hash = (ans_hash_ptr) current_node; + bucket = Hash_buckets(hash); + last_bucket = bucket + Hash_num_buckets(hash); + do { + current_node = *bucket; + if (current_node) { + ans_node_ptr next_node = TrNode_next(current_node); + if (IS_ANSWER_LEAF_NODE(current_node)) { + INVALIDATE_ANSWER_TRIE_LEAF_NODE(current_node, sg_fr); + } else { + invalidate_answer_trie(TrNode_child(current_node), sg_fr, TRAVERSE_POSITION_FIRST PASS_REGS); + INVALIDATE_ANSWER_TRIE_NODE(current_node, sg_fr); + } + while (next_node) { + current_node = next_node; + next_node = TrNode_next(current_node); + invalidate_answer_trie(current_node, sg_fr, TRAVERSE_POSITION_NEXT PASS_REGS); + } + } + } while (++bucket != last_bucket); + if (Hash_next(hash)) + Hash_previous(Hash_next(hash)) = Hash_previous(hash); + if (Hash_previous(hash)) + Hash_next(Hash_previous(hash)) = Hash_next(hash); + else + SgFr_hash_chain(sg_fr) = Hash_next(hash); + FREE_BUCKETS(Hash_buckets(hash)); + FREE_ANSWER_TRIE_HASH(hash); + } else { + if (position == TRAVERSE_POSITION_FIRST) { + ans_node_ptr next_node = TrNode_next(current_node); + if (IS_ANSWER_LEAF_NODE(current_node)) { + INVALIDATE_ANSWER_TRIE_LEAF_NODE(current_node, sg_fr); + } else { + invalidate_answer_trie(TrNode_child(current_node), sg_fr, TRAVERSE_POSITION_FIRST PASS_REGS); + INVALIDATE_ANSWER_TRIE_NODE(current_node, sg_fr); + } + while (next_node) { + current_node = next_node; + next_node = TrNode_next(current_node); + invalidate_answer_trie(current_node, sg_fr, TRAVERSE_POSITION_NEXT PASS_REGS); + } + } else { + if (IS_ANSWER_LEAF_NODE(current_node)) { + INVALIDATE_ANSWER_TRIE_LEAF_NODE(current_node, sg_fr); + } else { + invalidate_answer_trie(TrNode_child(current_node), sg_fr, TRAVERSE_POSITION_FIRST PASS_REGS); + INVALIDATE_ANSWER_TRIE_NODE(current_node, sg_fr); + } + } + } + return; +} +#endif /* INCLUDE_ANSWER_SEARCH_MODE_DIRECTED */ + + + +/************************************************************************ +** load_(answer|substitution)_loop ** +************************************************************************/ + +#ifdef INCLUDE_LOAD_ANSWER_LOOP +#ifdef MODE_GLOBAL_TRIE_LOOP +static inline CELL *load_substitution_loop(gt_node_ptr current_node, int *vars_arity_ptr, CELL *stack_terms USES_REGS) { +#else +static inline CELL *load_answer_loop(ans_node_ptr current_node USES_REGS) { +#endif /* MODE_GLOBAL_TRIE_LOOP */ +/************************************************************************ + =========== + | | + | ... | + | | + ----------- + TR --> | VAR_0 | <-- stack_vars_base + ----------- * + | ... | /|\ + ----------- | vars_arity (N+1) + | VAR_N | \|/ + ----------- * + | | <-- stack_terms_limit + ----------- + | | + | ... | + | | + ----------| + | TERM_N | <-- stack_terms + ----------| * + | ... | /|\ + ----------| | stack_terms_pair_offset (TRIE_COMPACT_PAIRS) + | TERM_1 | \|/ + =========== * + LOCAL_TrailTop --> | | <-- stack_terms_base (TRIE_COMPACT_PAIRS) + ----------- +************************************************************************/ +#ifdef MODE_GLOBAL_TRIE_LOOP + int vars_arity = *vars_arity_ptr; +#else + int vars_arity = 0; + CELL *stack_terms = (CELL *) LOCAL_TrailTop; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + CELL *stack_vars_base = (CELL *) TR; +#define stack_terms_limit (stack_vars_base + vars_arity) +#ifdef TRIE_COMPACT_PAIRS +#define stack_terms_base ((CELL *) LOCAL_TrailTop) + int stack_terms_pair_offset = 0; +#endif /* TRIE_COMPACT_PAIRS */ + Term t = TrNode_entry(current_node); +#ifdef MODE_GLOBAL_TRIE_LOOP + current_node = TrNode_parent(current_node); +#else + current_node = (ans_node_ptr) UNTAG_ANSWER_NODE(TrNode_parent(current_node)); +#endif /* MODE_GLOBAL_TRIE_LOOP */ + +#ifdef TRIE_RATIONAL_TERMS + term_array Ts; + void* CyclicTerm; + term_array_init(&Ts, 10); + Term RationalTermTMP; // a temporary temp to be used from the rational code +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + + do { +#ifdef TRIE_RATIONAL_TERMS + CyclicTerm = term_array_member(Ts, (void *) current_node); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + if (IsVarTerm(t)) { +#ifdef TRIE_RATIONAL_TERMS + if (t > VarIndexOfTableTerm(MAX_TABLE_VARS) && TrNode_child((gt_node_ptr) t) != (gt_node_ptr)(1)) { //TODO: substitute the != 1 test to something more appropriate + /* Rational term */ + RationalTermTMP = (Term) term_array_member(Ts, (void *) t); + if (RationalTermTMP) { + /* rational term is assigned a variable already */ + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit); + STACK_PUSH_UP(RationalTermTMP, stack_terms); + } else { + RationalTermTMP = MkVarTerm(); + STACK_PUSH_UP(RationalTermTMP, stack_terms); + /* memorize the rational term and assign it a variable */ + term_array_push(&Ts, (void *) t, (void *) RationalTermTMP); + } + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + { +#if ! defined(MODE_GLOBAL_TRIE_LOOP) || defined(GLOBAL_TRIE_FOR_SUBTERMS) + if (t > VarIndexOfTableTerm(MAX_TABLE_VARS)) { + stack_terms = load_substitution_loop((gt_node_ptr) t, &vars_arity, stack_terms PASS_REGS); + } else +#endif /* ! MODE_GLOBAL_TRIE_LOOP || GLOBAL_TRIE_FOR_SUBTERMS */ + { int var_index = VarIndexOfTableTerm(t); + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit - vars_arity + var_index + 1); + if (var_index >= vars_arity) { + while (vars_arity < var_index) + stack_vars_base[vars_arity++] = 0; + stack_vars_base[vars_arity++] = MkVarTerm(); + } else if (stack_vars_base[var_index] == 0) + stack_vars_base[var_index] = MkVarTerm(); + STACK_PUSH_UP(stack_vars_base[var_index], stack_terms); + } + } + } else if (IsAtomOrIntTerm(t)) { + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit); +#ifdef TRIE_RATIONAL_TERMS + if (CyclicTerm) { + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 4); + STACK_PUSH_UP((Term) RationalMark, stack_terms); // Add a rational term marker necessary as we read both ways the stack // + STACK_PUSH_UP(t, stack_terms); // Add the term // + STACK_PUSH_UP(CyclicTerm, stack_terms); // Add the variable that the term will unify with // + STACK_PUSH_UP((Term) RationalMark, stack_terms); // Add a rational term marker necessary as we read both ways the stack // + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(t, stack_terms); + } else if (IsPairTerm(t)) { +#ifdef TRIE_COMPACT_PAIRS + if (t == CompactPairInit) { + Term *stack_aux = stack_terms_base - stack_terms_pair_offset; + Term head, tail = STACK_POP_UP(stack_aux); +#ifdef TRIE_RATIONAL_TERMS + if (IsRationalTerm(tail)) { + Yap_Error(INTERNAL_ERROR, tail, "Rational element of a Rational Term appears as the first Tail of a list"); + } +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + while (STACK_NOT_EMPTY(stack_aux, stack_terms)) { + head = STACK_POP_UP(stack_aux); +#ifdef TRIE_RATIONAL_TERMS + if (IsRationalTerm(head)) { + head = STACK_POP_UP(stack_aux); // thats the rational term + RationalTermTMP = STACK_POP_UP(stack_aux); // that is the variable to unify with + (void) STACK_POP_UP(stack_aux); // eat the second rational mark + tail = MkPairTerm(head, tail); + Yap_unify(RationalTermTMP, tail); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + tail = MkPairTerm(head, tail); + } + stack_terms = stack_terms_base - stack_terms_pair_offset; + stack_terms_pair_offset = (int) STACK_POP_DOWN(stack_terms); + STACK_PUSH_UP(tail, stack_terms); + } else { /* CompactPairEndList / CompactPairEndTerm */ + Term last; + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1); + last = STACK_POP_DOWN(stack_terms); +#ifdef TRIE_RATIONAL_TERMS + RationalTermTMP = TermNil; + if (IsRationalTerm(last)) { // rather unlikely case the rational term is the last of a list + RationalTermTMP = STACK_POP_DOWN(stack_terms); // in this case we need to invert the term with the end of list + last = STACK_POP_DOWN(stack_terms); // variable to unify with + (void) STACK_POP_DOWN(stack_terms); // eat the second rational mark + } +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(stack_terms_pair_offset, stack_terms); + stack_terms_pair_offset = (int) (stack_terms_base - stack_terms); + if (t == CompactPairEndList) + STACK_PUSH_UP(TermNil, stack_terms); +#ifdef TRIE_RATIONAL_TERMS + if (RationalTermTMP && RationalTermTMP != TermNil) { + /* most probably this never occurs */ + STACK_PUSH_UP((Term) RationalMark, stack_terms); + STACK_PUSH_UP(last, stack_terms); + STACK_PUSH_UP(RationalTermTMP, stack_terms); + STACK_PUSH_UP((Term) RationalMark, stack_terms); + } else +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + STACK_PUSH_UP(last, stack_terms); + } +#else /* ! TRIE_COMPACT_PAIRS */ + Term head = STACK_POP_DOWN(stack_terms); + Term tail = STACK_POP_DOWN(stack_terms); + t = MkPairTerm(head, tail); + STACK_PUSH_UP(t, stack_terms); +#endif /* TRIE_COMPACT_PAIRS */ + } else if (IsApplTerm(t)) { + Functor f = (Functor) RepAppl(t); + if (f == FunctorDouble) { + union { + Term t_dbl[sizeof(Float)/sizeof(Term)]; + Float dbl; + } u; + t = TrNode_entry(current_node); + current_node = TrNode_parent(current_node); + u.t_dbl[0] = t; +#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P + t = TrNode_entry(current_node); + current_node = TrNode_parent(current_node); + u.t_dbl[1] = t; +#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */ + current_node = TrNode_parent(current_node); + t = MkFloatTerm(u.dbl); + } else if (f == FunctorLongInt) { + Int li = TrNode_entry(current_node); + current_node = TrNode_parent(current_node); + current_node = TrNode_parent(current_node); + t = MkLongIntTerm(li); + } else if (f == FunctorBigInt || f == FunctorString) { + CELL *ptr = (CELL *)TrNode_entry(current_node); + current_node = TrNode_parent(current_node); + current_node = TrNode_parent(current_node); + t = AbsAppl( ptr ); + } else { + int f_arity = ArityOfFunctor(f); + t = Yap_MkApplTerm(f, f_arity, stack_terms); + stack_terms += f_arity; + } + AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit); + STACK_PUSH_UP(t, stack_terms); + } +#ifdef TRIE_RATIONAL_TERMS + if (CyclicTerm) { + RationalTermTMP = STACK_POP_DOWN(stack_terms); + if IsRationalTerm(RationalTermTMP) { + //printf("Special Case\n"); + } else if (IsPairTerm(RationalTermTMP)) { + Yap_unify((Term) CyclicTerm, RationalTermTMP); + } else if (IsApplTerm(RationalTermTMP)) { + Yap_unify((Term) CyclicTerm, RationalTermTMP); + } + STACK_PUSH_UP(RationalTermTMP, stack_terms); + } + RationalTermTMP = TermNil; + CyclicTerm = NULL; +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ + t = TrNode_entry(current_node); + current_node = TrNode_parent(current_node); + } while (current_node); +#ifdef TRIE_RATIONAL_TERMS + term_array_free(&Ts); +#endif /* RATIONAL TERM SUPPORT FOR TRIES */ +#ifdef MODE_GLOBAL_TRIE_LOOP + *vars_arity_ptr = vars_arity; +#endif /* MODE_GLOBAL_TRIE_LOOP */ + return stack_terms; + +#undef stack_terms_limit +#ifdef TRIE_COMPACT_PAIRS +#undef stack_terms_base +#endif /* TRIE_COMPACT_PAIRS */ +} +#endif /* INCLUDE_LOAD_ANSWER_LOOP */ + + + +/*************************** +** Undef Macros ** +***************************/ + +#undef INCREMENT_GLOBAL_TRIE_REFERENCE +#undef NEW_SUBGOAL_TRIE_NODE +#undef NEW_ANSWER_TRIE_NODE +#undef NEW_GLOBAL_TRIE_NODE +#undef SUBGOAL_CHECK_INSERT_ENTRY +#undef ANSWER_CHECK_INSERT_ENTRY