about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-06-18 11:22:57 +0200
committerptitSeb <sebastien.chev@gmail.com>2021-06-18 11:22:57 +0200
commit3dcef655c37cc2e9656cb79007ab4f6ad6da5b67 (patch)
treef41edbf1c6cc37dab8c433f973d249c33d891813 /src
parent4c476de74b8124c2f70c18e7397199a41105c065 (diff)
downloadbox64-3dcef655c37cc2e9656cb79007ab4f6ad6da5b67.tar.gz
box64-3dcef655c37cc2e9656cb79007ab4f6ad6da5b67.zip
[DYNAREC] Optimized DIV/IDIV 32/64bits opcodes
Diffstat (limited to 'src')
-rwxr-xr-xsrc/dynarec/arm64_emitter.h22
-rwxr-xr-xsrc/dynarec/arm64_printer.c13
-rwxr-xr-xsrc/dynarec/dynarec_arm64_00.c78
-rwxr-xr-xsrc/dynarec/dynarec_arm64_helper.h10
4 files changed, 112 insertions, 11 deletions
diff --git a/src/dynarec/arm64_emitter.h b/src/dynarec/arm64_emitter.h
index b64413ef..3114d214 100755
--- a/src/dynarec/arm64_emitter.h
+++ b/src/dynarec/arm64_emitter.h
@@ -580,13 +580,27 @@
 #define UMULH(Xd, Xn, Xm)               EMIT(MULH_gen(1, Xm, Xn, Xd))
 #define SMULH(Xd, Xn, Xm)               EMIT(MULH_gen(0, Xm, Xn, Xd))
 
-#define MADD_gen(sf, Rm, Ra, Rn, Rd)    ((sf)<<31 | 0b11011<<24 | (Rm)<<16 | (Ra)<<10 | (Rn)<<5 | (Rd))
-#define MADDx(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(1, Rm, Ra, Rn, Rd))
-#define MADDw(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(0, Rm, Ra, Rn, Rd))
-#define MADDxw(Rd, Rn, Rm, Ra)          EMIT(MADD_gen(rex.w, Rm, Ra, Rn, Rd))
+#define MADD_gen(sf, Rm, o0, Ra, Rn, Rd)    ((sf)<<31 | 0b11011<<24 | (Rm)<<16 | (o0)<<15 | (Ra)<<10 | (Rn)<<5 | (Rd))
+#define MADDx(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(1, Rm, 0, Ra, Rn, Rd))
+#define MADDw(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(0, Rm, 0, Ra, Rn, Rd))
+#define MADDxw(Rd, Rn, Rm, Ra)          EMIT(MADD_gen(rex.w, Rm, 0, Ra, Rn, Rd))
 #define MULx(Rd, Rn, Rm)                MADDx(Rd, Rn, Rm, xZR)
 #define MULw(Rd, Rn, Rm)                MADDw(Rd, Rn, Rm, xZR)
 #define MULxw(Rd, Rn, Rm)               MADDxw(Rd, Rn, Rm, xZR)
+#define MSUBx(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(1, Rm, 1, Ra, Rn, Rd))
+#define MSUBw(Rd, Rn, Rm, Ra)           EMIT(MADD_gen(0, Rm, 1, Ra, Rn, Rd))
+#define MSUBxw(Rd, Rn, Rm, Ra)          EMIT(MADD_gen(rex.w, Rm, 1, Ra, Rn, Rd))
+#define MNEGx(Rd, Rn, Rm)               EMIT(MADD_gen(1, Rm, 1, xZR, Rn, Rd))
+#define MNEGw(Rd, Rn, Rm)               EMIT(MADD_gen(0, Rm, 1, xZR, Rn, Rd))
+#define MNEGxw(Rd, Rn, Rm)              EMIT(MADD_gen(rex.w, Rm, 1, xZR, Rn, Rd))
+
+
+// DIV
+#define DIV_gen(sf, Rm, o1, Rn, Rd)     ((sf)<<31 | 0b11010110<<21 | (Rm)<<16 | 0b00001<<11 | (o1)<<10 | (Rn)<<5 | (Rd))
+#define UDIVw(Wd, Wn, Wm)               EMIT(DIV_gen(0, Wm, 0, Wn, Wd))
+#define UDIVx(Xd, Xn, Xm)               EMIT(DIV_gen(1, Xm, 0, Xn, Xd))
+#define SDIVw(Wd, Wn, Wm)               EMIT(DIV_gen(0, Wm, 1, Wn, Wd))
+#define SDIVx(Xd, Xn, Xm)               EMIT(DIV_gen(1, Xm, 1, Xn, Xd))
 
 // CLZ
 #define CL_gen(sf, op, Rn, Rd)          ((sf)<<31 | 1<<30 | 0b11010110<<21 | 0b00010<<11 | (op)<<10 | (Rn)<<5 | (Rd))
diff --git a/src/dynarec/arm64_printer.c b/src/dynarec/arm64_printer.c
index f0ca7f36..b2c90dda 100755
--- a/src/dynarec/arm64_printer.c
+++ b/src/dynarec/arm64_printer.c
@@ -777,6 +777,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
             snprintf(buff, sizeof(buff), "MADD %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], sf?Xt[Ra]:Wt[Ra]);

         return buff;

     }

