diff options
Diffstat (limited to 'compiler-rt/lib/scudo/standalone/tests/atomic_test.cpp')
-rw-r--r-- | compiler-rt/lib/scudo/standalone/tests/atomic_test.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/compiler-rt/lib/scudo/standalone/tests/atomic_test.cpp b/compiler-rt/lib/scudo/standalone/tests/atomic_test.cpp new file mode 100644 index 00000000000..7e6f1d21f6e --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/tests/atomic_test.cpp @@ -0,0 +1,112 @@ +//===-- atomic_test.cpp -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "scudo/standalone/atomic_helpers.h" +#include "gtest/gtest.h" + +namespace scudo { + +template <typename T> struct ValAndMagic { + typename T::Type Magic0; + T A; + typename T::Type Magic1; + + static ValAndMagic<T> *Sink; +}; + +template <typename T> ValAndMagic<T> *ValAndMagic<T>::Sink; + +template <typename T, memory_order LoadMO, memory_order StoreMO> +void checkStoreLoad() { + typedef typename T::Type Type; + ValAndMagic<T> Val; + // Prevent the compiler from scalarizing the struct. + ValAndMagic<T>::Sink = &Val; + // Ensure that surrounding memory is not overwritten. + Val.Magic0 = Val.Magic1 = (Type)-3; + for (u64 I = 0; I < 100; I++) { + // Generate A value that occupies all bytes of the variable. + u64 V = I; + V |= V << 8; + V |= V << 16; + V |= V << 32; + Val.A.ValDoNotUse = (Type)V; + EXPECT_EQ(atomic_load(&Val.A, LoadMO), (Type)V); + Val.A.ValDoNotUse = (Type)-1; + atomic_store(&Val.A, (Type)V, StoreMO); + EXPECT_EQ(Val.A.ValDoNotUse, (Type)V); + } + EXPECT_EQ(Val.Magic0, (Type)-3); + EXPECT_EQ(Val.Magic1, (Type)-3); +} + +TEST(ScudoAtomicTest, AtomicStoreLoad) { + checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_relaxed>(); + checkStoreLoad<atomic_u8, memory_order_consume, memory_order_relaxed>(); + checkStoreLoad<atomic_u8, memory_order_acquire, memory_order_relaxed>(); + checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_release>(); + checkStoreLoad<atomic_u8, memory_order_seq_cst, memory_order_seq_cst>(); + + checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_relaxed>(); + checkStoreLoad<atomic_u16, memory_order_consume, memory_order_relaxed>(); + checkStoreLoad<atomic_u16, memory_order_acquire, memory_order_relaxed>(); + checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_release>(); + checkStoreLoad<atomic_u16, memory_order_seq_cst, memory_order_seq_cst>(); + + checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_relaxed>(); + checkStoreLoad<atomic_u32, memory_order_consume, memory_order_relaxed>(); + checkStoreLoad<atomic_u32, memory_order_acquire, memory_order_relaxed>(); + checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_release>(); + checkStoreLoad<atomic_u32, memory_order_seq_cst, memory_order_seq_cst>(); + + checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_relaxed>(); + checkStoreLoad<atomic_u64, memory_order_consume, memory_order_relaxed>(); + checkStoreLoad<atomic_u64, memory_order_acquire, memory_order_relaxed>(); + checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_release>(); + checkStoreLoad<atomic_u64, memory_order_seq_cst, memory_order_seq_cst>(); + + checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_relaxed>(); + checkStoreLoad<atomic_uptr, memory_order_consume, memory_order_relaxed>(); + checkStoreLoad<atomic_uptr, memory_order_acquire, memory_order_relaxed>(); + checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_release>(); + checkStoreLoad<atomic_uptr, memory_order_seq_cst, memory_order_seq_cst>(); +} + +template <typename T> void checkAtomicCompareExchange() { + typedef typename T::Type Type; + { + Type OldVal = 42; + Type NewVal = 24; + Type V = OldVal; + EXPECT_TRUE(atomic_compare_exchange_strong( + reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed)); + EXPECT_FALSE(atomic_compare_exchange_strong( + reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed)); + EXPECT_EQ(NewVal, OldVal); + } + { + Type OldVal = 42; + Type NewVal = 24; + Type V = OldVal; + EXPECT_TRUE(atomic_compare_exchange_weak(reinterpret_cast<T *>(&V), &OldVal, + NewVal, memory_order_relaxed)); + EXPECT_FALSE(atomic_compare_exchange_weak( + reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed)); + EXPECT_EQ(NewVal, OldVal); + } +} + +TEST(ScudoAtomicTest, AtomicCompareExchangeTest) { + checkAtomicCompareExchange<atomic_u8>(); + checkAtomicCompareExchange<atomic_u16>(); + checkAtomicCompareExchange<atomic_u32>(); + checkAtomicCompareExchange<atomic_u64>(); + checkAtomicCompareExchange<atomic_uptr>(); +} + +} // namespace scudo |