diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41e2a78e3..782950a42 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4098f33e2..68e5075b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/dynarec/rv64/dynarec_rv64_00_2.c b/src/dynarec/rv64/dynarec_rv64_00_2.c index e11d57a1d..6423ff20f 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_2.c +++ b/src/dynarec/rv64/dynarec_rv64_00_2.c @@ -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: diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c index 741a2fcba..7838e908f 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_3.c +++ b/src/dynarec/rv64/dynarec_rv64_00_3.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_0f.c b/src/dynarec/rv64/dynarec_rv64_0f.c index 178b30f16..623060334 100644 --- a/src/dynarec/rv64/dynarec_rv64_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_0f.c @@ -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 { \ diff --git a/src/dynarec/rv64/dynarec_rv64_0f_vector.c b/src/dynarec/rv64/dynarec_rv64_0f_vector.c index a8fe89bf7..39a997215 100644 --- a/src/dynarec/rv64/dynarec_rv64_0f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_0f_vector.c @@ -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; diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index 37251b07b..ee735d404 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c index 60007c7de..0edaa94ca 100644 --- a/src/dynarec/rv64/dynarec_rv64_660f.c +++ b/src/dynarec/rv64/dynarec_rv64_660f.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_660f38.c b/src/dynarec/rv64/dynarec_rv64_660f38.c index 5e5edbcb3..b0830d564 100644 --- a/src/dynarec/rv64/dynarec_rv64_660f38.c +++ b/src/dynarec/rv64/dynarec_rv64_660f38.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_660f_vector.c b/src/dynarec/rv64/dynarec_rv64_660f_vector.c index 65eaf34e2..889509c69 100644 --- a/src/dynarec/rv64/dynarec_rv64_660f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_660f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_66f20f.c b/src/dynarec/rv64/dynarec_rv64_66f20f.c index 6772e94ba..c6bb88bfd 100644 --- a/src/dynarec/rv64/dynarec_rv64_66f20f.c +++ b/src/dynarec/rv64/dynarec_rv64_66f20f.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_0f.c b/src/dynarec/rv64/dynarec_rv64_avx_0f.c index c744fbbea..af99f8d10 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_0f.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c b/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c index bbfd07128..835e1491f 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_0f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c b/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c index d0fa8a6b1..bb02b898b 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c @@ -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 { diff --git a/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c b/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c index 0cbfb3ffc..490e9ab16 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c b/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c index 0bbbcf117..561a79446 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c b/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c index 7335d4cdc..e86d6710a 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c b/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c index cddf06fad..7fc6f54f3 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_66_0f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c b/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c index a3a5e0bc7..73c9b2052 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c @@ -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 { diff --git a/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c b/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c index 71f4c84f6..2be87c489 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_f2_0f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c b/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c index 649cc950d..ed249ceb5 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c @@ -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); } diff --git a/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c b/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c index c343fef44..9131269b2 100644 --- a/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_avx_f3_0f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_d9.c b/src/dynarec/rv64/dynarec_rv64_d9.c index c7dc92735..7b92d866f 100644 --- a/src/dynarec/rv64/dynarec_rv64_d9.c +++ b/src/dynarec/rv64/dynarec_rv64_d9.c @@ -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); } diff --git a/src/dynarec/rv64/dynarec_rv64_f20f.c b/src/dynarec/rv64/dynarec_rv64_f20f.c index ede569caf..264ea4db9 100644 --- a/src/dynarec/rv64/dynarec_rv64_f20f.c +++ b/src/dynarec/rv64/dynarec_rv64_f20f.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_f20f_vector.c b/src/dynarec/rv64/dynarec_rv64_f20f_vector.c index e67a744af..06e4f69f2 100644 --- a/src/dynarec/rv64/dynarec_rv64_f20f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_f20f_vector.c @@ -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) { diff --git a/src/dynarec/rv64/dynarec_rv64_f30f.c b/src/dynarec/rv64/dynarec_rv64_f30f.c index ef87cefe4..e6307bde0 100644 --- a/src/dynarec/rv64/dynarec_rv64_f30f.c +++ b/src/dynarec/rv64/dynarec_rv64_f30f.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_f30f_vector.c b/src/dynarec/rv64/dynarec_rv64_f30f_vector.c index c8c320633..38386b38b 100644 --- a/src/dynarec/rv64/dynarec_rv64_f30f_vector.c +++ b/src/dynarec/rv64/dynarec_rv64_f30f_vector.c @@ -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); diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c index 12d300cb1..a01de6ab2 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.c +++ b/src/dynarec/rv64/dynarec_rv64_helper.c @@ -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); } } diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 3310968ea..d1317ebc2 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -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) diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index 1992318f0..a44b46091 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -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) diff --git a/src/dynarec/rv64/rv64_mov_imm.c b/src/dynarec/rv64/rv64_mov_imm.c new file mode 100644 index 000000000..0b0ca101a --- /dev/null +++ b/src/dynarec/rv64/rv64_mov_imm.c @@ -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 +#include + +#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)); +} diff --git a/src/dynarec/rv64/rv64_mov_imm.h b/src/dynarec/rv64/rv64_mov_imm.h new file mode 100644 index 000000000..6680fb139 --- /dev/null +++ b/src/dynarec/rv64/rv64_mov_imm.h @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +#ifndef __RV64_MOV_IMM_H__ +#define __RV64_MOV_IMM_H__ + +#include + +#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 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 79b32b07f..7d523cfd2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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) diff --git a/tests/ref37.txt b/tests/ref37.txt new file mode 100644 index 000000000..48d8cfd38 --- /dev/null +++ b/tests/ref37.txt @@ -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 diff --git a/tests/test37 b/tests/test37 new file mode 100755 index 000000000..1feae4e70 Binary files /dev/null and b/tests/test37 differ diff --git a/tests/test37.c b/tests/test37.c new file mode 100644 index 000000000..5689e2365 --- /dev/null +++ b/tests/test37.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: MIT +#include +#include +#include +#include +#include + +#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; +}