/************************************************************************ ** ** ** 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 ** ** ** ************************************************************************/ /************************************************************************ ** 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 */ #define TABLING_ERROR_CHECKING_STACK \ TABLING_ERROR_CHECKING(store_node, Unsigned(H) + 1024 > Unsigned(B)); \ TABLING_ERROR_CHECKING(store_node, Unsigned(H_FZ) + 1024 > Unsigned(B)) #define store_generator_node(TAB_ENT, SG_FR, ARITY, AP) \ { 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 = HR; \ store_yaam_reg_cpdepth(gcp); \ gcp->cp_tr = TR; \ gcp->cp_ap = (yamop *)(AP); \ gcp->cp_h = HR; \ gcp->cp_b = B; \ gcp->cp_env = ENV; \ gcp->cp_cp = CPREG; \ if (IsMode_Local(TabEnt_mode(TAB_ENT))) { \ /* go local */ \ register dep_fr_ptr new_dep_fr; \ /* adjust freeze registers */ \ H_FZ = HR; \ B_FZ = gcp; \ TR_FZ = TR; \ /* store dependency frame */ \ new_dependency_frame(new_dep_fr, TRUE, LOCAL_top_or_fr, gcp, \ gcp, SG_FR, FALSE, 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_ERROR_CHECKING_STACK; \ } #ifdef DETERMINISTIC_TABLING #define store_deterministic_generator_node(TAB_ENT, SG_FR) \ { register choiceptr gcp; \ /* initialize gcp and adjust subgoal frame field */ \ YENV = (CELL *) (DET_GEN_CP(YENV) - 1); \ gcp = NORM_CP(YENV); \ SgFr_gen_cp(SG_FR) = gcp; \ /* store deterministic generator choice point */ \ HBREG = HR; \ store_yaam_reg_cpdepth(gcp); \ gcp->cp_ap = COMPLETION; \ gcp->cp_b = B; \ gcp->cp_tr = TR; \ gcp->cp_h = HR; \ DET_GEN_CP(gcp)->cp_sg_fr = SG_FR; \ store_low_level_trace_info(DET_GEN_CP(gcp), TAB_ENT); \ set_cut((CELL *)gcp, B); \ B = gcp; \ YAPOR_SET_LOAD(B); \ SET_BB(B); \ TABLING_ERROR_CHECKING_STACK; \ } #endif /* DETERMINISTIC_TABLING */ #ifdef THREADS_CONSUMER_SHARING #define store_generator_consumer_node(TAB_ENT, SG_FR, DEP_ON_STACK,ARITY) \ { register CELL *pt_args; \ register choiceptr gccp; \ register dep_fr_ptr new_dep_fr; \ /* 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); \ gccp = NORM_CP(YENV); \ SgFr_gen_cp(SG_FR) = gccp; \ /* store generator choice point */ \ HBREG = HR; \ store_yaam_reg_cpdepth(gccp); \ gccp->cp_tr = TR; \ gccp->cp_ap = ANSWER_RESOLUTION_COMPLETION; \ gccp->cp_h = HR; \ gccp->cp_b = B; \ gccp->cp_env = ENV; \ gccp->cp_cp = CPREG; \ /* store dependency frame */ \ new_dependency_frame(new_dep_fr, DEP_ON_STACK, LOCAL_top_or_fr, \ gccp, gccp, SG_FR, TRUE, LOCAL_top_dep_fr); \ LOCAL_top_dep_fr = new_dep_fr; \ GEN_CP(gccp)->cp_dep_fr = LOCAL_top_dep_fr; \ GEN_CP(gccp)->cp_sg_fr = SG_FR; \ /* adjust freeze registers */ \ H_FZ = HR; \ B_FZ = gccp; \ TR_FZ = TR; \ store_low_level_trace_info(GEN_CP(gccp), TAB_ENT); \ set_cut((CELL *)gccp, B); \ B = gccp; \ YAPOR_SET_LOAD(B); \ SET_BB(B); \ TABLING_ERROR_CHECKING_STACK; \ } #endif /* THREADS_CONSUMER_SHARING */ #define restore_generator_node(ARITY, AP) \ { register CELL *pt_args, *x_args; \ register choiceptr gcp = B; \ /* restore generator choice point */ \ HR = 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 */ \ HR = 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 = HR; \ 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, FALSE, LOCAL_top_dep_fr); \ LOCAL_top_dep_fr = new_dep_fr; \ /* store consumer choice point */ \ HBREG = HR; \ store_yaam_reg_cpdepth(ccp); \ ccp->cp_tr = TR; \ ccp->cp_ap = ANSWER_RESOLUTION; \ ccp->cp_h = HR; \ 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_ERROR_CHECKING_STACK; \ } #ifdef THREADS_CONSUMER_SHARING #define consume_answer_and_procceed(DEP_FR, ANSWER) \ { CELL *subs_ptr; \ /* restore consumer choice point */ \ HR = 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) || DepFr_external(DEP_FR)) { \ /* B is a generator-consumer node */ \ TABLING_ERROR_CHECKING(generator_consumer, IS_BATCHED_GEN_CP(B)); \ 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(ANSWER, subs_ptr); \ /* procceed */ \ YENV = ENV; \ GONext(); \ } #else #define consume_answer_and_procceed(DEP_FR, ANSWER) \ { CELL *subs_ptr; \ /* restore consumer choice point */ \ HR = 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_ERROR_CHECKING(generator_consumer, IS_BATCHED_GEN_CP(B)); \ 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(ANSWER, subs_ptr); \ /* procceed */ \ YENV = ENV; \ GONext(); \ } #endif /* THREADS_CONSUMER_SHARING */ #define store_loader_node(TAB_ENT, ANSWER) \ { register choiceptr lcp; \ /* initialize lcp */ \ lcp = NORM_CP(LOAD_CP(YENV) - 1); \ /* store loader choice point */ \ HBREG = HR; \ store_yaam_reg_cpdepth(lcp); \ lcp->cp_tr = TR; \ lcp->cp_ap = LOAD_ANSWER; \ lcp->cp_h = HR; \ 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_ERROR_CHECKING_STACK; \ } #define restore_loader_node(ANSWER) \ HR = 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() \ HR = 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 */ /************************************************************************ ** clause_with_cut ** ************************************************************************/ #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 */ /************************************************************************ ** table_load_answer ** ************************************************************************/ PBOp(table_load_answer, Otapl) CELL *subs_ptr; ans_node_ptr ans_node; #ifdef YAPOR if (SCH_top_shared_cp(B)) { #if 0 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); #else fprintf(stderr, "PROBLEM: cp_last_answer field is local to the cp!\n"); exit(1); #endif } #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(ans_node, subs_ptr); YENV = ENV; GONext(); ENDPBOp(); /************************************************************************ ** table_try_answer ** ************************************************************************/ PBOp(table_try_answer, Otapl) #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); HR = 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(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,Otapl); PREG = PREG->y_u.Otapl.d; } else if (PREG->opc == Yap_opcode(_table_try_single)) { /* table_try_single */ code_ap = COMPLETION; PREG = PREG->y_u.Otapl.d; } else { /* table_try_me */ code_ap = PREG->y_u.Otapl.d; PREG = NEXTOP(PREG,Otapl); } 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->y_u.Otapl.d; PREFETCH_OP(PREG); GONext(); #endif /* INCOMPLETE_TABLING */ ENDPBOp(); /************************************************************************ ** table_try_single ** ************************************************************************/ PBOp(table_try_single, Otapl) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->y_u.Otapl.te; YENV2MEM; saveregs(); sg_fr = subgoal_search(PREG, YENV_ADDRESS); setregs(); MEM2YENV; #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_state(sg_fr) <= ready) { LOCK_SG_FR(sg_fr); if (SgFr_sg_ent_state(sg_fr) >= complete) SgFr_state(sg_fr) = SgFr_sg_ent_state(sg_fr); else SgFr_active_workers(sg_fr)++; UNLOCK_SG_FR(sg_fr); } #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ LOCK_SG_FR(sg_fr); #ifdef THREADS_CONSUMER_SHARING if (SgFr_state(sg_fr) == ready_external) { init_subgoal_frame(sg_fr); store_generator_consumer_node(tab_ent, sg_fr, TRUE, PREG->y_u.Otapl.s); PREFETCH_OP(PREG); allocate_environment(); check_for_deadlock(sg_fr); goto answer_resolution_completion; } else #endif /* THREADS_CONSUMER_SHARING */ if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK_SG_FR(sg_fr); #ifdef DETERMINISTIC_TABLING if (IsMode_Batched(TabEnt_mode(tab_ent))) { store_deterministic_generator_node(tab_ent, sg_fr); } else #endif /* DETERMINISTIC_TABLING */ { store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, COMPLETION); } PREG = PREG->y_u.Otapl.d; /* should work also with PREG = NEXTOP(PREG,Otapl); */ PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { printf("Currently Unsupported\n"); } else { /* 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_SG_FR(sg_fr); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, subs_ptr); YENV = ENV; GONext(); } #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { /* Used for coinductive tabling strategy */ CELL *subs_ptr; subs_ptr = (CELL *) (GEN_CP(SgFr_gen_cp(sg_fr)) + 1); subs_ptr += SgFr_arity(sg_fr); // Points at the Parent goal Variables int i; for (i = 0; i < subs_ptr[0]; i++) Yap_unify(subs_ptr[i+1], YENV[i+1]); /* yes answer --> procceed */ UNLOCK_SG_FR(sg_fr); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; // Consume the variables GONext(); // Succeed the goal :-D } else { /* subgoal in evaluation */ choiceptr leader_cp; #ifdef YAPOR int leader_dep_on_stack; #endif find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK_SG_FR(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 DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, Get_LOCAL_top_cp_on_stack())) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try_single, aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try_single, aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)); } #endif /* DEBUG_OPTYAP */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK_SG_FR(sg_fr); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK_SG_FR(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 defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (IsMode_LoadAnswers(TabEnt_mode(tab_ent)) || SgFr_active_workers(sg_fr) > 0) { #else if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ /* load answers from the trie */ UNLOCK_SG_FR(sg_fr); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_sg_ent_state(sg_fr) < compiled) #else if (SgFr_state(sg_fr) < compiled) #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ update_answer_trie(sg_fr); UNLOCK_SG_FR(sg_fr); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); /************************************************************************ ** table_try_me ** ************************************************************************/ PBOp(table_try_me, Otapl) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->y_u.Otapl.te; YENV2MEM; saveregs(); sg_fr = subgoal_search(PREG, YENV_ADDRESS); setregs(); MEM2YENV; #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_state(sg_fr) <= ready) { LOCK_SG_FR(sg_fr); if (SgFr_sg_ent_state(sg_fr) >= complete) SgFr_state(sg_fr) = SgFr_sg_ent_state(sg_fr); else SgFr_active_workers(sg_fr)++; UNLOCK_SG_FR(sg_fr); } #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ LOCK_SG_FR(sg_fr); #ifdef THREADS_CONSUMER_SHARING if (SgFr_state(sg_fr) == ready_external) { init_subgoal_frame(sg_fr); UNLOCK_SG_FR(sg_fr); store_generator_consumer_node(tab_ent, sg_fr, TRUE, PREG->y_u.Otapl.s); PREFETCH_OP(PREG); allocate_environment(); check_for_deadlock(sg_fr); goto answer_resolution_completion; } else #endif /* THREADS_CONSUMER_SHARING */ if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK_SG_FR(sg_fr); store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, PREG->y_u.Otapl.d); PREG = NEXTOP(PREG, Otapl); PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { printf("Currently Unsupported\n"); } else { /* 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_SG_FR(sg_fr); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, subs_ptr); YENV = ENV; GONext(); } #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { printf("Currently Unsupported\n"); } else { /* subgoal in evaluation */ choiceptr leader_cp; #ifdef YAPOR int leader_dep_on_stack; #endif find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK_SG_FR(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 DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, Get_LOCAL_top_cp_on_stack())) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try_me, aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try_me, aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)); } #endif /* DEBUG_OPTYAP */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK_SG_FR(sg_fr); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK_SG_FR(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 defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (IsMode_LoadAnswers(TabEnt_mode(tab_ent)) || SgFr_active_workers(sg_fr) > 0) { #else if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ /* load answers from the trie */ UNLOCK_SG_FR(sg_fr); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_sg_ent_state(sg_fr) < compiled) #else if (SgFr_state(sg_fr) < compiled) #endif /*THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING*/ update_answer_trie(sg_fr); UNLOCK_SG_FR(sg_fr); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); /************************************************************************ ** table_try ** ************************************************************************/ PBOp(table_try, Otapl) tab_ent_ptr tab_ent; sg_fr_ptr sg_fr; check_trail(TR); tab_ent = PREG->y_u.Otapl.te; YENV2MEM; sg_fr = subgoal_search(PREG, YENV_ADDRESS); MEM2YENV; #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_state(sg_fr) <= ready) { LOCK_SG_FR(sg_fr); if (SgFr_sg_ent_state(sg_fr) >= complete) SgFr_state(sg_fr) = SgFr_sg_ent_state(sg_fr); else SgFr_active_workers(sg_fr)++; UNLOCK_SG_FR(sg_fr); } #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ LOCK_SG_FR(sg_fr); #ifdef THREADS_CONSUMER_SHARING if (SgFr_state(sg_fr) == ready_external) { init_subgoal_frame(sg_fr); UNLOCK_SG_FR(sg_fr); store_generator_consumer_node(tab_ent, sg_fr, TRUE , PREG->y_u.Otapl.s); PREFETCH_OP(PREG); allocate_environment(); check_for_deadlock(sg_fr); goto answer_resolution_completion; } else #endif /* THREADS_CONSUMER_SHARING */ if (SgFr_state(sg_fr) == ready) { /* subgoal new */ init_subgoal_frame(sg_fr); UNLOCK_SG_FR(sg_fr); store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, NEXTOP(PREG,Otapl)); PREG = PREG->y_u.Otapl.d; PREFETCH_OP(PREG); allocate_environment(); GONext(); #ifdef INCOMPLETE_TABLING } else if (SgFr_state(sg_fr) == incomplete) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { printf("Currently Unsupported\n"); } else { /* 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_SG_FR(sg_fr); SgFr_try_answer(sg_fr) = ans_node; store_generator_node(tab_ent, sg_fr, PREG->y_u.Otapl.s, TRY_ANSWER); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, subs_ptr); YENV = ENV; GONext(); } #endif /* INCOMPLETE_TABLING */ } else if (SgFr_state(sg_fr) == evaluating) { if (IsMode_CoInductive(TabEnt_flags(tab_ent))) { /* Used for coinductive tabling strategy */ CELL *subs_ptr; subs_ptr = (CELL *) (GEN_CP(SgFr_gen_cp(sg_fr)) + 1); subs_ptr += SgFr_arity(sg_fr); // Points at the Parent goal Variables int i; for (i = 0; i < subs_ptr[0]; i++) Yap_unify(subs_ptr[i+1], YENV[i+1]); /* yes answer --> procceed */ UNLOCK_SG_FR(sg_fr); PREG = (yamop *) CPREG; PREFETCH_OP(PREG); YENV = ENV; // Consume the variables GONext(); // Succeed the goal :-D } else { /* subgoal in evaluation */ choiceptr leader_cp; #ifdef YAPOR int leader_dep_on_stack; #endif find_dependency_node(sg_fr, leader_cp, leader_dep_on_stack); UNLOCK_SG_FR(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 DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; aux_cp = B; while (YOUNGER_CP(aux_cp, Get_LOCAL_top_cp_on_stack())) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try, aux_cp->cp_or_fr != DepFr_top_or_fr(LOCAL_top_dep_fr)); aux_cp = B; while (YOUNGER_CP(aux_cp, DepFr_leader_cp(LOCAL_top_dep_fr))) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(table_try, aux_cp != DepFr_leader_cp(LOCAL_top_dep_fr)); } #endif /* DEBUG_OPTYAP */ goto answer_resolution; } else { /* subgoal completed */ ans_node_ptr ans_node = SgFr_first_answer(sg_fr); if (ans_node == NULL) { /* no answers --> fail */ UNLOCK_SG_FR(sg_fr); goto fail; } else if (ans_node == SgFr_answer_trie(sg_fr)) { /* yes answer --> procceed */ UNLOCK_SG_FR(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 defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (IsMode_LoadAnswers(TabEnt_mode(tab_ent)) || SgFr_active_workers(sg_fr) > 0) { #else if (IsMode_LoadAnswers(TabEnt_mode(tab_ent))) { #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ /* load answers from the trie */ UNLOCK_SG_FR(sg_fr); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, YENV); YENV = ENV; GONext(); } else { /* execute compiled code from the trie */ #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_sg_ent_state(sg_fr) < compiled) #else if (SgFr_state(sg_fr) < compiled) #endif /*THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ update_answer_trie(sg_fr); UNLOCK_SG_FR(sg_fr); PREG = (yamop *) TrNode_child(SgFr_answer_trie(sg_fr)); PREFETCH_OP(PREG); *--YENV = 0; /* vars_arity */ *--YENV = 0; /* heap_arity */ GONext(); } } } ENDPBOp(); /************************************************************************ ** table_retry_me ** ************************************************************************/ Op(table_retry_me, Otapl) restore_generator_node(PREG->y_u.Otapl.s, PREG->y_u.Otapl.d); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = NEXTOP(PREG,Otapl); GONext(); ENDOp(); /************************************************************************ ** table_retry ** ************************************************************************/ Op(table_retry, Otapl) restore_generator_node(PREG->y_u.Otapl.s, NEXTOP(PREG,Otapl)); YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = PREG->y_u.Otapl.d; GONext(); ENDOp(); /************************************************************************ ** table_trust_me ** ************************************************************************/ Op(table_trust_me, Otapl) restore_generator_node(PREG->y_u.Otapl.s, COMPLETION); #ifdef DETERMINISTIC_TABLING if (B_FZ > B && IS_BATCHED_NORM_GEN_CP(B)) { CELL *subs_ptr = (CELL *)(GEN_CP(B) + 1) + PREG->y_u.Otapl.s; choiceptr gcp = NORM_CP(DET_GEN_CP(subs_ptr) - 1); sg_fr_ptr sg_fr = GEN_CP(B)->cp_sg_fr; DET_GEN_CP(gcp)->cp_sg_fr = sg_fr; gcp->cp_h = B->cp_h; #ifdef DEPTH_LIMIT gcp->cp_depth = B->cp_depth; #endif /* DEPTH_LIMIT */ gcp->cp_tr = B->cp_tr; gcp->cp_b = B->cp_b; gcp->cp_ap = B->cp_ap; SgFr_gen_cp(sg_fr) = B = gcp; } #endif /* DETERMINISTIC_TABLING */ YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = NEXTOP(PREG,Otapl); GONext(); ENDOp(); /************************************************************************ ** table_trust ** ************************************************************************/ Op(table_trust, Otapl) restore_generator_node(PREG->y_u.Otapl.s, COMPLETION); #ifdef DETERMINISTIC_TABLING if (B_FZ > B && IS_BATCHED_NORM_GEN_CP(B)) { CELL *subs_ptr = (CELL *)(GEN_CP(B) + 1) + PREG->y_u.Otapl.s; choiceptr gcp = NORM_CP(DET_GEN_CP(subs_ptr) - 1); sg_fr_ptr sg_fr = GEN_CP(B)->cp_sg_fr; DET_GEN_CP(gcp)->cp_sg_fr = sg_fr; gcp->cp_h = B->cp_h; #ifdef DEPTH_LIMIT gcp->cp_depth = B->cp_depth; #endif /* DEPTH_LIMIT */ gcp->cp_tr = B->cp_tr; gcp->cp_b = B->cp_b; gcp->cp_ap = B->cp_ap; SgFr_gen_cp(sg_fr) = B = gcp; } #endif /* DETERMINISTIC_TABLING */ YENV = (CELL *) PROTECT_FROZEN_B(B); set_cut(YENV, B->cp_b); SET_BB(NORM_CP(YENV)); allocate_environment(); PREG = PREG->y_u.Otapl.d; GONext(); ENDOp(); /************************************************************************ ** table_new_answer ** ************************************************************************/ PBOp(table_new_answer, s) CELL *subs_ptr; choiceptr gcp; sg_fr_ptr sg_fr; ans_node_ptr ans_node; gcp = NORM_CP(YENV[E_B]); #ifdef DETERMINISTIC_TABLING if (IS_DET_GEN_CP(gcp)){ sg_fr = DET_GEN_CP(gcp)->cp_sg_fr; subs_ptr = (CELL *)(DET_GEN_CP(gcp) + 1) ; } else #endif /* DETERMINISTIC_TABLING */ { sg_fr = GEN_CP(gcp)->cp_sg_fr; subs_ptr = (CELL *)(GEN_CP(gcp) + 1) + PREG->y_u.s.s; } #if defined(DEBUG_TABLING) && !defined(DETERMINISTIC_TABLING) { int i, j, arity_args, arity_subs; CELL *aux_args; CELL *aux_subs; arity_args = PREG->y_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; } TABLING_ERROR_CHECKING(table_new_answer, j == arity_args); } } #endif /* DEBUG_TABLING && !DETERMINISTIC_TABLING */ LOCK_ANSWER_TRIE(sg_fr); #ifdef MODE_DIRECTED_TABLING if (SgFr_mode_directed(sg_fr)) { ans_node = mode_directed_answer_search(sg_fr, subs_ptr); if (ans_node == NULL) { /* no answer inserted */ UNLOCK_ANSWER_TRIE(sg_fr); goto fail; } } else #endif /* MODE_DIRECTED_TABLING */ ans_node = answer_search(sg_fr, subs_ptr); LOCK_ANSWER_NODE(ans_node); 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 < GLOBAL_number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(Get_LOCAL_top_cp(), REMOTE_pruning_scope(i))) { leftmost_or_fr = LOCAL_top_or_fr; pending_table_new_answer: UNLOCK_ANSWER_NODE(ans_node); UNLOCK_ANSWER_TRIE(sg_fr); LOCK_OR_FRAME(leftmost_or_fr); if (Get_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 < GLOBAL_number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(GetOrFr_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 < GLOBAL_number_workers; i++) { if (BITMAP_member(members, i) && BRANCH_LTT(i, depth) > ltt && EQUAL_OR_YOUNGER_CP(GetOrFr_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 (Get_LOCAL_prune_request()) { UNLOCK_ANSWER_NODE(ans_node); UNLOCK_ANSWER_TRIE(sg_fr); SCHEDULER_GET_WORK(); } #endif /* TABLING_INNER_CUTS */ TAG_AS_ANSWER_LEAF_NODE(ans_node); #ifdef THREADS_FULL_SHARING INFO_THREADS("new answer (1) sgfr=%p ans_node=%p",SgFr_sg_ent(sg_fr),ans_node); if (IsMode_Batched(TabEnt_mode(SgFr_tab_ent(sg_fr)))) { ANSWER_LEAF_NODE_INSTR_RELATIVE(ans_node); if (worker_id < ANSWER_LEAF_NODE_MAX_THREADS) ANSWER_LEAF_NODE_SET_WID(ans_node,worker_id); } #endif /* THREADS_FULL_SHARING */ UNLOCK_ANSWER_NODE(ans_node); #ifndef ANSWER_TRIE_LOCK_AT_ENTRY_LEVEL LOCK_SG_FR(sg_fr); #endif /* ! ANSWER_TRIE_LOCK_AT_ENTRY_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 DEBUG_TABLING { ans_node_ptr aux_ans_node = SgFr_first_answer(sg_fr); while (aux_ans_node != SgFr_last_answer(sg_fr)) { TABLING_ERROR_CHECKING(table_new_answer, !IS_ANSWER_LEAF_NODE(aux_ans_node)); aux_ans_node = TrNode_child(aux_ans_node); } } #endif /* DEBUG_TABLING */ UNLOCK_SG_FR(sg_fr); if (IS_BATCHED_GEN_CP(gcp)) { #ifdef THREADS_FULL_SHARING if (worker_id >= ANSWER_LEAF_NODE_MAX_THREADS) SgFr_batched_cached_answers_check_insert(sg_fr,ans_node); //add to buffer all answers except the ans_node #endif /* THREADS_FULL_SHARING */ #ifdef TABLING_EARLY_COMPLETION if (gcp == PROTECT_FROZEN_B(B) && (*subs_ptr == 0 || gcp->cp_ap == COMPLETION)) { /* if the current generator choice point is the topmost choice point and the current */ /* call is deterministic (i.e., the number of substitution variables is zero or */ /* there are no more alternatives) then the current answer is deterministic and we */ /* can perform an early completion and remove the current generator choice point */ private_completion(sg_fr); B = B->cp_b; SET_BB(PROTECT_FROZEN_B(B)); } else if (*subs_ptr == 0) { /* if the number of substitution variables is zero, an answer is sufficient to perform */ /* an early completion, but the current generator choice point cannot be removed */ mark_as_completed(sg_fr); if (gcp->cp_ap != NULL) gcp->cp_ap = COMPLETION; } #endif /* TABLING_EARLY_COMPLETION */ /* 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 { #ifdef TABLING_EARLY_COMPLETION if (*subs_ptr == 0) { /* if the number of substitution variables is zero, an answer is sufficient to perform */ /* an early completion, but the current generator choice point cannot be removed */ mark_as_completed(sg_fr); if (gcp->cp_ap != ANSWER_RESOLUTION) gcp->cp_ap = COMPLETION; } #endif /* TABLING_EARLY_COMPLETION */ /* fail */ goto fail; } } else { /* repeated answer */ #ifdef THREADS_FULL_SHARING if (IsMode_Batched(TabEnt_mode(SgFr_tab_ent(sg_fr)))){ if (worker_id >= ANSWER_LEAF_NODE_MAX_THREADS) { UNLOCK_ANSWER_NODE(ans_node); UNLOCK_ANSWER_TRIE(sg_fr); SgFr_batched_cached_answers_check_insert(sg_fr,NULL); INFO_THREADS("new answer (2) sgfr=%p ans_node=%p",SgFr_sg_ent(sg_fr),ans_node); if (SgFr_batched_cached_answers_check_remove(sg_fr , ans_node) == 1){ INFO_THREADS("ans_node=%p not found", ans_node); goto fail; } /* 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 { if (!ANSWER_LEAF_NODE_CHECK_WID(ans_node,worker_id)){ ANSWER_LEAF_NODE_SET_WID(ans_node,worker_id); UNLOCK_ANSWER_NODE(ans_node); UNLOCK_ANSWER_TRIE(sg_fr); /* deallocate and procceed */ INFO_THREADS("new answer (2) sgfr=%p ans_node=%p",SgFr_sg_ent(sg_fr),ans_node); 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 UNLOCK_ANSWER_NODE(ans_node); UNLOCK_ANSWER_TRIE(sg_fr); #endif /* THREADS_FULL_SHARING */ #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) INFO_THREADS("new answer(rep) sgfr=%p ans_node=%p",SgFr_sg_ent(sg_fr),ans_node); #else INFO_THREADS("new answer(rep) sgfr=%p ans_node=%p",sg_fr,ans_node); #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ goto fail; } ENDPBOp(); /************************************************************************ ** table_answer_resolution ** ************************************************************************/ BOp(table_answer_resolution, Otapl) #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; OPTYAP_ERROR_CHECKING(answer_resolution, SCH_top_shared_cp(B) && B->cp_or_fr->alternative != ANSWER_RESOLUTION); OPTYAP_ERROR_CHECKING(answer_resolution, !SCH_top_shared_cp(B) && B->cp_ap != ANSWER_RESOLUTION); dep_fr = CONS_CP(B)->cp_dep_fr; LOCK_DEP_FR(dep_fr); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* unconsumed answers */ #ifdef MODE_DIRECTED_TABLING if (IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) { ans_node_ptr old_ans_node; old_ans_node = ans_node; ans_node = TrNode_child(ans_node); do { ans_node = TrNode_child(ans_node); } while (IS_ANSWER_INVALID_NODE(ans_node)); TrNode_child(old_ans_node) = ans_node; } else #endif /* MODE_DIRECTED_TABLING */ ans_node = TrNode_child(ans_node); DepFr_last_answer(dep_fr) = ans_node; UNLOCK_DEP_FR(dep_fr); consume_answer_and_procceed(dep_fr, ans_node); } UNLOCK_DEP_FR(dep_fr); #ifdef YAPOR if (B == DepFr_leader_cp(LOCAL_top_dep_fr)) { /* B is a generator-consumer node ** ** never here if batched scheduling */ TABLING_ERROR_CHECKING(answer_resolution, IS_BATCHED_GEN_CP(B)); 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; TABLING_ERROR_CHECKING(answer_resolution, EQUAL_OR_YOUNGER_CP(top_chain_cp, B)); TABLING_ERROR_CHECKING(answer_resolution, EQUAL_OR_YOUNGER_CP(chain_cp, B)); /* check for dependency frames with unconsumed answers */ dep_fr = DepFr_next(dep_fr); while (YOUNGER_CP(DepFr_cons_cp(dep_fr), chain_cp)) { LOCK_DEP_FR(dep_fr); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* dependency frame with unconsumed answers */ #ifdef MODE_DIRECTED_TABLING if (IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) { ans_node_ptr old_ans_node; old_ans_node = ans_node; ans_node = TrNode_child(ans_node); do { ans_node = TrNode_child(ans_node); } while (IS_ANSWER_INVALID_NODE(ans_node)); TrNode_child(old_ans_node) = ans_node; } else #endif /* MODE_DIRECTED_TABLING */ ans_node = TrNode_child(ans_node); DepFr_last_answer(dep_fr) = 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_DEP_FR(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; Set_LOCAL_top_cp(GetOrFr_node(end_or_fr)); do { while (YOUNGER_CP(GetOrFr_node(start_or_fr), GetOrFr_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(GetOrFr_node(end_or_fr), GetOrFr_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 (Get_LOCAL_prune_request()) pruning_over_tabling_data_structures(); } #endif /* YAPOR */ #ifdef DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), Get_LOCAL_top_cp_on_stack())); aux_cp = chain_cp; while (aux_cp != Get_LOCAL_top_cp()) { OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), aux_cp)); OPTYAP_ERROR_CHECKING(completion, EQUAL_OR_YOUNGER_CP(Get_LOCAL_top_cp_on_stack(), aux_cp)); aux_cp = aux_cp->cp_b; } } #endif /* DEBUG_OPTYAP */ /* restore bindings, update registers, consume answer and procceed */ restore_bindings(B->cp_tr, chain_cp->cp_tr); TABLING_ERROR_CHECKING(answer_resolution, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(answer_resolution, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); B = chain_cp; TR = TR_FZ; TRAIL_LINK(B->cp_tr); consume_answer_and_procceed(dep_fr, ans_node); } UNLOCK_DEP_FR(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(Get_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; Set_LOCAL_top_cp(GetOrFr_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 (Get_LOCAL_prune_request()) pruning_over_tabling_data_structures(); } } #endif /* YAPOR */ #ifdef DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), Get_LOCAL_top_cp_on_stack())); aux_cp = chain_cp; while (aux_cp != Get_LOCAL_top_cp()) { OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), aux_cp)); OPTYAP_ERROR_CHECKING(completion, EQUAL_OR_YOUNGER_CP(Get_LOCAL_top_cp_on_stack(), aux_cp)); aux_cp = aux_cp->cp_b; } } #endif /* DEBUG_OPTYAP */ /* unbind variables */ unbind_variables(B->cp_tr, chain_cp->cp_tr); TABLING_ERROR_CHECKING(answer_resolution, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(answer_resolution, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); 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(); /************************************************************************ ** table_completion ** ************************************************************************/ BOp(table_completion, Otapl) #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 */ { #ifdef THREADS_CONSUMER_SHARING goto answer_resolution_completion; #endif /* THREADS_CONSUMER_SHARING */ 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: #ifdef THREADS_CONSUMER_SHARING goto answer_resolution_completion; #endif /* THREADS_CONSUMER_SHARING */ 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_DEP_FR(dep_fr); ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* dependency frame with unconsumed answers */ #ifdef MODE_DIRECTED_TABLING if (IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) { ans_node_ptr old_ans_node; old_ans_node = ans_node; ans_node = TrNode_child(ans_node); do { ans_node = TrNode_child(ans_node); } while (IS_ANSWER_INVALID_NODE(ans_node)); TrNode_child(old_ans_node) = ans_node; } else #endif /* MODE_DIRECTED_TABLING */ ans_node = TrNode_child(ans_node); DepFr_last_answer(dep_fr) = 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_DEP_FR(dep_fr); #ifdef DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; OPTYAP_ERROR_CHECKING(completion, Get_LOCAL_top_cp(), Get_LOCAL_top_cp_on_stack()); aux_cp = DepFr_cons_cp(dep_fr); while (YOUNGER_CP(aux_cp, Get_LOCAL_top_cp_on_stack())) aux_cp = aux_cp->cp_b; OPTYAP_ERROR_CHECKING(completion, aux_cp->cp_or_fr != DepFr_top_or_fr(dep_fr)); } #endif /* DEBUG_OPTYAP */ #ifdef YAPOR /* update shared nodes */ if (YOUNGER_CP(Get_LOCAL_top_cp_on_stack(), Get_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); Set_LOCAL_top_cp(GetOrFr_node(LOCAL_top_or_fr)); } #endif /* YAPOR */ #ifdef DEBUG_OPTYAP if (GLOBAL_parallel_mode == PARALLEL_MODE_RUNNING) { choiceptr aux_cp; OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), Get_LOCAL_top_cp_on_stack())); aux_cp = DepFr_cons_cp(dep_fr); while (aux_cp != Get_LOCAL_top_cp()) { OPTYAP_ERROR_CHECKING(completion, YOUNGER_CP(Get_LOCAL_top_cp(), aux_cp)); OPTYAP_ERROR_CHECKING(completion, EQUAL_OR_YOUNGER_CP(Get_LOCAL_top_cp_on_stack(), aux_cp)); aux_cp = aux_cp->cp_b; } } #endif /* DEBUG_OPTYAP */ /* rebind variables, update registers, consume answer and procceed */ TABLING_ERROR_CHECKING(completion, EQUAL_OR_YOUNGER_CP(B, DepFr_cons_cp(dep_fr))); TABLING_ERROR_CHECKING(completion, B->cp_tr > DepFr_cons_cp(dep_fr)->cp_tr); rebind_variables(DepFr_cons_cp(dep_fr)->cp_tr, B->cp_tr); TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); 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_DEP_FR(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(GetOrFr_node(LOCAL_top_susp_or_fr), Get_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(GetOrFr_node(susp_or_fr)->cp_tr, B->cp_tr); resume_suspension_frame(resume_fr, susp_or_fr); B = Get_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(GetOrFr_node(LOCAL_top_susp_or_fr), Get_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(GetOrFr_node(susp_or_fr)->cp_tr, B->cp_tr); resume_suspension_frame(resume_fr, susp_or_fr); B = Get_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(); } TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); 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; TABLING_ERROR_CHECKING(completion, IS_BATCHED_GEN_CP(B)); TR = B->cp_tr; SET_BB(B); LOCK_OR_FRAME(LOCAL_top_or_fr); LOCK_DEP_FR(LOCAL_top_dep_fr); ans_node = DepFr_last_answer(LOCAL_top_dep_fr); if (TrNode_child(ans_node)) { /* unconsumed answers */ UNLOCK_OR_FRAME(LOCAL_top_or_fr); #ifdef MODE_DIRECTED_TABLING if (IS_ANSWER_INVALID_NODE(TrNode_child(ans_node))) { ans_node_ptr old_ans_node; old_ans_node = ans_node; ans_node = TrNode_child(ans_node); do { ans_node = TrNode_child(ans_node); } while (IS_ANSWER_INVALID_NODE(ans_node)); TrNode_child(old_ans_node) = ans_node; } else #endif /* MODE_DIRECTED_TABLING */ ans_node = TrNode_child(ans_node); DepFr_last_answer(LOCAL_top_dep_fr) = ans_node; UNLOCK_DEP_FR(LOCAL_top_dep_fr); consume_answer_and_procceed(LOCAL_top_dep_fr, ans_node); } /* no unconsumed answers */ UNLOCK_DEP_FR(LOCAL_top_dep_fr); if (OrFr_owners(LOCAL_top_or_fr) > 1) { /* more owners -> move up one node */ Set_LOCAL_top_cp_on_stack(GetOrFr_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 && Get_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 */ #ifdef THREADS_CONSUMER_SHARING complete_all: #endif /* THREADS_CONSUMER_SHARING */ { /* complete all */ sg_fr_ptr sg_fr; #ifdef DETERMINISTIC_TABLING if (IS_DET_GEN_CP(B)) sg_fr = DET_GEN_CP(B)->cp_sg_fr; else #endif /* DETERMINISTIC_TABLING */ sg_fr = GEN_CP(B)->cp_sg_fr; private_completion(sg_fr); #ifdef THREADS_CONSUMER_SHARING if (IS_BATCHED_GEN_CP(B) || SgFr_gen_worker(sg_fr) != worker_id) { /* if it is an gen_cons node then all the answers were already consumed */ #else if (IS_BATCHED_GEN_CP(B)) { #endif /*THREADS_CONSUMER_SHARING */ /* 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; } TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(completion, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); 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(ans_node, YENV); YENV = ENV; GONext(); } else { #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) LOCK_SG_FR(sg_fr); if (SgFr_active_workers(sg_fr) > 0) { /* load answers from the trie */ UNLOCK_SG_FR(sg_fr); if(TrNode_child(ans_node) != NULL) { store_loader_node(tab_ent, ans_node); } PREG = (yamop *) CPREG; PREFETCH_OP(PREG); load_answer(ans_node, YENV); YENV = ENV; GONext(); } #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ /* execute compiled code from the trie */ #if defined(THREADS_FULL_SHARING) || defined(THREADS_CONSUMER_SHARING) if (SgFr_sg_ent_state(sg_fr) < compiled) #else LOCK_SG_FR(sg_fr); if (SgFr_state(sg_fr) < compiled) #endif /* THREADS_FULL_SHARING || THREADS_CONSUMER_SHARING */ update_answer_trie(sg_fr); UNLOCK_SG_FR(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(); /************************************************************************ ** table_answer_resolution_completion ** ************************************************************************/ #ifdef THREADS_CONSUMER_SHARING BOp(table_answer_resolution_completion, Otapl) answer_resolution_completion: { INIT_PREFETCH() int do_not_complete_tables; int wid = worker_id ; do { dep_fr_ptr dep_fr; ans_node_ptr ans_node; do_not_complete_tables = 0; /* 0 - complete all the tables 1 - do not complete all the tables */ if (B->cp_ap == ANSWER_RESOLUTION_COMPLETION ){ /* generator consumer node (external node) */ if ((IS_BATCHED_GEN_CP(B) && (EQUAL_OR_YOUNGER_CP(B_FZ, B) && B != DepFr_leader_cp(LOCAL_top_dep_fr))) || (B != DepFr_leader_cp(LOCAL_top_dep_fr))) { /* not leader on that node */ INFO_THREADS("ans_reso_com (1) : not leader on that node dep_fr = %p leader_node =%p", LOCAL_top_dep_fr, GEN_CP(DepFr_leader_cp(LOCAL_top_dep_fr))->cp_dep_fr); ThDepFr_state(GLOBAL_th_dep_fr(wid)) = working; B->cp_ap = ANSWER_RESOLUTION; goto answer_resolution; } /* leader on that node */ dep_fr = GEN_CP(B)->cp_dep_fr; ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { /* unconsumed answer */ ThDepFr_state(GLOBAL_th_dep_fr(wid)) = working; ans_node = DepFr_last_answer(dep_fr) = TrNode_child(ans_node); INFO_THREADS("ans_reso_com (2) : consume_answer =%p dep_fr = %p leader_node =%p", ans_node, dep_fr, GEN_CP(DepFr_leader_cp(dep_fr))->cp_dep_fr); consume_answer_and_procceed(dep_fr, ans_node); } sg_fr_ptr sg_fr = GEN_CP(B)->cp_sg_fr; if (SgFr_sg_ent_state(sg_fr) < complete || (SgFr_sg_ent_state(sg_fr) >= complete && TrNode_child(ans_node)!= NULL)) do_not_complete_tables = 1; } else { /* using the B->cp_ap == ANSWER_RESOLUTION_COMPLETION to distinguish gen_cons nodes from gen */ /* generator node */ if (IS_BATCHED_GEN_CP(B)) { if (EQUAL_OR_YOUNGER_CP(B_FZ, B) && B != DepFr_leader_cp(LOCAL_top_dep_fr)) { /* not leader on that node */ ThDepFr_state(GLOBAL_th_dep_fr(wid)) = working; B->cp_ap = NULL; B = B->cp_b; goto fail; } } else { if (B != DepFr_leader_cp(LOCAL_top_dep_fr)) { /* not leader on that node */ ThDepFr_state(GLOBAL_th_dep_fr(wid)) = working; B->cp_ap = ANSWER_RESOLUTION; B = B->cp_b; INFO_THREADS("ans_reso_com (3) : not leader on that node dep_fr = %p leader_node =%p", LOCAL_top_dep_fr, GEN_CP(DepFr_leader_cp(LOCAL_top_dep_fr))->cp_dep_fr); goto fail; } } } /* leader on that node */ /* no unconsumed answers */ dep_fr = LOCAL_top_dep_fr; /* check for dependency frames with unconsumed answers */ while (YOUNGER_CP(DepFr_cons_cp(dep_fr), B)) { ans_node = DepFr_last_answer(dep_fr); if (TrNode_child(ans_node)) { ThDepFr_state(GLOBAL_th_dep_fr(wid)) = working; /*dependency frame with unconsumed answers */ ans_node = DepFr_last_answer(dep_fr) = TrNode_child(ans_node); if (IS_BATCHED_GEN_CP(B)) DepFr_backchain_cp(dep_fr) = B->cp_b; else DepFr_backchain_cp(dep_fr) = B; /*rebind variables, update registers, consume answer and procceed */ TABLING_ERROR_CHECKING(answer_resolution_completion, EQUAL_OR_YOUNGER_CP(B, DepFr_cons_cp(dep_fr))); TABLING_ERROR_CHECKING(answer_resolution_completion, B->cp_tr > DepFr_cons_cp(dep_fr)->cp_tr); rebind_variables(DepFr_cons_cp(dep_fr)->cp_tr,B->cp_tr); //don't know if it is the same unbind_variables(DepFr_cons_cp(dep_fr)->cp_tr, B->cp_tr); TABLING_ERROR_CHECKING(answer_resolution_completion, TR != B->cp_tr && !IsPairTerm((CELL)TrailTerm(TR - 1))); TABLING_ERROR_CHECKING(answer_resolution_completion, TR != B->cp_tr && (tr_fr_ptr) RepPair((CELL)TrailTerm(TR - 1)) != B->cp_tr); B = DepFr_cons_cp(dep_fr); TR = TR_FZ; if (TR != B->cp_tr) TRAIL_LINK(B->cp_tr); INFO_THREADS("ans_reso_com (4) : consume_answer =%p dep_fr = %p leader_node =%p", ans_node, dep_fr, GEN_CP(DepFr_leader_cp(dep_fr))->cp_dep_fr); consume_answer_and_procceed(dep_fr, ans_node); } if (DepFr_external(dep_fr) == TRUE){ sg_fr_ptr sg_fr = GEN_CP(DepFr_cons_cp(dep_fr))->cp_sg_fr; if (SgFr_sg_ent_state(sg_fr) < complete || (SgFr_sg_ent_state(sg_fr) >= complete && TrNode_child(ans_node)!= NULL)) do_not_complete_tables = 1; } dep_fr = DepFr_next(dep_fr); } /******************************** a terminaƧao das threads *************************************/ if (do_not_complete_tables == 1){ /*all the dependency frames have consumed all answers and we have external tables */ if (ThDepFr_next(GLOBAL_th_dep_fr(wid)) == wid) /* worker_id is not inside an SCC */ continue; if (ThDepFr_state(GLOBAL_th_dep_fr(wid)) == working) { int c_wid = ThDepFr_next(GLOBAL_th_dep_fr(wid)); do { ThDepFr_terminator(GLOBAL_th_dep_fr(c_wid)) = 1; c_wid = ThDepFr_next(GLOBAL_th_dep_fr(c_wid)); }while(c_wid != wid); ThDepFr_terminator(GLOBAL_th_dep_fr(wid)) = 1; ThDepFr_state(GLOBAL_th_dep_fr(wid)) = idle; }else if (ThDepFr_state(GLOBAL_th_dep_fr(wid)) == idle){ int l_wid = wid; /* leader wid */ int c_wid = ThDepFr_next(GLOBAL_th_dep_fr(wid)); int jump_state = TRUE; do{ if (ThDepFr_state(GLOBAL_th_dep_fr(c_wid)) != idle){ jump_state = FALSE; break; } else if (l_wid > c_wid) l_wid = c_wid; c_wid = ThDepFr_next(GLOBAL_th_dep_fr(c_wid)); } while(c_wid != wid); if (jump_state && l_wid == wid){ /* wid is the current leader thread */ ThDepFr_terminator(GLOBAL_th_dep_fr(wid)) = 0; c_wid = ThDepFr_next(GLOBAL_th_dep_fr(wid)); do { dep_fr_ptr remote_dep_fr = REMOTE_top_dep_fr(c_wid); while(YOUNGER_CP(DepFr_cons_cp(remote_dep_fr),DepFr_leader_cp(REMOTE_top_dep_fr(c_wid)))){ if (TrNode_child(DepFr_last_answer(remote_dep_fr))){ /* dependency frame with unconsumed answers */ jump_state = FALSE; break; } remote_dep_fr = DepFr_next(remote_dep_fr); } if (ThDepFr_state(GLOBAL_th_dep_fr(c_wid)) != idle){ jump_state = FALSE; break; } c_wid = ThDepFr_next(GLOBAL_th_dep_fr(c_wid)); } while(c_wid != wid); } if (jump_state && ThDepFr_terminator(GLOBAL_th_dep_fr(wid)) == 0){ c_wid = ThDepFr_next(GLOBAL_th_dep_fr(wid)); do { ThDepFr_state(GLOBAL_th_dep_fr(c_wid)) = completing; c_wid = ThDepFr_next(GLOBAL_th_dep_fr(c_wid)); }while(c_wid != wid); ThDepFr_state(GLOBAL_th_dep_fr(wid)) = completing; } }else if (ThDepFr_state(GLOBAL_th_dep_fr(wid)) == completing){ INFO_THREADS("ans_reso_com (5) : completing thread_state =%d",ThDepFr_state(GLOBAL_th_dep_fr(wid))); break; /*do_not_complete_tables = 0; -- same as "break;" */ } } } while(do_not_complete_tables); END_PREFETCH() INFO_THREADS("ans_reso_com (6) : completing thread_state =%d",ThDepFr_state(GLOBAL_th_dep_fr(worker_id))); goto complete_all; } ENDBOp(); #endif /* THREADS_CONSUMER_SHARING */