mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-07 09:26:11 -10:00
[BOX64EC] Compile Dynarec emitters, add Box64EC register mapping (#4666)
* [BOX64EC] Add the ARM64EC register mapping to the Dynarec x18 is the TEB and x6 is guest R9 there, so the scratch registers are x1 to x5. * [BOX64EC] Keep guest R9 out of the Dynarec scratch registers x6 is R9 in the ARM64EC mapping, so the emitters use x1 to x5 only, with the same code on every target where it is the same size. * [BOX64EC] Pass PCMPESTRx REX.W without clobbering guest R9 REX.W goes in bit 8 of the imm8 argument, which a small wrapper unpacks. * [BOX64EC] Adapt Dynarec helper calls to the ARM64EC register map C calls use LR for the call address, spill R10 and R11 and reload x18 as the TEB, and checkCRC keeps emu on the stack instead of in x6. * [BOX64EC] Compile Dynarec sources without linking them The DLL still runs the interpreter.
This commit is contained in:
1 parent
27a2d1f81d
commit
83935bc134
18 files changed
+276
-121
No files matched your search
@@ -1677,6 +1677,7 @@ if(ARM64EC)
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/box64ec"
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw_arm64ec.cmake
|
||||
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
|
||||
-DINTERPRETER_STR=${INTERPRETER_STR}
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
@@ -39,6 +39,32 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#ifdef BOX64EC
|
||||
// x18 is the TEB and x6 is guest R9, the other scratch registers are x1 to x5
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
#define xRBX 8
|
||||
#define xRSP 20
|
||||
#define xRBP 21
|
||||
#define xRSI 16
|
||||
#define xRDI 17
|
||||
#define xR8 15
|
||||
#define xR9 6
|
||||
#define xR10 23
|
||||
#define xR11 9
|
||||
#define xR12 22
|
||||
#define xR13 25
|
||||
#define xR14 26
|
||||
#define xR15 19
|
||||
#define xFlags 7
|
||||
#define xRIP 27
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (((uint8_t[]){10, 11, 12, 8, 20, 21, 16, 17, 15, 6, 23, 9, 22, 25, 26, 19})[(A)])
|
||||
#define IS_GPR(A) (((uint8_t[]){0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, \
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0})[(A)])
|
||||
#else
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
@@ -62,6 +88,9 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
#define IS_GPR(A) ((A)>=xRAX && (A)<=xRIP)
|
||||
#endif
|
||||
// the Windows platform register, reloaded with the TEB after C calls
|
||||
#define xTEB 18
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
@@ -87,8 +116,14 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define x3 3
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#ifdef BOX64EC
|
||||
#define x6 BOX64EC_x6_IS_GUEST_R9_USE_xR9
|
||||
// x87pc is x5, a normal scratch: BOX64_DYNAREC_X87DOUBLE=2 precision tracking is not supported on Box64EC
|
||||
#define x87pc 5
|
||||
#else
|
||||
#define x6 6
|
||||
#define x87pc 7
|
||||
#endif
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
@@ -96,7 +131,11 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#ifdef BOX64EC
|
||||
#define w6 BOX64EC_w6_IS_GUEST_R9_USE_wR9
|
||||
#else
|
||||
#define w6 x6
|
||||
#endif
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
|
||||
@@ -1014,10 +1014,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
// Extract RPL (low 2 bits)
|
||||
UBFXw(x6, ed, 0, 2);
|
||||
UBFXw(x5, ed, 0, 2);
|
||||
UBFXw(x4, gd, 0, 2);
|
||||
// need_update = (dst_rpl < src_rpl)
|
||||
CMPSw_REG(x6, x4);
|
||||
CMPSw_REG(x5, x4);
|
||||
CSETw(x5, cLT);
|
||||
// ZF = need_update
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
@@ -1480,7 +1480,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x6);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x4);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
@@ -3584,7 +3584,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -3603,7 +3603,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -1336,8 +1336,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x6, rex.w);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
@@ -1415,6 +1414,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVBto(x2, d0, 0);
|
||||
BFIw(x1, x2, 8, 8); // insert
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
int lreg = x2; // no x6 (guest R9): lreg is lost in min(lmem, lreg) and recomputed for SF
|
||||
#else
|
||||
int lreg = x6;
|
||||
#endif
|
||||
// get abs of eax / edx and find min
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
@@ -1427,20 +1431,20 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CMPSx_REG(x3, x4);
|
||||
CSELx(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSx_REG(x2, x4);
|
||||
CSELx(x6, x2, x4, cLO); // x6 is lreg
|
||||
CSELx(lreg, x2, x4, cLO);
|
||||
} else {
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(x6, x2, x4, cLO); // x6 is lreg
|
||||
CSELw(lreg, x2, x4, cLO);
|
||||
}
|
||||
CMPSw_REG(x6, x3);
|
||||
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
|
||||
CMPSw_REG(lreg, x3);
|
||||
CSELw(x5, x3, lreg, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, lreg, x3, cLT); // x2 is min(lmem, lreg)
|
||||
// x2 is min length 0-n_packed
|
||||
MVNw_REG(x4, xZR);
|
||||
LSLw_REG(x87pc, x4, x2);
|
||||
BICw_REG(x1, x1, x87pc);
|
||||
LSLw_REG(x2, x4, x2);
|
||||
BICw_REG(x1, x1, x2);
|
||||
LSLw_REG(x4, x4, x5);
|
||||
ORRw_REG(x1, x1, x4);
|
||||
ANDw_mask(x1, x1, 0, (u8&1)?7:15);
|
||||
@@ -1472,8 +1476,17 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
#ifdef BOX64EC
|
||||
// lreg was overwritten by min(lmem, lreg), recompute it from abs(RAX)
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x2, x2);
|
||||
CMPSxw_REG(x2, x4);
|
||||
CSETw(x5, cLO);
|
||||
#else
|
||||
CMPSw_REG(x6, x4);
|
||||
CSETw(x5, cLT);
|
||||
#endif
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
}
|
||||
}
|
||||
@@ -1517,8 +1530,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x6, rex.w);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
}
|
||||
if(u8&0b1000000) {
|
||||
@@ -2522,7 +2534,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x4);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x1 to x5 are all in use and x6 is guest R9, so the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
@@ -2592,7 +2611,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CBZw_NEXT(x4);
|
||||
} else {
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// as SHLD, the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAE:
|
||||
@@ -2951,10 +2977,12 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if (!(MODREG && wback == u8)) MOVx_REG(x6, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
if (!(MODREG && wback == u8)) BFIx(u8, x6, 0, 16);
|
||||
if (!(MODREG && wback == u8)) {
|
||||
SUBw_REG(gd, ed, gd); // the old Ew is the sum minus Gw
|
||||
BFIx(u8, gd, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
|
||||
@@ -115,7 +115,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
UXTHw(x6, xRAX);
|
||||
UXTHw(x5, xRAX);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(cpuext.uscat) {
|
||||
@@ -129,12 +129,12 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
// Aligned version
|
||||
if(cpuext.atomics) {
|
||||
MOVw_REG(x1, x6);
|
||||
MOVw_REG(x1, x5);
|
||||
CASALH(x1, gd, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRH(x4, gd, wback);
|
||||
@@ -149,7 +149,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
@@ -158,7 +158,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x5, x1, x3, x4, x2);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -211,11 +211,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x5);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -362,11 +358,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -387,11 +379,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
|
||||
@@ -254,15 +254,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x6, vd);
|
||||
CMPSw_U12(x6, rex.w ? 64 : 32);
|
||||
UXTBw(x5, vd);
|
||||
CMPSw_U12(x5, rex.w ? 64 : 32);
|
||||
CSETMxw(x2, cPL);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
MVNxw_REG(x2, x2); //prepare mask
|
||||
B_MARK(cPL);
|
||||
LSLxw_REG(x2, x2, x6);
|
||||
LSLxw_REG(x2, x2, x5);
|
||||
MARK;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
|
||||
@@ -443,7 +443,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
u8 = sse_setround(dyn, ninst, x3, x2, x4); // the address below can use x2 and x3, x4 keeps the old FPCR
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
|
||||
@@ -510,17 +510,17 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
u8 = F8;
|
||||
if(u8&4) {
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x5);
|
||||
} else {
|
||||
u8&=3;
|
||||
if(u8==1) u8=2;
|
||||
else if(u8==2) u8=1;
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
MOV32w(x2, u8);
|
||||
MOVx_REG(x6, x1);
|
||||
MOVx_REG(x5, x1);
|
||||
BFIx(x1, x2, 22, 2); // inject new round
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
s0 = x6;
|
||||
s0 = x5;
|
||||
}
|
||||
FCVTN16(v1, v0);
|
||||
if(vex.l) {
|
||||
|
||||
@@ -586,11 +586,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// after the address, so x2 can keep the old FPCR
|
||||
u8 = sse_setround(dyn, ninst, x4, x5, x2);
|
||||
if(!BOX64ENV(dynarec_fastround) || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
|
||||
@@ -125,7 +125,7 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
|
||||
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
|
||||
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len_imm8w;
|
||||
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
|
||||
case const_x64test_step: return (uintptr_t)x64test_step;
|
||||
case const_printtrace: return (uintptr_t)PrintTrace;
|
||||
|
||||
@@ -276,7 +276,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
NOTEST(x5);
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
LDRH_U12(x4, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; // 0xDB or rex
|
||||
@@ -288,7 +288,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
STRH_U12(x4, ed, 8);
|
||||
} else {
|
||||
if(BOX64ENV(x87_no80bits)) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
@@ -357,11 +357,21 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
#ifdef BOX64EC
|
||||
// no x6 (guest R9) and x2 can be the address: x3 is free here (exp11 == 0), at the cost of the MOV
|
||||
CLZx(x3, x1);
|
||||
ADDw_U12(x3, x3, 1); // "one"
|
||||
SUBw_REG(x4, x4, x3); // x4 = exp16
|
||||
ORRw_REG(x4, x4, x5); // x4 = sign | exp16
|
||||
LSLx_REG(x5, x1, x3); // x5 = mantisse
|
||||
MOVw_REG(x3, x4);
|
||||
#else
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
#endif
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
|
||||
@@ -1275,9 +1275,14 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
}
|
||||
|
||||
// emit RCL32/RCL64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
#ifdef BOX64EC
|
||||
int s5 = s3; // no x6 (guest R9), so s3 is reused and the new CF waits in F_res2
|
||||
#else
|
||||
int s5 = x6;
|
||||
#endif
|
||||
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_OF|X_CF) {
|
||||
@@ -1292,6 +1297,11 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
LSRxw_REG(s3, s1, s4);
|
||||
}
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFIw(xFlags, s3, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX(X_OF) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
@@ -1319,15 +1329,27 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
#ifdef BOX64EC
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
#else
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
#endif
|
||||
}
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
#ifdef BOX64EC
|
||||
UBFXw(s3, xFlags, F_res2, 1);
|
||||
#endif
|
||||
EORxw_REG_LSR(s3, s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFCw(xFlags, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
@@ -1349,15 +1371,15 @@ void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
/*else*/
|
||||
{
|
||||
LSRxw_REG(s5, s1, s2);
|
||||
UBFXw(s4, xFlags, 0, 1);
|
||||
LSRxw_REG(s4, s1, s2);
|
||||
MOVZw(s3, (rex.w?64:32));
|
||||
SUBx_REG(s3, s3, s2);
|
||||
LSLxw_REG(s4, s4, s3);
|
||||
ORRxw_REG(s5, s5, s4);
|
||||
UBFXw(s2, xFlags, 0, 1); // s2 is not needed anymore
|
||||
LSLxw_REG(s2, s2, s3);
|
||||
ORRxw_REG(s4, s4, s2);
|
||||
ADDx_U12(s3, s3, 1);
|
||||
LSLxw_REG(s1, s1, s3);
|
||||
ORRxw_REG(s1, s1, s5);
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
|
||||
@@ -239,28 +239,28 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LOCK CMPXCHG Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x1);
|
||||
UBFXx(x6, xRAX, 0, 8);
|
||||
UBFXx(x5, xRAX, 0, 8);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
MOVw_REG(x2, x6);
|
||||
CASALB(x6, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x6, x3, x4, x5);
|
||||
MOVw_REG(x2, x5);
|
||||
CASALB(x5, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x5, x3, x4, x1);
|
||||
} else {
|
||||
CASALB(x6, gd, wback);
|
||||
CASALB(x5, gd, wback);
|
||||
}
|
||||
BFIx(xRAX, x6, 0, 8);
|
||||
BFIx(xRAX, x5, 0, 8);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x2, wback);
|
||||
CMPSxw_REG(x6, x2);
|
||||
CMPSxw_REG(x5, x2);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
MARK;
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, x2, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x5, x2, x3, x4, x1);}
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
UFLAG_IF { MOVxw_REG(x6, xRAX); }
|
||||
UFLAG_IF { MOVxw_REG(x5, xRAX); }
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -345,7 +345,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MARK;
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, x6, x1, x3, x4, x5);
|
||||
emit_cmp32(dyn, ninst, rex, x5, x1, x3, x4, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -823,11 +823,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
STLXRB(x4, x1, wback);
|
||||
@@ -848,11 +844,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
|
||||
STLXRxw(x4, x1, wback);
|
||||
@@ -1107,11 +1099,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1132,11 +1120,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1369,11 +1353,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
@@ -1394,11 +1374,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
|
||||
@@ -50,7 +50,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(hint>0 && hint<xRAX) scratch = hint;
|
||||
if(hint>0 && !IS_GPR(hint)) scratch = hint;
|
||||
int absmin = 0;
|
||||
if(s) absmin=-absmax;
|
||||
int seg_done = 0;
|
||||
@@ -204,7 +204,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
ADDy_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = TO_NAT(sib & 0x07) + (rex.b << 3));
|
||||
PASS3(int tmp = TO_NAT((sib & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBy_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -229,7 +229,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if(rex.seg && !seg_done) {
|
||||
scratch = (hint>0 && !IS_GPR(hint)) ? hint : x2;
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR; // dead between opcodes, ret+1 can be a guest register
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
ADDx_REGy(hint, scratch, ret);
|
||||
@@ -321,7 +321,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
|
||||
if(rex.seg) {
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR;
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
if(IS_GPR(ret)) {
|
||||
@@ -350,8 +350,10 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#endif
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -426,8 +428,10 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret) >= 3 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#endif
|
||||
// #ifdef HAVE_TRACE
|
||||
// The BLR form is only for gdb backtraces, but it breaks the
|
||||
// return-address-stack prediction on every block-to-block jump, which is
|
||||
@@ -448,6 +452,7 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
CHECK_DFNONE(0);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
@@ -459,6 +464,7 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
#endif
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
#ifdef HAVE_TRACE
|
||||
@@ -566,12 +572,16 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
// R10 and R11 are not preserved by the C call in the EC map
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10]));
|
||||
#endif
|
||||
fpu_pushcache(dyn, ninst, savereg, 0);
|
||||
for(int i=0; i<dyn->n.fpu_scratch; ++i)
|
||||
VSTR128_S9_preindex(SCRATCH0+i, xSP, -16);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64C(reg, fnc);
|
||||
BLR(reg);
|
||||
@@ -594,15 +604,23 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
fpu_popcache(dyn, ninst, savereg, 0); // savereg will not be used
|
||||
}
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x87pc is x5, the pop above restored an argument: reload it
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#else
|
||||
if(savereg!=x87pc && dyn->need_x87check) {
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
#endif
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
@@ -623,11 +641,14 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10])); // not preserved by the C call, as in call_c
|
||||
#endif
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_pushcache(dyn, ninst, x87pc, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
if(arg1!=-1)
|
||||
FMOVD(0, arg1);
|
||||
@@ -647,6 +668,9 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_popcache(dyn, ninst, x1, 0); // savereg will not be used
|
||||
@@ -2355,12 +2379,25 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(x1, j64);
|
||||
}
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
// updateflags uses x1 to x5 and x6 is guest R9: NZCV goes through the emu
|
||||
MRS_nzcv(x1);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
MRS_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
TABLE64C(x1, const_updateflags_arm64);
|
||||
BLR(x1);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
MSR_nzcv(x1);
|
||||
#else
|
||||
MSR_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
MARKF2;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
|
||||
@@ -2985,8 +3022,8 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
// grab the dynablock address in x5, as this on will not be erased by crc functions
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
LDRx_literal(x5, delta);
|
||||
// move away xEMU to X6, should be safe there
|
||||
MOVx_REG(x6, xEmu);
|
||||
// move away xEMU to the stack, x6 is guest R9 on Box64EC
|
||||
STPx_S7_preindex(xEmu, xZR, xSP, -16);
|
||||
// prepare and call the crc function
|
||||
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
|
||||
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
|
||||
@@ -2994,10 +3031,14 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
BLR(x3);
|
||||
// done, move away result and restore xEmu
|
||||
MOVw_REG(x1, xEmu);
|
||||
MOVx_REG(xEmu, x6);
|
||||
LDPx_S7_postindex(xEmu, xZR, xSP, 16);
|
||||
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
|
||||
SUBw_REG(x1, x1, x2);
|
||||
CBZw(x1, 4+2*4);
|
||||
TABLE64C(x3, const_native_next_invalidate);
|
||||
BLR(x3);
|
||||
#ifdef BOX64EC
|
||||
// x5 held the dynablock, which is x87pc here
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#endif
|
||||
}
|
||||
@@ -578,15 +578,15 @@
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || BOX64ENV(dynarec_aligned_atomics))
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || BOX64ENV(dynarec_aligned_atomics))
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// CALL will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x87pc, ret, 1, 0)
|
||||
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, xLR, ret, 1, 0)
|
||||
// CALL_ will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x87pc, ret, 1, reg)
|
||||
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, xLR, ret, 1, reg)
|
||||
// CALL_S will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x87pc, ret, 0, 0)
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, xLR, ret, 0, 0)
|
||||
// CALL_D will use x7 for the call address. Use for function having 1 or 2 double args and returning 1 double
|
||||
// All regs are saved, including xmm0-7, will move arg1/arg2 to D0, D1, return D0 to ret (unless any is -1)
|
||||
#define CALL_D(F, ret, arg1, arg2, sav1, sav2) call_d(dyn, ninst, F, ret, arg1, arg2, sav1, sav2)
|
||||
@@ -604,6 +604,26 @@
|
||||
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
|
||||
#define GETMARKSEG dyn->insts[ninst].markseg
|
||||
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
|
||||
#ifdef BOX64EC
|
||||
// x6 is guest R9 and x87pc is x5, so keep the flags in the emu across the retry loop
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
MRS_nzcv(x4); \
|
||||
STRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MARKLOCK; \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
LDRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MSR_nzcv(x4); \
|
||||
} while (0)
|
||||
#else
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
MOVx_REG(x6, xFlags); \
|
||||
MRS_nzcv(x87pc); \
|
||||
MARKLOCK; \
|
||||
MOVx_REG(xFlags, x6); \
|
||||
MSR_nzcv(x87pc); \
|
||||
} while (0)
|
||||
#endif
|
||||
#define GETMARKLOCK dyn->insts[ninst].marklock
|
||||
|
||||
// Branch to MARK if cond (use j64)
|
||||
@@ -1029,8 +1049,8 @@
|
||||
#define READFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& (dyn->f==status_unk)) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
} else if((A)==X_ALL) flushNative(dyn, ninst);
|
||||
#endif
|
||||
@@ -1038,8 +1058,8 @@
|
||||
#define GRABFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& ((dyn->f==status_unk) || (dyn->f==status_set))) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
|
||||
@@ -1483,8 +1503,8 @@ void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4);
|
||||
|
||||
@@ -134,3 +134,9 @@ uint32_t sse42_compare_string_implicit_len(x64emu_t* emu, sse_regs_t* mem, sse_r
|
||||
}
|
||||
return sse42_compare_string_explicit_len(emu, mem, lmem, reg, lreg, imm8, 0);
|
||||
}
|
||||
|
||||
// for the dynarec: REX.W is passed in bit 8 of imm8_w, to spare a register
|
||||
uint32_t sse42_compare_string_explicit_len_imm8w(x64emu_t* emu, sse_regs_t* mem, int64_t lmem, sse_regs_t* reg, int64_t lreg, uint32_t imm8_w)
|
||||
{
|
||||
return sse42_compare_string_explicit_len(emu, mem, lmem, reg, lreg, imm8_w & 0xff, (imm8_w >> 8) & 1);
|
||||
}
|
||||
@@ -10,5 +10,6 @@ typedef struct x64emu_s x64emu_t;
|
||||
|
||||
uint32_t sse42_compare_string_explicit_len(x64emu_t* emu, sse_regs_t* a, int64_t la, sse_regs_t* b, int64_t lb, uint8_t imm8, int w);
|
||||
uint32_t sse42_compare_string_implicit_len(x64emu_t* emu, sse_regs_t* a, sse_regs_t* b, uint8_t imm8);
|
||||
uint32_t sse42_compare_string_explicit_len_imm8w(x64emu_t* emu, sse_regs_t* a, int64_t la, sse_regs_t* b, int64_t lb, uint32_t imm8_w);
|
||||
|
||||
#endif //__X64_CMPSTRINGS_H__
|
||||
@@ -5,6 +5,7 @@ find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
set(BOX64_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||
|
||||
string(REPLACE "," ";" DYNAREC_PASS "${DYNAREC_PASS_STR}")
|
||||
string(REPLACE "," ";" INTERPRETER "${INTERPRETER_STR}")
|
||||
if(NOT INTERPRETER)
|
||||
message(FATAL_ERROR "Build Box64EC from the parent project with -DARM64EC=ON")
|
||||
@@ -51,7 +52,28 @@ add_library(box64ec SHARED
|
||||
"${BOX64_ROOT}/external/musl/sqrt_data.c"
|
||||
"${BOX64_ROOT}/external/musl/sqrtf.c"
|
||||
)
|
||||
foreach(target box64ec box64ec_interpreter)
|
||||
set(BOX64EC_TARGETS box64ec box64ec_interpreter)
|
||||
|
||||
# The Dynarec emitters are only compiled for now, the DLL does not link them yet.
|
||||
if(DYNAREC_PASS)
|
||||
add_library(box64ec_dynarec_helpers OBJECT
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_immenc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_consts.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/updateflags_arm64.c")
|
||||
target_compile_definitions(box64ec_dynarec_helpers PRIVATE DYNAREC)
|
||||
list(APPEND BOX64EC_TARGETS box64ec_dynarec_helpers)
|
||||
foreach(STEP_VALUE RANGE 3)
|
||||
add_library(box64ec_dynarec_pass${STEP_VALUE} OBJECT ${DYNAREC_PASS})
|
||||
target_compile_definitions(box64ec_dynarec_pass${STEP_VALUE} PRIVATE DYNAREC STEP=${STEP_VALUE})
|
||||
list(APPEND BOX64EC_TARGETS box64ec_dynarec_pass${STEP_VALUE})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
foreach(target ${BOX64EC_TARGETS})
|
||||
target_include_directories(${target} PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${BOX64_ROOT}/src/include"
|
||||
|
||||
Reference in new issue
Block a user