forked from OSchip/llvm-project
[TSAN] Honor failure memory orders in AtomicCAS
LLVM has lifted strong requirements for CAS failure memory orders in431e3138a
and819e0d105e
. Add support for honoring them in `AtomicCAS`. https://github.com/google/sanitizers/issues/970 Differential Revision: https://reviews.llvm.org/D99434
This commit is contained in:
parent
b2186a69c1
commit
fd184c062c
|
@ -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>
|
||||
|
|
|
@ -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 different 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
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue