/*
 * jit-opcode.c - Information about all of the JIT opcodes.
 *
 * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "jit-internal.h"
#include "jit-rules.h"

#define	F_(dest,src1,src2)	\
	(JIT_OPCODE_DEST_##dest | JIT_OPCODE_SRC1_##src1 | JIT_OPCODE_SRC2_##src2)
#define	O_(dest,src1,src2,oper)	\
	(JIT_OPCODE_DEST_##dest | JIT_OPCODE_SRC1_##src1 | \
	 JIT_OPCODE_SRC2_##src2 | JIT_OPCODE_OPER_##oper)
#define	B_(src1,src2)	\
	(JIT_OPCODE_IS_BRANCH | JIT_OPCODE_SRC1_##src1 | JIT_OPCODE_SRC2_##src2)
#define	A_(src1,src2,oper)	\
	(JIT_OPCODE_IS_BRANCH | JIT_OPCODE_SRC1_##src1 | \
	 JIT_OPCODE_SRC2_##src2 | JIT_OPCODE_OPER_##oper)
#if defined(JIT_BACKEND_INTERP)
	#define	NINT_ARG			JIT_OPCODE_NINT_ARG
	#define	NINT_ARG_TWO		JIT_OPCODE_NINT_ARG_TWO
	#define	INDIRECT_ARGS		JIT_OPCODE_CALL_INDIRECT_ARGS
#else
	#define	NINT_ARG			0
	#define	NINT_ARG_TWO		0
	#define	INDIRECT_ARGS		0
#endif

jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {

	/*
	 * Simple opcodes.
	 */
	{"nop",							F_(EMPTY, EMPTY, EMPTY)},

	/*
 	 * Conversion opcodes.
 	 */
	{"trunc_sbyte",					F_(INT, INT, EMPTY)},
	{"trunc_ubyte",					F_(INT, INT, EMPTY)},
	{"trunc_short",					F_(INT, INT, EMPTY)},
	{"trunc_ushort",				F_(INT, INT, EMPTY)},
	{"trunc_int",					F_(INT, INT, EMPTY)},
	{"trunc_uint",					F_(INT, INT, EMPTY)},
	{"check_sbyte",					F_(INT, INT, EMPTY)},
	{"check_ubyte",					F_(INT, INT, EMPTY)},
	{"check_short",					F_(INT, INT, EMPTY)},
	{"check_ushort",				F_(INT, INT, EMPTY)},
	{"check_int",					F_(INT, INT, EMPTY)},
	{"check_uint",					F_(INT, INT, EMPTY)},
	{"low_word",					F_(INT, LONG, EMPTY)},
	{"expand_int",					F_(LONG, INT, EMPTY)},
	{"expand_uint",					F_(LONG, INT, EMPTY)},
	{"check_low_word",				F_(INT, LONG, EMPTY)},
	{"check_signed_low_word",		F_(INT, LONG, EMPTY)},
	{"check_long",					F_(LONG, LONG, EMPTY)},
	{"check_ulong",					F_(LONG, LONG, EMPTY)},
	{"nfloat_to_int",				F_(INT, NFLOAT, EMPTY)},
	{"nfloat_to_uint",				F_(INT, NFLOAT, EMPTY)},
	{"nfloat_to_long",				F_(LONG, NFLOAT, EMPTY)},
	{"nfloat_to_ulong",				F_(LONG, NFLOAT, EMPTY)},
	{"check_nfloat_to_int",			F_(INT, NFLOAT, EMPTY)},
	{"check_nfloat_to_uint",		F_(INT, NFLOAT, EMPTY)},
	{"check_nfloat_to_long",		F_(LONG, NFLOAT, EMPTY)},
	{"check_nfloat_to_ulong",		F_(LONG, NFLOAT, EMPTY)},
	{"int_to_nfloat",				F_(NFLOAT, INT, EMPTY)},
	{"uint_to_nfloat",				F_(NFLOAT, INT, EMPTY)},
	{"long_to_nfloat",				F_(NFLOAT, LONG, EMPTY)},
	{"ulong_to_nfloat",				F_(NFLOAT, LONG, EMPTY)},
	{"nfloat_to_float32",			F_(FLOAT32, NFLOAT, EMPTY)},
	{"nfloat_to_float64",			F_(FLOAT64, NFLOAT, EMPTY)},
	{"float32_to_nfloat",			F_(NFLOAT, FLOAT32, EMPTY)},
	{"float64_to_nfloat",			F_(NFLOAT, FLOAT64, EMPTY)},

	/*
	 * Arithmetic opcodes.
	 */
	{"iadd",						O_(INT, INT, INT, ADD)},
	{"iadd_ovf",					F_(INT, INT, INT)},
	{"iadd_ovf_un",					F_(INT, INT, INT)},
	{"isub",						O_(INT, INT, INT, SUB)},
	{"isub_ovf",					F_(INT, INT, INT)},
	{"isub_ovf_un",					F_(INT, INT, INT)},
	{"imul",						O_(INT, INT, INT, MUL)},
	{"imul_ovf",					F_(INT, INT, INT)},
	{"imul_ovf_un",					F_(INT, INT, INT)},
	{"idiv",						O_(INT, INT, INT, DIV)},
	{"idiv_un",						F_(INT, INT, INT)},
	{"irem",						O_(INT, INT, INT, REM)},
	{"irem_un",						F_(INT, INT, INT)},
	{"ineg",						O_(INT, INT, EMPTY, NEG)},
	{"ladd",						O_(LONG, LONG, LONG, ADD)},
	{"ladd_ovf",					F_(LONG, LONG, LONG)},
	{"ladd_ovf_un",					F_(LONG, LONG, LONG)},
	{"lsub",						O_(LONG, LONG, LONG, SUB)},
	{"lsub_ovf",					F_(LONG, LONG, LONG)},
	{"lsub_ovf_un",					F_(LONG, LONG, LONG)},
	{"lmul",						O_(LONG, LONG, LONG, MUL)},
	{"lmul_ovf",					F_(LONG, LONG, LONG)},
	{"lmul_ovf_un",					F_(LONG, LONG, LONG)},
	{"ldiv",						O_(LONG, LONG, LONG, DIV)},
	{"ldiv_un",						F_(LONG, LONG, LONG)},
	{"lrem",						O_(LONG, LONG, LONG, REM)},
	{"lrem_un",						F_(LONG, LONG, LONG)},
	{"lneg",						O_(LONG, LONG, EMPTY, NEG)},
	{"fadd",						O_(FLOAT32, FLOAT32, FLOAT32, ADD)},
	{"fsub",						O_(FLOAT32, FLOAT32, FLOAT32, SUB)},
	{"fmul",						O_(FLOAT32, FLOAT32, FLOAT32, MUL)},
	{"fdiv",						O_(FLOAT32, FLOAT32, FLOAT32, DIV)},
	{"frem",						O_(FLOAT32, FLOAT32, FLOAT32, REM)},
	{"frem_ieee",					F_(FLOAT32, FLOAT32, FLOAT32)},
	{"fneg",						O_(FLOAT32, FLOAT32, EMPTY, NEG)},
	{"dadd",						O_(FLOAT64, FLOAT64, FLOAT64, ADD)},
	{"dsub",						O_(FLOAT64, FLOAT64, FLOAT64, SUB)},
	{"dmul",						O_(FLOAT64, FLOAT64, FLOAT64, MUL)},
	{"ddiv",						O_(FLOAT64, FLOAT64, FLOAT64, DIV)},
	{"drem",						O_(FLOAT64, FLOAT64, FLOAT64, REM)},
	{"drem_ieee",					F_(FLOAT64, FLOAT64, FLOAT64)},
	{"dneg",						O_(FLOAT64, FLOAT64, EMPTY, NEG)},
	{"nfadd",						O_(NFLOAT, NFLOAT, NFLOAT, ADD)},
	{"nfsub",						O_(NFLOAT, NFLOAT, NFLOAT, SUB)},
	{"nfmul",						O_(NFLOAT, NFLOAT, NFLOAT, MUL)},
	{"nfdiv",						O_(NFLOAT, NFLOAT, NFLOAT, DIV)},
	{"nfrem",						O_(NFLOAT, NFLOAT, NFLOAT, REM)},
	{"nfrem_ieee",					F_(NFLOAT, NFLOAT, NFLOAT)},
	{"nfneg",						O_(NFLOAT, NFLOAT, EMPTY, NEG)},

	/*
	 * Bitwise opcodes.
 	 */
	{"iand",						O_(INT, INT, INT, AND)},
	{"ior",							O_(INT, INT, INT, OR)},
	{"ixor",						O_(INT, INT, INT, XOR)},
	{"inot",						O_(INT, INT, EMPTY, NOT)},
	{"ishl",						O_(INT, INT, INT, SHL)},
	{"ishr",						O_(INT, INT, INT, SHR)},
	{"ishr_un",						O_(INT, INT, INT, SHR_UN)},
	{"land",						O_(LONG, LONG, LONG, AND)},
	{"lor",							O_(LONG, LONG, LONG, OR)},
	{"lxor",						O_(LONG, LONG, LONG, XOR)},
	{"lnot",						O_(LONG, LONG, EMPTY, NOT)},
	{"lshl",						O_(LONG, LONG, INT, SHL)},
	{"lshr",						O_(LONG, LONG, INT, SHR)},
	{"lshr_un",						O_(LONG, LONG, INT, SHR_UN)},

	/*
	 * Branch opcodes.
	 */
	{"br",							B_(EMPTY, EMPTY)},
	{"br_ifalse",					B_(INT, EMPTY)},
	{"br_itrue",					B_(INT, EMPTY)},
	{"br_ieq",						A_(INT, INT, EQ)},
	{"br_ine",						A_(INT, INT, NE)},
	{"br_ilt",						A_(INT, INT, LT)},
	{"br_ilt_un",					B_(INT, INT)},
	{"br_ile",						A_(INT, INT, LE)},
	{"br_ile_un",					B_(INT, INT)},
	{"br_igt",						A_(INT, INT, GT)},
	{"br_igt_un",					B_(INT, INT)},
	{"br_ige",						A_(INT, INT, GE)},
	{"br_ige_un",					B_(INT, INT)},
	{"br_lfalse",					B_(LONG, EMPTY)},
	{"br_ltrue",					B_(LONG, EMPTY)},
	{"br_leq",						A_(LONG, LONG, EQ)},
	{"br_lne",						A_(LONG, LONG, NE)},
	{"br_llt",						A_(LONG, LONG, LT)},
	{"br_llt_un",					B_(LONG, LONG)},
	{"br_lle",						A_(LONG, LONG, LE)},
	{"br_lle_un",					B_(LONG, LONG)},
	{"br_lgt",						A_(LONG, LONG, GT)},
	{"br_lgt_un",					B_(LONG, LONG)},
	{"br_lge",						A_(LONG, LONG, GE)},
	{"br_lge_un",					B_(LONG, LONG)},
	{"br_feq",						A_(FLOAT32, FLOAT32, EQ)},
	{"br_fne",						A_(FLOAT32, FLOAT32, NE)},
	{"br_flt",						A_(FLOAT32, FLOAT32, LT)},
	{"br_fle",						A_(FLOAT32, FLOAT32, LE)},
	{"br_fgt",						A_(FLOAT32, FLOAT32, GT)},
	{"br_fge",						A_(FLOAT32, FLOAT32, GE)},
	{"br_feq_inv",					B_(FLOAT32, FLOAT32)},
	{"br_fne_inv",					B_(FLOAT32, FLOAT32)},
	{"br_flt_inv",					B_(FLOAT32, FLOAT32)},
	{"br_fle_inv",					B_(FLOAT32, FLOAT32)},
	{"br_fgt_inv",					B_(FLOAT32, FLOAT32)},
	{"br_fge_inv",					B_(FLOAT32, FLOAT32)},
	{"br_deq",						A_(FLOAT64, FLOAT64, EQ)},
	{"br_dne",						A_(FLOAT64, FLOAT64, NE)},
	{"br_dlt",						A_(FLOAT64, FLOAT64, LT)},
	{"br_dle",						A_(FLOAT64, FLOAT64, LE)},
	{"br_dgt",						A_(FLOAT64, FLOAT64, GT)},
	{"br_dge",						A_(FLOAT64, FLOAT64, GE)},
	{"br_deq_inv",					B_(FLOAT64, FLOAT64)},
	{"br_dne_inv",					B_(FLOAT64, FLOAT64)},
	{"br_dlt_inv",					B_(FLOAT64, FLOAT64)},
	{"br_dle_inv",					B_(FLOAT64, FLOAT64)},
	{"br_dgt_inv",					B_(FLOAT64, FLOAT64)},
	{"br_dge_inv",					B_(FLOAT64, FLOAT64)},
	{"br_nfeq",						A_(NFLOAT, NFLOAT, EQ)},
	{"br_nfne",						A_(NFLOAT, NFLOAT, NE)},
	{"br_nflt",						A_(NFLOAT, NFLOAT, LT)},
	{"br_nfle",						A_(NFLOAT, NFLOAT, LE)},
	{"br_nfgt",						A_(NFLOAT, NFLOAT, GT)},
	{"br_nfge",						A_(NFLOAT, NFLOAT, GE)},
	{"br_nfeq_inv",					B_(NFLOAT, NFLOAT)},
	{"br_nfne_inv",					B_(NFLOAT, NFLOAT)},
	{"br_nflt_inv",					B_(NFLOAT, NFLOAT)},
	{"br_nfle_inv",					B_(NFLOAT, NFLOAT)},
	{"br_nfgt_inv",					B_(NFLOAT, NFLOAT)},
	{"br_nfge_inv",					B_(NFLOAT, NFLOAT)},

	/*
	 * Comparison opcodes.
	 */
	{"icmp",						F_(INT, INT, INT)},
	{"icmp_un",						F_(INT, INT, INT)},
	{"lcmp",						F_(INT, LONG, LONG)},
	{"lcmp_un",						F_(INT, LONG, LONG)},
	{"fcmpl",						F_(INT, FLOAT32, FLOAT32)},
	{"fcmpg",						F_(INT, FLOAT32, FLOAT32)},
	{"dcmpl",						F_(INT, FLOAT64, FLOAT64)},
	{"dcmpg",						F_(INT, FLOAT64, FLOAT64)},
	{"nfcmpl",						F_(INT, NFLOAT, NFLOAT)},
	{"nfcmpg",						F_(INT, NFLOAT, NFLOAT)},
	{"ieq",							O_(INT, INT, INT, EQ)},
	{"ine",							O_(INT, INT, INT, NE)},
	{"ilt",							O_(INT, INT, INT, LT)},
	{"ilt_un",						F_(INT, INT, INT)},
	{"ile",							O_(INT, INT, INT, LE)},
	{"ile_un",						F_(INT, INT, INT)},
	{"igt",							O_(INT, INT, INT, GT)},
	{"igt_un",						F_(INT, INT, INT)},
	{"ige",							O_(INT, INT, INT, GE)},
	{"ige_un",						F_(INT, INT, INT)},
	{"leq",							O_(INT, LONG, LONG, EQ)},
	{"lne",							O_(INT, LONG, LONG, NE)},
	{"llt",							O_(INT, LONG, LONG, LT)},
	{"llt_un",						F_(INT, LONG, LONG)},
	{"lle",							O_(INT, LONG, LONG, LE)},
	{"lle_un",						F_(INT, LONG, LONG)},
	{"lgt",							O_(INT, LONG, LONG, GT)},
	{"lgt_un",						F_(INT, LONG, LONG)},
	{"lge",							O_(INT, LONG, LONG, GE)},
	{"lge_un",						F_(INT, LONG, LONG)},
	{"feq",							O_(INT, FLOAT32, FLOAT32, EQ)},
	{"fne",							O_(INT, FLOAT32, FLOAT32, NE)},
	{"flt",							O_(INT, FLOAT32, FLOAT32, LT)},
	{"fle",							O_(INT, FLOAT32, FLOAT32, LE)},
	{"fgt",							O_(INT, FLOAT32, FLOAT32, GT)},
	{"fge",							O_(INT, FLOAT32, FLOAT32, GE)},
	{"feq_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"fne_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"flt_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"fle_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"fgt_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"fge_inv",						F_(INT, FLOAT32, FLOAT32)},
	{"deq",							O_(INT, FLOAT64, FLOAT64, EQ)},
	{"dne",							O_(INT, FLOAT64, FLOAT64, NE)},
	{"dlt",							O_(INT, FLOAT64, FLOAT64, LT)},
	{"dle",							O_(INT, FLOAT64, FLOAT64, LE)},
	{"dgt",							O_(INT, FLOAT64, FLOAT64, GT)},
	{"dge",							O_(INT, FLOAT64, FLOAT64, GE)},
	{"deq_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"dne_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"dlt_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"dle_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"dgt_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"dge_inv",						F_(INT, FLOAT64, FLOAT64)},
	{"nfeq",						O_(INT, NFLOAT, NFLOAT, EQ)},
	{"nfne",						O_(INT, NFLOAT, NFLOAT, NE)},
	{"nflt",						O_(INT, NFLOAT, NFLOAT, LT)},
	{"nfle",						O_(INT, NFLOAT, NFLOAT, LE)},
	{"nfgt",						O_(INT, NFLOAT, NFLOAT, GT)},
	{"nfge",						O_(INT, NFLOAT, NFLOAT, GE)},
	{"nfeq_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"nfne_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"nflt_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"nfle_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"nfgt_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"nfge_inv",					F_(INT, NFLOAT, NFLOAT)},
	{"is_fnan",						F_(INT, FLOAT32, EMPTY)},
	{"is_finf",						F_(INT, FLOAT32, EMPTY)},
	{"is_ffinite",					F_(INT, FLOAT32, EMPTY)},
	{"is_dnan",						F_(INT, FLOAT64, EMPTY)},
	{"is_dinf",						F_(INT, FLOAT64, EMPTY)},
	{"is_dfinite",					F_(INT, FLOAT64, EMPTY)},
	{"is_nfnan",					F_(INT, NFLOAT, EMPTY)},
	{"is_nfinf",					F_(INT, NFLOAT, EMPTY)},
	{"is_nffinite",					F_(INT, NFLOAT, EMPTY)},

	/*
	 * Mathematical functions.
	 */
	{"facos",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fasin",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fatan",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fatan2",						F_(FLOAT32, FLOAT32, FLOAT32)},
	{"fceil",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fcos",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fcosh",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fexp",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"ffloor",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"flog",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"flog10",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fpow",						F_(FLOAT32, FLOAT32, FLOAT32)},
	{"frint",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fround",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fsin",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fsinh",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"fsqrt",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"ftan",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"ftanh",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"dacos",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dasin",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"datan",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"datan2",						F_(FLOAT64, FLOAT64, FLOAT64)},
	{"dceil",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dcos",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dcosh",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dexp",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dfloor",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dlog",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dlog10",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dpow",						F_(FLOAT64, FLOAT64, FLOAT64)},
	{"drint",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dround",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dsin",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dsinh",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dsqrt",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dtan",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"dtanh",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"nfacos",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfasin",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfatan",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfatan2",						F_(NFLOAT, NFLOAT, NFLOAT)},
	{"nfceil",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfcos",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfcosh",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfexp",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nffloor",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nflog",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nflog10",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfpow",						F_(NFLOAT, NFLOAT, NFLOAT)},
	{"nfrint",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfround",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfsin",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfsinh",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nfsqrt",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nftan",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"nftanh",						F_(NFLOAT, NFLOAT, EMPTY)},

	/*
	 * Absolute, minimum, maximum, and sign.
	 */
	{"iabs",						F_(INT, INT, EMPTY)},
	{"labs",						F_(LONG, LONG, EMPTY)},
	{"fabs",						F_(FLOAT32, FLOAT32, EMPTY)},
	{"dabs",						F_(FLOAT64, FLOAT64, EMPTY)},
	{"nfabs",						F_(NFLOAT, NFLOAT, EMPTY)},
	{"imin",						F_(INT, INT, INT)},
	{"imin_un",						F_(INT, INT, INT)},
	{"lmin",						F_(LONG, LONG, LONG)},
	{"lmin_un",						F_(LONG, LONG, LONG)},
	{"fmin",						F_(FLOAT32, FLOAT32, FLOAT32)},
	{"dmin",						F_(FLOAT64, FLOAT64, FLOAT64)},
	{"nfmin",						F_(NFLOAT, NFLOAT, NFLOAT)},
	{"imax",						F_(INT, INT, INT)},
	{"imax_un",						F_(INT, INT, INT)},
	{"lmax",						F_(LONG, LONG, LONG)},
	{"lmax_un",						F_(LONG, LONG, LONG)},
	{"fmax",						F_(FLOAT32, FLOAT32, FLOAT32)},
	{"dmax",						F_(FLOAT64, FLOAT64, FLOAT64)},
	{"nfmax",						F_(NFLOAT, NFLOAT, NFLOAT)},
	{"isign",						F_(INT, INT, EMPTY)},
	{"lsign",						F_(INT, LONG, EMPTY)},
	{"fsign",						F_(INT, FLOAT32, EMPTY)},
	{"dsign",						F_(INT, FLOAT64, EMPTY)},
	{"nfsign",						F_(INT, NFLOAT, EMPTY)},

	/*
	 * Pointer check opcodes.
	 */
	{"check_null",					F_(EMPTY, PTR, EMPTY)},

	/*
	 * Function calls.
	 */
	{"call",						JIT_OPCODE_IS_CALL},
	{"call_tail",					JIT_OPCODE_IS_CALL},
	{"call_indirect",				F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
	{"call_indirect_tail",			F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
	{"call_vtable_ptr",				F_(EMPTY, PTR, EMPTY)},
	{"call_vtable_ptr_tail",		F_(EMPTY, PTR, EMPTY)},
	{"call_external",				JIT_OPCODE_IS_CALL_EXTERNAL},
	{"call_external_tail",			JIT_OPCODE_IS_CALL_EXTERNAL},
	{"return",						F_(EMPTY, EMPTY, EMPTY)},
	{"return_int",					F_(EMPTY, INT, EMPTY)},
	{"return_long",					F_(EMPTY, LONG, EMPTY)},
	{"return_float32",				F_(EMPTY, FLOAT32, EMPTY)},
	{"return_float64",				F_(EMPTY, FLOAT64, EMPTY)},
	{"return_nfloat",				F_(EMPTY, NFLOAT, EMPTY)},
	{"return_small_struct",			F_(EMPTY, PTR, PTR)},
	{"setup_for_nested",			F_(EMPTY, INT, EMPTY)},
	{"setup_for_sibling",			F_(EMPTY, INT, INT) | NINT_ARG},
	{"import",						F_(PTR, ANY, INT)},

	/*
	 * Exception handling.
	 */
	{"throw",						F_(EMPTY, PTR, EMPTY)},
	{"rethrow",						F_(EMPTY, PTR, EMPTY)},
	{"load_pc",						F_(PTR, EMPTY, EMPTY)},
	{"load_exception_pc",			F_(PTR, EMPTY, EMPTY)},
	{"enter_finally",				F_(EMPTY, EMPTY, EMPTY)},
	{"leave_finally",				F_(EMPTY, EMPTY, EMPTY)},
	{"call_finally",				B_(EMPTY, EMPTY)},
	{"enter_filter",				F_(ANY, EMPTY, EMPTY)},
	{"leave_filter",				F_(EMPTY, ANY, EMPTY)},
	{"call_filter",					B_(ANY, EMPTY)},
	{"call_filter_return",			F_(ANY, EMPTY, EMPTY)},
	{"address_of_label",			JIT_OPCODE_IS_ADDROF_LABEL},

	/*
	 * Data manipulation.
	 */
	{"copy_load_sbyte",				F_(INT, INT, EMPTY)},
	{"copy_load_ubyte",				F_(INT, INT, EMPTY)},
	{"copy_load_short",				F_(INT, INT, EMPTY)},
	{"copy_load_ushort",			F_(INT, INT, EMPTY)},
	{"copy_int",					O_(INT, INT, EMPTY, COPY)},
	{"copy_long",					O_(LONG, LONG, EMPTY, COPY)},
	{"copy_float32",				O_(FLOAT32, FLOAT32, EMPTY, COPY)},
	{"copy_float64",				O_(FLOAT64, FLOAT64, EMPTY, COPY)},
	{"copy_nfloat",					O_(NFLOAT, NFLOAT, EMPTY, COPY)},
	{"copy_struct",					O_(PTR, PTR, EMPTY, COPY)},
	{"copy_store_byte",				F_(INT, INT, EMPTY)},
	{"copy_store_short",			F_(INT, INT, EMPTY)},
	{"address_of",					O_(PTR, ANY, EMPTY, ADDRESS_OF)},

	/*
	 * Incoming registers, outgoing registers, and stack pushes.
	 */
	{"incoming_reg",				JIT_OPCODE_IS_REG},
	{"incoming_frame_posn",			F_(EMPTY, ANY, INT)},
	{"outgoing_reg",				JIT_OPCODE_IS_REG},
	{"outgoing_frame_posn",			F_(EMPTY, ANY, INT)},
	{"return_reg",					JIT_OPCODE_IS_REG},
	{"push_int",					F_(EMPTY, INT, EMPTY)},
	{"push_long",					F_(EMPTY, LONG, EMPTY)},
	{"push_float32",				F_(EMPTY, FLOAT32, EMPTY)},
	{"push_float64",				F_(EMPTY, FLOAT64, EMPTY)},
	{"push_nfloat",					F_(EMPTY, NFLOAT, EMPTY)},
	{"push_struct",					F_(EMPTY, ANY, PTR) | NINT_ARG},
	{"pop_stack",					F_(EMPTY, INT, EMPTY) | NINT_ARG},
	{"flush_small_struct",			F_(EMPTY, ANY, EMPTY)},
	{"set_param_int",				F_(EMPTY, INT, PTR)},
	{"set_param_long",				F_(EMPTY, LONG, PTR)},
	{"set_param_float32",			F_(EMPTY, FLOAT32, PTR)},
	{"set_param_float64",			F_(EMPTY, FLOAT64, PTR)},
	{"set_param_nfloat",			F_(EMPTY, NFLOAT, PTR)},
	{"set_param_struct",			F_(PTR, PTR, PTR)},
	{"push_return_area_ptr",		F_(EMPTY, EMPTY, EMPTY)},

	/*
	 * Pointer-relative loads and stores.
	 */
	{"load_relative_sbyte",			F_(INT, PTR, INT) | NINT_ARG},
	{"load_relative_ubyte",			F_(INT, PTR, INT) | NINT_ARG},
	{"load_relative_short",			F_(INT, PTR, INT) | NINT_ARG},
	{"load_relative_ushort",		F_(INT, PTR, INT) | NINT_ARG},
	{"load_relative_int",			F_(INT, PTR, INT) | NINT_ARG},
	{"load_relative_long",			F_(LONG, PTR, INT) | NINT_ARG},
	{"load_relative_float32",		F_(FLOAT32, PTR, INT) | NINT_ARG},
	{"load_relative_float64",		F_(FLOAT64, PTR, INT) | NINT_ARG},
	{"load_relative_nfloat",		F_(NFLOAT, PTR, INT) | NINT_ARG},
	{"load_relative_struct",		F_(ANY, PTR, INT) | NINT_ARG_TWO},
	{"store_relative_byte",			F_(PTR, INT, INT) | NINT_ARG},
	{"store_relative_short",		F_(PTR, INT, INT) | NINT_ARG},
	{"store_relative_int",			F_(PTR, INT, INT) | NINT_ARG},
	{"store_relative_long",			F_(PTR, LONG, INT) | NINT_ARG},
	{"store_relative_float32",		F_(PTR, FLOAT32, INT) | NINT_ARG},
	{"store_relative_float64",		F_(PTR, FLOAT64, INT) | NINT_ARG},
	{"store_relative_nfloat",		F_(PTR, NFLOAT, INT) | NINT_ARG},
	{"store_relative_struct",		F_(PTR, ANY, INT) | NINT_ARG_TWO},
	{"add_relative",				F_(PTR, PTR, INT) | NINT_ARG},

	/*
	 * Array element loads and stores.
	 */
	{"load_element_sbyte",			F_(INT, PTR, INT)},
	{"load_element_ubyte",			F_(INT, PTR, INT)},
	{"load_element_short",			F_(INT, PTR, INT)},
	{"load_element_ushort",			F_(INT, PTR, INT)},
	{"load_element_int",			F_(INT, PTR, INT)},
	{"load_element_long",			F_(LONG, PTR, INT)},
	{"load_element_float32",		F_(FLOAT32, PTR, INT)},
	{"load_element_float64",		F_(FLOAT64, PTR, INT)},
	{"load_element_nfloat",			F_(NFLOAT, PTR, INT)},
	{"store_element_byte",			F_(PTR, INT, INT)},
	{"store_element_short",			F_(PTR, INT, INT)},
	{"store_element_int",			F_(PTR, INT, INT)},
	{"store_element_long",			F_(PTR, INT, LONG)},
	{"store_element_float32",		F_(PTR, INT, FLOAT32)},
	{"store_element_float64",		F_(PTR, INT, FLOAT64)},
	{"store_element_nfloat",		F_(PTR, INT, NFLOAT)},

	/*
	 * Block operations.
	 */
	{"memcpy",						F_(PTR, PTR, PTR)},
	{"memmove",						F_(PTR, PTR, PTR)},
	{"memset",						F_(PTR, INT, PTR)},

	/*
	 * Allocate memory from the stack.
	 */
	{"alloca",						F_(PTR, PTR, EMPTY)},

	/*
	 * Debugging support.
	 */
	{"mark_offset",					F_(EMPTY, INT, EMPTY)},
	{"mark_breakpoint",				F_(EMPTY, PTR, PTR)},

};

#if defined(JIT_BACKEND_INTERP)

jit_opcode_info_t const _jit_interp_opcodes[JIT_OP_NUM_INTERP_OPCODES] = {

	/*
	 * Argument variable access opcodes.
	 */
	{"ldarg_sbyte",					JIT_OPCODE_NINT_ARG},
	{"ldarg_ubyte",					JIT_OPCODE_NINT_ARG},
	{"ldarg_short",					JIT_OPCODE_NINT_ARG},
	{"ldarg_ushort",				JIT_OPCODE_NINT_ARG},
	{"ldarg_int",					JIT_OPCODE_NINT_ARG},
	{"ldarg_long",					JIT_OPCODE_NINT_ARG},
	{"ldarg_float32",				JIT_OPCODE_NINT_ARG},
	{"ldarg_float64",				JIT_OPCODE_NINT_ARG},
	{"ldarg_nfloat",				JIT_OPCODE_NINT_ARG},
	{"ldarg_struct",				JIT_OPCODE_NINT_ARG_TWO},
	{"ldarga",						JIT_OPCODE_NINT_ARG},
	{"starg_byte",					JIT_OPCODE_NINT_ARG},
	{"starg_short",					JIT_OPCODE_NINT_ARG},
	{"starg_int",					JIT_OPCODE_NINT_ARG},
	{"starg_long",					JIT_OPCODE_NINT_ARG},
	{"starg_float32",				JIT_OPCODE_NINT_ARG},
	{"starg_float64",				JIT_OPCODE_NINT_ARG},
	{"starg_nfloat",				JIT_OPCODE_NINT_ARG},
	{"starg_struct",				JIT_OPCODE_NINT_ARG_TWO},

	/*
	 * Local variable frame access opcodes.
	 */
	{"ldloc_sbyte",					JIT_OPCODE_NINT_ARG},
	{"ldloc_ubyte",					JIT_OPCODE_NINT_ARG},
	{"ldloc_short",					JIT_OPCODE_NINT_ARG},
	{"ldloc_ushort",				JIT_OPCODE_NINT_ARG},
	{"ldloc_int",					JIT_OPCODE_NINT_ARG},
	{"ldloc_long",					JIT_OPCODE_NINT_ARG},
	{"ldloc_float32",				JIT_OPCODE_NINT_ARG},
	{"ldloc_float64",				JIT_OPCODE_NINT_ARG},
	{"ldloc_nfloat",				JIT_OPCODE_NINT_ARG},
	{"ldloc_struct",				JIT_OPCODE_NINT_ARG_TWO},
	{"ldloca",						JIT_OPCODE_NINT_ARG},
	{"stloc_byte",					JIT_OPCODE_NINT_ARG},
	{"stloc_short",					JIT_OPCODE_NINT_ARG},
	{"stloc_int",					JIT_OPCODE_NINT_ARG},
	{"stloc_long",					JIT_OPCODE_NINT_ARG},
	{"stloc_float32",				JIT_OPCODE_NINT_ARG},
	{"stloc_float64",				JIT_OPCODE_NINT_ARG},
	{"stloc_nfloat",				JIT_OPCODE_NINT_ARG},
	{"stloc_struct",				JIT_OPCODE_NINT_ARG_TWO},

	/*
	 * Pointer check opcodes (interpreter only).
	 */
	{"check_null_n",				JIT_OPCODE_NINT_ARG},

	/*
	 * Stack management.
	 */
	{"pop",							0},
	{"pop_2",						0},
	{"pop_3",						0},
	{"push_return_int",				0},
	{"push_return_long",			0},
	{"push_return_float32",			0},
	{"push_return_float64",			0},
	{"push_return_nfloat",			0},
	{"push_return_small_struct",	JIT_OPCODE_NINT_ARG},

	/*
	 * Nested function call handling.
	 */
	{"import_local",				JIT_OPCODE_NINT_ARG_TWO},
	{"import_arg",					JIT_OPCODE_NINT_ARG_TWO},

	/*
	 * Push constant values onto the stack.
	 */
	{"push_const_int",				JIT_OPCODE_NINT_ARG},
	{"push_const_long",				JIT_OPCODE_CONST_LONG},
	{"push_const_float32",			JIT_OPCODE_CONST_FLOAT32},
	{"push_const_float64",			JIT_OPCODE_CONST_FLOAT64},
	{"push_const_nfloat",			JIT_OPCODE_CONST_NFLOAT},

	/*
	 * Marker opcode for the end of a function.
	 */
	{"end_marker",					0},
};

#endif /* JIT_BACKEND_INTERP */
