#include <sys/auxv.h>
#ifdef __ARCH__
#define ENABLE_STATIC_FACILITY_DETECTION 1
#else
#define ENABLE_STATIC_FACILITY_DETECTION 0
#endif
#define ENABLE_DYNAMIC_FACILITY_DETECTION 1
SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "s390x" SLJIT_CPUINFO;
}
typedef sljit_uw sljit_ins;
const sljit_ins sljit_ins_const = (sljit_ins)1 << 48;
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
14, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1
};
typedef sljit_uw sljit_gpr;
const sljit_gpr r0 = 0;
const sljit_gpr r1 = 1;
const sljit_gpr r2 = 2;
const sljit_gpr r3 = 3;
const sljit_gpr r4 = 4;
const sljit_gpr r5 = 5;
const sljit_gpr r6 = 6;
const sljit_gpr r7 = 7;
const sljit_gpr r8 = 8;
const sljit_gpr r9 = 9;
const sljit_gpr r10 = 10;
const sljit_gpr r11 = 11;
const sljit_gpr r12 = 12;
const sljit_gpr r13 = 13;
const sljit_gpr r14 = 14;
const sljit_gpr r15 = 15;
#define tmp0 r0
#define tmp1 r1
const sljit_gpr link_r = 14;
const sljit_gpr fast_link_r = 0;
const sljit_gpr flag_r = 14;
struct sljit_s390x_const {
struct sljit_const const_;
sljit_sw init_value;
};
static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r)
{
SLJIT_ASSERT(r != SLJIT_UNUSED);
SLJIT_ASSERT(r < (sljit_s32)(sizeof(reg_map) / sizeof(reg_map[0])));
return reg_map[r];
}
static SLJIT_INLINE sljit_uw sizeof_ins(sljit_ins ins)
{
if (ins == 0)
return 2;
if ((ins & 0x00000000ffffL) == ins)
return 2;
if ((ins & 0x0000ffffffffL) == ins)
return 4;
if ((ins & 0xffffffffffffL) == ins)
return 6;
SLJIT_UNREACHABLE();
return (sljit_uw)-1;
}
static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
sljit_ins *ibuf = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ibuf);
*ibuf = ins;
compiler->size++;
return SLJIT_SUCCESS;
}
static sljit_s32 encode_inst(void **ptr, sljit_ins ins)
{
sljit_u16 *ibuf = (sljit_u16 *)*ptr;
sljit_uw size = sizeof_ins(ins);
SLJIT_ASSERT((size & 6) == size);
switch (size) {
case 6:
*ibuf++ = (sljit_u16)(ins >> 32);
case 4:
*ibuf++ = (sljit_u16)(ins >> 16);
case 2:
*ibuf++ = (sljit_u16)(ins);
}
*ptr = (void*)ibuf;
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_u8 get_cc(sljit_s32 type) {
const sljit_u8 eq = 1 << 3;
const sljit_u8 lt = 1 << 2;
const sljit_u8 gt = 1 << 1;
const sljit_u8 ov = 1 << 0;
switch (type) {
case SLJIT_EQUAL:
case SLJIT_EQUAL_F64:
return eq;
case SLJIT_NOT_EQUAL:
case SLJIT_NOT_EQUAL_F64:
return ~eq;
case SLJIT_LESS:
case SLJIT_SIG_LESS:
case SLJIT_LESS_F64:
return lt;
case SLJIT_LESS_EQUAL:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_LESS_EQUAL_F64:
return (lt | eq);
case SLJIT_GREATER:
case SLJIT_SIG_GREATER:
case SLJIT_GREATER_F64:
return gt;
case SLJIT_GREATER_EQUAL:
case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_GREATER_EQUAL_F64:
return (gt | eq);
case SLJIT_OVERFLOW:
case SLJIT_MUL_OVERFLOW:
case SLJIT_UNORDERED_F64:
return ov;
case SLJIT_NOT_OVERFLOW:
case SLJIT_MUL_NOT_OVERFLOW:
case SLJIT_ORDERED_F64:
return ~ov;
}
SLJIT_UNREACHABLE();
return (sljit_u8)-1;
}
typedef sljit_uw facility_bit;
#define STORE_FACILITY_LIST_EXTENDED_FACILITY 7
#define FAST_LONG_DISPLACEMENT_FACILITY 19
#define EXTENDED_IMMEDIATE_FACILITY 21
#define GENERAL_INSTRUCTION_EXTENSION_FACILITY 34
#define DISTINCT_OPERAND_FACILITY 45
#define HIGH_WORD_FACILITY 45
#define POPULATION_COUNT_FACILITY 45
#define LOAD_STORE_ON_CONDITION_1_FACILITY 45
#define MISCELLANEOUS_INSTRUCTION_EXTENSIONS_1_FACILITY 49
#define LOAD_STORE_ON_CONDITION_2_FACILITY 53
#define MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY 58
#define VECTOR_FACILITY 129
#define VECTOR_ENHANCEMENTS_1_FACILITY 135
static SLJIT_INLINE int have_facility_static(facility_bit x)
{
#if ENABLE_STATIC_FACILITY_DETECTION
switch (x) {
case FAST_LONG_DISPLACEMENT_FACILITY:
return (__ARCH__ >= 6 );
case EXTENDED_IMMEDIATE_FACILITY:
case STORE_FACILITY_LIST_EXTENDED_FACILITY:
return (__ARCH__ >= 7 );
case GENERAL_INSTRUCTION_EXTENSION_FACILITY:
return (__ARCH__ >= 8 );
case DISTINCT_OPERAND_FACILITY:
return (__ARCH__ >= 9 );
case MISCELLANEOUS_INSTRUCTION_EXTENSIONS_1_FACILITY:
return (__ARCH__ >= 10 );
case LOAD_STORE_ON_CONDITION_2_FACILITY:
case VECTOR_FACILITY:
return (__ARCH__ >= 11 );
case MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY:
case VECTOR_ENHANCEMENTS_1_FACILITY:
return (__ARCH__ >= 12 );
default:
SLJIT_UNREACHABLE();
}
#endif
return 0;
}
static SLJIT_INLINE unsigned long get_hwcap()
{
static unsigned long hwcap = 0;
if (SLJIT_UNLIKELY(!hwcap)) {
hwcap = getauxval(AT_HWCAP);
SLJIT_ASSERT(hwcap != 0);
}
return hwcap;
}
static SLJIT_INLINE int have_stfle()
{
if (have_facility_static(STORE_FACILITY_LIST_EXTENDED_FACILITY))
return 1;
return (get_hwcap() & HWCAP_S390_STFLE);
}
static int have_facility_dynamic(facility_bit x)
{
#if ENABLE_DYNAMIC_FACILITY_DETECTION
static struct {
sljit_uw bits[4];
} cpu_features;
size_t size = sizeof(cpu_features);
const sljit_uw word_index = x >> 6;
const sljit_uw bit_index = ((1UL << 63) >> (x & 63));
SLJIT_ASSERT(x < size * 8);
if (SLJIT_UNLIKELY(!have_stfle()))
return 0;
if (SLJIT_UNLIKELY(cpu_features.bits[0] == 0)) {
__asm__ __volatile__ (
"lgr %%r0, %0;"
"stfle 0(%1);"
:
: "d" ((size / 8) - 1), "a" (&cpu_features)
: "r0", "cc", "memory"
);
SLJIT_ASSERT(cpu_features.bits[0] != 0);
}
return (cpu_features.bits[word_index] & bit_index) != 0;
#else
return 0;
#endif
}
#define HAVE_FACILITY(name, bit) \
static SLJIT_INLINE int name() \
{ \
static int have = -1; \
\
if (have_facility_static(bit)) \
have = 1; \
else if (SLJIT_UNLIKELY(have < 0)) \
have = have_facility_dynamic(bit) ? 1 : 0; \
\
return have; \
}
HAVE_FACILITY(have_eimm, EXTENDED_IMMEDIATE_FACILITY)
HAVE_FACILITY(have_ldisp, FAST_LONG_DISPLACEMENT_FACILITY)
HAVE_FACILITY(have_genext, GENERAL_INSTRUCTION_EXTENSION_FACILITY)
HAVE_FACILITY(have_lscond1, LOAD_STORE_ON_CONDITION_1_FACILITY)
HAVE_FACILITY(have_lscond2, LOAD_STORE_ON_CONDITION_2_FACILITY)
HAVE_FACILITY(have_misc2, MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY)
#undef HAVE_FACILITY
#define is_u12(d) (0 <= (d) && (d) <= 0x00000fffL)
#define is_u32(d) (0 <= (d) && (d) <= 0xffffffffL)
#define CHECK_SIGNED(v, bitlen) \
((v) == (((v) << (sizeof(v) * 8 - bitlen)) >> (sizeof(v) * 8 - bitlen)))
#define is_s16(d) CHECK_SIGNED((d), 16)
#define is_s20(d) CHECK_SIGNED((d), 20)
#define is_s32(d) CHECK_SIGNED((d), 32)
static SLJIT_INLINE sljit_uw disp_s20(sljit_s32 d)
{
sljit_uw dh = (d >> 12) & 0xff;
sljit_uw dl = (d << 8) & 0xfff00;
SLJIT_ASSERT(is_s20(d));
return dh | dl;
}
#define SLJIT_S390X_INSTRUCTION(op, ...) \
static SLJIT_INLINE sljit_ins op(__VA_ARGS__)
#define SLJIT_S390X_RR(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \
{ \
return (pattern) | ((dst & 0xf) << 4) | (src & 0xf); \
}
SLJIT_S390X_RR(ar, 0x1a00)
SLJIT_S390X_RR(alr, 0x1e00)
SLJIT_S390X_RR(nr, 0x1400)
SLJIT_S390X_RR(basr, 0x0d00)
SLJIT_S390X_RR(bcr, 0x0700)
SLJIT_S390X_RR(cr, 0x1900)
SLJIT_S390X_RR(clr, 0x1500)
SLJIT_S390X_RR(dr, 0x1d00)
SLJIT_S390X_RR(xr, 0x1700)
SLJIT_S390X_RR(lr, 0x1800)
SLJIT_S390X_RR(lcr, 0x1300)
SLJIT_S390X_RR(or, 0x1600)
SLJIT_S390X_RR(sr, 0x1b00)
SLJIT_S390X_RR(slr, 0x1f00)
#undef SLJIT_S390X_RR
#define SLJIT_S390X_RRE(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \
{ \
return (pattern) | ((dst & 0xf) << 4) | (src & 0xf); \
}
SLJIT_S390X_RRE(agr, 0xb9080000)
SLJIT_S390X_RRE(algr, 0xb90a0000)
SLJIT_S390X_RRE(alcr, 0xb9980000)
SLJIT_S390X_RRE(alcgr, 0xb9880000)
SLJIT_S390X_RRE(ngr, 0xb9800000)
SLJIT_S390X_RRE(cgr, 0xb9200000)
SLJIT_S390X_RRE(clgr, 0xb9210000)
SLJIT_S390X_RRE(dlr, 0xb9970000)
SLJIT_S390X_RRE(dlgr, 0xb9870000)
SLJIT_S390X_RRE(dsgr, 0xb90d0000)
SLJIT_S390X_RRE(xgr, 0xb9820000)
SLJIT_S390X_RRE(lgr, 0xb9040000)
SLJIT_S390X_RRE(lgfr, 0xb9140000)
SLJIT_S390X_RRE(lbr, 0xb9260000)
SLJIT_S390X_RRE(lgbr, 0xb9060000)
SLJIT_S390X_RRE(lcgr, 0xb9030000)
SLJIT_S390X_RRE(lhr, 0xb9270000)
SLJIT_S390X_RRE(lghr, 0xb9070000)
SLJIT_S390X_RRE(llgfr, 0xb9160000)
SLJIT_S390X_RRE(llcr, 0xb9940000)
SLJIT_S390X_RRE(llgcr, 0xb9840000)
SLJIT_S390X_RRE(llhr, 0xb9950000)
SLJIT_S390X_RRE(llghr, 0xb9850000)
SLJIT_S390X_RRE(mlgr, 0xb9860000)
SLJIT_S390X_RRE(msr, 0xb2520000)
SLJIT_S390X_RRE(msgr, 0xb90c0000)
SLJIT_S390X_RRE(msgfr, 0xb91c0000)
SLJIT_S390X_RRE(ogr, 0xb9810000)
SLJIT_S390X_RRE(sgr, 0xb9090000)
SLJIT_S390X_RRE(slgr, 0xb90b0000)
SLJIT_S390X_RRE(slbr, 0xb9990000)
SLJIT_S390X_RRE(slbgr, 0xb9890000)
#undef SLJIT_S390X_RRE
#define SLJIT_S390X_RIA(name, pattern, imm_type) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \
{ \
return (pattern) | ((reg & 0xf) << 20) | (imm & 0xffff); \
}
SLJIT_S390X_RIA(ahi, 0xa70a0000, sljit_s16)
SLJIT_S390X_RIA(aghi, 0xa70b0000, sljit_s16)
SLJIT_S390X_RIA(chi, 0xa70e0000, sljit_s16)
SLJIT_S390X_RIA(cghi, 0xa70f0000, sljit_s16)
SLJIT_S390X_RIA(lhi, 0xa7080000, sljit_s16)
SLJIT_S390X_RIA(lghi, 0xa7090000, sljit_s16)
SLJIT_S390X_RIA(llihh, 0xa50c0000, sljit_u16)
SLJIT_S390X_RIA(llihl, 0xa50d0000, sljit_u16)
SLJIT_S390X_RIA(llilh, 0xa50e0000, sljit_u16)
SLJIT_S390X_RIA(llill, 0xa50f0000, sljit_u16)
SLJIT_S390X_RIA(mhi, 0xa70c0000, sljit_s16)
SLJIT_S390X_RIA(mghi, 0xa70d0000, sljit_s16)
SLJIT_S390X_RIA(oilh, 0xa50a0000, sljit_u16)
SLJIT_S390X_RIA(tmlh, 0xa7000000, sljit_u16)
#undef SLJIT_S390X_RIA
#define SLJIT_S390X_RILA(name, pattern, imm_type) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \
{ \
SLJIT_ASSERT(have_eimm()); \
return (pattern) | ((sljit_ins)(reg & 0xf) << 36) | (imm & 0xffffffff); \
}
SLJIT_S390X_RILA(afi, 0xc20900000000, sljit_s32)
SLJIT_S390X_RILA(agfi, 0xc20800000000, sljit_s32)
SLJIT_S390X_RILA(aih, 0xcc0800000000, sljit_s32)
SLJIT_S390X_RILA(alfi, 0xc20b00000000, sljit_u32)
SLJIT_S390X_RILA(algfi, 0xc20a00000000, sljit_u32)
SLJIT_S390X_RILA(nihf, 0xc00a00000000, sljit_u32)
SLJIT_S390X_RILA(nilf, 0xc00b00000000, sljit_u32)
SLJIT_S390X_RILA(cfi, 0xc20d00000000, sljit_s32)
SLJIT_S390X_RILA(cgfi, 0xc20c00000000, sljit_s32)
SLJIT_S390X_RILA(cih, 0xcc0d00000000, sljit_s32)
SLJIT_S390X_RILA(clfi, 0xc20f00000000, sljit_u32)
SLJIT_S390X_RILA(clgfi, 0xc20e00000000, sljit_u32)
SLJIT_S390X_RILA(xilf, 0xc00700000000, sljit_u32)
SLJIT_S390X_RILA(iihf, 0xc00800000000, sljit_u32)
SLJIT_S390X_RILA(iilf, 0xc00900000000, sljit_u32)
SLJIT_S390X_RILA(lgfi, 0xc00100000000, sljit_s32)
SLJIT_S390X_RILA(llihf, 0xc00e00000000, sljit_u32)
SLJIT_S390X_RILA(llilf, 0xc00f00000000, sljit_u32)
SLJIT_S390X_RILA(oilf, 0xc00d00000000, sljit_u32)
#undef SLJIT_S390X_RILA
#define SLJIT_S390X_RXA(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_u16 d, sljit_gpr x, sljit_gpr b) \
{ \
sljit_ins ri, xi, bi, di; \
\
SLJIT_ASSERT((d & 0xfff) == d); \
ri = (sljit_ins)(r & 0xf) << 20; \
xi = (sljit_ins)(x & 0xf) << 16; \
bi = (sljit_ins)(b & 0xf) << 12; \
di = (sljit_ins)(d & 0xfff); \
\
return (pattern) | ri | xi | bi | di; \
}
SLJIT_S390X_RXA(a, 0x5a000000)
SLJIT_S390X_RXA(al, 0x5e000000)
SLJIT_S390X_RXA(n, 0x54000000)
SLJIT_S390X_RXA(x, 0x57000000)
SLJIT_S390X_RXA(l, 0x58000000)
SLJIT_S390X_RXA(la, 0x41000000)
SLJIT_S390X_RXA(lh, 0x48000000)
SLJIT_S390X_RXA(ms, 0x71000000)
SLJIT_S390X_RXA(o, 0x56000000)
SLJIT_S390X_RXA(st, 0x50000000)
SLJIT_S390X_RXA(stc, 0x42000000)
SLJIT_S390X_RXA(sth, 0x40000000)
SLJIT_S390X_RXA(s, 0x5b000000)
SLJIT_S390X_RXA(sl, 0x5f000000)
#undef SLJIT_S390X_RXA
#define SLJIT_S390X_RXYA(name, pattern, cond) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b) \
{ \
sljit_ins ri, xi, bi, di; \
\
SLJIT_ASSERT(cond); \
ri = (sljit_ins)(r & 0xf) << 36; \
xi = (sljit_ins)(x & 0xf) << 32; \
bi = (sljit_ins)(b & 0xf) << 28; \
di = (sljit_ins)disp_s20(d) << 8; \
\
return (pattern) | ri | xi | bi | di; \
}
SLJIT_S390X_RXYA(ay, 0xe3000000005a, have_ldisp())
SLJIT_S390X_RXYA(ag, 0xe30000000008, 1)
SLJIT_S390X_RXYA(aly, 0xe3000000005e, have_ldisp())
SLJIT_S390X_RXYA(alg, 0xe3000000000a, 1)
SLJIT_S390X_RXYA(alc, 0xe30000000098, 1)
SLJIT_S390X_RXYA(alcg, 0xe30000000088, 1)
SLJIT_S390X_RXYA(ny, 0xe30000000054, have_ldisp())
SLJIT_S390X_RXYA(ng, 0xe30000000080, 1)
SLJIT_S390X_RXYA(xy, 0xe30000000057, have_ldisp())
SLJIT_S390X_RXYA(xg, 0xe30000000082, 1)
SLJIT_S390X_RXYA(ly, 0xe30000000058, have_ldisp())
SLJIT_S390X_RXYA(lg, 0xe30000000004, 1)
SLJIT_S390X_RXYA(lgf, 0xe30000000014, 1)
SLJIT_S390X_RXYA(lb, 0xe30000000076, have_ldisp())
SLJIT_S390X_RXYA(lgb, 0xe30000000077, have_ldisp())
SLJIT_S390X_RXYA(lhy, 0xe30000000078, have_ldisp())
SLJIT_S390X_RXYA(lgh, 0xe30000000015, 1)
SLJIT_S390X_RXYA(llgf, 0xe30000000016, 1)
SLJIT_S390X_RXYA(llc, 0xe30000000094, have_eimm())
SLJIT_S390X_RXYA(llgc, 0xe30000000090, 1)
SLJIT_S390X_RXYA(llh, 0xe30000000095, have_eimm())
SLJIT_S390X_RXYA(llgh, 0xe30000000091, 1)
SLJIT_S390X_RXYA(msy, 0xe30000000051, have_ldisp())
SLJIT_S390X_RXYA(msg, 0xe3000000000c, 1)
SLJIT_S390X_RXYA(oy, 0xe30000000056, have_ldisp())
SLJIT_S390X_RXYA(og, 0xe30000000081, 1)
SLJIT_S390X_RXYA(sty, 0xe30000000050, have_ldisp())
SLJIT_S390X_RXYA(stg, 0xe30000000024, 1)
SLJIT_S390X_RXYA(stcy, 0xe30000000072, have_ldisp())
SLJIT_S390X_RXYA(sthy, 0xe30000000070, have_ldisp())
SLJIT_S390X_RXYA(sy, 0xe3000000005b, have_ldisp())
SLJIT_S390X_RXYA(sg, 0xe30000000009, 1)
SLJIT_S390X_RXYA(sly, 0xe3000000005f, have_ldisp())
SLJIT_S390X_RXYA(slg, 0xe3000000000b, 1)
SLJIT_S390X_RXYA(slb, 0xe30000000099, 1)
SLJIT_S390X_RXYA(slbg, 0xe30000000089, 1)
#undef SLJIT_S390X_RXYA
#define SLJIT_S390X_RSA(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw d, sljit_gpr b) \
{ \
sljit_ins r1 = (sljit_ins)(reg & 0xf) << 20; \
sljit_ins b2 = (sljit_ins)(b & 0xf) << 12; \
sljit_ins d2 = (sljit_ins)(d & 0xfff); \
return (pattern) | r1 | b2 | d2; \
}
SLJIT_S390X_RSA(sll, 0x89000000)
SLJIT_S390X_RSA(sra, 0x8a000000)
SLJIT_S390X_RSA(srl, 0x88000000)
#undef SLJIT_S390X_RSA
#define SLJIT_S390X_RSYA(name, pattern, cond) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_sw d, sljit_gpr b) \
{ \
sljit_ins r1, r3, b2, d2; \
\
SLJIT_ASSERT(cond); \
r1 = (sljit_ins)(dst & 0xf) << 36; \
r3 = (sljit_ins)(src & 0xf) << 32; \
b2 = (sljit_ins)(b & 0xf) << 28; \
d2 = (sljit_ins)disp_s20(d) << 8; \
\
return (pattern) | r1 | r3 | b2 | d2; \
}
SLJIT_S390X_RSYA(lmg, 0xeb0000000004, 1)
SLJIT_S390X_RSYA(sllg, 0xeb000000000d, 1)
SLJIT_S390X_RSYA(srag, 0xeb000000000a, 1)
SLJIT_S390X_RSYA(srlg, 0xeb000000000c, 1)
SLJIT_S390X_RSYA(stmg, 0xeb0000000024, 1)
#undef SLJIT_S390X_RSYA
#define SLJIT_S390X_RIEF(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_u8 start, sljit_u8 end, sljit_u8 rot) \
{ \
sljit_ins r1, r2, i3, i4, i5; \
\
SLJIT_ASSERT(have_genext()); \
r1 = (sljit_ins)(dst & 0xf) << 36; \
r2 = (sljit_ins)(src & 0xf) << 32; \
i3 = (sljit_ins)start << 24; \
i4 = (sljit_ins)end << 16; \
i5 = (sljit_ins)rot << 8; \
\
return (pattern) | r1 | r2 | i3 | i4 | i5; \
}
SLJIT_S390X_RIEF(rosbg, 0xec0000000056)
SLJIT_S390X_RIEF(risbhg, 0xec000000005d)
#undef SLJIT_S390X_RIEF
#define SLJIT_S390X_RRFA(name, pattern, cond) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src1, sljit_gpr src2) \
{ \
sljit_ins r1, r2, r3; \
\
SLJIT_ASSERT(cond); \
r1 = (sljit_ins)(dst & 0xf) << 4; \
r2 = (sljit_ins)(src1 & 0xf); \
r3 = (sljit_ins)(src2 & 0xf) << 12; \
\
return (pattern) | r3 | r1 | r2; \
}
SLJIT_S390X_RRFA(msrkc, 0xb9fd0000, have_misc2())
SLJIT_S390X_RRFA(msgrkc, 0xb9ed0000, have_misc2())
#undef SLJIT_S390X_RRFA
#define SLJIT_S390X_RRFC(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_uw mask) \
{ \
sljit_ins r1, r2, m3; \
\
SLJIT_ASSERT(have_lscond1()); \
r1 = (sljit_ins)(dst & 0xf) << 4; \
r2 = (sljit_ins)(src & 0xf); \
m3 = (sljit_ins)(mask & 0xf) << 12; \
\
return (pattern) | m3 | r1 | r2; \
}
SLJIT_S390X_RRFC(locr, 0xb9f20000)
SLJIT_S390X_RRFC(locgr, 0xb9e20000)
#undef SLJIT_S390X_RRFC
#define SLJIT_S390X_RIEG(name, pattern) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw imm, sljit_uw mask) \
{ \
sljit_ins r1, m3, i2; \
\
SLJIT_ASSERT(have_lscond2()); \
r1 = (sljit_ins)(reg & 0xf) << 36; \
m3 = (sljit_ins)(mask & 0xf) << 32; \
i2 = (sljit_ins)(imm & 0xffffL) << 16; \
\
return (pattern) | r1 | m3 | i2; \
}
SLJIT_S390X_RIEG(lochi, 0xec0000000042)
SLJIT_S390X_RIEG(locghi, 0xec0000000046)
#undef SLJIT_S390X_RIEG
#define SLJIT_S390X_RILB(name, pattern, cond) \
SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw ri) \
{ \
sljit_ins r1, ri2; \
\
SLJIT_ASSERT(cond); \
r1 = (sljit_ins)(reg & 0xf) << 36; \
ri2 = (sljit_ins)(ri & 0xffffffff); \
\
return (pattern) | r1 | ri2; \
}
SLJIT_S390X_RILB(brasl, 0xc00500000000, 1)
SLJIT_S390X_RILB(larl, 0xc00000000000, 1)
SLJIT_S390X_RILB(lgrl, 0xc40800000000, have_genext())
#undef SLJIT_S390X_RILB
SLJIT_S390X_INSTRUCTION(br, sljit_gpr target)
{
return 0x07f0 | target;
}
SLJIT_S390X_INSTRUCTION(brcl, sljit_uw mask, sljit_sw target)
{
sljit_ins m1 = (sljit_ins)(mask & 0xf) << 36;
sljit_ins ri2 = (sljit_ins)target & 0xffffffff;
return 0xc00400000000L | m1 | ri2;
}
SLJIT_S390X_INSTRUCTION(flogr, sljit_gpr dst, sljit_gpr src)
{
sljit_ins r1 = ((sljit_ins)dst & 0xf) << 8;
sljit_ins r2 = ((sljit_ins)src & 0xf);
SLJIT_ASSERT(have_eimm());
return 0xb9830000 | r1 | r2;
}
SLJIT_S390X_INSTRUCTION(ipm, sljit_gpr dst)
{
return 0xb2220000 | ((sljit_ins)(dst & 0xf) << 4);
}
SLJIT_S390X_INSTRUCTION(risbhgz, sljit_gpr dst, sljit_gpr src, sljit_u8 start, sljit_u8 end, sljit_u8 rot)
{
return risbhg(dst, src, start, 0x8 | end, rot);
}
#undef SLJIT_S390X_INSTRUCTION
static sljit_s32 push_load_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
type &= ~SLJIT_I32_OP;
switch (type) {
case SLJIT_ZERO:
case SLJIT_NOT_ZERO:
return push_inst(compiler, cih(flag_r, 0));
break;
default:
return push_inst(compiler, tmlh(flag_r, 0x3000));
break;
}
return SLJIT_SUCCESS;
}
static sljit_s32 push_store_zero_flag(struct sljit_compiler *compiler, sljit_s32 op, sljit_gpr source)
{
FAIL_IF(push_inst(compiler, risbhgz(flag_r, source, 0, 31, 32)));
if (!(op & SLJIT_I32_OP)) {
return push_inst(compiler, rosbg(flag_r, source, 0, 31, 0));
}
return SLJIT_SUCCESS;
}
static sljit_s32 push_load_imm_inst(struct sljit_compiler *compiler, sljit_gpr target, sljit_sw v)
{
if (is_s16(v))
return push_inst(compiler, lghi(target, (sljit_s16)v));
if ((sljit_uw)v == (v & 0x000000000000ffffU))
return push_inst(compiler, llill(target, (sljit_u16)v));
if ((sljit_uw)v == (v & 0x00000000ffff0000U))
return push_inst(compiler, llilh(target, (sljit_u16)(v >> 16)));
if ((sljit_uw)v == (v & 0x0000ffff00000000U))
return push_inst(compiler, llihl(target, (sljit_u16)(v >> 32)));
if ((sljit_uw)v == (v & 0xffff000000000000U))
return push_inst(compiler, llihh(target, (sljit_u16)(v >> 48)));
if (have_eimm()) {
if (is_s32(v))
return push_inst(compiler, lgfi(target, (sljit_s32)v));
if ((sljit_uw)v == (v & 0x00000000ffffffffU))
return push_inst(compiler, llilf(target, (sljit_u32)v));
if ((sljit_uw)v == (v & 0xffffffff00000000U))
return push_inst(compiler, llihf(target, (sljit_u32)(v >> 32)));
FAIL_IF(push_inst(compiler, llilf(target, (sljit_u32)v)));
return push_inst(compiler, iihf(target, (sljit_u32)(v >> 32)));
}
abort();
}
struct addr {
sljit_gpr base;
sljit_gpr index;
sljit_sw offset;
};
static sljit_s32 make_addr_bxy(struct sljit_compiler *compiler,
struct addr *addr, sljit_s32 mem, sljit_sw off,
sljit_gpr tmp )
{
sljit_gpr base = r0;
sljit_gpr index = r0;
SLJIT_ASSERT(tmp != r0);
if (mem & REG_MASK)
base = gpr(mem & REG_MASK);
if (mem & OFFS_REG_MASK) {
index = gpr(OFFS_REG(mem));
if (off != 0) {
SLJIT_ASSERT(0 <= off && off < 64);
FAIL_IF(push_inst(compiler, sllg(tmp, index, off, 0)));
index = tmp;
off = 0;
}
}
else if (!is_s20(off)) {
FAIL_IF(push_load_imm_inst(compiler, tmp, off));
index = tmp;
off = 0;
}
addr->base = base;
addr->index = index;
addr->offset = off;
return SLJIT_SUCCESS;
}
static sljit_s32 make_addr_bx(struct sljit_compiler *compiler,
struct addr *addr, sljit_s32 mem, sljit_sw off,
sljit_gpr tmp )
{
sljit_gpr base = r0;
sljit_gpr index = r0;
SLJIT_ASSERT(tmp != r0);
if (mem & REG_MASK)
base = gpr(mem & REG_MASK);
if (mem & OFFS_REG_MASK) {
index = gpr(OFFS_REG(mem));
if (off != 0) {
SLJIT_ASSERT(0 <= off && off < 64);
FAIL_IF(push_inst(compiler, sllg(tmp, index, off, 0)));
index = tmp;
off = 0;
}
}
else if (!is_u12(off)) {
FAIL_IF(push_load_imm_inst(compiler, tmp, off));
index = tmp;
off = 0;
}
addr->base = base;
addr->index = index;
addr->offset = off;
return SLJIT_SUCCESS;
}
#define EVAL(op, r, addr) op(r, addr.offset, addr.index, addr.base)
#define WHEN(cond, r, i1, i2, addr) \
(cond) ? EVAL(i1, r, addr) : EVAL(i2, r, addr)
static sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst,
sljit_s32 src, sljit_sw srcw,
sljit_gpr tmp , sljit_s32 is_32bit)
{
struct addr addr;
sljit_ins ins;
SLJIT_ASSERT(src & SLJIT_MEM);
if (have_ldisp() || !is_32bit)
FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp));
else
FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp));
if (is_32bit)
ins = WHEN(is_u12(addr.offset), dst, l, ly, addr);
else
ins = lg(dst, addr.offset, addr.index, addr.base);
return push_inst(compiler, ins);
}
static sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src,
sljit_s32 dst, sljit_sw dstw,
sljit_gpr tmp , sljit_s32 is_32bit)
{
struct addr addr;
sljit_ins ins;
SLJIT_ASSERT(dst & SLJIT_MEM);
if (have_ldisp() || !is_32bit)
FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp));
else
FAIL_IF(make_addr_bx(compiler, &addr, dst, dstw, tmp));
if (is_32bit)
ins = WHEN(is_u12(addr.offset), src, st, sty, addr);
else
ins = stg(src, addr.offset, addr.index, addr.base);
return push_inst(compiler, ins);
}
#undef WHEN
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
struct sljit_label *label;
struct sljit_jump *jump;
struct sljit_s390x_const *const_;
struct sljit_put_label *put_label;
sljit_sw executable_offset;
sljit_uw ins_size = 0;
sljit_uw pool_size = 0;
sljit_uw pad_size;
sljit_uw i, j = 0;
struct sljit_memory_fragment *buf;
void *code, *code_ptr;
sljit_uw *pool, *pool_ptr;
sljit_uw source;
sljit_sw offset;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_generate_code(compiler));
reverse_buf(compiler);
label = compiler->labels;
jump = compiler->jumps;
put_label = compiler->put_labels;
for (buf = compiler->buf; buf != NULL; buf = buf->next) {
sljit_uw len = buf->used_size / sizeof(sljit_ins);
sljit_ins *ibuf = (sljit_ins *)buf->memory;
for (i = 0; i < len; ++i, ++j) {
sljit_ins ins = ibuf[i];
if (ins & sljit_ins_const) {
pool_size += sizeof(*pool);
ins &= ~sljit_ins_const;
}
if (label && label->size == j) {
label->size = ins_size;
label = label->next;
}
if (jump && jump->addr == j) {
if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) {
pool_size += sizeof(*pool);
ins_size += 2;
}
jump = jump->next;
}
if (put_label && put_label->addr == j) {
pool_size += sizeof(*pool);
put_label = put_label->next;
}
ins_size += sizeof_ins(ins);
}
}
if (label && label->size == j) {
label->size = ins_size;
label = label->next;
}
SLJIT_ASSERT(!label);
SLJIT_ASSERT(!jump);
SLJIT_ASSERT(!put_label);
pad_size = ((ins_size + 7UL) & ~7UL) - ins_size;
SLJIT_ASSERT(pad_size < 8UL);
code = SLJIT_MALLOC_EXEC(ins_size + pad_size + pool_size,
compiler->exec_allocator_data);
PTR_FAIL_WITH_EXEC_IF(code);
code_ptr = code;
executable_offset = SLJIT_EXEC_OFFSET(code);
pool = (sljit_uw *)((sljit_uw)code + ins_size + pad_size);
pool_ptr = pool;
const_ = (struct sljit_s390x_const *)compiler->consts;
label = compiler->labels;
while (label) {
label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(
(sljit_uw)code_ptr + label->size, executable_offset);
label = label->next;
}
jump = compiler->jumps;
put_label = compiler->put_labels;
j = 0;
for (buf = compiler->buf; buf != NULL; buf = buf->next) {
sljit_uw len = buf->used_size / sizeof(sljit_ins);
sljit_ins *ibuf = (sljit_ins *)buf->memory;
for (i = 0; i < len; ++i, ++j) {
sljit_ins ins = ibuf[i];
if (ins & sljit_ins_const) {
ins &= ~sljit_ins_const;
source = (sljit_uw)code_ptr;
offset = (sljit_uw)pool_ptr - source;
SLJIT_ASSERT(!(offset & 1));
offset >>= 1;
SLJIT_ASSERT(is_s32(offset));
ins |= (sljit_ins)offset & 0xffffffff;
const_->const_.addr = (sljit_uw)pool_ptr;
*(pool_ptr++) = const_->init_value;
const_ = (struct sljit_s390x_const *)const_->const_.next;
}
if (jump && jump->addr == j) {
sljit_sw target = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) {
jump->addr = (sljit_uw)pool_ptr;
source = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
offset = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
SLJIT_ASSERT(!(offset & 1));
offset >>= 1;
SLJIT_ASSERT(is_s32(offset));
encode_inst(&code_ptr,
lgrl(tmp1, offset & 0xffffffff));
*(pool_ptr++) = target;
sljit_ins op = (ins >> 32) & 0xf;
sljit_ins arg = (ins >> 36) & 0xf;
switch (op) {
case 4:
ins = bcr(arg, tmp1);
break;
case 5:
ins = basr(arg, tmp1);
break;
default:
abort();
}
}
else {
jump->addr = (sljit_uw)code_ptr + 2;
source = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
offset = target - source;
SLJIT_ASSERT(!(offset & 1));
offset >>= 1;
SLJIT_ASSERT(is_s32(offset));
ins |= (sljit_ins)offset & 0xffffffff;
}
jump = jump->next;
}
if (put_label && put_label->addr == j) {
source = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
SLJIT_ASSERT(put_label->label);
put_label->addr = (sljit_uw)code_ptr;
*pool_ptr = put_label->label->addr;
offset = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
pool_ptr++;
SLJIT_ASSERT(!(offset & 1));
offset >>= 1;
SLJIT_ASSERT(is_s32(offset));
ins |= (sljit_ins)offset & 0xffffffff;
put_label = put_label->next;
}
encode_inst(&code_ptr, ins);
}
}
SLJIT_ASSERT((sljit_u8 *)code + ins_size == code_ptr);
SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr);
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
compiler->executable_size = ins_size;
code = SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
code_ptr = SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
SLJIT_CACHE_FLUSH(code, code_ptr);
SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
return code;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
switch (feature_type) {
case SLJIT_HAS_CLZ:
return have_eimm() ? 1 : 0;
case SLJIT_HAS_CMOV:
return have_lscond1() ? 1 : 0;
case SLJIT_HAS_FPU:
return 0;
}
return 0;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
sljit_s32 args = get_arg_count(arg_types);
sljit_sw frame_size;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
compiler->local_size = (local_size + 0xf) & ~0xf;
frame_size = compiler->local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE;
FAIL_IF(push_inst(compiler, stmg(r6, r15, r6 * sizeof(sljit_sw), r15)));
if (frame_size != 0) {
if (is_s16(-frame_size))
FAIL_IF(push_inst(compiler, aghi(r15, -((sljit_s16)frame_size))));
else if (is_s32(-frame_size))
FAIL_IF(push_inst(compiler, agfi(r15, -((sljit_s32)frame_size))));
else {
FAIL_IF(push_load_imm_inst(compiler, tmp1, -frame_size));
FAIL_IF(push_inst(compiler, la(r15, 0, tmp1, r15)));
}
}
if (args >= 1)
FAIL_IF(push_inst(compiler, lgr(gpr(SLJIT_S0), gpr(SLJIT_R0))));
if (args >= 2)
FAIL_IF(push_inst(compiler, lgr(gpr(SLJIT_S1), gpr(SLJIT_R1))));
if (args >= 3)
FAIL_IF(push_inst(compiler, lgr(gpr(SLJIT_S2), gpr(SLJIT_R2))));
SLJIT_ASSERT(args < 4);
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
compiler->local_size = (local_size + 0xf) & ~0xf;
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
sljit_sw size;
sljit_gpr end;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
size = compiler->local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE + (r6 * sizeof(sljit_sw));
if (!is_s20(size)) {
FAIL_IF(push_load_imm_inst(compiler, tmp1, compiler->local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE));
FAIL_IF(push_inst(compiler, la(r15, 0, tmp1, r15)));
size = r6 * sizeof(sljit_sw);
end = r14;
}
else
end = r15;
FAIL_IF(push_inst(compiler, lmg(r6, end, size, r15)));
FAIL_IF(push_inst(compiler, br(r14)));
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
sljit_gpr arg0 = gpr(SLJIT_R0);
sljit_gpr arg1 = gpr(SLJIT_R1);
CHECK_ERROR();
CHECK(check_sljit_emit_op0(compiler, op));
op = GET_OPCODE(op) | (op & SLJIT_I32_OP);
switch (op) {
case SLJIT_BREAKPOINT:
case SLJIT_NOP:
return push_inst(compiler, 0x0700 );
case SLJIT_LMUL_UW:
FAIL_IF(push_inst(compiler, mlgr(arg0, arg0)));
break;
case SLJIT_LMUL_SW:
FAIL_IF(push_inst(compiler, srag(tmp0, arg0, 63, 0)));
FAIL_IF(push_inst(compiler, srag(tmp1, arg1, 63, 0)));
FAIL_IF(push_inst(compiler, ngr(tmp0, arg1)));
FAIL_IF(push_inst(compiler, ngr(tmp1, arg0)));
FAIL_IF(push_inst(compiler, mlgr(arg0, arg0)));
FAIL_IF(push_inst(compiler, sgr(arg0, tmp0)));
FAIL_IF(push_inst(compiler, sgr(arg0, tmp1)));
break;
case SLJIT_DIV_U32:
case SLJIT_DIVMOD_U32:
FAIL_IF(push_inst(compiler, lhi(tmp0, 0)));
FAIL_IF(push_inst(compiler, lr(tmp1, arg0)));
FAIL_IF(push_inst(compiler, dlr(tmp0, arg1)));
FAIL_IF(push_inst(compiler, lr(arg0, tmp1)));
if (op == SLJIT_DIVMOD_U32)
return push_inst(compiler, lr(arg1, tmp0));
return SLJIT_SUCCESS;
case SLJIT_DIV_S32:
case SLJIT_DIVMOD_S32:
FAIL_IF(push_inst(compiler, lhi(tmp0, 0)));
FAIL_IF(push_inst(compiler, lr(tmp1, arg0)));
FAIL_IF(push_inst(compiler, dr(tmp0, arg1)));
FAIL_IF(push_inst(compiler, lr(arg0, tmp1)));
if (op == SLJIT_DIVMOD_S32)
return push_inst(compiler, lr(arg1, tmp0));
return SLJIT_SUCCESS;
case SLJIT_DIV_UW:
case SLJIT_DIVMOD_UW:
FAIL_IF(push_inst(compiler, lghi(tmp0, 0)));
FAIL_IF(push_inst(compiler, lgr(tmp1, arg0)));
FAIL_IF(push_inst(compiler, dlgr(tmp0, arg1)));
FAIL_IF(push_inst(compiler, lgr(arg0, tmp1)));
if (op == SLJIT_DIVMOD_UW)
return push_inst(compiler, lgr(arg1, tmp0));
return SLJIT_SUCCESS;
case SLJIT_DIV_SW:
case SLJIT_DIVMOD_SW:
FAIL_IF(push_inst(compiler, lgr(tmp1, arg0)));
FAIL_IF(push_inst(compiler, dsgr(tmp0, arg1)));
FAIL_IF(push_inst(compiler, lgr(arg0, tmp1)));
if (op == SLJIT_DIVMOD_SW)
return push_inst(compiler, lgr(arg1, tmp0));
return SLJIT_SUCCESS;
case SLJIT_ENDBR:
return SLJIT_SUCCESS;
case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
return SLJIT_SUCCESS;
default:
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, lgr(tmp0, arg0)));
FAIL_IF(push_inst(compiler, lgr(arg0, arg1)));
return push_inst(compiler, lgr(arg1, tmp0));
}
#define WHEN2(cond, i1, i2) (cond) ? LEVAL(i1) : LEVAL(i2)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_ins ins;
struct addr mem;
sljit_gpr dst_r;
sljit_gpr src_r;
sljit_s32 opcode = GET_OPCODE(op);
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src, srcw);
if ((dst == SLJIT_UNUSED) && !HAS_FLAGS(op)) {
return SLJIT_SUCCESS;
}
if (opcode >= SLJIT_MOV && opcode <= SLJIT_MOV_P) {
if (FAST_IS_REG(dst) && FAST_IS_REG(src)) {
dst_r = gpr(dst);
src_r = gpr(src);
switch (opcode | (op & SLJIT_I32_OP)) {
case SLJIT_MOV32_U8:
ins = llcr(dst_r, src_r);
break;
case SLJIT_MOV32_S8:
ins = lbr(dst_r, src_r);
break;
case SLJIT_MOV32_U16:
ins = llhr(dst_r, src_r);
break;
case SLJIT_MOV32_S16:
ins = lhr(dst_r, src_r);
break;
case SLJIT_MOV32:
ins = lr(dst_r, src_r);
break;
case SLJIT_MOV_U8:
ins = llgcr(dst_r, src_r);
break;
case SLJIT_MOV_S8:
ins = lgbr(dst_r, src_r);
break;
case SLJIT_MOV_U16:
ins = llghr(dst_r, src_r);
break;
case SLJIT_MOV_S16:
ins = lghr(dst_r, src_r);
break;
case SLJIT_MOV_U32:
ins = llgfr(dst_r, src_r);
break;
case SLJIT_MOV_S32:
ins = lgfr(dst_r, src_r);
break;
case SLJIT_MOV:
case SLJIT_MOV_P:
ins = lgr(dst_r, src_r);
break;
default:
ins = 0;
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
if (HAS_FLAGS(op)) {
SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
return push_store_zero_flag(compiler, op, dst_r);
}
return SLJIT_SUCCESS;
}
if (FAST_IS_REG(dst) && (src & SLJIT_IMM)) {
switch (opcode) {
case SLJIT_MOV_U8:
srcw = (sljit_sw)((sljit_u8)(srcw));
break;
case SLJIT_MOV_S8:
srcw = (sljit_sw)((sljit_s8)(srcw));
break;
case SLJIT_MOV_U16:
srcw = (sljit_sw)((sljit_u16)(srcw));
break;
case SLJIT_MOV_S16:
srcw = (sljit_sw)((sljit_s16)(srcw));
break;
case SLJIT_MOV_U32:
srcw = (sljit_sw)((sljit_u32)(srcw));
break;
case SLJIT_MOV_S32:
srcw = (sljit_sw)((sljit_s32)(srcw));
break;
}
return push_load_imm_inst(compiler, gpr(dst), srcw);
}
#define LEVAL(i) EVAL(i, reg, mem)
if (FAST_IS_REG(dst) && (src & SLJIT_MEM)) {
sljit_gpr reg = gpr(dst);
FAIL_IF(make_addr_bxy(compiler, &mem, src, srcw, tmp1));
switch (opcode | (op & SLJIT_I32_OP)) {
case SLJIT_MOV32_U8:
ins = llc(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV32_S8:
ins = lb(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV32_U16:
ins = llh(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV32_S16:
ins = WHEN2(is_u12(mem.offset), lh, lhy);
break;
case SLJIT_MOV32:
ins = WHEN2(is_u12(mem.offset), l, ly);
break;
case SLJIT_MOV_U8:
ins = LEVAL(llgc);
break;
case SLJIT_MOV_S8:
ins = lgb(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV_U16:
ins = LEVAL(llgh);
break;
case SLJIT_MOV_S16:
ins = lgh(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV_U32:
ins = LEVAL(llgf);
break;
case SLJIT_MOV_S32:
ins = lgf(reg, mem.offset, mem.index, mem.base);
break;
case SLJIT_MOV_P:
case SLJIT_MOV:
ins = lg(reg, mem.offset, mem.index, mem.base);
break;
default:
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
if (HAS_FLAGS(op)) {
SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
return push_store_zero_flag(compiler, op, reg);
}
return SLJIT_SUCCESS;
}
if ((dst & SLJIT_MEM)
&& (FAST_IS_REG(src) || (src & SLJIT_IMM))) {
sljit_gpr reg = FAST_IS_REG(src) ? gpr(src) : tmp0;
if (src & SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, reg, srcw));
}
struct addr mem;
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
switch (opcode) {
case SLJIT_MOV_U8:
case SLJIT_MOV_S8:
return push_inst(compiler,
WHEN2(is_u12(mem.offset), stc, stcy));
case SLJIT_MOV_U16:
case SLJIT_MOV_S16:
return push_inst(compiler,
WHEN2(is_u12(mem.offset), sth, sthy));
case SLJIT_MOV_U32:
case SLJIT_MOV_S32:
return push_inst(compiler,
WHEN2(is_u12(mem.offset), st, sty));
case SLJIT_MOV_P:
case SLJIT_MOV:
FAIL_IF(push_inst(compiler, LEVAL(stg)));
if (HAS_FLAGS(op)) {
SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
return push_store_zero_flag(compiler, op, reg);
}
return SLJIT_SUCCESS;
default:
SLJIT_UNREACHABLE();
}
}
#undef LEVAL
if ((dst & SLJIT_MEM) && (src & SLJIT_MEM)) {
struct addr mem;
FAIL_IF(make_addr_bxy(compiler, &mem, src, srcw, tmp1));
switch (opcode) {
case SLJIT_MOV_U8:
case SLJIT_MOV_S8:
FAIL_IF(push_inst(compiler,
EVAL(llgc, tmp0, mem)));
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
return push_inst(compiler,
EVAL(stcy, tmp0, mem));
case SLJIT_MOV_U16:
case SLJIT_MOV_S16:
FAIL_IF(push_inst(compiler,
EVAL(llgh, tmp0, mem)));
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
return push_inst(compiler,
EVAL(sthy, tmp0, mem));
case SLJIT_MOV_U32:
case SLJIT_MOV_S32:
FAIL_IF(push_inst(compiler,
EVAL(ly, tmp0, mem)));
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
return push_inst(compiler,
EVAL(sty, tmp0, mem));
case SLJIT_MOV_P:
case SLJIT_MOV:
FAIL_IF(push_inst(compiler,
EVAL(lg, tmp0, mem)));
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
FAIL_IF(push_inst(compiler,
EVAL(stg, tmp0, mem)));
if (HAS_FLAGS(op)) {
SLJIT_ASSERT(!(op & VARIABLE_FLAG_MASK));
return push_store_zero_flag(compiler, op, tmp0);
}
return SLJIT_SUCCESS;
default:
SLJIT_UNREACHABLE();
}
}
SLJIT_UNREACHABLE();
}
SLJIT_ASSERT((src & SLJIT_IMM) == 0);
dst_r = SLOW_IS_REG(dst) ? gpr(REG_MASK & dst) : tmp0;
src_r = FAST_IS_REG(src) ? gpr(REG_MASK & src) : tmp0;
if (src & SLJIT_MEM)
FAIL_IF(load_word(compiler, src_r, src, srcw, tmp1, src & SLJIT_I32_OP));
switch (opcode | (op & SLJIT_I32_OP)) {
case SLJIT_NOT:
FAIL_IF(push_load_imm_inst(compiler, tmp1, -1));
if (src_r != dst_r)
FAIL_IF(push_inst(compiler, lgr(dst_r, src_r)));
FAIL_IF(push_inst(compiler, xgr(dst_r, tmp1)));
break;
case SLJIT_NOT32:
if (have_eimm())
FAIL_IF(push_inst(compiler, xilf(dst_r, -1)));
else {
FAIL_IF(push_load_imm_inst(compiler, tmp1, -1));
if (src_r != dst_r)
FAIL_IF(push_inst(compiler, lr(dst_r, src_r)));
FAIL_IF(push_inst(compiler, xr(dst_r, tmp1)));
}
break;
case SLJIT_NEG:
FAIL_IF(push_inst(compiler, lcgr(dst_r, src_r)));
break;
case SLJIT_NEG32:
FAIL_IF(push_inst(compiler, lcr(dst_r, src_r)));
break;
case SLJIT_CLZ:
if (have_eimm()) {
FAIL_IF(push_inst(compiler, flogr(tmp0, src_r)));
if (dst_r != tmp0)
FAIL_IF(push_inst(compiler, lgr(dst_r, tmp0)));
} else {
abort();
}
break;
case SLJIT_CLZ32:
if (have_eimm()) {
FAIL_IF(push_inst(compiler, sllg(tmp1, src_r, 32, 0)));
FAIL_IF(push_inst(compiler, iilf(tmp1, 0xffffffff)));
FAIL_IF(push_inst(compiler, flogr(tmp0, tmp1)));
if (dst_r != tmp0)
FAIL_IF(push_inst(compiler, lr(dst_r, tmp0)));
} else {
abort();
}
break;
default:
SLJIT_UNREACHABLE();
}
if (op & VARIABLE_FLAG_MASK)
FAIL_IF(push_inst(compiler, ipm(flag_r)));
if (op & SLJIT_SET_Z)
FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
if ((dst != SLJIT_UNUSED) && (dst & SLJIT_MEM))
FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
return SLJIT_SUCCESS;
}
static SLJIT_INLINE int is_commutative(sljit_s32 op)
{
switch (GET_OPCODE(op)) {
case SLJIT_ADD:
case SLJIT_ADDC:
case SLJIT_MUL:
case SLJIT_AND:
case SLJIT_OR:
case SLJIT_XOR:
return 1;
}
return 0;
}
static SLJIT_INLINE int is_shift(sljit_s32 op) {
sljit_s32 v = GET_OPCODE(op);
return (v == SLJIT_SHL || v == SLJIT_ASHR || v == SLJIT_LSHR) ? 1 : 0;
}
static SLJIT_INLINE int sets_signed_flag(sljit_s32 op)
{
switch (GET_FLAG_TYPE(op)) {
case SLJIT_OVERFLOW:
case SLJIT_NOT_OVERFLOW:
case SLJIT_SIG_LESS:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_SIG_GREATER:
case SLJIT_SIG_GREATER_EQUAL:
return 1;
}
return 0;
}
static int have_op_3_imm(sljit_s32 op, sljit_sw imm) {
return 0;
}
static int have_op_2_imm(sljit_s32 op, sljit_sw imm) {
switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
case SLJIT_ADD32:
case SLJIT_ADD:
if (!HAS_FLAGS(op) || sets_signed_flag(op))
return have_eimm() ? is_s32(imm) : is_s16(imm);
return have_eimm() && is_u32(imm);
case SLJIT_MUL32:
case SLJIT_MUL:
if (op & VARIABLE_FLAG_MASK)
return 0;
return have_genext() && is_s16(imm);
case SLJIT_OR32:
case SLJIT_XOR32:
case SLJIT_AND32:
return have_eimm();
case SLJIT_AND:
case SLJIT_OR:
case SLJIT_XOR:
return 0;
case SLJIT_ADDC32:
case SLJIT_ADDC:
return 0;
case SLJIT_SUB:
case SLJIT_SUB32:
case SLJIT_SUBC:
case SLJIT_SUBC32:
return 0;
}
return 0;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(dst, dstw);
ADJUST_LOCAL_OFFSET(src1, src1w);
ADJUST_LOCAL_OFFSET(src2, src2w);
if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
return SLJIT_SUCCESS;
sljit_gpr dst_r = SLOW_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
if (is_commutative(op)) {
#define SWAP_ARGS \
do { \
sljit_s32 t = src1; \
sljit_sw tw = src1w; \
src1 = src2; \
src1w = src2w; \
src2 = t; \
src2w = tw; \
} while(0);
if (src1 & SLJIT_IMM) {
SWAP_ARGS
}
if (FAST_IS_REG(src2) && gpr(src2 & REG_MASK) == dst_r) {
SWAP_ARGS
}
if (FAST_IS_REG(src2) && (src1 & SLJIT_MEM)) {
SWAP_ARGS
}
#undef SWAP_ARGS
}
sljit_gpr src1_r = FAST_IS_REG(src1) ? gpr(src1 & REG_MASK) : tmp0;
if (src1 & SLJIT_IMM)
FAIL_IF(push_load_imm_inst(compiler, src1_r, src1w));
if (src1 & SLJIT_MEM)
FAIL_IF(load_word(compiler, src1_r, src1, src1w, tmp1, op & SLJIT_I32_OP));
if (GET_OPCODE(op) == SLJIT_SUB && (op & VARIABLE_FLAG_MASK)) {
sljit_sw cmp = 0;
switch (GET_FLAG_TYPE(op)) {
case SLJIT_LESS:
case SLJIT_LESS_EQUAL:
case SLJIT_GREATER:
case SLJIT_GREATER_EQUAL:
cmp = 1;
break;
case SLJIT_EQUAL:
case SLJIT_SIG_LESS:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_SIG_GREATER:
case SLJIT_SIG_GREATER_EQUAL:
cmp = -1;
break;
}
if (cmp) {
op &= ~VARIABLE_FLAG_MASK;
sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
if (src2 & SLJIT_IMM) {
#define LEVAL(i) i(src1_r, src2w)
if (cmp > 0 && is_u32(src2w)) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, clfi, clgfi)));
}
else if (cmp < 0 && is_s16(src2w)) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, chi, cghi)));
}
else if (cmp < 0 && is_s32(src2w)) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, cfi, cgfi)));
}
#undef LEVAL
#define LEVAL(i) i(src1_r, src2_r)
else {
FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
if (cmp > 0) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, clr, clgr)));
}
if (cmp < 0) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, cr, cgr)));
}
}
}
else {
if (src2 & SLJIT_MEM) {
FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
}
if (cmp > 0) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, clr, clgr)));
}
if (cmp < 0) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, cr, cgr)));
}
#undef LEVAL
}
FAIL_IF(push_inst(compiler, ipm(flag_r)));
}
}
if (!HAS_FLAGS(op) && dst == SLJIT_UNUSED)
return SLJIT_SUCCESS;
int signed_flags = sets_signed_flag(op);
if (is_shift(op)) {
sljit_sw d = 0;
sljit_gpr b = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : r0;
if (src2 & SLJIT_IMM)
d = src2w & ((op & SLJIT_I32_OP) ? 31 : 63);
if (src2 & SLJIT_MEM) {
FAIL_IF(load_word(compiler, tmp1, src2, src2w, tmp1, op & SLJIT_I32_OP));
b = tmp1;
}
int workaround_alias = op & SLJIT_I32_OP && src1_r != dst_r;
if (workaround_alias) {
FAIL_IF(push_inst(compiler, lr(tmp0, src1_r)));
src1_r = tmp0;
}
switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
case SLJIT_SHL:
FAIL_IF(push_inst(compiler, sllg(dst_r, src1_r, d, b)));
break;
case SLJIT_SHL32:
FAIL_IF(push_inst(compiler, sll(src1_r, d, b)));
break;
case SLJIT_LSHR:
FAIL_IF(push_inst(compiler, srlg(dst_r, src1_r, d, b)));
break;
case SLJIT_LSHR32:
FAIL_IF(push_inst(compiler, srl(src1_r, d, b)));
break;
case SLJIT_ASHR:
FAIL_IF(push_inst(compiler, srag(dst_r, src1_r, d, b)));
break;
case SLJIT_ASHR32:
FAIL_IF(push_inst(compiler, sra(src1_r, d, b)));
break;
default:
SLJIT_UNREACHABLE();
}
if (workaround_alias && dst_r != src1_r)
FAIL_IF(push_inst(compiler, lr(dst_r, src1_r)));
}
else if ((GET_OPCODE(op) == SLJIT_MUL) && HAS_FLAGS(op)) {
SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW ||
GET_FLAG_TYPE(op) == SLJIT_MUL_NOT_OVERFLOW);
sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
if (src2 & SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
}
if (src2 & SLJIT_MEM) {
FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
}
if (have_misc2()) {
#define LEVAL(i) i(dst_r, src1_r, src2_r)
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, msrkc, msgrkc)));
#undef LEVAL
}
else if (op & SLJIT_I32_OP) {
op &= ~VARIABLE_FLAG_MASK;
FAIL_IF(push_inst(compiler, lgfr(tmp0, src1_r)));
FAIL_IF(push_inst(compiler, msgfr(tmp0, src2_r)));
if (dst_r != tmp0) {
FAIL_IF(push_inst(compiler, lr(dst_r, tmp0)));
}
FAIL_IF(push_inst(compiler, aih(tmp0, 1)));
FAIL_IF(push_inst(compiler, nihf(tmp0, ~1U)));
FAIL_IF(push_inst(compiler, ipm(flag_r)));
FAIL_IF(push_inst(compiler, oilh(flag_r, 0x2000)));
}
else
return SLJIT_ERR_UNSUPPORTED;
}
else if ((GET_OPCODE(op) == SLJIT_SUB) && (op & SLJIT_SET_Z) && !signed_flags) {
if (src1_r != dst_r && src1_r != tmp0) {
#define LEVAL(i) i(tmp0, src1_r)
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, lr, lgr)));
src1_r = tmp0;
#undef LEVAL
}
sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
if (src2 & SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
}
if (src2 & SLJIT_MEM) {
FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
}
if (op & SLJIT_I32_OP) {
FAIL_IF(push_inst(compiler, lcr(tmp1, src2_r)));
FAIL_IF(push_inst(compiler, alr(src1_r, tmp1)));
if (src1_r != dst_r)
FAIL_IF(push_inst(compiler, lr(dst_r, src1_r)));
}
else {
FAIL_IF(push_inst(compiler, lcgr(tmp1, src2_r)));
FAIL_IF(push_inst(compiler, algr(src1_r, tmp1)));
if (src1_r != dst_r)
FAIL_IF(push_inst(compiler, lgr(dst_r, src1_r)));
}
}
else if ((src2 & SLJIT_IMM) && (src1_r == dst_r) && have_op_2_imm(op, src2w)) {
switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
#define LEVAL(i) i(dst_r, src2w)
case SLJIT_ADD:
if (!HAS_FLAGS(op) || signed_flags) {
FAIL_IF(push_inst(compiler,
WHEN2(is_s16(src2w), aghi, agfi)));
}
else
FAIL_IF(push_inst(compiler, LEVAL(algfi)));
break;
case SLJIT_ADD32:
if (!HAS_FLAGS(op) || signed_flags)
FAIL_IF(push_inst(compiler,
WHEN2(is_s16(src2w), ahi, afi)));
else
FAIL_IF(push_inst(compiler, LEVAL(alfi)));
break;
#undef LEVAL
case SLJIT_MUL:
FAIL_IF(push_inst(compiler, mhi(dst_r, src2w)));
break;
case SLJIT_MUL32:
FAIL_IF(push_inst(compiler, mghi(dst_r, src2w)));
break;
case SLJIT_OR32:
FAIL_IF(push_inst(compiler, oilf(dst_r, src2w)));
break;
case SLJIT_XOR32:
FAIL_IF(push_inst(compiler, xilf(dst_r, src2w)));
break;
case SLJIT_AND32:
FAIL_IF(push_inst(compiler, nilf(dst_r, src2w)));
break;
default:
SLJIT_UNREACHABLE();
}
}
else if ((src2 & SLJIT_IMM) && have_op_3_imm(op, src2w)) {
abort();
}
else if ((src2 & SLJIT_MEM) && (dst_r == src1_r)) {
int need_u12 = !have_ldisp() &&
(op & SLJIT_I32_OP) &&
(GET_OPCODE(op) != SLJIT_ADDC) &&
(GET_OPCODE(op) != SLJIT_SUBC);
struct addr mem;
if (need_u12)
FAIL_IF(make_addr_bx(compiler, &mem, src2, src2w, tmp1));
else
FAIL_IF(make_addr_bxy(compiler, &mem, src2, src2w, tmp1));
int can_u12 = is_u12(mem.offset) ? 1 : 0;
sljit_ins ins = 0;
switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
#define LEVAL(i) EVAL(i, dst_r, mem)
case SLJIT_ADD:
ins = WHEN2(signed_flags, ag, alg);
break;
case SLJIT_SUB:
ins = WHEN2(signed_flags, sg, slg);
break;
case SLJIT_ADDC:
ins = LEVAL(alcg);
break;
case SLJIT_SUBC:
ins = LEVAL(slbg);
break;
case SLJIT_MUL:
ins = LEVAL(msg);
break;
case SLJIT_OR:
ins = LEVAL(og);
break;
case SLJIT_XOR:
ins = LEVAL(xg);
break;
case SLJIT_AND:
ins = LEVAL(ng);
break;
case SLJIT_ADD32:
if (signed_flags)
ins = WHEN2(can_u12, a, ay);
else
ins = WHEN2(can_u12, al, aly);
break;
case SLJIT_SUB32:
if (signed_flags)
ins = WHEN2(can_u12, s, sy);
else
ins = WHEN2(can_u12, sl, sly);
break;
case SLJIT_ADDC32:
ins = LEVAL(alc);
break;
case SLJIT_SUBC32:
ins = LEVAL(slb);
break;
case SLJIT_MUL32:
ins = WHEN2(can_u12, ms, msy);
break;
case SLJIT_OR32:
ins = WHEN2(can_u12, o, oy);
break;
case SLJIT_XOR32:
ins = WHEN2(can_u12, x, xy);
break;
case SLJIT_AND32:
ins = WHEN2(can_u12, n, ny);
break;
#undef LEVAL
default:
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
}
else {
sljit_gpr src2_r = FAST_IS_REG(src2) ? gpr(src2 & REG_MASK) : tmp1;
if (src2 & SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, src2_r, src2w));
}
if (src2 & SLJIT_MEM) {
FAIL_IF(load_word(compiler, src2_r, src2, src2w, tmp1, op & SLJIT_I32_OP));
}
#define LEVAL(i) i(tmp0, src1_r)
if (src1_r != dst_r && src1_r != tmp0) {
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, lr, lgr)));
src1_r = tmp0;
}
#undef LEVAL
sljit_ins ins = 0;
switch (GET_OPCODE(op) | (op & SLJIT_I32_OP)) {
#define LEVAL(i) i(src1_r, src2_r)
case SLJIT_ADD:
ins = WHEN2(signed_flags, agr, algr);
break;
case SLJIT_SUB:
ins = WHEN2(signed_flags, sgr, slgr);
break;
case SLJIT_ADDC:
ins = LEVAL(alcgr);
break;
case SLJIT_SUBC:
ins = LEVAL(slbgr);
break;
case SLJIT_MUL:
ins = LEVAL(msgr);
break;
case SLJIT_AND:
ins = LEVAL(ngr);
break;
case SLJIT_OR:
ins = LEVAL(ogr);
break;
case SLJIT_XOR:
ins = LEVAL(xgr);
break;
case SLJIT_ADD32:
ins = WHEN2(signed_flags, ar, alr);
break;
case SLJIT_SUB32:
ins = WHEN2(signed_flags, sr, slr);
break;
case SLJIT_ADDC32:
ins = LEVAL(alcr);
break;
case SLJIT_SUBC32:
ins = LEVAL(slbr);
break;
case SLJIT_MUL32:
ins = LEVAL(msr);
break;
case SLJIT_AND32:
ins = LEVAL(nr);
break;
case SLJIT_OR32:
ins = LEVAL(or);
break;
case SLJIT_XOR32:
ins = LEVAL(xr);
break;
#undef LEVAL
default:
SLJIT_UNREACHABLE();
}
FAIL_IF(push_inst(compiler, ins));
#define LEVAL(i) i(dst_r, src1_r)
if (src1_r != dst_r)
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, lr, lgr)));
#undef LEVAL
}
if (op & VARIABLE_FLAG_MASK)
FAIL_IF(push_inst(compiler, ipm(flag_r)));
if (op & SLJIT_SET_Z)
FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
if (dst & SLJIT_MEM) {
SLJIT_ASSERT(dst_r != tmp1);
FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
}
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(
struct sljit_compiler *compiler,
sljit_s32 op, sljit_s32 src, sljit_sw srcw)
{
sljit_gpr src_r;
CHECK_ERROR();
CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
switch (op) {
case SLJIT_FAST_RETURN:
src_r = FAST_IS_REG(src) ? gpr(src) : tmp1;
if (src & SLJIT_MEM)
FAIL_IF(load_word(compiler, tmp1, src, srcw, tmp1, 0));
return push_inst(compiler, br(src_r));
case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
return SLJIT_SUCCESS;
case SLJIT_PREFETCH_L1:
case SLJIT_PREFETCH_L2:
case SLJIT_PREFETCH_L3:
case SLJIT_PREFETCH_ONCE:
return SLJIT_SUCCESS;
default:
return SLJIT_SUCCESS;
}
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_register_index(reg));
return gpr(reg);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
{
CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
abort();
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_s32 size)
{
sljit_ins ins = 0;
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
memcpy((sljit_u8 *)&ins + sizeof(ins) - size, instruction, size);
return push_inst(compiler, ins);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
abort();
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
CHECK_ERROR();
abort();
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
if (FAST_IS_REG(dst))
return push_inst(compiler, lgr(gpr(dst), fast_link_r));
return store_word(compiler, fast_link_r, dst, dstw, tmp1, 0);
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
{
struct sljit_label *label;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_label(compiler));
if (compiler->last_label && compiler->last_label->size == compiler->size)
return compiler->last_label;
label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
PTR_FAIL_IF(!label);
set_label(label, compiler);
return label;
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
sljit_u8 mask = ((type & 0xff) < SLJIT_JUMP) ? get_cc(type & 0xff) : 0xf;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_jump(compiler, type));
if (mask != 0xf)
PTR_FAIL_IF(push_load_cc(compiler, type & 0xff));
struct sljit_jump *jump = (struct sljit_jump *)
ensure_abuf(compiler, sizeof(struct sljit_jump));
PTR_FAIL_IF(!jump);
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
jump->addr = compiler->size;
type &= 0xff;
if (type >= SLJIT_FAST_CALL)
PTR_FAIL_IF(push_inst(compiler, brasl(type == SLJIT_FAST_CALL ? fast_link_r : link_r, 0)));
else
PTR_FAIL_IF(push_inst(compiler, brcl(mask, 0)));
return jump;
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 arg_types)
{
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
return sljit_emit_jump(compiler, type);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
sljit_gpr src_r = FAST_IS_REG(src) ? gpr(src) : tmp1;
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
if (src & SLJIT_IMM) {
SLJIT_ASSERT(!(srcw & 1));
FAIL_IF(push_load_imm_inst(compiler, src_r, srcw));
}
else if (src & SLJIT_MEM)
FAIL_IF(load_word(compiler, src_r, src, srcw, tmp1, 0 ));
if (type >= SLJIT_FAST_CALL)
return push_inst(compiler, basr(type == SLJIT_FAST_CALL ? fast_link_r : link_r, src_r));
return push_inst(compiler, br(src_r));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 arg_types,
sljit_s32 src, sljit_sw srcw)
{
CHECK_ERROR();
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
return sljit_emit_ijump(compiler, type, src, srcw);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 type)
{
sljit_u8 mask = get_cc(type & 0xff);
CHECK_ERROR();
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
sljit_gpr loc_r = tmp1;
switch (GET_OPCODE(op)) {
case SLJIT_AND:
case SLJIT_OR:
case SLJIT_XOR:
if (dst & SLJIT_MEM)
FAIL_IF(load_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
break;
case SLJIT_MOV:
case (SLJIT_MOV32 & ~SLJIT_I32_OP):
loc_r = dst_r;
break;
default:
SLJIT_UNREACHABLE();
}
if (mask != 0xf)
FAIL_IF(push_load_cc(compiler, type & 0xff));
#define LEVAL(i) i(loc_r, 1, mask)
if (have_lscond2()) {
FAIL_IF(push_load_imm_inst(compiler, loc_r, 0));
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, lochi, locghi)));
} else {
abort();
}
#undef LEVAL
switch (GET_OPCODE(op)) {
#define LEVAL(i) i(dst_r, loc_r)
case SLJIT_AND:
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, nr, ngr)));
break;
case SLJIT_OR:
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, or, ogr)));
break;
case SLJIT_XOR:
FAIL_IF(push_inst(compiler,
WHEN2(op & SLJIT_I32_OP, xr, xgr)));
break;
#undef LEVAL
}
if (op & SLJIT_SET_Z)
FAIL_IF(push_store_zero_flag(compiler, op, dst_r));
if (dst & SLJIT_MEM)
FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, op & SLJIT_I32_OP));
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
sljit_s32 src, sljit_sw srcw)
{
sljit_u8 mask = get_cc(type & 0xff);
sljit_gpr dst_r = gpr(dst_reg & ~SLJIT_I32_OP);
sljit_gpr src_r = FAST_IS_REG(src) ? gpr(src) : tmp0;
CHECK_ERROR();
CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
if (mask != 0xf)
FAIL_IF(push_load_cc(compiler, type & 0xff));
if (src & SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, src_r, srcw));
}
#define LEVAL(i) i(dst_r, src_r, mask)
if (have_lscond1())
return push_inst(compiler,
WHEN2(dst_reg & SLJIT_I32_OP, locr, locgr));
#undef LEVAL
return SLJIT_ERR_UNSUPPORTED;
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_s390x_const *const_;
sljit_gpr dst_r;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
const_ = (struct sljit_s390x_const*)ensure_abuf(compiler,
sizeof(struct sljit_s390x_const));
PTR_FAIL_IF(!const_);
set_const((struct sljit_const*)const_, compiler);
const_->init_value = init_value;
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
if (have_genext())
PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | lgrl(dst_r, 0)));
else {
PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | larl(tmp1, 0)));
PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1)));
}
if (dst & SLJIT_MEM)
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, 0 ));
return (struct sljit_const*)const_;
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
sljit_uw *ptr = (sljit_uw *)addr;
SLJIT_UNUSED_ARG(executable_offset);
SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0);
*ptr = new_target;
SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);
SLJIT_CACHE_FLUSH(ptr, ptr + 1);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
{
sljit_set_jump_addr(addr, new_constant, executable_offset);
}
SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label(
struct sljit_compiler *compiler,
sljit_s32 dst, sljit_sw dstw)
{
struct sljit_put_label *put_label;
sljit_gpr dst_r;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
PTR_FAIL_IF(!put_label);
set_put_label(put_label, compiler, 0);
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
if (have_genext())
PTR_FAIL_IF(push_inst(compiler, lgrl(dst_r, 0)));
else {
PTR_FAIL_IF(push_inst(compiler, larl(tmp1, 0)));
PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1)));
}
if (dst & SLJIT_MEM)
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, tmp1, 0));
return put_label;
}
#undef WHEN2
#undef EVAL
#undef tmp1
#undef tmp0