/*
 * Copyright (C) 2013-2019  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
 */

#if PROTO
typedef union {
/* aarch64-opc.c */
#  define ui			jit_uint32_t
#  if __BYTE_ORDER == __LITTLE_ENDIAN
    /* cond2: condition in truly conditional-executed inst.  */
    struct {		ui b:  4; } cond2;
    /* nzcv: flag bit specifier, encoded in the "nzcv" field.  */
    struct {		ui b:  4; } nzcv;
    /* defgh: d:e:f:g:h bits in AdvSIMD modified immediate.  */
    struct { ui _:  5;	ui b:  5; } defgh;
    /* abc: a:b:c bits in AdvSIMD modified immediate.  */
    struct { ui _: 16;	ui b:  3; } abc;
    /* imm19: e.g. in CBZ.  */
    struct { ui _:  5;	ui b: 19; } imm19;
    /* immhi: e.g. in ADRP.  */
    struct { ui _:  5;	ui b: 19; } immhi;
    /* immlo: e.g. in ADRP.  */
    struct { ui _: 29;	ui b:  2; } immlo;
    /* size: in most AdvSIMD and floating-point instructions.  */
    struct { ui _: 22;	ui b:  2; } size;
    /* vldst_size: size field in the AdvSIMD load/store inst.  */
    struct { ui _: 10;	ui b:  2; } vldst_size;
    /* op: in AdvSIMD modified immediate instructions.  */
    struct { ui _: 29;	ui b:  1; } op;
    /* Q: in most AdvSIMD instructions.  */
    struct { ui _: 30;	ui b:  1; } Q;
    /* Rt: in load/store instructions.  */
    struct { 		ui b:  5; } Rt;
    /* Rd: in many integer instructions.  */
    struct { 		ui b:  5; } Rd;
    /* Rn: in many integer instructions.  */
    struct { ui _:  5;	ui b:  5; } Rn;
    /* Rt2: in load/store pair instructions.  */
    struct { ui _: 10;	ui b:  5; } Rt2;
    /* Ra: in fp instructions.  */
    struct { ui _: 10;	ui b:  5; } Ra;
    /* op2: in the system instructions.  */
    struct { ui _:  5;	ui b:  3; } op2;
    /* CRm: in the system instructions.  */
    struct { ui _:  8;	ui b:  4; } CRm;
    /* CRn: in the system instructions.  */
    struct { ui _: 12;	ui b:  4; } CRn;
    /* op1: in the system instructions.  */
    struct { ui _: 16;	ui b:  3; } op1;
    /* op0: in the system instructions.  */
    struct { ui _: 19;	ui b:  2; } op0;
    /* imm3: in add/sub extended reg instructions.  */
    struct { ui _: 10;	ui b:  3; } imm3;
    /* cond: condition flags as a source operand.  */
    struct { ui _: 12;	ui b:  4; } cond;
    /* opcode: in advsimd load/store instructions.  */
    struct { ui _: 12;	ui b:  4; } opcode;
    /* cmode: in advsimd modified immediate instructions.  */
    struct { ui _: 12;	ui b:  4; } cmode;
    /* asisdlso_opcode: opcode in advsimd ld/st single element.  */
    struct { ui _: 13;	ui b:  3; } asisdlso_opcode;
    /* len: in advsimd tbl/tbx instructions.  */
    struct { ui _: 13;	ui b:  2; } len;
    /* Rm: in ld/st reg offset and some integer inst.  */
    struct { ui _: 16;	ui b:  5; } Rm;
    /* Rs: in load/store exclusive instructions.  */
    struct { ui _: 16;	ui b:  5; } Rs;
    /* option: in ld/st reg offset + add/sub extended reg inst.  */
    struct { ui _: 13;	ui b:  3; } option;
    /* S: in load/store reg offset instructions.  */
    struct { ui _: 12;	ui b:  1; } S;
    /* hw: in move wide constant instructions.  */
    struct { ui _: 21;	ui b:  2; } hw;
    /* opc: in load/store reg offset instructions.  */
    struct { ui _: 22;	ui b:  2; } opc;
    /* opc1: in load/store reg offset instructions.  */
    struct { ui _: 23;	ui b:  1; } opc1;
    /* shift: in add/sub reg/imm shifted instructions.  */
    struct { ui _: 22;	ui b:  2; } shift;
    /* type: floating point type field in fp data inst.  */
    struct { ui _: 22;	ui b:  2; } type;
    /* ldst_size: size field in ld/st reg offset inst.  */
    struct { ui _: 30;	ui b:  2; } ldst_size;
    /* imm6: in add/sub reg shifted instructions.  */
    struct { ui _: 10;	ui b:  6; } imm6;
    /* imm4: in advsimd ext and advsimd ins instructions.  */
    struct { ui _: 11;	ui b:  4; } imm4;
    /* imm5: in conditional compare (immediate) instructions.  */
    struct { ui _: 16;	ui b:  5; } imm5;
    /* imm7: in load/store pair pre/post index instructions.  */
    struct { ui _: 15;	ui b:  7; } imm7;
    /* imm8: in floating-point scalar move immediate inst.  */
    struct { ui _: 13;	ui b:  8; } imm8;
    /* imm9: in load/store pre/post index instructions.  */
    struct { ui _: 12;	ui b:  9; } imm9;
    /* imm12: in ld/st unsigned imm or add/sub shifted inst.  */
    struct { ui _: 10;	ui b: 12; } imm12;
    /* imm14: in test bit and branch instructions.  */
    struct { ui _:  5;	ui b: 14; } imm14;
    /* imm16: in exception instructions.  */
    struct { ui _:  5;	ui b: 16; } imm16;
    /* imm26: in unconditional branch instructions.  */
    struct {		ui b: 26; } imm26;
    /* imms: in bitfield and logical immediate instructions.  */
    struct { ui _: 10;	ui b:  6; } imms;
    /* immr: in bitfield and logical immediate instructions.  */
    struct { ui _: 16;	ui b:  6; } immr;
    /* immb: in advsimd shift by immediate instructions.  */
    struct { ui _: 16;	ui b:  3; } immb;
    /* immh: in advsimd shift by immediate instructions.  */
    struct { ui _: 19;	ui b:  4; } immh;
    /* N: in logical (immediate) instructions.  */
    struct { ui _: 22;	ui b:  1; } N;
    /* index: in ld/st inst deciding the pre/post-index.  */
    struct { ui _: 11;	ui b:  1; } index;
    /* index2: in ld/st pair inst deciding the pre/post-index.  */
    struct { ui _: 24;	ui b:  1; } index2;
    /* sf: in integer data processing instructions.  */
    struct { ui _: 31;	ui b:  1; } sf;
    /* H: in advsimd scalar x indexed element instructions.  */
    struct { ui _: 11;	ui b:  1; } H;
    /* L: in advsimd scalar x indexed element instructions.  */
    struct { ui _: 21;	ui b:  1; } L;
    /* M: in advsimd scalar x indexed element instructions.  */
    struct { ui _: 20;	ui b:  1; } M;
    /* b5: in the test bit and branch instructions.  */
    struct { ui _: 31;	ui b:  1; } b5;
    /* b40: in the test bit and branch instructions.  */
    struct { ui _: 19;	ui b:  5; } b40;
    /* scale: in the fixed-point scalar to fp converting inst.  */
    struct { ui _: 10;	ui b:  6; } scale;
#  else
    struct { ui _: 28;	ui b:  4; } cond2;
    struct { ui _: 28;	ui b:  4; } nzcv;
    struct { ui _: 22;	ui b:  5; } defgh;
    struct { ui _: 13;	ui b:  3; } abc;
    struct { ui _:  8;	ui b: 19; } imm19;
    struct { ui _:  8;	ui b: 19; } immhi;
    struct { ui _:  1;	ui b: 29; } immlo;
    struct { ui _:  8;	ui b:  2; } size;
    struct { ui _: 20;	ui b:  2; } vldst_size;
    struct { ui _:  2;	ui b:  1; } op;
    struct { ui _:  1;	ui b:  1; } Q;
    struct { ui _: 27;	ui b:  1; } Rt;
    struct { ui _: 27;	ui b:  1; } Rd;
    struct { ui _: 22;	ui b:  5; } Rn;
    struct { ui _: 17;	ui b:  5; } Rt2;
    struct { ui _: 17;	ui b:  5; } Ra;
    struct { ui _: 24;	ui b:  3; } op2;
    struct { ui _: 20;	ui b:  4; } CRm;
    struct { ui _: 16;	ui b:  4; } CRn;
    struct { ui _: 13;	ui b:  3; } op1;
    struct { ui _: 11;	ui b:  2; } op0;
    struct { ui _: 19;	ui b:  3; } imm3;
    struct { ui _: 16;	ui b:  4; } cond;
    struct { ui _: 16;	ui b:  4; } opcode;
    struct { ui _: 16;	ui b:  4; } cmode;
    struct { ui _: 16;	ui b:  3; } asisdlso_opcode;
    struct { ui _: 17;	ui b:  2; } len;
    struct { ui _: 11;	ui b:  5; } Rm;
    struct { ui _: 11;	ui b:  5; } Rs;
    struct { ui _: 16;	ui b:  3; } option;
    struct { ui _: 19;	ui b:  1; } S;
    struct { ui _:  9;	ui b:  2; } hw;
    struct { ui _:  8;	ui b:  2; } opc;
    struct { ui _:  8;	ui b:  1; } opc1;
    struct { ui _:  8;	ui b:  2; } shift;
    struct { ui _:  8;	ui b:  2; } type;
    struct {		ui b:  2; } ldst_size;
    struct { ui _: 16;	ui b:  6; } imm6;
    struct { ui _: 17;	ui b:  4; } imm4;
    struct { ui _: 11;	ui b:  5; } imm5;
    struct { ui _: 10;	ui b:  7; } imm7;
    struct { ui _: 11;	ui b:  8; } imm8;
    struct { ui _: 11;	ui b:  9; } imm9;
    struct { ui _: 10;	ui b: 12; } imm12;
    struct { ui _: 13;	ui b: 14; } imm14;
    struct { ui _: 11;	ui b: 16; } imm16;
    struct { ui _:  6;	ui b: 26; } imm26;
    struct { ui _: 16;	ui b:  6; } imms;
    struct { ui _: 10;	ui b:  6; } immr;
    struct { ui _: 13;	ui b:  3; } immb;
    struct { ui _:  9;	ui b:  4; } immh;
    struct { ui _:  9;	ui b:  1; } N;
    struct { ui _: 20;	ui b:  1; } index;
    struct { ui _:  7;	ui b:  1; } index2;
    struct {		ui b:  1; } sf;
    struct { ui _: 20;	ui b:  1; } H;
    struct { ui _: 10;	ui b:  1; } L;
    struct { ui _: 11;	ui b:  1; } M;
    struct {		ui b:  1; } b5;
    struct { ui _:  8;	ui b:  5; } b40;
    struct { ui _: 16;	ui b:  6; } scale;
#  endif
    jit_int32_t		w;
#  undef ui
} instr_t;
#  define stack_framesize		160
#  define ii(i)				*_jit->pc.ui++ = i
#  define ldr(r0,r1)			ldr_l(r0,r1)
#  define ldxr(r0,r1,r2)		ldxr_l(r0,r1,r2)
#  define ldxi(r0,r1,i0)		ldxi_l(r0,r1,i0)
#  define stxi(i0,r0,r1)		stxi_l(i0,r0,r1)
#  define FP_REGNO			0x1d
#  define LR_REGNO			0x1e
#  define SP_REGNO			0x1f
#  define XZR_REGNO			0x1f
#  define WZR_REGNO			XZR_REGNO
#  define LSL_12			0x00400000
#  define MOVI_LSL_16			0x00200000
#  define MOVI_LSL_32			0x00400000
#  define MOVI_LSL_48			0x00600000
#  define XS				0x80000000	/* Wn -> Xn */
#  define DS				0x00400000	/* Sn -> Dn */
#  define CC_NE				0x0
#  define CC_EQ				0x1
#  define CC_CC				0x2
#  define CC_LO				CC_CC
#  define CC_CS				0x3
#  define CC_HS				CC_CS
#  define CC_PL				0x4
#  define CC_MI				0x5
#  define CC_VC				0x6
#  define CC_VS				0x7
#  define CC_LS				0x8
#  define CC_HI				0x9
#  define CC_LT				0xa
#  define CC_GE				0xb
#  define CC_LE				0xc
#  define CC_GT				0xd
#  define CC_NV				0xe
#  define CC_AL				0xf
/* Branches need inverted condition */
#  define BCC_EQ			0x0
#  define BCC_NE			0x1
#  define BCC_CS			0x2
#  define BCC_HS			BCC_CS
#  define BCC_CC			0x3
#  define BCC_LO			BCC_CC
#  define BCC_MI			0x4
#  define BCC_PL			0x5
#  define BCC_VS			0x6
#  define BCC_VC			0x7
#  define BCC_HI			0x8
#  define BCC_LS			0x9
#  define BCC_GE			0xa
#  define BCC_LT			0xb
#  define BCC_GT			0xc
#  define BCC_LE			0xd
#  define BCC_AL			0xe
#  define BCC_NV			0xf
/* adapted and cut down to only tested and required by lightning,
 * from data in binutils/aarch64-tbl.h */
