[RV64_DYNAREC] Reworked move immediate (#4591)

* [RV64_DYNAREC] Reworked move immediate

* Use -O2 for test37
This commit is contained in:
Yang Liu authored and GitHub committed 2026-10-25 20:57:34 +01:00
1 parent 420eda69ff
commit a46ad9dfe9
36 files changed
+1323 -208

No files matched your search

+1 -1
View File
@@ -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
+1
View File
@@ -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
+3 -6
View File
@@ -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:
+4 -5
View File
@@ -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);
+3 -4
View File
@@ -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 { \
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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);
+6 -6
View File
@@ -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);
+14 -18
View File
@@ -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);
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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);
+12 -15
View File
@@ -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 {
+7 -11
View File
@@ -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);
+3 -3
View File
@@ -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);
+3 -3
View File
@@ -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);
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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);
}
+4 -4
View File
@@ -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);
+2 -2
View File
@@ -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) {
+11 -35
View File
@@ -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);
+3 -3
View File
@@ -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);
+74 -40
View File
@@ -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);
}
}
+26 -8
View File
@@ -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)
+21 -20
View File
@@ -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)
+746
View File
@@ -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));
}
+74
View File
@@ -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
+1
View File
@@ -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)
+5
View File
@@ -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
View File
Binary file not shown.
+277
View File
@@ -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;
}