about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-11-16 15:10:56 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-11-16 15:10:56 +0100
commitc17e37b6e0c4d686702aa9abfdcc58b227626a2b (patch)
tree9470193ca07e676ae1e80cb48764894844e012b7 /src/dynarec
parentdf25986597a6c24984fd81a5eb14b95754ed6973 (diff)
downloadbox64-c17e37b6e0c4d686702aa9abfdcc58b227626a2b.tar.gz
box64-c17e37b6e0c4d686702aa9abfdcc58b227626a2b.zip
[ARM64_DYNAREC] Optimized 66 0F A4 opcode
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_660f.c22
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_shift.c57
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h2
3 files changed, 70 insertions, 11 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_660f.c b/src/dynarec/arm64/dynarec_arm64_660f.c
index 7b4a35a2..689f7143 100644
--- a/src/dynarec/arm64/dynarec_arm64_660f.c
+++ b/src/dynarec/arm64/dynarec_arm64_660f.c
@@ -2157,22 +2157,22 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
             BFIw(xFlags, x1, F_CF, 1);

             break;

         case 0xA4:

+            INST_NAME("SHLD Ew, Gw, Ib");

+            SETFLAGS(X_ALL, SF_SET_PENDING);

+            GETEW(x1, 1);

+            GETGW(x2);

+            u8 = F8;

+            emit_shld16c(dyn, ninst, ed, gd, u8, x4, x5);

+            EWBACK;

+            break;

         case 0xA5:

             nextop = F8;

-            if(opcode==0xA4) {

-                INST_NAME("SHLD Ew, Gw, Ib");

-            } else {

-                INST_NAME("SHLD Ew, Gw, CL");

-                UXTBw(x3, xRCX);

-            }

+            INST_NAME("SHLD Ew, Gw, CL");

+            UXTBw(x3, xRCX);

             MESSAGE(LOG_DUMP, "Need Optimization\n");

             SETFLAGS(X_ALL, SF_SET);

-            GETEWW(x4, x1, (opcode==0xA4)?1:0);

+            GETEWW(x4, x1, 0);

             GETGW(x2);

-            if(opcode==0xA4) {

-                u8 = F8;

-                MOV32w(x3, u8);

-            }

             CALL_(shld16, x1, wback);

             EWBACKW(x1);

             break;

diff --git a/src/dynarec/arm64/dynarec_arm64_emit_shift.c b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
index 6af2c7c9..cb944f8f 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_shift.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
@@ -1298,4 +1298,61 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
+}
+
+void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int s3, int s4)
+{
+    c&=0x1f;
+    IFX(X_PEND) {
+        MOV32w(s3, c);
+        STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
+        STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s4, d_shld16);
+    } else IFX(X_ALL) {
+        SET_DFNONE(s4);
+    }
+    if(c==0) {
+        IFX(X_OF) {
+            BFCw(xFlags, F_OF, 1);
+        }
+        IFX(X_PEND) {
+            STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+    ORRw_REG_LSL(s1, s2, s1, 16);   // create concat first
+    IFX(X_CF) {
+        LSRw(s3, s1, 32-c);
+        BFIw(xFlags, s3, F_CF, 1);
+    }
+    IFX(X_OF) {
+        LSRw(s3, s1, 31);
+        BFIw(xFlags, s3, F_OF, 1);  // store current sign for later use
+    }
+    RORw(s1, s1, c+16);
+
+    IFX(X_PEND) {
+        STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_ZF) {
+        TSTw_mask(s1, 0, 15);   // 0xffff
+        CSETw(s4, cEQ);
+        BFIw(xFlags, s4, F_ZF, 1);
+    }
+    IFX(X_SF) {
+        LSRw(s4, s1, 15);
+        BFIw(xFlags, s4, F_SF, 1);
+    }
+    IFX(X_OF) {
+        if(c==1) {
+            LSRw(s3, s1, 15);
+            EORw_REG_LSR(s3, s3, xFlags, F_OF);  // OF is set if sign changed
+            BFIw(xFlags, s3, F_OF, 1);
+        } else {
+            BFCw(xFlags, F_OF, 1);
+        }
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
 }
\ No newline at end of file
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index ef03ff42..2ce35ee2 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1047,6 +1047,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_shld32     STEPNAME(emit_shld32)
 #define emit_shrd16c    STEPNAME(emit_shrd16c)
 #define emit_shrd16     STEPNAME(emit_shrd16)
+#define emit_shld16c    STEPNAME(emit_shld16c)
 
 #define emit_pf         STEPNAME(emit_pf)
 
@@ -1196,6 +1197,7 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_shld32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4);
 void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int s3, int s4);
 void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3, int s4);
+void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int s3, int s4);
 
 void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);