/* File:      choice.h
** Author(s): Xu, Swift, Sagonas, Freire, Johnson
** Contact:   xsb-contact@cs.sunysb.edu
** 
** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
** Copyright (C) ECRC, Germany, 1990
** 
** XSB is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with XSB; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: choice.h,v 1.19 2002/03/12 17:31:21 lfcastro Exp $
** 
*/
#ifndef __CHOICE_H__
#define __CHOICE_H__

/* --- Types of Choice Points ----------------------------------------- */

#define STANDARD_CP_FRAME       0
#define GENERATOR_CP_FRAME	1
#define CONSUMER_CP_FRAME	2
#define COMPL_SUSP_CP_FRAME	3

/* --- type definitions ----------------------------------------------- */

typedef struct choice_point {
    byte *next_clause;	/* the entry of next choice */
#ifdef SLG_GC
  CPtr prev_top;        /* previous top of CP stack */
#endif
#ifdef CP_DEBUG
  Psc  psc;             /* PSC of predicate that created this CP */
#endif
    CPtr ebreg;		/* environment backtrack -- top of env stack */
    CPtr hreg;		/* current top of heap */
    CPtr *trreg;	/* current top of trail stack */
    byte *cpreg;	/* return point of the call to the procedure	*/
    CPtr ereg;		/* current top of stack */
    CPtr pdreg;		/* value of delay register for the parent subgoal */
    CPtr ptcp;          /* pointer to parent tabled CP (subgoal) */
    CPtr prev;		/* dynamic link */
} *Choice;

#define CP_SIZE	(sizeof(struct choice_point)/sizeof(CPtr))

#define cp_pcreg(b)		((Choice)(b))->next_clause
#define cp_ebreg(b)		((Choice)(b))->ebreg
#define cp_hreg(b)		((Choice)(b))->hreg
#define cp_trreg(b)		((Choice)(b))->trreg
#define cp_cpreg(b)		((Choice)(b))->cpreg
#define cp_ereg(b)		((Choice)(b))->ereg
#define cp_prevbreg(b)		((Choice)(b))->prev
#define cp_pdreg(b)		((Choice)(b))->pdreg
#define cp_ptcp(b)              ((Choice)(b))->ptcp


#ifdef SLG_GC
#define cp_prevtop(b)              ((Choice)(b))->prev_top
#endif
#ifdef CP_DEBUG
#define cp_psc(b)               ((Choice)(b))->psc
#define SAVE_PSC(b) cp_psc(b) = pscreg
#else
#define SAVE_PSC(b)
#endif

#define save_choicepoint(t_breg, t_ereg, next_clause, prev) \
    t_breg -= CP_SIZE; \
    cp_ptcp(t_breg) = ptcpreg; \
    cp_pdreg(t_breg) = delayreg; \
    cp_prevbreg(t_breg) = prev; \
    cp_ereg(t_breg) = t_ereg; \
    cp_cpreg(t_breg) = cpreg; \
    cp_trreg(t_breg) = trreg; \
    cp_hreg(t_breg) = hreg; \
    cp_ebreg(t_breg) = ebreg; \
    SAVE_PSC(t_breg); \
    cp_pcreg(t_breg) = next_clause

/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/* Table-Producer Choice Point						*/
/*----------------------------------------------------------------------*/

typedef struct tabled_choice_point {
    byte *next_clause;	/* the entry of next choice */
#if defined(SLG_GC)
  CPtr prev_top;
#endif
#ifdef CP_DEBUG
  Psc  psc;             /* PSC of predicate that created this CP */
#endif
    CPtr ebreg;		/* environment backtrack -- top of env stack */
    CPtr hreg;		/* current top of heap */
    CPtr *trreg;	/* current top of trail stack */
    byte *cpreg;	/* return point of the call to the procedure */
    CPtr ereg;		/* current top of stack */
    CPtr pdreg;		/* value of delay register for the parent subgoal */
    CPtr ptcp;		/* pointer to parent tabled CP (subgoal) */
    CPtr prev;		/* previous choicepoint */
    CPtr answer_template;
    CPtr subgoal_ptr;	/* pointer to the subgoal frame */
#if defined(LOCAL_EVAL) && !defined(SLG_GC)
  CPtr prev_top;
#endif
/* The following are needed to reclaim frozen space at SCC completion time */
    CPtr bfreg;
    CPtr hfreg;
    CPtr *trfreg;
    CPtr efreg;
#ifdef LOCAL_EVAL
    ALNptr trie_return;
#endif
} *TChoice;