#  define A64_ADCS			0x3a000000
#  define A64_SBCS			0x7a000000
#  define A64_ADDI			0x11000000
#  define A64_ADDSI			0xb1000000
#  define A64_SUBI			0x51000000
#  define A64_SUBSI			0x71000000
#  define A64_ADD			0x0b000000
#  define A64_ADDS			0x2b000000
#  define A64_SUB			0x4b000000
#  define A64_NEG			0x4b0003e0
#  define A64_SUBS			0x6b000000
#  define A64_CMP			0x6b00001f
#  define A64_SBFM			0x93400000
#  define A64_UBFM			0x53400000
#  define A64_UBFX			0x53000000
#  define A64_B				0x14000000
#  define A64_BL			0x94000000
#  define A64_BR			0xd61f0000
#  define A64_BLR			0xd63f0000
#  define A64_RET			0xd65f0000
#  define A64_CBZ			0x34000000
#  define A64_CBNZ			0x35000000
#  define A64_B_C			0x54000000
#  define A64_CSINC			0x1a800400
#  define A64_REV			0xdac00c00
#  define A64_UDIV			0x1ac00800
#  define A64_SDIV			0x1ac00c00
#  define A64_LSL			0x1ac02000
#  define A64_LSR			0x1ac02400
#  define A64_ASR			0x1ac02800
#  define A64_MUL			0x1b007c00
#  define A64_SMULL			0x9b207c00
#  define A64_SMULH			0x9b407c00
#  define A64_UMULL			0x9ba07c00
#  define A64_UMULH			0x9bc07c00
#  define A64_STRBI			0x39000000
#  define A64_LDRBI			0x39400000
#  define A64_LDRSBI			0x39800000
#  define A64_STRI			0xf9000000
#  define A64_LDRI			0xf9400000
#  define A64_STRHI			0x79000000
#  define A64_LDRHI			0x79400000
#  define A64_LDRSHI			0x79800000
#  define A64_STRWI			0xb9000000
#  define A64_LDRWI			0xb9400000
#  define A64_LDRSWI			0xb9800000
#  define A64_STRB			0x38206800
#  define A64_LDRB			0x38606800
#  define A64_LDRSB			0x38e06800
#  define A64_STR			0xf8206800
#  define A64_LDR			0xf8606800
#  define A64_STRH			0x78206800
#  define A64_LDRH			0x78606800
#  define A64_LDRSH			0x78a06800
#  define A64_STRW			0xb8206800
#  define A64_LDRW			0xb8606800
#  define A64_LDRSW			0xb8a06800
#  define A64_STURB			0x38000000
#  define A64_LDURB			0x38400000
#  define A64_LDURSB			0x38800000
#  define A64_STUR			0xf8000000
#  define A64_LDUR			0xf8400000
#  define A64_STURH			0x78000000
#  define A64_LDURH			0x78400000
#  define A64_LDURSH			0x78800000
#  define A64_STURW			0xb8000000
#  define A64_LDURW			0xb8400000
#  define A64_LDURSW			0xb8800000
#  define A64_STP			0x29000000
#  define A64_LDP			0x29400000
#  define A64_STP_POS			0x29800000
#  define A64_LDP_PRE			0x28c00000
#  define A64_ANDI			0x12400000
#  define A64_ORRI			0x32400000
#  define A64_EORI			0x52400000
#  define A64_ANDSI			0x72000000
#  define A64_AND			0x0a000000
#  define A64_ORR			0x2a000000
#  define A64_MOV			0x2a0003e0	/* AKA orr Rd,xzr,Rm */
#  define A64_MVN			0x2a2003e0
#  define A64_UXTW			0x2a0003e0	/* AKA MOV */
#  define A64_EOR			0x4a000000
#  define A64_ANDS			0x6a000000
#  define A64_MOVN			0x12800000
#  define A64_MOVZ			0x52800000
#  define A64_MOVK			0x72800000
#  define SBFM(Rd,Rn,ImmR,ImmS)		oxxrs(A64_SBFM|XS,Rd,Rn,ImmR,ImmS)
#  define UBFM(Rd,Rn,ImmR,ImmS)		oxxrs(A64_UBFM|XS,Rd,Rn,ImmR,ImmS)
#  define UBFX(Rd,Rn,ImmR,ImmS)		oxxrs(A64_UBFX,Rd,Rn,ImmR,ImmS)
#  define CMP(Rn,Rm)			oxx_(A64_CMP|XS,Rn,Rm)
#  define CMPI(Rn,Imm12)		oxxi(A64_SUBSI|XS,XZR_REGNO,Rn,Imm12)
#  define CMPI_12(Rn,Imm12)		oxxi(A64_SUBSI|XS|LSL_12,XZR_REGNO,Rn,Imm12)
#  define CMNI(Rn,Imm12)		oxxi(A64_ADDSI|XS,XZR_REGNO,Rn,Imm12)
#  define CMNI_12(Rn,Imm12)		oxxi(A64_ADDSI|XS|LSL_12,XZR_REGNO,Rn,Imm12)
#  define CSINC(Rd,Rn,Rm,Cc)		oxxxc(A64_CSINC|XS,Rd,Rn,Rm,Cc)
#  define TST(Rn,Rm)			oxxx(A64_ANDS|XS,XZR_REGNO,Rn,Rm)
/* actually should use oxxrs but logical_immediate returns proper encoding */
#  define TSTI(Rn,Imm12)		oxxi(A64_ANDSI,XZR_REGNO,Rn,Imm12)
#  define MOV(Rd,Rm)			ox_x(A64_MOV|XS,Rd,Rm)
#  define MVN(Rd,Rm)			ox_x(A64_MVN|XS,Rd,Rm)
#  define NEG(Rd,Rm)			ox_x(A64_NEG|XS,Rd,Rm)
#  define MOVN(Rd,Imm16)		ox_h(A64_MOVN|XS,Rd,Imm16)
#  define MOVN_16(Rd,Imm16)		ox_h(A64_MOVN|XS|MOVI_LSL_16,Rd,Imm16)
#  define MOVN_32(Rd,Imm16)		ox_h(A64_MOVN|XS|MOVI_LSL_32,Rd,Imm16)
#  define MOVN_48(Rd,Imm16)		ox_h(A64_MOVN|XS|MOVI_LSL_48,Rd,Imm16)
#  define MOVZ(Rd,Imm16)		ox_h(A64_MOVZ|XS,Rd,Imm16)
#  define MOVZ_16(Rd,Imm16)		ox_h(A64_MOVZ|XS|MOVI_LSL_16,Rd,Imm16)
#  define MOVZ_32(Rd,Imm16)		ox_h(A64_MOVZ|XS|MOVI_LSL_32,Rd,Imm16)
#  define MOVZ_48(Rd,Imm16)		ox_h(A64_MOVZ|XS|MOVI_LSL_48,Rd,Imm16)
#  define MOVK(Rd,Imm16)		ox_h(A64_MOVK|XS,Rd,Imm16)
#  define MOVK_16(Rd,Imm16)		ox_h(A64_MOVK|XS|MOVI_LSL_16,Rd,Imm16)
#  define MOVK_32(Rd,Imm16)		ox_h(A64_MOVK|XS|MOVI_LSL_32,Rd,Imm16)
#  define MOVK_48(Rd,Imm16)		ox_h(A64_MOVK|XS|MOVI_LSL_48,Rd,Imm16)
#  define ADD(Rd,Rn,Rm)			oxxx(A64_ADD|XS,Rd,Rn,Rm)
#  define ADDI(Rd,Rn,Imm12)		oxxi(A64_ADDI|XS,Rd,Rn,Imm12)
#  define ADDI_12(Rd,Rn,Imm12)		oxxi(A64_ADDI|XS|LSL_12,Rd,Rn,Imm12)
#  define MOV_XSP(Rd,Rn)		ADDI(Rd,Rn,0)
#  define ADDS(Rd,Rn,Rm)		oxxx(A64_ADDS|XS,Rd,Rn,Rm)
#  define ADDSI(Rd,Rn,Imm12)		oxxi(A64_ADDSI|XS,Rd,Rn,Imm12)
#  define ADDSI_12(Rd,Rn,Imm12)		oxxi(A64_ADDSI|XS|LSL_12,Rd,Rn,Imm12)
#  define ADCS(Rd,Rn,Rm)		oxxx(A64_ADCS|XS,Rd,Rn,Rm)
#  define SUB(Rd,Rn,Rm)			oxxx(A64_SUB|XS,Rd,Rn,Rm)
#  define SUBI(Rd,Rn,Imm12)		oxxi(A64_SUBI|XS,Rd,Rn,Imm12)
#  define SUBI_12(Rd,Rn,Imm12)		oxxi(A64_SUBI|XS|LSL_12,Rd,Rn,Imm12)
#  define SUBS(Rd,Rn,Rm)		oxxx(A64_SUBS|XS,Rd,Rn,Rm)
#  define SUBSI(Rd,Rn,Imm12)		oxxi(A64_SUBSI|XS,Rd,Rn,Imm12)
#  define SUBSI_12(Rd,Rn,Imm12)		oxxi(A64_SUBSI|XS|LSL_12,Rd,Rn,Imm12)
#  define SBCS(Rd,Rn,Rm)		oxxx(A64_SBCS|XS,Rd,Rn,Rm)
#  define MUL(Rd,Rn,Rm)			oxxx(A64_MUL|XS,Rd,Rn,Rm)
#  define SMULL(Rd,Rn,Rm)		oxxx(A64_SMULL,Rd,Rn,Rm)
#  define SMULH(Rd,Rn,Rm)		oxxx(A64_SMULH,Rd,Rn,Rm)
#  define UMULL(Rd,Rn,Rm)		oxxx(A64_UMULL,Rd,Rn,Rm)
#  define UMULH(Rd,Rn,Rm)		oxxx(A64_UMULH,Rd,Rn,Rm)
#  define SDIV(Rd,Rn,Rm)		oxxx(A64_SDIV|XS,Rd,Rn,Rm)
#  define UDIV(Rd,Rn,Rm)		oxxx(A64_UDIV|XS,Rd,Rn,Rm)
#  define LSL(Rd,Rn,Rm)			oxxx(A64_LSL|XS,Rd,Rn,Rm)
#  define LSLI(r0,r1,i0)		UBFM(r0,r1,(64-i0)&63,63-i0)
#  define ASR(Rd,Rn,Rm)			oxxx(A64_ASR|XS,Rd,Rn,Rm)
#  define ASRI(r0,r1,i0)		SBFM(r0,r1,i0,63)
#  define LSR(Rd,Rn,Rm)			oxxx(A64_LSR|XS,Rd,Rn,Rm)
#  define LSRI(r0,r1,i0)		UBFM(r0,r1,i0,63)
#  define AND(Rd,Rn,Rm)			oxxx(A64_AND|XS,Rd,Rn,Rm)
/* actually should use oxxrs but logical_immediate returns proper encoding */
#  define ANDI(Rd,Rn,Imm12)		oxxi(A64_ANDI|XS,Rd,Rn,Imm12)
#  define ORR(Rd,Rn,Rm)			oxxx(A64_ORR|XS,Rd,Rn,Rm)
/* actually should use oxxrs but logical_immediate returns proper encoding */
#  define ORRI(Rd,Rn,Imm12)		oxxi(A64_ORRI|XS,Rd,Rn,Imm12)
#  define EOR(Rd,Rn,Rm)			oxxx(A64_EOR|XS,Rd,Rn,Rm)
/* actually should use oxxrs but logical_immediate returns proper encoding */
#  define EORI(Rd,Rn,Imm12)		oxxi(A64_EORI|XS,Rd,Rn,Imm12)
#  define SXTB(Rd,Rn)			SBFM(Rd,Rn,0,7)
#  define SXTH(Rd,Rn)			SBFM(Rd,Rn,0,15)
#  define SXTW(Rd,Rn)			SBFM(Rd,Rn,0,31)
#  define UXTB(Rd,Rn)			UBFX(Rd,Rn,0,7)
#  define UXTH(Rd,Rn)			UBFX(Rd,Rn,0,15)
#  define UXTW(Rd,Rm)			ox_x(A64_UXTW,Rd,Rm)
#  define REV(Rd,Rn)			o_xx(A64_REV,Rd,Rn)
#  define LDRSB(Rt,Rn,Rm)		oxxx(A64_LDRSB,Rt,Rn,Rm)
#  define LDRSBI(Rt,Rn,Imm12)		oxxi(A64_LDRSBI,Rt,Rn,Imm12)
#  define LDURSB(Rt,Rn,Imm9)		oxx9(A64_LDURSB,Rt,Rn,Imm9)
#  define LDRB(Rt,Rn,Rm)		oxxx(A64_LDRB,Rt,Rn,Rm)
#  define LDRBI(Rt,Rn,Imm12)		oxxi(A64_LDRBI,Rt,Rn,Imm12)
#  define LDURB(Rt,Rn,Imm9)		oxx9(A64_LDURB,Rt,Rn,Imm9)
#  define LDRSH(Rt,Rn,Rm)		oxxx(A64_LDRSH,Rt,Rn,Rm)
#  define LDRSHI(Rt,Rn,Imm12)		oxxi(A64_LDRSHI,Rt,Rn,Imm12)
#  define LDURSH(Rt,Rn,Imm9)		oxx9(A64_LDURSH,Rt,Rn,Imm9)
#  define LDRH(Rt,Rn,Rm)		oxxx(A64_LDRH,Rt,Rn,Rm)
#  define LDRHI(Rt,Rn,Imm12)		oxxi(A64_LDRHI,Rt,Rn,Imm12)
#  define LDURH(Rt,Rn,Imm9)		oxx9(A64_LDURH,Rt,Rn,Imm9)
#  define LDRSW(Rt,Rn,Rm)		oxxx(A64_LDRSW,Rt,Rn,Rm)
#  define LDRSWI(Rt,Rn,Imm12)		oxxi(A64_LDRSWI,Rt,Rn,Imm12)
#  define LDURSW(Rt,Rn,Imm9)		oxx9(A64_LDURSW,Rt,Rn,Imm9)
#  define LDRW(Rt,Rn,Rm)		oxxx(A64_LDRW,Rt,Rn,Rm)
#  define LDRWI(Rt,Rn,Imm12)		oxxi(A64_LDRWI,Rt,Rn,Imm12)
#  define LDURW(Rt,Rn,Imm9)		oxx9(A64_LDURW,Rt,Rn,Imm9)
#  define LDR(Rt,Rn,Rm)			oxxx(A64_LDR,Rt,Rn,Rm)
#  define LDRI(Rt,Rn,Imm12)		oxxi(A64_LDRI,Rt,Rn,Imm12)
#  define LDUR(Rt,Rn,Imm9)		oxx9(A64_LDUR,Rt,Rn,Imm9)
#  define STRB(Rt,Rn,Rm)		oxxx(A64_STRB,Rt,Rn,Rm)
#  define STRBI(Rt,Rn,Imm12)		oxxi(A64_STRBI,Rt,Rn,Imm12)
#  define STURB(Rt,Rn,Imm9)		oxx9(A64_STURB,Rt,Rn,Imm9)
#  define STRH(Rt,Rn,Rm)		oxxx(A64_STRH,Rt,Rn,Rm)
#  define STRHI(Rt,Rn,Imm12)		oxxi(A64_STRHI,Rt,Rn,Imm12)
#  define STURH(Rt,Rn,Imm9)		oxx9(A64_STURH,Rt,Rn,Imm9)
#  define STRW(Rt,Rn,Rm)		oxxx(A64_STRW,Rt,Rn,Rm)
#  define STRWI(Rt,Rn,Imm12)		oxxi(A64_STRWI,Rt,Rn,Imm12)
#  define STURW(Rt,Rn,Imm9)		oxx9(A64_STURW,Rt,Rn,Imm9)
#  define STR(Rt,Rn,Rm)			oxxx(A64_STR,Rt,Rn,Rm)
#  define STRI(Rt,Rn,Imm12)		oxxi(A64_STRI,Rt,Rn,Imm12)
#  define STUR(Rt,Rn,Imm9)		oxx9(A64_STUR,Rt,Rn,Imm9)
#  define LDPI(Rt,Rt2,Rn,Simm7)		oxxx7(A64_LDP|XS,Rt,Rt2,Rn,Simm7)
#  define STPI(Rt,Rt2,Rn,Simm7)		oxxx7(A64_STP|XS,Rt,Rt2,Rn,Simm7)
#  define LDPI_PRE(Rt,Rt2,Rn,Simm7)	oxxx7(A64_LDP_PRE|XS,Rt,Rt2,Rn,Simm7)
#  define STPI_POS(Rt,Rt2,Rn,Simm7)	oxxx7(A64_STP_POS|XS,Rt,Rt2,Rn,Simm7)
#  define CSET(Rd,Cc)			CSINC(Rd,XZR_REGNO,XZR_REGNO,Cc)
#  define B(Simm26)			o26(A64_B,Simm26)
#  define BL(Simm26)			o26(A64_BL,Simm26)
#  define BR(Rn)			o_x_(A64_BR,Rn)
#  define BLR(Rn)			o_x_(A64_BLR,Rn)
#  define RET()				o_x_(A64_RET,LR_REGNO)
#  define B_C(Cc,Simm19)		oc19(A64_B_C,Cc,Simm19)
#  define CBZ(Rd,Simm19)		ox19(A64_CBZ|XS,Rd,Simm19)
#  define CBNZ(Rd,Simm19)		ox19(A64_CBNZ|XS,Rd,Simm19)
#  define NOP()				ii(0xd503201f)
static jit_int32_t logical_immediate(jit_word_t);
#  define oxxx(Op,Rd,Rn,Rm)		_oxxx(_jit,Op,Rd,Rn,Rm)
static void _oxxx(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxxi(Op,Rd,Rn,Imm12)		_oxxi(_jit,Op,Rd,Rn,Imm12)
static void _oxxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxx9(Op,Rd,Rn,Imm9)		_oxx9(_jit,Op,Rd,Rn,Imm9)
static void _oxx9(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define ox19(Op,Rd,Simm19)		_ox19(_jit,Op,Rd,Simm19)
static void _ox19(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define oc19(Op,Cc,Simm19)		_oc19(_jit,Op,Cc,Simm19)
static void _oc19(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define o26(Op,Simm26)		_o26(_jit,Op,Simm26)
static void _oc26(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ox_x(Op,Rd,Rn)		_ox_x(_jit,Op,Rd,Rn)
static void _ox_x(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define o_xx(Op,Rd,Rn)		_o_xx(_jit,Op,Rd,Rn)
static void _o_xx(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxx_(Op,Rn,Rm)		_oxx_(_jit,Op,Rn,Rm)
static void _oxx_(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define o_x_(Op,Rn)			_o_x_(_jit,Op,Rn)
static void _o_x_(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ox_h(Op,Rd,Imm16)		_ox_h(_jit,Op,Rd,Imm16)
static void _ox_h(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxxrs(Op,Rd,Rn,R,S)		_oxxrs(_jit,Op,Rd,Rn,R,S)
static void _oxxrs(jit_state_t*,jit_int32_t,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxxxc(Op,Rd,Rn,Rm,Cc)		_oxxxc(_jit,Op,Rd,Rn,Rm,Cc)
static void _oxxxc(jit_state_t*,jit_int32_t,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_int32_t);
#  define oxxx7(Op,Rt,Rt2,Rn,Simm7)	_oxxx7(_jit,Op,Rt,Rt2,Rn,Simm7)
static void _oxxx7(jit_state_t*,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define nop(i0)			_nop(_jit,i0)
static void _nop(jit_state_t*,jit_int32_t);
#  define addr(r0,r1,r2)		ADD(r0,r1,r2)
#  define addi(r0,r1,i0)		_addi(_jit,r0,r1,i0)
static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define addcr(r0,r1,r2)		ADDS(r0,r1,r2)
#  define addci(r0,r1,i0)		_addci(_jit,r0,r1,i0)
static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define addxr(r0,r1,r2)		ADCS(r0,r1,r2)
#  define addxi(r0,r1,i0)		_addxi(_jit,r0,r1,i0)
static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define subr(r0,r1,r2)		SUB(r0,r1,r2)
#  define subi(r0,r1,i0)		_subi(_jit,r0,r1,i0)
static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define subcr(r0,r1,r2)		SUBS(r0,r1,r2)
#  define subci(r0,r1,i0)		_subci(_jit,r0,r1,i0)
static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define subxr(r0,r1,r2)		SBCS(r0,r1,r2)
#  define subxi(r0,r1,i0)		_subxi(_jit,r0,r1,i0)
static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define rsbi(r0, r1, i0)		_rsbi(_jit, r0, r1, i0)
static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define mulr(r0,r1,r2)		MUL(r0,r1,r2)
#  define muli(r0,r1,i0)		_muli(_jit,r0,r1,i0)
static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define qmulr(r0,r1,r2,r3)		_qmulr(_jit,r0,r1,r2,r3)
static void _qmulr(jit_state_t*,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_int32_t);
#  define qmuli(r0,r1,r2,i0)		_qmuli(_jit,r0,r1,r2,i0)
static void _qmuli(jit_state_t*,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_word_t);
#  define qmulr_u(r0,r1,r2,r3)		_qmulr_u(_jit,r0,r1,r2,r3)
static void _qmulr_u(jit_state_t*,jit_int32_t,
		     jit_int32_t,jit_int32_t,jit_int32_t);
#  define qmuli_u(r0,r1,r2,i0)		_qmuli_u(_jit,r0,r1,r2,i0)
static void _qmuli_u(jit_state_t*,jit_int32_t,
		     jit_int32_t,jit_int32_t,jit_word_t);
#  define divr(r0,r1,r2)		SDIV(r0,r1,r2)
#  define divi(r0,r1,i0)		_divi(_jit,r0,r1,i0)
static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define divr_u(r0,r1,r2)		UDIV(r0,r1,r2)
#  define divi_u(r0,r1,i0)		_divi_u(_jit,r0,r1,i0)
static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define qdivr(r0,r1,r2,r3)		_iqdivr(_jit,1,r0,r1,r2,r3)
#  define qdivr_u(r0,r1,r2,r3)		_iqdivr(_jit,0,r0,r1,r2,r3)
static void _iqdivr(jit_state_t*,jit_bool_t,
		    jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define qdivi(r0,r1,r2,i0)		_qdivi(_jit,r0,r1,r2,i0)
static void _qdivi(jit_state_t*,jit_int32_t,
		   jit_int32_t,jit_int32_t,jit_word_t);
#  define qdivi_u(r0,r1,r2,i0)		_qdivi_u(_jit,r0,r1,r2,i0)
static void _qdivi_u(jit_state_t*,jit_int32_t,
		     jit_int32_t,jit_int32_t,jit_word_t);
#  define remr(r0,r1,r2)		_remr(_jit,r0,r1,r2)
static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define remi(r0,r1,i0)		_remi(_jit,r0,r1,i0)
static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define remr_u(r0,r1,r2)		_remr_u(_jit,r0,r1,r2)
static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define remi_u(r0,r1,i0)		_remi_u(_jit,r0,r1,i0)
static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define lshr(r0,r1,r2)		LSL(r0,r1,r2)
#  define lshi(r0,r1,i0)		_lshi(_jit,r0,r1,i0)
static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define rshr(r0,r1,r2)		ASR(r0,r1,r2)
#  define rshi(r0,r1,i0)		_rshi(_jit,r0,r1,i0)
static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define rshr_u(r0,r1,r2)		LSR(r0,r1,r2)
#  define rshi_u(r0,r1,i0)		_rshi_u(_jit,r0,r1,i0)
static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define negr(r0,r1)			NEG(r0,r1)
#  define comr(r0,r1)			MVN(r0,r1)
#  define andr(r0,r1,r2)		AND(r0,r1,r2)
#  define andi(r0,r1,i0)		_andi(_jit,r0,r1,i0)
static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define orr(r0,r1,r2)			ORR(r0,r1,r2)
#  define ori(r0,r1,i0)			_ori(_jit,r0,r1,i0)
static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define xorr(r0,r1,r2)		EOR(r0,r1,r2)
#  define xori(r0,r1,i0)		_xori(_jit,r0,r1,i0)
static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldr_c(r0,r1)			LDRSBI(r0,r1,0)
#  define ldi_c(r0,i0)			_ldi_c(_jit,r0,i0)
static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_uc(r0,r1)			_ldr_uc(_jit,r0,r1)
static void _ldr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ldi_uc(r0,i0)			_ldi_uc(_jit,r0,i0)
static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_s(r0,r1)			LDRSHI(r0,r1,0)
#  define ldi_s(r0,i0)			_ldi_s(_jit,r0,i0)
static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_us(r0,r1)			_ldr_us(_jit,r0,r1)
static void _ldr_us(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ldi_us(r0,i0)			_ldi_us(_jit,r0,i0)
static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_i(r0,r1)			LDRSWI(r0,r1,0)
#  define ldi_i(r0,i0)			_ldi_i(_jit,r0,i0)
static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_ui(r0,r1)			_ldr_ui(_jit,r0,r1)
static void _ldr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ldi_ui(r0,i0)			_ldi_ui(_jit,r0,i0)
static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldr_l(r0,r1)			LDRI(r0,r1,0)
static void _ldr_l(jit_state_t*,jit_int32_t,jit_int32_t);
#  define ldi_l(r0,i0)			_ldi_l(_jit,r0,i0)
static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
#  define ldxr_c(r0,r1,r2)		_ldxr_c(_jit,r0,r1,r2)
static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define ldxi_c(r0,r1,i0)		_ldxi_c(_jit,r0,r1,i0)
static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_uc(r0,r1,r2)		_ldxr_uc(_jit,r0,r1,r2)
static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define ldxi_uc(r0,r1,i0)		_ldxi_uc(_jit,r0,r1,i0)
static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_s(r0,r1,r2)		LDRSH(r0,r1,r2)
#  define ldxi_s(r0,r1,i0)		_ldxi_s(_jit,r0,r1,i0)
static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_us(r0,r1,r2)		_ldxr_us(_jit,r0,r1,r2)
static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define ldxi_us(r0,r1,i0)		_ldxi_us(_jit,r0,r1,i0)
static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_i(r0,r1,r2)		LDRSW(r0,r1,r2)
#  define ldxi_i(r0,r1,i0)		_ldxi_i(_jit,r0,r1,i0)
static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_ui(r0,r1,r2)		_ldxr_ui(_jit,r0,r1,r2)
static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
#  define ldxi_ui(r0,r1,i0)		_ldxi_ui(_jit,r0,r1,i0)
static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define ldxr_l(r0,r1,r2)		LDR(r0,r1,r2)
#  define ldxi_l(r0,r1,i0)		_ldxi_l(_jit,r0,r1,i0)
static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
#  define str_c(r0,r1)			STRBI(r1,r0,0)
#  define sti_c(i0,r0)			_sti_c(_jit,i0,r0)
static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
#  define str_s(r0,r1)			STRHI(r1,r0,0)
#  define sti_s(i0,r0)			_sti_s(_jit,i0,r0)
static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
#  define str_i(r0,r1)			STRWI(r1,r0,0)
#  define sti_i(i0,r0)			_sti_i(_jit,i0,r0)
static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
#  define str_l(r0,r1)			STRI(r1,r0,0)
#  define sti_l(i0,r0)			_sti_l(_jit,i0,r0)
static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
#  define stxr_c(r0,r1,r2)		STRB(r2,r1,r0)
#  define stxi_c(i0,r0,r1)		_stxi_c(_jit,i0,r0,r1)
static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
#  define stxr_s(r0,r1,r2)		STRH(r2,r1,r0)
#  define stxi_s(i0,r0,r1)		_stxi_s(_jit,i0,r0,r1)
static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
#  define stxr_i(r0,r1,r2)		STRW(r2,r1,r0)
#  define stxi_i(i0,r0,r1)		_stxi_i(_jit,i0,r0,r1)
static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
#  define stxr_l(r0,r1,r2)		STR(r2,r1,r0)
#  define stxi_l(i0,r0,r1)		_stxi_l(_jit,i0,r0,r1)
static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
#  if __BYTE_ORDER == __LITTLE_ENDIAN
#  define htonr_us(r0,r1)		_htonr_us(_jit,r0,r1)
static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
#  define htonr_ui(r0,r1)		_htonr_ui(_jit,r0,r1)
static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
#    define htonr_ul(r0,r1)		REV(r0,r1)
#  else
#    define htonr_us(r0,r1)		extr_us(r0,r1)
#    define htonr_ui(r0,r1)		extr_ui(r0,r1)
#    define htonr_ul(r0,r1)		movr(r0,r1)
#  endif
#  define extr_c(r0,r1)			SXTB(r0,r1)
#  define extr_uc(r0,r1)		UXTB(r0,r1)
#  define extr_s(r0,r1)			SXTH(r0,r1)
#  define extr_us(r0,r1)		UXTH(r0,r1)
#  define extr_i(r0,r1)			SXTW(r0,r1)
#  define extr_ui(r0,r1)		UXTW(r0,r1)
#  define movr(r0,r1)			_movr(_jit,r0,r1)
static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
#  define movi(r0,i0)			_movi(_jit,r0,i0)
static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
#  define movi_p(r0,i0)			_movi_p(_jit,r0,i0)
static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
#  define ccr(cc,r0,r1,r2)		_ccr(_jit,cc,r0,r1,r2)
static void _ccr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
#  define cci(cc,r0,r1,i0)		_cci(_jit,cc,r0,r1,i0)
static void _cci(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
#  define ltr(r0,r1,r2)			ccr(CC_LT,r0,r1,r2)
#  define lti(r0,r1,i0)			cci(CC_LT,r0,r1,i0)
#  define ltr_u(r0,r1,r2)		ccr(CC_CC,r0,r1,r2)
#  define lti_u(r0,r1,i0)		cci(CC_CC,r0,r1,i0)
#  define ler(r0,r1,r2)			ccr(CC_LE,r0,r1,r2)
#  define lei(r0,r1,i0)			cci(CC_LE,r0,r1,i0)
#  define ler_u(r0,r1,r2)		ccr(CC_LS,r0,r1,r2)
#  define lei_u(r0,r1,i0)		cci(CC_LS,r0,r1,i0)
#  define eqr(r0,r1,r2)			ccr(CC_EQ,r0,r1,r2)
#  define eqi(r0,r1,i0)			cci(CC_EQ,r0,r1,i0)
#  define ger(r0,r1,r2)			ccr(CC_GE,r0,r1,r2)
#  define gei(r0,r1,i0)			cci(CC_GE,r0,r1,i0)
#  define ger_u(r0,r1,r2)		ccr(CC_CS,r0,r1,r2)
#  define gei_u(r0,r1,i0)		cci(CC_CS,r0,r1,i0)
#  define gtr(r0,r1,r2)			ccr(CC_GT,r0,r1,r2)
#  define gti(r0,r1,i0)			cci(CC_GT,r0,r1,i0)
#  define gtr_u(r0,r1,r2)		ccr(CC_HI,r0,r1,r2)
#  define gti_u(r0,r1,i0)		cci(CC_HI,r0,r1,i0)
#  define ner(r0,r1,r2)			ccr(CC_NE,r0,r1,r2)
#  define nei(r0,r1,i0)			cci(CC_NE,r0,r1,i0)
#  define bccr(cc,i0,r0,r1)		_bccr(_jit,cc,i0,r0,r1)
static jit_word_t
_bccr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
#  define bcci(cc,i0,r0,i1)		_bcci(_jit,cc,i0,r0,i1)
static jit_word_t
_bcci(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
#  define bltr(i0,r0,r1)		bccr(BCC_LT,i0,r0,r1)
#  define blti(i0,r0,i1)		bcci(BCC_LT,i0,r0,i1)
#  define bltr_u(i0,r0,r1)		bccr(BCC_CC,i0,r0,r1)
#  define blti_u(i0,r0,i1)		bcci(BCC_CC,i0,r0,i1)
#  define bler(i0,r0,r1)		bccr(BCC_LE,i0,r0,r1)
#  define blei(i0,r0,i1)		bcci(BCC_LE,i0,r0,i1)
#  define bler_u(i0,r0,r1)		bccr(BCC_LS,i0,r0,r1)
#  define blei_u(i0,r0,i1)		bcci(BCC_LS,i0,r0,i1)
#  define beqr(i0,r0,r1)		bccr(BCC_EQ,i0,r0,r1)
#  define beqi(i0,r0,i1)		_beqi(_jit,i0,r0,i1)
static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
#  define bger(i0,r0,r1)		bccr(BCC_GE,i0,r0,r1)
#  define bgei(i0,r0,i1)		bcci(BCC_GE,i0,r0,i1)
#  define bger_u(i0,r0,r1)		bccr(BCC_CS,i0,r0,r1)
#  define bgei_u(i0,r0,i1)		bcci(BCC_CS,i0,r0,i1)
#  define bgtr(i0,r0,r1)		bccr(BCC_GT,i0,r0,r1)
#  define bgti(i0,r0,i1)		bcci(BCC_GT,i0,r0,i1)
#  define bgtr_u(i0,r0,r1)		bccr(BCC_HI,i0,r0,r1)
#  define bgti_u(i0,r0,i1)		bcci(BCC_HI,i0,r0,i1)
#  define bner(i0,r0,r1)		bccr(BCC_NE,i0,r0,r1)
#  define bnei(i0,r0,i1)		_bnei(_jit,i0,r0,i1)
static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
#  define baddr(cc,i0,r0,r1)		_baddr(_jit,cc,i0,r0,r1)
static jit_word_t
_baddr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
#  define baddi(cc,i0,r0,i1)		_baddi(_jit,cc,i0,r0,i1)
static jit_word_t
_baddi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
#  define boaddr(i0,r0,r1)		baddr(BCC_VS,i0,r0,r1)
#  define boaddi(i0,r0,i1)		baddi(BCC_VS,i0,r0,i1)
#  define boaddr_u(i0,r0,r1)		baddr(BCC_HS,i0,r0,r1)
#  define boaddi_u(i0,r0,i1)		baddi(BCC_HS,i0,r0,i1)
#  define bxaddr(i0,r0,r1)		baddr(BCC_VC,i0,r0,r1)
#  define bxaddi(i0,r0,i1)		baddi(BCC_VC,i0,r0,i1)
#  define bxaddr_u(i0,r0,r1)		baddr(BCC_LO,i0,r0,r1)
#  define bxaddi_u(i0,r0,i1)		baddi(BCC_LO,i0,r0,i1)
#  define bsubr(cc,i0,r0,r1)		_bsubr(_jit,cc,i0,r0,r1)
static jit_word_t
_bsubr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
#  define bsubi(cc,i0,r0,i1)		_bsubi(_jit,cc,i0,r0,i1)
static jit_word_t
_bsubi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
#  define bosubr(i0,r0,r1)		bsubr(BCC_VS,i0,r0,r1)
#  define bosubi(i0,r0,i1)		bsubi(BCC_VS,i0,r0,i1)
#  define bosubr_u(i0,r0,r1)		bsubr(BCC_LO,i0,r0,r1)
#  define bosubi_u(i0,r0,i1)		bsubi(BCC_LO,i0,r0,i1)
#  define bxsubr(i0,r0,r1)		bsubr(BCC_VC,i0,r0,r1)
#  define bxsubi(i0,r0,i1)		bsubi(BCC_VC,i0,r0,i1)
#  define bxsubr_u(i0,r0,r1)		bsubr(BCC_HS,i0,r0,r1)
#  define bxsubi_u(i0,r0,i1)		bsubi(BCC_HS,i0,r0,i1)
#  define bmxr(cc,i0,r0,r1)		_bmxr(_jit,cc,i0,r0,r1)
static jit_word_t
_bmxr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
#  define bmxi(cc,i0,r0,r1)		_bmxi(_jit,cc,i0,r0,r1)
static jit_word_t
_bmxi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
#  define bmsr(i0,r0,r1)		bmxr(BCC_NE,i0,r0,r1)
#  define bmsi(i0,r0,i1)		bmxi(BCC_NE,i0,r0,i1)
#  define bmcr(i0,r0,r1)		bmxr(BCC_EQ,i0,r0,r1)
#  define bmci(i0,r0,i1)		bmxi(BCC_EQ,i0,r0,i1)
#  define jmpr(r0)			BR(r0)
#  define jmpi(i0)			_jmpi(_jit,i0)
static void _jmpi(jit_state_t*,jit_word_t);
#  define jmpi_p(i0)			_jmpi_p(_jit,i0)
static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
#  define callr(r0)			BLR(r0)
#  define calli(i0)			_calli(_jit,i0)
static void _calli(jit_state_t*,jit_word_t);
#  define calli_p(i0)			_calli_p(_jit,i0)
static jit_word_t _calli_p(jit_state_t*,jit_word_t);
#  define prolog(i0)			_prolog(_jit,i0)
static void _prolog(jit_state_t*,jit_node_t*);
#  define epilog(i0)			_epilog(_jit,i0)
static void _epilog(jit_state_t*,jit_node_t*);
#  define vastart(r0)			_vastart(_jit, r0)
static void _vastart(jit_state_t*, jit_int32_t);
#  define vaarg(r0, r1)			_vaarg(_jit, r0, r1)
static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
#  define patch_at(jump,label)		_patch_at(_jit,jump,label)
static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
#endif

#if CODE
static jit_int32_t
logical_immediate(jit_word_t imm)
{
    /* There are 5334 possible immediate values, but to avoid the
     * need of either too complex code or large lookup tables,
     * only check for (simply) encodable common/small values */
    switch (imm) {
	case -16:	return (0xf3b);
	case -15:	return (0xf3c);
	case -13:	return (0xf3d);
	case -9:	return (0xf3e);
	case -8:	return (0xf7c);
	case -7:	return (0xf7d);
	case -5:	return (0xf7e);
	case -4:	return (0xfbd);
	case -3:	return (0xfbe);
	case -2:	return (0xffe);
	case 1:		return (0x000);
	case 2:		return (0xfc0);
	case 3:		return (0x001);
	case 4:		return (0xf80);
	case 6:		return (0xfc1);
	case 7:		return (0x002);
	case 8:		return (0xf40);
	case 12:	return (0xf81);
	case 14:	return (0xfc2);
	case 15:	return (0x003);
	case 16:	return (0xf00);
	default:	return (-1);
    }
}

static void
_oxxx(jit_state_t *_jit, jit_int32_t Op,
      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Rm)
{
    instr_t	i;
    assert(!(Rd &       ~0x1f));
    assert(!(Rn &       ~0x1f));
    assert(!(Rm &       ~0x1f));
    assert(!(Op & ~0xffe0fc00));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    i.Rm.b = Rm;
    ii(i.w);
}

static void
_oxxi(jit_state_t *_jit, jit_int32_t Op,
      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Imm12)
{
    instr_t	i;
    assert(!(Rd    &       ~0x1f));
    assert(!(Rn    &       ~0x1f));
    assert(!(Imm12 &      ~0xfff));
    assert(!(Op    & ~0xffe00000));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    i.imm12.b = Imm12;
    ii(i.w);
}

static void
_oxx9(jit_state_t *_jit, jit_int32_t Op,
      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Imm9)
{
    instr_t	i;
    assert(!(Rd   &       ~0x1f));
    assert(!(Rn   &       ~0x1f));
    assert(!(Imm9 &      ~0x1ff));
    assert(!(Op   & ~0xffe00000));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    i.imm9.b = Imm9;
    ii(i.w);
}

static void
_ox19(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Simm19)
{
    instr_t	i;
    assert(!(Rd &         ~0x1f));
    assert(Simm19 >= -262148 && Simm19 <= 262143);
    assert(!(Op   & ~0xff000000));
    i.w = Op;
    i.Rd.b = Rd;
    i.imm19.b = Simm19;
    ii(i.w);
}

static void
_oc19(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Cc, jit_int32_t Simm19)
{
    instr_t	i;
    assert(!(Cc &          ~0xf));
    assert(Simm19 >= -262148 && Simm19 <= 262143);
    assert(!(Op   & ~0xff000000));
    i.w = Op;
    i.cond2.b = Cc;
    i.imm19.b = Simm19;
    ii(i.w);
}

static void
_o26(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Simm26)
{
    instr_t	i;
    assert(Simm26 >= -33554432 && Simm26 <= 33554431);
    assert(!(Op   & ~0xfc000000));
    i.w = Op;
    i.imm26.b = Simm26;
    ii(i.w);
}

static void
_ox_x(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Rm)
{
    instr_t	i;
    assert(!(Rd &       ~0x1f));
    assert(!(Rm &       ~0x1f));
    assert(!(Op & ~0xffe0ffe0));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rm.b = Rm;
    ii(i.w);
}

static void
_o_xx(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Rn)
{
    instr_t	i;
    assert(!(Rd &       ~0x1f));
    assert(!(Rn &       ~0x1f));
    assert(!(Op & ~0xfffffc00));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    ii(i.w);
}

static void
_oxx_(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rn, jit_int32_t Rm)
{
    instr_t	i;
    assert(!(Rn &       ~0x1f));
    assert(!(Rm &       ~0x1f));
    assert(!(Op & ~0xffc0fc1f));
    i.w = Op;
    i.Rn.b = Rn;
    i.Rm.b = Rm;
    ii(i.w);
}

static void
_o_x_(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rn)
{
    instr_t	i;
    assert(!(Rn & ~0x1f));
    assert(!(Op & 0x3e0));
    i.w = Op;
    i.Rn.b = Rn;
    ii(i.w);
}

static void
_ox_h(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Imm16)
{
    instr_t	i;
    assert(!(Rd    &       ~0x1f));
    assert(!(Imm16 &     ~0xffff));
    assert(!(Op    & ~0xffe00000));
    i.w = Op;
    i.Rd.b = Rd;
    i.imm16.b = Imm16;
    ii(i.w);
}

static void
_oxxrs(jit_state_t *_jit, jit_int32_t Op,
       jit_int32_t Rd, jit_int32_t Rn, jit_int32_t R, jit_int32_t S)
{
    instr_t	i;
    assert(!(Rd &       ~0x1f));
    assert(!(Rn &       ~0x1f));
    assert(!(R  &       ~0x3f));
    assert(!(S  &       ~0x3f));
    assert(!(Op & ~0xffc00000));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    i.immr.b = R;
    i.imms.b = S;
    ii(i.w);
}

static void
_oxxxc(jit_state_t *_jit, jit_int32_t Op,
       jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Rm, jit_int32_t Cc)
{
    instr_t	i;
    assert(!(Rd &       ~0x1f));
    assert(!(Rn &       ~0x1f));
    assert(!(Rm &       ~0x1f));
    assert(!(Cc  &       ~0xf));
    assert(!(Op & ~0xffc00c00));
    i.w = Op;
    i.Rd.b = Rd;
    i.Rn.b = Rn;
    i.Rm.b = Rm;
    i.cond.b = Cc;
    ii(i.w);
}

static void
_oxxx7(jit_state_t *_jit, jit_int32_t Op,
       jit_int32_t Rt, jit_int32_t Rt2, jit_int32_t Rn, jit_int32_t Simm7)
{
    instr_t	i;
    assert(!(Rt  &       ~0x1f));
    assert(!(Rt2 &       ~0x1f));
    assert(!(Rn  &       ~0x1f));
    assert(Simm7 >= -128 && Simm7 <= 127);
    assert(!(Op & ~0xffc003e0));
    i.w = Op;
    i.Rt.b = Rt;
    i.Rt2.b = Rt2;
    i.Rn.b = Rn;
    i.imm7.b = Simm7;
    ii(i.w);
}

static void
_nop(jit_state_t *_jit, jit_int32_t i0)
{
    for (; i0 > 0; i0 -= 4)
	NOP();
    assert(i0 == 0);
}

static void
_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_word_t		is =  i0 >> 12;
    jit_word_t		in = -i0;
    jit_word_t		iS =  in >> 12;
    if (      i0 >= 0 && i0 <= 0xfff)
	ADDI   (r0, r1, i0);
    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
	ADDI_12(r0, r1, is);
    else if ( in >= 0 && in <= 0xfff)
	SUBI   (r0, r1, in);
    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
	SUBI_12(r0, r1, iS);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	addr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_word_t		is =  i0 >> 12;
    jit_word_t		in = -i0;
    jit_word_t		iS =  in >> 12;
    if (      i0 >= 0 && i0 <= 0xfff)
	ADDSI   (r0, r1, i0);
    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
	ADDSI_12(r0, r1, is);
    else if ( in >= 0 && in <= 0xfff)
	SUBSI   (r0, r1, in);
    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
	SUBSI_12(r0, r1, iS);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	addcr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    addxr(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_word_t		is = i0 >> 12;
    if (      i0 >= 0 && i0 <= 0xfff)
	SUBI   (r0, r1, i0);
    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
	SUBI_12(r0, r1, is);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	subr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_word_t		is = i0 >> 12;
    if (      i0 >= 0 && i0 <= 0xfff)
	SUBSI   (r0, r1, i0);
    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
	SUBSI_12(r0, r1, is);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	subcr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    subxr(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    subi(r0, r1, i0);
    negr(r0, r0);
}

static void
_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    mulr(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_qmulr(jit_state_t *_jit, jit_int32_t r0,
       jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
{
    jit_int32_t		reg;
    if (r0 == r2 || r0 == r3) {
	reg = jit_get_reg(jit_class_gpr);
	mulr(rn(reg), r2, r3);
    }
    else
	mulr(r0, r2, r3);
    SMULH(r1, r2, r3);
    if (r0 == r2 || r0 == r3) {
	movr(r0, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_qmuli(jit_state_t *_jit, jit_int32_t r0,
       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    qmulr(r0, r1, r2, rn(reg));
    jit_unget_reg(reg);
}

static void
_qmulr_u(jit_state_t *_jit, jit_int32_t r0,
	 jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
{
    jit_int32_t		reg;
    if (r0 == r2 || r0 == r3) {
	reg = jit_get_reg(jit_class_gpr);
	mulr(rn(reg), r2, r3);
    }
    else
	mulr(r0, r2, r3);
    UMULH(r1, r2, r3);
    if (r0 == r2 || r0 == r3) {
	movr(r0, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_qmuli_u(jit_state_t *_jit, jit_int32_t r0,
	 jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    qmulr_u(r0, r1, r2, rn(reg));
    jit_unget_reg(reg);
}

static void
_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    divr(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    divr_u(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_iqdivr(jit_state_t *_jit, jit_bool_t sign,
	jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
{
    jit_int32_t		sv0, rg0;
    jit_int32_t		sv1, rg1;
    if (r0 == r2 || r0 == r3) {
	sv0 = jit_get_reg(jit_class_gpr);
	rg0 = rn(sv0);
    }
    else
	rg0 = r0;
    if (r1 == r2 || r1 == r3) {
	sv1 = jit_get_reg(jit_class_gpr);
	rg1 = rn(sv1);
    }
    else
	rg1 = r1;
    if (sign)
	divr(rg0, r2, r3);
    else
	divr_u(rg0, r2, r3);
    mulr(rg1, r3, rg0);
    subr(rg1, r2, rg1);
    if (rg0 != r0) {
	movr(r0, rg0);
	jit_unget_reg(sv0);
    }
    if (rg1 != r1) {
	movr(r1, rg1);
	jit_unget_reg(sv1);
    }
}

static void
_qdivi(jit_state_t *_jit, jit_int32_t r0,
       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    qdivr(r0, r1, r2, rn(reg));
    jit_unget_reg(reg);
}

static void
_qdivi_u(jit_state_t *_jit, jit_int32_t r0,
	 jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    qdivr_u(r0, r1, r2, rn(reg));
    jit_unget_reg(reg);
}

static void
_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    jit_int32_t		reg;
    if (r0 == r1 || r0 == r2) {
	reg = jit_get_reg(jit_class_gpr);
	divr(rn(reg), r1, r2);
	mulr(rn(reg), r2, rn(reg));
	subr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
    else {
	divr(r0, r1, r2);
	mulr(r0, r2, r0);
	subr(r0, r1, r0);
    }
}

static void
_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    remr(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    jit_int32_t		reg;
    if (r0 == r1 || r0 == r2) {
	reg = jit_get_reg(jit_class_gpr);
	divr_u(rn(reg), r1, r2);
	mulr(rn(reg), r2, rn(reg));
	subr(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
    else {
	divr_u(r0, r1, r2);
	mulr(r0, r2, r0);
	subr(r0, r1, r0);
    }
}

static void
_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    remr_u(r0, r1, rn(reg));
    jit_unget_reg(reg);
}

static void
_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    if (i0 == 0)
	movr(r0, r1);
    else {
	assert(i0 > 0 && i0 < 64);
	LSLI(r0, r1, i0);
    }
}

static void
_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    if (i0 == 0)
	movr(r0, r1);
    else {
	assert(i0 > 0 && i0 < 64);
	ASRI(r0, r1, i0);
    }
}

static void
_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    if (i0 == 0)
	movr(r0, r1);
    else {
	assert(i0 > 0 && i0 < 64);
	LSRI(r0, r1, i0);
    }
}

static void
_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_int32_t		imm;
    if (i0 == 0)
	movi(r0, 0);
    else if (i0 == -1)
	movr(r0, r1);
    else {
	imm = logical_immediate(i0);
	if (imm != -1)
	    ANDI(r0, r1, imm);
	else {
	    reg = jit_get_reg(jit_class_gpr);
	    movi(rn(reg), i0);
	    andr(r0, r1, rn(reg));
	    jit_unget_reg(reg);
	}
    }
}

static void
_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_int32_t		imm;
    if (i0 == 0)
	movr(r0, r1);
    else if (i0 == -1)
	movi(r0, -1);
    else {
	imm = logical_immediate(i0);
	if (imm != -1)
	    ORRI(r0, r1, imm);
	else {
	    reg = jit_get_reg(jit_class_gpr);
	    movi(rn(reg), i0);
	    orr(r0, r1, rn(reg));
	    jit_unget_reg(reg);
	}
    }
}

static void
_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_int32_t		imm;
    if (i0 == 0)
	movr(r0, r1);
    else if (i0 == -1)
	comr(r0, r1);
    else {
	imm = logical_immediate(i0);
	if (imm != -1)
	    EORI(r0, r1, imm);
	else {
	    reg = jit_get_reg(jit_class_gpr);
	    movi(rn(reg), i0);
	    xorr(r0, r1, rn(reg));
	    jit_unget_reg(reg);
	}
    }
}

#if __BYTE_ORDER == __LITTLE_ENDIAN
static void
_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    htonr_ul(r0, r1);
    rshi_u(r0, r0, 48);
}

static void
_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    htonr_ul(r0, r1);
    rshi_u(r0, r0, 32);
}
#endif

static void
_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_c(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    LDRBI(r0, r1, 0);
#if 0
    extr_uc(r0, r0);
#endif
}

static void
_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_uc(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_s(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    LDRHI(r0, r1, 0);
#if 0
    extr_us(r0, r0);
#endif
}

static void
_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_us(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_i(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    LDRWI(r0, r1, 0);
#if 0
    extr_ui(r0, r0);
#endif
}

static void
_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_ui(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    ldr_l(r0, rn(reg));
    jit_unget_reg(reg);
}

static void
_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    LDRSB(r0, r1, r2);
    extr_c(r0, r0);
}

static void
_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 4095)
	LDRSBI(r0, r1, i0);
    else if (i0 > -256 && i0 < 0)
	LDURSB(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	LDRSB(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
    extr_c(r0, r0);
}

static void
_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    LDRB(r0, r1, r2);
#if 0
    extr_uc(r0, r0);
#endif
}

static void
_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 4095)
	LDRBI(r0, r1, i0);
    else if (i0 > -256 && i0 < 0)
	LDURB(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r1, i0);
	ldr_uc(r0, rn(reg));
	jit_unget_reg(reg);
    }
#if 0
    extr_uc(r0, r0);
#endif
}

static void
_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 8191 && !(i0 & 1))
	LDRSHI(r0, r1, i0 >> 1);
    else if (i0 > -256 && i0 < 0)
	LDURSH(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	LDRSH(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    LDRH(r0, r1, r2);
#if 0
    extr_us(r0, r0);
#endif
}

static void
_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 8191 && !(i0 & 1))
	LDRHI(r0, r1, i0 >> 1);
    else if (i0 > -256 && i0 < 0)
	LDURH(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	LDRH(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
#if 0
    extr_us(r0, r0);
#endif
}

static void
_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 16383 && !(i0 & 3))
	LDRSWI(r0, r1, i0 >> 2);
    else if (i0 > -256 && i0 < 0)
	LDURSW(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r1, i0);
	ldr_i(r0, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    LDRW(r0, r1, r2);
#if 0
    extr_ui(r0, r0);
#endif
}

static void
_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 16383 && !(i0 & 3))
	LDRWI(r0, r1, i0 >> 2);
    else if (i0 > -256 && i0 < 0)
	LDURW(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	LDRW(r0, r1, rn(reg));
	jit_unget_reg(reg);
    }
#if 0
    extr_ui(r0, r0);
#endif
}

static void
_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 32767 && !(i0 & 7))
	LDRI(r0, r1, i0 >> 3);
    else if (i0 > -256 && i0 < 0)
	LDUR(r0, r1, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r1, i0);
	ldr_l(r0, rn(reg));
	jit_unget_reg(reg);
    }
}

static void
_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    str_c(rn(reg), r0);
    jit_unget_reg(reg);
}

static void
_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    str_s(rn(reg), r0);
    jit_unget_reg(reg);
}

static void
_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    str_i(rn(reg), r0);
    jit_unget_reg(reg);
}

static void
_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
{
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    movi(rn(reg), i0);
    str_l(rn(reg), r0);
    jit_unget_reg(reg);
}

static void
_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 4095)
	STRBI(r1, r0, i0);
    else if (i0 > -256 && i0 < 0)
	STURB(r1, r0, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r0, i0);
	str_c(rn(reg), r1);
	jit_unget_reg(reg);
    }
}

static void
_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 8191 && !(i0 & 1))
	STRHI(r1, r0, i0 >> 1);
    else if (i0 > -256 && i0 < 0)
	STURH(r1, r0, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r0, i0);
	str_s(rn(reg), r1);
	jit_unget_reg(reg);
    }
}

static void
_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 16383 && !(i0 & 3))
	STRWI(r1, r0, i0 >> 2);
    else if (i0 > -256 && i0 < 0)
	STURW(r1, r0, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r0, i0);
	str_i(rn(reg), r1);
	jit_unget_reg(reg);
    }
}

static void
_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_int32_t		reg;
    if (i0 >= 0 && i0 <= 32767 && !(i0 & 7))
	STRI(r1, r0, i0 >> 3);
    else if (i0 > -256 && i0 < 0)
	STUR(r1, r0, i0 & 0x1ff);
    else {
	reg = jit_get_reg(jit_class_gpr);
	addi(rn(reg), r0, i0);
	str_l(rn(reg), r1);
	jit_unget_reg(reg);
    }
}

