/********************************************************************** The OPTYap Prolog system OPTYap extends the Yap Prolog system to support or-parallel tabling Copyright: R. Rocha and NCC - University of Porto, Portugal File: tab.insts.i version: $Id: tab.insts.i,v 1.23 2006-05-02 08:01:27 ricroc Exp $ **********************************************************************/ /* ------------------------------------------------ ** ** Tabling instructions: auxiliary macros ** ** ------------------------------------------------ */ #ifdef LOW_LEVEL_TRACER #define store_low_level_trace_info(CP, TAB_ENT) CP->cp_pred_entry = TabEnt_pe(TAB_ENT) #else #define store_low_level_trace_info(CP, TAB_ENT) #endif /* LOW_LEVEL_TRACER */ #ifdef TABLING_ERRORS #define TABLING_ERRORS_check_stack \ if (Unsigned(H) + 1024 > Unsigned(B)) \ TABLING_ERROR_MESSAGE("H + 1024 > B (check_stack)"); \ if (Unsigned(H_FZ) + 1024 > Unsigned(B)) \ TABLING_ERROR_MESSAGE("H_FZ + 1024 > B (check_stack)") #define TABLING_ERRORS_consume_answer_and_procceed \ if (IS_BATCHED_GEN_CP(B)) \ TABLING_ERROR_MESSAGE("IS_BATCHED_GEN_CP(B) (consume_answer_and_procceed)") #else #define TABLING_ERRORS_check_stack #define TABLING_ERRORS_consume_answer_and_procceed #endif /* TABLING_ERRORS */ #define store_generator_node(TAB_ENT, SG_FR, ARITY, AP) \ { register int subs_arity = *YENV; \ register CELL *pt_args; \ register choiceptr gcp; \ /* store args */ \ pt_args = XREGS + (ARITY); \ while (pt_args > XREGS) { \ register CELL aux_arg = pt_args[0]; \ --YENV; \ --pt_args; \ *YENV = aux_arg; \ } \ /* initialize gcp and adjust subgoal frame field */ \ YENV = (CELL *) (GEN_CP(YENV) - 1); \ gcp = NORM_CP(YENV); \ SgFr_gen_cp(SG_FR) = gcp; \ /* store generator choice point */ \ HBREG = H; \ store_yaam_reg_cpdepth(gcp); \ gcp->cp_tr = TR; \ gcp->cp_ap = (yamop *)(AP); \ gcp->cp_h = H; \ gcp->cp_b = B; \ gcp->cp_env = ENV; \ gcp->cp_cp = CPREG; \ if (subs_arity && IsMode_Local(TabEnt_mode(TAB_ENT))) { \ /* go local */ \ register dep_fr_ptr new_dep_fr; \ /* adjust freeze registers */ \ H_FZ = H; \ B_FZ = gcp; \ TR_FZ = TR; \ /* store dependency frame */ \ new_dependency_frame(new_dep_fr, TRUE, LOCAL_top_or_fr, \ gcp, gcp, SG_FR, LOCAL_top_dep_fr); \ LOCAL_top_dep_fr = new_dep_fr; \ GEN_CP(gcp)->cp_dep_fr = LOCAL_top_dep_fr; \ } else { \ /* go batched */ \ GEN_CP(gcp)->cp_dep_fr = NULL; \ } \ GEN_CP(gcp)->cp_sg_fr = SG_FR; \ store_low_level_trace_info(GEN_CP(gcp), TAB_ENT); \ set_cut((CELL *)gcp, B); \ B = gcp; \ YAPOR_SET_LOAD(B); \ SET_BB(B); \ TABLING_ERRORS_check_stack; \ } #define restore_generator_node(ARITY, AP) \ { register CELL *pt_args, *x_args; \ register choiceptr gcp = B; \ /* restore generator choice point */ \ H = HBREG = PROTECT_FROZEN_H(gcp); \ restore_yaam_reg_cpdepth(gcp); \ CPREG = gcp->cp_cp; \ ENV = gcp->cp_env; \ YAPOR_update_alternative(PREG, (yamop *) AP) \ gcp->cp_ap = (yamop *) AP; \ /* restore args */ \ pt_args = (CELL *)(GEN_CP(gcp) + 1) + ARITY; \ x_args = XREGS + 1 + ARITY; \ while (x_args > XREGS + 1) { \ register CELL x = pt_args[-1]; \ --x_args; \ --pt_args; \ *x_args = x; \ } \ } #define pop_generator_node(ARITY) \ { register CELL *pt_args, *x_args; \ register choiceptr gcp = B; \ /* pop generator choice point */ \ H = PROTECT_FROZEN_H(gcp); \ pop_yaam_reg_cpdepth(gcp); \ CPREG = gcp->cp_cp; \ ENV = gcp->cp_env; \ TR = gcp->cp_tr; \ B = gcp->cp_b; \ HBREG = PROTECT_FROZEN_H(B); \ /* pop args */ \ x_args = XREGS + 1 ; \ pt_args = (CELL *)(GEN_CP(gcp) + 1); \ while (x_args < XREGS + 1 + ARITY) { \ register CELL x = pt_args[0]; \ pt_args++; \ x_args++; \ x_args[-1] = x; \ } \ YENV = pt_args; \ SET_BB(PROTECT_FROZEN_B(B)); \ } #define store_consumer_node(TAB_ENT, SG_FR, LEADER_CP, DEP_ON_STACK) \ { register choiceptr ccp; \ register dep_fr_ptr new_dep_fr; \ /* initialize ccp */ \ YENV = (CELL *) (CONS_CP(YENV) - 1); \ ccp = NORM_CP(YENV); \ /* adjust freeze registers */ \ H_FZ = H; \ B_FZ = ccp; \ TR_FZ = TR; \ /* store dependency frame */ \ new_dependency_frame(new_dep_fr, DEP_ON_STACK, LOCAL_top_or_fr, \ LEADER_CP, ccp, SG_FR, LOCAL_top_dep_fr); \ LOCAL_top_dep_fr = new_dep_fr; \ /* store consumer choice point */ \ HBREG = H; \ store_yaam_reg_cpdepth(ccp); \ ccp->cp_tr = TR; \ ccp->cp_ap = ANSWER_RESOLUTION; \ ccp->cp_h = H; \ ccp->cp_b = B; \ ccp->cp_env= ENV; \ ccp->cp_cp = CPREG; \ CONS_CP(ccp)->cp_dep_fr = LOCAL_top_dep_fr; \ store_low_level_trace_info(CONS_CP(ccp), TAB_ENT); \ /* set_cut((CELL *)ccp, B); --> no effect */ \ B = ccp; \ YAPOR_SET_LOAD(B); \ SET_BB(B); \ TABLING_ERRORS_check_stack; \ } #define consume_answer_and_procceed(DEP_FR, ANSWER) \ { CELL *subs_ptr; \ /* restore consumer choice point */ \ H = HBREG = PROTECT_FROZEN_H(B); \ restore_yaam_reg_cpdepth(B); \ CPREG = B->cp_cp; \ ENV = B->cp_env; \ /* set_cut(YENV, B->cp_b); --> no effect */ \ PREG = (yamop *) CPREG; \ PREFETCH_OP(PREG); \ /* load answer from table to global stack */ \ if (B == DepFr_leader_cp(DEP_FR)) { \ /* B is a generator-consumer node */ \ /* never here if batched scheduling */ \ TABLING_ERRORS_consume_answer_and_procceed; \ subs_ptr = (CELL *) (GEN_CP(B) + 1); \ subs_ptr += SgFr_arity(GEN_CP(B)->cp_sg_fr); \ } else { \ subs_ptr = (CELL *) (CONS_CP(B) + 1); \ } \ load_answer_trie(ANSWER, subs_ptr); \ /* procceed */ \ YENV = ENV; \ GONext(); \ } #define store_loader_node(TAB_ENT, ANSWER) \ { register choiceptr lcp; \ /* initialize lcp */ \ lcp = NORM_CP(LOAD_CP(YENV) - 1); \ /* store loader choice point */ \ HBREG = H; \ store_yaam_reg_cpdepth(lcp); \ lcp->cp_tr = TR; \ lcp->cp_ap = LOAD_ANSWER; \ lcp->cp_h = H; \ lcp->cp_b = B; \ lcp->cp_env= ENV; \ lcp->cp_cp = CPREG; \ LOAD_CP(lcp)->cp_last_answer = ANSWER; \ store_low_level_trace_info(LOAD_CP(lcp), TAB_ENT); \ /* set_cut((CELL *)lcp, B); --> no effect */ \ B = lcp; \ YAPOR_SET_LOAD(B); \ SET_BB(B); \ TABLING_ERRORS_check_stack; \ } #define restore_loader_node(ANSWER) \ H = HBREG = PROTECT_FROZEN_H(B); \ restore_yaam_reg_cpdepth(B); \ CPREG = B->cp_cp; \ ENV = B->cp_env; \ LOAD_CP(B)->cp_last_answer = ANSWER; \ SET_BB(PROTECT_FROZEN_B(B)) #define pop_loader_node() \ H = PROTECT_FROZEN_H(B); \ pop_yaam_reg_cpdepth(B); \ CPREG = B->cp_cp; \ TABLING_close_alt(B); \ ENV = B->cp_env; \ B = B->cp_b; \ HBREG = PROTECT_FROZEN_H(B); \ SET_BB(PROTECT_FROZEN_B(B)) #ifdef DEPTH_LIMIT #define allocate_environment() \ YENV[E_CP] = (CELL) CPREG; \ YENV[E_E] = (CELL) ENV; \ YENV[E_B] = (CELL) B; \ YENV[E_DEPTH] = (CELL)DEPTH; \ ENV = YENV #else #define allocate_environment() \ YENV[E_CP] = (CELL) CPREG; \ YENV[E_E] = (CELL) ENV; \ YENV[E_B] = (CELL) B; \ ENV = YENV #endif /* DEPTH_LIMIT */ /* ------------------------------ ** ** Tabling instructions ** ** ------------------------------ */ #ifdef TABLING_INNER_CUTS Op(clause_with_cut, e) if (LOCAL_pruning_scope) { if (YOUNGER_CP(LOCAL_pruning_scope, B)) LOCAL_pruning_scope = B; } else { LOCAL_pruning_scope = B; PUT_IN_PRUNING(worker_id); } PREG = NEXTOP(PREG, e); GONext(); ENDOp(); #endif /* TABLING_INNER_CUTS */ PBOp(table_load_answer, ld) CELL *subs_ptr; ans_node_ptr ans_node; #ifdef YAPOR if (SCH_top_shared_cp(B)) { PROBLEM: cp_last_answer field is local to the cp! -> we need a shared data structure to avoid redundant computations! UNLOCK_OR_FRAME(LOCAL_top_or_fr); } #endif /* YAPOR */ subs_ptr = (CELL *) (LOAD_CP(B) + 1); ans_node = TrNode_child(LOAD_CP(B)->cp_last_answer); if(TrNode_child(ans_node) != NULL) { restore_loader_node(ans_node); } else { pop_loader_node(); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, subs_ptr); YENV = ENV; GONext(); ENDPBOp(); PBOp(table_try_answer, ld) #ifdef INCOMPLETE_TABLING sg_fr_ptr sg_fr; ans_node_ptr ans_node; sg_fr = GEN_CP(B)->cp_sg_fr; ans_node = TrNode_child(SgFr_try_answer(sg_fr)); if(ans_node) { CELL *subs_ptr = (CELL *) (GEN_CP(B) + 1) + SgFr_arity(sg_fr); H = HBREG = PROTECT_FROZEN_H(B); restore_yaam_reg_cpdepth(B); CPREG = B->cp_cp; ENV = B->cp_env; SgFr_try_answer(sg_fr) = ans_node; #ifdef YAPOR if (SCH_top_shared_cp(B)) UNLOCK_OR_FRAME(LOCAL_top_or_fr); #endif /* YAPOR */ SET_BB(PROTECT_FROZEN_B(B)); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, subs_ptr); YENV = ENV; GONext(); } else { yamop *code_ap; PREG = SgFr_code(sg_fr); if (PREG->opc == Yap_opcode(_table_try)) { /* table_try */ code_ap = NEXTOP(PREG,ld); PREG = PREG->u.ld.d; } else if (PREG->opc == Yap_opcode(_table_try_single)) { /* table_try_single */ code_ap = COMPLETION; PREG = PREG->u.ld.d; } else { /* table_try_me */ code_ap = PREG->u.ld.d; PREG = NEXTOP(PREG,ld); } PREFETCH_OP(PREG); restore_generator_node(SgFr_arity(sg_fr), code_ap); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); GONext(); } #else PREG = PREG->u.ld.d; PREFETCH_OP(PREG); GONext(); #endif /* INCOMPLETE_TABLING */ ENDPBOp(); PBOp(table_try_single, ld) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->u.ld.te; YENV2MEM; sg_fr = subgoal_search(PREG, YENV_ADDRESS); MEM2YENV; LOCK(SgFr_lock(sg_fr)); if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, COMPLETION); PREG = PREG->u.ld.d; /* should work also with PREG = NEXTOP(PREG,ld); */ PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { /* subgoal incomplete --> start by loading the answers already found */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); CELL *subs_ptr = YENV; init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, subs_ptr); YENV = ENV; GONext(); #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { /* subgoal in evaluation */ choiceptr leader_cp; int leader_dep_on_stack; find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK(SgFr_lock(sg_fr)); find_leader_node(leader_cp, leader_dep_on_stack); store_consumer_node(tab_ent, sg_fr, leader_cp, leader_dep_on_stack); #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, LOCAL_top_cp_on_stack)) aux_cp = aux_cp->cp_b; if (aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_top_or_fr (table_try_single)"); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; if (aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_leader_cp (table_try_single)"); } #endif /* OPTYAP_ERRORS */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK(SgFr_lock(sg_fr)); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; GONext(); } else { /* answers -> get first answer */ #ifdef LIMIT_TABLING if (SgFr_state(sg_fr) == complete || SgFr_state(sg_fr) == compiled) { SgFr_state(sg_fr)++; /* complete --> complete_in_use : compiled --> compiled_in_use */ remove_from_global_sg_fr_list(sg_fr); TRAIL_FRAME(sg_fr); } #endif /* LIMIT_TABLING */ if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { /* load answers from the trie */ UNLOCK(SgFr_lock(sg_fr)); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ if (SgFr_state(sg_fr) < compiled) update_answer_trie(sg_fr); UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); PBOp(table_try_me, ld) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->u.ld.te; YENV2MEM; sg_fr = subgoal_search(PREG, YENV_ADDRESS); MEM2YENV; LOCK(SgFr_lock(sg_fr)); if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, PREG->u.ld.d); PREG = NEXTOP(PREG, ld); PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { /* subgoal incomplete --> start by loading the answers already found */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); CELL *subs_ptr = YENV; init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, subs_ptr); YENV = ENV; GONext(); #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { /* subgoal in evaluation */ choiceptr leader_cp; int leader_dep_on_stack; find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK(SgFr_lock(sg_fr)); find_leader_node(leader_cp, leader_dep_on_stack); store_consumer_node(tab_ent, sg_fr, leader_cp, leader_dep_on_stack); #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, LOCAL_top_cp_on_stack)) aux_cp = aux_cp->cp_b; if (aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_top_or_fr (table_try_me)"); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; if (aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_leader_cp (table_try_me)"); } #endif /* OPTYAP_ERRORS */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK(SgFr_lock(sg_fr)); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; GONext(); } else { /* answers -> get first answer */ #ifdef LIMIT_TABLING if (SgFr_state(sg_fr) == complete || SgFr_state(sg_fr) == compiled) { SgFr_state(sg_fr)++; /* complete --> complete_in_use : compiled --> compiled_in_use */ remove_from_global_sg_fr_list(sg_fr); TRAIL_FRAME(sg_fr); } #endif /* LIMIT_TABLING */ if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { /* load answers from the trie */ UNLOCK(SgFr_lock(sg_fr)); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ if (SgFr_state(sg_fr) < compiled) update_answer_trie(sg_fr); UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); PBOp(table_try, ld) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->u.ld.te; YENV2MEM; sg_fr = subgoal_search(PREG, YENV_ADDRESS); MEM2YENV; LOCK(SgFr_lock(sg_fr)); if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, NEXTOP(PREG,ld)); PREG = PREG->u.ld.d; PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { /* subgoal incomplete --> start by loading the answers already found */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); CELL *subs_ptr = YENV; init_subgoal_frame(sg_fr); UNLOCK(SgFr_lock(sg_fr)); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->u.ld.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, subs_ptr); YENV = ENV; GONext(); #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { /* subgoal in evaluation */ choiceptr leader_cp; int leader_dep_on_stack; find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK(SgFr_lock(sg_fr)); find_leader_node(leader_cp, leader_dep_on_stack); store_consumer_node(tab_ent, sg_fr, leader_cp, leader_dep_on_stack); #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, LOCAL_top_cp_on_stack)) aux_cp = aux_cp->cp_b; if (aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_top_or_fr (table_try)"); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; if (aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_leader_cp (table_try)"); } #endif /* OPTYAP_ERRORS */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK(SgFr_lock(sg_fr)); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; GONext(); } else { /* answers -> get first answer */ #ifdef LIMIT_TABLING if (SgFr_state(sg_fr) == complete || SgFr_state(sg_fr) == compiled) { SgFr_state(sg_fr)++; /* complete --> complete_in_use : compiled --> compiled_in_use */ remove_from_global_sg_fr_list(sg_fr); TRAIL_FRAME(sg_fr); } #endif /* LIMIT_TABLING */ if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { /* load answers from the trie */ UNLOCK(SgFr_lock(sg_fr)); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ if (SgFr_state(sg_fr) < compiled) update_answer_trie(sg_fr); UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); Op(table_retry_me, ld) restore_generator_node(PREG->u.ld.s, PREG->u.ld.d); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = NEXTOP(PREG,ld); GONext(); ENDOp(); Op(table_retry, ld) restore_generator_node(PREG->u.ld.s, NEXTOP(PREG,ld)); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = PREG->u.ld.d; GONext(); ENDOp(); Op(table_trust_me, ld) restore_generator_node(PREG->u.ld.s, COMPLETION); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = NEXTOP(PREG,ld); GONext(); ENDOp(); Op(table_trust, ld) restore_generator_node(PREG->u.ld.s, COMPLETION); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = PREG->u.ld.d; GONext(); ENDOp(); PBOp(table_new_answer, s) CELL *subs_ptr; choiceptr gcp; sg_fr_ptr sg_fr; ans_node_ptr ans_node; /* possible optimization: when the number of substitution variables ** ** is zero, an answer is sufficient to perform an early completion */ gcp = NORM_CP(YENV[E_B]); sg_fr = GEN_CP(gcp)->cp_sg_fr; subs_ptr = (CELL *)(GEN_CP(gcp) + 1) + PREG->u.s.s; #ifdef TABLING_ERRORS { sg_fr_ptr aux_sg_fr; int i, j, arity_args, arity_subs; CELL *aux_args; CELL *aux_subs; aux_sg_fr = LOCAL_top_sg_fr; while (aux_sg_fr && aux_sg_fr != sg_fr) aux_sg_fr = SgFr_next(aux_sg_fr); if (aux_sg_fr == NULL) TABLING_ERROR_MESSAGE("aux_sg_fr == NULL (table_new_answer)"); arity_args = PREG->u.s.s; arity_subs = *subs_ptr; aux_args = (CELL *)(GEN_CP(gcp) + 1); aux_subs = subs_ptr; for (i = 1; i <= arity_subs; i++) { Term term_subs = Deref(*(aux_subs + i)); for (j = 0; j < arity_args; j++) { Term term_arg = Deref(*(aux_args + j)); if (term_subs == term_arg) break; } if (j == arity_args) TABLING_ERROR_MESSAGE("j == arity_args (table_new_answer)"); } } #endif /* TABLING_ERRORS */ #ifdef TABLE_LOCK_AT_ENTRY_LEVEL LOCK(SgFr_lock(sg_fr)); #endif /* TABLE_LOCK_LEVEL */ ans_node = answer_search(sg_fr, subs_ptr); #if defined(TABLE_LOCK_AT_NODE_LEVEL) LOCK(TrNode_lock(ans_node)); #elif defined(TABLE_LOCK_AT_WRITE_LEVEL) LOCK_TABLE(ans_node); #endif /* TABLE_LOCK_LEVEL */ if (! IS_ANSWER_LEAF_NODE(ans_node)) { /* new answer */ #ifdef TABLING_INNER_CUTS /* check for potencial prunings */ if (! BITMAP_empty(GLOBAL_bm_pruning_workers)) { int until_depth, depth; until_depth = OrFr_depth(SgFr_gen_top_or_fr(sg_fr)); depth = OrFr_depth(LOCAL_top_or_fr); if (depth > until_depth) { int i, ltt; bitmap prune_members, members; or_fr_ptr leftmost_or_fr, or_fr, nearest_or_fr; BITMAP_copy(prune_members, GLOBAL_bm_pruning_workers); BITMAP_delete(prune_members, worker_id); ltt = BRANCH_LTT(worker_id, depth); BITMAP_intersection(members, prune_members, OrFr_members(LOCAL_top_or_fr)); if (members) { for (i = 0; i < number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(LOCAL_top_cp, REMOTE_pruning_scope(i))) { leftmost_or_fr = LOCAL_top_or_fr; pending_table_new_answer: #if defined(TABLE_LOCK_AT_ENTRY_LEVEL) UNLOCK(SgFr_lock(sg_fr)); #elif defined(TABLE_LOCK_AT_NODE_LEVEL) UNLOCK(TrNode_lock(ans_node)); #elif defined(TABLE_LOCK_AT_WRITE_LEVEL) UNLOCK_TABLE(ans_node); #endif /* TABLE_LOCK_LEVEL */ LOCK_OR_FRAME(leftmost_or_fr); if (LOCAL_prune_request) { UNLOCK_OR_FRAME(leftmost_or_fr); SCHEDULER_GET_WORK(); } else { CUT_store_tg_answer(leftmost_or_fr, ans_node, gcp, ltt); UNLOCK_OR_FRAME(leftmost_or_fr); } if (IS_BATCHED_GEN_CP(gcp)) { /* deallocate and procceed */ PREG = (yamop *) YENV[E_CP]; PREFETCH_OP(PREG); CPREG = PREG; SREG = YENV; ENV = YENV = (CELL *) YENV[E_E]; #ifdef DEPTH_LIMIT DEPTH = YENV[E_DEPTH]; #endif /* DEPTH_LIMIT */ GONext(); } else { /* fail */ goto fail; } } } BITMAP_minus(prune_members, members); } leftmost_or_fr = OrFr_nearest_leftnode(LOCAL_top_or_fr); depth = OrFr_depth(leftmost_or_fr); if (depth > until_depth) { ltt = BRANCH_LTT(worker_id, depth); BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr)); if (members) { for (i = 0; i < number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(OrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i))) goto pending_table_new_answer; } BITMAP_minus(prune_members, members); } /* reaching that point we should update the nearest leftnode data */ leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr); depth = OrFr_depth(leftmost_or_fr); while (depth > until_depth) { ltt = BRANCH_LTT(worker_id, depth); BITMAP_intersection(members, prune_members, OrFr_members(leftmost_or_fr)); if (members) { for (i = 0; i < number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(OrFr_node(leftmost_or_fr), REMOTE_pruning_scope(i))) { /* update nearest leftnode data */ or_fr = LOCAL_top_or_fr; nearest_or_fr = OrFr_nearest_leftnode(or_fr); while (OrFr_depth(nearest_or_fr) > depth) { LOCK_OR_FRAME(or_fr); OrFr_nearest_leftnode(or_fr) = leftmost_or_fr; UNLOCK_OR_FRAME(or_fr); or_fr = nearest_or_fr; nearest_or_fr = OrFr_nearest_leftnode(or_fr); } goto pending_table_new_answer; } } BITMAP_minus(prune_members, members); } leftmost_or_fr = OrFr_nearest_leftnode(leftmost_or_fr); depth = OrFr_depth(leftmost_or_fr); } /* update nearest leftnode data */ or_fr = LOCAL_top_or_fr; nearest_or_fr = OrFr_nearest_leftnode(or_fr); while (OrFr_depth(nearest_or_fr) > depth) { LOCK_OR_FRAME(or_fr); OrFr_nearest_leftnode(or_fr) = leftmost_or_fr; UNLOCK_OR_FRAME(or_fr); or_fr = nearest_or_fr; nearest_or_fr = OrFr_nearest_leftnode(or_fr); } } } } /* check for prune requests */ if (LOCAL_prune_request) { #if defined(TABLE_LOCK_AT_ENTRY_LEVEL) UNLOCK(SgFr_lock(sg_fr)); #elif defined(TABLE_LOCK_AT_NODE_LEVEL) UNLOCK(TrNode_lock(ans_node)); #elif defined(TABLE_LOCK_AT_WRITE_LEVEL) UNLOCK_TABLE(ans_node); #endif /* TABLE_LOCK_LEVEL */ SCHEDULER_GET_WORK(); } #endif /* TABLING_INNER_CUTS */ TAG_AS_ANSWER_LEAF_NODE(ans_node); #if defined(TABLE_LOCK_AT_NODE_LEVEL) UNLOCK(TrNode_lock(ans_node)); LOCK(SgFr_lock(sg_fr)); #elif defined(TABLE_LOCK_AT_WRITE_LEVEL) UNLOCK_TABLE(ans_node); LOCK(SgFr_lock(sg_fr)); #endif /* TABLE_LOCK_LEVEL */ if (SgFr_first_answer(sg_fr) == NULL) SgFr_first_answer(sg_fr) = ans_node; else TrNode_child(SgFr_last_answer(sg_fr)) = ans_node; SgFr_last_answer(sg_fr) = ans_node; #ifdef TABLING_ERRORS { ans_node_ptr aux_ans_node = SgFr_first_answer(sg_fr); while (aux_ans_node != SgFr_last_answer(sg_fr)) { if (! IS_ANSWER_LEAF_NODE(aux_ans_node)) TABLING_ERROR_MESSAGE("! IS_ANSWER_LEAF_NODE(aux_ans_node) (table_new_answer)"); aux_ans_node = TrNode_child(aux_ans_node); } } #endif /* TABLING_ERRORS */ UNLOCK(SgFr_lock(sg_fr)); if (IS_BATCHED_GEN_CP(gcp)) { /* deallocate and procceed */ PREG = (yamop *) YENV[E_CP]; PREFETCH_OP(PREG); CPREG = PREG; SREG = YENV; ENV = YENV = (CELL *) YENV[E_E]; #ifdef DEPTH_LIMIT DEPTH = YENV[E_DEPTH]; #endif /* DEPTH_LIMIT */ GONext(); } else { /* fail */ goto fail; } } else { /* repeated answer */ #if defined(TABLE_LOCK_AT_ENTRY_LEVEL) UNLOCK(SgFr_lock(sg_fr)); #elif defined(TABLE_LOCK_AT_NODE_LEVEL) UNLOCK(TrNode_lock(ans_node)); #elif defined(TABLE_LOCK_AT_WRITE_LEVEL) UNLOCK_TABLE(ans_node); #endif /* TABLE_LOCK_LEVEL */ goto fail; } ENDPBOp(); BOp(table_answer_resolution, ld) #ifdef YAPOR if (SCH_top_shared_cp(B)) { UNLOCK_OR_FRAME(LOCAL_top_or_fr); } #endif /* YAPOR */ answer_resolution: INIT_PREFETCH() dep_fr_ptr dep_fr; ans_node_ptr ans_node; #ifdef OPTYAP_ERRORS if (SCH_top_shared_cp(B)) { if (B->cp_or_fr->alternative != ANSWER_RESOLUTION) OPTYAP_ERROR_MESSAGE("B->cp_or_fr->alternative != ANSWER_RESOLUTION (answer_resolution)"); } else { if (B->cp_ap != ANSWER_RESOLUTION) OPTYAP_ERROR_MESSAGE("B->cp_ap != ANSWER_RESOLUTION (answer_resolution)"); } #endif /* OPTYAP_ERRORS */ dep_fr = CONS_CP(B)->cp_dep_fr; LOCK(DepFr_lock(dep_fr)); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* unconsumed answer */ ans_node = DepFr_last_answer(dep_fr) = TrNode_child(ans_node); UNLOCK(DepFr_lock(dep_fr)); consume_answer_and_procceed(dep_fr, ans_node); } UNLOCK(DepFr_lock(dep_fr)); #ifdef YAPOR if (B == DepFr_leader_cp(LOCAL_top_dep_fr)) { /* B is a generator-consumer node ** ** never here if batched scheduling */ #ifdef TABLING_ERRORS if (IS_BATCHED_GEN_CP(B)) TABLING_ERROR_MESSAGE("IS_BATCHED_GEN_CP(B) (answer_resolution)"); #endif /* TABLING_ERRORS */ goto completion; } #endif /* YAPOR */ /* no unconsumed answers */ if (DepFr_backchain_cp(dep_fr) == NULL) { /* normal backtrack */ #ifdef YAPOR if (SCH_top_shared_cp(B)) { SCHEDULER_GET_WORK(); } #endif /* YAPOR */ B = B->cp_b; goto fail; } else { /* chain backtrack */ choiceptr top_chain_cp, chain_cp; #ifdef YAPOR or_fr_ptr start_or_fr, end_or_fr; #endif /* YAPOR */ /* find chain choice point to backtrack */ top_chain_cp = DepFr_backchain_cp(dep_fr); chain_cp = DepFr_leader_cp(LOCAL_top_dep_fr); if (YOUNGER_CP(top_chain_cp, chain_cp)) chain_cp = top_chain_cp; #ifdef TABLING_ERRORS if (EQUAL_OR_YOUNGER_CP(top_chain_cp, B)) TABLING_ERROR_MESSAGE("EQUAL_OR_YOUNGER_CP(top_chain_cp, B) (answer_resolution)"); else if (EQUAL_OR_YOUNGER_CP(chain_cp, B)) TABLING_ERROR_MESSAGE("EQUAL_OR_YOUNGER_CP(chain_cp, B) (answer_resolution)"); #endif /* TABLING_ERRORS */ /* check for dependency frames with unconsumed answers */ dep_fr = DepFr_next(dep_fr); while (YOUNGER_CP(DepFr_cons_cp(dep_fr), chain_cp)) { LOCK(DepFr_lock(dep_fr)); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* dependency frame with unconsumed answers */ ans_node = DepFr_last_answer(dep_fr) = TrNode_child(ans_node); #ifdef YAPOR if (YOUNGER_CP(DepFr_backchain_cp(dep_fr), top_chain_cp)) #endif /* YAPOR */ DepFr_backchain_cp(dep_fr) = top_chain_cp; UNLOCK(DepFr_lock(dep_fr)); chain_cp = DepFr_cons_cp(dep_fr); #ifdef YAPOR /* update shared nodes */ start_or_fr = LOCAL_top_or_fr; end_or_fr = DepFr_top_or_fr(dep_fr); if (start_or_fr != end_or_fr) { LOCAL_top_or_fr = end_or_fr; LOCAL_top_cp = OrFr_node(end_or_fr); do { while (YOUNGER_CP(OrFr_node(start_or_fr), OrFr_node(end_or_fr))) { LOCK_OR_FRAME(start_or_fr); BITMAP_delete(OrFr_members(start_or_fr), worker_id); if (BITMAP_empty(OrFr_members(start_or_fr))) { if (frame_with_suspensions_not_collected(start_or_fr)) { collect_suspension_frames(start_or_fr); } #ifdef TABLING_INNER_CUTS if (OrFr_tg_solutions(start_or_fr)) { tg_sol_fr_ptr tg_solutions; or_fr_ptr leftmost_until; tg_solutions = OrFr_tg_solutions(start_or_fr); leftmost_until = CUT_leftmost_until(start_or_fr, OrFr_depth(TgSolFr_gen_cp(tg_solutions)->cp_or_fr)); OrFr_tg_solutions(start_or_fr) = NULL; UNLOCK_OR_FRAME(start_or_fr); if (leftmost_until) { LOCK_OR_FRAME(leftmost_until); tg_solutions = CUT_store_tg_answers(leftmost_until, tg_solutions, BRANCH_LTT(worker_id, OrFr_depth(leftmost_until))); UNLOCK_OR_FRAME(leftmost_until); } CUT_validate_tg_answers(tg_solutions); goto continue_update_loop1; } #endif /* TABLING_INNER_CUTS */ } UNLOCK_OR_FRAME(start_or_fr); #ifdef TABLING_INNER_CUTS continue_update_loop1: #endif /* TABLING_INNER_CUTS */ start_or_fr = OrFr_next(start_or_fr); } while (YOUNGER_CP(OrFr_node(end_or_fr), OrFr_node(start_or_fr))) { LOCK_OR_FRAME(end_or_fr); BITMAP_insert(OrFr_members(end_or_fr), worker_id); BRANCH(worker_id, OrFr_depth(end_or_fr)) = 1; UNLOCK_OR_FRAME(end_or_fr); end_or_fr = OrFr_next(end_or_fr); } } while (start_or_fr != end_or_fr); if (LOCAL_prune_request) pruning_over_tabling_data_structures(); } #endif /* YAPOR */ #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { if (YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack)) { OPTYAP_ERROR_MESSAGE("YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack) (answer_resolution)"); } else { choiceptr aux_cp; aux_cp = chain_cp; while (aux_cp != LOCAL_top_cp) { if (YOUNGER_CP(LOCAL_top_cp, aux_cp)) { OPTYAP_ERROR_MESSAGE("LOCAL_top_cp not in branch (answer_resolution)"); break; } if (EQUAL_OR_YOUNGER_CP(LOCAL_top_cp_on_stack, aux_cp)) { OPTYAP_ERROR_MESSAGE("shared frozen segments in branch (answer_resolution)"); break; } aux_cp = aux_cp->cp_b; } } } #endif /* OPTYAP_ERRORS */ /* restore bindings, update registers, consume answer and procceed */ restore_bindings(B->cp_tr, chain_cp->cp_tr); #ifdef TABLING_ERRORS if (TR != B->cp_tr) { if(! IsPairTerm((CELL)TrailTerm(TR - 1))) TABLING_ERROR_MESSAGE("! IsPairTerm((CELL)TrailTerm(TR - 1)) (answer_resolution)"); if ((tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr) TABLING_ERROR_MESSAGE("RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr (answer_resolution)"); } #endif /* TABLING_ERRORS */ B = chain_cp; TR = TR_FZ; TRAIL_LINK(B->cp_tr); consume_answer_and_procceed(dep_fr, ans_node); } UNLOCK(DepFr_lock(dep_fr)); dep_fr = DepFr_next(dep_fr); } /* no dependency frames with unconsumed answers found */ #ifdef YAPOR /* update shared nodes */ if (EQUAL_OR_YOUNGER_CP(LOCAL_top_cp_on_stack, chain_cp)) { end_or_fr = chain_cp->cp_or_fr; start_or_fr = LOCAL_top_or_fr; if (start_or_fr != end_or_fr) { LOCAL_top_or_fr = end_or_fr; LOCAL_top_cp = OrFr_node(end_or_fr); while (start_or_fr != end_or_fr) { LOCK_OR_FRAME(start_or_fr); BITMAP_delete(OrFr_members(start_or_fr), worker_id); if (BITMAP_empty(OrFr_members(start_or_fr))) { if (frame_with_suspensions_not_collected(start_or_fr)) { collect_suspension_frames(start_or_fr); } #ifdef TABLING_INNER_CUTS if (OrFr_tg_solutions(start_or_fr)) { tg_sol_fr_ptr tg_solutions; or_fr_ptr leftmost_until; tg_solutions = OrFr_tg_solutions(start_or_fr); leftmost_until = CUT_leftmost_until(start_or_fr, OrFr_depth(TgSolFr_gen_cp(tg_solutions)->cp_or_fr)); OrFr_tg_solutions(start_or_fr) = NULL; UNLOCK_OR_FRAME(start_or_fr); if (leftmost_until) { LOCK_OR_FRAME(leftmost_until); tg_solutions = CUT_store_tg_answers(leftmost_until, tg_solutions, BRANCH_LTT(worker_id, OrFr_depth(leftmost_until))); UNLOCK_OR_FRAME(leftmost_until); } CUT_validate_tg_answers(tg_solutions); goto continue_update_loop2; } #endif /* TABLING_INNER_CUTS */ } UNLOCK_OR_FRAME(start_or_fr); #ifdef TABLING_INNER_CUTS continue_update_loop2: #endif /* TABLING_INNER_CUTS */ start_or_fr = OrFr_next(start_or_fr); } if (LOCAL_prune_request) pruning_over_tabling_data_structures(); } } #endif /* YAPOR */ #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { if (YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack)) { OPTYAP_ERROR_MESSAGE("YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack) (answer_resolution)"); } else { choiceptr aux_cp; aux_cp = chain_cp; while (aux_cp != LOCAL_top_cp) { if (YOUNGER_CP(LOCAL_top_cp, aux_cp)) { OPTYAP_ERROR_MESSAGE("LOCAL_top_cp not in branch (answer_resolution)"); break; } if (EQUAL_OR_YOUNGER_CP(LOCAL_top_cp_on_stack, aux_cp)) { OPTYAP_ERROR_MESSAGE("shared frozen segments in branch (answer_resolution)"); break; } aux_cp = aux_cp->cp_b; } } } #endif /* OPTYAP_ERRORS */ /* unbind variables */ unbind_variables(B->cp_tr, chain_cp->cp_tr); #ifdef TABLING_ERRORS if (TR != B->cp_tr) { if(! IsPairTerm((CELL)TrailTerm(TR - 1))) TABLING_ERROR_MESSAGE("! IsPairTerm((CELL)TrailTerm(TR - 1)) (answer_resolution)"); if ((tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr) TABLING_ERROR_MESSAGE("RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr (answer_resolution)"); } #endif /* TABLING_ERRORS */ if (DepFr_leader_cp(LOCAL_top_dep_fr) == chain_cp && ( /* chain_cp is a leader node AND ... */ #ifdef YAPOR /* the leader dependency is not on stack OR ... */ DepFr_leader_dep_is_on_stack(LOCAL_top_dep_fr) == FALSE || /* the leader dependency is on stack (this means that chain_cp is a generator node) and */ #endif /* YAPOR */ /* there are no unexploited alternatives ** ** (NULL if batched scheduling OR ANSWER_RESOLUTION if local scheduling) */ chain_cp->cp_ap == NULL || chain_cp->cp_ap == ANSWER_RESOLUTION)) { B = chain_cp; TR = TR_FZ; TRAIL_LINK(B->cp_tr); goto completion; } /* backtrack to chain choice point */ PREG = chain_cp->cp_ap; PREFETCH_OP(PREG); B = chain_cp; TR = TR_FZ; TRAIL_LINK(B->cp_tr); GONext(); } END_PREFETCH() ENDBOp(); BOp(table_completion, ld) #ifdef YAPOR if (SCH_top_shared_cp(B)) { if (IS_BATCHED_GEN_CP(B)) { SCH_new_alternative(PREG, NULL); if (B != DepFr_leader_cp(LOCAL_top_dep_fr) && EQUAL_OR_YOUNGER_CP(B_FZ, B)) { /* not leader on that node */ SCHEDULER_GET_WORK(); } } else { SCH_new_alternative(PREG, ANSWER_RESOLUTION); if (B != DepFr_leader_cp(LOCAL_top_dep_fr)) { /* not leader on that node */ SCHEDULER_GET_WORK(); } } } else #endif /* YAPOR */ { if (IS_BATCHED_GEN_CP(B)) { B->cp_ap = NULL; if (EQUAL_OR_YOUNGER_CP(B_FZ, B) && B != DepFr_leader_cp(LOCAL_top_dep_fr)) { /* not leader on that node */ B = B->cp_b; goto fail; } } else { B->cp_ap = ANSWER_RESOLUTION; if (B != DepFr_leader_cp(LOCAL_top_dep_fr)) { /* not leader on that node */ B = B->cp_b; goto fail; } } } /* leader on that node */ completion: INIT_PREFETCH() dep_fr_ptr dep_fr; ans_node_ptr ans_node; #ifdef YAPOR #ifdef TIMESTAMP_CHECK long timestamp = 0; #endif /* TIMESTAMP_CHECK */ int entry_owners = 0; if (SCH_top_shared_cp(B)) { #ifdef TIMESTAMP_CHECK timestamp = ++GLOBAL_timestamp; #endif /* TIMESTAMP_CHECK */ entry_owners = OrFr_owners(LOCAL_top_or_fr); } #endif /* YAPOR */ /* check for dependency frames with unconsumed answers */ dep_fr = LOCAL_top_dep_fr; while (YOUNGER_CP(DepFr_cons_cp(dep_fr), B)) { LOCK(DepFr_lock(dep_fr)); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* dependency frame with unconsumed answers */ ans_node = DepFr_last_answer(dep_fr) = TrNode_child(ans_node); if (B->cp_ap) { #ifdef YAPOR if (YOUNGER_CP(DepFr_backchain_cp(dep_fr), B)) #endif /* YAPOR */ DepFr_backchain_cp(dep_fr) = B; } else { #ifdef YAPOR if (YOUNGER_CP(DepFr_backchain_cp(dep_fr), B->cp_b)) #endif /* YAPOR */ DepFr_backchain_cp(dep_fr) = B->cp_b; } UNLOCK(DepFr_lock(dep_fr)); #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { if (YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack)) { OPTYAP_ERROR_MESSAGE("YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack) (completion)"); } else { choiceptr aux_cp; aux_cp = DepFr_cons_cp(dep_fr); while (YOUNGER_CP(aux_cp, LOCAL_top_cp_on_stack)) aux_cp = aux_cp->cp_b; if (aux_cp->cp_or_fr != DepFr_top_or_fr(dep_fr)) OPTYAP_ERROR_MESSAGE("Error on DepFr_top_or_fr (completion)"); } } #endif /* OPTYAP_ERRORS */ #ifdef YAPOR /* update shared nodes */ if (YOUNGER_CP(LOCAL_top_cp_on_stack, LOCAL_top_cp)) { or_fr_ptr or_frame = DepFr_top_or_fr(dep_fr); while (or_frame != LOCAL_top_or_fr) { LOCK_OR_FRAME(or_frame); BITMAP_insert(OrFr_members(or_frame), worker_id); BRANCH(worker_id, OrFr_depth(or_frame)) = 1; UNLOCK_OR_FRAME(or_frame); or_frame = OrFr_next(or_frame); } LOCAL_top_or_fr = DepFr_top_or_fr(dep_fr); LOCAL_top_cp = OrFr_node(LOCAL_top_or_fr); } #endif /* YAPOR */ #ifdef OPTYAP_ERRORS if (PARALLEL_EXECUTION_MODE) { if (YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack)) { OPTYAP_ERROR_MESSAGE("YOUNGER_CP(LOCAL_top_cp, LOCAL_top_cp_on_stack) (completion)"); } else { choiceptr aux_cp; aux_cp = DepFr_cons_cp(dep_fr); while (aux_cp != LOCAL_top_cp) { if (YOUNGER_CP(LOCAL_top_cp, aux_cp)) { OPTYAP_ERROR_MESSAGE("LOCAL_top_cp not in branch (completion)"); break; } if (EQUAL_OR_YOUNGER_CP(LOCAL_top_cp_on_stack, aux_cp)) { OPTYAP_ERROR_MESSAGE("shared frozen segments in branch (completion)"); break; } aux_cp = aux_cp->cp_b; } } } #endif /* OPTYAP_ERRORS */ /* rebind variables, update registers, consume answer and procceed */ #ifdef TABLING_ERRORS if (EQUAL_OR_YOUNGER_CP(B, DepFr_cons_cp(dep_fr))) TABLING_ERROR_MESSAGE("EQUAL_OR_YOUNGER_CP(B, DepFr_cons_cp(dep_fr)) (completion)"); if (B->cp_tr > DepFr_cons_cp(dep_fr)->cp_tr) TABLING_ERROR_MESSAGE("B->cp_tr > DepFr_cons_cp(dep_fr)->cp_tr (completion)"); #endif /* TABLING_ERRORS */ rebind_variables(DepFr_cons_cp(dep_fr)->cp_tr, B->cp_tr); #ifdef TABLING_ERRORS if (TR != B->cp_tr) { if(! IsPairTerm((CELL)TrailTerm(TR - 1))) TABLING_ERROR_MESSAGE("! IsPairTerm((CELL)TrailTerm(TR - 1)) (completion)"); if ((tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr) TABLING_ERROR_MESSAGE("RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr (completion)"); } #endif /* TABLING_ERRORS */ B = DepFr_cons_cp(dep_fr); TR = TR_FZ; if (TR != B->cp_tr) TRAIL_LINK(B->cp_tr); consume_answer_and_procceed(dep_fr, ans_node); } UNLOCK(DepFr_lock(dep_fr)); #ifdef TIMESTAMP_CHECK DepFr_timestamp(dep_fr) = timestamp; #endif /* TIMESTAMP_CHECK */ dep_fr = DepFr_next(dep_fr); } /* no dependency frames with unconsumed answers found */ #ifdef YAPOR if (SCH_top_shared_cp(B)) { if (entry_owners > 1) { /* more owners when we start looking for dependency frames with unconsumed answers */ if (YOUNGER_CP(B_FZ, B)) { suspend_branch(); /* check for suspension frames to be resumed */ while (YOUNGER_CP(OrFr_node(LOCAL_top_susp_or_fr), LOCAL_top_cp)) { or_fr_ptr susp_or_fr; susp_fr_ptr resume_fr; susp_or_fr = LOCAL_top_susp_or_fr; LOCK_OR_FRAME(susp_or_fr); #ifdef TIMESTAMP_CHECK resume_fr = suspension_frame_to_resume(susp_or_fr, timestamp); #else resume_fr = suspension_frame_to_resume(susp_or_fr); #endif /* TIMESTAMP_CHECK */ if (resume_fr) { if (OrFr_suspensions(susp_or_fr) == NULL) { LOCAL_top_susp_or_fr = OrFr_nearest_suspnode(susp_or_fr); OrFr_nearest_suspnode(susp_or_fr) = susp_or_fr; } UNLOCK_OR_FRAME(susp_or_fr); rebind_variables(OrFr_node(susp_or_fr)->cp_tr, B->cp_tr); resume_suspension_frame(resume_fr, susp_or_fr); B = LOCAL_top_cp; SET_BB(B_FZ); TR = TR_FZ; TRAIL_LINK(B->cp_tr); goto completion; } LOCAL_top_susp_or_fr = OrFr_nearest_suspnode(susp_or_fr); OrFr_nearest_suspnode(susp_or_fr) = NULL; UNLOCK_OR_FRAME(susp_or_fr); } } } else { /* unique owner */ if (frame_with_suspensions_not_collected(LOCAL_top_or_fr)) collect_suspension_frames(LOCAL_top_or_fr); /* check for suspension frames to be resumed */ while (EQUAL_OR_YOUNGER_CP(OrFr_node(LOCAL_top_susp_or_fr), LOCAL_top_cp)) { or_fr_ptr susp_or_fr; susp_fr_ptr resume_fr; susp_or_fr = LOCAL_top_susp_or_fr; #ifdef TIMESTAMP_CHECK resume_fr = suspension_frame_to_resume(susp_or_fr, timestamp); #else resume_fr = suspension_frame_to_resume(susp_or_fr); #endif /* TIMESTAMP_CHECK */ if (resume_fr) { if (OrFr_suspensions(susp_or_fr) == NULL) { LOCAL_top_susp_or_fr = OrFr_nearest_suspnode(susp_or_fr); OrFr_nearest_suspnode(susp_or_fr) = susp_or_fr; } if (YOUNGER_CP(B_FZ, B)) { suspend_branch(); } rebind_variables(OrFr_node(susp_or_fr)->cp_tr, B->cp_tr); resume_suspension_frame(resume_fr, susp_or_fr); B = LOCAL_top_cp; SET_BB(B_FZ); TR = TR_FZ; TRAIL_LINK(B->cp_tr); goto completion; } LOCAL_top_susp_or_fr = OrFr_nearest_suspnode(susp_or_fr); OrFr_nearest_suspnode(susp_or_fr) = NULL; } /* complete all */ public_completion(); } #ifdef TABLING_ERRORS if (TR != B->cp_tr) { if(! IsPairTerm((CELL)TrailTerm(TR - 1))) TABLING_ERROR_MESSAGE("! IsPairTerm((CELL)TrailTerm(TR - 1)) (completion)"); if ((tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr) TABLING_ERROR_MESSAGE("RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr (completion)"); } #endif /* TABLING_ERRORS */ if (B == DepFr_leader_cp(LOCAL_top_dep_fr)) { /* B is a generator-consumer node */ /* never here if batched scheduling */ ans_node_ptr ans_node; #ifdef TABLING_ERRORS if (IS_BATCHED_GEN_CP(B)) TABLING_ERROR_MESSAGE("IS_BATCHED_GEN_CP(B) (completion)"); #endif /* TABLING_ERRORS */ TR = B->cp_tr; SET_BB(B); LOCK_OR_FRAME(LOCAL_top_or_fr); LOCK(DepFr_lock(LOCAL_top_dep_fr)); ans_node = DepFr_last_answer(LOCAL_top_dep_fr); if (TrNode_child(ans_node)) { /* unconsumed answer */ UNLOCK_OR_FRAME(LOCAL_top_or_fr); ans_node = DepFr_last_answer(LOCAL_top_dep_fr) = TrNode_child(ans_node); UNLOCK(DepFr_lock(LOCAL_top_dep_fr)); consume_answer_and_procceed(LOCAL_top_dep_fr, ans_node); } /* no unconsumed answers */ UNLOCK(DepFr_lock(LOCAL_top_dep_fr)); if (OrFr_owners(LOCAL_top_or_fr) > 1) { /* more owners -> move up one node */ LOCAL_top_cp_on_stack = OrFr_node(OrFr_next_on_stack(LOCAL_top_or_fr)); BITMAP_delete(OrFr_members(LOCAL_top_or_fr), worker_id); OrFr_owners(LOCAL_top_or_fr)--; LOCAL_top_dep_fr = DepFr_next(LOCAL_top_dep_fr); UNLOCK_OR_FRAME(LOCAL_top_or_fr); if (LOCAL_top_sg_fr && LOCAL_top_cp == SgFr_gen_cp(LOCAL_top_sg_fr)) { LOCAL_top_sg_fr = SgFr_next(LOCAL_top_sg_fr); } SCH_update_local_or_tops(); CUT_reset_prune_request(); adjust_freeze_registers(); goto shared_fail; } else { /* free top dependency frame --> get work */ OrFr_alternative(LOCAL_top_or_fr) = NULL; UNLOCK_OR_FRAME(LOCAL_top_or_fr); dep_fr = DepFr_next(LOCAL_top_dep_fr); FREE_DEPENDENCY_FRAME(LOCAL_top_dep_fr); LOCAL_top_dep_fr = dep_fr; adjust_freeze_registers(); SCHEDULER_GET_WORK(); } } /* goto getwork */ PREG = B->cp_ap; PREFETCH_OP(PREG); TR = B->cp_tr; SET_BB(B); GONext(); } else #endif /* YAPOR */ { /* complete all */ sg_fr_ptr sg_fr; sg_fr = GEN_CP(B)->cp_sg_fr; private_completion(sg_fr); if (IS_BATCHED_GEN_CP(B)) { /* backtrack */ B = B->cp_b; SET_BB(PROTECT_FROZEN_B(B)); goto fail; } else { /* subgoal completed */ ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ B = B->cp_b; SET_BB(PROTECT_FROZEN_B(B)); goto fail; } #ifdef TABLING_ERRORS if (TR != B->cp_tr) { if(! IsPairTerm((CELL)TrailTerm(TR - 1))) TABLING_ERROR_MESSAGE("! IsPairTerm((CELL)TrailTerm(TR - 1)) (completion)"); if ((tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr) TABLING_ERROR_MESSAGE("RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr (completion)"); } #endif /* TABLING_ERRORS */ pop_generator_node(SgFr_arity(sg_fr)); if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; GONext(); } else { /* answers -> get first answer */ tab_ent_ptr tab_ent = SgFr_tab_ent(sg_fr); #ifdef LIMIT_TABLING SgFr_state(sg_fr)++; /* complete --> complete_in_use */ remove_from_global_sg_fr_list(sg_fr); TRAIL_FRAME(sg_fr); #endif /* LIMIT_TABLING */ if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { /* load answers from the trie */ if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer_trie(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ LOCK(SgFr_lock(sg_fr)); if (SgFr_state(sg_fr) < compiled) update_answer_trie(sg_fr); UNLOCK(SgFr_lock(sg_fr)); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } } END_PREFETCH() ENDBOp();