1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-13 09:10:26 +02:00
guile/lightening/aarch64-cpu.c
Andy Wingo f348b8ed6d Change headers and files to be named "lightening" instead of "jit"
This improves integration with other projects.  Like for example Guile
already has files named jit.c and jit.h; it's easier to manage if
lightening uses its own file names.
2019-04-03 13:57:48 +02:00

2446 lines
70 KiB
C

/*
* Copyright (C) 2013-2017 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 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
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 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*,int32_t,int32_t,int32_t,int32_t);
# define oxxi(Op,Rd,Rn,Imm12) _oxxi(_jit,Op,Rd,Rn,Imm12)
static void _oxxi(jit_state_t*,int32_t,int32_t,int32_t,int32_t);
# define oxx9(Op,Rd,Rn,Imm9) _oxx9(_jit,Op,Rd,Rn,Imm9)
static void _oxx9(jit_state_t*,int32_t,int32_t,int32_t,int32_t);
# define ox19(Op,Rd,Simm19) _ox19(_jit,Op,Rd,Simm19)
static void _ox19(jit_state_t*,int32_t,int32_t,int32_t);
# define oc19(Op,Cc,Simm19) _oc19(_jit,Op,Cc,Simm19)
static void _oc19(jit_state_t*,int32_t,int32_t,int32_t);
# define o26(Op,Simm26) _o26(_jit,Op,Simm26)
static void _oc26(jit_state_t*,int32_t,int32_t);
# define ox_x(Op,Rd,Rn) _ox_x(_jit,Op,Rd,Rn)
static void _ox_x(jit_state_t*,int32_t,int32_t,int32_t);
# define o_xx(Op,Rd,Rn) _o_xx(_jit,Op,Rd,Rn)
static void _o_xx(jit_state_t*,int32_t,int32_t,int32_t);
# define oxx_(Op,Rn,Rm) _oxx_(_jit,Op,Rn,Rm)
static void _oxx_(jit_state_t*,int32_t,int32_t,int32_t);
# define o_x_(Op,Rn) _o_x_(_jit,Op,Rn)
static void _o_x_(jit_state_t*,int32_t,int32_t);
# define ox_h(Op,Rd,Imm16) _ox_h(_jit,Op,Rd,Imm16)
static void _ox_h(jit_state_t*,int32_t,int32_t,int32_t);
# define oxxrs(Op,Rd,Rn,R,S) _oxxrs(_jit,Op,Rd,Rn,R,S)
static void _oxxrs(jit_state_t*,int32_t,int32_t,
int32_t,int32_t,int32_t);
# define oxxxc(Op,Rd,Rn,Rm,Cc) _oxxxc(_jit,Op,Rd,Rn,Rm,Cc)
static void _oxxxc(jit_state_t*,int32_t,int32_t,
int32_t,int32_t,int32_t);
# define oxxx7(Op,Rt,Rt2,Rn,Simm7) _oxxx7(_jit,Op,Rt,Rt2,Rn,Simm7)
static void _oxxx7(jit_state_t*,int32_t,
int32_t,int32_t,int32_t,int32_t);
# define nop(i0) _nop(_jit,i0)
static void _nop(jit_state_t*,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,int32_t,jit_word_t);
# define rsbi(r0, r1, i0) _rsbi(_jit, r0, r1, i0)
static void _rsbi(jit_state_t*,int32_t,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*,int32_t,int32_t,jit_word_t);
# define qmulr(r0,r1,r2,r3) _qmulr(_jit,r0,r1,r2,r3)
static void _qmulr(jit_state_t*,int32_t,
int32_t,int32_t,int32_t);
# define qmuli(r0,r1,r2,i0) _qmuli(_jit,r0,r1,r2,i0)
static void _qmuli(jit_state_t*,int32_t,
int32_t,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*,int32_t,
int32_t,int32_t,int32_t);
# define qmuli_u(r0,r1,r2,i0) _qmuli_u(_jit,r0,r1,r2,i0)
static void _qmuli_u(jit_state_t*,int32_t,
int32_t,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*,int32_t,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*,int32_t,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,
int32_t,int32_t,int32_t,int32_t);
# define qdivi(r0,r1,r2,i0) _qdivi(_jit,r0,r1,r2,i0)
static void _qdivi(jit_state_t*,int32_t,
int32_t,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*,int32_t,
int32_t,int32_t,jit_word_t);
# define remr(r0,r1,r2) _remr(_jit,r0,r1,r2)
static void _remr(jit_state_t*,int32_t,int32_t,int32_t);
# define remi(r0,r1,i0) _remi(_jit,r0,r1,i0)
static void _remi(jit_state_t*,int32_t,int32_t,jit_word_t);
# define remr_u(r0,r1,r2) _remr_u(_jit,r0,r1,r2)
static void _remr_u(jit_state_t*,int32_t,int32_t,int32_t);
# define remi_u(r0,r1,i0) _remi_u(_jit,r0,r1,i0)
static void _remi_u(jit_state_t*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,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*,int32_t,jit_word_t);
# define ldr_uc(r0,r1) _ldr_uc(_jit,r0,r1)
static void _ldr_uc(jit_state_t*,int32_t,int32_t);
# define ldi_uc(r0,i0) _ldi_uc(_jit,r0,i0)
static void _ldi_uc(jit_state_t*,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*,int32_t,jit_word_t);
# define ldr_us(r0,r1) _ldr_us(_jit,r0,r1)
static void _ldr_us(jit_state_t*,int32_t,int32_t);
# define ldi_us(r0,i0) _ldi_us(_jit,r0,i0)
static void _ldi_us(jit_state_t*,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*,int32_t,jit_word_t);
# define ldr_ui(r0,r1) _ldr_ui(_jit,r0,r1)
static void _ldr_ui(jit_state_t*,int32_t,int32_t);
# define ldi_ui(r0,i0) _ldi_ui(_jit,r0,i0)
static void _ldi_ui(jit_state_t*,int32_t,jit_word_t);
# define ldr_l(r0,r1) LDRI(r0,r1,0)
static void _ldr_l(jit_state_t*,int32_t,int32_t);
# define ldi_l(r0,i0) _ldi_l(_jit,r0,i0)
static void _ldi_l(jit_state_t*,int32_t,jit_word_t);
# define ldxr_c(r0,r1,r2) _ldxr_c(_jit,r0,r1,r2)
static void _ldxr_c(jit_state_t*,int32_t,int32_t,int32_t);
# define ldxi_c(r0,r1,i0) _ldxi_c(_jit,r0,r1,i0)
static void _ldxi_c(jit_state_t*,int32_t,int32_t,jit_word_t);
# define ldxr_uc(r0,r1,r2) _ldxr_uc(_jit,r0,r1,r2)
static void _ldxr_uc(jit_state_t*,int32_t,int32_t,int32_t);
# define ldxi_uc(r0,r1,i0) _ldxi_uc(_jit,r0,r1,i0)
static void _ldxi_uc(jit_state_t*,int32_t,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*,int32_t,int32_t,jit_word_t);
# define ldxr_us(r0,r1,r2) _ldxr_us(_jit,r0,r1,r2)
static void _ldxr_us(jit_state_t*,int32_t,int32_t,int32_t);
# define ldxi_us(r0,r1,i0) _ldxi_us(_jit,r0,r1,i0)
static void _ldxi_us(jit_state_t*,int32_t,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*,int32_t,int32_t,jit_word_t);
# define ldxr_ui(r0,r1,r2) _ldxr_ui(_jit,r0,r1,r2)
static void _ldxr_ui(jit_state_t*,int32_t,int32_t,int32_t);
# define ldxi_ui(r0,r1,i0) _ldxi_ui(_jit,r0,r1,i0)
static void _ldxi_ui(jit_state_t*,int32_t,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*,int32_t,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,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,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,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,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,int32_t,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,int32_t,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,int32_t,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,int32_t,int32_t);
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define bswapr_us(r0,r1) _bswapr_us(_jit,r0,r1)
static void _bswapr_us(jit_state_t*,int32_t,int32_t);
# define bswapr_ui(r0,r1) _bswapr_ui(_jit,r0,r1)
static void _bswapr_ui(jit_state_t*,int32_t,int32_t);
# define bswapr_ul(r0,r1) REV(r0,r1)
# else
# define bswapr_us(r0,r1) extr_us(r0,r1)
# define bswapr_ui(r0,r1) extr_ui(r0,r1)
# define bswapr_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*,int32_t,int32_t);
# define movi(r0,i0) _movi(_jit,r0,i0)
static void _movi(jit_state_t*,int32_t,jit_word_t);
# define movi_p(r0,i0) _movi_p(_jit,r0,i0)
static jit_word_t _movi_p(jit_state_t*,int32_t,jit_word_t);
# define ccr(cc,r0,r1,r2) _ccr(_jit,cc,r0,r1,r2)
static void _ccr(jit_state_t*,int32_t,int32_t,int32_t,int32_t);
# define cci(cc,r0,r1,i0) _cci(_jit,cc,r0,r1,i0)
static void _cci(jit_state_t*,int32_t,int32_t,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*,int32_t,jit_word_t,int32_t,int32_t);
# define bcci(cc,i0,r0,i1) _bcci(_jit,cc,i0,r0,i1)
static jit_word_t
_bcci(jit_state_t*,int32_t,jit_word_t,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,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,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*,int32_t,jit_word_t,int32_t,int32_t);
# define baddi(cc,i0,r0,i1) _baddi(_jit,cc,i0,r0,i1)
static jit_word_t
_baddi(jit_state_t*,int32_t,jit_word_t,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*,int32_t,jit_word_t,int32_t,int32_t);
# define bsubi(cc,i0,r0,i1) _bsubi(_jit,cc,i0,r0,i1)
static jit_word_t
_bsubi(jit_state_t*,int32_t,jit_word_t,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*,int32_t,jit_word_t,int32_t,int32_t);
# define bmxi(cc,i0,r0,r1) _bmxi(_jit,cc,i0,r0,r1)
static jit_word_t
_bmxi(jit_state_t*,int32_t,jit_word_t,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*, int32_t);
# define vaarg(r0, r1) _vaarg(_jit, r0, r1)
static void _vaarg(jit_state_t*, int32_t, 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 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, int32_t Op,
int32_t Rd, int32_t Rn, 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, int32_t Op,
int32_t Rd, int32_t Rn, 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, int32_t Op,
int32_t Rd, int32_t Rn, 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, int32_t Op, int32_t Rd, 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, int32_t Op, int32_t Cc, 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, int32_t Op, 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, int32_t Op, int32_t Rd, 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, int32_t Op, int32_t Rd, 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, int32_t Op, int32_t Rn, 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, int32_t Op, 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, int32_t Op, int32_t Rd, 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, int32_t Op,
int32_t Rd, int32_t Rn, int32_t R, 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, int32_t Op,
int32_t Rd, int32_t Rn, int32_t Rm, 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, int32_t Op,
int32_t Rt, int32_t Rt2, int32_t Rn, 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, int32_t i0)
{
for (; i0 > 0; i0 -= 4)
NOP();
assert(i0 == 0);
}
static void
_addi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
subi(r0, r1, i0);
negr(r0, r0);
}
static void
_muli(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0,
int32_t r1, int32_t r2, int32_t r3)
{
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, int32_t r0,
int32_t r1, int32_t r2, jit_word_t i0)
{
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, int32_t r0,
int32_t r1, int32_t r2, int32_t r3)
{
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, int32_t r0,
int32_t r1, int32_t r2, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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,
int32_t r0, int32_t r1, int32_t r2, int32_t r3)
{
int32_t sv0, rg0;
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, int32_t r0,
int32_t r1, int32_t r2, jit_word_t i0)
{
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, int32_t r0,
int32_t r1, int32_t r2, jit_word_t i0)
{
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, int32_t r0, int32_t r1, int32_t r2)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, int32_t r2)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, 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, int32_t r0, 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, int32_t r0, 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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
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
_bswapr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
{
bswapr_ul(r0, r1);
rshi_u(r0, r0, 48);
}
static void
_bswapr_ui(jit_state_t *_jit, int32_t r0, int32_t r1)
{
bswapr, 2019_ul(r0, r1);
rshi_u(r0, r0, 32);
}
#endif
static void
_ldi_c(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
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, int32_t r0, int32_t r1)
{
LDRBI(r0, r1, 0);
#if 0
extr_uc(r0, r0);
#endif
}
static void
_ldi_uc(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
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, int32_t r0, jit_word_t i0)
{
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, int32_t r0, int32_t r1)
{
LDRHI(r0, r1, 0);
#if 0
extr_us(r0, r0);
#endif
}
static void
_ldi_us(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
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, int32_t r0, jit_word_t i0)
{
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, int32_t r0, int32_t r1)
{
LDRWI(r0, r1, 0);
#if 0
extr_ui(r0, r0);
#endif
}
static void
_ldi_ui(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
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, int32_t r0, jit_word_t i0)
{
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, int32_t r0, int32_t r1, int32_t r2)
{
LDRSB(r0, r1, r2);
extr_c(r0, r0);
}
static void
_ldxi_c(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, int32_t r2)
{
LDRB(r0, r1, r2);
#if 0
extr_uc(r0, r0);
#endif
}
static void
_ldxi_uc(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
assert(!(i0 & 1));
if (i0 >= 0 && i0 <= 8191)
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, int32_t r0, int32_t r1, int32_t r2)
{
LDRH(r0, r1, r2);
#if 0
extr_us(r0, r0);
#endif
}
static void
_ldxi_us(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
assert(!(i0 & 1));
if (i0 >= 0 && i0 <= 8191)
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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
assert(!(i0 & 3));
if (i0 >= 0 && i0 <= 16383)
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, int32_t r0, int32_t r1, int32_t r2)
{
LDRW(r0, r1, r2);
#if 0
extr_ui(r0, r0);
#endif
}
static void
_ldxi_ui(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
assert(!(i0 & 3));
if (i0 >= 0 && i0 <= 16383)
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, int32_t r0, int32_t r1, jit_word_t i0)
{
int32_t reg;
assert(!(i0 & 7));
if (i0 >= 0 && i0 <= 32767)
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, int32_t r0)
{
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, int32_t r0)
{
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, int32_t r0)
{
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, int32_t r0)
{
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, int32_t r0, int32_t r1)
{
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, int32_t r0, int32_t r1)
{
int32_t reg;
assert(!(i0 & 1));
if (i0 >= 0 && i0 <= 8191)
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, int32_t r0, int32_t r1)
{
int32_t reg;
assert(!(i0 & 3));
if (i0 >= 0 && i0 <= 16383)
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, int32_t r0, int32_t r1)
{
int32_t reg;
assert(!(i0 & 7));
if (i0 >= 0 && i0 <= 32767)
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, int32_t r0, int32_t r1)
{
if (r0 != r1)
MOV(r0, r1);
}
static void
_movi(jit_state_t *_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, 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, int32_t cc,
int32_t r0, int32_t r1, int32_t r2)
{
CMP(r1, r2);
CSET(r0, cc);
}
static void
_cci(jit_state_t *_jit, int32_t cc,
int32_t r0, int32_t r1, jit_word_t i0)
{
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, int32_t cc,
jit_word_t i0, int32_t r0, 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, int32_t cc,
jit_word_t i0, int32_t r0, jit_word_t i1)
{
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) == i0 && 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, 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, 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, int32_t cc,
jit_word_t i0, int32_t r0, 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, int32_t cc,
jit_word_t i0, 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, int32_t cc,
jit_word_t i0, int32_t r0, 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, int32_t cc,
jit_word_t i0, 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, int32_t cc,
jit_word_t i0, int32_t r0, 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, int32_t cc,
jit_word_t i0, int32_t r0, jit_word_t i1)
{
jit_word_t w;
int32_t reg;
int32_t imm;
imm = logical_immediate(i1);
if (imm != -1)
TSTI(r0, imm);
else {
reg = jit_get_reg(jit_class_gpr);
movi(rn(reg), i0);
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;
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;
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;
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;
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)
{
int32_t reg;
if (_jitc->function->define_frame || _jitc->function->assume_frame) {
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, int32_t r0)
{
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, int32_t r0, int32_t r1)
{
jit_word_t ge_code;
jit_word_t lt_code;
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;
int32_t fc, ff, ffc;
union {
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