#ifndef EJIT_COMMON_H
#define EJIT_COMMON_H

#include <stdbool.h>
#include "vec.h"

enum ejit_opcode {
	MOVI,
	MOVI_F,
	MOVI_D,
	MOVR,
	MOVR_F,
	MOVR_D,

	LDI8,
	LDI16,
	LDI32,
	LDI64,
	LDIU8,
	LDIU16,
	LDIU32,
	LDIU64,
	LDIF,
	LDID,

	LDXI8,
	LDXI16,
	LDXI32,
	LDXI64,
	LDXIU8,
	LDXIU16,
	LDXIU32,
	LDXIU64,
	LDXIF,
	LDXID,

	LDXR8,
	LDXR16,
	LDXR32,
	LDXR64,
	LDXRU8,
	LDXRU16,
	LDXRU32,
	LDXRU64,
	LDXRF,
	LDXRD,

	STI8,
	STI16,
	STI32,
	STI64,
	STIF,
	STID,

	STXI8,
	STXI16,
	STXI32,
	STXI64,
	STXIF,
	STXID,

	STXR8,
	STXR16,
	STXR32,
	STXR64,
	STXRF,
	STXRD,

	EXTR8,
	EXTR16,
	EXTR32,
	EXTRU8,
	EXTRU16,
	EXTRU32,
	EXTRF,
	EXTRD,

	ADDR,
	ADDR_F,
	ADDR_D,
	ADDI,

	ABSR_F,
	ABSR_D,

	SUBR,
	SUBR_F,
	SUBR_D,
	SUBI,

	MULR,
	MULR_F,
	MULR_D,

	DIVR,
	DIVR_U,
	DIVR_F,
	DIVR_D,

	REMR,
	REMR_U,

	COMR,
	NEGR,
	NEGR_F,
	NEGR_D,

	LSHI,
	LSHR,
	RSHI,
	RSHI_U,
	RSHR,
	RSHR_U,

	ANDR,
	ANDI,

	ORR,
	ORI,

	XORR,
	XORI,

	TRUNCR_D_32,
	TRUNCR_D_64,
	TRUNCR_F_32,
	TRUNCR_F_64,

	EQR,
	NER,
	GTR,
	GTR_U,
	GER,
	GER_U,

	EQR_F,
	NER_F,
	GTR_F,
	GER_F,
	EQR_D,
	NER_D,
	GTR_D,
	GER_D,

	BNER,
	BNEI,
	BNER_F,
	BNER_D,

	BEQR,
	BEQI,
	BEQR_F,
	BEQR_D,

	BGER,
	BGER_U,
	BGEI,
	BGEI_U,
	BGER_F,
	BGER_D,

	BLEI,
	BLEI_U,

	BGTR,
	BGTR_U,
	BGTI,
	BGTI_U,
	BGTR_F,
	BGTR_D,

	BLTI,
	BLTI_U,

	JMP,
	JMPR,

	BMCI,
	BMCR,
	BMSI,
	BMSR,

	PARAM,
	PARAM_F,

	ARG,
	ARG_I,
	ARG_F,
	ARG_FI,

	ESCAPEI,
	ESCAPEI_F,

	CALLI,
	CALLI_F,

	RETR,
	RETI,
	RETR_F,
	RETR_D,
	RETI_F,
	RETI_D,

	RETVAL,
	RETVAL_F,
	RETVAL_D,

	START,
	END,

	OPCODE_COUNT,
};

struct ejit_insn {
	union {
		enum ejit_opcode op;
		void *addr;
	};

	size_t r0;
	size_t r1;
	union {
		size_t r2;
		void *p;
		int64_t o;
		double d;
		float f;
	};
};

struct ejit_func {
	struct vec insns;
	struct vec labels;
	enum ejit_type rtype;

	size_t gpr;
	size_t fpr;

	void *arena;
	size_t size;
};


union interp_ret {
	int64_t r;
	double d;
};

struct interp_state {
	struct vec gprs;
	struct vec fprs;
	struct vec args;
};

union interp_ret ejit_interp(struct ejit_func *f, size_t argc,
                             struct ejit_arg args[argc],
                             struct interp_state *state, bool run,
                             void ***labels_wb);

int64_t ejit_run_interp(struct ejit_func *f, size_t argc,
                        struct ejit_arg args[argc], struct interp_state *state);

bool ejit_compile(struct ejit_func *f, bool use_64);

#endif /* EJIT_COMMON_H */