1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 20:00:19 +02:00
guile/libguile/lightning/lightening/x86-cpu.c
2019-04-03 13:59:33 +02:00

2762 lines
57 KiB
C

/*
* Copyright (C) 2012-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
*/
/* avoid using it due to partial stalls */
#define USE_INC_DEC 0
#if __X32 || __X64_32
# define WIDE 0
# define IF_WIDE(wide, narrow) narrow
#else
# define WIDE 1
# define IF_WIDE(wide, narrow) wide
#endif
#define _RAX_REGNO 0
#define _RCX_REGNO 1
#define _RDX_REGNO 2
#define _RBX_REGNO 3
#define _RSP_REGNO 4
#define _RBP_REGNO 5
#define _RSI_REGNO 6
#define _RDI_REGNO 7
#define _R8_REGNO 8
#define _R9_REGNO 9
#define _R10_REGNO 10
#define _R11_REGNO 11
#define _R12_REGNO 12
#define _R13_REGNO 13
#define _R14_REGNO 14
#define _R15_REGNO 15
#define r7(reg) ((reg) & 7)
#define r8(reg) ((reg) & 15)
#if __X32 || __CYGWIN__ || __X64_32
# define reg8_p(rn) ((rn) >= _RAX_REGNO && (rn) <= _RBX_REGNO)
#else
# define reg8_p(rn) 1
#endif
#define can_sign_extend_int_p(im) \
IF_WIDE((((im) >= 0 && (long long)(im) <= 0x7fffffffLL) || \
((im) < 0 && (long long)(im) > -0x80000000LL)), \
1)
#define can_zero_extend_int_p(im) \
IF_WIDE(((im) >= 0 && (im) < 0x80000000LL), \
1)
#define fits_uint32_p(im) \
IF_WIDE((((im) & 0xffffffff00000000LL) == 0), \
1)
#define _SCL1 0x00
#define _SCL2 0x01
#define _SCL4 0x02
#define _SCL8 0x03
#define X86_ADD 0
#define X86_OR 1 << 3
#define X86_ADC 2 << 3
#define X86_SBB 3 << 3
#define X86_AND 4 << 3
#define X86_SUB 5 << 3
#define X86_XOR 6 << 3
#define X86_CMP 7 << 3
#define X86_ROL 0
#define X86_ROR 1
#define X86_RCL 2
#define X86_RCR 3
#define X86_SHL 4
#define X86_SHR 5
#define X86_SAR 7
#define X86_NOT 2
#define X86_NEG 3
#define X86_MUL 4
#define X86_IMUL 5
#define X86_DIV 6
#define X86_IDIV 7
#define FOR_EACH_CC(M) \
M(o, O, 0x0) \
M(no, NO, 0x1) \
M(nae, NAE, 0x2) \
M(b, B, 0x2) \
M(c, C, 0x2) \
M(ae, AE, 0x3) \
M(nb, NB, 0x3) \
M(nc, NC, 0x3) \
M(e, E, 0x4) \
M(z, Z, 0x4) \
M(ne, NE, 0x5) \
M(nz, NZ, 0x5) \
M(be, BE, 0x6) \
M(na, NA, 0x6) \
M(a, A, 0x7) \
M(nbe, NBE, 0x7) \
M(s, S, 0x8) \
M(ns, NS, 0x9) \
M(p, P, 0xa) \
M(pe, PE, 0xa) \
M(np, NP, 0xb) \
M(po, PO, 0xb) \
M(l, L, 0xc) \
M(nge, NGE, 0xc) \
M(ge, GE, 0xd) \
M(nl_, NL, 0xd) \
M(le, LE, 0xe) \
M(ng, NG, 0xe) \
M(g, G, 0xf) \
M(nle, NLE, 0xf) \
/* EOL */
enum x86_cc
{
#define DEFINE_ENUM(cc, CC, code) X86_CC_##CC = code,
FOR_EACH_CC(DEFINE_ENUM)
#undef DEFINE_ENUM
};
static inline void
mrm(jit_state_t *_jit, uint8_t md, uint8_t r, uint8_t m)
{
emit_u8(_jit, (md<<6) | (r<<3) | m);
}
static inline void
sib(jit_state_t *_jit, uint8_t sc, uint8_t i, uint8_t b)
{
emit_u8(_jit, (sc<<6) | (i<<3) | b);
}
static inline void
ic(jit_state_t *_jit, uint8_t c)
{
emit_u8(_jit, c);
}
static inline void
is(jit_state_t *_jit, uint16_t s)
{
emit_u16(_jit, s);
}
static inline void
ii(jit_state_t *_jit, uint32_t i)
{
emit_u32(_jit, i);
}
static inline void
il(jit_state_t *_jit, unsigned long l)
{
#if __X64 && !__X64_32
emit_u64(_jit, l);
#else
ii(_jit, l);
#endif
}
static void
rex(jit_state_t *_jit, int32_t l, int32_t w,
int32_t r, int32_t x, int32_t b)
{
#if __X64
int32_t v = 0x40 | (w << 3);
if (r != _NOREG)
v |= (r & 8) >> 1;
if (x != _NOREG)
v |= (x & 8) >> 2;
if (b != _NOREG)
v |= (b & 8) >> 3;
if (l || v != 0x40)
ic(_jit, v);
#endif
}
static void
rx(jit_state_t *_jit, int32_t rd, int32_t md,
int32_t rb, int32_t ri, int32_t ms)
{
if (ri == _NOREG) {
if (rb == _NOREG) {
#if __X32
mrm(_jit, 0x00, r7(rd), 0x05);
#else
mrm(_jit, 0x00, r7(rd), 0x04);
sib(_jit, _SCL1, 0x04, 0x05);
#endif
ii(_jit, md);
} else if (r7(rb) == _RSP_REGNO) {
if (md == 0) {
mrm(_jit, 0x00, r7(rd), 0x04);
sib(_jit, ms, 0x04, 0x04);
}
else if ((int8_t)md == md) {
mrm(_jit, 0x01, r7(rd), 0x04);
sib(_jit, ms, 0x04, 0x04);
ic(_jit, md);
} else {
mrm(_jit, 0x02, r7(rd), 0x04);
sib(_jit, ms, 0x04, 0x04);
ii(_jit, md);
}
} else {
if (md == 0 && r7(rb) != _RBP_REGNO)
mrm(_jit, 0x00, r7(rd), r7(rb));
else if ((int8_t)md == md) {
mrm(_jit, 0x01, r7(rd), r7(rb));
ic(_jit, md);
} else {
mrm(_jit, 0x02, r7(rd), r7(rb));
ii(_jit, md);
}
}
}
else if (rb == _NOREG) {
mrm(_jit, 0x00, r7(rd), 0x04);
sib(_jit, ms, r7(ri), 0x05);
ii(_jit, md);
}
else if (r8(ri) != _RSP_REGNO) {
if (md == 0 && r7(rb) != _RBP_REGNO) {
mrm(_jit, 0x00, r7(rd), 0x04);
sib(_jit, ms, r7(ri), r7(rb));
} else if ((int8_t)md == md) {
mrm(_jit, 0x01, r7(rd), 0x04);
sib(_jit, ms, r7(ri), r7(rb));
ic(_jit, md);
} else {
mrm(_jit, 0x02, r7(rd), 0x04);
sib(_jit, ms, r7(ri), r7(rb));
ic(_jit, md);
}
} else {
fprintf(stderr, "illegal index register");
abort();
}
}
static void
pushr(jit_state_t *_jit, int32_t r0)
{
rex(_jit, 0, WIDE, 0, 0, r0);
ic(_jit, 0x50 | r7(r0));
}
static void
popr(jit_state_t *_jit, int32_t r0)
{
rex(_jit, 0, WIDE, 0, 0, r0);
ic(_jit, 0x58 | r7(r0));
}
static jit_gpr_t
get_temp_gpr(jit_state_t *_jit)
{
ASSERT(!_jit->temp_gpr_saved);
_jit->temp_gpr_saved = 1;
#if __X32
pushr(_jit, _RBP_REGNO);
return JIT_GPR(_RBP);
#else
return JIT_GPR(_R8);
#endif
}
static void
unget_temp_gpr(jit_state_t *_jit)
{
ASSERT(_jit->temp_gpr_saved);
_jit->temp_gpr_saved = 0;
#if __X32
popr(_jit, _RBP_REGNO);
#endif
}
static void
nop(jit_state_t *_jit, int32_t count)
{
switch (count) {
case 0:
break;
case 1: /* NOP */
ic(_jit, 0x90);
break;
case 2: /* 66 NOP */
ic(_jit, 0x66); ic(_jit, 0x90);
break;
case 3: /* NOP DWORD ptr [EAX] */
ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x00);
break;
case 4: /* NOP DWORD ptr [EAX + 00H] */
ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x40); ic(_jit, 0x00);
break;
case 5: /* NOP DWORD ptr [EAX + EAX*1 + 00H] */
ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x44); ic(_jit, 0x00);
ic(_jit, 0x00);
break;
case 6: /* 66 NOP DWORD ptr [EAX + EAX*1 + 00H] */
ic(_jit, 0x66); ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x44);
ic(_jit, 0x00); ic(_jit, 0x00);
break;
case 7: /* NOP DWORD ptr [EAX + 00000000H] */
ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x80); ii(_jit, 0x0000);
break;
case 8: /* NOP DWORD ptr [EAX + EAX*1 + 00000000H] */
ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x84); ic(_jit, 0x00);
ii(_jit, 0x0000);
break;
case 9: /* 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] */
ic(_jit, 0x66); ic(_jit, 0x0f); ic(_jit, 0x1f); ic(_jit, 0x84);
ic(_jit, 0x00); ii(_jit, 0x0000);
break;
default:
abort();
}
}
static void
movr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (r0 != r1) {
rex(_jit, 0, 1, r1, _NOREG, r0);
ic(_jit, 0x89);
ic(_jit, 0xc0 | (r1 << 3) | r7(r0));
}
}
static void
movcr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbe);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
static void
movcr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb6);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
static void
movsr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbf);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
static void
movsr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb7);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
#if __X64
static void
movir(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 1, r0, _NOREG, r1);
ic(_jit, 0x63);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
static void
movir_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x89);
ic(_jit, 0xc0 | (r1 << 3) | r7(r0));
}
#endif
static jit_reloc_t
mov_addr(jit_state_t *_jit, int32_t r0)
{
uint8_t *pc_start = _jit->pc.uc;
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xb8 | r7(r0));
ptrdiff_t inst_start = _jit->pc.uc - pc_start;
return jit_reloc(_jit, JIT_RELOC_ABSOLUTE, inst_start, 0);
}
static void
imovi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
#if __X64
# if !__X64_32
if (fits_uint32_p(i0)) {
# endif
rex(_jit, 0, 0, _NOREG, _NOREG, r0);
ic(_jit, 0xb8 | r7(r0));
ii(_jit, i0);
# if !__X64_32
} else {
rex(_jit, 0, 1, _NOREG, _NOREG, r0);
ic(_jit, 0xb8 | r7(r0));
il(_jit, i0);
}
# endif
#else
ic(_jit, 0xb8 | r7(r0));
ii(_jit, i0);
#endif
}
static void
alur(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r1, _NOREG, r0);
ic(_jit, code | 0x01);
mrm(_jit, 0x03, r7(r1), r7(r0));
}
static inline void
icmpr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_CMP, r0, r1);
}
static inline void
iaddr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_ADD, r0, r1);
}
static inline void
iaddxr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_ADC, r0, r1);
}
static inline void
isubr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_SUB, r0, r1);
}
static inline void
isubxr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_SBB, r0, r1);
}
static inline void
iandr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_AND, r0, r1);
}
static inline void
iorr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_OR, r0, r1);
}
static inline void
ixorr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return alur(_jit, X86_XOR, r0, r1);
}
static void
movi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (i0)
imovi(_jit, r0, i0);
else
ixorr(_jit, r0, r0);
}
static void
alui(jit_state_t *_jit, int32_t code, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
if ((int8_t)i0 == i0) {
ic(_jit, 0x83);
ic(_jit, 0xc0 | code | r7(r0));
ic(_jit, i0);
} else {
if (r0 == _RAX_REGNO) {
ic(_jit, code | 0x05);
} else {
ic(_jit, 0x81);
ic(_jit, 0xc0 | code | r7(r0));
}
ii(_jit, i0);
}
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
alur(_jit, code, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static inline void
icmpi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_CMP, r0, i0);
}
static inline void
iaddi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_ADD, r0, i0);
}
static inline void
iaddxi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_ADC, r0, i0);
}
static inline void
isubi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_SUB, r0, i0);
}
static inline void
isubxi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_SBB, r0, i0);
}
static inline void
iandi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_AND, r0, i0);
}
static inline void
iori(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_OR, r0, i0);
}
static inline void
ixori(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
return alui(_jit, X86_XOR, r0, i0);
}
static void
unr(jit_state_t *_jit, int32_t code, int32_t r0)
{
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xf7);
mrm(_jit, 0x03, code, r7(r0));
}
static inline void
umulr(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_IMUL, r0);
}
static inline void
umulr_u(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_MUL, r0);
}
static inline void
idivr(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_IDIV, r0);
}
static inline void
idivr_u(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_DIV, r0);
}
static inline void
inegr(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_NEG, r0);
}
static inline void
icomr(jit_state_t *_jit, int32_t r0)
{
return unr(_jit, X86_NOT, r0);
}
#if USE_INC_DEC
static void
incr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
movr(_jit, r0, r1);
# if __X64
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xff);
ic(_jit, 0xc0 | r7(r0));
# else
ic(_jit, 0x40 | r7(r0));
# endif
}
static void
decr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
movr(_jit, r0, r1);
# if __X64
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xff);
ic(_jit, 0xc8 | r7(r0));
# else
ic(_jit, 0x48 | r7(r0));
# endif
}
#endif
static void
lea(jit_state_t *_jit, int32_t md, int32_t rb,
int32_t ri, int32_t ms, int32_t rd)
{
rex(_jit, 0, WIDE, rd, ri, rb);
ic(_jit, 0x8d);
rx(_jit, rd, md, rb, ri, ms);
}
static void
xchgr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r1, _NOREG, r0);
ic(_jit, 0x87);
mrm(_jit, 0x03, r7(r1), r7(r0));
}
static void
testr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r1, _NOREG, r0);
ic(_jit, 0x85);
mrm(_jit, 0x03, r7(r1), r7(r0));
}
static void
testi(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
if (r0 == _RAX_REGNO) {
ic(_jit, 0xa9);
} else {
ic(_jit, 0xf7);
mrm(_jit, 0x03, 0x00, r7(r0));
}
ii(_jit, i0);
}
static void
cc(jit_state_t *_jit, int32_t code, int32_t r0)
{
rex(_jit, 0, 0, _NOREG, _NOREG, r0);
ic(_jit, 0x0f);
ic(_jit, 0x90 | code);
mrm(_jit, 0x03, 0x00, r7(r0));
}
static void
negr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (r0 == r1) {
inegr(_jit, r0);
} else {
ixorr(_jit, r0, r0);
isubr(_jit, r0, r1);
}
}
static void
addr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r1)
iaddr(_jit, r0, r2);
else if (r0 == r2)
iaddr(_jit, r0, r1);
else
lea(_jit, 0, r1, r2, _SCL1, r0);
}
static void
addi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
movr(_jit, r0, r1);
#if USE_INC_DEC
else if (i0 == 1)
incr(_jit, r0, r1);
else if (i0 == -1)
decr(_jit, r0, r1);
#endif
else if (can_sign_extend_int_p(i0)) {
if (r0 == r1)
iaddi(_jit, r0, i0);
else
lea(_jit, i0, r1, _NOREG, _SCL1, r0);
}
else if (r0 != r1) {
movi(_jit, r0, i0);
iaddr(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
iaddr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
addcr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r2) {
iaddr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
iaddr(_jit, r0, r2);
}
}
static void
addci(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
movr(_jit, r0, r1);
iaddi(_jit, r0, i0);
}
else if (r0 == r1) {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
iaddr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
} else {
movi(_jit, r0, i0);
iaddr(_jit, r0, r1);
}
}
static void
addxr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r2) {
iaddxr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
iaddxr(_jit, r0, r2);
}
}
static void
addxi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
movr(_jit, r0, r1);
iaddxi(_jit, r0, i0);
}
else if (r0 == r1) {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
iaddxr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
} else {
movi(_jit, r0, i0);
iaddxr(_jit, r0, r1);
}
}
static void
subr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r1 == r2)
ixorr(_jit, r0, r0);
else if (r0 == r2) {
isubr(_jit, r0, r1);
inegr(_jit, r0);
} else {
movr(_jit, r0, r1);
isubr(_jit, r0, r2);
}
}
static void
subi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
movr(_jit, r0, r1);
#if USE_INC_DEC
else if (i0 == 1)
decr(_jit, r0, r1);
else if (i0 == -1)
incr(_jit, r0, r1);
#endif
else if (can_sign_extend_int_p(i0)) {
if (r0 == r1)
isubi(_jit, r0, i0);
else
lea(_jit, -i0, r1, _NOREG, _SCL1, r0);
}
else if (r0 != r1) {
movi(_jit, r0, -i0);
iaddr(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
isubr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
subcr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r2 && r0 != r1) {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r0);
movr(_jit, r0, r1);
isubr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
} else {
movr(_jit, r0, r1);
isubr(_jit, r0, r2);
}
}
static void
subci(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
movr(_jit, r0, r1);
if (can_sign_extend_int_p(i0)) {
isubi(_jit, r0, i0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
isubr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
subxr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r2 && r0 != r1) {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r0);
movr(_jit, r0, r1);
isubxr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
} else {
movr(_jit, r0, r1);
isubxr(_jit, r0, r2);
}
}
static void
subxi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
movr(_jit, r0, r1);
if (can_sign_extend_int_p(i0)) {
isubxi(_jit, r0, i0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
imovi(_jit, rn(reg), i0);
isubxr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
irotshr(jit_state_t *_jit, int32_t code, int32_t r0)
{
rex(_jit, 0, WIDE, _RCX_REGNO, _NOREG, r0);
ic(_jit, 0xd3);
mrm(_jit, 0x03, code, r7(r0));
}
static void
rotshr(jit_state_t *_jit, int32_t code,
int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == _RCX_REGNO) {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r1);
if (r2 != _RCX_REGNO)
movr(_jit, _RCX_REGNO, r2);
irotshr(_jit, code, rn(reg));
movr(_jit, _RCX_REGNO, rn(reg));
unget_temp_gpr(_jit);
} else if (r2 != _RCX_REGNO) {
/* Already know that R0 isn't RCX. */
pushr(_jit, _RCX_REGNO);
if (r1 == _RCX_REGNO) {
if (r0 == r2)
xchgr(_jit, r0, _RCX_REGNO);
else {
movr(_jit, r0, r1);
movr(_jit, _RCX_REGNO, r2);
}
} else {
movr(_jit, _RCX_REGNO, r2);
movr(_jit, r0, r1);
}
irotshr(_jit, code, r0);
popr(_jit, _RCX_REGNO);
} else {
movr(_jit, r0, r1);
irotshr(_jit, code, r0);
}
}
static void
irotshi(jit_state_t *_jit, int32_t code, int32_t r0, jit_word_t i0)
{
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
if (i0 == 1) {
ic(_jit, 0xd1);
mrm(_jit, 0x03, code, r7(r0));
} else {
ic(_jit, 0xc1);
mrm(_jit, 0x03, code, r7(r0));
ic(_jit, i0);
}
}
static void
rotshi(jit_state_t *_jit, int32_t code,
int32_t r0, int32_t r1, jit_word_t i0)
{
movr(_jit, r0, r1);
if (i0)
irotshi(_jit, code, r0, i0);
}
static void
lshi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
movr(_jit, r0, r1);
else if (i0 <= 3)
lea(_jit, 0, _NOREG, r1, i0 == 1 ? _SCL2 : i0 == 2 ? _SCL4 : _SCL8, r0);
else
rotshi(_jit, X86_SHL, r0, r1, i0);
}
static void
lshr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return rotshr(_jit, X86_SHL, r0, r1, r2);
}
static void
rshr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return rotshr(_jit, X86_SAR, r0, r1, r2);
}
static void
rshi(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t i0)
{
return rotshi(_jit, X86_SAR, r0, r1, i0);
}
static void
rshr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return rotshr(_jit, X86_SHR, r0, r1, r2);
}
static void
rshi_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t i0)
{
return rotshi(_jit, X86_SHR, r0, r1, i0);
}
static void
imulr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xaf);
mrm(_jit, 0x03, r7(r0), r7(r1));
}
static void
imuli(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, r1);
if ((int8_t)i0 == i0) {
ic(_jit, 0x6b);
mrm(_jit, 0x03, r7(r0), r7(r1));
ic(_jit, i0);
} else {
ic(_jit, 0x69);
mrm(_jit, 0x03, r7(r0), r7(r1));
ii(_jit, i0);
}
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
imulr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
mulr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r0 == r1)
imulr(_jit, r0, r2);
else if (r0 == r2) {
imulr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
imulr(_jit, r0, r2);
}
}
static int
ffsw(jit_word_t i)
{
if (sizeof(int) == sizeof(i))
return ffs(i);
int bit = ffs((int)i);
if (bit == 0) {
bit = ffs((int)((unsigned long)i >> 32));
if (bit)
bit += 32;
}
return bit;
}
static void
muli(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
switch (i0) {
case 0:
ixorr(_jit, r0, r0);
break;
case 1:
movr(_jit, r0, r1);
break;
case -1:
negr(_jit, r0, r1);
break;
case 2:
lea(_jit, 0, _NOREG, r1, _SCL2, r0);
break;
case 4:
lea(_jit, 0, _NOREG, r1, _SCL4, r0);
break;
case 8:
lea(_jit, 0, _NOREG, r1, _SCL8, r0);
break;
default:
if (i0 > 0 && !(i0 & (i0 - 1)))
lshi(_jit, r0, r1, ffsw(i0) - 1);
else if (can_sign_extend_int_p(i0))
imuli(_jit, r0, r1, i0);
else if (r0 != r1) {
movi(_jit, r0, i0);
imulr(_jit, r0, r1);
}
else
imuli(_jit, r0, r0, i0);
break;
}
}
static void
iqmulr(jit_state_t *_jit, int32_t r0, int32_t r1,
int32_t r2, int32_t r3, jit_bool_t sign)
{
if (r0 != _RAX_REGNO && r1 != _RAX_REGNO)
pushr(_jit, _RAX_REGNO);
if (r0 != _RDX_REGNO && r1 != _RDX_REGNO)
pushr(_jit, _RDX_REGNO);
int32_t mul;
if (r3 == _RAX_REGNO) {
mul = r2;
} else {
mul = r3;
movr(_jit, _RAX_REGNO, r2);
}
if (sign)
umulr(_jit, mul);
else
umulr_u(_jit, mul);
if (r0 == _RDX_REGNO && r1 == _RAX_REGNO) {
xchgr(_jit, _RAX_REGNO, _RDX_REGNO);
} else {
if (r0 != _RDX_REGNO)
movr(_jit, r0, _RAX_REGNO);
movr(_jit, r1, _RDX_REGNO);
if (r0 == _RDX_REGNO)
movr(_jit, r0, _RAX_REGNO);
}
if (r0 != _RDX_REGNO && r1 != _RDX_REGNO)
popr(_jit, _RDX_REGNO);
if (r0 != _RAX_REGNO && r1 != _RAX_REGNO)
popr(_jit, _RAX_REGNO);
}
static void
qmulr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
{
return iqmulr(_jit, r0, r1, r2, r3, 1);
}
static void
qmulr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
{
return iqmulr(_jit, r0, r1, r2, r3, 0);
}
static void
iqmuli(jit_state_t *_jit, int32_t r0, int32_t r1,
int32_t r2, jit_word_t i0, jit_bool_t sign)
{
if (i0 == 0) {
ixorr(_jit, r0, r0);
ixorr(_jit, r1, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
if (sign)
qmulr(_jit, r0, r1, r2, rn(reg));
else
qmulr_u(_jit, r0, r1, r2, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
qmuli(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, jit_word_t i0)
{
return iqmuli(_jit, r0, r1, r2, i0, 1);
}
static void
qmuli_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, jit_word_t i0)
{
return iqmuli(_jit, r0, r1, r2, i0, 0);
}
static void
sign_extend_rdx_rax(jit_state_t *_jit)
{
rex(_jit, 0, WIDE, 0, 0, 0);
ic(_jit, 0x99);
}
static void
divremr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2,
jit_bool_t sign, jit_bool_t divide)
{
if (r0 != _RAX_REGNO)
pushr(_jit, _RAX_REGNO);
if (r0 != _RDX_REGNO)
pushr(_jit, _RDX_REGNO);
int tmp_divisor = 0;
if (r2 == _RAX_REGNO || r2 == _RDX_REGNO) {
jit_gpr_t tmp = get_temp_gpr(_jit);
movr(_jit, rn(tmp), r2);
r2 = rn(tmp);
tmp_divisor = 1;
}
movr(_jit, _RAX_REGNO, r1);
if (sign) {
sign_extend_rdx_rax(_jit);
idivr(_jit, r2);
} else {
ixorr(_jit, _RDX_REGNO, _RDX_REGNO);
idivr_u(_jit, r2);
}
if (divide)
movr(_jit, r0, _RAX_REGNO);
else
movr(_jit, r0, _RDX_REGNO);
if (tmp_divisor)
unget_temp_gpr(_jit);
if (r0 != _RDX_REGNO)
popr(_jit, _RDX_REGNO);
if (r0 != _RAX_REGNO)
popr(_jit, _RAX_REGNO);
}
static void
divremi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0,
jit_bool_t sign, jit_bool_t divide)
{
jit_gpr_t tmp = get_temp_gpr(_jit);
movi(_jit, rn(tmp), i0);
divremr(_jit, r0, r1, rn(tmp), sign, divide);
}
static void
divr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return divremr(_jit, r0, r1, r2, 1, 1);
}
static void
divi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
return divremi(_jit, r0, r1, i0, 1, 1);
}
static void
divr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return divremr(_jit, r0, r1, r2, 0, 1);
}
static void
divi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
return divremi(_jit, r0, r1, i0, 0, 1);
}
static void
remr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return divremr(_jit, r0, r1, r2, 1, 0);
}
static void
remi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
return divremi(_jit, r0, r1, i0, 1, 0);
}
static void
remr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
return divremr(_jit, r0, r1, r2, 0, 0);
}
static void
remi_u(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
return divremi(_jit, r0, r1, i0, 0, 0);
}
static void
iqdivr(jit_state_t *_jit, int32_t r0, int32_t r1,
int32_t r2, int32_t r3, jit_bool_t sign)
{
if (r0 != _RAX_REGNO && r1 != _RAX_REGNO)
pushr(_jit, _RAX_REGNO);
if (r0 != _RDX_REGNO && r1 != _RDX_REGNO)
pushr(_jit, _RDX_REGNO);
int tmp_divisor = 0;
if (r3 == _RAX_REGNO || r3 == _RDX_REGNO) {
jit_gpr_t tmp = get_temp_gpr(_jit);
movr(_jit, rn(tmp), r3);
r3 = rn(tmp);
tmp_divisor = 1;
}
movr(_jit, _RAX_REGNO, r2);
if (sign) {
sign_extend_rdx_rax(_jit);
idivr(_jit, r3);
} else {
ixorr(_jit, _RDX_REGNO, _RDX_REGNO);
idivr_u(_jit, r3);
}
if (r0 == _RDX_REGNO && r1 == _RAX_REGNO) {
xchgr(_jit, _RAX_REGNO, _RDX_REGNO);
} else {
if (r0 != _RDX_REGNO)
movr(_jit, r0, _RAX_REGNO);
movr(_jit, r1, _RDX_REGNO);
if (r0 == _RDX_REGNO)
movr(_jit, r0, _RAX_REGNO);
}
if (tmp_divisor)
unget_temp_gpr(_jit);
if (r0 != _RDX_REGNO && r1 != _RDX_REGNO)
popr(_jit, _RDX_REGNO);
if (r0 != _RAX_REGNO && r1 != _RAX_REGNO)
popr(_jit, _RAX_REGNO);
}
static void
qdivr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
{
return iqdivr(_jit, r0, r1, r2, r3, 1);
}
static void
qdivr_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, int32_t r3)
{
return iqdivr(_jit, r0, r1, r2, r3, 0);
}
static void
iqdivi(jit_state_t *_jit, int32_t r0, int32_t r1,
int32_t r2, jit_word_t i0, jit_bool_t sign)
{
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
if (sign)
qdivr(_jit, r0, r1, r2, rn(reg));
else
qdivr_u(_jit, r0, r1, r2, rn(reg));
unget_temp_gpr(_jit);
}
static void
qdivi(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, jit_word_t i0)
{
return iqdivi(_jit, r0, r1, r2, i0, 1);
}
static void
qdivi_u(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2, jit_word_t i0)
{
return iqdivi(_jit, r0, r1, r2, i0, 0);
}
static void
comr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
movr(_jit, r0, r1);
icomr(_jit, r0);
}
static void
andr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r1 == r2)
movr(_jit, r0, r1);
else if (r0 == r1)
iandr(_jit, r0, r2);
else if (r0 == r2) {
iandr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
iandr(_jit, r0, r2);
}
}
static void
andi(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
ixorr(_jit, r0, r0);
else if (i0 == -1)
movr(_jit, r0, r1);
else if (r0 == r1) {
if (can_sign_extend_int_p(i0)) {
iandi(_jit, r0, i0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
iandr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
} else {
movi(_jit, r0, i0);
iandr(_jit, r0, r1);
}
}
static void
orr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r1 == r2)
movr(_jit, r0, r1);
else if (r0 == r1)
iorr(_jit, r0, r2);
else if (r0 == r2) {
iorr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
iorr(_jit, r0, r2);
}
}
static void
ori(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
movr(_jit, r0, r1);
else if (i0 == -1)
movi(_jit, r0, -1);
else if (can_sign_extend_int_p(i0)) {
movr(_jit, r0, r1);
iori(_jit, r0, i0);
}
else if (r0 != r1) {
movi(_jit, r0, i0);
iorr(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
iorr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
xorr(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
if (r1 == r2)
ixorr(_jit, r0, r0);
else if (r0 == r1)
ixorr(_jit, r0, r2);
else if (r0 == r2) {
ixorr(_jit, r0, r1);
} else {
movr(_jit, r0, r1);
ixorr(_jit, r0, r2);
}
}
static void
xori(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (i0 == 0)
movr(_jit, r0, r1);
else if (i0 == -1)
comr(_jit, r0, r1);
else if (can_sign_extend_int_p(i0)) {
movr(_jit, r0, r1);
ixori(_jit, r0, i0);
}
else if (r0 != r1) {
movi(_jit, r0, i0);
ixorr(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ixorr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
cr(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1, int32_t r2)
{
if (reg8_p(r0)) {
jit_bool_t same = r0 == r1 || r0 == r2;
if (!same)
ixorr(_jit, r0, r0);
icmpr(_jit, r1, r2);
if (same)
imovi(_jit, r0, 0);
cc(_jit, code, r0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
ixorr(_jit, rn(reg), rn(reg));
icmpr(_jit, r1, r2);
cc(_jit, code, rn(reg));
movr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ci(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1, jit_word_t i0)
{
if (reg8_p(r0)) {
jit_bool_t same = r0 == r1;
if (!same)
ixorr(_jit, r0, r0);
icmpi(_jit, r1, i0);
if (same)
imovi(_jit, r0, 0);
cc(_jit, code, r0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
ixorr(_jit, rn(reg), rn(reg));
icmpi(_jit, r1, i0);
cc(_jit, code, rn(reg));
movr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ci0(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1)
{
if (reg8_p(r0)) {
jit_bool_t same = r0 == r1;
if (!same)
ixorr(_jit, r0, r0);
testr(_jit, r1, r1);
if (same)
imovi(_jit, r0, 0);
cc(_jit, code, r0);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
ixorr(_jit, rn(reg), rn(reg));
testr(_jit, r1, r1);
cc(_jit, code, rn(reg));
movr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
extr_c(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (reg8_p(r1)) {
movcr(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r1);
movcr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
extr_uc(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (reg8_p(r1)) {
movcr_u(_jit, r0, r1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r1);
movcr_u(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
extr_s(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return movsr(_jit, r0, r1);
}
static void
extr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return movsr_u(_jit, r0, r1);
}
#if __X64 && !__X64_32
static void
extr_i(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return movir(_jit, r0, r1);
}
static void
extr_ui(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return movir_u(_jit, r0, r1);
}
#endif
static void
bswapr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
{
extr_us(_jit, r0, r1);
ic(_jit, 0x66);
rex(_jit, 0, 0, _NOREG, _NOREG, r0);
ic(_jit, 0xc1);
mrm(_jit, 0x03, X86_ROR, r7(r0));
ic(_jit, 8);
}
static void
bswapr_ui(jit_state_t *_jit, int32_t r0, int32_t r1)
{
movr(_jit, r0, r1);
rex(_jit, 0, 0, _NOREG, _NOREG, r0);
ic(_jit, 0x0f);
ic(_jit, 0xc8 | r7(r0));
}
#if __X64 && !__X64_32
static void
bswapr_ul(jit_state_t *_jit, int32_t r0, int32_t r1)
{
movr(_jit, r0, r1);
rex(_jit, 0, 1, _NOREG, _NOREG, r0);
ic(_jit, 0x0f);
ic(_jit, 0xc8 | r7(r0));
}
#endif
static void
ldr_c(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbe);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_c(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, _NOREG);
ic(_jit, 0x0f);
ic(_jit, 0xbe);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_c(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldr_uc(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb6);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_uc(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, _NOREG);
ic(_jit, 0x0f);
ic(_jit, 0xb6);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_uc(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldr_s(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbf);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_s(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, _NOREG);
ic(_jit, 0x0f);
ic(_jit, 0xbf);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_s(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldr_us(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb7);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_us(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, _NOREG);
ic(_jit, 0x0f);
ic(_jit, 0xb7);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_us(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
#if __X32 || !__X64_32
static void
ldr_i(jit_state_t *_jit, int32_t r0, int32_t r1)
{
#if __X64
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x63);
#else
ic(_jit, 0x8b);
#endif
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_i(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
#if __X64
rex(_jit, 0, WIDE, r0, _NOREG, _NOREG);
ic(_jit, 0x63);
#else
ic(_jit, 0x8b);
#endif
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_i(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
#endif
#if __X64
static void
ldr_ui(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 0, r0, _NOREG, r1);
ic(_jit, 0x63);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_ui(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 0, r0, _NOREG, _NOREG);
ic(_jit, 0x63);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_ui(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
# if !__X64_32
static void
ldr_l(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 1, r0, _NOREG, r1);
ic(_jit, 0x8b);
rx(_jit, r0, 0, r1, _NOREG, _SCL1);
}
static void
ldi_l(jit_state_t *_jit, int32_t r0, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 1, r0, _NOREG, _NOREG);
ic(_jit, 0x8b);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldr_l(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
}
# endif
#endif
static void
ldxr_c(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
addr(_jit, r0, r1, r2);
ldr_c(r0, r0);
#else
rex(_jit, 0, WIDE, r0, r1, r2);
ic(_jit, 0x0f);
ic(_jit, 0xbe);
rx(_jit, r0, 0, r2, r1, _SCL1);
#endif
}
static void
ldxi_c(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbe);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_c(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldxr_uc(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
addr(_jit, r0, r1, r2);
ldr_uc(_jit, r0, r0);
#else
rex(_jit, 0, WIDE, r0, r1, r2);
ic(_jit, 0x0f);
ic(_jit, 0xb6);
rx(_jit, r0, 0, r2, r1, _SCL1);
#endif
}
static void
ldxi_uc(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb6);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_uc(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldxr_s(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
addr(_jit, r0, r1, r2);
ldr_s(_jit, r0, r0);
#else
rex(_jit, 0, WIDE, r0, r1, r2);
ic(_jit, 0x0f);
ic(_jit, 0xbf);
rx(_jit, r0, 0, r2, r1, _SCL1);
#endif
}
static void
ldxi_s(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xbf);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_s(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
ldxr_us(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
addr(_jit, r0, r1, r2);
ldr_us(_jit, r0, r0);
#else
rex(_jit, 0, WIDE, r0, r1, r2);
ic(_jit, 0x0f);
ic(_jit, 0xb7);
rx(_jit, r0, 0, r2, r1, _SCL1);
#endif
}
static void
ldxi_us(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x0f);
ic(_jit, 0xb7);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_us(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
#if __X64 || !__X64_32
static void
ldxr_i(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64
rex(_jit, 0, WIDE, r0, r1, r2);
ic(_jit, 0x63);
#else
ic(_jit, 0x8b);
#endif
rx(_jit, r0, 0, r2, r1, _SCL1);
}
static void
ldxi_i(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
#if __X64
rex(_jit, 0, WIDE, r0, _NOREG, r1);
ic(_jit, 0x63);
#else
ic(_jit, 0x8b);
#endif
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_i(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
#endif
#if __X64
static void
ldxr_ui(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
addr(_jit, r0, r1, r2);
/* to avoid confusion with macro renames */
_ldr_ui(_jit, r0, r0);
#else
rex(_jit, 0, 0, r0, r1, r2);
ic(_jit, 0x8b);
rx(_jit, r0, 0, r2, r1, _SCL1);
#endif
}
static void
ldxi_ui(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 0, r0, _NOREG, r1);
ic(_jit, 0x8b);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_ui(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
# if !__X64_32
static void
ldxr_l(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
rex(_jit, 0, 1, r0, r1, r2);
ic(_jit, 0x8b);
rx(_jit, r0, 0, r2, r1, _SCL1);
}
static void
ldxi_l(jit_state_t *_jit, int32_t r0, int32_t r1, jit_word_t i0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 1, r0, _NOREG, r1);
ic(_jit, 0x8b);
rx(_jit, r0, i0, r1, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
ldxr_l(_jit, r0, r1, rn(reg));
unget_temp_gpr(_jit);
}
}
# endif
#endif
static void
str_c(jit_state_t *_jit, int32_t r0, int32_t r1)
{
if (reg8_p(r1)) {
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x88);
rx(_jit, r1, 0, r0, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r1);
rex(_jit, 0, 0, rn(reg), _NOREG, r0);
ic(_jit, 0x88);
rx(_jit, rn(reg), 0, r0, _NOREG, _SCL1);
unget_temp_gpr(_jit);
}
}
static void
sti_c(jit_state_t *_jit, jit_word_t i0, int32_t r0)
{
if (can_sign_extend_int_p(i0)) {
if (reg8_p(r0)) {
rex(_jit, 0, 0, r0, _NOREG, _NOREG);
ic(_jit, 0x88);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r0);
rex(_jit, 0, 0, rn(reg), _NOREG, _NOREG);
ic(_jit, 0x88);
rx(_jit, rn(reg), i0, _NOREG, _NOREG, _SCL1);
unget_temp_gpr(_jit);
}
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
str_c(_jit, rn(reg), r0);
unget_temp_gpr(_jit);
}
}
static void
str_s(jit_state_t *_jit, int32_t r0, int32_t r1)
{
ic(_jit, 0x66);
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, 0, r0, _NOREG, _SCL1);
}
static void
sti_s(jit_state_t *_jit, jit_word_t i0, int32_t r0)
{
if (can_sign_extend_int_p(i0)) {
ic(_jit, 0x66);
rex(_jit, 0, 0, r0, _NOREG, _NOREG);
ic(_jit, 0x89);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
str_s(_jit, rn(reg), r0);
unget_temp_gpr(_jit);
}
}
static void
str_i(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, 0, r0, _NOREG, _SCL1);
}
static void
sti_i(jit_state_t *_jit, jit_word_t i0, int32_t r0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 0, r0, _NOREG, _NOREG);
ic(_jit, 0x89);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
str_i(_jit, rn(reg), r0);
unget_temp_gpr(_jit);
}
}
#if __X64 && !__X64_32
static void
str_l(jit_state_t *_jit, int32_t r0, int32_t r1)
{
rex(_jit, 0, 1, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, 0, r0, _NOREG, _SCL1);
}
static void
sti_l(jit_state_t *_jit, jit_word_t i0, int32_t r0)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 1, r0, _NOREG, _NOREG);
ic(_jit, 0x89);
rx(_jit, r0, i0, _NOREG, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
str_l(_jit, rn(reg), r0);
unget_temp_gpr(_jit);
}
}
#endif
static void
stxr_c(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
jit_gpr_t reg = get_temp_gpr(_jit);
addr(_jit, rn(reg), r0, r1);
str_c(_jit, rn(reg), r2);
unget_temp_gpr(_jit);
#else
if (reg8_p(r2)) {
rex(_jit, 0, 0, r2, r1, r0);
ic(_jit, 0x88);
rx(_jit, r2, 0, r0, r1, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r2);
rex(_jit, 0, 0, rn(reg), r1, r0);
ic(_jit, 0x88);
rx(_jit, rn(reg), 0, r0, r1, _SCL1);
unget_temp_gpr(_jit);
}
#endif
}
static void
stxi_c(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
{
if (can_sign_extend_int_p(i0)) {
if (reg8_p(r1)) {
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x88);
rx(_jit, r1, i0, r0, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movr(_jit, rn(reg), r1);
rex(_jit, 0, 0, rn(reg), _NOREG, r0);
ic(_jit, 0x88);
rx(_jit, rn(reg), i0, r0, _NOREG, _SCL1);
unget_temp_gpr(_jit);
}
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
stxr_c(_jit, rn(reg), r0, r1);
unget_temp_gpr(_jit);
}
}
static void
stxr_s(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
jit_gpr_t reg = get_temp_gpr(_jit);
addr(_jit, rn(reg), r0, r1);
str_s(_jit, rn(reg), r2);
unget_temp_gpr(_jit);
#else
ic(_jit, 0x66);
rex(_jit, 0, 0, r2, r1, r0);
ic(_jit, 0x89);
rx(_jit, r2, 0, r0, r1, _SCL1);
#endif
}
static void
stxi_s(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
{
if (can_sign_extend_int_p(i0)) {
ic(_jit, 0x66);
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, i0, r0, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
stxr_s(_jit, rn(reg), r0, r1);
unget_temp_gpr(_jit);
}
}
static void
stxr_i(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
#if __X64_32
jit_gpr_t reg = get_temp_gpr(_jit);
addr(_jit, rn(reg), r0, r1);
str_i(rn(reg), r2);
unget_temp_gpr(_jit);
#else
rex(_jit, 0, 0, r2, r1, r0);
ic(_jit, 0x89);
rx(_jit, r2, 0, r0, r1, _SCL1);
#endif
}
static void
stxi_i(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 0, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, i0, r0, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
stxr_i(_jit, rn(reg), r0, r1);
unget_temp_gpr(_jit);
}
}
#if __X64 && !__X64_32
static void
stxr_l(jit_state_t *_jit, int32_t r0, int32_t r1, int32_t r2)
{
rex(_jit, 0, 1, r2, r1, r0);
ic(_jit, 0x89);
rx(_jit, r2, 0, r0, r1, _SCL1);
}
static void
stxi_l(jit_state_t *_jit, jit_word_t i0, int32_t r0, int32_t r1)
{
if (can_sign_extend_int_p(i0)) {
rex(_jit, 0, 1, r1, _NOREG, r0);
ic(_jit, 0x89);
rx(_jit, r1, i0, r0, _NOREG, _SCL1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i0);
stxr_l(_jit, rn(reg), r0, r1);
unget_temp_gpr(_jit);
}
}
#endif
static jit_reloc_t
jccs(jit_state_t *_jit, int32_t code)
{
ic(_jit, 0x70 | code);
return jit_reloc(_jit, JIT_RELOC_REL8, 1, 0);
}
static jit_reloc_t
jcc(jit_state_t *_jit, int32_t code)
{
ic(_jit, 0x0f);
ic(_jit, 0x80 | code);
return jit_reloc(_jit, JIT_RELOC_REL32, 2, 0);
}
#define DEFINE_JUMPS(cc, CC, code) \
static inline jit_reloc_t j##cc(jit_state_t *_jit) \
{ \
return jcc(_jit, X86_CC_##CC); \
} \
static inline jit_reloc_t j##cc##s(jit_state_t *_jit) \
{ \
return jccs(_jit, X86_CC_##CC); \
}
FOR_EACH_CC(DEFINE_JUMPS)
#undef DEFINE_JUMPS
static jit_reloc_t
jcr(jit_state_t *_jit, int32_t code, int32_t r0, int32_t r1)
{
alur(_jit, X86_CMP, r0, r1);
return jcc(_jit, code);
}
static jit_reloc_t
jci(jit_state_t *_jit, int32_t code, int32_t r0, jit_word_t i0)
{
alui(_jit, X86_CMP, r0, i0);
return jcc(_jit, code);
}
static jit_reloc_t
jci0(jit_state_t *_jit, int32_t code, int32_t r0)
{
testr(_jit, r0, r0);
return jcc(_jit, code);
}
static jit_reloc_t
bltr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr(_jit, X86_CC_L, r0, r1);
}
static jit_reloc_t
blti(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_L, r0, i1);
else return jci0(_jit, X86_CC_S, r0);
}
static jit_reloc_t
bltr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr(_jit, X86_CC_B, r0, r1);
}
static jit_reloc_t
blti_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_B, r0, i1);
else return jci0(_jit, X86_CC_B, r0);
}
static jit_reloc_t
bler(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr (_jit, X86_CC_LE, r0, r1);
}
static jit_reloc_t
blei(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_LE, r0, i1);
else return jci0(_jit, X86_CC_LE, r0);
}
static jit_reloc_t
bler_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr (_jit, X86_CC_BE, r0, r1);
}
static jit_reloc_t
blei_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_BE, r0, i1);
else return jci0(_jit, X86_CC_BE, r0);
}
static jit_reloc_t
beqr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr (_jit, X86_CC_E, r0, r1);
}
static jit_reloc_t
beqi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_E, r0, i1);
else return jci0(_jit, X86_CC_E, r0);
}
static jit_reloc_t
bger(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr (_jit, X86_CC_GE, r0, r1);
}
static jit_reloc_t
bgei(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_GE, r0, i1);
else return jci0(_jit, X86_CC_NS, r0);
}
static jit_reloc_t
bger_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr (_jit, X86_CC_AE, r0, r1);
}
static jit_reloc_t
bgei_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
return jci (_jit, X86_CC_AE, r0, i1);
}
static jit_reloc_t
bgtr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr(_jit, X86_CC_G, r0, r1);
}
static jit_reloc_t
bgti(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
return jci(_jit, X86_CC_G, r0, i1);
}
static jit_reloc_t
bgtr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr(_jit, X86_CC_A, r0, r1);
}
static jit_reloc_t
bgti_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_A, r0, i1);
else return jci0(_jit, X86_CC_NE, r0);
}
static jit_reloc_t
bner(jit_state_t *_jit, int32_t r0, int32_t r1)
{
return jcr(_jit, X86_CC_NE, r0, r1);
}
static jit_reloc_t
bnei(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (i1) return jci (_jit, X86_CC_NE, r0, i1);
else return jci0(_jit, X86_CC_NE, r0);
}
static jit_reloc_t
bmsr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
testr(_jit, r0, r1);
return jnz(_jit);
}
static jit_reloc_t
bmsi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_zero_extend_int_p(i1)) {
testi(_jit, r0, i1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
testr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
return jnz(_jit);
}
static jit_reloc_t
bmcr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
testr(_jit, r0, r1);
return jz(_jit);
}
static jit_reloc_t
bmci(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_zero_extend_int_p(i1)) {
testi(_jit, r0, i1);
} else {
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
testr(_jit, r0, rn(reg));
unget_temp_gpr(_jit);
}
return jz(_jit);
}
static jit_reloc_t
boaddr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
iaddr(_jit, r0, r1);
return jo(_jit);
}
static jit_reloc_t
boaddi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
iaddi(_jit, r0, i1);
return jo(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return boaddr(_jit, r0, rn(reg));
}
static jit_reloc_t
boaddr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
iaddr(_jit, r0, r1);
return jc(_jit);
}
static jit_reloc_t
boaddi_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
iaddi(_jit, r0, i1);
return jc(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return boaddr_u(_jit, r0, rn(reg));
}
static jit_reloc_t
bxaddr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
iaddr(_jit, r0, r1);
return jno(_jit);
}
static jit_reloc_t
bxaddi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
iaddi(_jit, r0, i1);
return jno(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bxaddr(_jit, r0, rn(reg));
}
static jit_reloc_t
bxaddr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
iaddr(_jit, r0, r1);
return jnc(_jit);
}
static jit_reloc_t
bxaddi_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
iaddi(_jit, r0, i1);
return jnc(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bxaddr_u(_jit, r0, rn(reg));
}
static jit_reloc_t
bosubr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
isubr(_jit, r0, r1);
return jo(_jit);
}
static jit_reloc_t
bosubi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
isubi(_jit, r0, i1);
return jo(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bosubr(_jit, r0, rn(reg));
}
static jit_reloc_t
bosubr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
isubr(_jit, r0, r1);
return jc(_jit);
}
static jit_reloc_t
bosubi_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
isubi(_jit, r0, i1);
return jc(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bosubr_u(_jit, r0, rn(reg));
}
static jit_reloc_t
bxsubr(jit_state_t *_jit, int32_t r0, int32_t r1)
{
isubr(_jit, r0, r1);
return jno(_jit);
}
static jit_reloc_t
bxsubi(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
isubi(_jit, r0, i1);
return jno(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bxsubr(_jit, r0, rn(reg));
}
static jit_reloc_t
bxsubr_u(jit_state_t *_jit, int32_t r0, int32_t r1)
{
isubr(_jit, r0, r1);
return jnc(_jit);
}
static jit_reloc_t
bxsubi_u(jit_state_t *_jit, int32_t r0, jit_word_t i1)
{
if (can_sign_extend_int_p(i1)) {
isubi(_jit, r0, i1);
return jnc(_jit);
}
jit_gpr_t reg = get_temp_gpr(_jit);
movi(_jit, rn(reg), i1);
unget_temp_gpr(_jit);
return bxsubr_u(_jit, r0, rn(reg));
}
static void
callr(jit_state_t *_jit, int32_t r0)
{
rex(_jit, 0, 0, _NOREG, _NOREG, r0);
ic(_jit, 0xff);
mrm(_jit, 0x03, 0x02, r7(r0));
}
static void
calli(jit_state_t *_jit, jit_word_t i0)
{
ptrdiff_t rel32 = i0 - (_jit->pc.w + 4);
if (INT32_MIN <= rel32 && rel32 <= INT32_MAX)
{
ic(_jit, 0xe8);
ii(_jit, rel32);
}
else
{
jit_gpr_t reg = get_temp_gpr(_jit);
jit_patch_there(_jit, mov_addr(_jit, rn(reg)), (void*)i0);
callr(_jit, rn(reg));
unget_temp_gpr(_jit);
}
}
static void
jmpr(jit_state_t *_jit, int32_t r0)
{
rex(_jit, 0, WIDE, _NOREG, _NOREG, r0);
ic(_jit, 0xff);
mrm(_jit, 0x03, 0x04, r7(r0));
}
static void
jmpi(jit_state_t *_jit, jit_word_t i0)
{
ptrdiff_t rel32 = i0 - (_jit->pc.w + 4);
if (INT32_MIN <= rel32 && rel32 <= INT32_MAX)
{
ic(_jit, 0xe9);
ii(_jit, rel32);
}
else
{
jit_gpr_t reg = get_temp_gpr(_jit);
jit_patch_there(_jit, mov_addr(_jit, rn(reg)), (void*)i0);
jmpr(_jit, rn(reg));
unget_temp_gpr(_jit);
}
}
static jit_reloc_t
jmp(jit_state_t *_jit)
{
ic(_jit, 0xe9);
return jit_reloc(_jit, JIT_RELOC_REL32, 1, 0);
}
static jit_reloc_t
jmpsi(jit_state_t *_jit)
{
ic(_jit, 0xeb);
return jit_reloc(_jit, JIT_RELOC_REL8, 1, 0);
}
static void
ret(jit_state_t *_jit)
{
ic(_jit, 0xc3);
}
static void
retr(jit_state_t *_jit, int32_t r0)
{
movr(_jit, _RAX_REGNO, r0);
ret(_jit);
}
static void
reti(jit_state_t *_jit, jit_word_t i0)
{
movi(_jit, _RAX_REGNO, i0);
ret(_jit);
}
static void
retval_c(jit_state_t *_jit, int32_t r0)
{
extr_c(_jit, r0, rn(JIT_RET));
}
static void
retval_uc(jit_state_t *_jit, int32_t r0)
{
extr_uc(_jit, r0, rn(JIT_RET));
}
static void
retval_s(jit_state_t *_jit, int32_t r0)
{
extr_s(_jit, r0, rn(JIT_RET));
}
static void
retval_us(jit_state_t *_jit, int32_t r0)
{
extr_us(_jit, r0, rn(JIT_RET));
}
static void
retval_i(jit_state_t *_jit, int32_t r0)
{
#if __X32 || __X64_32
movr(_jit, r0, rn(JIT_RET));
#else
extr_i(_jit, r0, rn(JIT_RET));
#endif
}
#if __X64 && !__X64_32
static void
retval_ui(jit_state_t *_jit, int32_t r0)
{
extr_ui(_jit, r0, rn(JIT_RET));
}
static void
retval_l(jit_state_t *_jit, int32_t r0)
{
movr(_jit, r0, rn(JIT_RET));
}
#endif