/*************************************************************************
*									 *
*	 YAP Prolog    @(#)amidefs.h	1.3 3/15/90
*									 *
*	Yiap Prolog was developed at NCCUP - Universidade do Porto	 *
*									 *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
*									 *
**************************************************************************
*									 *
* File:		amidefs.h						 *
* Last rev:								 *
* mods:									 *
* comments:	Abstract machine peculiarities				 *
*									 *
*************************************************************************/

#if ALIGN_LONGS
/*   */ typedef Int DISPREG;
/*   */ typedef CELL SMALLUNSGN;
/*   */ typedef Int  OPREG;
/*   */ typedef CELL UOPREG;

#else
/*   */ typedef Short DISPREG;
/*   */ typedef BITS16 SMALLUNSGN;
/*   */ typedef SBITS16 OPREG;
/*   */ typedef SBITS16 UOPREG;

#endif


typedef Int (*CPredicate)(void);

typedef Int (*CmpPredicate)(Term, Term);


#define OpRegSize    sizeof(OPREG)

/*
   Possible arguments to YAP emulator:
   wamreg describes an A or X register;
   yslot describes an Y slot
   COUNT is a small number (eg, number of arguments to a choicepoint,
   number of permanent variables in a environment
*/

typedef OPREG  wamreg;
typedef OPREG  yslot;
typedef OPREG  COUNT;


/*
   This is a table with the codes for YAP instructions
*/
typedef enum {
#define OPCODE(OP,TYPE) _##OP
#include "YapOpcodes.h"
#undef  OPCODE
} op_numbers;


#define _std_top	_p_execute_tail

typedef enum {
	_atom,
	_atomic,
	_integer,
	_compound,
	_float,
	_nonvar,
	_number,
	_var,
	_cut_by,
	_db_ref,
	_primitive,
	_equal,
	_dif,
	_eq,
	_plus,
	_minus,
	_times,
	_div,
	_and,
	_or,
	_sll,
	_slr,
	_arg,
	_functor
} basic_preds;

#if USE_THREADED_CODE

#if ALIGN_LONGS
/*   */ typedef CELL OPCODE;
#else

#if LOW_ABSMI
/*   */ typedef BITS16 OPCODE;
#else
/*   */ typedef CELL OPCODE;
#endif
#endif /* ALIGN_LONGS */
#else /* if does not USE_THREADED_CODE */
/*   */ typedef op_numbers OPCODE;
#endif
#define OpCodeSize   sizeof(OPCODE)


