about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2025-05-07 22:50:37 +0800
committerGitHub <noreply@github.com>2025-05-07 16:50:37 +0200
commit5d14413b89d7bb78023307fc59d2d9da182554a4 (patch)
tree3822c9835ff42632837da6dde40a292e7048247f /src/dynarec
parentec549690944d2768b811340bc999abdfbc60ca2c (diff)
downloadbox64-5d14413b89d7bb78023307fc59d2d9da182554a4.tar.gz
box64-5d14413b89d7bb78023307fc59d2d9da182554a4.zip
[DYNAREC] Use PE volatile metadata in dynarec (#2610)
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c11
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_private.h8
-rw-r--r--src/dynarec/dynarec_helper.h102
-rw-r--r--src/dynarec/dynarec_native_pass.c23
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c6
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.c10
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h6
-rw-r--r--src/dynarec/la64/dynarec_la64_private.h8
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c6
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c10
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h6
-rw-r--r--src/dynarec/rv64/dynarec_rv64_private.h8
14 files changed, 132 insertions, 84 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index 34913701..351e1e0a 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -2387,7 +2387,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3);  // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2398,7 +2398,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 READFLAGS(X_PEND);  // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3);  // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2724,7 +2724,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             INST_NAME("IRET");
             SETFLAGS(X_ALL, SF_SET_NODF);    // Not a hack, EFLAGS are restored
             BARRIER(BARRIER_FLOAT);
-            iret_to_epilog(dyn, ninst, rex.is32bits, rex.w);
+            iret_to_epilog(dyn, ip, ninst, rex.is32bits, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 51f619b2..32f03214 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -30,7 +30,10 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
 {
     MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
 
-    if(l==LOCK_LOCK) { /*SMDMB();*/DMB_ISH(); }
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+        DMB_ISH();
+    }
 
     if(rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, l, s);
@@ -617,7 +620,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
     #endif
 }
 
-void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
+void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn); MAYUSE(ninst);
     MESSAGE(LOG_DUMP, "Ret to epilog\n");
@@ -658,7 +661,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn); MAYUSE(ninst);
     MESSAGE(LOG_DUMP, "Retn to epilog\n");
@@ -705,7 +708,7 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
-void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
+void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
 {
     int64_t j64;
     //#warning TODO: is64bits
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index fa3cff10..f36601e6 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1479,9 +1479,9 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
 // generic x64 helper
 void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
-void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex);
-void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n);
-void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits);
+void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
 void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void call_i(dynarec_arm_t* dyn, int ninst, void* fnc);
 void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index ae615571..60c24aa2 100644
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -109,9 +109,11 @@ typedef struct instruction_arm64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     uint8_t             barrier_maybe;
-    uint8_t             will_write:2; // [strongmem] will write to memory
-    uint8_t             last_write:1; // [strongmem] the last write in a SEQ
-    uint8_t             lock:1;       // [strongmem] lock semantic
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             wfe:1;        // opcode uses sevl + wfe
     uint8_t             set_nat_flags;  // 0 or combinaison of native flags define
     uint8_t             use_nat_flags;  // 0 or combinaison of native flags define
diff --git a/src/dynarec/dynarec_helper.h b/src/dynarec/dynarec_helper.h
index d8b0eb52..f5fbfeee 100644
--- a/src/dynarec/dynarec_helper.h
+++ b/src/dynarec/dynarec_helper.h
@@ -1,6 +1,10 @@
 #ifndef __DYNAREC_HELPER__H_

 #define __DYNAREC_HELPER__H_

 

+#include "env.h"

+#include "pe_tools.h"

+#include "debug.h"

