/*
 * Copyright (C) 2012-2023  Free Software Foundation, Inc.
 *
 * This file is part of GNU lightning.
 *
 * GNU lightning is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GNU lightning 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 Lesser General Public
 * License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#ifndef _jit_private_h
#define _jit_private_h

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>
#include <limits.h>
#include <stdio.h>

#ifdef STDC_HEADERS
#  include <stddef.h>
#else
#  if !defined(offsetof)
#    define offsetof(type, field) ((char *)&((type *)0)->field - (char *)0)
#  endif
#endif

#if defined(__GNUC__)
#  define maybe_unused		__attribute__ ((unused))
#  define unlikely(exprn)	__builtin_expect(!!(exprn), 0)
#  define likely(exprn)		__builtin_expect(!!(exprn), 1)
#  if (__GNUC__ >= 4)
#    define PUBLIC		__attribute__ ((visibility("default")))
#    define HIDDEN		__attribute__ ((visibility("hidden")))
#  else
#    define PUBLIC		/**/
#    define HIDDEN		/**/
#  endif
#else
#  define maybe_unused		/**/
#  define unlikely(exprn)	exprn
#  define likely(exprn)		exprn
#  define PUBLIC		/**/
#  define HIDDEN		/**/
#endif

#if PACKED_STACK || STRONG_TYPE_CHECKING
#  define assert_arg_type(code, expect)					\
    do assert((code) == (expect)); while (0)
#  define assert_putarg_type(code, expect)				\
    do									\
	assert((((code) - jit_code_putargr_c) >> 2) ==			\
	       ((expect) - jit_code_arg_c));				\
    while (0)
#else
#  define assert_arg_type(code, expect)					\
    do assert((int)(code) == (int)(expect) ||				\
	      (code) == jit_code_arg); while (0)
#  define assert_putarg_type(code, expect)				\
    do									\
	assert(((((code) - jit_code_putargr_c) >> 2) ==			\
	       ((expect) - jit_code_arg_c)) ||				\
	       ((code) == jit_code_arg));				\
    while (0)
#endif

#define rc(value)		jit_class_##value
#define rn(reg)			(jit_regno(_rvs[jit_regno(reg)].spec))

#if defined(__i386__) || defined(__x86_64__)
#  define JIT_SP		_RSP
#  define JIT_RET		_RAX
#  if __X32
#    define JIT_FRET		_ST0
typedef jit_uint32_t		jit_regset_t;
#  else
#    if __CYGWIN__ || _WIN32
#      define JIT_RA0		_RCX
#    else
#      define JIT_RA0		_RDI
#    endif
#    define JIT_FA0		_XMM0
#    define JIT_FRET		_XMM0
typedef jit_uint64_t		jit_regset_t;
#  endif
#elif defined(__mips__)
#  define JIT_RA0		_A0
#  define JIT_FA0		_F12
#  define JIT_SP		_SP
#  define JIT_RET		_V0
#  define JIT_FRET		_F0
typedef jit_uint64_t		jit_regset_t;
#elif defined(__arm__)
#  define JIT_RA0		_R0
#  define JIT_FA0		_D0
#  define JIT_SP		_R13
#  define JIT_RET		_R0
#  if defined(__ARM_PCS_VFP)
#    define JIT_FRET		_D0
#  else
#    define JIT_FRET		_R0
#  endif
typedef jit_uint64_t		jit_regset_t;
#elif defined(__powerpc__)
#  define JIT_RA0		_R3
#  define JIT_FA0		_F1
#  define JIT_SP		_R1
#  define JIT_RET		_R3
#  define JIT_FRET		_F1
typedef jit_uint64_t		jit_regset_t;
#elif defined(__sparc__)
#  define JIT_SP		_SP
#  define JIT_RET		_I0
#  define JIT_FRET		_F0
#  if __WORDSIZE == 32
typedef jit_uint64_t		jit_regset_t;
#  else
typedef struct {
    jit_uint64_t	rl;
    jit_uint64_t	rh;
} jit_regset_t;
#  endif
#elif defined(__ia64__)
#  define JIT_SP		_R12
#  define JIT_RET		_R8
#  define JIT_FRET		_F8
typedef struct {
    jit_uint64_t	rl;
    jit_uint64_t	rh;
    jit_uint64_t	fl;
    jit_uint64_t	fh;
} jit_regset_t;
#elif defined(__hppa__)
#  define JIT_SP		_R30
#  define JIT_RET		_R28
#  define JIT_FRET		_F4
typedef jit_uint64_t		jit_regset_t;
#elif defined(__aarch64__)
#  define JIT_RA0		_R0
#  define JIT_FA0		_V0
#  define JIT_SP		_SP
#  define JIT_RET		_R0
#  define JIT_FRET		_V0
typedef jit_uint64_t		jit_regset_t;
#elif defined(__s390__) || defined(__s390x__)
#  define JIT_SP		_R15
#  define JIT_RET		_R2
#  define JIT_FRET		_F0
typedef jit_uint32_t		jit_regset_t;
#elif defined(__alpha__)
#  define JIT_SP		_SP
#  define JIT_RET		_V0
#  define JIT_FRET		_F0
typedef jit_uint64_t		jit_regset_t;
#elif defined(__riscv)
#  define JIT_RA0		_A0
#  define JIT_FA0		_FA0
#  define JIT_SP		_SP
#  define JIT_RET		_A0
#  define JIT_FRET		_FA0
typedef jit_uint64_t		jit_regset_t;
#elif defined(__loongarch__)
#  define JIT_RA0		_A0
#  define JIT_FA0		_FA0
#  define JIT_SP		_SP
#  define JIT_RET		_A0
#  define JIT_FRET		_FA0
typedef jit_uint64_t		jit_regset_t;
#endif