/*

   Types of possible YAAM instructions.

   The meaning of the symbols in a abstract machine instruction is:

   c: constant
   d: predicate definition
   f: functor
   n: small number
   l: label
   x: argument or temporary register
   y: environment slot

*/
typedef struct yami {
  OPCODE opc;
  union {
       struct {
	 CELL next;
       } e;
       struct {
	 CELL                c;
	 CELL next;
       } c;
       struct {
	 CELL                c;
	 struct yami        *l1;
	 struct yami        *l2;
	 struct yami        *l3;
	 CELL next;
       } clll;
       struct {
	 CODEADDR            d;
	 CELL next;
       } d;
       struct {
	 CODEADDR            d;
	 struct pred_entry  *p;
	 CELL next;
       } dp;
       struct {
	 Int  ClTrail;
	 Int  ClENV;
	 Int  ClRefs;
	 struct yami *ClBase;
	 CELL  next;
       } EC;
       struct {
	 Functor             f;
	 Int                 a;
	 CELL next;
       } f;
       struct {
	 Functor             f;
	 CODEADDR            l1;
	 CODEADDR            l2;
	 CELL next;
       } fll;
       struct {
	 wamreg               x;
	 struct yami         *f;
	 CELL next;
       } fx;
       struct {
	 yslot                y;
	 struct yami         *f;
	 CELL next;
       } fy;
       struct {
	 struct logic_upd_index  *I;
	 struct yami             *l1;
	 struct yami             *l2;
	 COUNT                    s;
	 CELL next;
       } Ill;
       struct {
	 struct yami   *l;
	 CELL next;
       } l;
       struct {
#ifdef YAPOR
         unsigned int        or_arg;
#endif /* YAPOR */
#ifdef TABLING
         struct table_entry *te; /* pointer to table entry */
#endif /* TABLING */
	 COUNT               s;
	 struct pred_entry  *p;
	 struct yami              *d;
	 CELL next;
       } ld;
       struct {
#ifdef YAPOR
         unsigned int        or_arg;
#endif /* YAPOR */
#ifdef TABLING
         struct table_entry *te; /* pointer to table entry */
#endif /* TABLING */
	 COUNT               s;
	 struct pred_entry  *p;
	 struct yami        *d;
	 struct yami        *bl;
	 CELL next;
       } ldl;
       struct {
	 CODEADDR            l;
	 SMALLUNSGN          flags;
	 CELL next;
       } lf;
       struct {
#ifdef YAPOR
         unsigned int        or_arg;
#endif /* YAPOR */
#ifdef TABLING
         struct table_entry *te; /* pointer to table entry */
#endif /* TABLING */
	 COUNT               s;
	 struct pred_entry  *p;
	 CPredicate          f;
	 COUNT               extra;
	 CELL next;
       } lds;
       struct {
	 struct yami               *l1;
	 struct yami               *l2;
	 struct yami               *l3;
	 CELL next;
       } lll;
       struct {
#ifdef YAPOR
         unsigned int        or_arg;
#endif /* YAPOR */
#ifdef TABLING
         struct table_entry *te; /* pointer to table entry */
#endif /* TABLING */
	 COUNT               s;
	 struct pred_entry  *p;
	 struct yami        *l1;
	 struct yami        *l2;
	 struct yami        *l3;
	 CELL next;
       } slll;
       struct {
	 struct yami               *l1;
	 struct yami               *l2;
	 struct yami               *l3;
	 struct yami               *l4;
	 CELL next;
       } llll;
       struct {
	 wamreg                     x;
	 struct yami               *l1;
	 struct yami               *l2;
	 struct yami               *l3;
	 struct yami               *l4;
	 CELL next;
       } xllll;
       struct {
	 COUNT                      s;
	 struct yami               *l1;
	 struct yami               *l2;
	 struct yami               *l3;
	 struct yami               *l4;
	 CELL next;
       } sllll;
       struct {
	 struct pred_entry    *p;
	 struct yami          *f;
	 wamreg                x1;
	 wamreg                x2;
	 wamreg                flags;
	 CELL next;
       } llxx;
       struct {
	 struct pred_entry    *p;
	 struct yami          *f;
	 wamreg                x;
	 yslot                 y;
	 wamreg                flags;
	 CELL next;
       } llxy;
       struct {
	 struct pred_entry    *p;
	 struct yami          *f;
	 wamreg                y1;
	 yslot                 y2;
	 wamreg                flags;
	 CELL next;
       } llyy;
       struct {
	 OPCODE              pop;
	 struct yami               *l1;
	 struct yami               *l2;
	 struct yami               *l3;
	 struct yami               *l4;
	 CELL next;
       } ollll;
       struct {
	 OPCODE              opcw;
	 CELL next;
       } o;
       struct {
	 OPCODE              opcw;
	 CELL                c;
	 CELL next;
       } oc;
       struct {
	 OPCODE              opcw;
	 Functor             f;
	 Int                 a;
	 CELL next;
       } of;
       struct {
	 OPCODE              opcw;
	 COUNT               s;
	 CELL                c;
	 CELL next;
       } osc;
       struct {
	 OPCODE              opcw;
	 COUNT               s;
	 CELL next;
       } os;
       struct {
	 OPCODE              opcw;
	 wamreg                x;
	 CELL next;
       } ox;
       struct {
	 OPCODE              opcw;
	 wamreg                xl;
	 wamreg                xr;
	 CELL next;
       } oxx;
       struct {
	 OPCODE              opcw;
	 yslot                y;
	 CELL next;
       } oy;
       struct {
	 struct pred_entry   *p;
	 CELL next;
       } p;
       struct {
	 COUNT               s;
	 CELL next;
       } s;
       struct {
	 COUNT               s;
	 struct pred_entry  *p;
	 CELL next;
       } sp;
       struct {
	 COUNT               s;
	 CELL                c;
	 CELL next;
       } sc;
       struct {
	 COUNT               s;
	 CPredicate          d;
	 struct yami        *l;
	 struct pred_entry  *p;
	 CELL next;
       } sdl;
       struct {
	 COUNT               s;
	 struct yami        *l;
	 CELL next;
       } sl;
       struct {
#ifdef YAPOR
         unsigned int        or_arg;
#endif /* YAPOR */
	 COUNT               s;
	 CELL               *bmap;
	 union {
	   struct yami *l;
	   struct pred_entry  *p;
	   Term  mod;
	 } sla_u;
         struct pred_entry  *p0;
	 CELL next;
       } sla; /* also check env for yes and trustfail code before making any changes */
       struct {
	 wamreg                x;
	 CELL next;
       } x;
       struct {
	 wamreg                x;
	 CELL                c;
	 CELL next;
       } xc;
       struct {
	 wamreg                x;
	 Functor             f;
	 Int                 a;
	 CELL next;
       } xf;
       struct {
	 wamreg                x;
	 struct yami	       *l;
	 CELL next;
       } xl; 
      struct {
	 wamreg                xl;
	 wamreg                xr;
	 CELL next;
       } xx;
       struct {
	 wamreg                x;
	 wamreg                x1;
	 wamreg                x2;
	 CELL next;
       } xxx;
       struct {
	 wamreg                x;
	 Int                 c;
	 wamreg                xi;
	 CELL next;
       } xcx, xxc;
       struct {
	 wamreg                x;
	 yslot                y;
	 CELL next;
       } xy;
       struct {
	 wamreg                x;
	 yslot                y2;
	 wamreg                x1;
	 CELL next;
       } xyx;
       struct {
	 yslot                y;
	 CELL next;
       } y;
       struct {
	 yslot                y;
	 wamreg                x;
	 CELL next;
       } yx;
       struct {
	 yslot                y;
	 wamreg                x1;
	 wamreg                x2;
	 CELL next;
       } yxx;
       struct {
	 yslot                y1;
	 yslot                y2;
	 wamreg                x;
	 CELL next;
       } yyx;
       struct {
	 yslot                y;
	 yslot                y1;
	 yslot                y2;
	 CELL next;
       } yyy;
       struct {
	 yslot                y;
	 Int                 c;
	 wamreg                xi;
	 CELL next;
       } ycx, yxc;
     } u;
} yamop;

