about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-11-16 11:00:09 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-11-16 11:00:09 +0100
commit19a24c2171cd943e7b1398c5636c666e07efe6d4 (patch)
treefb5f66a9a0f2a00b64e24dfa401f44dfda4d6935 /src
parentf7d75ca641ec6de4a35421fe206f8608ee531a20 (diff)
downloadbox64-19a24c2171cd943e7b1398c5636c666e07efe6d4.tar.gz
box64-19a24c2171cd943e7b1398c5636c666e07efe6d4.zip
[ARM64_DYNAREC] Optimized 66 AC opcode
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_660f.c20
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_shift.c54
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h2
-rw-r--r--src/emu/x64run_private.c14
4 files changed, 78 insertions, 12 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_660f.c b/src/dynarec/arm64/dynarec_arm64_660f.c
index ba330878..47586faf 100644
--- a/src/dynarec/arm64/dynarec_arm64_660f.c
+++ b/src/dynarec/arm64/dynarec_arm64_660f.c
@@ -2207,22 +2207,22 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
             }

             break;

         case 0xAC:

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

+            SETFLAGS(X_ALL, SF_SET_PENDING);

+            GETEW(x1, 1);

+            GETGW(x2);

+            u8 = F8;

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

+            EWBACK;

+            break;

         case 0xAD:

             nextop = F8;

-            if(opcode==0xAC) {

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

-            } else {

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

-                UXTBw(x3, xRCX);

-            }

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

+            UXTBw(x3, xRCX);

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

             SETFLAGS(X_ALL, SF_SET);

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

             GETGW(x2);

-            if(opcode==0xAC) {

-                u8 = F8;

-                MOV32w(x3, u8);

-            }

             CALL_(shrd16, 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 7b504321..bab869b7 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_shift.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
@@ -1005,7 +1005,6 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
         MOV32w(s3, c);
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
         STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
-        // same flags computation as with shl64/shl32
         SET_DF(s4, rex.w?d_shrd64:d_shrd32);
     } else IFX(X_ALL) {
         SET_DFNONE(s4);
@@ -1152,3 +1151,56 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
         emit_pf(dyn, ninst, s1, s3, s4);
     }
 }
+
+// emit SHRD16 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
+void emit_shrd16c(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_shrd16);
+    } else IFX(X_ALL) {
+        SET_DFNONE(s4);
+    }
+    if(!c) {
+        IFX(X_PEND) {
+            STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+    IFX(X_CF) {
+        BFXILw(xFlags, s1, c-1, 1);    // set CF
+    }
+    IFX(X_OF) {
+        if(c==1) {
+            LSRw(s4, s1, 15);
+            BFIw(xFlags, s4, F_OF, 1);  // store sign for later use
+        }
+    }
+    ORRw_REG_LSL(s1, s1, s2, 16);
+    LSRw_IMM(s1, s1, c);
+    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(s4, s1, 15);
+            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 91273cea..6102c9bc 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1044,6 +1044,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_shrd32c    STEPNAME(emit_shrd32c)
 #define emit_shld32c    STEPNAME(emit_shld32c)
 #define emit_shrd32     STEPNAME(emit_shrd32)
+#define emit_shrd16c    STEPNAME(emit_shrd16c)
 
 #define emit_pf         STEPNAME(emit_pf)
 
@@ -1190,6 +1191,7 @@ void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
 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_shrd16c(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);
 
diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c
index f50c32cc..a5a588c2 100644
--- a/src/emu/x64run_private.c
+++ b/src/emu/x64run_private.c
@@ -692,6 +692,19 @@ void UpdateFlags(x64emu_t *emu)
                 }
             }
             break;
+        case d_shrd16:
+            cnt = emu->op2.u16;
+            if (cnt > 0) {
+                cc = emu->op1.u16 & (1 << (cnt - 1));
+                CONDITIONAL_SET_FLAG(cc, F_CF);
+                CONDITIONAL_SET_FLAG(!emu->res.u16, F_ZF);
+                CONDITIONAL_SET_FLAG(emu->res.u16 & 0x8000, F_SF);
+                CONDITIONAL_SET_FLAG(PARITY(emu->res.u16 & 0xff), F_PF);
+                if (cnt == 1) {
+                    CONDITIONAL_SET_FLAG((emu->op1.u16 ^ emu->res.u16) & 0x8000, F_OF);
+                }
+            }
+            break;
         case d_shrd32:
             cnt = emu->op2.u32;
             if (cnt > 0) {
@@ -1001,7 +1014,6 @@ void UpdateFlags(x64emu_t *emu)
         case d_rcr16:
         case d_rcr32:
         case d_rcr64:
-        case d_shrd16:
         case d_unknown:
             printf_log(LOG_NONE, "Box64: %p trying to evaluate Unknown deferred Flags\n", (void*)R_RIP);
             break;