about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-11-14 18:54:40 +0100
committerptitSeb <sebastien.chev@gmail.com>2024-11-14 18:54:40 +0100
commit8c17a37d1ae4258e7a7a7fdf87a43305f40dc2a1 (patch)
treecc5e5cfb52ca5ca707e8a26b9a4dbc4b0fc2a324 /src
parent979a3232f9d23c34b6c8c86fb3913fb34b3da333 (diff)
downloadbox64-8c17a37d1ae4258e7a7a7fdf87a43305f40dc2a1.tar.gz
box64-8c17a37d1ae4258e7a7a7fdf87a43305f40dc2a1.zip
[ARM64_DYNAREC] Reworked 8/16/32/64bits TEST opcodes
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/arm64_emitter.h1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_64.c3
-rw-r--r--src/dynarec/arm64/dynarec_arm64_66.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_67.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_tests.c243
-rw-r--r--src/dynarec/arm64/dynarec_arm64_f0.c3
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h6
8 files changed, 236 insertions, 38 deletions
diff --git a/src/dynarec/arm64/arm64_emitter.h b/src/dynarec/arm64/arm64_emitter.h
index a4269283..ec16b71b 100644
--- a/src/dynarec/arm64/arm64_emitter.h
+++ b/src/dynarec/arm64/arm64_emitter.h
@@ -598,6 +598,7 @@ int convert_bitmask(uint64_t bitmask);
 #define ANDSx_REG(Rd, Rn, Rm)          FEMIT(LOGIC_REG_gen(1, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
 #define ANDSw_REG(Rd, Rn, Rm)          FEMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
 #define ANDSxw_REG(Rd, Rn, Rm)         FEMIT(LOGIC_REG_gen(rex.w, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
+#define ANDSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, lsl, Rn, Rd))
 #define ORRx_REG(Rd, Rn, Rm)            EMIT(LOGIC_REG_gen(1, 0b01, 0b00, 0, Rm, 0, Rn, Rd))
 #define ORRx_REG_LSL(Rd, Rn, Rm, lsl)   EMIT(LOGIC_REG_gen(1, 0b01, 0b00, 0, Rm, lsl, Rn, Rd))
 #define ORRw_REG_LSL(Rd, Rn, Rm, lsl)   EMIT(LOGIC_REG_gen(0, 0b01, 0b00, 0, Rm, lsl, Rn, Rd))
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index f1bc34f7..cd886163 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -1690,8 +1690,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             INST_NAME("TEST EAX, Id");
             SETFLAGS(X_ALL, SF_SET_PENDING);
             i64 = F32S;
-            MOV64xw(x2, i64);
-            emit_test32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
+            emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
             break;
         case 0xAA:
             WILLWRITE();
@@ -3335,8 +3334,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     SETFLAGS(X_ALL, SF_SET_PENDING);
                     GETEDH(x1, 4);
                     i64 = F32S;
-                    MOV64xw(x2, i64);
-                    emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
+                    emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
                     break;
                 case 2:
                     INST_NAME("NOT Ed");
diff --git a/src/dynarec/arm64/dynarec_arm64_64.c b/src/dynarec/arm64/dynarec_arm64_64.c
index 9ad0be88..636b9b02 100644
--- a/src/dynarec/arm64/dynarec_arm64_64.c
+++ b/src/dynarec/arm64/dynarec_arm64_64.c
@@ -1306,8 +1306,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     SETFLAGS(X_ALL, SF_SET_PENDING);
                     GETEDO(x6, 4);
                     i64 = F32S;
-                    MOV64xw(x2, i64);
-                    emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
+                    emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
                     break;
                 case 2:
                     INST_NAME("NOT Ed");
