about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-11-16 10:04:22 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-11-16 10:04:22 +0100
commit5baa0833865379799136eea5541b62fe4044ed9a (patch)
tree86f392d60824d130015abb6473d498242b8d0f44 /src
parent6f7cb088b034d9eda95a603d170b96d8bf3050c4 (diff)
downloadbox64-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.c26
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_shift.c65
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h2
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);