+

 /* Box64 Strong Memory Model Emulation

  *

  * Definition of a SEQ:

@@ -32,6 +36,8 @@
 #define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put

 #define STRONGMEM_SEQ_WRITE  3 // The level of a barrier at every third memory store will be  put

 

+#define STRONGMEM_LEVEL() (box64_wine && VolatileRangesContains(ip) ? 0 : BOX64DRENV(dynarec_strongmem))

+

 #if STEP == 1

 

 #define SMWRITE()                                                \

@@ -49,15 +55,20 @@
         SMWRITE();                     \

     } while (0)

 

-#define SMWRITE2()                                                   \

-    do {                                                             \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) { \

-            dyn->smwrite = 1;                                        \

-            dyn->insts[ninst].will_write = 2;                        \

-        }                                                            \

+#define SMWRITE2()                                       \

+    do {                                                 \

+        if (STRONGMEM_LEVEL() >= STRONGMEM_SIMD_WRITE) { \

+            dyn->smwrite = 1;                            \

+            dyn->insts[ninst].will_write = 2;            \

+        }                                                \

+    } while (0)

+

+#define SMREAD()                                               \

+    do {                                                       \

+        /* Mark that current opcode read from guest memory. */ \

+        dyn->insts[ninst].will_read = 1;                       \

     } while (0)

 

-#define SMREAD()

 #define SMREADLOCK(lock)

 #define WILLWRITE()

 #define WILLWRITELOCK(lock)