static void
_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    if (r0 != r1)
	MOV(r0, r1);
}

static void
_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_word_t		n0, ibit, nbit;
    n0 = ~i0;
    ibit = nbit = 0;
    if (i0 & 0x000000000000ffffL)	ibit |= 1;
    if (i0 & 0x00000000ffff0000L)	ibit |= 2;
    if (i0 & 0x0000ffff00000000L)	ibit |= 4;
    if (i0 & 0xffff000000000000L)	ibit |= 8;
    if (n0 & 0x000000000000ffffL)	nbit |= 1;
    if (n0 & 0x00000000ffff0000L)	nbit |= 2;
    if (n0 & 0x0000ffff00000000L)	nbit |= 4;
    if (n0 & 0xffff000000000000L)	nbit |= 8;
    switch (ibit) {
	case 0:
	    MOVZ   (r0,  0);
	    break;
	case 1:
	    MOVZ   (r0,  i0        & 0xffff);
	    break;
	case 2:
	    MOVZ_16(r0, (i0 >> 16) & 0xffff);
	    break;
	case 3:
	    MOVZ   (r0,  i0        & 0xffff);
	    MOVK_16(r0, (i0 >> 16) & 0xffff);
	    break;
	case 4:
	    MOVZ_32(r0, (i0 >> 32) & 0xffff);
	    break;
	case 5:
	    MOVZ   (r0,  i0        & 0xffff);
	    MOVK_32(r0, (i0 >> 32) & 0xffff);
	    break;
	case 6:
	    MOVZ_16(r0, (i0 >> 16) & 0xffff);
	    MOVK_32(r0, (i0 >> 32) & 0xffff);
	    break;
	case 7:
	    if (nbit == 8)
		MOVN_48(r0, (n0 >> 48) & 0xffff);
	    else {
		MOVZ   (r0,  i0        & 0xffff);
		MOVK_16(r0, (i0 >> 16) & 0xffff);
		MOVK_32(r0, (i0 >> 32) & 0xffff);
	    }
	    break;
	case 8:
	    MOVZ_48(r0, (i0 >> 48) & 0xffff);
	    break;
	case 9:
	    MOVZ   (r0,  i0        & 0xffff);
	    MOVK_48(r0, (i0 >> 48) & 0xffff);
	    break;
	case 10:
	    MOVZ_16(r0, (i0 >> 16) & 0xffff);
	    MOVK_48(r0, (i0 >> 48) & 0xffff);
	    break;
	case 11:
	    if (nbit == 4)
		MOVN_32(r0, (n0 >> 32) & 0xffff);
	    else {
		MOVZ   (r0,  i0        & 0xffff);
		MOVK_16(r0, (i0 >> 16) & 0xffff);
		MOVK_48(r0, (i0 >> 48) & 0xffff);
	    }
	    break;
	case 12:
	    MOVZ_32(r0, (i0 >> 32) & 0xffff);
	    MOVK_48(r0, (i0 >> 48) & 0xffff);
	    break;
	case 13:
	    if (nbit == 2)
		MOVN_16(r0, (n0 >> 16) & 0xffff);
	    else {
		MOVZ   (r0,  i0        & 0xffff);
		MOVK_32(r0, (i0 >> 32) & 0xffff);
		MOVK_48(r0, (i0 >> 48) & 0xffff);
	    }
	    break;
	case 14:
	    if (nbit == 1)
		MOVN   (r0, (n0)       & 0xffff);
	    else {
		MOVZ_16(r0, (i0 >> 16) & 0xffff);
		MOVK_32(r0, (i0 >> 32) & 0xffff);
		MOVK_48(r0, (i0 >> 48) & 0xffff);
	    }
	    break;
	case 15:
	    if (nbit == 0)
		MOVN   (r0,  0);
	    else if (nbit == 1)
		MOVN   (r0,  n0        & 0xffff);
	    else if (nbit == 8)
		MOVN_48(r0, (n0 >> 48) & 0xffff);
	    else {
		MOVZ   (r0,  i0        & 0xffff);
		MOVK_16(r0, (i0 >> 16) & 0xffff);
		MOVK_32(r0, (i0 >> 32) & 0xffff);
		MOVK_48(r0, (i0 >> 48) & 0xffff);
	    }
	    break;
	default:
	    abort();
    }
}

