diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h index 5de25a94722..66c3f273fc7 100644 --- a/runtime/platform/globals.h +++ b/runtime/platform/globals.h @@ -90,6 +90,7 @@ #include #include +#include #include // For assert() in constant expressions. #if defined(_WIN32) @@ -644,41 +645,7 @@ constexpr double MicrosecondsToMilliseconds(int64_t micros) { template 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 -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 diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h index bb6896ae8ab..1ea942d08d2 100644 --- a/runtime/platform/utils.h +++ b/runtime/platform/utils.h @@ -379,8 +379,7 @@ class Utils { ASSERT(0 <= rotate); ASSERT(rotate <= width); using Unsigned = typename std::make_unsigned::type; - return (static_cast(value) << rotate) | - (static_cast(value) >> ((width - rotate) & (width - 1))); + return std::rotl(static_cast(value), rotate); } template 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::type; - return (static_cast(value) >> rotate) | - (static_cast(value) << ((width - rotate) & (width - 1))); + return std::rotr(static_cast(value), rotate); } NO_SANITIZE_UNDEFINED("float-divide-by-zero") diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc index ddd83b72fc6..55dcc097765 100644 --- a/runtime/vm/bss_relocs.cc +++ b/runtime/vm/bss_relocs.cc @@ -12,17 +12,16 @@ namespace dart { void BSS::InitializeBSSEntry(BSS::Relocation relocation, uword new_value, uword* bss_start) { - std::atomic* slot = reinterpret_cast*>( - &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); } } diff --git a/runtime/vm/field_table.cc b/runtime/vm/field_table.cc index b15dc84bf4e..8dc5549ea98 100644 --- a/runtime/vm/field_table.cc +++ b/runtime/vm/field_table.cc @@ -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*>(&table_)->store(new_table); + std::atomic_ref(table_).store(new_table, std::memory_order_release); if (isolate_group_ != nullptr) { isolate_group_->ForEachIsolate( [&](Isolate* isolate) { diff --git a/runtime/vm/field_table.h b/runtime/vm/field_table.h index 2414038711b..3f6e753ee01 100644 --- a/runtime/vm/field_table.h +++ b/runtime/vm/field_table.h @@ -63,8 +63,8 @@ class FieldTable { ASSERT(IsValidIndex(index)); if (concurrent_use) { ObjectPtr* table = - reinterpret_cast*>(&table_)->load(); - return reinterpret_cast*>(&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* old_tables_; diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc index e18315db5d5..4eb76776f29 100644 --- a/runtime/vm/heap/scavenger.cc +++ b/runtime/vm/heap/scavenger.cc @@ -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*>(UntaggedObject::ToAddr(obj)) - ->load(std::memory_order_relaxed); + return std::atomic_ref(*reinterpret_cast(UntaggedObject::ToAddr(obj))) + .load(std::memory_order_relaxed); } DART_FORCE_INLINE static void WriteHeaderRelaxed(ObjectPtr obj, uword header) { - reinterpret_cast*>(UntaggedObject::ToAddr(obj)) - ->store(header, std::memory_order_relaxed); + std::atomic_ref(*reinterpret_cast(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*>(addr)->compare_exchange_strong( - *old_header, new_header, std::memory_order_relaxed); + return std::atomic_ref(*reinterpret_cast(addr)) + .compare_exchange_strong(*old_header, new_header, + std::memory_order_relaxed); } DART_FORCE_INLINE diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc index c4a8f3e7432..52ca0aac661 100644 --- a/runtime/vm/isolate_test.cc +++ b/runtime/vm/isolate_test.cc @@ -126,9 +126,9 @@ class InterruptChecker : public ThreadPool::Task { // Busy wait for interrupts. uword limit = 0; do { - limit = reinterpret_cast*>( - thread_->stack_limit_address()) - ->load(); + limit = std::atomic_ref( + *reinterpret_cast(thread_->stack_limit_address())) + .load(std::memory_order_relaxed); } while ( (limit == thread_->saved_stack_limit_) || (((limit & Thread::kInterruptsMask) & Thread::kVMInterrupt) == 0)); diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc index 63cce5cc151..f0bb8b7d2e3 100644 --- a/runtime/vm/message_snapshot.cc +++ b/runtime/vm/message_snapshot.cc @@ -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(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); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 45c7a07b449..a3f9d0ccc7f 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -896,9 +896,8 @@ class Object { template FieldType LoadNonPointer(const FieldType* addr) const { - return reinterpret_cast*>( - const_cast(addr)) - ->load(order); + return std::atomic_ref(*const_cast(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(addr) >= UntaggedObject::ToAddr(ptr())); - reinterpret_cast*>(const_cast(addr)) - ->store(value, order); + std::atomic_ref(*const_cast(addr)) + .store(value, order); } // Provides non-const access to non-pointer fields within the object. Such diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 65a32d24da6..bd3cc12c285 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -602,8 +602,7 @@ class UntaggedObject { } template type LoadPointer(type const* addr) const { - return reinterpret_cast*>(const_cast(addr)) - ->load(order); + return std::atomic_ref(*const_cast(addr)).load(order); } template type LoadCompressedPointer(compressed_type const* addr) const { @@ -612,9 +611,9 @@ class UntaggedObject { } template type LoadCompressedPointer(compressed_type const* addr) const { - compressed_type v = reinterpret_cast*>( - const_cast(addr)) - ->load(order); + compressed_type v = + std::atomic_ref(*const_cast(addr)) + .load(order); return static_cast(v.Decompress(heap_base())); } template @@ -638,8 +637,7 @@ class UntaggedObject { } template void StorePointer(type const* addr, type value) { - reinterpret_cast*>(const_cast(addr)) - ->store(value, order); + std::atomic_ref(*const_cast(addr)).store(value, order); if (value.IsHeapObject()) { CheckHeapPointerStore(value, Thread::Current()); } @@ -654,9 +652,8 @@ class UntaggedObject { } template void StoreCompressedPointer(compressed_type const* addr, type value) { - reinterpret_cast*>( - const_cast(addr)) - ->store(static_cast(value), order); + std::atomic_ref(*const_cast(addr)) + .store(static_cast(value), order); if (value.IsHeapObject()) { CheckHeapPointerStore(value, Thread::Current()); } @@ -698,8 +695,7 @@ class UntaggedObject { } template void StoreArrayPointer(type const* addr, value_type value) { - reinterpret_cast*>(const_cast(addr)) - ->store(type(value), order); + std::atomic_ref(*const_cast(addr)).store(type(value), order); if (value->IsHeapObject()) { CheckArrayPointerStore(addr, value, Thread::Current()); } @@ -722,9 +718,8 @@ class UntaggedObject { } template void StoreCompressedArrayPointer(compressed_type const* addr, type value) { - reinterpret_cast*>( - const_cast(addr)) - ->store(static_cast(value), order); + std::atomic_ref(*const_cast(addr)) + .store(static_cast(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*>( - const_cast(addr)) - ->store(static_cast(value), order); + std::atomic_ref(*const_cast(addr)) + .store(static_cast(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*>( - const_cast(addr)) - ->exchange(static_cast(value), order); + std::atomic_ref(*const_cast(addr)) + .exchange(static_cast(value), order); if (value.IsHeapObject()) { CheckHeapPointerStore(value, Thread::Current()); } @@ -771,8 +764,7 @@ class UntaggedObject { } template SmiPtr LoadSmi(SmiPtr const* addr) const { - return reinterpret_cast*>(const_cast(addr)) - ->load(order); + return std::atomic_ref(*const_cast(addr)).load(order); } SmiPtr LoadCompressedSmi(CompressedSmiPtr const* addr) const { return static_cast( @@ -780,10 +772,10 @@ class UntaggedObject { } template SmiPtr LoadCompressedSmi(CompressedSmiPtr const* addr) const { - return static_cast(reinterpret_cast*>( - const_cast(addr)) - ->load(order) - .DecompressSmi()); + return static_cast( + std::atomic_ref(*const_cast(addr)) + .load(order) + .DecompressSmi()); } // Use for storing into an explicitly Smi-typed field of an object @@ -794,17 +786,15 @@ class UntaggedObject { } template void StoreSmi(type const* addr, type value) { - reinterpret_cast*>(const_cast(addr)) - ->store(value, order); + std::atomic_ref(*const_cast(addr)).store(value, order); } void StoreCompressedSmi(CompressedSmiPtr const* addr, SmiPtr value) { *const_cast(addr) = value; } template void StoreCompressedSmi(CompressedSmiPtr const* addr, SmiPtr value) { - reinterpret_cast*>( - const_cast(addr)) - ->store(static_cast(value), order); + std::atomic_ref(*const_cast(addr)) + .store(static_cast(value), order); } private: diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc index 4218f5c2929..afadc2fb59b 100644 --- a/runtime/vm/simulator_arm64.cc +++ b/runtime/vm/simulator_arm64.cc @@ -2560,15 +2560,15 @@ void Simulator::DecodeAtomicMemory(Instr* instr) { if (size == 3) { uint64_t in = get_register(rs, R31IsZR); - auto addr = - reinterpret_cast*>(get_register(rn, R31IsSP)); + auto addr = std::atomic_ref( + *reinterpret_cast(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*>(get_register(rn, R31IsSP)); + auto addr = std::atomic_ref( + *reinterpret_cast(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(); diff --git a/runtime/vm/simulator_memory.h b/runtime/vm/simulator_memory.h index bfb7694b7fe..e814a5422a8 100644 --- a/runtime/vm/simulator_memory.h +++ b/runtime/vm/simulator_memory.h @@ -26,20 +26,12 @@ class DirectSimulatorMemory { template 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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - return reinterpret_cast*>(addr)->load(order); + return std::atomic_ref(*reinterpret_cast(addr)).load(order); } template 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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - reinterpret_cast*>(addr)->store(value, order); + std::atomic_ref(*reinterpret_cast(addr)).store(value, order); } template @@ -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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - return reinterpret_cast*>(addr)->compare_exchange_weak( - old_value, value, order); + return std::atomic_ref(*reinterpret_cast(addr)) + .compare_exchange_weak(old_value, value, order); } void FlushAddress(uword addr) {} @@ -112,21 +100,13 @@ class BufferedSimulatorMemory { template 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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - return reinterpret_cast*>(addr)->load(order); + return std::atomic_ref(*reinterpret_cast(addr)).load(order); } template 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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - reinterpret_cast*>(addr)->store(value, order); + std::atomic_ref(*reinterpret_cast(addr)).store(value, order); } template @@ -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` which supports performing atomic operations on - // non-atomic data. - static_assert(sizeof(std::atomic) == sizeof(T)); - return reinterpret_cast*>(addr)->compare_exchange_weak( - old_value, value, order); + return std::atomic_ref(*reinterpret_cast(addr)) + .compare_exchange_weak(old_value, value, order); } void FlushAddress(uword addr) { diff --git a/runtime/vm/simulator_riscv.cc b/runtime/vm/simulator_riscv.cc index 7ccf4b7e69f..0e0789eccd6 100644 --- a/runtime/vm/simulator_riscv.cc +++ b/runtime/vm/simulator_riscv.cc @@ -2398,9 +2398,9 @@ void Simulator::InterpretAMOSWAP(Instr instr) { Fault("Misaligned atomic memory operation"); } memory_.FlushAddress(addr); - std::atomic* atomic = reinterpret_cast*>(addr); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); - type expected = atomic->load(std::memory_order_relaxed); + // TODO(c++26): fetch_max + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); - type expected = atomic->load(std::memory_order_relaxed); + // TODO(c++26): fetch_max + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); - type value = atomic->load(instr.memory_order()); + std::atomic_ref atomic(*reinterpret_cast(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* atomic = reinterpret_cast*>(addr); - atomic->store(value, instr.memory_order()); + std::atomic_ref atomic(*reinterpret_cast(addr)); + atomic.store(value, instr.memory_order()); } template @@ -2524,8 +2526,8 @@ void Simulator::InterpretAMOCAS(Instr instr) { } type expected = get_xreg(instr.rd()); type desired = get_xreg(instr.rs2()); - std::atomic* atomic = reinterpret_cast*>(addr); - atomic->compare_exchange_weak(expected, desired, instr.memory_order()); + std::atomic_ref atomic(*reinterpret_cast(addr)); + atomic.compare_exchange_weak(expected, desired, instr.memory_order()); set_xreg(instr.rd(), expected); }