fix undefined behavior in memset due to missing sequence points
[musl] / arch / mips / atomic_arch.h
index ce2823b..1248d17 100644 (file)
@@ -1,12 +1,24 @@
+#if __mips_isa_rev < 6
+#define LLSC_M "m"
+#else
+#define LLSC_M "ZC"
+#endif
+
 #define a_ll a_ll
 static inline int a_ll(volatile int *p)
 {
        int v;
+#if __mips < 2
        __asm__ __volatile__ (
                ".set push ; .set mips2\n\t"
                "ll %0, %1"
                "\n\t.set pop"
                : "=r"(v) : "m"(*p));
+#else
+       __asm__ __volatile__ (
+               "ll %0, %1"
+               : "=r"(v) : LLSC_M(*p));
+#endif
        return v;
 }
 
@@ -14,26 +26,33 @@ static inline int a_ll(volatile int *p)
 static inline int a_sc(volatile int *p, int v)
 {
        int r;
+#if __mips < 2
        __asm__ __volatile__ (
                ".set push ; .set mips2\n\t"
                "sc %0, %1"
                "\n\t.set pop"
                : "=r"(r), "=m"(*p) : "0"(v) : "memory");
+#else
+       __asm__ __volatile__ (
+               "sc %0, %1"
+               : "=r"(r), "="LLSC_M(*p) : "0"(v) : "memory");
+#endif
        return r;
 }
 
 #define a_barrier a_barrier
 static inline void a_barrier()
 {
+#if __mips < 2
        /* mips2 sync, but using too many directives causes
         * gcc not to inline it, so encode with .long instead. */
        __asm__ __volatile__ (".long 0xf" : : : "memory");
-#if 0
-       __asm__ __volatile__ (
-               ".set push ; .set mips2 ; sync ; .set pop"
-               : : : "memory");
+#else
+       __asm__ __volatile__ ("sync" : : : "memory");
 #endif
 }
 
 #define a_pre_llsc a_barrier
 #define a_post_llsc a_barrier
+
+#undef LLSC_M