static jit_word_t
_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
{
    jit_word_t		w;
    w = _jit->pc.w;
    MOVZ   (r0,  i0        & 0xffff);
    MOVK_16(r0, (i0 >> 16) & 0xffff);
    MOVK_32(r0, (i0 >> 32) & 0xffff);
    MOVK_48(r0, (i0 >> 48) & 0xffff);
    return (w);
}

static void
_ccr(jit_state_t *_jit, jit_int32_t cc,
     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
{
    CMP(r1, r2);
    CSET(r0, cc);
}

static void
_cci(jit_state_t *_jit, jit_int32_t cc,
     jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
{
    jit_int32_t		reg;
    jit_word_t		is =  i0 >> 12;
    jit_word_t		in = -i0;
    jit_word_t		iS =  in >> 12;
    if (      i0 >= 0 && i0 <= 0xfff)
	CMPI   (r1, i0);
    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
	CMPI_12(r1, is);
    else if ( in >= 0 && in <= 0xfff)
	CMNI   (r1, in);
    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
	CMNI_12(r1, iS);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	CMP(r1, rn(reg));
	jit_unget_reg(reg);
    }
    CSET(r0, cc);
}

static jit_word_t
_bccr(jit_state_t *_jit, jit_int32_t cc,
      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_word_t		w, d;
    CMP(r0, r1);
    w = _jit->pc.w;
    d = (i0 - w) >> 2;
    B_C(cc, d);
    return (w);
}

static jit_word_t
_bcci(jit_state_t *_jit, jit_int32_t cc,
      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_int32_t		reg;
    jit_word_t		w, d;
    jit_word_t		is =  i1 >> 12;
    jit_word_t		in = -i1;
    jit_word_t		iS =  in >> 12;
    if (      i1 >= 0 && i1 <= 0xfff)
	CMPI   (r0, i1);
    else if ((is << 12) == i1 && is >= 0 && is <= 0xfff)
	CMPI_12(r0, is);
    else if ( in >= 0 && in <= 0xfff)
	CMNI   (r0, in);
    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
	CMNI_12(r0, iS);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i1);
	CMP(r0, rn(reg));
	jit_unget_reg(reg);
    }
    w = _jit->pc.w;
    d = (i0 - w) >> 2;
    B_C(cc, d);
    return (w);
}