typedef yamop yamopp;

#define OPCR                opc
#define OPCW                u.ox.opcw


#define NEXTOP(V,TYPE)    ((yamop *)(&((V)->u.TYPE.next)))

#define PREVOP(V,TYPE)    ((yamop *)((CODEADDR)(V)-(CELL)NEXTOP((yamop *)NULL,TYPE)))

#if defined(TABLING) || defined(SBA)
typedef struct trail_frame {
  Term term;
  CELL value;
} *tr_fr_ptr;

#define TrailTerm(X)   ((X)->term)
#define TrailVal(X)    ((X)->value)
#else
typedef Term *tr_fr_ptr;

#define TrailTerm(X)   (*(X))
#define TrailVal(X)    OOOOOOPS: this program should not compile
#endif /* TABLING || SBA  */


/*
   Choice Point Structure

   6 fixed fields (TR,AP,H,B,ENV,CP) plus arguments

*/
typedef struct choicept {
  tr_fr_ptr cp_tr;
  CELL *cp_h;
  struct choicept *cp_b;
#ifdef DEPTH_LIMIT
  CELL cp_depth;
#endif /* DEPTH_LIMIT */
  yamop *cp_cp;
#ifdef YAPOR
  int cp_lub;           /* local untried branches */
  struct or_frame *cp_or_fr;  /* or-frame pointer */
#endif /* YAPOR */
  yamop *cp_ap;
#if MIN_ARRAY == 0
  CELL *cp_env;
  /* GNUCC understands empty arrays */
  CELL cp_args[MIN_ARRAY];
#define cp_a1		cp_args[0]
#define cp_a2		cp_args[1]
#define cp_a3		cp_args[2]
#define cp_a4		cp_args[3]
#define cp_a5		cp_args[4]
#define cp_a6		cp_args[5]
#define cp_a7		cp_args[6]
#define cp_a8		cp_args[7]
#define EXTRA_CBACK_ARG(Arity,Offset)  B->cp_args[(Arity)+(Offset)-1]
#else
  /* Otherwise, we need a very dirty trick to access the arguments */
  union {
    CELL *cp_uenv;
    CELL  cp_args[1];
  } cp_last;
#define cp_env		cp_last.cp_uenv
#define cp_a1		cp_last.cp_args[1]
#define cp_a2		cp_last.cp_args[2]
#define cp_a3		cp_last.cp_args[3]
#define cp_a4		cp_last.cp_args[4]
#define cp_a5		cp_last.cp_args[5]
#define cp_a6		cp_last.cp_args[6]
#define cp_a7		cp_last.cp_args[7]
#define cp_a8		cp_last.cp_args[8]
#define EXTRA_CBACK_ARG(Arity,Offset)  B->cp_last.cp_args[(Arity)+(Offset)]
#endif
} *choiceptr;

