diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2023-11-16 10:04:22 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2023-11-16 10:04:22 +0100 |
| commit | 5baa0833865379799136eea5541b62fe4044ed9a (patch) | |
| tree | 86f392d60824d130015abb6473d498242b8d0f44 /src | |
| parent | 6f7cb088b034d9eda95a603d170b96d8bf3050c4 (diff) | |
| download | box64-5baa0833865379799136eea5541b62fe4044ed9a.tar.gz box64-5baa0833865379799136eea5541b62fe4044ed9a.zip | |
[ARM64_DYNAREC] Reworked shrd 32/64bits opcodes
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_0f.c | 26 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_emit_shift.c | 65 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.h | 2 |
3 files changed, 81 insertions, 12 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_0f.c b/src/dynarec/arm64/dynarec_arm64_0f.c index 48af11a0..ea126cbf 100644 --- a/src/dynarec/arm64/dynarec_arm64_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_0f.c @@ -1358,13 +1358,27 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 0xAD: nextop = F8; INST_NAME("SHRD Ed, Gd, CL"); - MESSAGE(LOG_DUMP, "Need Optimization\n"); - SETFLAGS(X_ALL, SF_SET); - UXTBw(x3, xRCX); - GETEDW(x4, x1, 0); + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + if(box64_dynarec_safeflags>1) + MAYSETFLAGS(); GETGD; - MOVxw_REG(x2, gd); - CALL_(rex.w?((void*)shrd64):((void*)shrd32), ed, x4); + GETED(0); + if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);} + UFLAG_IF { + if(rex.w) { + ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f + } else { + ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f + } + B_NEXT(cEQ); + } else { + if(rex.w) { + ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f + } else { + ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f + } + } + emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4); WBACK; break; diff --git a/src/dynarec/arm64/dynarec_arm64_emit_shift.c b/src/dynarec/arm64/dynarec_arm64_emit_shift.c index 2ebb5ae5..e67961b2 100644 --- a/src/dynarec/arm64/dynarec_arm64_emit_shift.c +++ b/src/dynarec/arm64/dynarec_arm64_emit_shift.c @@ -1017,11 +1017,15 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint return; } IFX(X_CF) { - LSRxw(s3, s1, c-1); - BFIw(xFlags, s3, 0, 1); + BFXILxw(xFlags, s1, c-1, 1); // set CF + } + IFX(X_OF) { + if(c==1) { + LSRxw(s4, s1, rex.w?63:31); + BFIw(xFlags, s4, F_OF, 1); // store sign for later use + } } - LSRxw(s3, s1, c); - ORRxw_REG_LSL(s1, s3, s2, (rex.w?64:32)-c); + EXTRxw(s1, s1, s2, c); IFX(X_PEND) { STRxw_U12(s1, xEmu, offsetof(x64emu_t, res)); } @@ -1036,8 +1040,8 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint } IFX(X_OF) { if(c==1) { - LSRxw(s4, s1, rex.w?62:30); - EORw_REG_LSR(s4, s4, s4, 1); + LSRxw(s4, s1, rex.w?63:31); + EORw_REG_LSR(s4, s4, xFlags, F_OF); // set if sign changed BFIw(xFlags, s4, F_OF, 1); } } @@ -1099,3 +1103,52 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint emit_pf(dyn, ninst, s1, s3, s4); } } + +// emit SHRD32 instruction, from s1, fill s2 , shift s5, store result in s1 using s3 and s4 as scratch +void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4) +{ + IFX(X_PEND) { + STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1)); + STRxw_U12(s5, xEmu, offsetof(x64emu_t, op2)); + // same flags computation as with shl64/shl32 + SET_DF(s4, rex.w?d_shl64:d_shl32); + } else IFX(X_ALL) { + SET_DFNONE(s4); + } + IFX(X_CF) { + SUBw_U12(s3, s5, 1); + LSRxw_REG(s3, s1, s3); + BFIw(xFlags, s3, F_CF, 1); + } + IFX(X_OF) { + LSRxw(s4, s1, rex.w?63:31); + BFIw(xFlags, s4, F_OF, 1); // store sign fr now + } + LSRxw_REG(s3, s1, s5); + SUBxw_U12(s4, s5, rex.w?64:32); + NEGxw_REG(s4, s4); + LSLxw_REG(s4, s2, s4); + ORRxw_REG(s1, s3, s4); + IFX(X_PEND) { + STRxw_U12(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_ZF) { + TSTxw_REG(s1, s1); + CSETw(s4, cEQ); + BFIw(xFlags, s4, F_ZF, 1); + } + IFX(X_SF) { + LSRxw(s4, s1, (rex.w)?63:31); + BFIx(xFlags, s4, F_SF, 1); + } + IFX(X_OF) { + CMPSw_U12(s5, 1); + Bcond(cNE, 4+3*4); + LSRxw(s4, s1, rex.w?62:30); + EORw_REG_LSR(s4, s4, xFlags, F_OF); // Set if sign changed + BFIw(xFlags, s4, F_OF, 1); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h index d24423c4..91273cea 100644 --- a/src/dynarec/arm64/dynarec_arm64_helper.h +++ b/src/dynarec/arm64/dynarec_arm64_helper.h @@ -1043,6 +1043,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr); #define emit_ror16c STEPNAME(emit_ror16c) #define emit_shrd32c STEPNAME(emit_shrd32c) #define emit_shld32c STEPNAME(emit_shld32c) +#define emit_shrd32 STEPNAME(emit_shrd32) #define emit_pf STEPNAME(emit_pf) @@ -1188,6 +1189,7 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, 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); void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4); |