@@ -71,7 +82,7 @@
 #define SMEND()                                                                                \

     do {                                                                                       \

         /* If there is any guest memory write, which is a SEQ, then compute the last_write. */ \

-        if (dyn->smwrite && (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE)) {         \

+        if (dyn->smwrite && (STRONGMEM_LEVEL() >= STRONGMEM_LAST_WRITE)) {                     \

             int i = ninst;                                                                     \

             while (i >= 0 && !dyn->insts[i].will_write)                                        \

                 --i;                                                                           \

@@ -85,22 +96,23 @@
 #else

 

 // An opcode writes guest memory, this need to be put after the STORE instruction manually. It will also end the SEQ automaticaly on last_write immediatly

-#define SMWRITE()                                                     \

-    do {                                                              \

-        if(dyn->insts[ninst].last_write) {                            \

-            dyn->smwrite = 1;                                         \

-            SMEND();                                                  \

-        } else {                                                      \

-        /* Put a barrier at every third memory write. */              \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SEQ_WRITE) {   \

-            if (++dyn->smwrite >= 3 /* Every third memory write */) { \

-                DMB_ISH();                                            \

-                dyn->smwrite = 1;                                     \

-            }                                                         \

-        } else {                                                      \

-            /* Mark that current sequence writes to guest memory. */  \

-            dyn->smwrite = 1;                                         \

-        } }                                                           \

+#define SMWRITE()                                                         \

+    do {                                                                  \

+        if (dyn->insts[ninst].last_write) {                               \

+            dyn->smwrite = 1;                                             \

+            SMEND();                                                      \

+        } else {                                                          \

+            /* Put a barrier at every third memory write. */              \

+            if (STRONGMEM_LEVEL() >= STRONGMEM_SEQ_WRITE) {               \

+                if (++dyn->smwrite >= 3 /* Every third memory write */) { \

+                    DMB_ISH();                                            \

+                    dyn->smwrite = 1;                                     \

+                }                                                         \

+            } else {                                                      \

+                /* Mark that current sequence writes to guest memory. */  \

+                dyn->smwrite = 1;                                         \

+            }                                                             \

+        }                                                                 \

     } while (0)

 

 // Similar to SMWRITE, but checks lock.

@@ -114,10 +126,10 @@
     } while (0)

 

 // Similar to SMWRITE, but for SIMD instructions.

-#define SMWRITE2()                                                 \

-    do {                                                           \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) \

-            SMWRITE();                                             \

+#define SMWRITE2()                                     \

+    do {                                               \

+        if (STRONGMEM_LEVEL() >= STRONGMEM_SIMD_WRITE) \

+            SMWRITE();                                 \

     } while (0)

 

 // An opcode reads guest memory, this need to be put before the LOAD instruction manually.

@@ -134,22 +146,22 @@
     } while (0)

 

 // An opcode will write memory, this will be put before the STORE instruction automatically.

-#define WILLWRITE()                                                                                            \

-    do {                                                                                                       \

-        if (BOX64DRENV(dynarec_strongmem) >= dyn->insts[ninst].will_write && dyn->smwrite == 0) {              \

-            /* Will write but never written, this is the start of a SEQ, put a barrier. */                     \

-            if (BOX64ENV(dynarec_weakbarrier))                                                                 \

-                DMB_ISHLD();                                                                                   \

-            else                                                                                               \

-                DMB_ISH();                                                                                     \

-        } else if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE && BOX64ENV(dynarec_weakbarrier) != 2 \

-            && dyn->insts[ninst].last_write) {                                                                 \

-            /* Last write, put a barrier */                                                                    \

-            if (BOX64ENV(dynarec_weakbarrier))                                                                 \

-                DMB_ISHST();                                                                                   \

-            else                                                                                               \

-                DMB_ISH();                                                                                     \

-        }                                                                                                      \

+#define WILLWRITE()                                                                                \

+    do {                                                                                           \

+        if (STRONGMEM_LEVEL() >= dyn->insts[ninst].will_write && dyn->smwrite == 0) {              \

+            /* Will write but never written, this is the start of a SEQ, put a barrier. */         \

+            if (BOX64ENV(dynarec_weakbarrier))                                                     \

+                DMB_ISHLD();                                                                       \

+            else                                                                                   \

+                DMB_ISH();                                                                         \

+        } else if (STRONGMEM_LEVEL() >= STRONGMEM_LAST_WRITE && BOX64ENV(dynarec_weakbarrier) != 2 \

+            && dyn->insts[ninst].last_write) {                                                     \

+            /* Last write, put a barrier */                                                        \

+            if (BOX64ENV(dynarec_weakbarrier))                                                     \

+                DMB_ISHST();                                                                       \

+            else                                                                                   \

+                DMB_ISH();                                                                         \

+        }                                                                                          \

     } while (0)

 

 // Similar to WILLWRITE, but checks lock.

@@ -171,7 +183,7 @@
 // Will be put at the end of the SEQ

 #define SMEND()                                                         \

     do {                                                                \

-        if (BOX64DRENV(dynarec_strongmem)) {                            \

+        if (STRONGMEM_LEVEL()) {                                        \

             /* It's a SEQ, put a barrier here. */                       \

             if (dyn->smwrite) {                                         \

                 /* Check if the next instruction has a end loop mark */ \

diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c
index 1f55ada4..eab3e10b 100644
--- a/src/dynarec/dynarec_native_pass.c
+++ b/src/dynarec/dynarec_native_pass.c
@@ -18,6 +18,7 @@
 #include "dynablock_private.h"
 #include "custommem.h"
 #include "x64test.h"
+#include "pe_tools.h"
 
 #include "dynarec_arch.h"
 #include "dynarec_helper.h"
@@ -132,6 +133,14 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         } else if (dyn->insts[ninst].will_write) {
             WILLWRITE();
         }
+
+        int is_opcode_volatile = box64_wine && VolatileRangesContains(ip);
+        if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed) {
+            if (dyn->insts[ninst].will_write)
+                DMB_ISH();
+            else if (dyn->insts[ninst].will_read)
+                DMB_ISHLD();
+        }
         #endif
         if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
             READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
@@ -149,7 +158,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
             dyn->need_dump = BOX64DRENV(dynarec_dump);
         }
-#ifdef HAVE_TRACE
+        #ifdef HAVE_TRACE
         else if(my_context->dec && BOX64ENV(dynarec_trace)) {
         if((trace_end == 0)
             || ((ip >= trace_start) && (ip < trace_end)))  {
@@ -160,7 +169,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
                 MESSAGE(LOG_DUMP, "----------\n");
             }
         }
-#endif
+        #endif
 
         rep = 0;
         uint8_t pk = PK(0);
@@ -187,6 +196,16 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         if(dyn->abort)
             return ip;
         INST_EPILOG;
+
+        #if STEP > 1
+        if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed) {
+            if (dyn->insts[ninst].will_write)
+                DMB_ISHST();
+            else if (dyn->insts[ninst].will_read)
+                DMB_ISHLD();
+        }
+        #endif
+
         fpu_reset_scratch(dyn);
         int next = ninst+1;
         #if STEP > 0
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index b44b3e75..4811bbac 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -1854,7 +1854,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -1864,7 +1864,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2032,7 +2032,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             INST_NAME("IRET");
             SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Not a hack, EFLAGS are restored
             BARRIER(BARRIER_FLOAT);
-            iret_to_epilog(dyn, ninst, rex.w);
+            iret_to_epilog(dyn, ip, ninst, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c
index c76690d9..b6fc31c2 100644
--- a/src/dynarec/la64/dynarec_la64_helper.c
+++ b/src/dynarec/la64/dynarec_la64_helper.c
@@ -35,6 +35,10 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
     MAYUSE(ninst);
     MAYUSE(delta);
 
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+    }
+
     if (rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, scratch, fixaddress, l, i12);
 
@@ -572,7 +576,7 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
     JIRL((dyn->insts[ninst].x64.has_callret ? xRA : xZR), x2, 0x0); // save LR...
 }
 
