Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
317 changes: 317 additions & 0 deletions runtime/include/latomic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
#pragma once

#include <atomic>

namespace ltest {

// This class is intended to be the entry point
// for the weak memory logic later.
template <class T>
class latomic {
std::atomic<T> atomicValue;

public:
#if __cplusplus >= 201703L // C++17
static constexpr bool is_always_lock_free =
std::atomic<T>::is_always_lock_free;
#endif

// Constructors
constexpr latomic() noexcept = default;
constexpr latomic(T desired) noexcept : atomicValue(desired) {}
latomic(const latomic&) = delete;
latomic& operator=(const latomic&) = delete;
latomic& operator=(const latomic&) volatile = delete;

// operator=
T operator=(T desired) noexcept {
store(desired);
return desired;
}

T operator=(T desired) volatile noexcept {
store(desired);
return desired;
}

// is_lock_free
bool is_lock_free() const noexcept { return atomicValue.is_lock_free(); }

bool is_lock_free() const volatile noexcept {
return atomicValue.is_lock_free();
}

// store
void store(T desired,
std::memory_order order = std::memory_order_seq_cst) noexcept {
atomicValue.store(desired, order);
}

void store(T desired, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
atomicValue.store(desired, order);
}

// load
T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
return atomicValue.load(order);
}

T load(std::memory_order order = std::memory_order_seq_cst) const
volatile noexcept {
return atomicValue.load(order);
}

// operator T()
operator T() const noexcept { return atomicValue.load(); }

operator T() const volatile noexcept { return atomicValue.load(); }

// exchange
T exchange(T desired,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.exchange(desired, order);
}

T exchange(T desired, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.exchange(desired, order);
}

// compare_exchange_weak
bool compare_exchange_weak(T& expected, T desired, std::memory_order success,
std::memory_order failure) noexcept {
return atomicValue.compare_exchange_weak(expected, desired, success,
failure);
}

bool compare_exchange_weak(T& expected, T desired, std::memory_order success,
std::memory_order failure) volatile noexcept {
return atomicValue.compare_exchange_weak(expected, desired, success,
failure);
}

bool compare_exchange_weak(
T& expected, T desired,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.compare_exchange_weak(expected, desired, order);
}

bool compare_exchange_weak(
T& expected, T desired,
std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
return atomicValue.compare_exchange_weak(expected, desired, order);
}

// compare_exchange_strong
bool compare_exchange_strong(T& expected, T desired,
std::memory_order success,
std::memory_order failure) noexcept {
return atomicValue.compare_exchange_strong(expected, desired, success,
failure);
}

bool compare_exchange_strong(T& expected, T desired,
std::memory_order success,
std::memory_order failure) volatile noexcept {
return atomicValue.compare_exchange_strong(expected, desired, success,
failure);
}

bool compare_exchange_strong(
T& expected, T desired,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.compare_exchange_strong(expected, desired, order);
}

bool compare_exchange_strong(
T& expected, T desired,
std::memory_order order = std::memory_order_seq_cst) volatile noexcept {
return atomicValue.compare_exchange_strong(expected, desired, order);
}

// wait
#if __cplusplus >= 202002L // C++20
void wait(T old, std::memory_order order =
std::memory_order_seq_cst) const noexcept {
atomicValue.wait(old, order);
}

void wait(T old, std::memory_order order = std::memory_order_seq_cst) const
volatile noexcept {
atomicValue.wait(old, order);
}

// notify_one
void notify_one() noexcept { atomicValue.notify_one(); }

void notify_one() volatile noexcept { atomicValue.notify_one(); }

// notify all
void notify_all() noexcept { atomicValue.notify_all(); }

void notify_all() volatile noexcept { atomicValue.notify_all(); }
#endif

// fetch_add
T fetch_add(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_add(arg, order);
}

T fetch_add(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_add(arg, order);
}

// TODO: fix ambiguity with specialization for T*
// T* fetch_add(std::ptrdiff_t arg, std::memory_order order =
// std::memory_order_seq_cst) noexcept {
// return atomicValue.fetch_add(arg, order);
// }

// T* fetch_add(std::ptrdiff_t arg, std::memory_order order =
// std::memory_order_seq_cst) volatile noexcept {
// return atomicValue.fetch_add(arg, order);
// }

// fetch_sub
T fetch_sub(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_sub(arg, order);
}

T fetch_sub(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_sub(arg, order);
}

// TODO: fix ambiguity with specialization for T*
// T* fetch_sub(std::ptrdiff_t arg, std::memory_order order =
// std::memory_order_seq_cst) noexcept {
// return atomicValue.fetch_sub(arg, order);
// }

// T* fetch_sub(std::ptrdiff_t arg, std::memory_order order =
// std::memory_order_seq_cst) volatile noexcept {
// return atomicValue.fetch_sub(arg, order);
// }

// operator+=
T operator+=(T arg) noexcept { return atomicValue.operator+=(arg); }

T operator+=(T arg) volatile noexcept { return atomicValue.operator+=(arg); }

// TODO: fix ambiguity with specialization for T*
// T* operator+=(std::ptrdiff_t arg) noexcept {
// return atomicValue.operator+=(arg);
// }

// T* operator+=(std::ptrdiff_t arg) volatile noexcept {
// return atomicValue.operator+=(arg);
// }

// operator-=
T operator-=(T arg) noexcept { return atomicValue.operator-=(arg); }

T operator-=(T arg) volatile noexcept { return atomicValue.operator-=(arg); }

// TODO: fix ambiguity with specialization for T*
// T* operator-=(std::ptrdiff_t arg) noexcept {
// return atomicValue.operator-=(arg);
// }

// T* operator-=(std::ptrdiff_t arg) volatile noexcept {
// return atomicValue.operator-=(arg);
// }

// fetch_max
T fetch_max(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_max(arg, order);
}

T fetch_max(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_max(arg, order);
}

// fetch_min
T fetch_min(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_min(arg, order);
}

T fetch_min(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_min(arg, order);
}

// operator++
T operator++() noexcept { return atomicValue.operator++(); }

T operator++() volatile noexcept { return atomicValue.operator++(); }

T operator++(int) noexcept { return atomicValue.operator++(0); }

T operator++(int) volatile noexcept { return atomicValue.operator++(0); }

// operator--
T operator--() noexcept { return atomicValue.operator--(); }

T operator--() volatile noexcept { return atomicValue.operator--(); }

T operator--(int) noexcept { return atomicValue.operator--(0); }

T operator--(int) volatile noexcept { return atomicValue.operator--(0); }

// fetch_and
T fetch_and(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_and(arg, order);
}

T fetch_and(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_and(arg, order);
}

// fetch_or
T fetch_or(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_or(arg, order);
}

T fetch_or(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_or(arg, order);
}

// fetch_xor
T fetch_xor(T arg,
std::memory_order order = std::memory_order_seq_cst) noexcept {
return atomicValue.fetch_xor(arg, order);
}

T fetch_xor(T arg, std::memory_order order =
std::memory_order_seq_cst) volatile noexcept {
return atomicValue.fetch_xor(arg, order);
}

// operator&=
T operator&=(T arg) noexcept { return atomicValue.operator&=(arg); }

T operator&=(T arg) volatile noexcept { return atomicValue.operator&=(arg); }

// operator|=
T operator|=(T arg) noexcept { return atomicValue.operator|=(arg); }

T operator|=(T arg) volatile noexcept { return atomicValue.operator|=(arg); }

// operator^=
T operator^=(T arg) noexcept { return atomicValue.operator^=(arg); }

T operator^=(T arg) volatile noexcept { return atomicValue.operator^=(arg); }
};

} // namespace ltest
1 change: 1 addition & 0 deletions runtime/include/verifying.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <type_traits>

#include "blocking_primitives.h"
#include "latomic.h"
#include "custom_round.h"
#include "lib.h"
#include "lincheck_recursive.h"
Expand Down
4 changes: 2 additions & 2 deletions verifying/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ function(verify_target_without_plugin target)
COMMAND ${CLANG_TOOL_EXECUTABLE}
-p=${CMAKE_BINARY_DIR}/compile_commands.json # passing compilation database, make sure CMAKE_EXPORT_COMPILE_COMMANDS flag is set
--temp-prefix ${CLANG_TOOL_TMP_PREFIX}
--replace-names ::std::mutex,::std::shared_mutex,::std::condition_variable
--insert-names ltest::mutex,ltest::shared_mutex,ltest::condition_variable
--replace-names ::std::mutex,::std::shared_mutex,::std::condition_variable,::std::atomic
--insert-names ltest::mutex,ltest::shared_mutex,ltest::condition_variable,ltest::latomic
${CMAKE_CURRENT_SOURCE_DIR}/${source_name}
DEPENDS ${CLANG_TOOL}
COMMENT "Running Clang Pass Tool on ${source_name}"
Expand Down