about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorphorcys <phorcys@126.com>2025-07-09 14:10:14 +0800
committerGitHub <noreply@github.com>2025-07-09 08:10:14 +0200
commitaeec79ec008e373fa9797f3fabb0a03261526fe6 (patch)
tree9d9424e31ddb2cffac66da6a53338aad778c4a8c
parentb1971c8ef3e7206ecc60993065f2c948af756d9b (diff)
downloadbox64-aeec79ec008e373fa9797f3fabb0a03261526fe6.tar.gz
box64-aeec79ec008e373fa9797f3fabb0a03261526fe6.zip
[LA64_DYNAREC] Add la64 avx bitwise ops. (#2780)
* avx  VEX.66.0F 54/55/56/57  VANDPD/VANDNPD/VORPD/VXORPD
  * avx  VEX.0F    54/55/56/57  VANDPS/VANDNPS/VORPS/VXORPS
  * avx  VEX.66.0F DB/DF/EB/EF  VPAND/VPANDN/VPOR/VPXOR
  * bmi1 VEX.0F38    F2  ANDN
  * bmi2 VEX.F2.0F3A F0  RORX
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/dynarec/la64/dynarec_la64_avx.c16
-rw-r--r--src/dynarec/la64/dynarec_la64_avx_0f.c24
-rw-r--r--src/dynarec/la64/dynarec_la64_avx_0f38.c87
-rw-r--r--src/dynarec/la64/dynarec_la64_avx_66_0f.c48
-rw-r--r--src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c72
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h56
-rw-r--r--src/dynarec/la64/la64_emitter.h35
8 files changed, 307 insertions, 33 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9d86097..6050b3b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1097,10 +1097,12 @@ if(LARCH64_DYNAREC)
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f.c"
+    "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f38.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f38.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f3a.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f.c"
+    "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c"
     "${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f3_0f.c"
     )
 endif()
diff --git a/src/dynarec/la64/dynarec_la64_avx.c b/src/dynarec/la64/dynarec_la64_avx.c
index 1a8a14a7..12e00db2 100644
--- a/src/dynarec/la64/dynarec_la64_avx.c
+++ b/src/dynarec/la64/dynarec_la64_avx.c
@@ -51,8 +51,8 @@ uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int n
 
     if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_NONE))
         addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
-    // else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_NONE))
-    //     addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
+    else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_NONE))
+        addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
     else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_66))
         addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
     else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_F2))
@@ -65,17 +65,17 @@ uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int n
         addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
     // else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2))
     //     addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
-    // else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_F2))
-    //     addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
+    else if ((vex.m == VEX_M_0F3A) && (vex.p == VEX_P_F2))
+        addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
     // else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F3))
     //     addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
     else {
         DEFAULT;
     }
 
-    if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
-        if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || dyn->need_dump) {
-            dynarec_log(LOG_NONE, "  Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
-    }
+    if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
+        if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) {
+            dynarec_log(LOG_NONE, "  Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
+        }
     return addr;
 }
\ No newline at end of file
diff --git a/src/dynarec/la64/dynarec_la64_avx_0f.c b/src/dynarec/la64/dynarec_la64_avx_0f.c
index 52243184..47208926 100644
--- a/src/dynarec/la64/dynarec_la64_avx_0f.c
+++ b/src/dynarec/la64/dynarec_la64_avx_0f.c
@@ -233,6 +233,30 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
                 VPICKVE2GR_DU(gd, d1, 0);
             }
             break;
