about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2024-10-08 16:53:18 +0800
committerGitHub <noreply@github.com>2024-10-08 10:53:18 +0200
commit65adf2a860c0fd5e8ac5eed6c25726c610f268ae (patch)
tree5db27b29acf65052f2261cc1d9bb2b943d8324e8 /src
parentdea6906ae9582376da5338feafdce63cace30420 (diff)
downloadbox64-65adf2a860c0fd5e8ac5eed6c25726c610f268ae.tar.gz
box64-65adf2a860c0fd5e8ac5eed6c25726c610f268ae.zip
[RV64_DYNAREC] Fixed CVTSS2SD and CVTSD2SS opcodes (#1913)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_f20f.c12
-rw-r--r--src/dynarec/rv64/dynarec_rv64_f30f.c10
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c37
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h55
4 files changed, 83 insertions, 31 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_f20f.c b/src/dynarec/rv64/dynarec_rv64_f20f.c
index 73fea164..373541f0 100644
--- a/src/dynarec/rv64/dynarec_rv64_f20f.c
+++ b/src/dynarec/rv64/dynarec_rv64_f20f.c
@@ -238,9 +238,15 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
         case 0x5A:
             INST_NAME("CVTSD2SS Gx, Ex");
             nextop = F8;
-            GETEXSD(v1, 0);
-            GETGXSS_empty(v0);
-            FCVTSD(v0, v1);
+            gd = ((nextop & 0x38) >> 3) + (rex.r << 3);
+            if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
+                v0 = sse_get_reg_size_changed(dyn, ninst, x2, gd, 1);
+                FCVTSD(v0, v0);
+            } else {
+                GETEXSD(v1, 0);
+                GETGXSS_empty(v0);
+                FCVTSD(v0, v1);
+            }
             break;
         case 0x5C:
             INST_NAME("SUBSD Gx, Ex");
diff --git a/src/dynarec/rv64/dynarec_rv64_f30f.c b/src/dynarec/rv64/dynarec_rv64_f30f.c
index 7401d717..29438f2f 100644
--- a/src/dynarec/rv64/dynarec_rv64_f30f.c
+++ b/src/dynarec/rv64/dynarec_rv64_f30f.c
@@ -221,9 +221,15 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
         case 0x5A:
             INST_NAME("CVTSS2SD Gx, Ex");
             nextop = F8;
+            gd = ((nextop & 0x38) >> 3) + (rex.r << 3);
             GETEXSS(v1, 0);
-            GETGXSD_empty(v0);
-            FCVTDS(v0, v1);
+            if (MODREG && gd == (nextop & 7) + (rex.b << 3)) {
+                v0 = sse_get_reg_size_changed(dyn, ninst, x2, gd, 0);
+                FCVTDS(v0, v0);
+            } else {
+                GETGXSD_empty(v0);
+                FCVTDS(v0, v1);
+            }
             break;
         case 0x5C:
             INST_NAME("SUBSS Gx, Ex");
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index 7c572092..3dbe24f2 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -1701,6 +1701,43 @@ int sse_get_reg_empty(dynarec_rv64_t* dyn, int ninst, int s1, int a, int single)
     return dyn->e.ssecache[a].reg;
 }
 