+    if(isMask(opcode, "f0011011000mmmmm1aaaaannnnnddddd", &a)) {

+        if(Ra==31)

+            snprintf(buff, sizeof(buff), "MNEG %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]);

+        else

+            snprintf(buff, sizeof(buff), "MSUB %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], sf?Xt[Ra]:Wt[Ra]);

+        return buff;

+    }

+

+    // DIV

+    if(isMask(opcode, "f0011010110mmmmm00001onnnnnddddd", &a)) {

+        snprintf(buff, sizeof(buff), "%cDIV %s, %s, %s", option?'S':'U', sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]);

+        return buff;

+    }

 

     // MRS / MSR

     if(isMask(opcode, "110101010001opppnnnnmmmm222ttttt", &a)) {

diff --git a/src/dynarec/dynarec_arm64_00.c b/src/dynarec/dynarec_arm64_00.c
index 4e0721d2..3a136b12 100755
--- a/src/dynarec/dynarec_arm64_00.c
+++ b/src/dynarec/dynarec_arm64_00.c
@@ -35,13 +35,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
     uint8_t gb1, gb2, eb1, eb2;
     uint32_t u32;
     uint64_t u64;
-    uint8_t wback, wb1, wb2;
+    uint8_t wback, wb1, wb2, wb;
     int64_t fixedaddress;
 
     opcode = F8;
     MAYUSE(eb1);
     MAYUSE(eb2);
     MAYUSE(j64);
+    MAYUSE(wb);
 
     switch(opcode) {
         case 0x00:
@@ -2171,16 +2172,79 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 case 6:
                     INST_NAME("DIV Ed");
                     SETFLAGS(X_ALL, SF_SET);
-                    GETEDH(x1, 0);
-                    if(ed!=x1) {MOVxw_REG(x1, ed);}
-                    CALL(rex.w?((void*)div64):((void*)div32), -1);
+                    if(!rex.w) {
+                        SET_DFNONE(x2);
+                        GETED(0);
+                        MOVw_REG(x3, xRAX);
+                        ORRx_REG_LSL(x3, x3, xRDX, 32);
+                        if(MODREG) {
+                            MOVw_REG(x4, ed);
+                            ed = x4;
+                        }
+                        UDIVx(x2, x3, ed);
+                        MSUBx(x4, x2, ed, xRAX);
+                        MOVw_REG(xRAX, x2);
+                        MOVw_REG(xRDX, x4);
+                    } else {
+                        if(ninst && dyn->insts 
+                           && dyn->insts[ninst-1].x64.addr 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
+                            SET_DFNONE(x2);
+                            GETED(0);
+                            UDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                        } else {
+                            GETEDH(x1, 0);  // get edd changed addr, so cannot be called 2 times for same op...
+                            CBZxw_MARK(xRDX);
+                            if(ed!=x1) {MOVxw_REG(x1, ed);}
+                            CALL(div64, -1);
+                            B_NEXT_nocond;
+                            MARK;
+                            UDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVx_REG(xRAX, x2);
+                            SET_DFNONE(x2);
+                        }
+                    }
                     break;
                 case 7:
                     INST_NAME("IDIV Ed");
                     SETFLAGS(X_ALL, SF_SET);
-                    GETEDH(x1, 0);
-                    if(ed!=x1) {MOVxw_REG(x1, ed);}
-                    CALL(rex.w?((void*)idiv64):((void*)idiv32), -1);
+                    if(!rex.w) {
+                        SET_DFNONE(x2)
+                        GETSEDw(0);
+                        MOVw_REG(x3, xRAX);
+                        ORRx_REG_LSL(x3, x3, xRDX, 32);
+                        SDIVx(x2, x3, wb);
+                        MSUBx(x4, x2, wb, x3);
+                        MOVw_REG(xRAX, x2);
+                        MOVw_REG(xRDX, x4);
+                    } else {
+                        if(ninst && dyn->insts
+                           &&  dyn->insts[ninst-1].x64.addr 
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x99) {
+                            SET_DFNONE(x2)
+                            GETED(0);
+                            SDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVw_REG(xRAX, x2);
+                        } else {
+                            GETEDH(x1, 0);  // get edd changed addr, so cannot be called 2 times for same op...
+                            CBZxw_MARK(xRDX);
+                            MVNx_REG(x2, xRDX);
+                            CBZxw_MARK(x2);
+                            if(ed!=x1) {MOVxw_REG(x1, ed);}
+                            CALL((void*)idiv64, -1);
+                            B_NEXT_nocond;
+                            MARK;
+                            SDIVx(x2, xRAX, ed);
+                            MSUBx(xRDX, x2, ed, xRAX);
+                            MOVw_REG(xRAX, x2);
+                            SET_DFNONE(x2)
+                        }
+                    }
                     break;
             }
             break;
diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h
index cf778874..aae92a2d 100755
--- a/src/dynarec/dynarec_arm64_helper.h
+++ b/src/dynarec/dynarec_arm64_helper.h
@@ -59,6 +59,16 @@
                     LDRw_U12(x1, wback, fixedaddress);  \
                     ed = x1;                            \
                 }
+#define GETSEDw(D)  if((nextop&0xC0)==0xC0) {           \
+                    ed = xRAX+(nextop&7)+(rex.b<<3);    \
+                    SXTWx(x1, ed);                      \
+                    wb = x1;                            \
+                    wback = 0;                          \
+                } else {                                \
+                    addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
+                    LDRw_U12(x1, wback, fixedaddress);  \
+                    wb = ed = x1;                       \
+                }
 //GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI
 #define GETEDH(hint, D) if(MODREG) {                    \
                     ed = xRAX+(nextop&7)+(rex.b<<3);    \