[compiler-rt] fd184c0 - [TSAN] Honor failure memory orders in AtomicCAS

Bruno Cardoso Lopes via llvm-commits llvm-commits at lists.llvm.org
Thu May 13 01:07:53 PDT 2021


Author: Bruno Cardoso Lopes
Date: 2021-05-13T01:07:22-07:00
New Revision: fd184c062c1a1b4727ddf0452ebab11fb8834880

URL: https://github.com/llvm/llvm-project/commit/fd184c062c1a1b4727ddf0452ebab11fb8834880
DIFF: https://github.com/llvm/llvm-project/commit/fd184c062c1a1b4727ddf0452ebab11fb8834880.diff

LOG: [TSAN] Honor failure memory orders in AtomicCAS

LLVM has lifted strong requirements for CAS failure memory orders in 431e3138a and 819e0d105e84.

Add support for honoring them in `AtomicCAS`.

https://github.com/google/sanitizers/issues/970

Differential Revision: https://reviews.llvm.org/D99434

Added: 
    compiler-rt/test/tsan/compare_exchange.cpp

Modified: 
    compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp
    llvm/test/Instrumentation/ThreadSanitizer/atomic.ll

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp b/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp
index 3f459aff532cb..16b4e2218cf1a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp
@@ -402,34 +402,45 @@ static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
 template<typename T>
 static bool AtomicCAS(ThreadState *thr, uptr pc,
     volatile T *a, T *c, T v, morder mo, morder fmo) {
-  (void)fmo;  // Unused because llvm does not pass it yet.
+  // 31.7.2.18: "The failure argument shall not be memory_order_release
+  // nor memory_order_acq_rel". LLVM (2021-05) fallbacks to Monotonic
+  // (mo_relaxed) when those are used.
+  CHECK(IsLoadOrder(fmo));
+
   MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
   SyncVar *s = 0;
-  bool write_lock = mo != mo_acquire && mo != mo_consume;
-  if (mo != mo_relaxed) {
+  bool write_lock = IsReleaseOrder(mo);
+
+  if (mo != mo_relaxed || fmo != mo_relaxed)
     s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock);
+
+  T cc = *c;
+  T pr = func_cas(a, cc, v);
+  bool success = pr == cc;
+  if (!success) {
+    *c = pr;
+    mo = fmo;
+  }
+
+  if (s) {
     thr->fast_state.IncrementEpoch();
     // Can't increment epoch w/o writing to the trace as well.
     TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
-    if (IsAcqRelOrder(mo))
+
+    if (success && IsAcqRelOrder(mo))
       AcquireReleaseImpl(thr, pc, &s->clock);
-    else if (IsReleaseOrder(mo))
+    else if (success && IsReleaseOrder(mo))
       ReleaseImpl(thr, pc, &s->clock);
     else if (IsAcquireOrder(mo))
       AcquireImpl(thr, pc, &s->clock);
-  }
-  T cc = *c;
-  T pr = func_cas(a, cc, v);
-  if (s) {
+
     if (write_lock)
       s->mtx.Unlock();
     else
       s->mtx.ReadUnlock();
   }
-  if (pr == cc)
-    return true;
-  *c = pr;
-  return false;
+
+  return success;
 }
 
 template<typename T>

