[vm] C++20 updates.
- std::atomic_ref - std::bit_cast - std::rotl,rotr - designated initializers TEST=ci Bug: https://github.com/dart-lang/sdk/issues/42074 Change-Id: I7be17147723db6f7620a147e75d38ebe46393f8c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/484700 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
e8d02a14da
commit
4bb6609724
@@ -90,6 +90,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <bit>
|
||||
#include <cassert> // For assert() in constant expressions.
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -644,41 +645,7 @@ constexpr double MicrosecondsToMilliseconds(int64_t micros) {
|
||||
template <typename T>
|
||||
static inline void USE(T&&) {}
|
||||
|
||||
// The type-based aliasing rule allows the compiler to assume that
|
||||
// pointers of different types (for some definition of different)
|
||||
// never alias each other. Thus the following code does not work:
|
||||
//
|
||||
// float f = foo();
|
||||
// int fbits = *(int*)(&f);
|
||||
//
|
||||
// The compiler 'knows' that the int pointer can't refer to f since
|
||||
// the types don't match, so the compiler may cache f in a register,
|
||||
// leaving random data in fbits. Using C++ style casts makes no
|
||||
// difference, however a pointer to char data is assumed to alias any
|
||||
// other pointer. This is the 'memcpy exception'.
|
||||
//
|
||||
// The bit_cast function uses the memcpy exception to move the bits
|
||||
// from a variable of one type to a variable of another type. Of
|
||||
// course the end result is likely to be implementation dependent.
|
||||
// Most compilers (gcc-4.2 and MSVC 2005) will completely optimize
|
||||
// bit_cast away.
|
||||
//
|
||||
// There is an additional use for bit_cast. Recent gccs will warn when
|
||||
// they see casts that may result in breakage due to the type-based
|
||||
// aliasing rule. If you have checked that there is no breakage you
|
||||
// can use bit_cast to cast one pointer type to another. This confuses
|
||||
// gcc enough that it can no longer see that you have cast one pointer
|
||||
// type to another thus avoiding the warning.
|
||||
template <class D, class S>
|
||||
DART_FORCE_INLINE D bit_cast(const S& source) {
|
||||
static_assert(sizeof(D) == sizeof(S),
|
||||
"Source and destination must have the same size");
|
||||
|
||||
D destination;
|
||||
// This use of memcpy is safe: source and destination cannot overlap.
|
||||
memcpy(&destination, &source, sizeof(destination));
|
||||
return destination;
|
||||
}
|
||||
using std::bit_cast;
|
||||
|
||||
// Similar to bit_cast, but allows copying from types of unrelated
|
||||
// sizes. This method was introduced to enable the strict aliasing
|
||||
|
||||
@@ -379,8 +379,7 @@ class Utils {
|
||||
ASSERT(0 <= rotate);
|
||||
ASSERT(rotate <= width);
|
||||
using Unsigned = typename std::make_unsigned<T>::type;
|
||||
return (static_cast<Unsigned>(value) << rotate) |
|
||||
(static_cast<T>(value) >> ((width - rotate) & (width - 1)));
|
||||
return std::rotl(static_cast<Unsigned>(value), rotate);
|
||||
}
|
||||
template <typename T>
|
||||
static inline T RotateRight(T value, uint8_t rotate) {
|
||||
@@ -388,8 +387,7 @@ class Utils {
|
||||
ASSERT(0 <= rotate);
|
||||
ASSERT(rotate <= width);
|
||||
using Unsigned = typename std::make_unsigned<T>::type;
|
||||
return (static_cast<T>(value) >> rotate) |
|
||||
(static_cast<Unsigned>(value) << ((width - rotate) & (width - 1)));
|
||||
return std::rotr(static_cast<Unsigned>(value), rotate);
|
||||
}
|
||||
|
||||
NO_SANITIZE_UNDEFINED("float-divide-by-zero")
|
||||
|
||||
@@ -12,17 +12,16 @@ namespace dart {
|
||||
void BSS::InitializeBSSEntry(BSS::Relocation relocation,
|
||||
uword new_value,
|
||||
uword* bss_start) {
|
||||
std::atomic<uword>* slot = reinterpret_cast<std::atomic<uword>*>(
|
||||
&bss_start[BSS::RelocationIndex(relocation)]);
|
||||
uword old_value = slot->load(std::memory_order_relaxed);
|
||||
auto slot = std::atomic_ref(bss_start[BSS::RelocationIndex(relocation)]);
|
||||
uword old_value = slot.load(std::memory_order_relaxed);
|
||||
// FullSnapshotReader::ReadProgramSnapshot, and thus BSS::Initialize, can
|
||||
// get called multiple times for the same isolate in different threads, though
|
||||
// the initialized value will be consistent and thus change only once. Avoid
|
||||
// calling compare_exchange_strong unless we actually need to change the
|
||||
// value, to avoid spurious read/write races by TSAN.
|
||||
if (old_value == new_value) return;
|
||||
if (!slot->compare_exchange_strong(old_value, new_value,
|
||||
std::memory_order_relaxed)) {
|
||||
if (!slot.compare_exchange_strong(old_value, new_value,
|
||||
std::memory_order_relaxed)) {
|
||||
RELEASE_ASSERT(old_value == new_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void FieldTable::Grow(intptr_t new_capacity) {
|
||||
old_tables_->Add(old_table);
|
||||
// Ensure that new_table_ is populated before it is published
|
||||
// via store to table_.
|
||||
reinterpret_cast<AcqRelAtomic<ObjectPtr*>*>(&table_)->store(new_table);
|
||||
std::atomic_ref(table_).store(new_table, std::memory_order_release);
|
||||
if (isolate_group_ != nullptr) {
|
||||
isolate_group_->ForEachIsolate(
|
||||
[&](Isolate* isolate) {
|
||||
|
||||
@@ -63,8 +63,8 @@ class FieldTable {
|
||||
ASSERT(IsValidIndex(index));
|
||||
if (concurrent_use) {
|
||||
ObjectPtr* table =
|
||||
reinterpret_cast<const AcqRelAtomic<ObjectPtr*>*>(&table_)->load();
|
||||
return reinterpret_cast<AcqRelAtomic<ObjectPtr>*>(&table[index])->load();
|
||||
std::atomic_ref(table_).load(std::memory_order::acquire);
|
||||
return std::atomic_ref(table[index]).load(std::memory_order_acquire);
|
||||
} else {
|
||||
// There is no concurrent access expected for this field, so we avoid
|
||||
// using atomics. This will allow us to detect via TSAN if there are
|
||||
@@ -106,7 +106,8 @@ class FieldTable {
|
||||
// element, last element contains -1.
|
||||
intptr_t free_head_;
|
||||
|
||||
ObjectPtr* table_;
|
||||
// Mutable for atomic_ref in At.
|
||||
mutable ObjectPtr* table_;
|
||||
// When table_ grows and have to reallocated, keep the old one here
|
||||
// so it will get freed when its are no longer in use.
|
||||
MallocGrowableArray<ObjectPtr*>* old_tables_;
|
||||
|
||||
@@ -117,14 +117,14 @@ static void objcpy(void* dst, const void* src, size_t size) {
|
||||
|
||||
DART_FORCE_INLINE
|
||||
static uword ReadHeaderRelaxed(ObjectPtr obj) {
|
||||
return reinterpret_cast<std::atomic<uword>*>(UntaggedObject::ToAddr(obj))
|
||||
->load(std::memory_order_relaxed);
|
||||
return std::atomic_ref(*reinterpret_cast<uword*>(UntaggedObject::ToAddr(obj)))
|
||||
.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE
|
||||
static void WriteHeaderRelaxed(ObjectPtr obj, uword header) {
|
||||
reinterpret_cast<std::atomic<uword>*>(UntaggedObject::ToAddr(obj))
|
||||
->store(header, std::memory_order_relaxed);
|
||||
std::atomic_ref(*reinterpret_cast<uword*>(UntaggedObject::ToAddr(obj)))
|
||||
.store(header, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
class ScavengerVisitor : public ObjectPointerVisitor,
|
||||
@@ -524,8 +524,9 @@ class ScavengerVisitor : public ObjectPointerVisitor,
|
||||
bool InstallForwardingPointer(uword addr,
|
||||
uword* old_header,
|
||||
uword new_header) {
|
||||
return reinterpret_cast<std::atomic<uword>*>(addr)->compare_exchange_strong(
|
||||
*old_header, new_header, std::memory_order_relaxed);
|
||||
return std::atomic_ref(*reinterpret_cast<uword*>(addr))
|
||||
.compare_exchange_strong(*old_header, new_header,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE
|
||||
|
||||
@@ -126,9 +126,9 @@ class InterruptChecker : public ThreadPool::Task {
|
||||
// Busy wait for interrupts.
|
||||
uword limit = 0;
|
||||
do {
|
||||
limit = reinterpret_cast<RelaxedAtomic<uword>*>(
|
||||
thread_->stack_limit_address())
|
||||
->load();
|
||||
limit = std::atomic_ref(
|
||||
*reinterpret_cast<uword*>(thread_->stack_limit_address()))
|
||||
.load(std::memory_order_relaxed);
|
||||
} while (
|
||||
(limit == thread_->saved_stack_limit_) ||
|
||||
(((limit & Thread::kInterruptsMask) & Thread::kVMInterrupt) == 0));
|
||||
|
||||
@@ -26,40 +26,19 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
static Dart_CObject cobj_sentinel = {Dart_CObject_kUnsupported, {false}};
|
||||
static Dart_CObject cobj_dynamic_type = {Dart_CObject_kUnsupported, {false}};
|
||||
static Dart_CObject cobj_void_type = {Dart_CObject_kUnsupported, {false}};
|
||||
static Dart_CObject cobj_empty_type_arguments = {Dart_CObject_kUnsupported,
|
||||
{false}};
|
||||
static Dart_CObject cobj_true = {Dart_CObject_kBool, {true}};
|
||||
static Dart_CObject cobj_false = {Dart_CObject_kBool, {false}};
|
||||
|
||||
// Workaround for lack of designated initializers until we adopt c++20
|
||||
class PredefinedCObjects {
|
||||
public:
|
||||
static PredefinedCObjects& getInstance() {
|
||||
static PredefinedCObjects instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static Dart_CObject* cobj_null() { return &getInstance().cobj_null_; }
|
||||
static Dart_CObject* cobj_empty_array() {
|
||||
return &getInstance().cobj_empty_array_;
|
||||
}
|
||||
|
||||
private:
|
||||
PredefinedCObjects() {
|
||||
cobj_null_.type = Dart_CObject_kNull;
|
||||
cobj_null_.value.as_int64 = 0;
|
||||
cobj_empty_array_.type = Dart_CObject_kArray;
|
||||
cobj_empty_array_.value.as_array = {0, nullptr};
|
||||
}
|
||||
|
||||
Dart_CObject cobj_null_;
|
||||
Dart_CObject cobj_empty_array_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PredefinedCObjects);
|
||||
};
|
||||
static Dart_CObject cobj_sentinel = {.type = Dart_CObject_kUnsupported};
|
||||
static Dart_CObject cobj_dynamic_type = {.type = Dart_CObject_kUnsupported};
|
||||
static Dart_CObject cobj_void_type = {.type = Dart_CObject_kUnsupported};
|
||||
static Dart_CObject cobj_empty_type_arguments = {.type =
|
||||
Dart_CObject_kUnsupported};
|
||||
static Dart_CObject cobj_true = {.type = Dart_CObject_kBool,
|
||||
.value = {.as_bool = true}};
|
||||
static Dart_CObject cobj_false = {.type = Dart_CObject_kBool,
|
||||
.value = {.as_bool = false}};
|
||||
static Dart_CObject cobj_null = {.type = Dart_CObject_kNull,
|
||||
.value = {.as_int64 = 0}};
|
||||
static Dart_CObject cobj_empty_array = {.type = Dart_CObject_kArray,
|
||||
.value = {.as_array = {0, nullptr}}};
|
||||
|
||||
enum class MessagePhase {
|
||||
kBeforeTypes = 0,
|
||||
@@ -2374,7 +2353,7 @@ class ArrayMessageSerializationCluster : public MessageSerializationCluster {
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
Dart_CObject* array = reinterpret_cast<Dart_CObject*>(objects_[i]);
|
||||
intptr_t length = array->value.as_array.length;
|
||||
s->WriteRef(PredefinedCObjects::cobj_null()); // TypeArguments
|
||||
s->WriteRef(&cobj_null); // TypeArguments
|
||||
for (intptr_t j = 0; j < length; j++) {
|
||||
s->WriteRef(array->value.as_array.values[j]);
|
||||
}
|
||||
@@ -2819,7 +2798,7 @@ bool ApiMessageSerializer::Trace(Dart_CObject* object) {
|
||||
intptr_t cid;
|
||||
switch (object->type) {
|
||||
case Dart_CObject_kNull:
|
||||
ForwardRef(object, PredefinedCObjects::cobj_null());
|
||||
ForwardRef(object, &cobj_null);
|
||||
return true;
|
||||
case Dart_CObject_kBool:
|
||||
ForwardRef(object, object->value.as_bool ? &cobj_true : &cobj_false);
|
||||
@@ -3234,9 +3213,9 @@ void MessageDeserializer::AddBaseObjects() {
|
||||
}
|
||||
|
||||
void ApiMessageSerializer::AddBaseObjects() {
|
||||
AddBaseObject(PredefinedCObjects::cobj_null());
|
||||
AddBaseObject(&cobj_null);
|
||||
AddBaseObject(&cobj_sentinel);
|
||||
AddBaseObject(PredefinedCObjects::cobj_empty_array());
|
||||
AddBaseObject(&cobj_empty_array);
|
||||
AddBaseObject(&cobj_dynamic_type);
|
||||
AddBaseObject(&cobj_void_type);
|
||||
AddBaseObject(&cobj_empty_type_arguments);
|
||||
@@ -3245,9 +3224,9 @@ void ApiMessageSerializer::AddBaseObjects() {
|
||||
}
|
||||
|
||||
void ApiMessageDeserializer::AddBaseObjects() {
|
||||
AddBaseObject(PredefinedCObjects::cobj_null());
|
||||
AddBaseObject(&cobj_null);
|
||||
AddBaseObject(&cobj_sentinel);
|
||||
AddBaseObject(PredefinedCObjects::cobj_empty_array());
|
||||
AddBaseObject(&cobj_empty_array);
|
||||
AddBaseObject(&cobj_dynamic_type);
|
||||
AddBaseObject(&cobj_void_type);
|
||||
AddBaseObject(&cobj_empty_type_arguments);
|
||||
|
||||
+4
-5
@@ -896,9 +896,8 @@ class Object {
|
||||
|
||||
template <typename FieldType, std::memory_order order>
|
||||
FieldType LoadNonPointer(const FieldType* addr) const {
|
||||
return reinterpret_cast<std::atomic<FieldType>*>(
|
||||
const_cast<FieldType*>(addr))
|
||||
->load(order);
|
||||
return std::atomic_ref<FieldType>(*const_cast<FieldType*>(addr))
|
||||
.load(order);
|
||||
}
|
||||
|
||||
// Needs two template arguments to allow assigning enums to fixed-size ints.
|
||||
@@ -913,8 +912,8 @@ class Object {
|
||||
void StoreNonPointer(const FieldType* addr, ValueType value) const {
|
||||
// Can't use Contains, as it uses tags_, which is set through this method.
|
||||
ASSERT(reinterpret_cast<uword>(addr) >= UntaggedObject::ToAddr(ptr()));
|
||||
reinterpret_cast<std::atomic<FieldType>*>(const_cast<FieldType*>(addr))
|
||||
->store(value, order);
|
||||
std::atomic_ref<FieldType>(*const_cast<FieldType*>(addr))
|
||||
.store(value, order);
|
||||
}
|
||||
|
||||
// Provides non-const access to non-pointer fields within the object. Such
|
||||
|
||||
+22
-32
@@ -602,8 +602,7 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, std::memory_order order>
|
||||
type LoadPointer(type const* addr) const {
|
||||
return reinterpret_cast<std::atomic<type>*>(const_cast<type*>(addr))
|
||||
->load(order);
|
||||
return std::atomic_ref<type>(*const_cast<type*>(addr)).load(order);
|
||||
}
|
||||
template <typename type, typename compressed_type>
|
||||
type LoadCompressedPointer(compressed_type const* addr) const {
|
||||
@@ -612,9 +611,9 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, typename compressed_type, std::memory_order order>
|
||||
type LoadCompressedPointer(compressed_type const* addr) const {
|
||||
compressed_type v = reinterpret_cast<std::atomic<compressed_type>*>(
|
||||
const_cast<compressed_type*>(addr))
|
||||
->load(order);
|
||||
compressed_type v =
|
||||
std::atomic_ref<compressed_type>(*const_cast<compressed_type*>(addr))
|
||||
.load(order);
|
||||
return static_cast<type>(v.Decompress(heap_base()));
|
||||
}
|
||||
template <typename type, typename compressed_type>
|
||||
@@ -638,8 +637,7 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, std::memory_order order>
|
||||
void StorePointer(type const* addr, type value) {
|
||||
reinterpret_cast<std::atomic<type>*>(const_cast<type*>(addr))
|
||||
->store(value, order);
|
||||
std::atomic_ref<type>(*const_cast<type*>(addr)).store(value, order);
|
||||
if (value.IsHeapObject()) {
|
||||
CheckHeapPointerStore(value, Thread::Current());
|
||||
}
|
||||
@@ -654,9 +652,8 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, typename compressed_type, std::memory_order order>
|
||||
void StoreCompressedPointer(compressed_type const* addr, type value) {
|
||||
reinterpret_cast<std::atomic<compressed_type>*>(
|
||||
const_cast<compressed_type*>(addr))
|
||||
->store(static_cast<compressed_type>(value), order);
|
||||
std::atomic_ref<compressed_type>(*const_cast<compressed_type*>(addr))
|
||||
.store(static_cast<compressed_type>(value), order);
|
||||
if (value.IsHeapObject()) {
|
||||
CheckHeapPointerStore(value, Thread::Current());
|
||||
}
|
||||
@@ -698,8 +695,7 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, std::memory_order order, typename value_type = type>
|
||||
void StoreArrayPointer(type const* addr, value_type value) {
|
||||
reinterpret_cast<std::atomic<type>*>(const_cast<type*>(addr))
|
||||
->store(type(value), order);
|
||||
std::atomic_ref<type>(*const_cast<type*>(addr)).store(type(value), order);
|
||||
if (value->IsHeapObject()) {
|
||||
CheckArrayPointerStore(addr, value, Thread::Current());
|
||||
}
|
||||
@@ -722,9 +718,8 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, typename compressed_type, std::memory_order order>
|
||||
void StoreCompressedArrayPointer(compressed_type const* addr, type value) {
|
||||
reinterpret_cast<std::atomic<compressed_type>*>(
|
||||
const_cast<compressed_type*>(addr))
|
||||
->store(static_cast<compressed_type>(value), order);
|
||||
std::atomic_ref<compressed_type>(*const_cast<compressed_type*>(addr))
|
||||
.store(static_cast<compressed_type>(value), order);
|
||||
if (value->IsHeapObject()) {
|
||||
CheckArrayPointerStore(addr, value, Thread::Current());
|
||||
}
|
||||
@@ -734,9 +729,8 @@ class UntaggedObject {
|
||||
void StoreCompressedArrayPointer(compressed_type const* addr,
|
||||
type value,
|
||||
Thread* thread) {
|
||||
reinterpret_cast<std::atomic<compressed_type>*>(
|
||||
const_cast<compressed_type*>(addr))
|
||||
->store(static_cast<compressed_type>(value), order);
|
||||
std::atomic_ref<compressed_type>(*const_cast<compressed_type*>(addr))
|
||||
.store(static_cast<compressed_type>(value), order);
|
||||
if (value->IsHeapObject()) {
|
||||
CheckArrayPointerStore(addr, value, thread);
|
||||
}
|
||||
@@ -757,9 +751,8 @@ class UntaggedObject {
|
||||
std::memory_order order = std::memory_order_relaxed>
|
||||
type ExchangeCompressedPointer(compressed_type const* addr, type value) {
|
||||
compressed_type previous_value =
|
||||
reinterpret_cast<std::atomic<compressed_type>*>(
|
||||
const_cast<compressed_type*>(addr))
|
||||
->exchange(static_cast<compressed_type>(value), order);
|
||||
std::atomic_ref<compressed_type>(*const_cast<compressed_type*>(addr))
|
||||
.exchange(static_cast<compressed_type>(value), order);
|
||||
if (value.IsHeapObject()) {
|
||||
CheckHeapPointerStore(value, Thread::Current());
|
||||
}
|
||||
@@ -771,8 +764,7 @@ class UntaggedObject {
|
||||
}
|
||||
template <std::memory_order order>
|
||||
SmiPtr LoadSmi(SmiPtr const* addr) const {
|
||||
return reinterpret_cast<std::atomic<SmiPtr>*>(const_cast<SmiPtr*>(addr))
|
||||
->load(order);
|
||||
return std::atomic_ref<SmiPtr>(*const_cast<SmiPtr*>(addr)).load(order);
|
||||
}
|
||||
SmiPtr LoadCompressedSmi(CompressedSmiPtr const* addr) const {
|
||||
return static_cast<SmiPtr>(
|
||||
@@ -780,10 +772,10 @@ class UntaggedObject {
|
||||
}
|
||||
template <std::memory_order order>
|
||||
SmiPtr LoadCompressedSmi(CompressedSmiPtr const* addr) const {
|
||||
return static_cast<SmiPtr>(reinterpret_cast<std::atomic<CompressedSmiPtr>*>(
|
||||
const_cast<CompressedSmiPtr*>(addr))
|
||||
->load(order)
|
||||
.DecompressSmi());
|
||||
return static_cast<SmiPtr>(
|
||||
std::atomic_ref<CompressedSmiPtr>(*const_cast<CompressedSmiPtr*>(addr))
|
||||
.load(order)
|
||||
.DecompressSmi());
|
||||
}
|
||||
|
||||
// Use for storing into an explicitly Smi-typed field of an object
|
||||
@@ -794,17 +786,15 @@ class UntaggedObject {
|
||||
}
|
||||
template <typename type, std::memory_order order>
|
||||
void StoreSmi(type const* addr, type value) {
|
||||
reinterpret_cast<std::atomic<type>*>(const_cast<type*>(addr))
|
||||
->store(value, order);
|
||||
std::atomic_ref<type>(*const_cast<type*>(addr)).store(value, order);
|
||||
}
|
||||
void StoreCompressedSmi(CompressedSmiPtr const* addr, SmiPtr value) {
|
||||
*const_cast<CompressedSmiPtr*>(addr) = value;
|
||||
}
|
||||
template <std::memory_order order>
|
||||
void StoreCompressedSmi(CompressedSmiPtr const* addr, SmiPtr value) {
|
||||
reinterpret_cast<std::atomic<CompressedSmiPtr>*>(
|
||||
const_cast<CompressedSmiPtr*>(addr))
|
||||
->store(static_cast<CompressedSmiPtr>(value), order);
|
||||
std::atomic_ref<CompressedSmiPtr>(*const_cast<CompressedSmiPtr*>(addr))
|
||||
.store(static_cast<CompressedSmiPtr>(value), order);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -2560,15 +2560,15 @@ void Simulator::DecodeAtomicMemory(Instr* instr) {
|
||||
|
||||
if (size == 3) {
|
||||
uint64_t in = get_register(rs, R31IsZR);
|
||||
auto addr =
|
||||
reinterpret_cast<std::atomic<uint64_t>*>(get_register(rn, R31IsSP));
|
||||
auto addr = std::atomic_ref(
|
||||
*reinterpret_cast<uint64_t*>(get_register(rn, R31IsSP)));
|
||||
uint64_t out;
|
||||
switch (opc) {
|
||||
case 1:
|
||||
out = addr->fetch_and(~in, order);
|
||||
out = addr.fetch_and(~in, order);
|
||||
break;
|
||||
case 3:
|
||||
out = addr->fetch_or(in, order);
|
||||
out = addr.fetch_or(in, order);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
@@ -2577,15 +2577,15 @@ void Simulator::DecodeAtomicMemory(Instr* instr) {
|
||||
} else if (size == 2) {
|
||||
ASSERT(size == 2);
|
||||
uint32_t in = get_wregister(rs, R31IsZR);
|
||||
auto addr =
|
||||
reinterpret_cast<std::atomic<uint32_t>*>(get_register(rn, R31IsSP));
|
||||
auto addr = std::atomic_ref(
|
||||
*reinterpret_cast<uint32_t*>(get_register(rn, R31IsSP)));
|
||||
uint32_t out;
|
||||
switch (opc) {
|
||||
case 1:
|
||||
out = addr->fetch_and(~in, order);
|
||||
out = addr.fetch_and(~in, order);
|
||||
break;
|
||||
case 3:
|
||||
out = addr->fetch_or(in, order);
|
||||
out = addr.fetch_or(in, order);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
|
||||
@@ -26,20 +26,12 @@ class DirectSimulatorMemory {
|
||||
|
||||
template <typename T>
|
||||
T Load(uword addr, std::memory_order order) {
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
return reinterpret_cast<std::atomic<T>*>(addr)->load(order);
|
||||
return std::atomic_ref(*reinterpret_cast<T*>(addr)).load(order);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Store(uword addr, T value, std::memory_order order) {
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
reinterpret_cast<std::atomic<T>*>(addr)->store(value, order);
|
||||
std::atomic_ref(*reinterpret_cast<T*>(addr)).store(value, order);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -47,12 +39,8 @@ class DirectSimulatorMemory {
|
||||
T& old_value,
|
||||
T value,
|
||||
std::memory_order order) {
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
return reinterpret_cast<std::atomic<T>*>(addr)->compare_exchange_weak(
|
||||
old_value, value, order);
|
||||
return std::atomic_ref(*reinterpret_cast<T*>(addr))
|
||||
.compare_exchange_weak(old_value, value, order);
|
||||
}
|
||||
|
||||
void FlushAddress(uword addr) {}
|
||||
@@ -112,21 +100,13 @@ class BufferedSimulatorMemory {
|
||||
template <typename T>
|
||||
T Load(uword addr, std::memory_order order) {
|
||||
FlushAddress(addr);
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
return reinterpret_cast<std::atomic<T>*>(addr)->load(order);
|
||||
return std::atomic_ref(*reinterpret_cast<T*>(addr)).load(order);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Store(uword addr, T value, std::memory_order order) {
|
||||
FlushAddress(addr);
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
reinterpret_cast<std::atomic<T>*>(addr)->store(value, order);
|
||||
std::atomic_ref(*reinterpret_cast<T*>(addr)).store(value, order);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -135,12 +115,8 @@ class BufferedSimulatorMemory {
|
||||
T value,
|
||||
std::memory_order order) {
|
||||
FlushAddress(addr);
|
||||
// TODO(42074): Once we switch to C++20 we should change this to use use
|
||||
// `std::atomic_ref<T>` which supports performing atomic operations on
|
||||
// non-atomic data.
|
||||
static_assert(sizeof(std::atomic<T>) == sizeof(T));
|
||||
return reinterpret_cast<std::atomic<T>*>(addr)->compare_exchange_weak(
|
||||
old_value, value, order);
|
||||
return std::atomic_ref<T>(*reinterpret_cast<T*>(addr))
|
||||
.compare_exchange_weak(old_value, value, order);
|
||||
}
|
||||
|
||||
void FlushAddress(uword addr) {
|
||||
|
||||
@@ -2398,9 +2398,9 @@ void Simulator::InterpretAMOSWAP(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type desired = get_xreg(instr.rs2());
|
||||
type result = atomic->exchange(desired, instr.memory_order());
|
||||
type result = atomic.exchange(desired, instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(result));
|
||||
}
|
||||
|
||||
@@ -2411,9 +2411,9 @@ void Simulator::InterpretAMOADD(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type arg = get_xreg(instr.rs2());
|
||||
type result = atomic->fetch_add(arg, instr.memory_order());
|
||||
type result = atomic.fetch_add(arg, instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(result));
|
||||
}
|
||||
|
||||
@@ -2424,9 +2424,9 @@ void Simulator::InterpretAMOXOR(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type arg = get_xreg(instr.rs2());
|
||||
type result = atomic->fetch_xor(arg, instr.memory_order());
|
||||
type result = atomic.fetch_xor(arg, instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(result));
|
||||
}
|
||||
|
||||
@@ -2437,9 +2437,9 @@ void Simulator::InterpretAMOAND(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type arg = get_xreg(instr.rs2());
|
||||
type result = atomic->fetch_and(arg, instr.memory_order());
|
||||
type result = atomic.fetch_and(arg, instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(result));
|
||||
}
|
||||
|
||||
@@ -2450,9 +2450,9 @@ void Simulator::InterpretAMOOR(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type arg = get_xreg(instr.rs2());
|
||||
type result = atomic->fetch_or(arg, instr.memory_order());
|
||||
type result = atomic.fetch_or(arg, instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(result));
|
||||
}
|
||||
|
||||
@@ -2463,14 +2463,15 @@ void Simulator::InterpretAMOMIN(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
type expected = atomic->load(std::memory_order_relaxed);
|
||||
// TODO(c++26): fetch_max
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type expected = atomic.load(std::memory_order_relaxed);
|
||||
type compare = get_xreg(instr.rs2());
|
||||
type desired;
|
||||
do {
|
||||
desired = expected < compare ? expected : compare;
|
||||
} while (
|
||||
!atomic->compare_exchange_weak(expected, desired, instr.memory_order()));
|
||||
!atomic.compare_exchange_weak(expected, desired, instr.memory_order()));
|
||||
set_xreg(instr.rd(), sign_extend(expected));
|
||||
}
|
||||
|
||||
@@ -2481,14 +2482,15 @@ void Simulator::InterpretAMOMAX(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
type expected = atomic->load(std::memory_order_relaxed);
|
||||
// TODO(c++26): fetch_max
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type expected = atomic.load(std::memory_order_relaxed);
|
||||
type compare = get_xreg(instr.rs2());
|
||||
type desired;
|
||||
do {
|
||||
desired = expected > compare ? expected : compare;
|
||||
} while (
|
||||
!atomic->compare_exchange_weak(expected, desired, instr.memory_order()));
|
||||
!atomic.compare_exchange_weak(expected, desired, instr.memory_order()));
|
||||
set_xreg(instr.rd(), sign_extend(expected));
|
||||
}
|
||||
|
||||
@@ -2499,8 +2501,8 @@ void Simulator::InterpretLOADORDERED(Instr instr) {
|
||||
Fault("Misaligned atomic memory operation");
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
type value = atomic->load(instr.memory_order());
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
type value = atomic.load(instr.memory_order());
|
||||
set_xreg(instr.rd(), sign_extend(value));
|
||||
}
|
||||
|
||||
@@ -2512,8 +2514,8 @@ void Simulator::InterpretSTOREORDERED(Instr instr) {
|
||||
}
|
||||
memory_.FlushAddress(addr);
|
||||
type value = get_xreg(instr.rs2());
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
atomic->store(value, instr.memory_order());
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
atomic.store(value, instr.memory_order());
|
||||
}
|
||||
|
||||
template <typename type>
|
||||
@@ -2524,8 +2526,8 @@ void Simulator::InterpretAMOCAS(Instr instr) {
|
||||
}
|
||||
type expected = get_xreg(instr.rd());
|
||||
type desired = get_xreg(instr.rs2());
|
||||
std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
|
||||
atomic->compare_exchange_weak(expected, desired, instr.memory_order());
|
||||
std::atomic_ref<type> atomic(*reinterpret_cast<type*>(addr));
|
||||
atomic.compare_exchange_weak(expected, desired, instr.memory_order());
|
||||
set_xreg(instr.rd(), expected);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user