text: /*
  ** Bytecode instruction format.
  ** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
  */
  
  #ifndef _LJ_BC_H
  #define _LJ_BC_H
  
  #include "lj_def.h"
  #include "lj_arch.h"
  
  /* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit:
  **
  ** +----+----+----+----+
  ** | B  | C  | A  | OP | Format ABC
  ** +----+----+----+----+
  ** |    D    | A  | OP | Format AD
  ** +--------------------
  ** MSB               LSB
  **
  ** In-memory instructions are always stored in host byte order.
  */
  
  /* Operand ranges and related constants. */
  #define BCMAX_A		0xff
  #define BCMAX_B		0xff
  #define BCMAX_C		0xff
  #define BCMAX_D		0xffff
  #define BCBIAS_J	0x8000
  #define NO_REG		BCMAX_A
  #define NO_JMP		(~(BCPos)0)
  
  /* Macros to get instruction fields. */
  #define bc_op(i)	((BCOp)((i)&0xff))
  #define bc_a(i)		((BCReg)(((i)>>8)&0xff))
  #define bc_b(i)		((BCReg)((i)>>24))
  #define bc_c(i)		((BCReg)(((i)>>16)&0xff))
  #define bc_d(i)		((BCReg)((i)>>16))
  #define bc_j(i)		((ptrdiff_t)bc_d(i)-BCBIAS_J)
  
  /* Macros to set instruction fields. */
  #define setbc_byte(p, x, ofs) \
    ((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x)
  #define setbc_op(p, x)	setbc_byte(p, (x), 0)
  #define setbc_a(p, x)	setbc_byte(p, (x), 1)
  #define setbc_b(p, x)	setbc_byte(p, (x), 3)
  #define setbc_c(p, x)	setbc_byte(p, (x), 2)
  #define setbc_d(p, x) \
    ((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x)
  #define setbc_j(p, x)	setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J))
  
  /* Macros to compose instructions. */
  #define BCINS_ABC(o, a, b, c) \
    (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16))
  #define BCINS_AD(o, a, d) \
    (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16))
  #define BCINS_AJ(o, a, j)	BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J))
  
  /* Bytecode instruction definition. Order matters, see below.
  **
  ** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod)
  **
  ** The opcode name suffixes specify the type for RB/RC or RD:
  ** V = variable slot
  ** S = string const
  ** N = number const
  ** P = primitive type (~itype)
  ** B = unsigned byte literal
  ** M = multiple args/results
  */
  #define BCDEF(_) \
    /* Comparison ops. ORDER OPR. */ \
    _(ISLT,	var,	___,	var,	lt) \
    _(ISGE,	var,	___,	var,	lt) \
    _(ISLE,	var,	___,	var,	le) \
    _(ISGT,	var,	___,	var,	le) \
    \
    _(ISEQV,	var,	___,	var,	eq) \
    _(ISNEV,	var,	___,	var,	eq) \
    _(ISEQS,	var,	___,	str,	eq) \
    _(ISNES,	var,	___,	str,	eq) \
    _(ISEQN,	var,	___,	num,	eq) \
    _(ISNEN,	var,	___,	num,	eq) \
    _(ISEQP,	var,	___,	pri,	eq) \
    _(ISNEP,	var,	___,	pri,	eq) \
    \
    /* Unary test and copy ops. */ \
    _(ISTC,	dst,	___,	var,	___) \
    _(ISFC,	dst,	___,	var,	___) \
    _(IST,	___,	___,	var,	___) \
    _(ISF,	___,	___,	var,	___) \
    _(ISTYPE,	var,	___,	lit,	___) \
    _(ISNUM,	var,	___,	lit,	___) \
    \
    /* Unary ops. */ \
    _(MOV,	dst,	___,	var,	___) \
    _(NOT,	dst,	___,	var,	___) \
    _(UNM,	dst,	___,	var,	unm) \
    _(LEN,	dst,	___,	var,	len) \
    \
    /* Binary ops. ORDER OPR. VV last, POW must be next. */ \
    _(ADDVN,	dst,	var,	num,	add) \
    _(SUBVN,	dst,	var,	num,	sub) \
    _(MULVN,	dst,	var,	num,	mul) \
    _(DIVVN,	dst,	var,	num,	div) \
    _(MODVN,	dst,	var,	num,	mod) \
    \
    _(ADDNV,	dst,	var,	num,	add) \
    _(SUBNV,	dst,	var,	num,	sub) \
    _(MULNV,	dst,	var,	num,	mul) \
    _(DIVNV,	dst,	var,	num,	div) \
    _(MODNV,	dst,	var,	num,	mod) \
    \
    _(ADDVV,	dst,	var,	var,	add) \
    _(SUBVV,	dst,	var,	var,	sub) \
    _(MULVV,	dst,	var,	var,	mul) \
    _(DIVVV,	dst,	var,	var,	div) \
    _(MODVV,	dst,	var,	var,	mod) \
    \
    _(POW,	dst,	var,	var,	pow) \
    _(CAT,	dst,	rbase,	rbase,	concat) \
    \
    /* Constant ops. */ \
    _(KSTR,	dst,	___,	str,	___) \
    _(KCDATA,	dst,	___,	cdata,	___) \
    _(KSHORT,	dst,	___,	lits,	___) \
    _(KNUM,	dst,	___,	num,	___) \
    _(KPRI,	dst,	___,	pri,	___) \
    _(KNIL,	base,	___,	base,	___) \
    \
    /* Upvalue and function ops. */ \
    _(UGET,	dst,	___,	uv,	___) \
    _(USETV,	uv,	___,	var,	___) \
    _(USETS,	uv,	___,	str,	___) \
    _(USETN,	uv,	___,	num,	___) \
    _(USETP,	uv,	___,	pri,	___) \
    _(UCLO,	rbase,	___,	jump,	___) \
    _(FNEW,	dst,	___,	func,	gc) \
    \
    /* Table ops. */ \
    _(TNEW,	dst,	___,	lit,	gc) \
    _(TDUP,	dst,	___,	tab,	gc) \
    _(GGET,	dst,	___,	str,	index) \
    _(GSET,	var,	___,	str,	newindex) \
    _(TGETV,	dst,	var,	var,	index) \
    _(TGETS,	dst,	var,	str,	index) \
    _(TGETB,	dst,	var,	lit,	index) \
    _(TGETR,	dst,	var,	var,	index) \
    _(TSETV,	var,	var,	var,	newindex) \
    _(TSETS,	var,	var,	str,	newindex) \
    _(TSETB,	var,	var,	lit,	newindex) \
    _(TSETM,	base,	___,	num,	newindex) \
    _(TSETR,	var,	var,	var,	newindex) \
    \
    /* Calls and vararg handling. T = tail call. */ \
    _(CALLM,	base,	lit,	lit,	call) \
    _(CALL,	base,	lit,	lit,	call) \
    _(CALLMT,	base,	___,	lit,	call) \
    _(CALLT,	base,	___,	lit,	call) \
    _(ITERC,	base,	lit,	lit,	call) \
    _(ITERN,	base,	lit,	lit,	call) \
    _(VARG,	base,	lit,	lit,	___) \
    _(ISNEXT,	base,	___,	jump,	___) \
    \
    /* Returns. */ \
    _(RETM,	base,	___,	lit,	___) \
    _(RET,	rbase,	___,	lit,	___) \
    _(RET0,	rbase,	___,	lit,	___) \
    _(RET1,	rbase,	___,	lit,	___) \
    \
    /* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \
    _(FORI,	base,	___,	jump,	___) \
    _(JFORI,	base,	___,	jump,	___) \
    \
    _(FORL,	base,	___,	jump,	___) \
    _(IFORL,	base,	___,	jump,	___) \
    _(JFORL,	base,	___,	lit,	___) \
    \
    _(ITERL,	base,	___,	jump,	___) \
    _(IITERL,	base,	___,	jump,	___) \
    _(JITERL,	base,	___,	lit,	___) \
    \
    _(LOOP,	rbase,	___,	jump,	___) \
    _(ILOOP,	rbase,	___,	jump,	___) \
    _(JLOOP,	rbase,	___,	lit,	___) \
    \
    _(JMP,	rbase,	___,	jump,	___) \
    \
    /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \
    _(FUNCF,	rbase,	___,	___,	___) \
    _(IFUNCF,	rbase,	___,	___,	___) \
    _(JFUNCF,	rbase,	___,	lit,	___) \
    _(FUNCV,	rbase,	___,	___,	___) \
    _(IFUNCV,	rbase,	___,	___,	___) \
    _(JFUNCV,	rbase,	___,	lit,	___) \
    _(FUNCC,	rbase,	___,	___,	___) \
    _(FUNCCW,	rbase,	___,	___,	___)
  
  /* Bytecode opcode numbers. */
  typedef enum {
  #define BCENUM(name, ma, mb, mc, mt)	BC_##name,
  BCDEF(BCENUM)
  #undef BCENUM
    BC__MAX
  } BCOp;
  
  LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV);
  LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV);
  LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES);
  LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN);
  LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP);
  LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE);
  LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT);
  LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT);
  LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC);
  LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM);
  LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT);
  LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET);
  LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL);
  LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL);
  LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL);
  LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL);
  LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP);
  LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP);
  LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF);
  LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF);
  LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV);
  LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV);
  
  /* This solves a circular dependency problem, change as needed. */
  #define FF_next_N	4
  
  /* Stack slots used by FORI/FORL, relative to operand A. */
  enum {
    FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT
  };
  
  /* Bytecode operand modes. ORDER BCMode */
  typedef enum {
    BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv,  /* Mode A must be <= 7 */
    BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata,
    BCM_max
  } BCMode;
  #define BCM___		BCMnone
  
  #define bcmode_a(op)	((BCMode)(lj_bc_mode[op] & 7))
  #define bcmode_b(op)	((BCMode)((lj_bc_mode[op]>>3) & 15))
  #define bcmode_c(op)	((BCMode)((lj_bc_mode[op]>>7) & 15))
  #define bcmode_d(op)	bcmode_c(op)
  #define bcmode_hasd(op)	((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3))
  #define bcmode_mm(op)	((MMS)(lj_bc_mode[op]>>11))
  
  #define BCMODE(name, ma, mb, mc, mm) \
    (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
  #define BCMODE_FF	0
  
  static LJ_AINLINE int bc_isret(BCOp op)
  {
    return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
  }
  
  LJ_DATA const uint16_t lj_bc_mode[];
  LJ_DATA const uint16_t lj_bc_ofs[];
  
  #endif
  