mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-07 09:26:11 -10:00
[RV64_DYNAREC] Reworked move immediate (#4591)
* [RV64_DYNAREC] Reworked move immediate * Use -O2 for test37
This commit is contained in:
1 parent
420eda69ff
commit
a46ad9dfe9
36 files changed
+1323
-208
No files matched your search
@@ -261,7 +261,7 @@ jobs:
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON" >> $GITHUB_ENV
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON -DBAD_SIGNAL=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-powerpc64le-linux-gnu cmake make python3 libzydis-dev
|
||||
else
|
||||
|
||||
@@ -1103,6 +1103,7 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_consts.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_mov_imm.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/updateflags_rv64.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
|
||||
@@ -1267,18 +1267,15 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg, Id");
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
SCRATCH_USAGE(0);
|
||||
MARKREGd(gd);
|
||||
if (rex.w) {
|
||||
u64 = F64;
|
||||
MOV64x(gd, u64);
|
||||
MOV64xss(gd, u64, x1, x2);
|
||||
} else {
|
||||
SCRATCH_USAGE(0);
|
||||
u32 = F32;
|
||||
MOV32w(gd, u32);
|
||||
if ((int32_t)u32 >= 0)
|
||||
UP32_ZERO(gd);
|
||||
else if (NEED_ZEROUP(gd))
|
||||
ZEROUP_RESULT(gd);
|
||||
UP32_ZERO(gd);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -402,8 +402,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
if (eb2) {
|
||||
// load a mask to x3 (ffffffffffff00ff)
|
||||
LUI(x3, 0xffff0);
|
||||
ORI(x3, x3, 0xff);
|
||||
MOV64x(x3, 0xFFFFFFFFFFFF00FF);
|
||||
// apply mask
|
||||
AND(eb1, eb1, x3);
|
||||
if (u8) {
|
||||
@@ -1532,7 +1531,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
OR(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
LUI(x2, 0xffff0);
|
||||
MOV64x(x2, 0xFFFFFFFFFFFF0000);
|
||||
AND(xRAX, xRAX, x2);
|
||||
ZEXTH(x1, x1);
|
||||
OR(xRAX, xRAX, x1);
|
||||
@@ -1561,7 +1560,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
OR(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
LUI(x2, 0xffff0);
|
||||
MOV64x(x2, 0xFFFFFFFFFFFF0000);
|
||||
AND(xRAX, xRAX, x2);
|
||||
ZEXTH(x1, x1);
|
||||
OR(xRAX, xRAX, x1);
|
||||
@@ -1589,7 +1588,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
DIVUW(x3, x2, ed);
|
||||
REMUW(x4, x2, ed);
|
||||
LUI(x5, 0xffff0);
|
||||
MOV64x(x5, 0xFFFFFFFFFFFF0000);
|
||||
AND(xRAX, xRAX, x5);
|
||||
ANDI(x3, x3, 0xff);
|
||||
OR(xRAX, xRAX, x3);
|
||||
|
||||
@@ -1252,7 +1252,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s1 = fpu_get_scratch(dyn); // 1.0f
|
||||
v0 = fpu_get_scratch(dyn); // 0.0f
|
||||
LUI(x3, 0x3f800);
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(s1, x3); // 1.0f
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCVTSW(v0, xZR, RD_DYN);
|
||||
@@ -1293,7 +1293,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEX(x2, 0, 12);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
LUI(x3, 0x3f800);
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(d0, x3); // 1.0f
|
||||
if (!BOX64ENV(dynarec_fastnan))
|
||||
MOV32w(x6, 0x00400000);
|
||||
@@ -2120,8 +2120,7 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
eb1 = TO_NAT(ed & 3); \
|
||||
} \
|
||||
if (eb2) { \
|
||||
LUI(tmp1, 0xffff0); \
|
||||
ORI(tmp1, tmp1, 0xff); \
|
||||
MOV64x(tmp1, 0xFFFFFFFFFFFF00FF); \
|
||||
AND(eb1, eb1, tmp1); \
|
||||
SLLI(tmp3, tmp3, 8); \
|
||||
} else { \
|
||||
|
||||
@@ -552,7 +552,7 @@ uintptr_t dynarec64_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEX_vector(v0, 0, 0, VECTOR_SEW32);
|
||||
GETGX_empty_vector(v1);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
VMV_V_X(v2, x4); // 1.0f broadcast
|
||||
VFSQRT_V(v1, v0, VECTOR_UNMASKED);
|
||||
VFDIV_VV(v1, v2, v1, VECTOR_UNMASKED); // 1.0/sqrt(x)
|
||||
@@ -565,7 +565,7 @@ uintptr_t dynarec64_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEX_vector(v0, 0, 0, VECTOR_SEW32);
|
||||
GETGX_empty_vector(v1);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
VMV_V_X(v2, x4); // 1.0f broadcast
|
||||
VFDIV_VV(v1, v2, v0, VECTOR_UNMASKED); // 1.0/x
|
||||
break;
|
||||
|
||||
@@ -687,7 +687,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNEZ_MARK(x3);
|
||||
|
||||
ANDI(x3, ed, 0b10);
|
||||
LUI(x5, 0xffff0);
|
||||
MOV64x(x5, 0xFFFFFFFFFFFF0000);
|
||||
ZEXTH(x6, gd);
|
||||
BNEZ_MARK3(x3);
|
||||
|
||||
@@ -850,7 +850,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
POP1_16(x1);
|
||||
FLAGS_ADJUST_FROM11(x1, x1, x2);
|
||||
LUI(x2, 0xffff0);
|
||||
MOV64x(x2, 0xFFFFFFFFFFFF0000);
|
||||
AND(xFlags, xFlags, x2);
|
||||
OR(xFlags, xFlags, x1);
|
||||
MOV32w(x1, 0x3F7FF7);
|
||||
|
||||
@@ -304,7 +304,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ed = x4; \
|
||||
} \
|
||||
B##NO(x1, 4 + 3 * 4); \
|
||||
LUI(x3, 0xffff0); \
|
||||
MOV64x(x3, 0xFFFFFFFFFFFF0000); \
|
||||
AND(gd, gd, x3); \
|
||||
OR(gd, gd, ed);
|
||||
|
||||
@@ -466,7 +466,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SRLI(x3, x3, 29);
|
||||
MOV32w(x5, 0x007fffff);
|
||||
AND(x3, x3, x5);
|
||||
LUI(x5, 0x7fc00);
|
||||
MOV32w(x5, 0x7FC00000);
|
||||
OR(x3, x3, x5);
|
||||
OR(x3, x3, x4);
|
||||
FMVWX(d0, x3);
|
||||
@@ -490,7 +490,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FCVTLS(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000); // INT32_MIN
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -1580,7 +1580,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
LBU(x1, ed, fixedaddress);
|
||||
}
|
||||
LUI(x5, 0xffff0);
|
||||
MOV64x(x5, 0xFFFFFFFFFFFF0000);
|
||||
AND(gd, gd, x5);
|
||||
OR(gd, gd, x1);
|
||||
break;
|
||||
@@ -1842,7 +1842,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
LB(x1, ed, fixedaddress);
|
||||
}
|
||||
LUI(x5, 0xffff0);
|
||||
MOV64x(x5, 0xFFFFFFFFFFFF0000);
|
||||
AND(gd, gd, x5);
|
||||
ANDN(x1, x1, x5, x5);
|
||||
OR(gd, gd, x1);
|
||||
@@ -2104,7 +2104,7 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGDd;
|
||||
LD(x1, wback, fixedaddress + 8); // high part
|
||||
LD(x2, wback, fixedaddress + 0); // low part, also destroyed wback(x2)
|
||||
MOV64x(x5, 0x8080808080808080);
|
||||
MOV64xs(x5, 0x8080808080808080, x3);
|
||||
MOV64x(x6, 0x0002040810204081);
|
||||
AND(x2, x2, x5);
|
||||
MUL(x2, x2, x6);
|
||||
|
||||
@@ -144,9 +144,8 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
INST_NAME("PHADDSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// tmp32s = GX->sw[i*2+0]+GX->sw[i*2+1];
|
||||
// GX->sw[i] = sat(tmp32s);
|
||||
@@ -178,9 +177,8 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0, 15);
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LBU(x3, gback, gdoffset + i * 2);
|
||||
LB(x4, wback, fixedaddress + i * 2);
|
||||
@@ -255,9 +253,8 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
INST_NAME("PHSUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
LUI(x6, 0xFFFF8);
|
||||
LUI(x7, 0x8);
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LH(x3, gback, gdoffset + 2 * (i * 2 + 0));
|
||||
LH(x4, gback, gdoffset + 2 * (i * 2 + 1));
|
||||
@@ -536,8 +533,7 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
nextop = F8;
|
||||
GETGX();
|
||||
GETEX(x2, 0, 12);
|
||||
LUI(x5, 0x10); // 65536
|
||||
ADDIW(x5, x5, -1);
|
||||
MOV32w(x5, 0xFFFF);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LW(x3, gback, gdoffset + i * 4);
|
||||
SATUw(x3, x5);
|
||||
@@ -968,7 +964,7 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
SRLI(x1, x1, 8);
|
||||
OR(x1, x1, x2);
|
||||
}
|
||||
LUI(x2, 0xffff0);
|
||||
MOV64x(x2, 0xFFFFFFFFFFFF0000);
|
||||
AND(gd, gd, x2);
|
||||
OR(gd, gd, x1);
|
||||
break;
|
||||
@@ -1081,16 +1077,16 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
// i = 0
|
||||
FLD(d0, wback, fixedaddress);
|
||||
FEQD(x4, d0, d0);
|
||||
BNEZ(x4, BOX64ENV(dynarec_fastnan) ? 8 : (7 * 4));
|
||||
BNEZ_MARK3(x4);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
// sNaN -> qNaN, d0 |= (0x1 << 51)
|
||||
FMVXD(x3, d0);
|
||||
ADDI(x4, xZR, 1);
|
||||
SLLI(x4, x4, 51);
|
||||
MOV64x(x4, 1ULL << 51);
|
||||
OR(x3, x3, x4);
|
||||
FMVDX(d0, x3);
|
||||
}
|
||||
B_MARK_nocond;
|
||||
MARK3;
|
||||
// d0 is not nan
|
||||
FABSD(v1, d0);
|
||||
FLTD(x4, v1, d1);
|
||||
@@ -1118,16 +1114,16 @@ uintptr_t dynarec64_660F38(dynarec_rv64_t* dyn, uintptr_t addr, uint8_t opcode,
|
||||
// i = 1
|
||||
FLD(d0, wback, fixedaddress + 8);
|
||||
FEQD(x4, d0, d0);
|
||||
BNEZ(x4, BOX64ENV(dynarec_fastnan) ? 8 : (7 * 4));
|
||||
BNEZ_MARK4(x4);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
// sNaN -> qNaN, d0 |= (0x1 << 51)
|
||||
FMVXD(x3, d0);
|
||||
ADDI(x4, xZR, 1);
|
||||
SLLI(x4, x4, 51);
|
||||
MOV64x(x4, 1ULL << 51);
|
||||
OR(x3, x3, x4);
|
||||
FMVDX(d0, x3);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK4;
|
||||
|
||||
// d0 is not nan
|
||||
FABSD(v1, d0);
|
||||
|
||||
@@ -1778,7 +1778,7 @@ uintptr_t dynarec64_660F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
}
|
||||
} else {
|
||||
tmp64u0 = ((tmp64u0 >> 6) << 48) | (((tmp64u0 >> 4) & 3) << 32) | (((tmp64u0 >> 2) & 3) << 16) | (tmp64u0 & 3);
|
||||
VECTOR_SPLAT_IMM(v0, tmp64u0, x4);
|
||||
VECTOR_SPLAT_IMM_S(v0, tmp64u0, x4, x3);
|
||||
SET_ELEMENT_WIDTH(x1, VECTOR_SEW32, 1);
|
||||
if (q0 == q1) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -64,7 +64,7 @@ uintptr_t dynarec64_66F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
ZEROUP(gd);
|
||||
XOR(x5, x5, gd);
|
||||
SLLI(x5, x5, 48);
|
||||
MOV64x(x2, 0x4869EC38DEA713F1ULL);
|
||||
MOV64xs(x2, 0x4869EC38DEA713F1ULL, x3);
|
||||
CLMUL(x5, x5, x2);
|
||||
MOV64x(x2, 0x105EC76F1ULL);
|
||||
CLMULH(x5, x5, x2);
|
||||
|
||||
@@ -389,7 +389,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s1 = fpu_get_scratch(dyn); // 1.0f
|
||||
v0 = fpu_get_scratch(dyn); // 0.0f
|
||||
LUI(x3, 0x3f800);
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(s1, x3); // 1.0f
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FMVWX(v0, xZR);
|
||||
@@ -462,7 +462,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
GETGY();
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
LUI(x3, 0x3f800);
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(d0, x3); // 1.0f
|
||||
if (!BOX64ENV(dynarec_fastnan))
|
||||
MOV32w(x6, 0x00400000);
|
||||
|
||||
@@ -239,7 +239,7 @@ uintptr_t dynarec64_AVX_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t
|
||||
GETEY_vector(v1, 0, VECTOR_SEW32);
|
||||
GETGY_empty_vector(v0);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
VMV_V_X(v2, x4);
|
||||
VFSQRT_V(v0, v1, VECTOR_UNMASKED);
|
||||
VFDIV_VV(v0, v2, v0, VECTOR_UNMASKED);
|
||||
@@ -252,7 +252,7 @@ uintptr_t dynarec64_AVX_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t
|
||||
GETEY_vector(v1, 0, VECTOR_SEW32);
|
||||
GETGY_empty_vector(v0);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
VMV_V_X(v2, x4);
|
||||
VFDIV_VV(v0, v2, v1, VECTOR_UNMASKED);
|
||||
PUTGY_vector(v0, VECTOR_SEW32);
|
||||
@@ -516,7 +516,7 @@ uintptr_t dynarec64_AVX_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
MOV64x(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48));
|
||||
MOV64xs(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48), x3);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
if (vex.l) {
|
||||
VMV_V_X(q2, x4);
|
||||
|
||||
@@ -602,7 +602,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX();
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
if (!BOX64ENV(dynarec_fastnan)) LUI(x7, 0x7fc00);
|
||||
if (!BOX64ENV(dynarec_fastnan)) MOV32w(x7, 0x7FC00000);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
FLD(d0, wback, fixedaddress + i * 8);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
@@ -663,7 +663,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FCVTLS(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000); // INT32_MIN
|
||||
MOV64x(x3, (int64_t)INT32_MIN); // INT32_MIN
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
if (vex.l) {
|
||||
@@ -673,7 +673,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FCVTLS(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000); // INT32_MIN
|
||||
MOV64x(x3, (int64_t)INT32_MIN); // INT32_MIN
|
||||
SW(x3, gback, gyoffset + 4 * i);
|
||||
}
|
||||
} else
|
||||
@@ -1184,9 +1184,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGY();
|
||||
GETVX();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
if (gd == ed) {
|
||||
ADDI(x5, xEmu, offsetof(x64emu_t, scratch));
|
||||
LD(x3, wback, fixedaddress + 0);
|
||||
@@ -2537,7 +2536,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEX(x2, 0, vex.l ? 28 : 12);
|
||||
GETGD;
|
||||
MOV64x(x5, 0x8080808080808080);
|
||||
MOV64xs(x5, 0x8080808080808080, x3);
|
||||
MOV64x(x6, 0x0002040810204081);
|
||||
LD(x1, wback, fixedaddress + 0);
|
||||
AND(x1, x1, x5);
|
||||
@@ -3061,9 +3060,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGY();
|
||||
GETVX();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LH(x3, vback, vxoffset + i * 2);
|
||||
LH(x4, wback, fixedaddress + i * 2);
|
||||
@@ -3180,9 +3178,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGY();
|
||||
GETVX();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LH(x3, vback, vxoffset + i * 2);
|
||||
LH(x4, wback, fixedaddress + i * 2);
|
||||
@@ -3661,7 +3658,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
LWU(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
ORI(x5, x5, 1);
|
||||
SW(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
LUI(x3, 0x80000);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
if (vex.l) {
|
||||
@@ -3674,7 +3671,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
LWU(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
ORI(x5, x5, 1);
|
||||
SW(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
LUI(x3, 0x80000);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
SW(x3, gback, gdoffset + 8 + 4 * i);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -111,9 +111,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETVX();
|
||||
GETGY();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
if (gd == ed) {
|
||||
ADDI(x5, xEmu, offsetof(x64emu_t, scratch));
|
||||
LD(x3, wback, fixedaddress + 0);
|
||||
@@ -260,9 +259,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETVX();
|
||||
GETGY();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
LBU(x3, vback, vxoffset + i * 2);
|
||||
LB(x4, wback, fixedaddress + i * 2);
|
||||
@@ -302,9 +300,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETVX();
|
||||
GETGY();
|
||||
GETVY();
|
||||
LUI(x6, 0xFFFF8); // -32768
|
||||
LUI(x7, 0x8); // 32768
|
||||
ADDIW(x7, x7, -1);
|
||||
MOV64x(x6, -32768);
|
||||
MOV32w(x7, 0x7FFF);
|
||||
if (gd == ed) {
|
||||
ADDI(x5, xEmu, offsetof(x64emu_t, scratch));
|
||||
LD(x3, wback, fixedaddress + 0);
|
||||
@@ -1226,8 +1223,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETEX(x2, 0, vex.l ? 28 : 12);
|
||||
GETGX();
|
||||
GETGY();
|
||||
LUI(x5, 0x10); // 65536
|
||||
ADDIW(x5, x5, -1);
|
||||
MOV32w(x5, 0xFFFF);
|
||||
if (MODREG && ed == vex.v) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
LW(x3, vback, vxoffset + i * 4);
|
||||
|
||||
@@ -354,15 +354,15 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
MARK;
|
||||
FLD(d0, x1, 0);
|
||||
FEQD(x4, d0, d0);
|
||||
BNEZ(x4, BOX64ENV(dynarec_fastnan) ? 8 : (7 * 4));
|
||||
BNEZ_MARK3(x4);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FMVXD(x3, d0);
|
||||
ADDI(x4, xZR, 1);
|
||||
SLLI(x4, x4, 51);
|
||||
MOV64x(x4, 1ULL << 51);
|
||||
OR(x3, x3, x4);
|
||||
FMVDX(d0, x3);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK3;
|
||||
FABSD(v1, d0);
|
||||
FLTD(x4, v1, d1);
|
||||
BNEZ(x4, 8);
|
||||
|
||||
@@ -66,7 +66,7 @@ uintptr_t dynarec64_AVX_66_0F3A_vector(dynarec_rv64_t* dyn, uintptr_t addr, uint
|
||||
iota |= ((uint64_t)((u8 >> 4) & 3)) << 32;
|
||||
iota |= ((uint64_t)((u8 >> 6) & 3)) << 48;
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, vex.l ? 2 : 1);
|
||||
VECTOR_SPLAT_IMM(q2, iota, x4);
|
||||
VECTOR_SPLAT_IMM_S(q2, iota, x4, x3);
|
||||
}
|
||||
if (v0 == q0 || v0 == q2) {
|
||||
VRGATHEREI16_VV(q1, q0, q2, VECTOR_UNMASKED);
|
||||
@@ -94,7 +94,7 @@ uintptr_t dynarec64_AVX_66_0F3A_vector(dynarec_rv64_t* dyn, uintptr_t addr, uint
|
||||
u8 = F8;
|
||||
VEC_SRC_KEEP(q0, v0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
MOV64x(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48));
|
||||
MOV64xs(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48), x3);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
if (vex.l) {
|
||||
VMV_V_X(q1, x4);
|
||||
@@ -118,6 +118,7 @@ uintptr_t dynarec64_AVX_66_0F3A_vector(dynarec_rv64_t* dyn, uintptr_t addr, uint
|
||||
VEC_SRC_KEEP(q0, v0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
MOV64x(x4, (uint64_t)(u8 & 1) | ((uint64_t)((u8 >> 1) & 1) << 16) | ((uint64_t)(((u8 >> 2) & 1) + 2) << 32) | ((uint64_t)(((u8 >> 3) & 1) + 2) << 48));
|
||||
MOV64xs(x4, (uint64_t)(u8 & 1) | ((uint64_t)((u8 >> 1) & 1) << 16) | ((uint64_t)(((u8 >> 2) & 1) + 2) << 32) | ((uint64_t)(((u8 >> 3) & 1) + 2) << 48), x3);
|
||||
VMV_S_X(q1, x4);
|
||||
VRGATHEREI16_VV(v0, q0, q1, VECTOR_UNMASKED);
|
||||
PUTGY_vector(v0, VECTOR_SEW64);
|
||||
|
||||
@@ -579,10 +579,7 @@ uintptr_t dynarec64_AVX_66_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
uint32_t sel_lo = (u8 & 3) | (((u8 >> 2) & 3) << 16);
|
||||
uint32_t sel_hi = ((u8 >> 4) & 3) | (((u8 >> 6) & 3) << 16);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
MOV32w(x4, sel_hi);
|
||||
SLLI(x4, x4, 32);
|
||||
MOV32w(x5, sel_lo);
|
||||
OR(x4, x4, x5); // x4 = lane0 selector (64-bit,4 halfword indices)
|
||||
MOV64x(x4, ((uint64_t)sel_hi << 32) | sel_lo);
|
||||
if (vex.l) {
|
||||
int s = fpu_get_scratch(dyn);
|
||||
MOV64x(x5, 0x0004000400040004LL);
|
||||
@@ -1370,7 +1367,7 @@ uintptr_t dynarec64_AVX_66_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
selectors = 0;
|
||||
for (int i = 0; i < (2 << vex.l); ++i)
|
||||
selectors |= (uint64_t)((i >> 1) * 2 + ((u8 >> i) & 1)) << (i * 16);
|
||||
MOV64x(x4, selectors);
|
||||
MOV64xs(x4, selectors, x3);
|
||||
SET_AVX_VECTOR_WIDTH(x1, VECTOR_SEW64);
|
||||
VMV_V_X(v1, x4);
|
||||
VRGATHEREI16_VV(q2, q0, v1, VECTOR_UNMASKED);
|
||||
|
||||
@@ -404,7 +404,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
SRLI(x4, x4, 29);
|
||||
MOV32w(x5, 0x007fffff);
|
||||
AND(x4, x4, x5);
|
||||
LUI(x5, 0x7fc00);
|
||||
MOV32w(x5, 0x7FC00000);
|
||||
OR(x4, x4, x5);
|
||||
OR(x4, x4, x6);
|
||||
FMVWX(v0, x4);
|
||||
@@ -932,7 +932,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FCVTLD(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
if (vex.l) {
|
||||
@@ -942,7 +942,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FCVTLD(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
SW(x3, gback, gdoffset + 8 + 4 * i);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -162,7 +162,7 @@ uintptr_t dynarec64_AVX_F2_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
SRLI(x4, x4, 29);
|
||||
MOV32w(x5, 0x007fffff);
|
||||
AND(x4, x4, x5);
|
||||
LUI(x5, 0x7fc00);
|
||||
MOV32w(x5, 0x7FC00000);
|
||||
OR(x4, x4, x5);
|
||||
OR(x4, x4, x6);
|
||||
FMVWX(d1, x4);
|
||||
@@ -247,7 +247,7 @@ uintptr_t dynarec64_AVX_F2_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
u8 = F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
MOV64x(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48));
|
||||
MOV64xs(x4, (uint64_t)(u8 & 3) | ((uint64_t)((u8 >> 2) & 3) << 16) | ((uint64_t)((u8 >> 4) & 3) << 32) | ((uint64_t)((u8 >> 6) & 3) << 48), x3);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
VMV_V_X(q0, x4);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW16, VECTOR_LMUL1, 1);
|
||||
|
||||
@@ -377,7 +377,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FRFLAGS(x5);
|
||||
ANDI(x5, x5, (1 << FR_NV) | (1 << FR_OF));
|
||||
BEQZ(x5, 4 + 4);
|
||||
LUI(x3, 0x80000000 >> 12);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
}
|
||||
SW(x3, gback, gdoffset + i * 4);
|
||||
}
|
||||
@@ -393,7 +393,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FRFLAGS(x5);
|
||||
ANDI(x5, x5, (1 << FR_NV) | (1 << FR_OF));
|
||||
BEQZ(x5, 4 + 4);
|
||||
LUI(x3, 0x80000000 >> 12);
|
||||
MOV64x(x3, (int64_t)INT32_MIN);
|
||||
}
|
||||
SW(x3, gback, gyoffset + i * 4);
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ uintptr_t dynarec64_AVX_F3_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
u8 = F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
MOV64x(x4, (uint64_t)(4 + (u8 & 3)) | ((uint64_t)(4 + ((u8 >> 2) & 3)) << 16) | ((uint64_t)(4 + ((u8 >> 4) & 3)) << 32) | ((uint64_t)(4 + ((u8 >> 6) & 3)) << 48));
|
||||
MOV64xs(x4, (uint64_t)(4 + (u8 & 3)) | ((uint64_t)(4 + ((u8 >> 2) & 3)) << 16) | ((uint64_t)(4 + ((u8 >> 4) & 3)) << 32) | ((uint64_t)(4 + ((u8 >> 6) & 3)) << 48), x3);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
VMV_V_X(q0, x4);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW16, VECTOR_LMUL1, 1);
|
||||
|
||||
@@ -148,7 +148,7 @@ uintptr_t dynarec64_D9(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (i2 >= 0) {
|
||||
LHU(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if (i2 > 0) {
|
||||
LUI(x5, 0xffff0);
|
||||
MOV64x(x5, 0xFFFFFFFFFFFF0000);
|
||||
OR(x3, x3, x5);
|
||||
SRLI(x3, x3, i2 * 2);
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ZEROUP(gd);
|
||||
XOR(x5, x5, gd);
|
||||
SLLI(x5, x5, 56);
|
||||
MOV64x(x2, 0x4869EC38DEA713F1ULL);
|
||||
MOV64xs(x2, 0x4869EC38DEA713F1ULL, x3);
|
||||
CLMUL(x5, x5, x2);
|
||||
MOV64x(x2, 0x105EC76F1ULL);
|
||||
CLMULH(x5, x5, x2);
|
||||
@@ -188,7 +188,7 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ZEROUP(gd);
|
||||
XOR(x5, x5, gd);
|
||||
if (!rex.w) SLLI(x5, x5, 32);
|
||||
MOV64x(x2, 0x4869EC38DEA713F1ULL);
|
||||
MOV64xs(x2, 0x4869EC38DEA713F1ULL, x3);
|
||||
CLMUL(x5, x5, x2);
|
||||
MOV64x(x2, 0x105EC76F1ULL);
|
||||
CLMULH(x5, x5, x2);
|
||||
@@ -323,7 +323,7 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SRLI(x4, x4, 29);
|
||||
MOV32w(x5, 0x007fffff);
|
||||
AND(x4, x4, x5);
|
||||
LUI(x5, 0x7fc00);
|
||||
MOV32w(x5, 0x7FC00000);
|
||||
OR(x4, x4, x5);
|
||||
OR(x4, x4, x6);
|
||||
FMVWX(v0, x4);
|
||||
@@ -773,7 +773,7 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FCVTLD(x3, d0, RD_DYN);
|
||||
SEXT_W(x5, x3);
|
||||
BEQ(x5, x3, 8);
|
||||
LUI(x3, 0x80000); // INT32_MIN
|
||||
MOV64x(x3, (int64_t)INT32_MIN); // INT32_MIN
|
||||
SW(x3, gback, gdoffset + 4 * i);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -435,10 +435,10 @@ uintptr_t dynarec64_F20F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
tmp64u0 = 0x0007000600050004ULL;
|
||||
MOV64x(x5, tmp64u0);
|
||||
MOV64xs(x5, tmp64u0, x3);
|
||||
VMV_S_X(d1, x5);
|
||||
tmp64u0 = ((((uint64_t)u8 >> 6) & 3) << 48) | ((((uint64_t)u8 >> 4) & 3) << 32) | (((u8 >> 2) & 3) << 16) | (u8 & 3);
|
||||
MOV64x(x5, tmp64u0);
|
||||
MOV64xs(x5, tmp64u0, x3);
|
||||
VSLIDE1UP_VX_SAFE(d0, d1, x5, VECTOR_UNMASKED);
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW16, VECTOR_LMUL1, 1);
|
||||
if (v0 == v1) {
|
||||
|
||||
@@ -223,7 +223,7 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FEQS(x5, v1, v1);
|
||||
BNEZ_MARK(x5);
|
||||
BNEZ_MARK2(x4);
|
||||
LUI(x5, 0x00400);
|
||||
MOV32w(x5, 0x400000);
|
||||
OR(x3, x3, x5);
|
||||
FMVWX(v1, x3);
|
||||
B_MARK_nocond;
|
||||
@@ -239,7 +239,7 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGXSS_empty(v1);
|
||||
q0 = fpu_get_scratch(dyn); // 1.0f
|
||||
d0 = fpu_get_scratch(dyn); // 0.0f
|
||||
LUI(x3, 0x3F800); // 1.0f
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(q0, x3);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
MOV32w(x6, 0x00400000);
|
||||
@@ -273,7 +273,7 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEXSS(v0, 0);
|
||||
GETGXSS_empty(v1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
LUI(x3, 0x3F800); // 1.0f
|
||||
MOV32w(x3, 0x3F800000);
|
||||
FMVWX(q0, x3);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
MOV32w(x6, 0x00400000);
|
||||
@@ -628,22 +628,14 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
CPOPxw(gd, ed);
|
||||
} else {
|
||||
if (rex.w) {
|
||||
// x7 = 0x5555555555555555
|
||||
LUI(x7, 0x55555);
|
||||
ADDIW(x7, x7, 0x555);
|
||||
SLLI(x6, x7, 32);
|
||||
ADD(x7, x7, x6);
|
||||
MOV64xs(x7, 0x5555555555555555ULL, x6);
|
||||
|
||||
// v = v - ((v >> 1) & x7)
|
||||
SRLI(x5, ed, 1);
|
||||
AND(x5, x5, x7);
|
||||
SUB(x5, ed, x5);
|
||||
|
||||
// x3 = 0x3333333333333333
|
||||
LUI(x3, 0x33333);
|
||||
ADDIW(x3, x3, 0x333);
|
||||
SLLI(x6, x3, 32);
|
||||
ADD(x3, x3, x6);
|
||||
MOV64xs(x3, 0x3333333333333333ULL, x6);
|
||||
|
||||
// v = (v & x3) + ((v >> 2) & x3);
|
||||
SRLI(x7, x5, 2);
|
||||
@@ -651,39 +643,27 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
AND(x5, x5, x3);
|
||||
ADD(x5, x5, x7);
|
||||
|
||||
// x3 = 0x0F0F0F0F0F0F0F0F
|
||||
LUI(x3, 0xF0F1);
|
||||
ADDIW(x3, x3, 0xF0F);
|
||||
SLLI(x6, x3, 32);
|
||||
ADD(x3, x3, x6);
|
||||
MOV64xs(x3, 0x0F0F0F0F0F0F0F0FULL, x6);
|
||||
|
||||
// v = (v + (v >> 4) & x3)
|
||||
SRLI(x7, x5, 4);
|
||||
ADD(x5, x5, x7);
|
||||
AND(x5, x5, x3);
|
||||
|
||||
// x3 = 0x0101010101010101
|
||||
LUI(x3, 0x1010);
|
||||
ADDIW(x3, x3, 0x101);
|
||||
SLLI(x6, x3, 32);
|
||||
ADD(x3, x3, x6);
|
||||
MOV64xs(x3, 0x0101010101010101ULL, x6);
|
||||
|
||||
// count = (v * x3) >> 56
|
||||
MUL(gd, x5, x3);
|
||||
SRLI(gd, gd, 56);
|
||||
} else {
|
||||
// x7 = 0x55555555uLL
|
||||
LUI(x7, 0x55555);
|
||||
ADDIW(x7, x7, 0x555);
|
||||
MOV32w(x7, 0x55555555);
|
||||
|
||||
// v = v - ((v >> 1) & x7)
|
||||
SRLI(x5, ed, 1);
|
||||
AND(x5, x5, x7);
|
||||
SUB(x5, ed, x5);
|
||||
|
||||
// x3 = 0x33333333uLL
|
||||
LUI(x3, 0x33333);
|
||||
ADDIW(x3, x3, 0x333);
|
||||
MOV32w(x3, 0x33333333);
|
||||
|
||||
// v = (v & x3) + ((v >> 2) & x3);
|
||||
SRLI(x7, x5, 2);
|
||||
@@ -691,18 +671,14 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
AND(x5, x5, x3);
|
||||
ADD(x5, x5, x7);
|
||||
|
||||
// x3 = 0x0F0F0F0FuLL
|
||||
LUI(x3, 0xF0F1);
|
||||
ADDIW(x3, x3, 0xF0F);
|
||||
MOV32w(x3, 0x0F0F0F0F);
|
||||
|
||||
// v = (v + (v >> 4) & x3)
|
||||
SRLI(x7, x5, 4);
|
||||
ADD(x5, x5, x7);
|
||||
AND(x5, x5, x3);
|
||||
|
||||
// x3 = 01010101uLL
|
||||
LUI(x3, 0x1010);
|
||||
ADDIW(x3, x3, 0x101);
|
||||
MOV32w(x3, 0x01010101);
|
||||
|
||||
// count = (v * x3) >> 24
|
||||
MULW(gd, x5, x3);
|
||||
|
||||
@@ -251,7 +251,7 @@ uintptr_t dynarec64_F30F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VMV_S_X(v1, x4);
|
||||
GETGX_vector(v0, 1, VECTOR_SEW32);
|
||||
}
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
FMVWX(v1, x4); // 1.0f
|
||||
SET_SCALAR_FP_WIDTH(x1, VECTOR_SEW32);
|
||||
VFSQRT_V(v0, v1, VECTOR_UNMASKED);
|
||||
@@ -273,7 +273,7 @@ uintptr_t dynarec64_F30F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VMV_S_X(v1, x4);
|
||||
GETGX_vector(v0, 1, VECTOR_SEW32);
|
||||
}
|
||||
LUI(x4, 0x3f800);
|
||||
MOV32w(x4, 0x3F800000);
|
||||
FMVWX(v1, x4); // 1.0f
|
||||
VECTOR_LOAD_VMASK(0b0001, x4, 1);
|
||||
VFRDIV_VF(v0, v1, v1, VECTOR_MASKED);
|
||||
@@ -491,7 +491,7 @@ uintptr_t dynarec64_F30F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
vector_vsetvli(dyn, ninst, x1, VECTOR_SEW64, VECTOR_LMUL1, 1);
|
||||
tmp64u0 = ((((uint64_t)u8 >> 6) & 3) << 48) | ((((uint64_t)u8 >> 4) & 3) << 32) | (((u8 >> 2) & 3) << 16) | (u8 & 3);
|
||||
tmp64u0 += 0x0004000400040004ULL;
|
||||
MOV64x(x5, tmp64u0);
|
||||
MOV64xs(x5, tmp64u0, x3);
|
||||
VMV_S_X(d1, x5);
|
||||
tmp64u0 = 0x0003000200010000ULL;
|
||||
MOV64x(x5, tmp64u0);
|
||||
|
||||
@@ -25,6 +25,23 @@
|
||||
#include "dynarec_rv64_private.h"
|
||||
#include "dynarec_rv64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "rv64_mov_imm.h"
|
||||
|
||||
typedef struct rv64_mov_dynctx_s {
|
||||
dynarec_rv64_t* dyn;
|
||||
int ninst;
|
||||
} rv64_mov_dynctx_t;
|
||||
|
||||
static void rv64_mov_emit_word(void* p, uint32_t insn)
|
||||
{
|
||||
rv64_mov_dynctx_t* c = (rv64_mov_dynctx_t*)p;
|
||||
dynarec_rv64_t* dyn = c->dyn;
|
||||
int ninst = c->ninst;
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(insn);
|
||||
EMIT(insn);
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, uint8_t scratch, int64_t* fixaddress, rex_t rex, int* l, int i12, int delta)
|
||||
@@ -918,7 +935,7 @@ void x87_purgecache(dynarec_rv64_t* dyn, int ninst, int next, int s1, int s2, in
|
||||
if (a > 0) {
|
||||
SLLI(s1, s1, a * 2);
|
||||
} else {
|
||||
LUI(s3, 0xffff0);
|
||||
MOV64x(s3, 0xFFFFFFFFFFFF0000);
|
||||
OR(s1, s1, s3);
|
||||
SRLI(s1, s1, -a * 2);
|
||||
}
|
||||
@@ -2781,55 +2798,72 @@ void CacheTransform(dynarec_rv64_t* dyn, int ninst, int cacheupd, int s1, int s2
|
||||
}
|
||||
|
||||
|
||||
void rv64_move32(dynarec_rv64_t* dyn, int ninst, int reg, int32_t val, int zeroup)
|
||||
void rv64_move32(dynarec_rv64_t* dyn, int ninst, int reg, int32_t val)
|
||||
{
|
||||
// Depending on val, the following insts are emitted.
|
||||
// val == 0 -> ADDI
|
||||
// lo12 != 0 && hi20 == 0 -> ADDI
|
||||
// lo12 == 0 && hi20 != 0 -> LUI
|
||||
// else -> LUI+ADDI
|
||||
int32_t hi20 = (val + 0x800) >> 12 & 0xfffff;
|
||||
int32_t lo12 = val & 0xfff;
|
||||
#if STEP == 1
|
||||
(void)dyn;
|
||||
(void)ninst;
|
||||
(void)reg;
|
||||
(void)val;
|
||||
return;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
(void)ninst;
|
||||
(void)reg;
|
||||
(void)val;
|
||||
for (int i = 0; i < RV64_MOV_MAXOPS; ++i)
|
||||
EMIT(0);
|
||||
return;
|
||||
#endif
|
||||
rv64_mov_seq_t seq;
|
||||
rv64_mov_dynctx_t ec = { dyn, ninst };
|
||||
|
||||
int src = xZR;
|
||||
if (hi20) {
|
||||
LUI(reg, hi20);
|
||||
src = reg;
|
||||
if (rv64_mov_cache_get((uint64_t)(uint32_t)val, 0, 1, &seq)) {
|
||||
rv64_mov_emit_seq(reg, -1, -1, &seq, rv64_mov_emit_word, &ec);
|
||||
return;
|
||||
}
|
||||
if (lo12 || !hi20) ADDIW(reg, src, lo12);
|
||||
if (zeroup && (val & 0x80000000)) {
|
||||
ZEROUP(reg);
|
||||
|
||||
rv64_movctx_t ctx = { { cpuext.zba, cpuext.zbs, cpuext.zbb }, RV64_MOV_BUDGET };
|
||||
if (rv64_mov_seq32(&ctx, (uint32_t)val, 0, &seq)) {
|
||||
rv64_mov_cache_put((uint64_t)(uint32_t)val, 0, 1, &seq);
|
||||
rv64_mov_emit_seq(reg, -1, -1, &seq, rv64_mov_emit_word, &ec);
|
||||
}
|
||||
}
|
||||
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val)
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val, int s1, int s2)
|
||||
{
|
||||
uint64_t uval = (uint64_t)val;
|
||||
if (cpuext.zbs && uval && !(uval & (uval - 1))) {
|
||||
BSETI_(reg, xZR, TrailingZeros64(uval));
|
||||
#if STEP == 1
|
||||
(void)dyn;
|
||||
(void)ninst;
|
||||
(void)reg;
|
||||
(void)val;
|
||||
(void)s1;
|
||||
(void)s2;
|
||||
return;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
(void)ninst;
|
||||
(void)reg;
|
||||
(void)val;
|
||||
(void)s1;
|
||||
(void)s2;
|
||||
for (int i = 0; i < RV64_MOV_MAXOPS; ++i)
|
||||
EMIT(0);
|
||||
return;
|
||||
#endif
|
||||
rv64_mov_seq_t seq;
|
||||
rv64_mov_dynctx_t ec = { dyn, ninst };
|
||||
int nscratch = (s1 >= 0) + (s2 >= 0);
|
||||
|
||||
if (rv64_mov_cache_get((uint64_t)val, nscratch, 0, &seq)) {
|
||||
rv64_mov_emit_seq(reg, s1, s2, &seq, rv64_mov_emit_word, &ec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (((val << 32) >> 32) == val) {
|
||||
// 32bits value
|
||||
rv64_move32(dyn, ninst, reg, val, 0);
|
||||
return;
|
||||
}
|
||||
if (!(uval & (uval + 1))) {
|
||||
ADDI(reg, xZR, -1);
|
||||
SRLI(reg, reg, 64 - TrailingZeros64(~uval));
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t lo12 = (val << 52) >> 52;
|
||||
int64_t hi52 = (val + 0x800) >> 12;
|
||||
int shift = 12 + TrailingZeros64((uint64_t)hi52);
|
||||
hi52 = ((hi52 >> (shift - 12)) << shift) >> shift;
|
||||
rv64_move64(dyn, ninst, reg, hi52);
|
||||
SLLI(reg, reg, shift);
|
||||
|
||||
if (lo12) {
|
||||
ADDI(reg, reg, lo12);
|
||||
rv64_movctx_t ctx = { { cpuext.zba, cpuext.zbs, cpuext.zbb }, RV64_MOV_BUDGET };
|
||||
if (rv64_mov_seq64(&ctx, (uint64_t)val, 0, nscratch, &seq)) {
|
||||
rv64_mov_cache_put((uint64_t)val, nscratch, 0, &seq);
|
||||
rv64_mov_emit_seq(reg, s1, s2, &seq, rv64_mov_emit_word, &ec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -979,6 +979,8 @@
|
||||
#define GETMARK2 GETMARKi(1)
|
||||
#define MARK3 MARKi(2)
|
||||
#define GETMARK3 GETMARKi(2)
|
||||
#define MARK4 MARKi(3)
|
||||
#define GETMARK4 GETMARKi(3)
|
||||
|
||||
#define MARKFi(i) dyn->insts[ninst].markf[i] = dyn->native_size
|
||||
#define GETMARKFi(i) dyn->insts[ninst].markf[i]
|
||||
@@ -1054,6 +1056,12 @@
|
||||
#define BEQZ_MARK2(reg) BEQ_MARK2(reg, xZR)
|
||||
// Branch to MARK3 if reg1==0 (use j64)
|
||||
#define BEQZ_MARK3(reg) BEQ_MARK3(reg, xZR)
|
||||
// Branch to MARK4 if reg1!=reg2 (use j64)
|
||||
#define BNE_MARK4(reg1, reg2) Bxx_gen(NE, MARK4, reg1, reg2)
|
||||
// Branch to MARK4 if reg1!=0 (use j64)
|
||||
#define BNEZ_MARK4(reg) BNE_MARK4(reg, xZR)
|
||||
// Branch to MARK4 instruction unconditionnal (use j64)
|
||||
#define B_MARK4_nocond Bxx_gen(__, MARK4, 0, 0)
|
||||
// Branch to MARK3 instruction unconditionnal (use j64)
|
||||
#define B_MARK3_nocond Bxx_gen(__, MARK3, 0, 0)
|
||||
// Branch to MARKLOCK if reg1!=reg2 (use j64)
|
||||
@@ -1250,7 +1258,7 @@
|
||||
SLLI(xs, xs, 41); \
|
||||
SRLI(xs, xs, 41); \
|
||||
OR(xs, xs, xt); \
|
||||
LUI(xt, 0x7fc00); \
|
||||
MOV32w(xt, 0x7FC00000); \
|
||||
OR(xs, xs, xt); \
|
||||
FMVWX(d, xs)
|
||||
#endif
|
||||
@@ -1400,8 +1408,7 @@
|
||||
|
||||
// Adjust the xFlags bit 5 -> bit 11, src and dst can be the same (and can be xFlags, but not s1)
|
||||
#define FLAGS_ADJUST_TO11(dst, src, s1) \
|
||||
LUI(s1, 0xFFFFF); \
|
||||
ADDIW(s1, s1, 0x7DF); \
|
||||
MOV64x(s1, 0xFFFFFFFFFFFFF7DF); \
|
||||
AND(s1, src, s1); \
|
||||
ANDI(dst, src, 1 << 5); \
|
||||
SLLI(dst, dst, 11 - 5); \
|
||||
@@ -2184,8 +2191,8 @@ int sse_setround(dynarec_rv64_t* dyn, int ninst, int s1, int s2);
|
||||
|
||||
void CacheTransform(dynarec_rv64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val);
|
||||
void rv64_move32(dynarec_rv64_t* dyn, int ninst, int reg, int32_t val, int zeroup);
|
||||
void rv64_move64(dynarec_rv64_t* dyn, int ninst, int reg, int64_t val, int s1, int s2);
|
||||
void rv64_move32(dynarec_rv64_t* dyn, int ninst, int reg, int32_t val);
|
||||
|
||||
int vector_vsetvli(dynarec_rv64_t* dyn, int ninst, int s1, int sew, int vlmul, float multiple);
|
||||
void vector_loadmask(dynarec_rv64_t* dyn, int ninst, int vreg, uint64_t imm, int s1, float multiple);
|
||||
@@ -2526,11 +2533,10 @@ uintptr_t dynarec64_AVX_F3_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
SLLI(s1, s2, 8); \
|
||||
J(20); /* end */ \
|
||||
/* undefined/NaN */ \
|
||||
LUI(s1, 4); \
|
||||
ADDI(s1, s1, 0b010100000000); \
|
||||
MOV32w(s1, 0x4500); \
|
||||
J(8); /* end */ \
|
||||
/* equal */ \
|
||||
LUI(s1, 4); \
|
||||
MOV32w(s1, 0x4000); \
|
||||
/* end */ \
|
||||
OR(s3, s3, s1); \
|
||||
SH(s3, xEmu, offsetof(x64emu_t, sw));
|
||||
@@ -2672,6 +2678,18 @@ uintptr_t dynarec64_AVX_F3_0F_vector(dynarec_rv64_t* dyn, uintptr_t addr, uintpt
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VECTOR_SPLAT_IMM_S(vreg, imm, s1, s2) \
|
||||
do { \
|
||||
if (imm == 0) { \
|
||||
VXOR_VV(vreg, vreg, vreg, VECTOR_UNMASKED); \
|
||||
} else if ((imm & 0xf) == imm) { \
|
||||
VMV_V_I(vreg, imm); \
|
||||
} else { \
|
||||
MOV64xs(s1, imm, s2); \
|
||||
VMV_V_X(vreg, s1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VECTOR_LOAD_VMASK(mask, s1, multiple) \
|
||||
vector_loadmask(dyn, ninst, VMASK, mask, s1, multiple)
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#define SPLIT12(A) ((A) & 0xfff)
|
||||
|
||||
// MOV64x/MOV32w is quite complex, so use a function for this
|
||||
#define MOV64x(A, B) rv64_move64(dyn, ninst, A, B)
|
||||
#define MOV32w(A, B) rv64_move32(dyn, ninst, A, B, 1)
|
||||
#define MOV64x(A, B) rv64_move64(dyn, ninst, A, B, -1, -1)
|
||||
#define MOV64xs(A, B, S1) rv64_move64(dyn, ninst, A, B, S1, -1)
|
||||
#define MOV64xss(A, B, S1, S2) rv64_move64(dyn, ninst, A, B, S1, S2)
|
||||
#define MOV32w(A, B) rv64_move32(dyn, ninst, A, (int32_t)(B))
|
||||
#define MOV64xw(A, B) \
|
||||
do { \
|
||||
if (rex.w) { \
|
||||
@@ -1201,14 +1203,14 @@
|
||||
}
|
||||
|
||||
// Insert low 16bits in rs to low 16bits of rd
|
||||
#define INSH(rd, rs, s1, s2, init_s1, zexth_rs) \
|
||||
if (init_s1) LUI(s1, 0xffff0); \
|
||||
AND(rd, rd, s1); \
|
||||
if (zexth_rs) { \
|
||||
ZEXTH(s2, rs); \
|
||||
OR(rd, rd, s2); \
|
||||
} else { \
|
||||
OR(rd, rd, rs); \
|
||||
#define INSH(rd, rs, s1, s2, init_s1, zexth_rs) \
|
||||
if (init_s1) MOV64x(s1, 0xFFFFFFFFFFFF0000); \
|
||||
AND(rd, rd, s1); \
|
||||
if (zexth_rs) { \
|
||||
ZEXTH(s2, rs); \
|
||||
OR(rd, rd, s2); \
|
||||
} else { \
|
||||
OR(rd, rd, rs); \
|
||||
}
|
||||
|
||||
// Insert low 16bits in rs to low 16bits of rd
|
||||
@@ -1291,7 +1293,7 @@
|
||||
OR(s1, s1, s3); \
|
||||
OR(s1, s1, s4); \
|
||||
SLLIW(s3, rs, 8); \
|
||||
LUI(s2, 0xff0); \
|
||||
MOV32w(s2, 0xFF0000); \
|
||||
AND(s3, s3, s2); \
|
||||
OR(rd, s1, s3); \
|
||||
} \
|
||||
@@ -1327,15 +1329,14 @@
|
||||
// Single-bit Set (Immediate)
|
||||
#define BSETI_(rd, rs1, imm) EMIT(R_type(0b0010100, imm, rs1, 0b001, rd, 0b0010011))
|
||||
// Single-bit Set (Immediate), with fallback (s0 is used as a scratch register)
|
||||
#define BSETI(rd, rs1, imm, s0) \
|
||||
do { \
|
||||
if (cpuext.zbs) \
|
||||
BSETI_(rd, rs1, imm); \
|
||||
else { \
|
||||
ADDI(s0, xZR, 1); \
|
||||
SLLI(s0, s0, (imm)); \
|
||||
OR(rd, rs1, s0); \
|
||||
} \
|
||||
#define BSETI(rd, rs1, imm, s0) \
|
||||
do { \
|
||||
if (cpuext.zbs) \
|
||||
BSETI_(rd, rs1, imm); \
|
||||
else { \
|
||||
MOV64x(s0, 1ULL << (imm)); \
|
||||
OR(rd, rs1, s0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Single-bit Extract (Register)
|
||||
|
||||
@@ -0,0 +1,746 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
* 1. rv64_mov_seq64() and rv64_mov_seq32()
|
||||
*
|
||||
* These two functions try a number of standard tricks and keep the best result.
|
||||
* "Best" means the fewest instructions; if two results use the same number of instructions,
|
||||
* the one with the shorter dependency chain wins, because it has less latency.
|
||||
*
|
||||
* Some of the tricks are:
|
||||
* - single ADDI for values that fit in 12 signed bits
|
||||
* - LUI + ADDIW for ordinary 32-bit values
|
||||
* - BSETI when only one or a few bits are set
|
||||
* - building -1 and shifting it for simple masks
|
||||
* - shifting the value, building the shifted value and shifting it back
|
||||
* - splitting the value into a low half and a high half, building each half and joining them with a shift and an ADD
|
||||
* - optional Zba / Zbs / Zbb instructions (SH1ADD, BCLRI, RORI, SLLIUW, ...) when the CPU has those extensions
|
||||
*
|
||||
* Some tricks build the value in pieces:
|
||||
* they ask for a sequence for a sub-value and then add the instruction that joins the pieces together.
|
||||
* The expensive recursive candidates stop at RV64_MOV_MAXDEPTH (currently 2), RV64_MOV_BUDGET caps the total work,
|
||||
* and rv64_mov_min_ops64() skips branches that cannot improve the best result.
|
||||
*
|
||||
* 2. rv64_mov_emit_seq()
|
||||
*
|
||||
* This is the emitter, it turns the list that step 1 returns into real RISC-V instructions,
|
||||
* using the destination register and the scratch registers that the caller provided.
|
||||
*
|
||||
* 3. rv64_mov_cache_get() and rv64_mov_cache_put()
|
||||
*
|
||||
* A small per-thread cache table remembers up to 1024 answers.
|
||||
* An entry is identified by the value, the number of scratch registers used and whether this is a 32-bit or a 64-bit move.
|
||||
* Very long sequences (more than 8 steps) are not cached.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rv64_mov_imm.h"
|
||||
#include "rv64_emitter.h"
|
||||
|
||||
static int rv64_mov_ctz64(uint64_t x) { return x ? __builtin_ctzll(x) : 64; }
|
||||
static int rv64_mov_clz64(uint64_t x) { return x ? __builtin_clzll(x) : 64; }
|
||||
static int rv64_mov_popcnt64(uint64_t x) { return __builtin_popcountll(x); }
|
||||
|
||||
static int32_t rv64_mov_sext12(uint32_t x) { return (int32_t)(((x & 0xfffu) ^ 0x800u) - 0x800u); }
|
||||
|
||||
static int rv64_mov_fits12(uint64_t v)
|
||||
{
|
||||
int64_t s = (int64_t)v;
|
||||
return s >= -2048 && s <= 2047;
|
||||
}
|
||||
|
||||
static int rv64_mov_fits32(uint64_t v)
|
||||
{
|
||||
int64_t s = (int64_t)v;
|
||||
return s >= -0x80000000LL && s <= 0x7fffffffLL;
|
||||
}
|
||||
|
||||
static int rv64_mov_min_ops64(const rv64_movctx_t* ctx, uint64_t v)
|
||||
{
|
||||
if (rv64_mov_fits12(v)) return 1;
|
||||
if (ctx->caps.zbs && v && !(v & (v - 1))) return 1;
|
||||
if (rv64_mov_fits32(v) && !(v & 0xfff)) return 1;
|
||||
if (v && !(v & (v + 1))) return 2;
|
||||
if (ctx->caps.zbs) {
|
||||
int c = rv64_mov_popcnt64(v);
|
||||
if (c && c <= 4) return c;
|
||||
int z = rv64_mov_popcnt64(~v);
|
||||
if (z && z <= 3) return 1 + z;
|
||||
}
|
||||
if (rv64_mov_fits32(v)) return 2;
|
||||
int t = rv64_mov_ctz64(v);
|
||||
if (v && t > 0 && (v >> t) == (~UINT64_C(0) >> t)) return 2;
|
||||
if (v && t >= 12 && (v >> t) < 0x100000 && (ctx->caps.zba || (v >> t) < 0x80000)) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static void rv64_mov_seq_zero(rv64_mov_seq_t* p)
|
||||
{
|
||||
p->n = 0;
|
||||
p->depth = 0;
|
||||
p->overflow = 0;
|
||||
}
|
||||
|
||||
static void rv64_mov_seq_copy(rv64_mov_seq_t* dst, const rv64_mov_seq_t* src)
|
||||
{
|
||||
dst->n = src->n;
|
||||
dst->depth = src->depth;
|
||||
dst->overflow = src->overflow;
|
||||
memcpy(dst->op, src->op, src->n * sizeof(rv64_movop_t));
|
||||
}
|
||||
|
||||
static void rv64_mov_seq_add(rv64_mov_seq_t* p, uint8_t op, uint8_t rd, uint8_t rs, uint8_t rs2, int32_t imm, int depth)
|
||||
{
|
||||
if (p->n >= RV64_MOV_MAXOPS) {
|
||||
p->overflow = 1;
|
||||
return;
|
||||
}
|
||||
p->op[p->n].op = op;
|
||||
p->op[p->n].rd = rd;
|
||||
p->op[p->n].rs = rs;
|
||||
p->op[p->n].rs2 = rs2;
|
||||
p->op[p->n].imm = imm;
|
||||
p->n++;
|
||||
if (depth > p->depth) p->depth = (uint8_t)depth;
|
||||
}
|
||||
|
||||
static void rv64_mov_seq_rename(rv64_mov_seq_t* p, uint8_t from, uint8_t to)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < p->n; ++i) {
|
||||
if (p->op[i].rd == from) p->op[i].rd = to;
|
||||
if (p->op[i].rs == from) p->op[i].rs = to;
|
||||
if (p->op[i].rs2 == from) p->op[i].rs2 = to;
|
||||
}
|
||||
}
|
||||
|
||||
static void rv64_mov_seq_concat(rv64_mov_seq_t* dst, const rv64_mov_seq_t* src)
|
||||
{
|
||||
int i;
|
||||
int base = dst->depth;
|
||||
if (dst->overflow || src->overflow) {
|
||||
dst->overflow = 1;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < src->n; ++i) {
|
||||
if (dst->n >= RV64_MOV_MAXOPS) {
|
||||
dst->overflow = 1;
|
||||
return;
|
||||
}
|
||||
dst->op[dst->n] = src->op[i];
|
||||
dst->n++;
|
||||
}
|
||||
if (src->depth > base) base = src->depth;
|
||||
dst->depth = (uint8_t)base;
|
||||
}
|
||||
|
||||
typedef struct rv64_movbest_s {
|
||||
int cost;
|
||||
int depth;
|
||||
rv64_mov_seq_t seq;
|
||||
} rv64_movbest_t;
|
||||
|
||||
static void rv64_mov_best_try(rv64_movbest_t* best, const rv64_mov_seq_t* p)
|
||||
{
|
||||
if (!p->n || p->n > RV64_MOV_MAXOPS || p->overflow) return;
|
||||
if (p->n < best->cost || (p->n == best->cost && p->depth < best->depth)) {
|
||||
best->cost = p->n;
|
||||
best->depth = p->depth;
|
||||
rv64_mov_seq_copy(&best->seq, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void rv64_mov_best_try1(rv64_movbest_t* best, const rv64_mov_seq_t* sub,
|
||||
uint8_t op, uint8_t rd, uint8_t rs, int32_t imm)
|
||||
{
|
||||
rv64_mov_seq_t p;
|
||||
if (!sub->n || sub->n + 1 > RV64_MOV_MAXOPS || sub->overflow) return;
|
||||
rv64_mov_seq_copy(&p, sub);
|
||||
rv64_mov_seq_add(&p, op, rd, rs, 0, imm, sub->depth + 1);
|
||||
rv64_mov_best_try(best, &p);
|
||||
}
|
||||
|
||||
|
||||
static int rv64_mov_seq_high(rv64_movctx_t* ctx, uint64_t hi, int sh, int depth, int nscratch, rv64_mov_seq_t* out)
|
||||
{
|
||||
rv64_mov_seq_t sub;
|
||||
rv64_movbest_t best;
|
||||
best.cost = 99;
|
||||
best.depth = 99;
|
||||
best.seq.n = 0;
|
||||
best.seq.depth = 0;
|
||||
best.seq.overflow = 0;
|
||||
|
||||
if (rv64_mov_seq64(ctx, hi, depth, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLI, RV64_MOV_DST, 0, sh);
|
||||
|
||||
if (hi < 0x100000000ULL && (hi & 0x80000000ULL) && sh >= 32) {
|
||||
if (rv64_mov_seq64(ctx, (uint64_t)(int64_t)(int32_t)hi, depth, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLI, RV64_MOV_DST, 0, sh);
|
||||
}
|
||||
|
||||
if (hi && hi < 0x100000ULL && sh >= 12) {
|
||||
rv64_mov_seq_t p;
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, (int32_t)hi, 1);
|
||||
if (hi < 0x80000ULL) {
|
||||
if (sh > 12) rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, sh - 12, 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
} else if (ctx->caps.zba && sh > 12) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLIUW, RV64_MOV_DST, 0, 0, sh - 12, 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!best.cost) return 0;
|
||||
rv64_mov_seq_copy(out, &best.seq);
|
||||
return out->n;
|
||||
}
|
||||
|
||||
int rv64_mov_seq64(rv64_movctx_t* ctx, uint64_t v, int depth, int nscratch, rv64_mov_seq_t* out)
|
||||
{
|
||||
rv64_movbest_t best;
|
||||
best.cost = 99;
|
||||
best.depth = 99;
|
||||
best.seq.n = 0;
|
||||
best.seq.depth = 0;
|
||||
best.seq.overflow = 0;
|
||||
rv64_mov_seq_t p, sub;
|
||||
int64_t sv = (int64_t)v;
|
||||
int t, n;
|
||||
|
||||
if (rv64_mov_fits12(v)) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, (int32_t)sv, 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (rv64_mov_fits32(v) && !rv64_mov_fits12(v)) {
|
||||
uint32_t vv = (uint32_t)v;
|
||||
int32_t hi20 = (int32_t)(((uint64_t)vv + 0x800) >> 12) & 0xfffff;
|
||||
int32_t lo12 = rv64_mov_sext12(vv);
|
||||
rv64_mov_seq_zero(&p);
|
||||
if (!lo12) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, hi20, 1);
|
||||
} else if (!hi20) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDIW, RV64_MOV_DST, 0, 0, lo12, 1);
|
||||
} else {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, hi20, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDIW, RV64_MOV_DST, 0, 0, lo12, 2);
|
||||
}
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && v && !(v & (v - 1))) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BSETI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(v), 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && v && rv64_mov_popcnt64(v) <= 4) {
|
||||
uint64_t z = v;
|
||||
int c = 0;
|
||||
rv64_mov_seq_zero(&p);
|
||||
while (z) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BSETI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(z), ++c);
|
||||
z &= z - 1;
|
||||
}
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (v && !(v & (v + 1))) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, -1, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SRLI, RV64_MOV_DST, 0, 0, rv64_mov_clz64(v), 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
t = rv64_mov_ctz64(v);
|
||||
if (v && t > 0 && t < 64 && (v >> t) == (~UINT64_C(0) >> t)) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, -1, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, t, 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && v != ~UINT64_C(0)) {
|
||||
int k = rv64_mov_ctz64(~v);
|
||||
if ((v | (UINT64_C(1) << k)) == ~UINT64_C(0) && !rv64_mov_fits12(v)) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, -1, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BCLRI, RV64_MOV_DST, 0, 0, k, 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && best.cost > 2) {
|
||||
uint64_t zeros = ~v;
|
||||
n = rv64_mov_popcnt64(zeros);
|
||||
if (n > 0 && n <= 3) {
|
||||
uint64_t z = zeros;
|
||||
int c = 1;
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, -1, 1);
|
||||
while (z) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BCLRI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(z), ++c);
|
||||
z &= z - 1;
|
||||
}
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && best.cost > 1) {
|
||||
uint32_t low12 = (uint32_t)v & 0xfff;
|
||||
int32_t cand[2];
|
||||
int ncand = 0;
|
||||
if (v & 0x7ff) cand[ncand++] = (int32_t)(v & 0x7ff);
|
||||
if (low12) {
|
||||
int32_t a = rv64_mov_sext12(low12);
|
||||
if (a >= 0 || (((uint64_t)v - (uint64_t)(int64_t)a) & 0x7ffff000ULL))
|
||||
cand[ncand++] = a;
|
||||
}
|
||||
for (int i = 0; i < ncand; ++i) {
|
||||
int32_t a = cand[i];
|
||||
uint64_t w = v - (uint64_t)(int64_t)a;
|
||||
uint64_t lui_part, rest, z;
|
||||
int c = 0;
|
||||
if (w & 0xfff) continue;
|
||||
lui_part = w & 0x7ffff000ULL;
|
||||
rest = w & ~0x7ffff000ULL;
|
||||
if (a < 0 && !lui_part) continue;
|
||||
if (rv64_mov_popcnt64(rest) > 4) continue;
|
||||
rv64_mov_seq_zero(&p);
|
||||
if (lui_part) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, (int32_t)(lui_part >> 12), ++c);
|
||||
}
|
||||
if (a) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, a, ++c);
|
||||
}
|
||||
z = rest;
|
||||
while (z) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BSETI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(z), ++c);
|
||||
z &= z - 1;
|
||||
}
|
||||
if (c) rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t low12 = (uint32_t)v & 0xfff;
|
||||
if (low12) {
|
||||
int32_t a = rv64_mov_sext12(low12);
|
||||
uint64_t w = v - (uint64_t)(int64_t)a;
|
||||
if (w && w != v && rv64_mov_min_ops64(ctx, w) + 1 <= best.cost
|
||||
&& rv64_mov_seq64(ctx, w, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_ADDI, RV64_MOV_DST, 0, a);
|
||||
}
|
||||
}
|
||||
|
||||
t = rv64_mov_ctz64(v);
|
||||
if (v && t >= 12 && t < 64) {
|
||||
uint64_t hi = v >> t;
|
||||
uint64_t his = (uint64_t)(sv >> t);
|
||||
if (rv64_mov_min_ops64(ctx, hi) + 1 <= best.cost
|
||||
&& rv64_mov_seq64(ctx, hi, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLI, RV64_MOV_DST, 0, t);
|
||||
if (his != hi && rv64_mov_min_ops64(ctx, his) + 1 <= best.cost
|
||||
&& rv64_mov_seq64(ctx, his, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLI, RV64_MOV_DST, 0, t);
|
||||
if (ctx->caps.zba && t < 32 && hi < 0x100000000ULL && (hi & 0x80000000ULL)) {
|
||||
if (rv64_mov_min_ops64(ctx, (uint64_t)(int64_t)(int32_t)hi) + 1 <= best.cost
|
||||
&& rv64_mov_seq64(ctx, (uint64_t)(int64_t)(int32_t)hi, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLIUW, RV64_MOV_DST, 0, t);
|
||||
}
|
||||
}
|
||||
|
||||
if (depth < RV64_MOV_MAXDEPTH && best.cost > 2 && ctx->budget > 0 && rv64_mov_min_ops64(ctx, v) < best.cost) {
|
||||
ctx->budget--;
|
||||
uint32_t low12 = (uint32_t)v & 0xfff;
|
||||
|
||||
{
|
||||
int lz = rv64_mov_clz64(v);
|
||||
for (int s = 1; s <= lz; ++s) {
|
||||
uint64_t w = v << s;
|
||||
int32_t sw = (int32_t)(uint32_t)w;
|
||||
if ((uint64_t)(int64_t)sw != w || (w & 0xfff)) continue;
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, (int32_t)((w >> 12) & 0xfffff), 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SRLI, RV64_MOV_DST, 0, 0, s, 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
if (sv < 0 && rv64_mov_min_ops64(ctx, ~v) + 1 <= best.cost) {
|
||||
if (rv64_mov_seq64(ctx, ~v, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_XORI, RV64_MOV_DST, 0, -1);
|
||||
}
|
||||
|
||||
if (low12 >= 0x800) {
|
||||
uint64_t w = v ^ (uint64_t)(int64_t)rv64_mov_sext12(low12);
|
||||
if (w != v && rv64_mov_min_ops64(ctx, w) + 1 <= best.cost && rv64_mov_seq64(ctx, w, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_XORI, RV64_MOV_DST, 0,
|
||||
rv64_mov_sext12(low12));
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs) {
|
||||
uint64_t hi_zeros = ~v & 0xffffffff80000000ULL;
|
||||
n = rv64_mov_popcnt64(hi_zeros);
|
||||
if (n > 0 && n <= 3) {
|
||||
uint64_t nval = v | 0xffffffff80000000ULL;
|
||||
if (nval != v && rv64_mov_min_ops64(ctx, nval) + n <= best.cost && rv64_mov_seq64(ctx, nval, depth + 1, nscratch, &sub)) {
|
||||
uint64_t z = hi_zeros;
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
int c = sub.depth;
|
||||
while (z) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BCLRI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(z), ++c);
|
||||
z &= z - 1;
|
||||
}
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->caps.zba) {
|
||||
static const int mk[3] = { 9, 5, 3 };
|
||||
static const uint8_t mop[3] = { RV64_MOV_SH3ADD, RV64_MOV_SH2ADD, RV64_MOV_SH1ADD };
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (v % mk[i] == 0 && rv64_mov_min_ops64(ctx, v / mk[i]) + 1 <= best.cost && rv64_mov_seq64(ctx, v / mk[i], depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, mop[i], RV64_MOV_DST, RV64_MOV_DST, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (int sh = 12; sh < 64; ++sh) {
|
||||
uint64_t mask = (UINT64_C(1) << sh) - 1;
|
||||
uint64_t low = v & mask;
|
||||
int64_t lo = (int64_t)low;
|
||||
uint64_t w, hi, his;
|
||||
if (low >> (sh - 1)) lo = (int64_t)(low - (UINT64_C(1) << sh));
|
||||
if (lo < -2048 || lo > 2047) continue;
|
||||
w = v - (uint64_t)lo;
|
||||
hi = w >> sh;
|
||||
his = (uint64_t)((int64_t)w >> sh);
|
||||
int ov = 1 + !!lo;
|
||||
if (rv64_mov_min_ops64(ctx, hi) + ov <= best.cost && rv64_mov_seq64(ctx, hi, depth + 1, nscratch, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, sh, sub.depth + 1);
|
||||
if (lo) rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, (int32_t)lo, sub.depth + 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
if (his != hi && rv64_mov_min_ops64(ctx, his) + ov <= best.cost && rv64_mov_seq64(ctx, his, depth + 1, nscratch, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, sh, sub.depth + 1);
|
||||
if (lo) rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, (int32_t)lo, sub.depth + 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
if (ctx->caps.zba && sh < 32 && hi < 0x100000000ULL && (hi & 0x80000000ULL)) {
|
||||
if (rv64_mov_min_ops64(ctx, (uint64_t)(int64_t)(int32_t)hi) + ov <= best.cost && rv64_mov_seq64(ctx, (uint64_t)(int64_t)(int32_t)hi, depth + 1, nscratch, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLIUW, RV64_MOV_DST, 0, 0, sh, sub.depth + 1);
|
||||
if (lo) rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, (int32_t)lo, sub.depth + 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nscratch && v > 0xffffffffULL) {
|
||||
uint32_t lo = (uint32_t)v;
|
||||
uint64_t hi = v >> 32;
|
||||
|
||||
if (lo == hi) {
|
||||
if (rv64_mov_seq32(ctx, lo, depth + 1, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI2, RV64_MOV_DST, RV64_MOV_S1, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_DST, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
if ((lo & 0x80000000u) && rv64_mov_seq32(ctx, ~lo & 0xffffffffu, depth + 1, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI2, RV64_MOV_DST, RV64_MOV_S1, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_DST, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_XORI, RV64_MOV_DST, 0, 0, -1, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
} else {
|
||||
if (rv64_mov_seq32(ctx, lo, depth + 1, &sub)) {
|
||||
rv64_mov_seq_t lo_seq, hi_seq;
|
||||
rv64_mov_seq_copy(&lo_seq, &sub);
|
||||
if (rv64_mov_seq_high(ctx, hi, 32, depth + 1, 0, &hi_seq)) {
|
||||
rv64_mov_seq_rename(&lo_seq, RV64_MOV_DST, RV64_MOV_S1);
|
||||
p = lo_seq;
|
||||
rv64_mov_seq_concat(&p, &hi_seq);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_DST, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
if (hi == (uint64_t)(uint32_t)(lo - 1) && (lo & 0x80000000u)) {
|
||||
if (rv64_mov_seq64(ctx, (uint64_t)(int64_t)(int32_t)lo, depth + 1, 0, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI2, RV64_MOV_DST, RV64_MOV_S1, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_DST, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
if (!(lo & 0x80000000u)) {
|
||||
uint32_t dlt = (uint32_t)hi - lo;
|
||||
if (hi == (uint64_t)(uint32_t)~lo) {
|
||||
if (rv64_mov_seq32(ctx, lo, depth + 1, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_XORI2, RV64_MOV_S2, RV64_MOV_S1, 0, -1, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_S2, 0, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_S2, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
if (nscratch >= 2 && dlt > 0 && dlt <= 2047) {
|
||||
if (rv64_mov_seq32(ctx, lo, depth + 1, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI2, RV64_MOV_S2, RV64_MOV_S1, 0, (int32_t)dlt, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_S2, 0, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_S2, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
if (nscratch >= 2 && ctx->caps.zba) {
|
||||
static const int mk[3] = { 3, 5, 9 };
|
||||
static const uint8_t mop[3] = { RV64_MOV_SH1ADD, RV64_MOV_SH2ADD, RV64_MOV_SH3ADD };
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (hi != (uint64_t)(uint32_t)(lo * mk[i])) continue;
|
||||
if (rv64_mov_seq32(ctx, lo, depth + 1, &sub)) {
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_rename(&p, RV64_MOV_DST, RV64_MOV_S1);
|
||||
rv64_mov_seq_add(&p, mop[i], RV64_MOV_S2, RV64_MOV_S1, 0, 0, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_S2, 0, 0, 32, p.depth + 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_S2, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int sh = 33; sh <= 40; ++sh) {
|
||||
uint64_t mask = (UINT64_C(1) << sh) - 1;
|
||||
uint64_t lv = v & mask;
|
||||
uint64_t hv = v >> sh;
|
||||
if (!lv || !hv) continue;
|
||||
if (!rv64_mov_seq64(ctx, lv, depth + 1, 0, &sub)) continue;
|
||||
{
|
||||
rv64_mov_seq_t lo_seq, hi_seq;
|
||||
rv64_mov_seq_copy(&lo_seq, &sub);
|
||||
if (!rv64_mov_seq_high(ctx, hv, sh, depth + 1, 0, &hi_seq)) continue;
|
||||
rv64_mov_seq_rename(&lo_seq, RV64_MOV_DST, RV64_MOV_S1);
|
||||
p = lo_seq;
|
||||
rv64_mov_seq_concat(&p, &hi_seq);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADD, RV64_MOV_DST, RV64_MOV_DST, RV64_MOV_S1, 0, p.depth + 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->caps.zbb) {
|
||||
uint64_t notv = ~v;
|
||||
if (notv) {
|
||||
int lo_z = rv64_mov_ctz64(notv);
|
||||
int hi_z = rv64_mov_clz64(notv);
|
||||
if (lo_z > 0 && rv64_mov_popcnt64(notv) == 64 - lo_z - hi_z) {
|
||||
uint64_t rot = (v >> lo_z) | (v << (64 - lo_z));
|
||||
if (rv64_mov_seq64(ctx, rot, depth + 1, nscratch, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_RORI, RV64_MOV_DST, 0, 64 - lo_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!best.cost) return 0;
|
||||
rv64_mov_seq_copy(out, &best.seq);
|
||||
return out->n;
|
||||
}
|
||||
|
||||
int rv64_mov_seq32(rv64_movctx_t* ctx, uint32_t v, int depth, rv64_mov_seq_t* out)
|
||||
{
|
||||
rv64_movbest_t best;
|
||||
best.cost = 99;
|
||||
best.depth = 99;
|
||||
best.seq.n = 0;
|
||||
best.seq.depth = 0;
|
||||
best.seq.overflow = 0;
|
||||
rv64_mov_seq_t p, sub;
|
||||
int t;
|
||||
|
||||
if (!v || rv64_mov_fits12(v)) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, (int32_t)v, 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (ctx->caps.zbs && v && !(v & (v - 1))) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BSETI, RV64_MOV_DST, 0, 0, rv64_mov_ctz64(v), 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (v && !(v & (v + 1))) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, -1, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SRLI, RV64_MOV_DST, 0, 0, rv64_mov_clz64(v), 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (!(v & 0x80000000u) && !rv64_mov_fits12(v)) {
|
||||
int32_t hi20 = (int32_t)(((uint64_t)v + 0x800) >> 12) & 0xfffff;
|
||||
int32_t lo12 = rv64_mov_sext12(v);
|
||||
rv64_mov_seq_zero(&p);
|
||||
if (!lo12) {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, hi20, 1);
|
||||
} else {
|
||||
rv64_mov_seq_add(&p, RV64_MOV_LUI, RV64_MOV_DST, 0, 0, hi20, 1);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_ADDIW, RV64_MOV_DST, 0, 0, lo12, 2);
|
||||
}
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
|
||||
if (depth < RV64_MOV_MAXDEPTH && (v & 0x80000000u) && ctx->budget > 0) {
|
||||
ctx->budget--;
|
||||
uint32_t w = v & 0x7fffffff;
|
||||
|
||||
if (ctx->caps.zbs) {
|
||||
if (!w) {
|
||||
rv64_mov_seq_zero(&p);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_BSETI, RV64_MOV_DST, 0, 0, 31, 1);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
} else if (rv64_mov_seq32(ctx, w, depth + 1, &sub)) {
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_BSETI, RV64_MOV_DST, 0, 31);
|
||||
}
|
||||
}
|
||||
if (rv64_mov_seq64(ctx, (uint64_t)(int64_t)(int32_t)v, depth + 1, 0, &sub)) {
|
||||
if (ctx->caps.zba)
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_ZEXTW, RV64_MOV_DST, 0, 0);
|
||||
{
|
||||
rv64_mov_seq_t q;
|
||||
rv64_mov_seq_copy(&q, &sub);
|
||||
rv64_mov_seq_add(&q, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, 32, sub.depth + 1);
|
||||
rv64_mov_seq_add(&q, RV64_MOV_SRLI, RV64_MOV_DST, 0, 0, 32, sub.depth + 2);
|
||||
rv64_mov_best_try(&best, &q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = rv64_mov_ctz64(v);
|
||||
if (depth < RV64_MOV_MAXDEPTH && v && t >= 12 && t <= 31 && ctx->budget > 0) {
|
||||
ctx->budget--;
|
||||
if (rv64_mov_seq32(ctx, v >> t, depth + 1, &sub))
|
||||
rv64_mov_best_try1(&best, &sub, RV64_MOV_SLLI, RV64_MOV_DST, 0, t);
|
||||
}
|
||||
|
||||
if (depth < RV64_MOV_MAXDEPTH && best.cost > 2 && ctx->budget > 0) {
|
||||
ctx->budget--;
|
||||
for (int sh = 12; sh < 32; ++sh) {
|
||||
uint32_t low = v & ((UINT32_C(1) << sh) - 1);
|
||||
int32_t lo;
|
||||
uint32_t hi;
|
||||
if (low >> (sh - 1))
|
||||
lo = (int32_t)(low - (UINT32_C(1) << sh));
|
||||
else
|
||||
lo = (int32_t)low;
|
||||
if (lo < -2048 || lo > 2047) continue;
|
||||
hi = (v - (uint32_t)lo) >> sh;
|
||||
if (!rv64_mov_seq32(ctx, hi, depth + 1, &sub)) continue;
|
||||
rv64_mov_seq_copy(&p, &sub);
|
||||
rv64_mov_seq_add(&p, RV64_MOV_SLLI, RV64_MOV_DST, 0, 0, sh, sub.depth + 1);
|
||||
if (lo) rv64_mov_seq_add(&p, RV64_MOV_ADDI, RV64_MOV_DST, 0, 0, lo, sub.depth + 2);
|
||||
rv64_mov_best_try(&best, &p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!best.cost) return 0;
|
||||
rv64_mov_seq_copy(out, &best.seq);
|
||||
return out->n;
|
||||
}
|
||||
|
||||
#define EMIT(A) emit_fn(emit_ctx, (uint32_t)(A))
|
||||
|
||||
void rv64_mov_emit_seq(int reg, int s1, int s2, const rv64_mov_seq_t* seq, rv64_mov_emit_fn emit_fn, void* emit_ctx)
|
||||
{
|
||||
int vreg[3] = { reg, s1, s2 };
|
||||
uint8_t init = 0;
|
||||
|
||||
for (int i = 0; i < seq->n; ++i) {
|
||||
const rv64_movop_t* o = &seq->op[i];
|
||||
int rd = vreg[o->rd];
|
||||
int rs = vreg[o->rs];
|
||||
int first = !(init & (1 << o->rd));
|
||||
init |= (uint8_t)(1 << o->rd);
|
||||
|
||||
switch (o->op) {
|
||||
case RV64_MOV_ADDI: ADDI(rd, first ? xZR : rd, o->imm); break;
|
||||
case RV64_MOV_ADDIW: ADDIW(rd, first ? xZR : rd, o->imm); break;
|
||||
case RV64_MOV_LUI: LUI(rd, o->imm); break;
|
||||
case RV64_MOV_SLLI: SLLI(rd, rd, o->imm); break;
|
||||
case RV64_MOV_SRLI: SRLI(rd, rd, o->imm); break;
|
||||
case RV64_MOV_SLLIUW: SLLIUW(rd, rd, o->imm); break;
|
||||
case RV64_MOV_BSETI: BSETI_(rd, first ? xZR : rd, o->imm); break;
|
||||
case RV64_MOV_BCLRI: BCLI(rd, first ? xZR : rd, o->imm); break;
|
||||
case RV64_MOV_XORI: XORI(rd, rd, o->imm); break;
|
||||
case RV64_MOV_ZEXTW: ZEXTW(rd, rd); break;
|
||||
case RV64_MOV_RORI: RORI(rd, rd, o->imm); break;
|
||||
case RV64_MOV_ADD: ADD(rd, rs, vreg[o->rs2]); break;
|
||||
case RV64_MOV_SLLI2: SLLI(rd, rs, o->imm); break;
|
||||
case RV64_MOV_SH1ADD: SH1ADD(rd, rs, rs); break;
|
||||
case RV64_MOV_SH2ADD: SH2ADD(rd, rs, rs); break;
|
||||
case RV64_MOV_SH3ADD: SH3ADD(rd, rs, rs); break;
|
||||
case RV64_MOV_ADDI2: ADDI(rd, rs, o->imm); break;
|
||||
case RV64_MOV_XORI2: XORI(rd, rs, o->imm); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define RV64_MOV_CACHE_SIZE 1024
|
||||
|
||||
typedef struct rv64_mov_cache_s {
|
||||
uint64_t v;
|
||||
uint32_t key;
|
||||
uint8_t n;
|
||||
uint8_t used;
|
||||
uint8_t pad[2];
|
||||
rv64_movop_t op[8];
|
||||
} rv64_mov_cache_t;
|
||||
|
||||
static __thread rv64_mov_cache_t rv64_mov_cache[RV64_MOV_CACHE_SIZE];
|
||||
|
||||
static unsigned rv64_mov_cache_slot(uint64_t v, uint32_t key)
|
||||
{
|
||||
uint64_t h = (v + ((uint64_t)key << 56)) * UINT64_C(0x9E3779B97F4A7C15);
|
||||
return (unsigned)(h >> 54) & (RV64_MOV_CACHE_SIZE - 1);
|
||||
}
|
||||
|
||||
int rv64_mov_cache_get(uint64_t v, int nscratch, int is32, rv64_mov_seq_t* out)
|
||||
{
|
||||
uint32_t key = (uint32_t)nscratch | ((uint32_t)is32 << 8);
|
||||
rv64_mov_cache_t* e = &rv64_mov_cache[rv64_mov_cache_slot(v, key)];
|
||||
if (!e->used || e->v != v || e->key != key) return 0;
|
||||
out->n = e->n;
|
||||
out->depth = 0;
|
||||
out->overflow = 0;
|
||||
memcpy(out->op, e->op, (size_t)e->n * sizeof(rv64_movop_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rv64_mov_cache_put(uint64_t v, int nscratch, int is32, const rv64_mov_seq_t* seq)
|
||||
{
|
||||
uint32_t key = (uint32_t)nscratch | ((uint32_t)is32 << 8);
|
||||
rv64_mov_cache_t* e;
|
||||
if (!seq->n || seq->n > 8) return;
|
||||
e = &rv64_mov_cache[rv64_mov_cache_slot(v, key)];
|
||||
e->v = v;
|
||||
e->key = key;
|
||||
e->n = seq->n;
|
||||
e->used = 1;
|
||||
memcpy(e->op, seq->op, (size_t)seq->n * sizeof(rv64_movop_t));
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __RV64_MOV_IMM_H__
|
||||
#define __RV64_MOV_IMM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define RV64_MOV_MAXOPS 16
|
||||
#ifndef RV64_MOV_MAXDEPTH
|
||||
#define RV64_MOV_MAXDEPTH 2
|
||||
#endif
|
||||
#ifndef RV64_MOV_BUDGET
|
||||
#define RV64_MOV_BUDGET 4096
|
||||
#endif
|
||||
|
||||
enum rv64_movop_e {
|
||||
RV64_MOV_ADDI,
|
||||
RV64_MOV_ADDIW,
|
||||
RV64_MOV_LUI,
|
||||
RV64_MOV_SLLI,
|
||||
RV64_MOV_SRLI,
|
||||
RV64_MOV_SLLIUW,
|
||||
RV64_MOV_BSETI,
|
||||
RV64_MOV_BCLRI,
|
||||
RV64_MOV_XORI,
|
||||
RV64_MOV_ZEXTW,
|
||||
RV64_MOV_RORI,
|
||||
RV64_MOV_ADD,
|
||||
RV64_MOV_SLLI2,
|
||||
RV64_MOV_SH1ADD,
|
||||
RV64_MOV_SH2ADD,
|
||||
RV64_MOV_SH3ADD,
|
||||
RV64_MOV_ADDI2,
|
||||
RV64_MOV_XORI2,
|
||||
};
|
||||
|
||||
#define RV64_MOV_DST 0
|
||||
#define RV64_MOV_S1 1
|
||||
#define RV64_MOV_S2 2
|
||||
|
||||
typedef struct rv64_movop_s {
|
||||
uint8_t op;
|
||||
uint8_t rd;
|
||||
uint8_t rs;
|
||||
uint8_t rs2;
|
||||
int32_t imm;
|
||||
} rv64_movop_t;
|
||||
|
||||
typedef struct rv64_mov_seq_s {
|
||||
uint8_t n;
|
||||
uint8_t depth;
|
||||
uint8_t overflow;
|
||||
rv64_movop_t op[RV64_MOV_MAXOPS];
|
||||
} rv64_mov_seq_t;
|
||||
|
||||
typedef struct rv64_movcaps_s {
|
||||
uint8_t zba;
|
||||
uint8_t zbs;
|
||||
uint8_t zbb;
|
||||
} rv64_movcaps_t;
|
||||
|
||||
typedef struct rv64_movctx_s {
|
||||
rv64_movcaps_t caps;
|
||||
int budget;
|
||||
} rv64_movctx_t;
|
||||
|
||||
typedef void (*rv64_mov_emit_fn)(void* ctx, uint32_t insn);
|
||||
|
||||
int rv64_mov_seq64(rv64_movctx_t* ctx, uint64_t v, int depth, int nscratch, rv64_mov_seq_t* out);
|
||||
int rv64_mov_seq32(rv64_movctx_t* ctx, uint32_t v, int depth, rv64_mov_seq_t* out);
|
||||
void rv64_mov_emit_seq(int reg, int s1, int s2, const rv64_mov_seq_t* seq, rv64_mov_emit_fn emit_fn, void* emit_ctx);
|
||||
int rv64_mov_cache_get(uint64_t v, int nscratch, int is32, rv64_mov_seq_t* out);
|
||||
void rv64_mov_cache_put(uint64_t v, int nscratch, int is32, const rv64_mov_seq_t* seq);
|
||||
|
||||
#endif
|
||||
@@ -82,6 +82,7 @@ box64_add_test(Boundary 33 DISABLED_ON_ANDROID)
|
||||
box64_add_test(mmx 34)
|
||||
box64_add_test(xsave_xrstor 35 DISABLED_ON_ANDROID)
|
||||
box64_add_test(mxcsr_rounding_interpreter 36 ENV "BOX64_DYNAREC=0;BOX64_AVX=2" DISABLED_ON_ANDROID)
|
||||
box64_add_test(move_imm 37 ARGS2 quick DISABLED_ON_ANDROID)
|
||||
|
||||
if(BOX32)
|
||||
box64_add_test(bootSyscall_32bits 01 32BIT)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
mov r64, imm64: 69154 values ok
|
||||
mov r32, imm32: 83538 values ok
|
||||
mov r64, imm32: 83538 values ok
|
||||
mov qword [rdi+disp], imm32: 66154 values ok
|
||||
move immediate: PASS
|
||||
Executable
BIN
Binary file not shown.
+277
@@ -0,0 +1,277 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define BLOCK_VALUES 2048
|
||||
#define N16 0x10000u
|
||||
#define N24 0x1000000u
|
||||
#define STEP24 31u
|
||||
#define NRAND64 50000u
|
||||
#define NRAND32 12500u
|
||||
#define NPOW (64u * 9u)
|
||||
|
||||
enum {
|
||||
F_MOV64,
|
||||
F_MOV32,
|
||||
F_MOVSXD,
|
||||
F_STORE32,
|
||||
F_COUNT
|
||||
};
|
||||
|
||||
static uint8_t* pool;
|
||||
static size_t pool_used;
|
||||
static size_t pool_size;
|
||||
static uint64_t checked[F_COUNT];
|
||||
static uint64_t failures;
|
||||
|
||||
static void* alloc_code(size_t bytes)
|
||||
{
|
||||
void* p;
|
||||
if (pool_used + bytes > pool_size) {
|
||||
fprintf(stderr, "code pool exhausted\n");
|
||||
exit(1);
|
||||
}
|
||||
p = pool + pool_used;
|
||||
pool_used += bytes;
|
||||
return p;
|
||||
}
|
||||
|
||||
static size_t emit_mov64(uint8_t* p, uint64_t v, int32_t disp)
|
||||
{
|
||||
p[0] = 0x48;
|
||||
p[1] = 0xB8;
|
||||
memcpy(p + 2, &v, 8);
|
||||
p[10] = 0x48;
|
||||
p[11] = 0x89;
|
||||
p[12] = 0x87;
|
||||
memcpy(p + 13, &disp, 4);
|
||||
return 17;
|
||||
}
|
||||
|
||||
static size_t emit_mov32(uint8_t* p, uint32_t v, int32_t disp)
|
||||
{
|
||||
p[0] = 0xB8;
|
||||
memcpy(p + 1, &v, 4);
|
||||
p[5] = 0x48;
|
||||
p[6] = 0x89;
|
||||
p[7] = 0x87;
|
||||
memcpy(p + 8, &disp, 4);
|
||||
return 12;
|
||||
}
|
||||
|
||||
static size_t emit_movsxd(uint8_t* p, int32_t v, int32_t disp)
|
||||
{
|
||||
p[0] = 0x48;
|
||||
p[1] = 0xC7;
|
||||
p[2] = 0xC0;
|
||||
memcpy(p + 3, &v, 4);
|
||||
p[7] = 0x48;
|
||||
p[8] = 0x89;
|
||||
p[9] = 0x87;
|
||||
memcpy(p + 10, &disp, 4);
|
||||
return 14;
|
||||
}
|
||||
|
||||
static size_t emit_store32(uint8_t* p, int32_t v, int32_t disp)
|
||||
{
|
||||
p[0] = 0x48;
|
||||
p[1] = 0xC7;
|
||||
p[2] = 0x87;
|
||||
memcpy(p + 3, &disp, 4);
|
||||
memcpy(p + 7, &v, 4);
|
||||
return 11;
|
||||
}
|
||||
|
||||
static size_t emit_value(int form, uint8_t* p, uint64_t v, int32_t disp)
|
||||
{
|
||||
switch (form) {
|
||||
case F_MOV64:
|
||||
return emit_mov64(p, v, disp);
|
||||
case F_MOV32:
|
||||
return emit_mov32(p, (uint32_t)v, disp);
|
||||
case F_MOVSXD:
|
||||
return emit_movsxd(p, (int32_t)v, disp);
|
||||
default:
|
||||
return emit_store32(p, (int32_t)v, disp);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t expected(int form, uint64_t v)
|
||||
{
|
||||
switch (form) {
|
||||
case F_MOV64:
|
||||
return v;
|
||||
case F_MOV32:
|
||||
return (uint32_t)v;
|
||||
default:
|
||||
return (uint64_t)(int64_t)(int32_t)v;
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*block_fn)(uint64_t*);
|
||||
|
||||
static void run_values(int form, const uint64_t* values, size_t count)
|
||||
{
|
||||
size_t nblocks = (count + BLOCK_VALUES - 1) / BLOCK_VALUES;
|
||||
size_t i, b;
|
||||
uint8_t* start;
|
||||
uint8_t* p;
|
||||
uint8_t** blocks;
|
||||
|
||||
start = alloc_code(count * 17 + nblocks);
|
||||
blocks = malloc(nblocks * sizeof(*blocks));
|
||||
if (!blocks) exit(1);
|
||||
|
||||
p = start;
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
size_t base = b * BLOCK_VALUES;
|
||||
size_t n = count - base;
|
||||
if (n > BLOCK_VALUES) n = BLOCK_VALUES;
|
||||
blocks[b] = p;
|
||||
for (i = 0; i < n; ++i)
|
||||
p += emit_value(form, p, values[base + i], (int32_t)(i * 8));
|
||||
*p++ = 0xC3;
|
||||
}
|
||||
__builtin___clear_cache((char*)start, (char*)p);
|
||||
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
size_t base = b * BLOCK_VALUES;
|
||||
size_t n = count - base;
|
||||
uint64_t out[BLOCK_VALUES];
|
||||
block_fn fn = (block_fn)blocks[b];
|
||||
if (n > BLOCK_VALUES) n = BLOCK_VALUES;
|
||||
fn(out);
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint64_t want = expected(form, values[base + i]);
|
||||
checked[form]++;
|
||||
if (out[i] != want) {
|
||||
if (failures < 20)
|
||||
printf("FAIL form=%d value=%016llx expected=%016llx got=%016llx\n", form,
|
||||
(unsigned long long)values[base + i], (unsigned long long)want,
|
||||
(unsigned long long)out[i]);
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(blocks);
|
||||
}
|
||||
|
||||
static uint64_t rng_state = 0x123456789abcdefULL;
|
||||
|
||||
static uint64_t rng(void)
|
||||
{
|
||||
rng_state ^= rng_state << 13;
|
||||
rng_state ^= rng_state >> 7;
|
||||
rng_state ^= rng_state << 17;
|
||||
return rng_state;
|
||||
}
|
||||
|
||||
static const uint64_t special[] = {
|
||||
0, 1, 2, 3, 0x7F, 0x80, 0xFF, 0x100, 0x7FFF, 0x8000, 0xFFFF, 0x10000,
|
||||
0x7FFFFFFF, 0x80000000, 0xFFFFFFFF, 0x100000000,
|
||||
0x7FFFFFFFFFFFFFFF, 0x8000000000000000, 0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFF0000FFFF0000, 0x0000FFFF0000FFFF, 0x00FF00FF00FF00FF, 0xFF00FF00FF00FF00,
|
||||
0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 0x3333333333333333, 0xCCCCCCCCCCCCCCCC,
|
||||
0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 0x0101010101010101, 0x8080808080808080,
|
||||
0x123456789ABCDEF0, 0xFEDCBA9876543210, 0xDEADBEEFCAFEBABE,
|
||||
0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0x0000000100000001, 0xFFFFFFFF00000001,
|
||||
0x7FFFFFFFFFFFFFFE, 0x8000000000000001, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFEFFFFFFFF
|
||||
};
|
||||
|
||||
static void print_group(int form)
|
||||
{
|
||||
static const char* name[F_COUNT] = {
|
||||
"mov r64, imm64",
|
||||
"mov r32, imm32",
|
||||
"mov r64, imm32",
|
||||
"mov qword [rdi+disp], imm32"
|
||||
};
|
||||
printf("%s: %llu values ok\n", name[form], (unsigned long long)checked[form]);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int quick = argc > 1 && !strcmp(argv[1], "quick");
|
||||
uint64_t* v16;
|
||||
uint64_t* v24;
|
||||
uint64_t* r64;
|
||||
uint64_t* r32;
|
||||
uint64_t* kpow;
|
||||
uint64_t step24 = quick ? 0x400 : STEP24;
|
||||
size_t nrand64 = quick ? 2000 : NRAND64;
|
||||
size_t nrand32 = quick ? 1000 : NRAND32;
|
||||
size_t n24 = (N24 - 1) / step24 + 1;
|
||||
uint64_t i, k;
|
||||
int d;
|
||||
|
||||
pool_size = 64u << 20;
|
||||
pool = mmap(NULL, pool_size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (pool == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
v16 = malloc(N16 * sizeof(uint64_t));
|
||||
v24 = malloc(n24 * sizeof(uint64_t));
|
||||
r64 = malloc(nrand64 * sizeof(uint64_t));
|
||||
r32 = malloc(nrand32 * sizeof(uint64_t));
|
||||
kpow = malloc(NPOW * sizeof(uint64_t));
|
||||
if (!v16 || !v24 || !r64 || !r32 || !kpow) {
|
||||
perror("malloc");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < N16; ++i)
|
||||
v16[i] = i;
|
||||
for (i = 0; i < n24; ++i)
|
||||
v24[i] = i * step24;
|
||||
for (i = 0; i < nrand64; ++i)
|
||||
r64[i] = rng();
|
||||
for (i = 0; i < nrand32; ++i)
|
||||
r32[i] = (uint32_t)rng();
|
||||
i = 0;
|
||||
for (k = 0; k < 64; ++k) {
|
||||
for (d = -0x1000; d <= 0x1000; d += 0x400) {
|
||||
kpow[i] = (UINT64_C(1) << k) + (uint64_t)(int64_t)d;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
run_values(F_MOV64, v16, N16);
|
||||
run_values(F_MOV64, r64, nrand64);
|
||||
run_values(F_MOV64, r32, nrand32);
|
||||
run_values(F_MOV64, kpow, NPOW);
|
||||
run_values(F_MOV64, special, sizeof(special) / sizeof(special[0]));
|
||||
|
||||
run_values(F_MOV32, v16, N16);
|
||||
run_values(F_MOV32, v24, n24);
|
||||
run_values(F_MOV32, r32, nrand32);
|
||||
run_values(F_MOV32, kpow, NPOW);
|
||||
run_values(F_MOV32, special, sizeof(special) / sizeof(special[0]));
|
||||
|
||||
run_values(F_MOVSXD, v16, N16);
|
||||
run_values(F_MOVSXD, v24, n24);
|
||||
run_values(F_MOVSXD, r32, nrand32);
|
||||
run_values(F_MOVSXD, kpow, NPOW);
|
||||
run_values(F_MOVSXD, special, sizeof(special) / sizeof(special[0]));
|
||||
|
||||
run_values(F_STORE32, v16, N16);
|
||||
run_values(F_STORE32, kpow, NPOW);
|
||||
run_values(F_STORE32, special, sizeof(special) / sizeof(special[0]));
|
||||
|
||||
for (d = 0; d < F_COUNT; ++d)
|
||||
print_group(d);
|
||||
printf("move immediate: %s\n", failures ? "FAILED" : "PASS");
|
||||
|
||||
free(v16);
|
||||
free(v24);
|
||||
free(r64);
|
||||
free(r32);
|
||||
free(kpow);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
Reference in new issue
Block a user