#define TCP_SIZE	(sizeof(struct tabled_choice_point)/sizeof(CPtr))

#define tcp_pcreg(b)		((TChoice)(b))->next_clause
#define tcp_ebreg(b)		((TChoice)(b))->ebreg
#define tcp_hreg(b)		((TChoice)(b))->hreg
#define tcp_trreg(b)		((TChoice)(b))->trreg
#define tcp_cpreg(b)		((TChoice)(b))->cpreg
#define tcp_ereg(b)		((TChoice)(b))->ereg
#define tcp_prevbreg(b)		((TChoice)(b))->prev
#define tcp_pdreg(b)		((TChoice)(b))->pdreg
#define tcp_ptcp(b)		((TChoice)(b))->ptcp
#define tcp_subgoal_ptr(b)	((TChoice)(b))->subgoal_ptr

#ifdef CP_DEBUG
#define tcp_psc(b)              ((TChoice)(b))->psc
#define SAVE_TPSC(b)            tcp_psc(b) = pscreg
#else
#define SAVE_TPSC(b)
#endif

#if defined(SLG_GC) || defined(LOCAL_EVAL)
#define tcp_prevtop(b)          ((TChoice)(b))->prev_top
#endif

#define tcp_template(b)         ((TChoice)(b))->answer_template

#define tcp_bfreg(b)		((TChoice)(b))->bfreg
#define tcp_hfreg(b)		((TChoice)(b))->hfreg
#define tcp_trfreg(b)		((TChoice)(b))->trfreg
#define tcp_efreg(b)		((TChoice)(b))->efreg

#ifdef LOCAL_EVAL
#define tcp_trie_return(b)	((TChoice)(b))->trie_return
#endif

#define is_generator_choicepoint(b)			\
    ((cp_pcreg(b) == (byte *) &check_complete_inst) ||	\
     (cell_opcode(cp_pcreg(b)) == tabletrust) ||	\
     (cell_opcode(cp_pcreg(b)) == tableretry))

/* The following macro is used to perform early completion */
#define perform_early_completion(ProdSF,ProdCPF)	    \
    if (tcp_pcreg(ProdCPF) != (byte *) &answer_return_inst) \
      tcp_pcreg(ProdCPF) = (byte *) &check_complete_inst;   \
    mark_as_completed(ProdSF)


#define _SaveProducerCPF_common(TopCPS, Cont, pSF) {    \
   TopCPS -= TCP_SIZE;					\
   tcp_ptcp(TopCPS) = ptcpreg;				\
   tcp_pdreg(TopCPS) = delayreg;			\
   tcp_ereg(TopCPS) = ereg;				\
   tcp_cpreg(TopCPS) = cpreg;				\
   tcp_trreg(TopCPS) = trreg;				\
   tcp_hreg(TopCPS) = hreg;				\
   tcp_ebreg(TopCPS) = ebreg;				\
   tcp_subgoal_ptr(TopCPS) = (CPtr)pSF;			\
   SAVE_TPSC(TopCPS);                                   \
   tcp_prevbreg(TopCPS) = breg;				\
   tcp_pcreg(TopCPS) = Cont;				\
 }

#define _SaveProducerCPF_slg(TopCPS, Cont, pSF, AT) {	\
   _SaveProducerCPF_common(TopCPS, Cont, pSF);		\
   tcp_bfreg(TopCPS) = bfreg;				\
   tcp_efreg(TopCPS) = efreg;				\
   tcp_trfreg(TopCPS) = trfreg;				\
   tcp_hfreg(TopCPS) = hfreg;				\
   tcp_template(TopCPS) = AT;                           \
 }

#ifdef LOCAL_EVAL
#define SaveProducerCPF(TopCPS, Cont, pSF, Arity, AT) {	\
   _SaveProducerCPF_slg(TopCPS, Cont, pSF, AT);		\
   tcp_trie_return(TopCPS) = NULL;			\
 }
#else
#define SaveProducerCPF(TopCPS, Cont, pSF, Arity, AT)	\
   _SaveProducerCPF_slg(TopCPS, Cont, pSF, AT)
#endif

/*----------------------------------------------------------------------*/
/* Consumer Choice Point						*/
/*----------------------------------------------------------------------*/

