2197 lines
85 KiB
C
2197 lines
85 KiB
C
/************************************************************************
|
|
** **
|
|
** 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
|
|
Sfprintf(Serror, "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 */
|