/* This has problems with \+ \+ a, !, b. */
#define SHOULD_CUT_UP_TO(X,Y)  ((X) != (Y))
/* #define SHOULD_CUT_UP_TO(X,Y)  ((X)  (Y)) */

#ifdef SBA
#define SHARED_CP(CP)  ((CP) >= B_FZ || (CP) < (choiceptr)H_FZ)

#define YOUNGER_CP(CP1, CP2)                                                                    \
        (SHARED_CP(CP1) ?                                                                       \
          (SHARED_CP(CP2) ? OrFr_depth((CP1)->cp_or_fr) > OrFr_depth((CP2)->cp_or_fr) : FALSE)  \
        :                                                                                    \
          (SHARED_CP(CP2) ? TRUE : CP1 < CP2)                                                   \
        )

#define EQUAL_OR_YOUNGER_CP(CP1, CP2)                                                            \
        (SHARED_CP(CP1) ?                                                                        \
          (SHARED_CP(CP2) ? OrFr_depth((CP1)->cp_or_fr) >= OrFr_depth((CP2)->cp_or_fr) : FALSE)  \
        :                                                                                     \
          (SHARED_CP(CP2) ? TRUE : CP1 <= CP2)                                                   \
        )
#else /* ENV_COPY || ACOW */
#define YOUNGER_CP(CP1, CP2)           ((CP1) <  (CP2))
#define EQUAL_OR_YOUNGER_CP(CP1, CP2)  ((CP1) <= (CP2))
#endif /* SBA */

/*
   Environment Structure (CP, E, and CUT_B). Yap always saves the B
   where to cut to, even if not needed.
*/
#define E_CP		-1
#define E_E		-2
#define E_CB		-3
#ifdef TABLING
#define E_B		-4
#ifdef  DEPTH_LIMIT
#define E_DEPTH         -5
#define EnvSizeInCells   5
#else
#define EnvSizeInCells   4
#endif  /* DEPTH_LIMIT */
#else   /* TABLING */
#ifdef  DEPTH_LIMIT
#define E_DEPTH         -4
#define EnvSizeInCells   4
#else
#define EnvSizeInCells   3
#endif  /* DEPTH_LIMIT */
#endif  /* TABLING */

#if MSHIFTOFFS
#define FixedEnvSize		EnvSizeInCells
#else
#define FixedEnvSize		(EnvSizeInCells*sizeof(CELL))
#endif
#define RealEnvSize	(EnvSizeInCells*sizeof(CELL))

#define ENV_Size(cp)       (((yamop *)((CODEADDR)(cp) - (CELL)NEXTOP((yamop *)NULL,sla)))->u.sla.s)
#define ENV_ToP(cp)        (((yamop *)((CODEADDR)(cp) - (CELL)NEXTOP((yamop *)NULL,sla)))->u.sla.sla_u.p)
#define ENV_ToOp(cp)       (((yamop *)((CODEADDR)(cp) - (CELL)NEXTOP((yamop *)NULL,sla)))->opc)
#define EnvSize(cp)        ((-ENV_Size(cp))/(OPREG)sizeof(CELL))
#define EnvBMap(p)         (((yamop *)((CODEADDR)(p) - (CELL)NEXTOP((yamop *)NULL,sla)))->u.sla.bmap)
#define EnvPreg(p)         (((yamop *)((CODEADDR)(p) - (CELL)NEXTOP((yamop *)NULL,sla)))->u.sla.p0)

/* access to instructions */

#if USE_THREADED_CODE
extern void **Yap_ABSMI_OPCODES;

#define absmadr(i) ((OPCODE)(Yap_ABSMI_OPCODES[(i)]))
#else
#define absmadr(i) ((OPCODE)(i))
#endif

/* used to find out how many instructions of each kind are executed */
#ifdef ANALYST
extern int Yap_opcount[_std_top+1];
#endif /* ANALYST */

#if DEPTH_LIMIT
/*
  Make this into an even number so that the system will know
   it should ignore the depth limit
*/   
#define RESET_DEPTH() DEPTH = MkIntTerm(MAX_ABS_INT-1)
#else

#endif


