[LA64_DYNAREC] Added SIMD registers preload and added SS/SD renaming (#4255)

This commit is contained in:
Yang Liu authored and GitHub committed 2026-08-17 20:17:06 +02:00
1 parent f204ae6900
commit d69e4a9684
15 files changed
+560 -183

No files matched your search

+1 -1
View File
@@ -66,7 +66,7 @@ extern void arm64_next_invalid();
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define POSTUPDATE_SPECIFICS(A) updatePreloads(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
+5 -1
View File
@@ -172,6 +172,10 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
if(!ninst) {
if(dyn->always_test)
checkCRC(dyn, 0);
if(dyn->insts[0].preload_xmmymm) {
doPreload(dyn, 0);
}
ENDPREFIX;
}
#endif
fpu_propagate_stack(dyn, ninst);
@@ -307,7 +311,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
else if (is_opcode_volatile && dyn->insts[ninst].will_read)
DMB_ISHLD();
#endif
#ifdef ARM64
#if defined(ARM64) || defined(LA64)
if(dyn->insts[ninst].x64.has_next && dyn->insts[ninst+1].preload_xmmymm) {
doPreload(dyn, ninst+1);
}
+43 -43
View File
@@ -391,49 +391,49 @@ uintptr_t dynarec64_00_1(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
*ok = 0;
break;
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
COMIS_JCC(I); \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
i8 = F8S; \
JUMP(addr + i8, 1); \
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
if (cpuext.lbt) { \
X64_SETJ(tmp1, I); \
} else { \
GETFLAGS; \
} \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32, ninst); \
} else if (cpuext.lbt) \
BEQZ_safe(tmp1, i32, ninst); \
else \
B##NO##_safe(tmp1, i32, ninst); \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, tmp1, tmp2, tmp3); \
jump_to_next(dyn, addr + i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, tmp1, tmp2, tmp3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (cpuext.lbt) \
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
else \
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
COMIS_JCC(I); \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
i8 = F8S; \
JUMP(addr + i8, 1); \
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
if (cpuext.lbt) { \
X64_SETJ(tmp1, I); \
} else { \
GETFLAGS; \
} \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32, ninst); \
} else if (cpuext.lbt) \
BEQZ_safe(tmp1, i32, ninst); \
else \
B##NO##_safe(tmp1, i32, ninst); \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, tmp1, tmp2, tmp3); \
jump_to_next(dyn, addr + i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, tmp1, tmp2, tmp3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (cpuext.lbt) \
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
else \
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
}
GOCOND(0x70, "J", "ib");
+28 -28
View File
@@ -1154,33 +1154,33 @@ uintptr_t dynarec64_00_3(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
addr = dynarec64_DF(dyn, addr, ip, ninst, rex, ok, need_epilog);
break;
#define GO(Z, R) \
JUMP(addr + i8, 1); \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (Z) { \
BNE(R, xZR, i32); \
} else { \
BEQ(R, xZR, i32); \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr + i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
if (Z) { \
BEQ(R, xZR, i32); \
} else { \
BNE(R, xZR, i32); \
}; \
#define GO(Z, R) \
JUMP(addr + i8, 1); \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (Z) { \
BNE(R, xZR, i32); \
} else { \
BEQ(R, xZR, i32); \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr + i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
if (Z) { \
BEQ(R, xZR, i32); \
} else { \
BNE(R, xZR, i32); \
}; \
}
case 0xE0:
@@ -1464,7 +1464,7 @@ uintptr_t dynarec64_00_3(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
// inside the block
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size);
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size);
MESSAGE(1, "Jump to %d / 0x%x\n", tmp, tmp);
if (tmp == 4) {
NOP();
+51 -51
View File
@@ -1462,57 +1462,57 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SMWRITE2();
}
break;
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
COMIS_JCC(I); \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
i32_ = F32S; \
if (rex.is32bits) \
j64 = (uint32_t)(addr + i32_); \
else \
j64 = addr + i32_; \
JUMP(j64, 1); \
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
GETFLAGS; \
} \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32, ninst); \
} else { \
if (cpuext.lbt) \
BEQZ_safe(x1, i32, ninst); \
else \
B##NO##_safe(x1, i32, ninst); \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, tmp1, tmp2, tmp3); \
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, tmp1, tmp2, tmp3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
} else { \
if (cpuext.lbt) \
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
else \
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
} \
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
COMIS_JCC(I); \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
i32_ = F32S; \
if (rex.is32bits) \
j64 = (uint32_t)(addr + i32_); \
else \
j64 = addr + i32_; \
JUMP(j64, 1); \
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
GETFLAGS; \
} \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32, ninst); \
} else { \
if (cpuext.lbt) \
BEQZ_safe(x1, i32, ninst); \
else \
B##NO##_safe(x1, i32, ninst); \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, tmp1, tmp2, tmp3); \
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, tmp1, tmp2, tmp3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].branch_address - (dyn->native_size); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
} else { \
if (cpuext.lbt) \
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
else \
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
} \
}
GOCOND(0x80, "J", "Id");
+9 -9
View File
@@ -52,7 +52,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
v1 = sse_get_reg_scalar(dyn, ninst, x1, ed, 0, XMM_SCALAR_SD);
xmm_live_read(dyn, ninst, ed, XMM_WIDTH_64);
xmm_scalar_move(dyn, ninst, v0, v1, gd, XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
} else {
@@ -68,7 +68,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("MOVSD Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg_scalar(dyn, ninst, x1, gd, 0, XMM_SCALAR_SD);
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
@@ -99,7 +99,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x2A:
INST_NAME("CVTSI2SD Gx, Ed");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETED(0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
if (rex.w) {
@@ -202,7 +202,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x51:
INST_NAME("SQRTSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSD(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
FSQRT_D(d1, d0);
@@ -218,7 +218,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x58:
INST_NAME("ADDSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSD(v1, 0, 0);
xmm_live_read(dyn, ninst, gd, XMM_WIDTH_64);
d0 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
@@ -243,7 +243,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x59:
INST_NAME("MULSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSD(v1, 0, 0);
xmm_live_read(dyn, ninst, gd, XMM_WIDTH_64);
d0 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
@@ -268,7 +268,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5A:
INST_NAME("CVTSD2SS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSD(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FCVT_S_D(d1, d0);
@@ -277,7 +277,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5C:
INST_NAME("SUBSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSD(v1, 0, 0);
xmm_live_read(dyn, ninst, gd, XMM_WIDTH_64);
d0 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
@@ -316,7 +316,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5E:
INST_NAME("DIVSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSD(v1, 0, 0);
xmm_live_read(dyn, ninst, gd, XMM_WIDTH_64);
d0 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
+13 -13
View File
@@ -55,7 +55,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETG;
if (MODREG) {
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
v1 = sse_get_reg_scalar(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0, XMM_SCALAR_SS);
xmm_live_read(dyn, ninst, (nextop & 7) + (rex.b << 3), XMM_WIDTH_32);
xmm_scalar_move(dyn, ninst, v0, v1, gd, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
} else {
@@ -71,7 +71,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("MOVSS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg_scalar(dyn, ninst, x1, gd, 0, XMM_SCALAR_SS);
if (MODREG) {
q0 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
xmm_live_read(dyn, ninst, gd, XMM_WIDTH_32);
@@ -105,7 +105,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x2A:
INST_NAME("CVTSI2SS Gx, Ed");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETED(0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
MOVGR2FR_D(d1, ed);
@@ -268,7 +268,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x51:
INST_NAME("SQRTSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FSQRT_S(d1, d0);
@@ -284,7 +284,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x52:
INST_NAME("RSQRTSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(v1, 0, 0);
q0 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
if (cpuext.frecipe) {
@@ -297,7 +297,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x53:
INST_NAME("RCPSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(v1, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FRECIP_S(d1, v1);
@@ -306,7 +306,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x58:
INST_NAME("ADDSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FADD_S(d1, v0, d0);
@@ -330,7 +330,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x59:
INST_NAME("MULSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FMUL_S(d1, v0, d0);
@@ -354,7 +354,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5A:
INST_NAME("CVTSS2SD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSD(v0, 1);
GETEXSS(v1, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, 1, XMM_SCALAR_SD, XMM_UPPER_PRESERVE);
FCVT_D_S(d1, v1);
@@ -388,7 +388,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5C:
INST_NAME("SUBSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FSUB_S(d1, v0, d0);
@@ -412,7 +412,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5D:
INST_NAME("MINSS Gx, Ex");
nextop = F8;
GETGX(d0, 1);
GETGXSS(d0, 1);
GETEXSS(d1, 0, 0);
q0 = xmm_scalar_begin(dyn, ninst, &scalar, d0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FCMP_S(fcc0, d1, d0, cULE);
@@ -422,7 +422,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5E:
INST_NAME("DIVSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGXSS(v0, 1);
GETEXSS(d0, 0, 0);
d1 = xmm_scalar_begin(dyn, ninst, &scalar, v0, gd, BOX64ENV(dynarec_fastnan), XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FDIV_S(d1, v0, d0);
@@ -446,7 +446,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5F:
INST_NAME("MAXSS Gx, Ex");
nextop = F8;
GETGX(d0, 1);
GETGXSS(d0, 1);
GETEXSS(d1, 0, 0);
q0 = xmm_scalar_begin(dyn, ninst, &scalar, d0, gd, 1, XMM_SCALAR_SS, XMM_UPPER_PRESERVE);
FCMP_S(fcc0, d1, d0, cLT);
+186 -4
View File
@@ -49,6 +49,8 @@ void fpu_reset_scratch(dynarec_la64_t* dyn)
dyn->lsx.fpu_scratch = 0;
dyn->lsx.ymm_used = 0;
dyn->lsx.xmm_used = 0;
dyn->lsx.ymm_load = 0;
dyn->lsx.xmm_load = 0;
}
// Get a x87 double reg
int fpu_get_reg_x87(dynarec_la64_t* dyn, int t, int n)
@@ -100,6 +102,22 @@ int fpu_get_reg_xmm(dynarec_la64_t* dyn, int t, int xmm)
return i;
}
int fpu_get_reg_xmm_scalar(dynarec_la64_t* dyn, int t, int xmm)
{
if (dyn->use_x87 || dyn->use_mmx) return -1;
int i = X870;
while (i < 24 && dyn->lsx.fpuused[i])
++i;
if (i >= 24) return -1;
dyn->lsx.fpuused[i] = 1;
dyn->lsx.lsxcache[i].t = t;
dyn->lsx.lsxcache[i].n = xmm;
dyn->lsx.scalarcache[xmm] = i;
dyn->lsx.news |= 1u << i;
dyn->use_xmm = 1;
return i;
}
// Get an YMM quad reg
int fpu_get_reg_ymm(dynarec_la64_t* dyn, int t, int ymm)
{
@@ -458,6 +476,8 @@ void lsxcacheUnwind(lsxcache_t* cache)
cache->ssecache[i * 2 + 1].v = -1;
cache->avxcache[i * 2].v = -1;
cache->avxcache[i * 2 + 1].v = -1;
cache->scalarcache[i * 2] = -1;
cache->scalarcache[i * 2 + 1] = -1;
}
int x87reg = 0;
for (int i = 0; i < 24; ++i) {
@@ -473,6 +493,10 @@ void lsxcacheUnwind(lsxcache_t* cache)
cache->ssecache[cache->lsxcache[i].n].reg = i;
cache->ssecache[cache->lsxcache[i].n].write = (cache->lsxcache[i].t == LSX_CACHE_XMMW) ? 1 : 0;
break;
case LSX_CACHE_XMM_S:
case LSX_CACHE_XMM_D:
cache->scalarcache[cache->lsxcache[i].n] = i;
break;
case LSX_CACHE_YMMR:
case LSX_CACHE_YMMW:
cache->avxcache[cache->lsxcache[i].n].reg = i;
@@ -507,6 +531,8 @@ const char* getCacheName(int t, int n)
case LSX_CACHE_MM: sprintf(buff, "MM%d", n); break;
case LSX_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
case LSX_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
case LSX_CACHE_XMM_S: sprintf(buff, "XMM%d.s", n); break;
case LSX_CACHE_XMM_D: sprintf(buff, "XMM%d.d", n); break;
case LSX_CACHE_YMMW: sprintf(buff, "YMM%d", n); break;
case LSX_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
case LSX_CACHE_SCR: sprintf(buff, "Scratch"); break;
@@ -626,6 +652,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
length += sprintf(buf + length, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
if (dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts == -1)
length += sprintf(buf + length, ", jmp=out");
if (dyn->insts[ninst].preload_xmmymm)
length += sprintf(buf + length, ", preload=%x/%d", dyn->insts[ninst].preload_xmmymm, dyn->insts[ninst].preload_from);
if (dyn->last_ip)
length += sprintf(buf + length, ", last_ip=%p", (void*)dyn->last_ip);
for (int ii = 0; ii < 24; ++ii) {
@@ -636,6 +664,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
case LSX_CACHE_MM: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMMW: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMMR: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMM_S: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMM_D: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_YMMW: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_YMMR: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_SCR: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
@@ -779,8 +809,10 @@ static void mmx_reset(lsxcache_t* lsx)
static void sse_reset(lsxcache_t* lsx)
{
for (int i = 0; i < 16; ++i)
for (int i = 0; i < 16; ++i) {
lsx->ssecache[i].v = -1;
lsx->scalarcache[i] = -1;
}
}
static void avx_reset(lsxcache_t* lsx)
{
@@ -1020,6 +1052,155 @@ static vector_upper_t transferXmmCopyLiveness(vector_upper_t live_out, const vec
return live_out;
}
static uint32_t getFullXYMMMask(const dynarec_la64_t* dyn, int ninst)
{
if (ninst < 0)
return 0;
uint32_t ret = 0;
for (int i = 0; i < 24; ++i) {
const lsx_cache_t cache = dyn->insts[ninst].lsx.lsxcache[i];
if (cache.t == LSX_CACHE_XMMR || cache.t == LSX_CACHE_XMMW)
ret |= 1u << cache.n;
else if (cache.t == LSX_CACHE_YMMR || cache.t == LSX_CACHE_YMMW)
ret |= 1u << (16 + cache.n);
}
return ret;
}
static uint16_t getCachedVectorMask(const dynarec_la64_t* dyn, int ninst)
{
if (ninst < 0)
return 0;
uint16_t ret = 0;
for (int i = 0; i < 24; ++i) {
int type = dyn->insts[ninst].lsx.lsxcache[i].t;
if (type == LSX_CACHE_XMMR || type == LSX_CACHE_XMMW
|| type == LSX_CACHE_XMM_S || type == LSX_CACHE_XMM_D
|| type == LSX_CACHE_YMMR || type == LSX_CACHE_YMMW)
ret |= 1u << dyn->insts[ninst].lsx.lsxcache[i].n;
}
return ret;
}
static uint32_t filterPreloadLoads(const dynarec_la64_t* dyn, int first, int last, uint32_t preload)
{
uint16_t pending_xmm = preload;
uint16_t pending_ymm = preload >> 16;
uint32_t ret = 0;
for (int i = first; i <= last && (pending_xmm || pending_ymm); ++i) {
const lsxcache_t* cache = &dyn->insts[i].lsx;
uint16_t touched = cache->xmm_used | cache->ymm_used;
uint16_t first_xmm = pending_xmm & touched;
uint16_t first_ymm = pending_ymm & touched;
ret |= first_xmm & cache->xmm_load;
ret |= (uint32_t)(first_ymm & cache->ymm_load) << 16;
pending_xmm &= ~touched;
pending_ymm &= ~touched;
}
return ret;
}
static int tryApplyPreloadCache(dynarec_la64_t* dyn, int first, int last, int reg, int ymm)
{
uint16_t bit = 1u << reg;
int first_use = -1;
for (int i = first; i <= last; ++i) {
if ((dyn->insts[i].lsx.xmm_used | dyn->insts[i].lsx.ymm_used) & bit) {
first_use = i;
break;
}
}
if (first_use < 0) return 0;
for (int i = first; i < first_use; ++i)
if (dyn->insts[i].lsx.lsxcache[reg].v)
return 0;
lsx_cache_t first_cache = dyn->insts[first_use].lsx.lsxcache[reg];
if (first_cache.n != reg) return 0;
if (ymm) {
if (first_cache.t != LSX_CACHE_YMMR && first_cache.t != LSX_CACHE_YMMW)
return 0;
} else if (first_cache.t != LSX_CACHE_XMMR && first_cache.t != LSX_CACHE_XMMW) {
return 0;
}
for (int i = first; i < first_use; ++i) {
lsxcache_t* cache = &dyn->insts[i].lsx;
cache->lsxcache[reg].t = ymm ? LSX_CACHE_YMMR : LSX_CACHE_XMMR;
cache->lsxcache[reg].n = reg;
cache->fpuused[reg] = 1;
cache->news &= ~(1u << reg);
if (ymm) {
cache->ssecache[reg].v = -1;
cache->avxcache[reg].reg = reg;
cache->avxcache[reg].upper_zero_pending = 0;
cache->avxcache[reg].write = 0;
} else {
cache->avxcache[reg].v = -1;
cache->ssecache[reg].reg = reg;
cache->ssecache[reg].write = 0;
}
}
dyn->insts[first_use].lsx.news &= ~(1u << reg);
return 1;
}
static void addSSEPreload(dynarec_la64_t* dyn, int last, int first, uint32_t preload)
{
if (first < 0 || first > last || !preload || dyn->insts[first].preload_xmmymm)
return;
if (first && !dyn->insts[first - 1].x64.has_next)
return;
for (int i = first; i < last; ++i) {
const instruction_la64_t* inst = &dyn->insts[i];
if (!inst->x64.has_next || (inst->x64.barrier & BARRIER_FLOAT)
|| inst->x64.jmp || inst->x64.has_callret || inst->fpupurge || inst->host_call)
return;
}
uint32_t accepted = 0;
for (int reg = 0; reg < 16; ++reg) {
if ((preload & (1u << reg)) && tryApplyPreloadCache(dyn, first, last, reg, 0))
accepted |= 1u << reg;
if ((preload & (1u << (16 + reg))) && tryApplyPreloadCache(dyn, first, last, reg, 1))
accepted |= 1u << (16 + reg);
}
if (!accepted)
return;
dyn->insts[first].preload_xmmymm = accepted;
dyn->insts[first].preload_from = last;
}
void updatePreloads(dynarec_la64_t* dyn)
{
if (!dyn->use_xmm && !dyn->use_ymm)
return;
for (int first = 0; first < dyn->size; ++first) {
if ((first && dyn->insts[first].pred_sz <= 1) || (!first && !dyn->insts[first].pred_sz))
continue;
int last = dyn->size + 1;
for (int j = 0; j < dyn->insts[first].pred_sz; ++j) {
int pred = dyn->insts[first].pred[j];
if (pred != first - 1 && pred < last)
last = pred;
}
if (last > dyn->size || last <= first)
continue;
int prev = getNominalPred(dyn, first);
if (first && prev != first - 1)
continue;
uint32_t preload = getFullXYMMMask(dyn, last);
uint16_t occupied = getCachedVectorMask(dyn, prev);
preload &= ~(uint32_t)occupied;
preload &= ~((uint32_t)occupied << 16);
preload = filterPreloadLoads(dyn, first, last, preload);
if (preload)
addSSEPreload(dyn, last, first, preload);
}
}
static int fpuCacheTransformStoresXmm(dynarec_la64_t* dyn, int ninst)
{
const instruction_la64_t* inst = &dyn->insts[ninst];
@@ -1104,9 +1285,6 @@ void updateUpperLiveness(dynarec_la64_t* dyn)
vector_live_in.xmm_lane1 = 0xFFFF;
vector_live_in.xmm_lanes23 = 0xFFFF;
vector_live_in.ymm_upper = 0xFFFF;
} else if (fpuCacheTransformStoresXmm(dyn, i)) {
vector_live_in.xmm_lane1 = 0xFFFF;
vector_live_in.xmm_lanes23 = 0xFFFF;
} else {
const vector_liveness_t* liveness = &inst->vector_liveness;
vector_upper_t vector_live_out = {.raw = combined_out >> UPPER_LIVENESS_VECTOR_SHIFT};
@@ -1116,6 +1294,10 @@ void updateUpperLiveness(dynarec_la64_t* dyn)
uint16_t untracked = touched & (uint16_t)~liveness->xmm_tracked;
vector_live_in.xmm_lane1 |= untracked;
vector_live_in.xmm_lanes23 |= untracked;
if (fpuCacheTransformStoresXmm(dyn, i)) {
vector_live_in.xmm_lane1 = 0xFFFF;
vector_live_in.xmm_lanes23 = 0xFFFF;
}
}
uint64_t combined_in = gpr_live_in | (vector_live_in.raw << UPPER_LIVENESS_VECTOR_SHIFT);
if (combined_in != live_in[i]) {
@@ -19,6 +19,8 @@ void fpu_reset_scratch(dynarec_la64_t* dyn);
int fpu_get_reg_x87(dynarec_la64_t* dyn, int t, int n);
// Get an XMM quad reg
int fpu_get_reg_xmm(dynarec_la64_t* dyn, int t, int xmm);
// Get a temporary cached renamed scalar register, or -1 when none is available
int fpu_get_reg_xmm_scalar(dynarec_la64_t* dyn, int t, int xmm);
// Get an YMM quad reg
int fpu_get_reg_ymm(dynarec_la64_t* dyn, int t, int ymm);
// Free a FPU/MMX/XMM reg
@@ -74,4 +76,5 @@ int isUpper32Zero(dynarec_la64_t* dyn, int ninst, int reg);
void updateUpperLiveness(dynarec_la64_t* dyn);
void updateRspMerge(dynarec_la64_t* dyn, int is32bits);
void updatePreloads(dynarec_la64_t* dyn);
#endif //__DYNAREC_LA64_FUNCTIONS_H__
+75 -6
View File
@@ -1406,11 +1406,18 @@ static void mmx_reflectcache(dynarec_la64_t* dyn, int ninst, int s1)
}
// SSE / SSE2 helpers
void sse_merge_all(dynarec_la64_t* dyn, int ninst)
{
for (int i = 0; i < 16; ++i)
xmm_scalar_merge(dyn, ninst, i);
}
// get lsx register for a SSE reg, create the entry if needed
int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite)
{
dyn->lsx.xmm_used |= 1 << a;
if (dyn->lsx.ssecache[a].v != -1) {
xmm_scalar_merge(dyn, ninst, a);
if (forwrite) {
dyn->lsx.ssecache[a].write = 1; // update only if forwrite
dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t = LSX_CACHE_XMMW;
@@ -1421,15 +1428,38 @@ int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite)
dyn->lsx.ssecache[a].reg = fpu_get_reg_xmm(dyn, forwrite ? LSX_CACHE_XMMW : LSX_CACHE_XMMR, a);
int ret = dyn->lsx.ssecache[a].reg;
dyn->lsx.ssecache[a].write = forwrite;
dyn->lsx.xmm_load |= 1 << a;
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a])); // skip VLD if migrate from avx
return ret;
}
int sse_get_reg_scalar(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite, int kind)
{
MAYUSE(forwrite);
dyn->lsx.xmm_used |= 1 << a;
if (dyn->lsx.scalarcache[a] != -1) {
int reg = dyn->lsx.scalarcache[a];
if (dyn->lsx.lsxcache[reg].t == (kind == XMM_SCALAR_SS ? LSX_CACHE_XMM_S : LSX_CACHE_XMM_D)) return reg;
xmm_scalar_merge(dyn, ninst, a);
}
if (dyn->lsx.ssecache[a].v != -1) {
return dyn->lsx.ssecache[a].reg;
}
avx_forget_reg(dyn, ninst, a);
dyn->lsx.ssecache[a].reg = fpu_get_reg_xmm(dyn, LSX_CACHE_XMMR, a);
int ret = dyn->lsx.ssecache[a].reg;
dyn->lsx.ssecache[a].write = 0;
dyn->lsx.xmm_load |= 1 << a;
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
return ret;
}
// get lsx register for an SSE reg, but don't try to synch it if it needed to be created
int sse_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a)
{
dyn->lsx.xmm_used |= 1 << a;
if (dyn->lsx.ssecache[a].v != -1) {
xmm_scalar_discard(dyn, a);
dyn->lsx.ssecache[a].write = 1;
dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t = LSX_CACHE_XMMW;
return dyn->lsx.ssecache[a].reg;
@@ -1449,9 +1479,10 @@ void sse_forget_reg(dynarec_la64_t* dyn, int ninst, int a)
dyn->lsx.xmm_used |= 1 << a;
if (dyn->lsx.ssecache[a].v == -1)
return;
if (dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t == LSX_CACHE_XMMW) {
VST(dyn->lsx.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
}
xmm_scalar_merge(dyn, ninst, a);
int reg = dyn->lsx.ssecache[a].reg;
if (dyn->lsx.lsxcache[reg].t == LSX_CACHE_XMMW)
VST(reg, xEmu, offsetof(x64emu_t, xmm[a]));
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
dyn->lsx.ssecache[a].v = -1;
return;
@@ -1462,14 +1493,16 @@ void sse_reflect_reg(dynarec_la64_t* dyn, int ninst, int a)
dyn->lsx.xmm_used |= 1 << a;
if (dyn->lsx.ssecache[a].v == -1)
return;
if (dyn->lsx.lsxcache[dyn->lsx.ssecache[a].reg].t == LSX_CACHE_XMMW) {
VST(dyn->lsx.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
}
xmm_scalar_merge(dyn, ninst, a);
int reg = dyn->lsx.ssecache[a].reg;
if (dyn->lsx.lsxcache[reg].t == LSX_CACHE_XMMW)
VST(reg, xEmu, offsetof(x64emu_t, xmm[a]));
}
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
{
sse_merge_all(dyn, ninst);
int old = -1;
for (int i = 0; i < 8; ++i)
if (dyn->lsx.ssecache[i].v != -1 || dyn->lsx.avxcache[i].v != -1) {
@@ -1502,6 +1535,7 @@ void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
// purge the SSE cache only
static void sse_purgecache(dynarec_la64_t* dyn, int ninst, int next, int s1)
{
sse_merge_all(dyn, ninst);
int old = -1;
for (int i = 0; i < 16; ++i)
if (dyn->lsx.ssecache[i].v != -1) {
@@ -1525,6 +1559,7 @@ static void sse_purgecache(dynarec_la64_t* dyn, int ninst, int next, int s1)
static void sse_reflectcache(dynarec_la64_t* dyn, int ninst, int s1)
{
sse_merge_all(dyn, ninst);
for (int i = 0; i < 16; ++i)
if (dyn->lsx.ssecache[i].v != -1) {
dyn->lsx.xmm_used |= 1 << i;
@@ -1568,6 +1603,7 @@ int avx_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite, int
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
dyn->lsx.avxcache[a].upper_zero_pending = 1;
} else {
dyn->lsx.ymm_load |= 1 << a;
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
XVPERMI_Q(ret, SCRATCH, XVPERMI_IMM_4_0(0, 2));
@@ -1589,6 +1625,7 @@ int avx_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a, int width)
return dyn->lsx.avxcache[a].reg;
}
if (dyn->lsx.ssecache[a].v != -1) {
xmm_scalar_discard(dyn, a);
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
dyn->lsx.ssecache[a].v = -1;
}
@@ -1723,6 +1760,7 @@ static void avx_reflectcache(dynarec_la64_t* dyn, int ninst, int s1)
void fpu_pushcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
{
sse_merge_all(dyn, ninst);
int start = not07 ? 8 : 0;
int n = 0;
@@ -1834,6 +1872,10 @@ void fpu_reset_cache(dynarec_la64_t* dyn, int ninst, int reset_n)
// for STEP 2 & 3, just need to refresh with current, and undo the changes (push & swap)
dyn->lsx = dyn->insts[ninst].lsx;
lsxcacheUnwind(&dyn->lsx);
uint16_t ymm_pending = dyn->insts[ninst].vector_liveness.ymm_pending;
for (int i = 0; i < 16; ++i)
if (dyn->lsx.avxcache[i].v != -1)
dyn->lsx.avxcache[i].upper_zero_pending = (ymm_pending >> i) & 1;
#else
dyn->lsx = dyn->insts[reset_n].lsx;
#endif
@@ -2388,6 +2430,33 @@ void la64_move64(dynarec_la64_t* dyn, int ninst, int reg, int64_t val)
LU52I_D(reg, reg, (val >> 52) & 0xfff);
}
void doPreload(dynarec_la64_t* dyn, int ninst)
{
uint32_t preload = dyn->insts[ninst].preload_xmmymm;
if (!preload)
return;
MESSAGE(LOG_INFO, "Preload XMM/YMM -------- %x\n", preload);
for (int i = 0; i < 16; ++i) {
if (preload & (1u << i)) {
dyn->lsx.avxcache[i].v = -1;
dyn->lsx.ssecache[i].reg = fpu_get_reg_xmm(dyn, LSX_CACHE_XMMR, i);
dyn->lsx.ssecache[i].write = 0;
VLD(dyn->lsx.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
}
if (preload & (1u << (16 + i))) {
dyn->lsx.ssecache[i].v = -1;
dyn->lsx.avxcache[i].v = 0;
dyn->lsx.avxcache[i].reg = fpu_get_reg_ymm(dyn, LSX_CACHE_YMMR, i);
dyn->lsx.avxcache[i].upper_zero_pending = 0;
dyn->lsx.avxcache[i].write = 0;
VLD(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, XVPERMI_IMM_4_0(0, 2));
}
}
MESSAGE(LOG_INFO, "-------- Preload XMM/YMM\n");
}
void checkCRC(dynarec_la64_t* dyn, int ninst)
{
+90 -5
View File
@@ -23,6 +23,10 @@
#include "dynarec_la64_consts.h"
#include "dynarec_la64_functions.h"
#ifndef ENDPREFIX
#define ENDPREFIX
#endif
#define LA64_RESTORE_VZERO() \
do { \
if (cpuext.lasx) \
@@ -66,9 +70,11 @@ typedef enum xmm_upper_policy_s {
typedef struct xmm_scalar_s {
int host_dst;
int guest_dst;
int result;
xmm_scalar_kind_t kind;
xmm_upper_policy_t upper_policy;
int renamed;
} xmm_scalar_t;
static inline void xmm_live_track(dynarec_la64_t* dyn, int ninst, int reg)
@@ -202,18 +208,81 @@ static inline void xmm_scalar_track_write(dynarec_la64_t* dyn, int ninst, int re
xmm_live_track(dyn, ninst, reg);
}
static inline void xmm_scalar_merge(dynarec_la64_t* dyn, int ninst, int reg)
{
int renamed = dyn->lsx.scalarcache[reg];
if (renamed < 0) return;
int full = dyn->lsx.ssecache[reg].reg;
if (dyn->lsx.lsxcache[renamed].t == LSX_CACHE_XMM_S)
VEXTRINS_W(full, renamed, 0);
else
VEXTRINS_D(full, renamed, 0);
dyn->lsx.lsxcache[full].t = LSX_CACHE_XMMW;
dyn->lsx.ssecache[reg].write = 1;
fpu_free_reg(dyn, renamed);
dyn->lsx.scalarcache[reg] = -1;
}
static inline void xmm_scalar_discard(dynarec_la64_t* dyn, int reg)
{
int renamed = dyn->lsx.scalarcache[reg];
if (renamed < 0) return;
fpu_free_reg(dyn, renamed);
dyn->lsx.scalarcache[reg] = -1;
}
static inline int xmm_scalar_begin(dynarec_la64_t* dyn, int ninst, xmm_scalar_t* scalar, int host_dst, int guest_dst, int allow_direct, xmm_scalar_kind_t kind, xmm_upper_policy_t upper_policy)
{
xmm_scalar_track_write(dyn, ninst, guest_dst, upper_policy);
scalar->host_dst = host_dst;
scalar->result = allow_direct && xmm_preserved_lanes_dead(dyn, ninst, guest_dst, kind) ? host_dst : fpu_get_scratch(dyn);
int full_dst = dyn->lsx.ssecache[guest_dst].reg;
int renamed = dyn->lsx.scalarcache[guest_dst];
if (renamed >= 0 && dyn->lsx.lsxcache[renamed].t != (kind == XMM_SCALAR_SS ? LSX_CACHE_XMM_S : LSX_CACHE_XMM_D)) {
xmm_scalar_merge(dyn, ninst, guest_dst);
renamed = -1;
host_dst = full_dst;
}
if (!allow_direct && renamed >= 0) {
xmm_scalar_merge(dyn, ninst, guest_dst);
renamed = -1;
host_dst = full_dst;
}
scalar->host_dst = full_dst;
scalar->guest_dst = guest_dst;
scalar->kind = kind;
scalar->upper_policy = upper_policy;
scalar->renamed = 0;
int preserved_dead = xmm_preserved_lanes_dead(dyn, ninst, guest_dst, kind);
if (allow_direct && renamed >= 0) {
scalar->result = renamed;
scalar->renamed = 1;
return scalar->result;
}
if (allow_direct && preserved_dead) {
scalar->result = full_dst;
return scalar->result;
}
#if STEP > 0
if (allow_direct) {
int result = fpu_get_reg_xmm_scalar(dyn, kind == XMM_SCALAR_SS ? LSX_CACHE_XMM_S : LSX_CACHE_XMM_D, guest_dst);
if (result >= 0) {
if (upper_policy == XMM_UPPER_CLEAR)
VXOR_V(full_dst, full_dst, full_dst);
scalar->result = result;
scalar->renamed = 1;
return scalar->result;
}
}
#endif
scalar->result = fpu_get_scratch(dyn);
return scalar->result;
}
static inline void xmm_scalar_end(dynarec_la64_t* dyn, int ninst, const xmm_scalar_t* scalar)
{
dyn->lsx.ssecache[scalar->guest_dst].write = 1;
dyn->lsx.lsxcache[scalar->host_dst].t = LSX_CACHE_XMMW;
if (scalar->renamed)
return;
if (scalar->host_dst == scalar->result)
return;
if (scalar->upper_policy == XMM_UPPER_CLEAR)
@@ -731,6 +800,14 @@ static inline int comis_fuse_inverted(int condition)
gd = ((nextop & 0x38) >> 3) + (rex.r << 3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
#define GETGXSS(a, w) \
gd = ((nextop & 0x38) >> 3) + (rex.r << 3); \
a = sse_get_reg_scalar(dyn, ninst, x1, gd, w, XMM_SCALAR_SS)
#define GETGXSD(a, w) \
gd = ((nextop & 0x38) >> 3) + (rex.r << 3); \
a = sse_get_reg_scalar(dyn, ninst, x1, gd, w, XMM_SCALAR_SD)
#define GETGX_empty(a) \
gd = ((nextop & 0x38) >> 3) + (rex.r << 3); \
@@ -767,7 +844,7 @@ static inline int comis_fuse_inverted(int condition)
// Get Ex as a double, not a quad (warning, x1 get used, x2 might too)
#define GETEXSD(a, w, D) \
if (MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), w); \
a = sse_get_reg_scalar(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), w, XMM_SCALAR_SD); \
xmm_live_read(dyn, ninst, (nextop & 7) + (rex.b << 3), XMM_WIDTH_64); \
} else { \
SMREAD(); /* TODO */ \
@@ -782,7 +859,7 @@ static inline int comis_fuse_inverted(int condition)
// Get Ex as a single, not a quad (warning, x1 get used)
#define GETEXSS(a, w, D) \
if (MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), w); \
a = sse_get_reg_scalar(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), w, XMM_SCALAR_SS); \
xmm_live_read(dyn, ninst, (nextop & 7) + (rex.b << 3), XMM_WIDTH_32); \
} else { \
SMREAD(); \
@@ -1826,7 +1903,9 @@ static inline int comis_fuse_inverted(int condition)
#define mmx_get_reg STEPNAME(mmx_get_reg)
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
#define sse_purge07cache STEPNAME(sse_purge07cache)
#define sse_merge_all STEPNAME(sse_merge_all)
#define sse_get_reg STEPNAME(sse_get_reg)
#define sse_get_reg_scalar STEPNAME(sse_get_reg_scalar)
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
#define sse_forget_reg STEPNAME(sse_forget_reg)
#define sse_reflect_reg STEPNAME(sse_reflect_reg)
@@ -1848,7 +1927,8 @@ static inline int comis_fuse_inverted(int condition)
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
#define checkCRC STEPNAME(checkCRC)
#define doPreload STEPNAME(doPreload)
#define checkCRC STEPNAME(checkCRC)
#define CacheTransform STEPNAME(CacheTransform)
#define la64_move64 STEPNAME(la64_move64)
@@ -2031,8 +2111,12 @@ void sse_fcsr3_from_mxcsr(dynarec_la64_t* dyn, int ninst, int s1);
// SSE/SSE2 helpers
// purge the XMM0..XMM7 cache (before function call)
void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1);
// merge all pending renamed scalars back into their full XMM registers
void sse_merge_all(dynarec_la64_t* dyn, int ninst);
// get lsx register for a SSE reg, create the entry if needed
int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite);
// get an XMM scalar lane without materializing preserved lanes unless the requested lane needs it
int sse_get_reg_scalar(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite, int kind);
// get lsx register for an SSE reg, but don't try to synch it if it needed to be created
int sse_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a);
// forget float register for a SSE reg, create the entry if needed
@@ -2060,6 +2144,7 @@ void avx_reflect_reg_upper128(dynarec_la64_t* dyn, int ninst, int a, int forwrit
void avx_cleancache(dynarec_la64_t* dyn, int ninst);
// in case of always_test, this insert a check of crc of the dynablock (and exit to ArmNext if wrong)
void doPreload(dynarec_la64_t* dyn, int ninst);
void checkCRC(dynarec_la64_t* dyn, int ninst);
void CacheTransform(dynarec_la64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
+17 -11
View File
@@ -6,18 +6,24 @@
#define EMIT(A) \
do { \
} while (0)
#define NEW_INST \
dyn->insts[ninst].f_entry = dyn->f; \
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
dyn->lsx.swapped = 0; \
dyn->lsx.barrier = 0; \
AREFLAGSNEEDED()
#define NEW_INST \
dyn->insts[ninst].f_entry = dyn->f; \
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
dyn->lsx.swapped = 0; \
dyn->lsx.barrier = 0; \
AREFLAGSNEEDED(); \
if (dyn->insts[ninst].x64.jmp || (dyn->insts[ninst].x64.barrier & BARRIER_FLOAT) \
|| dyn->insts[ninst].x64.has_callret || dyn->insts[ninst].fpupurge || dyn->insts[ninst].host_call) \
sse_merge_all(dyn, ninst)
#define INST_EPILOG \
do { \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].f_exit = dyn->f; \
avx_cleancache(dyn, ninst); \
#define INST_EPILOG \
do { \
if (dyn->insts[ninst].x64.has_next && ninst + 1 < dyn->size \
&& (dyn->insts[ninst + 1].pred_sz != 1 || dyn->insts[ninst + 1].pred[0] != ninst)) \
sse_merge_all(dyn, ninst); \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].f_exit = dyn->f; \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name)
+19 -6
View File
@@ -1,7 +1,13 @@
#define INIT dyn->native_size = 0
#define ENDPREFIX \
dyn->prefixsize = dyn->native_size; \
dyn->insts[ninst].address = dyn->native_size; \
dyn->insts[ninst].branch_address = dyn->native_size; \
dyn->insts[ninst].size = 0
#define FINI \
if (ninst) { \
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
dyn->insts[ninst].branch_address = dyn->native_size; \
dyn->insts_size += 1 + ((dyn->insts[ninst - 1].x64.size > (dyn->insts[ninst - 1].size / 4)) ? dyn->insts[ninst - 1].x64.size : (dyn->insts[ninst - 1].size / 4)) / 15; \
}
@@ -16,15 +22,22 @@
#define NEW_INST \
if (ninst) { \
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
dyn->insts[ninst].branch_address = dyn->native_size; \
dyn->insts_size += 1 + ((dyn->insts[ninst - 1].x64.size > (dyn->insts[ninst - 1].size / 4)) ? dyn->insts[ninst - 1].x64.size : (dyn->insts[ninst - 1].size / 4)) / 15; \
dyn->insts[ninst].ymm0_pass2 = dyn->ymm_zero; \
} \
AREFLAGSNEEDED()
AREFLAGSNEEDED(); \
if (dyn->insts[ninst].x64.jmp || (dyn->insts[ninst].x64.barrier & BARRIER_FLOAT) \
|| dyn->insts[ninst].x64.has_callret || dyn->insts[ninst].fpupurge || dyn->insts[ninst].host_call) \
sse_merge_all(dyn, ninst)
#define INST_EPILOG \
do { \
dyn->insts[ninst].epilog = dyn->native_size; \
avx_cleancache(dyn, ninst); \
#define INST_EPILOG \
do { \
if (dyn->insts[ninst].x64.has_next && ninst + 1 < dyn->size \
&& (dyn->insts[ninst + 1].pred_sz != 1 || dyn->insts[ninst + 1].pred[0] != ninst)) \
sse_merge_all(dyn, ninst); \
dyn->insts[ninst].epilog = dyn->native_size; \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name)
@@ -65,4 +78,4 @@
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
} \
} while(0)
#define CALLRET_LOOP() do { dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
#define CALLRET_LOOP() do { dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+11 -4
View File
@@ -1,4 +1,5 @@
#define INIT
#define ENDPREFIX dyn->insts[ninst].size2 = 0
#define FINI \
if (ninst) \
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
@@ -22,11 +23,17 @@
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
} \
AREFLAGSNEEDED()
AREFLAGSNEEDED(); \
if (dyn->insts[ninst].x64.jmp || (dyn->insts[ninst].x64.barrier & BARRIER_FLOAT) \
|| dyn->insts[ninst].x64.has_callret || dyn->insts[ninst].fpupurge || dyn->insts[ninst].host_call) \
sse_merge_all(dyn, ninst)
#define INST_EPILOG \
do { \
avx_cleancache(dyn, ninst); \
#define INST_EPILOG \
do { \
if (dyn->insts[ninst].x64.has_next && ninst + 1 < dyn->size \
&& (dyn->insts[ninst + 1].pred_sz != 1 || dyn->insts[ninst + 1].pred[0] != ninst)) \
sse_merge_all(dyn, ninst); \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
+9 -1
View File
@@ -20,6 +20,8 @@ typedef struct box64env_s box64env_t;
#define LSX_CACHE_YMMW 7
#define LSX_CACHE_YMMR 8
#define LSX_CACHE_SCR 9
#define LSX_CACHE_XMM_S 10
#define LSX_CACHE_XMM_D 11
#define LSX_AVX_WIDTH_128 0
#define LSX_AVX_WIDTH_256 1
@@ -70,12 +72,15 @@ typedef struct lsxcache_s {
int8_t mmxcache[8]; // cache status for the 8 MMX registers
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
avx_cache_t avxcache[16]; // cache status for the 16 YMM registers
int8_t scalarcache[16]; // pending "scalar" register for each XMM
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
int8_t x87stack; // cache stack counter
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
int8_t fpu_scratch; // scratch counter
uint16_t xmm_used; // mask of the xmm regs used in this opcode
uint16_t ymm_used; // mask of the ymm regs used in this opcode
uint16_t xmm_load; // mask of cache-miss XMM loads emitted by this opcode
uint16_t ymm_load; // mask of cache-miss YMM loads emitted by this opcode
} lsxcache_t;
typedef enum flagcache_s {
@@ -115,7 +120,8 @@ typedef struct vector_liveness_s {
typedef struct instruction_la64_s {
instruction_x64_t x64;
uintptr_t address; // (start) address of the native emitted instruction
uintptr_t address; // start of native bytes attributed to this instruction
uintptr_t branch_address; // internal branch target after any preload
uintptr_t epilog; // epilog of current instruction (can be start of next, or barrier stuff)
int size; // size of the native emitted instruction
int size2; // size of the native emitted instrucion after pass2
@@ -130,6 +136,8 @@ typedef struct instruction_la64_s {
uintptr_t natcall;
uint16_t retn;
uint16_t ymm0_pass2, ymm0_pass3;
uint32_t preload_xmmymm;
int preload_from;
uint8_t barrier_maybe;
uint8_t will_write:2; // [strongmem] will write to memory
uint8_t will_read:1; // [strongmem] will read from memory