diff --git a/src/dynarec/arm64/dynarec_arm64_66.c b/src/dynarec/arm64/dynarec_arm64_66.c
index 0c6ef67b..c6e209c5 100644
--- a/src/dynarec/arm64/dynarec_arm64_66.c
+++ b/src/dynarec/arm64/dynarec_arm64_66.c
@@ -860,9 +860,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             INST_NAME("TEST AX,Iw");

             SETFLAGS(X_ALL, SF_SET_PENDING);

             u16 = F16;

-            MOV32w(x2, u16);

             UBFXx(x1, xRAX, 0, 16);

-            emit_test16(dyn, ninst, x1, x2, x3, x4, x5);

+            emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);

             break;

 

         case 0xAB:

@@ -1329,8 +1328,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     SETFLAGS(X_ALL, SF_SET_PENDING);

                     GETEW(x1, 2);

                     u16 = F16;

-                    MOV32w(x2, u16);

-                    emit_test16(dyn, ninst, x1, x2, x3, x4, x5);

+                    emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);

                     break;

                 case 2:

                     INST_NAME("NOT Ew");

diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c
index a77d88a5..bce01f5c 100644
--- a/src/dynarec/arm64/dynarec_arm64_67.c
+++ b/src/dynarec/arm64/dynarec_arm64_67.c
@@ -1204,8 +1204,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             INST_NAME("TEST EAX, Id");

             SETFLAGS(X_ALL, SF_SET_PENDING);

             i64 = F32S;

-            MOV64xw(x2, i64);

-            emit_test32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);

+            emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);

             break;

 

         case 0xC1:

@@ -1445,8 +1444,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     SETFLAGS(X_ALL, SF_SET_PENDING);

                     GETED32H(x1, 4);

                     i64 = F32S;

-                    MOV64xw(x2, i64);

-                    emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);

+                    emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);

                     break;

                 case 2:

                     INST_NAME("NOT Ed");

diff --git a/src/dynarec/arm64/dynarec_arm64_emit_tests.c b/src/dynarec/arm64/dynarec_arm64_emit_tests.c
index 77937ab0..1c78fa53 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_tests.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_tests.c
@@ -354,22 +354,37 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
 }
 
-// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
-void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
+void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
 {
-    MAYUSE(s1); MAYUSE(s2);
+    MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
+    int mask = convert_bitmask_xw(c);
     IFX_PENDOR0 {
-        SET_DF(s3, d_tst16);
+        SET_DF(s3, rex.w?d_tst64:d_tst32);
     } else {
         SET_DFNONE(s4);
     }
-    IFX(X_CF | X_AF | X_OF) {
-        MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
-        BICw(xFlags, xFlags, s3);
+    IFX(X_CF) {
+        IFNATIVE(NF_CF) {} else {
+            BFCw(xFlags, F_CF, 1);
+        }
+    }
+    IFX(X_OF) {
+        IFNATIVE(NF_VF) {} else {
+            BFCw(xFlags, F_OF, 1);
+        }
+    }
+    IFX(X_AF) {
+        BFCw(xFlags, F_AF, 1);
+    }
+    if(mask) {
+        ANDSxw_mask(s3, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
+    } else {
+        MOV64xw(s3, c);
+        ANDSxw_REG(s3, s1, s3);   // res = s1 & s2
     }
-    ANDSw_REG(s5, s1, s2);   // res = s1 & s2
     IFX_PENDOR0 {
-        STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
+        STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_ZF) {
         IFNATIVE(NF_EQ) {} else {
@@ -378,8 +393,117 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
         }
     }
     IFX(X_SF) {
-        LSRw(s4, s5, 15);
-        BFIw(xFlags, s4, F_SF, 1);
+        IFNATIVE(NF_SF) {} else {
+            LSRxw(s4, s3, rex.w?63:31);
+            BFIw(xFlags, s4, F_SF, 1);
+        }
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s3, s5);
+    }
+}
+
+// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
+void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    MAYUSE(s1); MAYUSE(s2);
+    IFX_PENDOR0 {
+        SET_DF(s3, d_tst16);
+    } else {
+        SET_DFNONE(s4);
+    }
+    IFX(X_CF|X_ZF|X_SF|X_OF) {
+        LSLw(s5, s1, 16);
+        ANDSw_REG_LSL(s5, s5, s2, 16);
+        IFX(X_ZF) {
+            IFNATIVE(NF_EQ) {} else {
+                CSETw(s4, cEQ);
+                BFIw(xFlags, s4, F_ZF, 1);
+            }
+        }
+        IFX(X_CF) {
+            IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
+        }
+        IFX(X_OF) {
+            IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
+        }
+        IFX(X_SF) {
+            IFNATIVE(NF_SF) {} else {
+                CSETw(s4, cMI);
+                BFIw(xFlags, s4, F_SF, 1);
+            }
+        }
+        IFX(X_PF|X_PEND) {
+            LSRw(s5, s5, 16);
+        }
+    } else {
+        ANDw_REG(s5, s1, s2);   // res = s1 & s2
+    }
+    IFX(X_AF) {
+        BFCw(xFlags, F_AF, 1);
+    }
+    IFX_PENDOR0 {
+        STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s5, s4);
+    }
+}
+
+// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
+void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
+{
+    MAYUSE(s1);
+    int mask = 0;
+    IFX_PENDOR0 {
+        SET_DF(s3, d_tst16);
+    } else {
+        SET_DFNONE(s4);
+    }
+    IFX(X_CF|X_ZF|X_SF|X_OF) {
+        LSLw(s5, s1, 16);
+        mask = convert_bitmask_w(c<<16);
+        if(mask) {
+            ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
+        } else {
+            MOV32w(s3, c);
+            ANDSw_REG_LSL(s5, s5, s3, 16);
+        }
+        IFX(X_ZF) {
+            IFNATIVE(NF_EQ) {} else {
+                CSETw(s4, cEQ);
+                BFIw(xFlags, s4, F_ZF, 1);
+            }
+        }
+        IFX(X_CF) {
+            IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
+        }
+        IFX(X_OF) {
+            IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
+        }
+        IFX(X_SF) {
+            IFNATIVE(NF_SF) {} else {
+                CSETw(s4, cMI);
+                BFIw(xFlags, s4, F_SF, 1);
+            }
+        }
+        IFX(X_PF|X_PEND) {
+            LSRw(s5, s5, 16);
+        }
+    } else {
+        mask = convert_bitmask_w(c);
+        if(mask) {
+            ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
+        } else {
+            MOV32w(s5, c);
+            ANDw_REG(s5, s1, s5);   // res = s1 & s2
+        }
+    }
+    IFX(X_AF) {
+        BFCw(xFlags, F_AF, 1);
+    }
+    IFX_PENDOR0 {
+        STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_PF) {
         emit_pf(dyn, ninst, s5, s4);
@@ -395,23 +519,98 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
     } else {
         SET_DFNONE(s4);
     }
-    IFX(X_CF | X_AF | X_OF) {
-        MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
-        BICw(xFlags, xFlags, s3);
+    IFX(X_CF|X_ZF|X_SF|X_OF) {
+        LSLw(s5, s1, 24);
+        ANDSw_REG_LSL(s5, s5, s2, 24);
+        IFX(X_ZF) {
+            IFNATIVE(NF_EQ) {} else {
+                CSETw(s4, cEQ);
+                BFIw(xFlags, s4, F_ZF, 1);
+            }
+        }
+        IFX(X_CF) {
+            IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
+        }
+        IFX(X_OF) {
+            IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
+        }
+        IFX(X_SF) {
+            IFNATIVE(NF_SF) {} else {
+                CSETw(s4, cMI);
+                BFIw(xFlags, s4, F_SF, 1);
+            }
+        }
+        IFX(X_PF|X_PEND) {
+            LSRw(s5, s5, 24);
+        }
+    } else {
+        ANDw_REG(s5, s1, s2);   // res = s1 & s2
+    }
+    IFX(X_AF) {
+        BFCw(xFlags, F_AF, 1);
     }
-    ANDSw_REG(s5, s1, s2);   // res = s1 & s2
     IFX_PENDOR0 {
         STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        IFNATIVE(NF_EQ) {} else {
-            CSETw(s4, cEQ);
-            BFIw(xFlags, s4, F_ZF, 1);
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s5, s4);
+    }
+}
+
+// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
+void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
+{
+    MAYUSE(s1);
+    int mask = 0;
+    IFX_PENDOR0 {
+        SET_DF(s3, d_tst8);
+    } else {
+        SET_DFNONE(s4);
+    }
+    IFX(X_CF|X_ZF|X_SF|X_OF) {
+        LSLw(s5, s1, 24);
+        mask = convert_bitmask_w(c<<24);
+        if(mask) {
+            ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
+        } else {
+            MOV32w(s3, c);
+            ANDSw_REG_LSL(s5, s5, s3, 24);
+        }
+        IFX(X_ZF) {
+            IFNATIVE(NF_EQ) {} else {
+                CSETw(s4, cEQ);
+                BFIw(xFlags, s4, F_ZF, 1);
+            }
+        }
+        IFX(X_CF) {
+            IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
+        }
+        IFX(X_OF) {
+            IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
+        }
+        IFX(X_SF) {
+            IFNATIVE(NF_SF) {} else {
+                CSETw(s4, cMI);
+                BFIw(xFlags, s4, F_SF, 1);
+            }
+        }
+        IFX(X_PF|X_PEND) {
+            LSRw(s5, s5, 24);
+        }
+    } else {
+        mask = convert_bitmask_w(c);
+        if(mask) {
+            ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
+        } else {
+            MOV32w(s5, c);
+            ANDw_REG(s5, s1, s5);   // res = s1 & s2
         }
     }
-    IFX(X_SF) {
-        LSRw(s4, s5, 7);
-        BFIw(xFlags, s4, F_SF, 1);
+    IFX(X_AF) {
+        BFCw(xFlags, F_AF, 1);
+    }
+    IFX_PENDOR0 {
+        STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_PF) {
         emit_pf(dyn, ninst, s5, s4);
diff --git a/src/dynarec/arm64/dynarec_arm64_f0.c b/src/dynarec/arm64/dynarec_arm64_f0.c
index 26f594d8..00cb91f2 100644
--- a/src/dynarec/arm64/dynarec_arm64_f0.c
+++ b/src/dynarec/arm64/dynarec_arm64_f0.c
@@ -1579,8 +1579,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     SMDMB();
                     GETEB(x1, 1);
                     u8 = F8;
-                    MOV32w(x2, u8);
-                    emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
+                    emit_test8c(dyn, ninst, x1, u8, x3, x4, x5);
                     break;
                 case 2:
                     INST_NAME("LOCK NOT Eb");
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index 5b4e5c1d..803e15e1 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1275,8 +1275,11 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_cmp16_0    STEPNAME(emit_cmp16_0)
 #define emit_cmp32_0    STEPNAME(emit_cmp32_0)
 #define emit_test8      STEPNAME(emit_test8)
+#define emit_test8c     STEPNAME(emit_test8c)
 #define emit_test16     STEPNAME(emit_test16)
+#define emit_test16c    STEPNAME(emit_test16c)
 #define emit_test32     STEPNAME(emit_test32)
+#define emit_test32c    STEPNAME(emit_test32c)
 #define emit_add32      STEPNAME(emit_add32)
 #define emit_add32c     STEPNAME(emit_add32c)
 #define emit_add8       STEPNAME(emit_add8)
@@ -1440,8 +1443,11 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
 void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
 void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
 void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
+void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
 void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
+void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
 void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
+void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
 void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
 void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
 void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);