typedef struct consumer_choice_point {
    byte *next_clause;	/* the entry of next choice */
#ifdef SLG_GC
  CPtr prev_top;
#endif
#ifdef CP_DEBUG
    Psc  psc;             /* PSC of predicate that created this CP */
#endif    
    CPtr ebreg;		/* environment backtrack -- top of env stack */
    CPtr hreg;		/* current top of heap */
    CPtr *trreg;	/* current top of trail stack */
    byte *cpreg;	/* return point of the call to the procedure */
    CPtr ereg;		/* current top of local stack */
    CPtr pdreg;		/* value of delay register for the parent subgoal */
    CPtr ptcp;		/* pointer to parent tabled CP (subgoal) */
    CPtr prev;		/* prev top of choice point stack */
    CPtr answer_template;
    CPtr subgoal_ptr;	/* where the answer list lives */
    CPtr prevlookup;	/* link for chain of consumer CPFs */
    ALNptr trie_return;	/* last answer consumed by this consumer */
}
*NLChoice;
#define NLCP_SIZE	(sizeof(struct consumer_choice_point)/sizeof(CPtr))

#define nlcp_pcreg(b)		((NLChoice)(b))->next_clause
#define nlcp_ebreg(b)		((NLChoice)(b))->ebreg
#define nlcp_hreg(b)		((NLChoice)(b))->hreg
#define nlcp_trreg(b)		((NLChoice)(b))->trreg
#define nlcp_cpreg(b)		((NLChoice)(b))->cpreg
#define nlcp_ereg(b)		((NLChoice)(b))->ereg
#define nlcp_subgoal_ptr(b)	((NLChoice)(b))->subgoal_ptr
#define nlcp_pdreg(b)		((NLChoice)(b))->pdreg
#define nlcp_ptcp(b)		((NLChoice)(b))->ptcp
#define nlcp_prevbreg(b)	((NLChoice)(b))->prev
#define nlcp_prevlookup(b)	((NLChoice)(b))->prevlookup
#define nlcp_trie_return(b)	((NLChoice)(b))->trie_return
#define nlcp_template(b)        ((NLChoice)(b))->answer_template
#ifdef SLG_GC
#define nlcp_prevtop(b)         ((NLChoice)(b))->prev_top
#endif

#define is_consumer_choicepoint(b) \
    (cp_pcreg(b) == (byte *) &answer_return_inst)

#ifdef CP_DEBUG
#define nlcp_psc(b)              ((NLChoice)(b))->psc
#define SAVE_NLPSC(b)            nlcp_psc(b) = pscreg
#else
#define SAVE_NLPSC(b)
#endif

#define _SaveConsumerCPF_common(TopCPS,SF,PrevConsumer) {	\
   TopCPS -= NLCP_SIZE;						\
   nlcp_trie_return(TopCPS) = subg_ans_list_ptr(SF); 		\
   nlcp_subgoal_ptr(TopCPS) = (CPtr)SF;				\
   nlcp_prevlookup(TopCPS) = PrevConsumer;			\
   nlcp_ptcp(TopCPS) = ptcpreg; 				\
   nlcp_pdreg(TopCPS) = delayreg; 				\
   nlcp_prevbreg(TopCPS) = breg; 				\
   nlcp_ereg(TopCPS) = ereg; 					\
   nlcp_cpreg(TopCPS) = cpreg; 					\
   nlcp_trreg(TopCPS) = trreg; 					\
   SAVE_NLPSC(TopCPS);                                          \
   nlcp_hreg(TopCPS) = hreg; 					\
   nlcp_ebreg(TopCPS) = ebreg; 					\
   nlcp_pcreg(TopCPS) = (pb) &answer_return_inst; 		\
 }

#define SaveConsumerCPF(TopCPS,ConsSF,PrevConsumer, AT)	\
   _SaveConsumerCPF_common(TopCPS,ConsSF,PrevConsumer); \
   nlcp_template(TopCPS) = AT

/*----------------------------------------------------------------------*/
/* The following CP is used for a computation that has been suspended	*/
/* on completion of a subgoal.                                          */
/*----------------------------------------------------------------------*/