static jit_word_t
_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_word_t		w;
    if (i1 == 0) {
	w = _jit->pc.w;
	CBZ(r0, (i0 - w) >> 2);
    }
    else
	w = bcci(BCC_EQ, i0, r0, i1);
    return (w);
}

static jit_word_t
_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_word_t		w;
    if (i1 == 0) {
	w = _jit->pc.w;
	CBNZ(r0, (i0 - w) >> 2);
    }
    else
	w = bcci(BCC_NE, i0, r0, i1);
    return (w);
}

static jit_word_t
_baddr(jit_state_t *_jit, jit_int32_t cc,
       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_word_t		w;
    addcr(r0, r0, r1);
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static jit_word_t
_baddi(jit_state_t *_jit, jit_int32_t cc,
       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_word_t		w;
    addci(r0, r0, i1);
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static jit_word_t
_bsubr(jit_state_t *_jit, jit_int32_t cc,
       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_word_t		w;
    subcr(r0, r0, r1);
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static jit_word_t
_bsubi(jit_state_t *_jit, jit_int32_t cc,
       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_word_t		w;
    subci(r0, r0, i1);
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static jit_word_t
_bmxr(jit_state_t *_jit, jit_int32_t cc,
      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
{
    jit_word_t		w;
    TST(r0, r1);
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static jit_word_t
_bmxi(jit_state_t *_jit, jit_int32_t cc,
      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
{
    jit_word_t		w;
    jit_int32_t		reg;
    jit_int32_t		imm;
    imm = logical_immediate(i1);
    if (imm != -1)
	TSTI(r0, imm);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i1);
	TST(r0, rn(reg));
	jit_unget_reg(reg);
    }
    w = _jit->pc.w;
    B_C(cc, (i0 - w) >> 2);
    return (w);
}

static void
_jmpi(jit_state_t *_jit, jit_word_t i0)
{
    jit_word_t		w;
    jit_int32_t		reg;
    w = (i0 - _jit->pc.w) >> 2;
    if (w >= -33554432 && w <= 33554431)
	B(w);
    else {
	reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
	movi(rn(reg), i0);
	jmpr(rn(reg));
	jit_unget_reg(reg);
    }
}

static jit_word_t
_jmpi_p(jit_state_t *_jit, jit_word_t i0)
{
    jit_word_t		w;
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
    w = movi_p(rn(reg), i0);
    jmpr(rn(reg));
    jit_unget_reg(reg);
    return (w);
}

static void
_calli(jit_state_t *_jit, jit_word_t i0)
{
    jit_word_t		w;
    jit_int32_t		reg;
    w = (i0 - _jit->pc.w) >> 2;
    if (w >= -33554432 && w <= 33554431)
	BL(w);
    else {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), i0);
	callr(rn(reg));
	jit_unget_reg(reg);
    }
}

static jit_word_t
_calli_p(jit_state_t *_jit, jit_word_t i0)
{
    jit_word_t		w;
    jit_int32_t		reg;
    reg = jit_get_reg(jit_class_gpr);
    w = movi_p(rn(reg), i0);
    callr(rn(reg));
    jit_unget_reg(reg);
    return (w);
}

/*
 * prolog and epilog not as "optimized" as one would like, but the
 * problem of overallocating stack space to save callee save registers
 * exists on all ports, and is still a todo to use a variable
 *	stack_framesize
 * value, what would cause needing to patch some calls, most likely
 * the offset of jit_arg* of stack arguments.
 */
static void
_prolog(jit_state_t *_jit, jit_node_t *node)
{
    jit_int32_t		reg;
    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
	jit_int32_t	frame = -_jitc->function->frame;
	assert(_jitc->function->self.aoff >= frame);
	if (_jitc->function->assume_frame)
	    return;
	_jitc->function->self.aoff = frame;
    }
    if (_jitc->function->allocar)
	_jitc->function->self.aoff &= -16;
    _jitc->function->stack = ((_jitc->function->self.alen -
			      /* align stack at 16 bytes */
			      _jitc->function->self.aoff) + 15) & -16;
    STPI_POS(FP_REGNO, LR_REGNO, SP_REGNO, -(stack_framesize >> 3));
    MOV_XSP(FP_REGNO, SP_REGNO);
#define SPILL(L, R, O)							\
    do {								\
	if (jit_regset_tstbit(&_jitc->function->regset, _R##L)) {	\
	    if (jit_regset_tstbit(&_jitc->function->regset, _R##R))	\
		STPI(L, R, SP_REGNO, O);				\
	    else							\
		STRI(L, SP_REGNO, O);					\
	}								\
	else if (jit_regset_tstbit(&_jitc->function->regset, _R##R))	\
	    STRI(R, SP_REGNO, O + 1);					\
    } while (0)
    SPILL(19, 20,  2);
    SPILL(21, 22,  4);
    SPILL(23, 24,  6);
    SPILL(25, 26,  8);
    SPILL(27, 28, 10);
#undef SPILL
#define SPILL(R, O)							\
    do {								\
	if (jit_regset_tstbit(&_jitc->function->regset, _V##R))		\
		stxi_d(O, SP_REGNO, R);					\
    } while (0)
    SPILL( 8,  96);
    SPILL( 9, 104);
    SPILL(10, 112);
    SPILL(11, 120);
    SPILL(12, 128);
    SPILL(13, 136);
    SPILL(14, 144);
    SPILL(15, 152);
#undef SPILL
    if (_jitc->function->stack)
	subi(SP_REGNO, SP_REGNO, _jitc->function->stack);
    if (_jitc->function->allocar) {
	reg = jit_get_reg(jit_class_gpr);
	movi(rn(reg), _jitc->function->self.aoff);
	stxi_i(_jitc->function->aoffoff, FP_REGNO, rn(reg));
	jit_unget_reg(reg);
    }

    if (_jitc->function->self.call & jit_call_varargs) {
	/* Save gp registers in the save area, if any is a vararg */
	for (reg = 8 - _jitc->function->vagp / -8;
	     jit_arg_reg_p(reg); ++reg)
	    stxi(_jitc->function->vaoff + offsetof(jit_va_list_t, x0) +
		 reg * 8, FP_REGNO, rn(JIT_RA0 - reg));

	for (reg = 8 - _jitc->function->vafp / -16;
	     jit_arg_f_reg_p(reg); ++reg)
	    /* Save fp registers in the save area, if any is a vararg */
	    /* Note that the full 16 byte register is not saved, because
	     * lightning only handles float and double, and, while
	     * attempting to provide a va_list compatible pointer as
	     * jit_va_start return, does not guarantee it (on all ports). */
	    stxi_d(_jitc->function->vaoff + offsetof(jit_va_list_t, q0) +
		   reg * 16 + offsetof(jit_qreg_t, l), FP_REGNO, rn(_V0 - reg));
    }
}

static void
_epilog(jit_state_t *_jit, jit_node_t *node)
{
    if (_jitc->function->assume_frame)
	return;
    if (_jitc->function->stack)
	MOV_XSP(SP_REGNO, FP_REGNO);
#define LOAD(L, R, O)							\
    do {								\
	if (jit_regset_tstbit(&_jitc->function->regset, _R##L)) {	\
	    if (jit_regset_tstbit(&_jitc->function->regset, _R##R))	\
		LDPI(L, R, SP_REGNO, O);				\
	    else							\
		LDRI(L, SP_REGNO, O);					\
	}								\
	else if (jit_regset_tstbit(&_jitc->function->regset, _R##R))	\
	    LDRI(R, SP_REGNO, O + 1);					\
    } while (0)
    LOAD(19, 20,  2);
    LOAD(21, 22,  4);
    LOAD(23, 24,  6);
    LOAD(25, 26,  8);
    LOAD(27, 28, 10);
#undef LOAD
#define LOAD(R, O)							\
    do {								\
	if (jit_regset_tstbit(&_jitc->function->regset, _V##R))		\
		ldxi_d(R, SP_REGNO, O);					\
    } while (0)
    LOAD( 8,  96);
    LOAD( 9, 104);
    LOAD(10, 112);
    LOAD(11, 120);
    LOAD(12, 128);
    LOAD(13, 136);
    LOAD(14, 144);
    LOAD(15, 152);
#undef LOAD
    LDPI_PRE(FP_REGNO, LR_REGNO, SP_REGNO, stack_framesize >> 3);
    RET();
}

static void
_vastart(jit_state_t *_jit, jit_int32_t r0)
{
    jit_int32_t		reg;

    assert(_jitc->function->self.call & jit_call_varargs);

    /* Return jit_va_list_t in the register argument */
    addi(r0, FP_REGNO, _jitc->function->vaoff);

    reg = jit_get_reg(jit_class_gpr);

    /* Initialize stack pointer to the first stack argument. */
    addi(rn(reg), FP_REGNO, _jitc->function->self.size);
    stxi(offsetof(jit_va_list_t, stack), r0, rn(reg));

    /* Initialize gp top pointer to the first stack argument. */
    addi(rn(reg), r0, va_gp_top_offset);
    stxi(offsetof(jit_va_list_t, gptop), r0, rn(reg));

    /* Initialize fp top pointer to the first stack argument. */
    addi(rn(reg), r0, va_fp_top_offset);
    stxi(offsetof(jit_va_list_t, fptop), r0, rn(reg));

    /* Initialize gp offset in the save area. */
    movi(rn(reg), _jitc->function->vagp);
    stxi_i(offsetof(jit_va_list_t, gpoff), r0, rn(reg));

    /* Initialize fp offset in the save area. */
    movi(rn(reg), _jitc->function->vafp);
    stxi_i(offsetof(jit_va_list_t, fpoff), r0, rn(reg));

    jit_unget_reg(reg);
}

static void
_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
{
    jit_word_t		ge_code;
    jit_word_t		lt_code;
    jit_int32_t		rg0, rg1;

    assert(_jitc->function->self.call & jit_call_varargs);

    rg0 = jit_get_reg(jit_class_gpr);
    rg1 = jit_get_reg(jit_class_gpr);

    /* Load the gp offset in save area in the first temporary. */
    ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, gpoff));

    /* Jump over if there are no remaining arguments in the save area. */
    ge_code = bgei(_jit->pc.w, rn(rg0), 0);

    /* Load the gp save pointer in the second temporary. */
    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, gptop));

    /* Load the vararg argument in the first argument. */
    ldxr(r0, rn(rg1), rn(rg0));

    /* Update the gp offset. */
    addi(rn(rg0), rn(rg0), 8);
    stxi_i(offsetof(jit_va_list_t, gpoff), r1, rn(rg0));

    /* Will only need one temporary register below. */
    jit_unget_reg(rg1);

    /* Jump over overflow code. */
    lt_code = jmpi_p(_jit->pc.w);

    /* Where to land if argument is in overflow area. */
    patch_at(ge_code, _jit->pc.w);

    /* Load stack pointer. */
    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack));

    /* Load argument. */
    ldr(r0, rn(rg0));

    /* Update stack pointer. */
    addi(rn(rg0), rn(rg0), 8);
    stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0));

    /* Where to land if argument is in gp save area. */
    patch_at(lt_code, _jit->pc.w);

    jit_unget_reg(rg0);
}

static void
_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
{
    instr_t		 i;
    jit_word_t		 d;
    jit_int32_t		 fc, ff, ffc;
    union {
	jit_int32_t	*i;
	jit_word_t	 w;
    } u;
    u.w = instr;
    i.w = u.i[0];
    fc  = i.w & 0xfc000000;
    ff  = i.w & 0xff000000;
    ffc = i.w & 0xffc00000;
    if (fc == A64_B || fc == A64_BL) {
	d = (label - instr) >> 2;
	assert(d >= -33554432 && d <= 33554431);
	i.imm26.b = d;
	u.i[0] = i.w;
    }
    else if (ff == A64_B_C || ff == (A64_CBZ|XS) || ff == (A64_CBNZ|XS)) {
	d = (label - instr) >> 2;
	assert(d >= -262148 && d <= 262143);
	i.imm19.b = d;
	u.i[0] = i.w;
    }
    else if (ffc == (A64_MOVZ|XS)) {
	i.imm16.b = label;
	u.i[0] = i.w;
	i.w = u.i[1];
	assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_16));
	i.imm16.b = label >> 16;
	u.i[1] = i.w;
	i.w = u.i[2];
	assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_32));
	i.imm16.b = label >> 32;
	u.i[2] = i.w;
	i.w = u.i[3];
	assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_48));
	i.imm16.b = label >> 48;
	u.i[3] = i.w;
    }
    else
	abort();
}
#endif