-void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
+void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -611,7 +615,7 @@ void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -656,7 +660,7 @@ void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
-void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits)
+void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits)
 {
     // #warning TODO: is64bits
     MAYUSE(ninst);
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index 7d472bf6..8dfa9970 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -1011,9 +1011,9 @@ uintptr_t geted32(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
 void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
-void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex);
-void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n);
-void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits);
+void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits);
 void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
 void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);
diff --git a/src/dynarec/la64/dynarec_la64_private.h b/src/dynarec/la64/dynarec_la64_private.h
index 2244b122..4bc621bd 100644
--- a/src/dynarec/la64/dynarec_la64_private.h
+++ b/src/dynarec/la64/dynarec_la64_private.h
@@ -93,9 +93,11 @@ typedef struct instruction_la64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     uint8_t             barrier_maybe;
-    uint8_t             will_write;
-    uint8_t             last_write;
-    uint8_t             lock;
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             df_notneeded;
     uint8_t             nat_flags_fusion:1;
     uint8_t             nat_flags_nofusion:1;
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index 2dfa119e..c10742db 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -285,7 +285,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -296,7 +296,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -553,7 +553,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             INST_NAME("IRET");
             SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Not a hack, EFLAGS are restored
             BARRIER(BARRIER_FLOAT);
-            iret_to_epilog(dyn, ninst, rex.w);
+            iret_to_epilog(dyn, ip, ninst, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index f436ea18..4d584d35 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -34,6 +34,10 @@ uintptr_t geted(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
     MAYUSE(ninst);
     MAYUSE(delta);
 
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+    }
+
     if (rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, scratch, fixaddress, l, i12);
 
@@ -601,7 +605,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
 #endif
 }
 
-void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
+void ret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -664,7 +668,7 @@ void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -732,7 +736,7 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
-void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits)
+void iret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, int is64bits)
 {
     // #warning TODO: is64bits
     MAYUSE(ninst);
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 48886fbd..900245fb 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -1434,9 +1434,9 @@ uintptr_t geted32(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
 void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
-void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex);
-void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n);
-void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits);
+void ret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, int is64bits);
 void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
 void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w);
 void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h
index 80507b49..16ea574f 100644
--- a/src/dynarec/rv64/dynarec_rv64_private.h
+++ b/src/dynarec/rv64/dynarec_rv64_private.h
@@ -125,9 +125,11 @@ typedef struct instruction_rv64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     int                 barrier_maybe;
-    uint8_t             will_write;
-    uint8_t             last_write;
-    uint8_t             lock;
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             df_notneeded;
     uint8_t             nat_flags_fusion:1;
     uint8_t             nat_flags_nofusion:1;