[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:
airidosas252 authored and GitHub committed 2026-11-05 12:04:41 +08:00
1 parent 27a2d1f81d
commit 83935bc134
18 files changed
+276 -121

No files matched your search

+1
View File
@@ -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
View File
@@ -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
+5 -5
View File
@@ -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:
+41 -13
View File
@@ -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");
+8 -20
View File
@@ -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);
+3 -3
View File
@@ -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;
+1 -1
View File
@@ -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) {
+2 -1
View File
@@ -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 {
+1 -1
View File
@@ -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;
+12 -2
View File
@@ -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);
+30 -8
View File
@@ -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);
+16 -40
View File
@@ -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);
+52 -11
View File
@@ -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
}
+32 -12
View File
@@ -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);
+6
View File
@@ -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);
}
+1
View File
@@ -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__
+23 -1
View File
@@ -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"