[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