typedef struct compl_susp_frame {
  byte *next_clause;	/* the completion suspension instruction */
#ifdef SLG_GC
  CPtr prev_top;
#endif
#ifdef CP_DEBUG
  Psc  psc;             /* PSC of predicate that created this CP */
#endif    
  CPtr ebreg;		/* environment backtrack -- top of env stack */
  CPtr hreg;		/* current top of heap */
  CPtr *trreg;	/* current top of trail stack */
  byte *cpreg;	/* return point of the call to the procedure */
  CPtr ereg;		/* current top of stack */
  CPtr pdreg;		/* value of delay register for the parent subgoal */
  CPtr ptcp;		/* pointer to parent tabled CP (subgoal) */
  CPtr subgoal_ptr;	/* pointer to the call structure */
  CPtr prevcsf;	/* previous completion suspension frame */
  Cell neg_loop;	/* !0 if the suspension is not LRD stratified */
} *ComplSuspFrame;

#define CSF_SIZE	(sizeof(struct compl_susp_frame)/sizeof(CPtr))

#define csf_pcreg(b)		((ComplSuspFrame)(b))->next_clause
#define csf_ebreg(b)		((ComplSuspFrame)(b))->ebreg
#define csf_hreg(b)		((ComplSuspFrame)(b))->hreg
#define csf_trreg(b)		((ComplSuspFrame)(b))->trreg
#define csf_cpreg(b)		((ComplSuspFrame)(b))->cpreg
#define csf_ereg(b)		((ComplSuspFrame)(b))->ereg
#define csf_pdreg(b)		((ComplSuspFrame)(b))->pdreg
#define csf_ptcp(b)		((ComplSuspFrame)(b))->ptcp
#define csf_subgoal_ptr(b)	((ComplSuspFrame)(b))->subgoal_ptr
#define csf_prevcsf(b)		((ComplSuspFrame)(b))->prevcsf
#define csf_neg_loop(b)		((ComplSuspFrame)(b))->neg_loop
#ifdef SLG_GC
#define csf_prevtop(b)          ((ComplSuspFrame)(b))->prev_top
#endif

#ifdef CP_DEBUG
#define csf_psc(b)              ((ComplSuspFrame)(b))->psc
#define SAVE_CSFPSC(b)            csf_psc(b) = pscreg
#else
#define SAVE_CSFPSC(b)
#endif

#define is_compl_susp_frame(b) \
    ((cp_pcreg(b) == (byte *) &resume_compl_suspension_inst) || \
    (cp_pcreg(b) == (byte *) &resume_compl_suspension_inst2))
      
#define save_compl_susp_frame(t_breg,t_ereg,subg,t_ptcp,CPREG) \
    t_breg -= CSF_SIZE; \
    csf_neg_loop(t_breg) = FALSE; \
    csf_prevcsf(t_breg) = subg_compl_susp_ptr(subg); \
    csf_ptcp(t_breg) = t_ptcp; \
    SAVE_CSFPSC(t_breg); \
    csf_pdreg(t_breg) = delayreg; \
    csf_subgoal_ptr(t_breg) = subg; \
    csf_ereg(t_breg) = t_ereg; \
    csf_cpreg(t_breg) = CPREG; \
    csf_trreg(t_breg) = trreg; \
    csf_hreg(t_breg) = hreg; \
    csf_ebreg(t_breg) = ebreg; \
    csf_pcreg(t_breg) = (pb) &resume_compl_suspension_inst

/*----------------------------------------------------------------------*/
/* The following CP is used to resume a set of computations that have	*/
/* been suspended on completion of a subgoal.  Only SLG-WAM uses this. 	*/
/*----------------------------------------------------------------------*/


typedef struct compl_susp_choice_point {
    byte *next_clause;	/* the completion suspension instruction */
#ifdef SLG_GC
  CPtr prev_top;
#endif
#ifdef CP_DEBUG
  Psc  psc;             /* PSC of predicate that created this CP */
#endif    
    CPtr ebreg;		/* environment backtrack -- top of env stack */
    CPtr hreg;		/* current top of heap */
#ifdef SLG_GC
  CPtr *trreg;	/* current top of trail stack */
  byte *cpreg;	/* return point of the call to the procedure */
  CPtr ereg;		/* current top of stack */
  CPtr pdreg;		/* value of delay register for the parent subgoal */
  CPtr ptcp;		/* pointer to parent tabled CP (subgoal) */
#endif
    CPtr prev;		/* lookup: previous choicepoint */
    CPtr compsuspptr;	/* pointer to the completion_suspension_frame */
} *ComplSuspChoice;

