mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 04:09:46 -10:00
[LA64_DYNAREC] Added SIMD registers preload and added SS/SD renaming (#4255)
This commit is contained in:
1 parent
f204ae6900
commit
d69e4a9684
15 files changed
+560
-183
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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__
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user