1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-13 17:20:21 +02:00
guile/lightening/x86-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

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