diff options
| author | phorcys <phorcys@126.com> | 2025-04-24 17:28:42 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-24 11:28:42 +0200 |
| commit | 7158405b7326f9817db3c2b75f2ea863450732a5 (patch) | |
| tree | bd019be0019ab3b61f41f9c9a43159ca0534d26a /src | |
| parent | e059506d5e4a90a216094787f396f8ce058e7c21 (diff) | |
| download | box64-7158405b7326f9817db3c2b75f2ea863450732a5.tar.gz box64-7158405b7326f9817db3c2b75f2ea863450732a5.zip | |
[LA64_DYNAREC] Add POPCNT/TZCNT/LZCNT ops. (#2566)
66.f3.0f.b8/bc/bd POPCNT/TZCNT/LZCNT 16bits ops f3.0f.bd LZCNT fix f3.0f.bc TZCNT (GETED/RESTORE_EFLAGS x1 conflict)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66.c | 1 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66f30f.c | 125 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f30f.c | 42 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 2 | ||||
| -rw-r--r-- | src/dynarec/la64/la64_emitter.h | 8 |
5 files changed, 170 insertions, 8 deletions
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c index c075f3c1..ce5a1845 100644 --- a/src/dynarec/la64/dynarec_la64_66.c +++ b/src/dynarec/la64/dynarec_la64_66.c @@ -114,6 +114,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni switch (rep) { case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break; case 1: addr = dynarec64_66F20F(dyn, addr, ip, ninst, rex, ok, need_epilog); break; + case 2: addr = dynarec64_66F30F(dyn, addr, ip, ninst, rex, ok, need_epilog); break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_66f30f.c b/src/dynarec/la64/dynarec_la64_66f30f.c new file mode 100644 index 00000000..4d46c8ba --- /dev/null +++ b/src/dynarec/la64/dynarec_la64_66f30f.c @@ -0,0 +1,125 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <errno.h> + +#include "debug.h" +#include "box64context.h" +#include "box64cpu.h" +#include "emu/x64emu_private.h" +#include "x64emu.h" +#include "box64stack.h" +#include "callback.h" +#include "emu/x64run_private.h" +#include "x64trace.h" +#include "dynarec_native.h" + +#include "la64_printer.h" +#include "dynarec_la64_private.h" +#include "dynarec_la64_functions.h" +#include "../dynarec_helper.h" + +uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog) +{ + (void)ip; + (void)need_epilog; + + uint8_t opcode = F8; + uint8_t nextop, u8, s8; + int32_t i32; + uint8_t gd, ed; + uint8_t wback, wb1, wb2, gback; + uint8_t eb1, eb2; + int64_t j64; + uint64_t tmp64u, tmp64u2; + int v0, v1; + int q0, q1; + int d0, d1; + int64_t fixedaddress, gdoffset; + int unscaled; + + MAYUSE(d0); + MAYUSE(d1); + MAYUSE(q0); + MAYUSE(q1); + MAYUSE(eb1); + MAYUSE(eb2); + MAYUSE(j64); + + switch (opcode) { + case 0xB8: + INST_NAME("POPCNT Gw, Ew"); + SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION); + SET_DFNONE(); + nextop = F8; + GETGD; + GETEW(x4, 0); + v0 = fpu_get_scratch(dyn); + VINSGR2VR_H(v0, ed, 0); + VPCNT_H(v0, v0); + VPICKVE2GR_HU(gd, v0, 0); + IFX (X_ALL) { + if (la64_lbt) { + X64_SET_EFLAGS(xZR, X_ALL); + BNEZ_MARK(gd); + ADDI_D(x5, xZR, 1 << F_ZF); + X64_SET_EFLAGS(x5, X_ZF); + } else { + CLEAR_FLAGS(x2); + BNEZ_MARK(gd); + ORI(xFlags, xFlags, 1 << F_ZF); + } + MARK; + } + break; + case 0xBC: + INST_NAME("TZCNT Gw, Ew"); + SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION); + SET_DFNONE(); + nextop = F8; + GETEW(x5, 0); + GETGD; + RESTORE_EFLAGS(x1); + /* + ZF is set if gd is zero, unset non-zero. + CF is set if ed is zero, unset non-zero. + OF, SF, PF, and AF flags are undefined + */ + CLEAR_FLAGS(x2); + ADDI_D(x4, xZR, -1); + BSTRINS_D(x4, ed, 15, 0); + CTZ_W(gd, x4); + BNE(gd, xZR, 4 + 4); + ORI(xFlags, xFlags, 1 << F_ZF); + SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0 + OR(xFlags, xFlags, x5); + SPILL_EFLAGS(); + break; + case 0xBD: + INST_NAME("LZCNT Gw, Ew"); + SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION); + SET_DFNONE(); + nextop = F8; + GETEW(x5, 0); + GETGD; + RESTORE_EFLAGS(x1); + /* + ZF is set if gd is zero, unset non-zero. + CF is set if ed is zero, unset non-zero. + OF, SF, PF, and AF flags are undefined + */ + CLEAR_FLAGS(x2); + ADDI_D(x4, xZR, -1); + BSTRINS_D(x4, ed, 31, 16); + CLZ_W(gd, x4); + BNE(gd, xZR, 4 + 4); + ORI(xFlags, xFlags, 1 << F_ZF); + SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0 + OR(xFlags, xFlags, x5); + SPILL_EFLAGS(); + break; + default: + DEFAULT; + } + return addr; +} diff --git a/src/dynarec/la64/dynarec_la64_f30f.c b/src/dynarec/la64/dynarec_la64_f30f.c index 22078287..df53bfb3 100644 --- a/src/dynarec/la64/dynarec_la64_f30f.c +++ b/src/dynarec/la64/dynarec_la64_f30f.c @@ -445,17 +445,43 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ZEROUP2(x4, ed); ed = x4; } - RESTORE_EFLAGS(x1); - ANDI(xFlags, xFlags, ~((1 << F_ZF) | (1 << F_CF))); - BNE_MARK(ed, xZR); - ORI(xFlags, xFlags, 1 << F_CF); - MOV32w(gd, rex.w ? 64 : 32); - SPILL_EFLAGS(); - B_NEXT_nocond; - MARK; + RESTORE_EFLAGS(x6); + /* + ZF is set if gd is zero, unset non-zero. + CF is set if ed is zero, unset non-zero. + OF, SF, PF, and AF flags are undefined + */ + CLEAR_FLAGS(x2); CTZxw(gd, ed); BNE(gd, xZR, 4 + 4); ORI(xFlags, xFlags, 1 << F_ZF); + SRLI_W(x5, gd, rex.w ? 6 : 5); // maximum value is 64/32, F_CF = 0 + OR(xFlags, xFlags, x5); + SPILL_EFLAGS(); + break; + case 0xBD: + INST_NAME("LZCNT Gd, Ed"); + SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION); + SET_DFNONE(); + nextop = F8; + GETED(0); + GETGD; + if (!rex.w && MODREG) { + ZEROUP2(x4, ed); + ed = x4; + } + RESTORE_EFLAGS(x6); + /* + ZF is set if gd is zero, unset non-zero. + CF is set if ed is zero, unset non-zero. + OF, SF, PF, and AF flags are undefined + */ + CLEAR_FLAGS(x2); + CLZxw(gd, ed); + BNE(gd, xZR, 4 + 4); + ORI(xFlags, xFlags, 1 << F_ZF); + SRLI_W(x5, gd, rex.w ? 6 : 5); // maximum value is 64/32, F_CF = 0 + OR(xFlags, xFlags, x5); SPILL_EFLAGS(); break; case 0xC2: diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index 105a502d..7d472bf6 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -886,6 +886,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define dynarec64_660F STEPNAME(dynarec64_660F) #define dynarec64_66F0 STEPNAME(dynarec64_66F0) #define dynarec64_66F20F STEPNAME(dynarec64_66F20F) +#define dynarec64_66F30F STEPNAME(dynarec64_66F30F) #define dynarec64_F0 STEPNAME(dynarec64_F0) #define dynarec64_F20F STEPNAME(dynarec64_F20F) @@ -1149,6 +1150,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog); uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog); uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog); +uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog); uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog); uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog); diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h index 2fc43905..41a87db9 100644 --- a/src/dynarec/la64/la64_emitter.h +++ b/src/dynarec/la64/la64_emitter.h @@ -540,6 +540,14 @@ f24-f31 fs0-fs7 Static registers Callee } \ } while (0) +#define CLZxw(rd, rj) \ + do { \ + if (rex.w) { \ + CLZ_D(rd, rj); \ + } else { \ + CLZ_W(rd, rj); \ + } \ + } while (0) // GR[rd] = SignExtend(GR[rj][7:0], GRLEN) #define EXT_W_B(rd, rj) EMIT(type_2R(0b0000000000000000010111, rj, rd)) |