diff  --git a/compiler-rt/test/tsan/compare_exchange.cpp b/compiler-rt/test/tsan/compare_exchange.cpp
new file mode 100644
index 0000000000000..d48bde86b88ee
--- /dev/null
+++ b/compiler-rt/test/tsan/compare_exchange.cpp
@@ -0,0 +1,106 @@
+// RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t && %deflake %env_tsan_opts=atexit_sleep_ms=50 %run %t 2>&1 | FileCheck --check-prefix=CHECK-REPORT %s
+
+#include <atomic>
+#include <cassert>
+#include <stdio.h>
+#include <thread>
+
+#define NUM_ORDS 16
+#define NUM_THREADS NUM_ORDS * 2
+struct node {
+  int val;
+};
+std::atomic<node *> _nodes[NUM_THREADS] = {};
+
+void f1(int i) {
+  auto n = new node();
+  n->val = 42;
+  _nodes[i].store(n, std::memory_order_release);
+}
+
+template <int version>
+void f2(int i, std::memory_order mo, std::memory_order fmo) {
+  node *expected = nullptr;
+  while (expected == nullptr) {
+    _nodes[i].compare_exchange_weak(expected, nullptr, mo, fmo);
+  };
+
+  ++expected->val;
+  assert(expected->val == 43);
+}
+
+struct MemOrdSuccFail {
+  std::memory_order mo;
+  std::memory_order fmo;
+};
+
+MemOrdSuccFail OrdList[NUM_ORDS] = {
+    {std::memory_order_release, std::memory_order_relaxed},
+    {std::memory_order_release, std::memory_order_acquire},
+    {std::memory_order_release, std::memory_order_consume},
+    {std::memory_order_release, std::memory_order_seq_cst},
+
+    {std::memory_order_acq_rel, std::memory_order_relaxed},
+    {std::memory_order_acq_rel, std::memory_order_acquire},
+    {std::memory_order_acq_rel, std::memory_order_consume},
+    {std::memory_order_acq_rel, std::memory_order_seq_cst},
+
+    {std::memory_order_seq_cst, std::memory_order_relaxed},
+    {std::memory_order_seq_cst, std::memory_order_acquire},
+    {std::memory_order_seq_cst, std::memory_order_consume},
+    {std::memory_order_seq_cst, std::memory_order_seq_cst},
+
+    {std::memory_order_relaxed, std::memory_order_relaxed},
+    {std::memory_order_relaxed, std::memory_order_acquire},
+    {std::memory_order_relaxed, std::memory_order_consume},
+    {std::memory_order_relaxed, std::memory_order_seq_cst},
+};
+
+int main() {
+  std::thread threads[NUM_THREADS];
+  int ords = 0;
+
+  // Instantiate a new f2 for each MO so we can dedup reports and actually
+  // make sure relaxed FMO triggers a warning for every 
diff erent MO.
+  for (unsigned t = 0; t < 8; t += 2) {
+    threads[t] = std::thread(f1, t);
+    threads[t + 1] = std::thread(f2<0>, t, OrdList[ords].mo, OrdList[ords].fmo);
+    threads[t].join();
+    threads[t + 1].join();
+    ords++;
+  }
+
+  for (unsigned t = 8; t < 16; t += 2) {
+    threads[t] = std::thread(f1, t);
+    threads[t + 1] = std::thread(f2<1>, t, OrdList[ords].mo, OrdList[ords].fmo);
+    threads[t].join();
+    threads[t + 1].join();
+    ords++;
+  }
+
+  for (unsigned t = 16; t < 24; t += 2) {
+    threads[t] = std::thread(f1, t);
+    threads[t + 1] = std::thread(f2<2>, t, OrdList[ords].mo, OrdList[ords].fmo);
+    threads[t].join();
+    threads[t + 1].join();
+    ords++;
+  }
+
+  for (unsigned t = 24; t < 32; t += 2) {
+    threads[t] = std::thread(f1, t);
+    threads[t + 1] = std::thread(f2<3>, t, OrdList[ords].mo, OrdList[ords].fmo);
+    threads[t].join();
+    threads[t + 1].join();
+    ords++;
+  }
+
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK-REPORT: WARNING: ThreadSanitizer: data race
+// CHECK-REPORT: WARNING: ThreadSanitizer: data race
+// CHECK-REPORT: WARNING: ThreadSanitizer: data race
+// CHECK-REPORT: WARNING: ThreadSanitizer: data race
+// CHECK-REPORT: DONE
+// CHECK-REPORT: ThreadSanitizer: reported 4 warnings
\ No newline at end of file

diff  --git a/llvm/test/Instrumentation/ThreadSanitizer/atomic.ll b/llvm/test/Instrumentation/ThreadSanitizer/atomic.ll
index a7fd60a052f99..7615c80f66c5d 100644
--- a/llvm/test/Instrumentation/ThreadSanitizer/atomic.ll
+++ b/llvm/test/Instrumentation/ThreadSanitizer/atomic.ll
@@ -349,41 +349,61 @@ entry:
 define void @atomic8_cas_monotonic(i8* %a) nounwind uwtable {
 entry:
   cmpxchg i8* %a, i8 0, i8 1 monotonic monotonic, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 monotonic acquire, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 monotonic seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic8_cas_monotonic
 ; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0, i32 0), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0, i32 2), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 0, i32 5), !dbg
 
 define void @atomic8_cas_acquire(i8* %a) nounwind uwtable {
 entry:
+  cmpxchg i8* %a, i8 0, i8 1 acquire monotonic, !dbg !7
   cmpxchg i8* %a, i8 0, i8 1 acquire acquire, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 acquire seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic8_cas_acquire
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2, i32 0), !dbg
 ; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2, i32 2), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 2, i32 5), !dbg
 
 define void @atomic8_cas_release(i8* %a) nounwind uwtable {
 entry:
   cmpxchg i8* %a, i8 0, i8 1 release monotonic, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 release acquire, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 release seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic8_cas_release
 ; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3, i32 0), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3, i32 2), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 3, i32 5), !dbg
 
 define void @atomic8_cas_acq_rel(i8* %a) nounwind uwtable {
 entry:
+  cmpxchg i8* %a, i8 0, i8 1 acq_rel monotonic, !dbg !7
   cmpxchg i8* %a, i8 0, i8 1 acq_rel acquire, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 acq_rel seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic8_cas_acq_rel
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4, i32 0), !dbg
 ; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4, i32 2), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 4, i32 5), !dbg
 
 define void @atomic8_cas_seq_cst(i8* %a) nounwind uwtable {
 entry:
+  cmpxchg i8* %a, i8 0, i8 1 seq_cst monotonic, !dbg !7
+  cmpxchg i8* %a, i8 0, i8 1 seq_cst acquire, !dbg !7
   cmpxchg i8* %a, i8 0, i8 1 seq_cst seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic8_cas_seq_cst
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5, i32 0), !dbg
+; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5, i32 2), !dbg
 ; CHECK: call i8 @__tsan_atomic8_compare_exchange_val(i8* %a, i8 0, i8 1, i32 5, i32 5), !dbg
 
 define i16 @atomic16_load_unordered(i16* %a) nounwind uwtable {
@@ -733,41 +753,61 @@ entry:
 define void @atomic16_cas_monotonic(i16* %a) nounwind uwtable {
 entry:
   cmpxchg i16* %a, i16 0, i16 1 monotonic monotonic, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 monotonic acquire, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 monotonic seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic16_cas_monotonic
 ; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0, i32 0), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0, i32 2), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 0, i32 5), !dbg
 
 define void @atomic16_cas_acquire(i16* %a) nounwind uwtable {
 entry:
+  cmpxchg i16* %a, i16 0, i16 1 acquire monotonic, !dbg !7
   cmpxchg i16* %a, i16 0, i16 1 acquire acquire, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 acquire seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic16_cas_acquire
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2, i32 0), !dbg
 ; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2, i32 2), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 2, i32 5), !dbg
 
 define void @atomic16_cas_release(i16* %a) nounwind uwtable {
 entry:
   cmpxchg i16* %a, i16 0, i16 1 release monotonic, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 release acquire, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 release seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic16_cas_release
 ; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3, i32 0), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3, i32 2), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 3, i32 5), !dbg
 
 define void @atomic16_cas_acq_rel(i16* %a) nounwind uwtable {
 entry:
+  cmpxchg i16* %a, i16 0, i16 1 acq_rel monotonic, !dbg !7
   cmpxchg i16* %a, i16 0, i16 1 acq_rel acquire, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 acq_rel seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic16_cas_acq_rel
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4, i32 0), !dbg
 ; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4, i32 2), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 4, i32 5), !dbg
 
 define void @atomic16_cas_seq_cst(i16* %a) nounwind uwtable {
 entry:
+  cmpxchg i16* %a, i16 0, i16 1 seq_cst monotonic, !dbg !7
+  cmpxchg i16* %a, i16 0, i16 1 seq_cst acquire, !dbg !7
   cmpxchg i16* %a, i16 0, i16 1 seq_cst seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic16_cas_seq_cst
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5, i32 0), !dbg
+; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5, i32 2), !dbg
 ; CHECK: call i16 @__tsan_atomic16_compare_exchange_val(i16* %a, i16 0, i16 1, i32 5, i32 5), !dbg
 
 define i32 @atomic32_load_unordered(i32* %a) nounwind uwtable {
@@ -1117,41 +1157,61 @@ entry:
 define void @atomic32_cas_monotonic(i32* %a) nounwind uwtable {
 entry:
   cmpxchg i32* %a, i32 0, i32 1 monotonic monotonic, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 monotonic acquire, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 monotonic seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic32_cas_monotonic
 ; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0, i32 0), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0, i32 2), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 0, i32 5), !dbg
 
 define void @atomic32_cas_acquire(i32* %a) nounwind uwtable {
 entry:
+  cmpxchg i32* %a, i32 0, i32 1 acquire monotonic, !dbg !7
   cmpxchg i32* %a, i32 0, i32 1 acquire acquire, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 acquire seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic32_cas_acquire
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2, i32 0), !dbg
 ; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2, i32 2), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 2, i32 5), !dbg
 
 define void @atomic32_cas_release(i32* %a) nounwind uwtable {
 entry:
   cmpxchg i32* %a, i32 0, i32 1 release monotonic, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 release acquire, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 release seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic32_cas_release
 ; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3, i32 0), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3, i32 2), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 3, i32 5), !dbg
 
 define void @atomic32_cas_acq_rel(i32* %a) nounwind uwtable {
 entry:
+  cmpxchg i32* %a, i32 0, i32 1 acq_rel monotonic, !dbg !7
   cmpxchg i32* %a, i32 0, i32 1 acq_rel acquire, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 acq_rel seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic32_cas_acq_rel
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4, i32 0), !dbg
 ; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4, i32 2), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 4, i32 5), !dbg
 
 define void @atomic32_cas_seq_cst(i32* %a) nounwind uwtable {
 entry:
+  cmpxchg i32* %a, i32 0, i32 1 seq_cst monotonic, !dbg !7
+  cmpxchg i32* %a, i32 0, i32 1 seq_cst acquire, !dbg !7
   cmpxchg i32* %a, i32 0, i32 1 seq_cst seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic32_cas_seq_cst
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5, i32 0), !dbg
+; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5, i32 2), !dbg
 ; CHECK: call i32 @__tsan_atomic32_compare_exchange_val(i32* %a, i32 0, i32 1, i32 5, i32 5), !dbg
 
 define i64 @atomic64_load_unordered(i64* %a) nounwind uwtable {
@@ -1521,41 +1581,61 @@ entry:
 define void @atomic64_cas_monotonic(i64* %a) nounwind uwtable {
 entry:
   cmpxchg i64* %a, i64 0, i64 1 monotonic monotonic, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 monotonic acquire, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 monotonic seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic64_cas_monotonic
 ; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0, i32 0), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0, i32 2), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 0, i32 5), !dbg
 
 define void @atomic64_cas_acquire(i64* %a) nounwind uwtable {
 entry:
+  cmpxchg i64* %a, i64 0, i64 1 acquire monotonic, !dbg !7
   cmpxchg i64* %a, i64 0, i64 1 acquire acquire, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 acquire seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic64_cas_acquire
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2, i32 0), !dbg
 ; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2, i32 2), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 2, i32 5), !dbg
 
 define void @atomic64_cas_release(i64* %a) nounwind uwtable {
 entry:
   cmpxchg i64* %a, i64 0, i64 1 release monotonic, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 release acquire, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 release seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic64_cas_release
 ; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3, i32 0), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3, i32 2), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 3, i32 5), !dbg
 
 define void @atomic64_cas_acq_rel(i64* %a) nounwind uwtable {
 entry:
+  cmpxchg i64* %a, i64 0, i64 1 acq_rel monotonic, !dbg !7
   cmpxchg i64* %a, i64 0, i64 1 acq_rel acquire, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 acq_rel seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic64_cas_acq_rel
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4, i32 0), !dbg
 ; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4, i32 2), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 4, i32 5), !dbg
 
 define void @atomic64_cas_seq_cst(i64* %a) nounwind uwtable {
 entry:
+  cmpxchg i64* %a, i64 0, i64 1 seq_cst monotonic, !dbg !7
+  cmpxchg i64* %a, i64 0, i64 1 seq_cst acquire, !dbg !7
   cmpxchg i64* %a, i64 0, i64 1 seq_cst seq_cst, !dbg !7
   ret void, !dbg !7
 }
 ; CHECK-LABEL: atomic64_cas_seq_cst
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 0), !dbg
+; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 2), !dbg
 ; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 5), !dbg
 
 define void @atomic64_cas_seq_cst_ptr_ty(i8** %a, i8* %v1, i8* %v2) nounwind uwtable {


        


More information about the llvm-commits mailing list