#define jit_data(u,v,w)		_jit_data(_jit,u,v,w)
extern jit_node_t *_jit_data(jit_state_t*, const void*,
			     jit_word_t, jit_int32_t);

#define jit_size(vector)	(sizeof(vector) / sizeof((vector)[0]))

#define jit_reg_free_p(regno)						\
    (!jit_regset_tstbit(&_jitc->reglive, regno) &&			\
     !jit_regset_tstbit(&_jitc->regarg, regno) &&			\
     !jit_regset_tstbit(&_jitc->regsav, regno))

#define jit_reg_free_if_spill_p(regno)					\
    (!jit_regset_tstbit(&_jitc->regarg, regno) &&			\
     !jit_regset_tstbit(&_jitc->regsav, regno))

#define jit_code_inc_synth(code)					\
    do {								\
	(void)jit_new_node(code);					\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth(name)						\
    jit_code_inc_synth(jit_code_##name)
#define jit_code_inc_synth_w(code, u)					\
    do {								\
	(void)jit_new_node_w(code, u);					\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_w(name, u)					\
    jit_code_inc_synth_w(jit_code_##name, u)
#define jit_code_inc_synth_f(code, u)					\
    do {								\
	(void)jit_new_node_f(code, u);					\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_f(name, u)					\
    jit_code_inc_synth_f(jit_code_##name, u)
#define jit_code_inc_synth_d(code, u)					\
    do {								\
	(void)jit_new_node_d(code, u);					\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_d(name, u)					\
    jit_code_inc_synth_d(jit_code_##name, u)
#define jit_code_inc_synth_ww(code, u, v)				\
    do {								\
	(void)jit_new_node_ww(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_ww(name, u, v)					\
    jit_code_inc_synth_ww(jit_code_##name, u, v)
#define jit_code_inc_synth_wp(code, u, v)				\
    do {								\
	(void)jit_new_node_wp(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_wp(name, u, v)					\
    jit_code_inc_synth_wp(jit_code_##name, u, v)
#define jit_code_inc_synth_fp(code, u, v)				\
    do {								\
	(void)jit_new_node_fp(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_fp(name, u, v)					\
    jit_code_inc_synth_fp(jit_code_##name, u, v)
#define jit_code_inc_synth_dp(code, u, v)				\
    do {								\
	(void)jit_new_node_dp(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_dp(name, u, v)					\
    jit_code_inc_synth_dp(jit_code_##name, u, v)
#define jit_inc_synth_wf(name, u, v)					\
    jit_code_inc_synth_wf(jit_code_##name, u, v)
#define jit_code_inc_synth_wf(code, u, v)				\
    do {								\
	(void)jit_new_node_wf(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_wqf(name, u, v, w, x)				\
    do {								\
	(void)jit_new_node_wqf(jit_code_##name, u, v, w, x);		\
	jit_synth_inc();						\
    } while (0)
#define jit_inc_synth_wd(name, u, v)					\
    jit_code_inc_synth_wd(jit_code_##name, u, v)
#define jit_inc_synth_wqd(name, u, v, w, x)				\
    do {								\
	(void)jit_new_node_wqd(jit_code_##name, u, v, w, x);		\
	jit_synth_inc();						\
    } while (0)
#define jit_code_inc_synth_wd(code, u, v)				\
    do {								\
	(void)jit_new_node_wd(code, u, v);				\
	jit_synth_inc();						\
    } while (0)
#define jit_dec_synth()		jit_synth_dec()

#define jit_link_alist(node)						\
    do {								\
	node->link = _jitc->function->alist;				\
	_jitc->function->alist = node;					\
    } while (0)
#define jit_check_frame()						\
    do {								\
	if (!_jitc->function->need_frame) {				\
	    _jitc->again = 1;						\
	    _jitc->function->need_frame = 1;				\
	}								\
    } while (0)
#define jit_diffsize()	(stack_framesize - _jitc->framesize)
#define jit_framesize()	(stack_framesize - jit_diffsize())
#define jit_selfsize()	(_jitc->function->self.size - jit_diffsize())

#define jit_link_prolog()						\
    do {								\
	_jitc->tail->link = _jitc->function->prolog->link;		\
	_jitc->function->prolog->link = _jitc->tail;			\
    } while (0)
#define jit_link_prepare()						\
    do {								\
	_jitc->tail->link = _jitc->prepare->link;			\
	_jitc->prepare->link = _jitc->tail;				\
    } while (0)
#define jit_link_reverse(where)						\
    do {								\
	jit_node_t	*tmp, *tail = 0;				\
	while (where) {							\
	    tmp = (where)->link;					\
	    (where)->link = tail;					\
	    tail = where;						\
	    where = tmp;						\
	}								\
	where = tail;							\
    } while (0);

/*
 * Private jit_class bitmasks
 */
#define jit_class_named		0x00400000	/* hit must be the named reg */
#define jit_class_nospill	0x00800000	/* hint to fail if need spill */
#define jit_class_sft		0x01000000	/* not a hardware register */
#define jit_class_rg8		0x04000000	/* x86 8 bits */
#define jit_class_xpr		0x80000000	/* float / vector */
/* Used on sparc64 where %f0-%f31 can be encode for single float
 * but %f32 to %f62 only as double precision */
#define jit_class_sng		0x00010000	/* Single precision float */
#define jit_class_dbl		0x00020000	/* Only double precision float */
#define jit_regno_patch		0x00008000	/* this is a register
						 * returned by a "user" call
						 * to jit_get_reg() */

#define jit_call_default	0
#define jit_call_varargs	1

#define jit_kind_register	1
#define jit_kind_code		2
#define jit_kind_word		3
#define jit_kind_float32	4
#define jit_kind_float64	5

#define jit_cc_a0_reg		0x00000001	/* arg0 is a register */
#define jit_cc_a0_chg		0x00000002	/* arg0 is modified */
#define jit_cc_a0_jmp		0x00000004	/* arg0 is a jump target */
#define jit_cc_a0_rlh		0x00000008	/* arg0 is a register pair */
#define jit_cc_a0_int		0x00000010	/* arg0 is immediate word */
#define jit_cc_a0_flt		0x00000020	/* arg0 is immediate float */
#define jit_cc_a0_dbl		0x00000040	/* arg0 is immediate double */
#define jit_cc_a0_arg		0x00000080	/* arg1 is an argument int id */
#define jit_cc_a0_cnd		0x00000100	/* arg1 is a conditinally set register */
#define jit_cc_a1_reg		0x00000200	/* arg1 is a register */
#define jit_cc_a1_chg		0x00000400	/* arg1 is modified */
#define jit_cc_a1_int		0x00000800	/* arg1 is immediate word */
#define jit_cc_a1_flt		0x00001000	/* arg1 is immediate float */
#define jit_cc_a1_dbl		0x00002000	/* arg1 is immediate double */
#define jit_cc_a1_arg		0x00004000	/* arg1 is an argument node */
#define jit_cc_a1_rlh		0x00008000	/* arg1 is a register pair */
#define jit_cc_a2_reg		0x00010000	/* arg2 is a register */
#define jit_cc_a2_chg		0x00020000	/* arg2 is modified */
#define jit_cc_a2_int		0x00100000	/* arg2 is immediate word */
#define jit_cc_a2_flt		0x00200000	/* arg2 is immediate float */
#define jit_cc_a2_dbl		0x00400000	/* arg2 is immediate double */
#define jit_cc_a2_rlh		0x00800000	/* arg2 is a register pair */

#if __ia64__ || (__sparc__ && __WORDSIZE == 64)
extern void
jit_regset_com(jit_regset_t*, jit_regset_t*);

extern void
jit_regset_and(jit_regset_t*, jit_regset_t*, jit_regset_t*);

extern void
jit_regset_ior(jit_regset_t*, jit_regset_t*, jit_regset_t*);

extern void
jit_regset_xor(jit_regset_t*, jit_regset_t*, jit_regset_t*);

extern void
jit_regset_set(jit_regset_t*, jit_regset_t*);

extern void
jit_regset_set_mask(jit_regset_t*, jit_int32_t);

extern jit_bool_t
jit_regset_cmp_ui(jit_regset_t*, jit_word_t);

extern void
jit_regset_set_ui(jit_regset_t*, jit_word_t);

extern jit_bool_t
jit_regset_set_p(jit_regset_t*);

extern void
jit_regset_clrbit(jit_regset_t*, jit_int32_t);

extern void
jit_regset_setbit(jit_regset_t*, jit_int32_t);

extern jit_bool_t
jit_regset_tstbit(jit_regset_t*, jit_int32_t);
#  if __sparc__ && __WORDSIZE == 64
#    define jit_regset_new(set)						\
    do { (set)->rl = (set)->rh = 0; } while (0)
#    define jit_regset_del(set)						\
    do { (set)->rl = (set)->rh = 0; } while (0)
#  else
#    define jit_regset_new(set)						\
    do { (set)->rl = (set)->rh = (set)->fl = (set)->fh = 0; } while (0)
#    define jit_regset_del(set)						\
    do { (set)->rl = (set)->rh = (set)->fl = (set)->fh = 0; } while (0)
#  endif
#else
#  define jit_regset_com(u, v)		(*(u) = ~*(v))
#  define jit_regset_and(u, v, w)	(*(u) = *(v) & *(w))
#  define jit_regset_ior(u, v, w)	(*(u) = *(v) | *(w))
#  define jit_regset_xor(u, v, w)	(*(u) = *(v) ^ *(w))
#  define jit_regset_set(u, v)		(*(u) = *(v))
#  define jit_regset_set_mask(u, v)	(*(u) = (1LL << (v)) - 1)
#  define jit_regset_cmp_ui(u, v)	(*(u) != (v))
#  define jit_regset_set_ui(u, v)	(*(u) = (v))
#  define jit_regset_set_p(set)		(*set)
#  define jit_regset_clrbit(set, bit)	(*(set) &= ~(1LL << (bit)))
#  define jit_regset_setbit(set, bit)	(*(set) |= 1LL << (bit))
#  define jit_regset_tstbit(set, bit)	(*(set) & (1LL << (bit)))
#  define jit_regset_new(set)		(*(set) = 0)
#  define jit_regset_del(set)		(*(set) = 0)
#endif
extern unsigned long
jit_regset_scan1(jit_regset_t*, jit_int32_t);

#define jit_reglive_setup()						\
    do {								\
	jit_regset_set_ui(&_jitc->reglive, 0);				\
	jit_regset_set_ui(&_jitc->regmask, 0);				\
    } while (0)

/*
 * Types
 */
typedef union jit_data		jit_data_t;
typedef struct jit_note		jit_note_t;
typedef struct jit_line		jit_line_t;
typedef struct jit_block	jit_block_t;
typedef struct jit_value	jit_value_t;
typedef struct jit_compiler	jit_compiler_t;
typedef struct jit_function	jit_function_t;
typedef struct jit_register	jit_register_t;
#if __arm__
#  if DISASSEMBLER
typedef struct jit_data_info	jit_data_info_t;
#  endif
#elif __riscv
typedef struct jit_const	jit_const_t;
#endif

union jit_data {
    struct {
#if __BYTE_ORDER == __LITTLE_ENDIAN
	jit_int32_t	 l;
	jit_int32_t	 h;
#else
	jit_int32_t	 h;
	jit_int32_t	 l;
#endif
    } q;
    jit_word_t		 w;
    jit_float32_t	 f;
    jit_float64_t	 d;
    jit_pointer_t	 p;
    jit_node_t		*n;
};

struct jit_note {
    jit_uint8_t		*code;
    char		*name;
    jit_line_t		*lines;
    jit_word_t		 length;
    jit_word_t		 size;		/* of code */
};

struct jit_line {
    char		*file;
    jit_int32_t		*linenos;
    jit_int32_t		*offsets;
    jit_word_t		 length;
};

struct jit_node {
    jit_node_t		*next;
    jit_code_t		 code;
    jit_uint16_t	 flag;
    jit_uint16_t	 offset;	/* Used if DEVEL_DISASSEMBLER */
    jit_data_t		 u;
    jit_data_t		 v;
    jit_data_t		 w;
    jit_node_t		*link;
};

struct jit_block {
    jit_node_t		*label;
    jit_regset_t	 reglive;
    jit_regset_t	 regmask;
    jit_bool_t		 again;		/* Flag need to rebuild regset masks
					 * due to changes in live and unknown
					 * state. */
};

struct jit_value {
    jit_int32_t		kind;
    jit_code_t		code;
    jit_data_t		base;
    jit_data_t		disp;
};

typedef struct {
#if __arm__
    jit_word_t		 kind;
#endif
    jit_word_t		 inst;
    jit_node_t		*node;
} jit_patch_t;

#if __arm__ && DISASSEMBLER
struct jit_data_info {
    jit_uword_t		  code;		/* pointer in code buffer */
    jit_word_t		  length;	/* length of constant vector */
};
#elif __riscv && __WORDSIZE == 64
struct jit_const {
    jit_word_t		  value;
    jit_word_t		  address;
    jit_const_t		 *next;
};
#endif

struct jit_function {
    struct {
	jit_int32_t	 argi;
	jit_int32_t	 argf;
	jit_int32_t	 size;
	jit_int32_t	 aoff;
	jit_int32_t	 alen;
	jit_int32_t	 call;
	jit_int32_t	 argn;		/* for debug output */
    } self;
    struct {
	jit_int32_t	 argi;
	jit_int32_t	 argf;
	jit_int32_t	 size;
	jit_int32_t	 call;
    } call;
    jit_node_t		*prolog;
    jit_node_t		*epilog;
    jit_node_t		*alist;
    jit_int32_t		*regoff;
    jit_regset_t	 regset;
    jit_int32_t		 stack;
#if defined(__i386__) || defined(__x86_64__) || \
    defined(__powerpc__) || defined(__sparc__) || \
    defined(__s390__) || defined(__s390x__) || \
    defined(__hppa__) || defined(__alpha__)
    jit_int32_t		 cvt_offset;	/* allocai'd offset for x87<->xmm or
					 * fpr<->gpr transfer using the stack */
#endif

    /* Helper for common jit generation pattern, used in GNU Smalltalk
     * and possibly others, where a static frame layout is required or
     * assumed. */
    jit_int32_t		 frame;
    jit_uint32_t	 define_frame : 1;
    jit_uint32_t	 assume_frame : 1;

    jit_uint32_t	 need_frame : 1;	/* need frame pointer? */
    jit_uint32_t	 need_stack : 1;	/* need stack pointer? */
    jit_uint32_t	 need_return : 1;	/* not a leaf function */

    /* alloca offset offset */
    jit_int32_t		 aoffoff;
    /* uses allocar flag */
    jit_uint32_t	 allocar : 1;

#if __arm__
    /* If will, or might use float registers and vfp is not available.
     * Use the first 64 bytes always, as the access to the virtual float
     * registers use hardcoded instructions that can only reach 64 byte
     * displacements, and to keep code simpler, do not use temporaries. */
    jit_uint32_t	  swf_offset : 1;
    /* If need to call C functions for some operation, or variadic function */
    jit_uint32_t	  save_reg_args : 1;
#endif

    /* varargs state offsets */
    jit_int32_t		 vaoff;		/* offset of jit_va_list */
    jit_int32_t		 vagp;		/* first gp va argument */
    jit_int32_t		 vafp;		/* first fp va argument */
};

/* data used only during jit generation */
struct jit_compiler {
#if __ia64__
    struct {
	jit_uint64_t	  i : 41;
	jit_uint64_t	  t :  4;
    } inst[3];
    jit_regset_t	  regs;		/* changed regs since last stop */
    jit_int32_t		  pred;		/* changed preds last stop */
    jit_int32_t		  ioff;		/* offset in inst vector */
    jit_int32_t		  rout;		/* first output register */
    jit_int32_t		  breg;		/* base register for prolog/epilog */
#endif
#if __mips__
    struct {
	jit_int32_t	  op;		/* pending instruction, candidate
					 * to be inserted in a delay slot */
	jit_bool_t	  pend;		/* non zero if need to emit op */
    } inst;
#endif
#if __mips__ || __ia64__ || __alpha__ || \
	(__sparc__ && __WORDSIZE == 64) || __riscv || __loongarch__
    jit_int32_t		  carry;
#define jit_carry	  _jitc->carry
#endif
    jit_node_t		 *head;
    jit_node_t		 *tail;
    jit_node_t		 *prepare;	/* inside prepare/finish* block */
    jit_uint32_t	  realize : 1;	/* jit_realize() called? */
    jit_uint32_t	  dataset : 1;	/* jit_dataset() called? */
    jit_uint32_t	  done	: 1;	/* emit state finished */
    jit_uint32_t	  emit	: 1;	/* emit state entered */
    jit_uint32_t	  again	: 1;	/* start over emiting function */
    jit_uint32_t	  synth : 8;	/* emiting synthesized instructions */
#if DEBUG
    jit_uint32_t	  getreg : 1;
#endif
    jit_uint32_t	  no_data : 1;
    jit_uint32_t	  no_note : 1;
    /* FIXME undocumented, might be moved to a jit_cpu field or a better
     * configuration api.
     * These are switches to a different unld* or unst*.
     * Defaults are the algorithms that generate shorter code*/
    jit_uint32_t	  unld_algorithm : 1;
    jit_uint32_t	  unst_algorithm : 1;
    jit_int32_t		  framesize;	/* space for callee save registers,
					 * frame pointer and return address */
    jit_int32_t		  reglen;	/* number of registers */
    jit_regset_t	  regarg;	/* cannot allocate */
    jit_regset_t	  regsav;	/* automatic spill only once */
    jit_regset_t	  reglive;	/* known live registers at some point */
    jit_regset_t	  regmask;	/* register mask to update reglive */
    jit_regset_t	  explive;	/* explicitly marked as live */
    struct {
	jit_uint8_t	 *end;
    } code;
    struct {
	jit_uint8_t	 *ptr;
	jit_node_t	**table;	/* very simple hash table */
	jit_word_t	  size;		/* number of vectors in table */
	jit_word_t	  count;	/* number of hash table entries */
	jit_word_t	  offset;	/* offset in bytes in ptr */
    } data;
    jit_node_t		**spill;
    jit_int32_t		 *gen;		/* ssa like "register version" */
    jit_value_t		 *values;	/* temporary jit_value_t vector */
    struct {
	jit_block_t	 *ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } blocks;				/* basic blocks */
    struct {
	jit_patch_t	 *ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } patches;				/* forward patch information */
    jit_function_t	 *function;	/* current function */
    struct {
	jit_function_t	 *ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } functions;			/* prolog/epilogue offsets in code */
    struct {
	jit_node_t	**ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } pool;
    jit_node_t		 *list;
    struct {
	jit_node_t	 *head;		/* first note node */
	jit_node_t	 *tail;		/* linked list insertion */
	/* fields to store temporary state information */
	jit_word_t	  size;
	jit_node_t	 *name;
	jit_node_t	 *note;
	jit_uint8_t	 *base;
    } note;
#if __arm__
    /* prevent using thumb instructions that set flags? */
    jit_uint32_t	  no_set_flags : 1;
#  if DISASSEMBLER
    struct {
	jit_data_info_t	 *ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } data_info;			/* constant pools information */
#  endif
    /* Note that this field is somewhat hackish, but required by most
     * ways to implement jit, unless implementing a pure one function
     * per jit, as most times it needs to start the jit buffer with a
     * jump where the "main" prolog starts, and because the initial
     * code is in "arm mode", need to make an "arm mode" patch on that
     * jump. A good example is the test suite assembler, where most
     * test cases start with a "jmpi main" call. */
    jit_uword_t		  thumb;
    struct {
	jit_uint8_t	 *data;		/* pointer to code */
	jit_word_t	  size;		/* size data */
	jit_word_t	  offset;	/* pending patches */
	jit_word_t	  length;	/* number of pending constants */
	jit_int32_t	  values[1024];	/* pending constants */
	jit_word_t	  patches[2048];
    } consts;
#elif (__powerpc__ && _CALL_AIXDESC) || __ia64__
    /* Keep track of prolog addresses, just for the sake of making
     * jit that starts with a jump to a "main" label work like other
     * backends. */
    struct {
	jit_word_t	 *ptr;
	jit_word_t	  offset;
	jit_word_t	  length;
    } prolog;
    jit_bool_t		  jump;
#elif __riscv && __WORDSIZE == 64
    struct {
	/* Hash table for constants to be resolved and patched */
	struct {
	    jit_const_t	**table;	/* very simple hash table */
	    jit_word_t	  size;		/* number of vectors in table */
	    jit_word_t	  count;	/* number of distinct entries */
	} hash;
	struct {
	    jit_const_t	**ptr;		/* keep a single pointer */
	    jit_const_t	 *list;		/* free list */
	    jit_word_t	  length;	/* length of pool */
	} pool;
	/* Linear list for constants that cannot be encoded easily */
	struct {
	    jit_word_t	 *instrs;	/* list of direct movi instructions */
	    jit_word_t	 *values;	/* list of direct movi constants */
	    jit_word_t	  offset;	/* offset in instrs/values vector */
	    jit_word_t	  length;	/* length of instrs/values vector */
	} vector;
    } consts;
#endif
#if GET_JIT_SIZE
    /* Temporary storage to calculate instructions length */
    jit_word_t		  size;
    /* Global flag for code buffer heuristic size computation */
    jit_word_t		  mult;
    /* Pointer to code to prevent miscalculation if reallocating buffer */
    jit_uint8_t		 *cptr;
#endif
};

#define _jitc				_jit->comp
struct jit_state {
    union {
	jit_uint8_t	 *uc;
	jit_uint16_t	 *us;
	jit_uint32_t	 *ui;
	jit_uint64_t	 *ul;
	jit_word_t	  w;
    } pc;
    struct {
	jit_uint8_t	*ptr;
	jit_word_t	 length;
        /* PROTECTED bytes starting at PTR are mprotect'd. */
        jit_word_t       protected;
    } code;
    struct {
	jit_uint8_t	*ptr;
	jit_word_t	 length;
    } data;
    struct {
	jit_note_t	*ptr;
	jit_word_t	 length;
    } note;
    jit_compiler_t	*comp;
    /* Flags to know if user did set the code and data buffers */
    jit_uint32_t	 user_code	: 1;
    jit_uint32_t	 user_data	: 1;
};

struct jit_register {
    jit_reg_t		 spec;
    char		*name;
};

/*
 * Prototypes
 */
extern void jit_get_cpu(void);

#define jit_init()			_jit_init(_jit)
extern void _jit_init(jit_state_t*);

#define jit_synth_inc()			_jit_synth_inc(_jit)
extern void _jit_synth_inc(jit_state_t*);

#define jit_new_node_no_link(u)		_jit_new_node_no_link(_jit, u)
extern jit_node_t *_jit_new_node_no_link(jit_state_t*, jit_code_t);

#define jit_link_node(u)		_jit_link_node(_jit, u)
extern void _jit_link_node(jit_state_t*, jit_node_t*);

#define jit_link_label(l)	_jit_link_label(_jit,l)
extern void
_jit_link_label(jit_state_t*,jit_node_t*);

#define jit_synth_dec()			_jit_synth_dec(_jit)
extern void _jit_synth_dec(jit_state_t*);

#define jit_reglive(node)	_jit_reglive(_jit, node)
extern void
_jit_reglive(jit_state_t*, jit_node_t*);

#define jit_regarg_set(n,v)	_jit_regarg_set(_jit,n,v)
extern void
_jit_regarg_set(jit_state_t*, jit_node_t*, jit_int32_t);

#define jit_regarg_clr(n,v)	_jit_regarg_clr(_jit,n,v)
extern void
_jit_regarg_clr(jit_state_t*, jit_node_t*, jit_int32_t);

#define jit_save(reg)		_jit_save(_jit, reg)
extern void
_jit_save(jit_state_t*, jit_int32_t);

#define jit_load(reg)		_jit_load(_jit, reg)
extern void
_jit_load(jit_state_t*, jit_int32_t);

#define jit_trampoline(u,v)	_jit_trampoline(_jit, u, v)
extern void _jit_trampoline(jit_state_t*, jit_int32_t, jit_bool_t);

#define jit_optimize()		_jit_optimize(_jit)
extern void
_jit_optimize(jit_state_t*);

#define jit_classify(code)	_jit_classify(_jit, code)
extern jit_int32_t
_jit_classify(jit_state_t*, jit_code_t);

#define jit_regarg_p(n, r)	_jit_regarg_p(_jit, n, r)
extern jit_bool_t
_jit_regarg_p(jit_state_t*, jit_node_t*, jit_int32_t);

#define emit_code()		_emit_code(_jit)
extern jit_pointer_t
_emit_code(jit_state_t*);

extern void
jit_flush(void *fptr, void *tptr);

#define emit_ldxi(r0, r1, i0)	_emit_ldxi(_jit, r0, r1, i0)
extern void
_emit_ldxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);

#define emit_stxi(i0, r0, r1)	_emit_stxi(_jit, i0, r0, r1)
extern void
_emit_stxi(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);

#define emit_ldxi_d(r0, r1, i0)	_emit_ldxi_d(_jit, r0, r1, i0)
extern void
_emit_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);

#define emit_stxi_d(i0, r0, r1)	_emit_stxi_d(_jit, i0, r0, r1)
extern void
_emit_stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);

extern void jit_init_print(void);
extern void jit_init_debug(const char*);
extern void jit_finish_debug(void);

extern void jit_init_note(void);
extern void jit_finish_note(void);
#define jit_set_note(n,u,v,w)	_jit_set_note(_jit, n, u, v, w)
extern void _jit_set_note(jit_state_t*, jit_note_t*, char*, int, jit_int32_t);
#define jit_annotate()		_jit_annotate(_jit)
extern void _jit_annotate(jit_state_t*);

#define jit_print_node(u)	_jit_print_node(_jit,u)
extern void _jit_print_node(jit_state_t*,jit_node_t*);

extern jit_pointer_t jit_memcpy(jit_pointer_t,const void*,jit_word_t);
extern jit_pointer_t jit_memmove(jit_pointer_t,const void*,jit_word_t);
extern void jit_alloc(jit_pointer_t*, jit_word_t);
extern void jit_realloc(jit_pointer_t*, jit_word_t, jit_word_t);
void jit_free(jit_pointer_t*);

extern void jit_init_size(void);
extern void jit_finish_size(void);

#if GET_JIT_SIZE
#  define jit_size_prepare()		_jit_size_prepare(_jit)
extern void
_jit_size_prepare(jit_state_t*);

#  define jit_size_collect(node)	_jit_size_collect(_jit, node)
extern void
_jit_size_collect(jit_state_t*, jit_node_t*);
#else
#  define jit_get_size()		_jit_get_size(_jit)
extern jit_word_t
_jit_get_size(jit_state_t*);
#endif

extern jit_word_t
jit_get_max_instr(void);

/*
 * Externs
 */
extern jit_register_t	 _rvs[];

#endif /* _jit_private_h */