#define COMPL_SUSP_CP_SIZE	\
	(sizeof(struct compl_susp_choice_point)/sizeof(CPtr))

#define cs_pcreg(b)		((ComplSuspChoice)(b))->next_clause
#define cs_ebreg(b)		((ComplSuspChoice)(b))->ebreg
#define cs_hreg(b)		((ComplSuspChoice)(b))->hreg
#define cs_compsuspptr(b)	((ComplSuspChoice)(b))->compsuspptr
#define cs_prevbreg(b)		((ComplSuspChoice)(b))->prev
#ifdef SLG_GC
#define SAVE_CSCP_EXTRA(t_breg) \
((ComplSuspChoice)(t_breg))->prev_top = t_breg + COMPL_SUSP_CP_SIZE; \
((ComplSuspChoice)(t_breg))->trreg = trreg; \
((ComplSuspChoice)(t_breg))->cpreg = cpreg; \
((ComplSuspChoice)(t_breg))->ereg = ereg; \
((ComplSuspChoice)(t_breg))->pdreg = delayreg; \
((ComplSuspChoice)(t_breg))->ptcp = ptcpreg
#else
#define SAVE_CSCP_EXTRA(t_breg)
#endif
#ifdef CP_DEBUG
#define cscp_psc(b)              ((ComplSuspChoice)(b))->psc
#define SAVE_CSCPPSC(b)            cscp_psc(b) = pscreg
#else
#define SAVE_CSCPPSC(b)
#endif

#define save_compl_susp_cp(t_breg,prev,compsuspptr) \
    t_breg -= COMPL_SUSP_CP_SIZE; \
    cs_prevbreg(t_breg) = prev; \
    SAVE_CSCP_EXTRA(t_breg); \
    SAVE_CSCPPSC(t_breg); \
    cs_compsuspptr(t_breg) = compsuspptr;\
    cs_hreg(t_breg) = hreg; \
    cs_ebreg(t_breg) = ebreg; \
    cs_pcreg(t_breg) = (pb) &resume_compl_suspension_inst2

/* --------------------------------------------------------------------	*/

/*
 *  Push on the CP Stack the arguments in the X reg's.  't_breg' gets the
 *  topmost Cell on the cpstack, 'arity' is the number of args to be pushed,
 *  'ii' is a variable supplied by the caller for macro use, and 'regbase'
 *  is a pointer to the "lowest" reg holding an argument.
 *
 *  On "exit", 't_breg' points to the topmost arg on the cpstack.
 */
#define save_registers(t_breg, arity, regbase) {\
    byte ii;\
    for (ii = 1; ((int)ii) <= arity; ii++) \
        bld_copy(--t_breg, cell(regbase+ii));\
  }

#define restore_registers(t_breg, arity, regbase) {\
    int ii;\
    t_breg += CP_SIZE; \
    for (ii = arity; ii >= 1; ii--) bld_copy(regbase+ii, cell(t_breg++));\
  }

#define table_restore_registers(t_breg, arity, regbase) {\
    int ii;\
    t_breg += TCP_SIZE; \
    for (ii = arity; ii >= 1; ii--) bld_copy(regbase+ii, cell(t_breg++));\
  }


/* Local (Environment) Stack
   ------------------------- */
/*
 *  Structure of an Activation Record (Environment Frame) is
 *
 * low mem
 *   |   Block of Permanent Variables
 *   |   Continuation Pointer  (CPreg value at procedure invocation)
 *   V   Dynamic Link  (ptr to link field of prev frame)
 * high mem
 *
 *  Ereg always points to the Dynamic Link field of an AR, while EBreg and
 *  EFreg always point to the topmost Permanent Variable in the frame.
 */

/*
 *  Set ebreg to the topmost env frame of those pointed to by ereg or efreg.
 */
#define save_find_locx(t_ereg) \
    if (efreg_on_top(t_ereg)) ebreg = efreg;\
    else if (ereg_on_top(t_ereg)) ebreg = t_ereg - *(cpreg-2*sizeof(Cell)+3)+1;

#define restore_some_wamregs(t_breg, t_ereg) \
    if (hbreg >= hfreg) hreg = hbreg; else hreg = hfreg; \
    cpreg = cp_cpreg(t_breg); \
    t_ereg = cp_ereg(t_breg)

#endif