+// get an ext register for an SSE reg which changes size, with single or not AFTER the change
+int sse_get_reg_size_changed(dynarec_rv64_t* dyn, int ninst, int s1, int a, int single)
+{
+    if (dyn->e.ssecache[a].v != -1) {
+        if (dyn->e.ssecache[a].vector == 1) {
+            // it's in the fpu, forget it first...
+            sse_forget_reg_vector(dyn, ninst, s1, a);
+            // update olds after the forget...
+            dyn->e.olds[a].changed = 1;
+            dyn->e.olds[a].purged = 0;
+            return sse_get_reg_size_changed(dyn, ninst, s1, a, single);
+        }
+
+        // forget / reload if change of size
+        if (dyn->e.ssecache[a].single == single) {
+            sse_forget_reg(dyn, ninst, s1, a);
+            return sse_get_reg_size_changed(dyn, ninst, s1, a, single);
+        }
+        dyn->e.olds[a].changed = 1;
+        dyn->e.olds[a].purged = 0;
+        dyn->e.olds[a].type = !single;
+        dyn->e.ssecache[a].single = single;
+        dyn->e.ssecache[a].vector = 0;
+        dyn->e.extcache[EXTIDX(dyn->e.ssecache[a].reg)].t = single ? EXT_CACHE_SS : EXT_CACHE_SD;
+        return dyn->e.ssecache[a].reg;
+    }
+    dyn->e.ssecache[a].reg = fpu_get_reg_xmm(dyn, single ? EXT_CACHE_SS : EXT_CACHE_SD, a);
+    int ret = dyn->e.ssecache[a].reg;
+    dyn->e.ssecache[a].single = single;
+    dyn->e.ssecache[a].vector = 0;
+    if (!single) // load happens before size changed
+        FLW(dyn->e.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
+    else
+        FLD(dyn->e.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
+    return ret;
+}
+
 // forget ext register for a SSE reg, does nothing if the regs is not loaded
 void sse_forget_reg(dynarec_rv64_t* dyn, int ninst, int s1, int a)
 {
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index d6380ea7..7e6f5e83 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -1246,32 +1246,33 @@ void* rv64_next(x64emu_t* emu, uintptr_t addr);
 
 #define emit_pf STEPNAME(emit_pf)
 
-#define x87_do_push           STEPNAME(x87_do_push)
-#define x87_do_push_empty     STEPNAME(x87_do_push_empty)
-#define x87_do_pop            STEPNAME(x87_do_pop)
-#define x87_get_current_cache STEPNAME(x87_get_current_cache)
-#define x87_get_cache         STEPNAME(x87_get_cache)
-#define x87_get_extcache      STEPNAME(x87_get_extcache)
-#define x87_get_st            STEPNAME(x87_get_st)
-#define x87_get_st_empty      STEPNAME(x87_get_st)
-#define x87_free              STEPNAME(x87_free)
-#define x87_refresh           STEPNAME(x87_refresh)
-#define x87_forget            STEPNAME(x87_forget)
-#define x87_reget_st          STEPNAME(x87_reget_st)
-#define x87_stackcount        STEPNAME(x87_stackcount)
-#define x87_unstackcount      STEPNAME(x87_unstackcount)
-#define x87_swapreg           STEPNAME(x87_swapreg)
-#define x87_setround          STEPNAME(x87_setround)
-#define x87_restoreround      STEPNAME(x87_restoreround)
-#define sse_setround          STEPNAME(sse_setround)
-#define mmx_get_reg           STEPNAME(mmx_get_reg)
-#define mmx_get_reg_empty     STEPNAME(mmx_get_reg_empty)
-#define mmx_forget_reg        STEPNAME(mmx_forget_reg)
-#define sse_get_reg           STEPNAME(sse_get_reg)
-#define sse_get_reg_empty     STEPNAME(sse_get_reg_empty)
-#define sse_forget_reg        STEPNAME(sse_forget_reg)
-#define sse_purge07cache      STEPNAME(sse_purge07cache)
-#define sse_reflect_reg       STEPNAME(sse_reflect_reg)
+#define x87_do_push              STEPNAME(x87_do_push)
+#define x87_do_push_empty        STEPNAME(x87_do_push_empty)
+#define x87_do_pop               STEPNAME(x87_do_pop)
+#define x87_get_current_cache    STEPNAME(x87_get_current_cache)
+#define x87_get_cache            STEPNAME(x87_get_cache)
+#define x87_get_extcache         STEPNAME(x87_get_extcache)
+#define x87_get_st               STEPNAME(x87_get_st)
+#define x87_get_st_empty         STEPNAME(x87_get_st)
+#define x87_free                 STEPNAME(x87_free)
+#define x87_refresh              STEPNAME(x87_refresh)
+#define x87_forget               STEPNAME(x87_forget)
+#define x87_reget_st             STEPNAME(x87_reget_st)
+#define x87_stackcount           STEPNAME(x87_stackcount)
+#define x87_unstackcount         STEPNAME(x87_unstackcount)
+#define x87_swapreg              STEPNAME(x87_swapreg)
+#define x87_setround             STEPNAME(x87_setround)
+#define x87_restoreround         STEPNAME(x87_restoreround)
+#define sse_setround             STEPNAME(sse_setround)
+#define mmx_get_reg              STEPNAME(mmx_get_reg)
+#define mmx_get_reg_empty        STEPNAME(mmx_get_reg_empty)
+#define mmx_forget_reg           STEPNAME(mmx_forget_reg)
+#define sse_get_reg              STEPNAME(sse_get_reg)
+#define sse_get_reg_empty        STEPNAME(sse_get_reg_empty)
+#define sse_get_reg_size_changed STEPNAME(sse_get_reg_size_changed)
+#define sse_forget_reg           STEPNAME(sse_forget_reg)
+#define sse_purge07cache         STEPNAME(sse_purge07cache)
+#define sse_reflect_reg          STEPNAME(sse_reflect_reg)
 
 #define sse_get_reg_empty_vector STEPNAME(sse_get_reg_empty_vector)
 #define sse_get_reg_vector       STEPNAME(sse_get_reg_vector)
@@ -1499,6 +1500,8 @@ int sse_get_reg(dynarec_rv64_t* dyn, int ninst, int s1, int a, int single);
 int sse_get_reg_vector(dynarec_rv64_t* dyn, int ninst, int s1, int a, int forwrite, int sew);
 // get float register for a SSE reg, but don't try to synch it if it needed to be created
 int sse_get_reg_empty(dynarec_rv64_t* dyn, int ninst, int s1, int a, int single);
+// get an ext register for an SSE reg which changes size, with single or not AFTER the change
+int sse_get_reg_size_changed(dynarec_rv64_t* dyn, int ninst, int s1, int a, int single);
 // get rvv register for an SSE reg, but don't try to synch it if it needed to be created
 int sse_get_reg_empty_vector(dynarec_rv64_t* dyn, int ninst, int s1, int a);
 // forget float register for a SSE reg, create the entry if needed