+        case 0x54:
+            INST_NAME("VANDPS Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VAND_Vxy(v0, v1, v2);
+            break;
+        case 0x55:
+            INST_NAME("VANDNPS Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VANDN_Vxy(v0, v1, v2);
+            break;
+        case 0x56:
+            INST_NAME("VORPS Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VOR_Vxy(v0, v1, v2);
+            break;
+        case 0x57:
+            INST_NAME("VXORPS Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VXOR_Vxy(v0, v1, v2);
+            break;
         case 0x77:
             if (!vex.l) {
                 INST_NAME("VZEROUPPER");
diff --git a/src/dynarec/la64/dynarec_la64_avx_0f38.c b/src/dynarec/la64/dynarec_la64_avx_0f38.c
new file mode 100644
index 00000000..fd2bcf5d
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_avx_0f38.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "env.h"
+#include "box64context.h"
+#include "box64cpu.h"
+#include "emu/x64emu_private.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "../dynarec_helper.h"
+
+uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
+{
+    (void)ip;
+    (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8;
+    uint8_t gd, ed, vd;
+    uint8_t wback, wb1, wb2;
+    uint8_t eb1, eb2, gb1, gb2;
+    int32_t i32, i32_;
+    int cacheupd = 0;
+    int v0, v1, v2;
+    int q0, q1, q2;
+    int d0, d1, d2;
+    int s0;
+    uint64_t tmp64u;
+    int64_t j64;
+    int64_t fixedaddress;
+    int unscaled;
+    MAYUSE(wb1);
+    MAYUSE(wb2);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(gb1);
+    MAYUSE(gb2);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(s0);
+    MAYUSE(j64);
+    MAYUSE(cacheupd);
+
+    rex_t rex = vex.rex;
+
+    switch (opcode) {
+        case 0xF2:
+            INST_NAME("ANDN Gd, Vd, Ed");
+            nextop = F8;
+            SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
+            GETGD;
+            GETED(0);
+            GETVD;
+            ANDN(gd, ed, vd);
+            if (!rex.w) {
+                BSTRPICK_D(gd, gd, 31, 0);
+            }
+            CLEAR_FLAGS(x6);
+            IFX (X_SF) {
+                SRLI_D(x6, gd, rex.w ? 63 : 31);
+                BEQZ(x6, 8);
+                ORI(xFlags, xFlags, 1 << F_SF);
+            }
+            IFX (X_ZF) {
+                BNEZ(gd, 8);
+                ORI(xFlags, xFlags, 1 << F_ZF);
+            }
+            SPILL_EFLAGS();
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_avx_66_0f.c b/src/dynarec/la64/dynarec_la64_avx_66_0f.c
index db6f4c96..3f04d192 100644
--- a/src/dynarec/la64/dynarec_la64_avx_66_0f.c
+++ b/src/dynarec/la64/dynarec_la64_avx_66_0f.c
@@ -227,6 +227,30 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
                 VPICKVE2GR_DU(gd, d1, 0);
             }
             break;
+        case 0x54:
+            INST_NAME("VANDPD Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VAND_Vxy(v0, v1, v2);
+            break;
+        case 0x55:
+            INST_NAME("VANDNPD Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VANDN_Vxy(v0, v1, v2);
+            break;
+        case 0x56:
+            INST_NAME("VORPD Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VOR_Vxy(v0, v1, v2);
+            break;
+        case 0x57:
+            INST_NAME("VXORPD Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VXOR_Vxy(v0, v1, v2);
+            break;
         case 0x6E:
             INST_NAME("VMOVD Gx, Ed");
             nextop = F8;
@@ -334,6 +358,18 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
                 VPICKVE2GR_DU(gd, d1, 0);
             }
             break;
+        case 0xDB:
+            INST_NAME("VPAND Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VAND_Vxy(v0, v1, v2);
+            break;
+        case 0xDF:
+            INST_NAME("VPANDN Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VANDN_Vxy(v0, v1, v2);
+            break;
         case 0xE7:
             INST_NAME("VMOVNTDQ Ex, Gx");
             nextop = F8;
@@ -350,6 +386,18 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
                 SMWRITE2();
             }
             break;
+        case 0xEB:
+            INST_NAME("VPOR Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VOR_Vxy(v0, v1, v2);
+            break;
+        case 0xEF:
+            INST_NAME("VPXOR Gx, Vx, Ex");
+            nextop = F8;
+            GETGY_empty_VYEY_xy(v0, v1, v2, 0);
+            VXOR_Vxy(v0, v1, v2);
+            break;
         case 0xF7:
             INST_NAME("VMASKMOVDQU Gx, Ex");
             nextop = F8;
diff --git a/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c b/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c
new file mode 100644
index 00000000..4181c68c
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "env.h"
+#include "box64context.h"
+#include "box64cpu.h"
+#include "emu/x64emu_private.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "../dynarec_helper.h"
+
+uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
+{
+    (void)ip;
+    (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8;
+    uint8_t gd, ed, vd;
+    uint8_t wback, wb1, wb2;
+    uint8_t eb1, eb2, gb1, gb2;
+    int32_t i32, i32_;
+    int cacheupd = 0;
+    int v0, v1, v2;
+    int q0, q1, q2;
+    int d0, d1, d2;
+    int s0;
+    uint64_t tmp64u;
+    int64_t j64;
+    int64_t fixedaddress;
+    int unscaled;
+    MAYUSE(wb1);
+    MAYUSE(wb2);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(gb1);
+    MAYUSE(gb2);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(s0);
+    MAYUSE(j64);
+    MAYUSE(cacheupd);
+
+    rex_t rex = vex.rex;
+
+    switch (opcode) {
+        case 0xF0:
+            INST_NAME("RORX Gd, Ed, Ib");
+            nextop = F8;
+            GETGD;
+            GETED(1);
+            u8 = F8;
+            ROTRIxw(gd, ed, u8 & (rex.w ? 0x3f : 0x1f));
+            break;
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index 010742dd..9e636cda 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -38,6 +38,8 @@
 
 // GETGD    get x64 register in gd
 #define GETGD gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
+// GETVD    get x64 register in vd
+#define GETVD vd = TO_NAT(vex.v)
 
 // GETGW extract x64 register in gd, that is i
 #define GETGW(i)                                        \
@@ -327,7 +329,7 @@
     }
 
 #define VEXTRINS_IMM_4_0(n, m) ((n & 0xf) << 4 | (m & 0xf))
-#define XVPERMI_IMM_4_0(n, m) ((n & 0xf) << 4 | (m & 0xf))
+#define XVPERMI_IMM_4_0(n, m)  ((n & 0xf) << 4 | (m & 0xf))
 
 // Get GX as a quad (might use x1)
 #define GETGX(a, w)                             \
@@ -435,9 +437,9 @@
         BSTRINS_D(wback, ed, wb2 + 7, wb2); \
     }
 
-#define YMM_UNMARK_UPPER_ZERO(a)                                  \
-    do {                                         \
-        dyn->lsx.avxcache[a].zero_upper = 0;     \
+#define YMM_UNMARK_UPPER_ZERO(a)             \
+    do {                                     \
+        dyn->lsx.avxcache[a].zero_upper = 0; \
     } while (0)
 
 // AVX helpers
@@ -608,36 +610,36 @@
     }
 
 // Get empty GY, and non-written VY and EY
-#define GETGY_empty_VYEY_xy(gx, vx, ex, D)  \
-    GETVYxy(vx, 0);                         \
-    GETEYxy(ex, 0, D);                      \
+#define GETGY_empty_VYEY_xy(gx, vx, ex, D) \
+    GETVYxy(vx, 0);                        \
+    GETEYxy(ex, 0, D);                     \
     GETGYxy_empty(gx);
 
 // Get empty GY, and non-written EY
-#define GETGY_empty_EY_xy(gx, ex, D)  \
-    GETEYxy(ex, 0, D);                \
+#define GETGY_empty_EY_xy(gx, ex, D) \
+    GETEYxy(ex, 0, D);               \
     GETGYxy_empty(gx);
 
 // Get writable GY, and non-written VY and EY
-#define GETGY_VYEY_xy(gx, vx, ex, D)  \
-    GETVYxy(vx, 0);                   \
-    GETEYxy(ex, 0, D);                \
+#define GETGY_VYEY_xy(gx, vx, ex, D) \
+    GETVYxy(vx, 0);                  \
+    GETEYxy(ex, 0, D);               \
     GETGYxy(gx, 1);
 
 // Get writable GY, and non-written EY
-#define GETGY_EY_xy(gx, ex, D)  \
-    GETEYxy(ex, 0, D);          \
+#define GETGY_EY_xy(gx, ex, D) \
+    GETEYxy(ex, 0, D);         \
     GETGYxy(gx, 1);
 
 // Get writable EY, and non-written VY and GY
-#define GETEY_VYGY_xy(ex, vx, gx, D)  \
-    GETVYxy(vx, 0);                   \
-    GETGYxy(gx, 0);                   \
+#define GETEY_VYGY_xy(ex, vx, gx, D) \
+    GETVYxy(vx, 0);                  \
+    GETGYxy(gx, 0);                  \
     GETEYxy(ex, 1, D);
 
 // Get writable EY, and non-written GY
-#define GETEY_GY_xy(ex, gx, D)  \
-    GETGYxy(gx, 0);             \
+#define GETEY_GY_xy(ex, gx, D) \
+    GETGYxy(gx, 0);            \
     GETEYxy(ex, 1, D);
 
 // Get direction with size Z and based of F_DF flag, on register r ready for load/store fetching
@@ -1095,10 +1097,12 @@
 #define dynarec64_F20F        STEPNAME(dynarec64_F20F)
 #define dynarec64_AVX         STEPNAME(dynarec64_AVX)
 #define dynarec64_AVX_0F      STEPNAME(dynarec64_AVX_0F)
+#define dynarec64_AVX_0F38    STEPNAME(dynarec64_AVX_0F38)
 #define dynarec64_AVX_66_0F   STEPNAME(dynarec64_AVX_66_0F)
 #define dynarec64_AVX_66_0F38 STEPNAME(dynarec64_AVX_66_0F38)
 #define dynarec64_AVX_66_0F3A STEPNAME(dynarec64_AVX_66_0F3A)
-#define dynarec64_AVX_F2_0F   STEPNAME(dynarec64_AVX_F3_0F)
+#define dynarec64_AVX_F2_0F   STEPNAME(dynarec64_AVX_F2_0F)
+#define dynarec64_AVX_F2_0F3A STEPNAME(dynarec64_AVX_F2_0F3A)
 #define dynarec64_AVX_F3_0F   STEPNAME(dynarec64_AVX_F3_0F)
 
 #define geted               STEPNAME(geted)
@@ -1198,11 +1202,11 @@
 #define sse_forget_reg    STEPNAME(sse_forget_reg)
 #define sse_reflect_reg   STEPNAME(sse_reflect_reg)
 
-#define avx_get_reg            STEPNAME(avx_get_reg)
-#define avx_get_reg_empty      STEPNAME(avx_get_reg_empty)
-#define avx_forget_reg         STEPNAME(sse_forget_reg)
-#define avx_reflect_reg        STEPNAME(avx_reflect_reg)
-#define avx_purgecache         STEPNAME(avx_purgecache)
+#define avx_get_reg              STEPNAME(avx_get_reg)
+#define avx_get_reg_empty        STEPNAME(avx_get_reg_empty)
+#define avx_forget_reg           STEPNAME(sse_forget_reg)
+#define avx_reflect_reg          STEPNAME(avx_reflect_reg)
+#define avx_purgecache           STEPNAME(avx_purgecache)
 #define avx_reflect_reg_upper128 STEPNAME(avx_reflect_reg_upper128)
 
 
@@ -1385,10 +1389,12 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
 uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
+uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
+uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
 
 
diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h
index f9c9782c..00ca7bdd 100644
--- a/src/dynarec/la64/la64_emitter.h
+++ b/src/dynarec/la64/la64_emitter.h
@@ -2622,4 +2622,39 @@ LSX instruction starts with V, LASX instruction starts with XV.
         }                   \
     } while (0)
 
+#define VAND_Vxy(vd, vj, vk)     \
+    do {                         \
+        if (vex.l) {             \
+            XVAND_V(vd, vj, vk); \
+        } else {                 \
+            VAND_V(vd, vj, vk);  \
+        }                        \
+    } while (0)
+
+#define VANDN_Vxy(vd, vj, vk)     \
+    do {                          \
+        if (vex.l) {              \
+            XVANDN_V(vd, vj, vk); \
+        } else {                  \
+            VANDN_V(vd, vj, vk);  \
+        }                         \
+    } while (0)
+
+#define VOR_Vxy(vd, vj, vk)     \
+    do {                        \
+        if (vex.l) {            \
+            XVOR_V(vd, vj, vk); \
+        } else {                \
+            VOR_V(vd, vj, vk);  \
+        }                       \
+    } while (0)
+
+#define VXOR_Vxy(vd, vj, vk)     \
+    do {                         \
+        if (vex.l) {             \
+            XVXOR_V(vd, vj, vk); \
+        } else {                 \
+            VXOR_V(vd, vj, vk);  \
+        }                        \
+    } while (0)
 #endif //__ARM64_EMITTER_H__