// Copyright (C) 2019-2023 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING3. If not see // . // { dg-options "-std=gnu++2a" } // { dg-add-options ieee } // { dg-do run { target c++2a } } #include #include void test01() { const auto mo = std::memory_order_relaxed; bool ok; float expected; if constexpr (std::atomic::is_always_lock_free) { std::atomic a0; std::atomic a1(1.0f); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5f); a1.store(0.5f, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5f); auto f1 = a1.exchange(12.5f, mo); VERIFY( a0 == 12.5f ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5f ); VERIFY( f0 == f1 ); expected = 12.5f; while (!a0.compare_exchange_weak(expected, 1.6f, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6f ); VERIFY( expected == 12.5f ); expected = 1.5f; ok = a1.compare_exchange_weak(expected, 1.6f, mo, mo); VERIFY( !ok && a1.load() == 12.5f && expected == 12.5f ); VERIFY( expected == 12.5f ); expected = 1.6f; ok = a0.compare_exchange_strong(expected, 3.2f, mo, mo); VERIFY( ok && a0.load() == 3.2f ); VERIFY( expected == 1.6f ); expected = 1.5f; ok = a1.compare_exchange_strong(expected, 3.2f, mo, mo); VERIFY( !ok && a1.load() == 12.5f && expected == 12.5f ); expected = 3.2f; while (!a0.compare_exchange_weak(expected, .64f)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64f ); expected = 12.5f; while (!a1.compare_exchange_weak(expected, 1.6f, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6f ); expected = 0.5f; ok = a0.compare_exchange_weak(expected, 3.2f); VERIFY( !ok && a0.load() == .64f && expected == .64f ); expected = 0.5f; ok = a1.compare_exchange_weak(expected, 3.2f, mo); VERIFY( !ok && a1.load() == 1.6f && expected == 1.6f ); expected = .64f; ok = a0.compare_exchange_strong(expected, 12.8f); VERIFY( ok && a0.load() == 12.8f ); expected = 1.6f; ok = a1.compare_exchange_strong(expected, 2.56f, mo); VERIFY( ok && a1.load() == 2.56f ); expected = 0.5f; ok = a0.compare_exchange_strong(expected, 3.2f); VERIFY( !ok && a0.load() == 12.8f && expected == 12.8f ); expected = 0.5f; ok = a1.compare_exchange_strong(expected, 3.2f, mo); VERIFY( !ok && a1.load() == 2.56f && expected == 2.56f ); f0 = a0.fetch_add(1.2f); VERIFY( f0 == 12.8f ); VERIFY( a0 == 14.0f ); f1 = a1.fetch_add(2.4f, mo); VERIFY( f1 == 2.56f ); VERIFY( a1 == 4.96f ); f0 = a0.fetch_sub(1.2f); VERIFY( f0 == 14.0f ); VERIFY( a0 == 12.8f ); f1 = a1.fetch_sub(3.5f, mo); VERIFY( f1 == 4.96f ); VERIFY( a1 == 1.46f ); f0 = a0 += 1.2f; VERIFY( f0 == 14.0f ); VERIFY( a0 == 14.0f ); f0 = a0 -= 0.8f; VERIFY( f0 == 13.2f ); VERIFY( a0 == 13.2f ); } // Repeat for volatile std::atomic if constexpr (std::atomic::is_always_lock_free) { volatile std::atomic a0; volatile std::atomic a1(1.0f); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5f); a1.store(0.5f, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5f); auto f1 = a1.exchange(12.5f, mo); VERIFY( a0 == 12.5f ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5f ); VERIFY( f0 == f1 ); expected = 12.5f; while (!a0.compare_exchange_weak(expected, 1.6f, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6f ); VERIFY( expected == 12.5f ); expected = 1.5f; ok = a1.compare_exchange_weak(expected, 1.6f, mo, mo); VERIFY( !ok && a1.load() == 12.5f && expected == 12.5f ); VERIFY( expected == 12.5f ); expected = 1.6f; ok = a0.compare_exchange_strong(expected, 3.2f, mo, mo); VERIFY( ok && a0.load() == 3.2f ); VERIFY( expected == 1.6f ); expected = 1.5f; ok = a1.compare_exchange_strong(expected, 3.2f, mo, mo); VERIFY( !ok && a1.load() == 12.5f && expected == 12.5f ); expected = 3.2f; while (!a0.compare_exchange_weak(expected, .64f)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64f ); expected = 12.5f; while (!a1.compare_exchange_weak(expected, 1.6f, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6f ); expected = 0.5f; ok = a0.compare_exchange_weak(expected, 3.2f); VERIFY( !ok && a0.load() == .64f && expected == .64f ); expected = 0.5f; ok = a1.compare_exchange_weak(expected, 3.2f, mo); VERIFY( !ok && a1.load() == 1.6f && expected == 1.6f ); expected = .64f; ok = a0.compare_exchange_strong(expected, 12.8f); VERIFY( ok && a0.load() == 12.8f ); expected = 1.6f; ok = a1.compare_exchange_strong(expected, 2.56f, mo); VERIFY( ok && a1.load() == 2.56f ); expected = 0.5f; ok = a0.compare_exchange_strong(expected, 3.2f); VERIFY( !ok && a0.load() == 12.8f && expected == 12.8f ); expected = 0.5f; ok = a1.compare_exchange_strong(expected, 3.2f, mo); VERIFY( !ok && a1.load() == 2.56f && expected == 2.56f ); f0 = a0.fetch_add(1.2f); VERIFY( f0 == 12.8f ); VERIFY( a0 == 14.0f ); f1 = a1.fetch_add(2.4f, mo); VERIFY( f1 == 2.56f ); VERIFY( a1 == 4.96f ); f0 = a0.fetch_sub(1.2f); VERIFY( f0 == 14.0f ); VERIFY( a0 == 12.8f ); f1 = a1.fetch_sub(3.5f, mo); VERIFY( f1 == 4.96f ); VERIFY( a1 == 1.46f ); f0 = a0 += 1.2f; VERIFY( f0 == 14.0f ); VERIFY( a0 == 14.0f ); f0 = a0 -= 0.8f; VERIFY( f0 == 13.2f ); VERIFY( a0 == 13.2f ); } } void test02() { const auto mo = std::memory_order_relaxed; bool ok; double expected; if constexpr (std::atomic::is_always_lock_free) { std::atomic a0; std::atomic a1(1.0); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5); a1.store(0.5, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5); auto f1 = a1.exchange(12.5, mo); VERIFY( a0 == 12.5 ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5 ); VERIFY( f0 == f1 ); expected = 12.5; while (!a0.compare_exchange_weak(expected, 1.6, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6 ); VERIFY( expected == 12.5 ); expected = 1.5; ok = a1.compare_exchange_weak(expected, 1.6, mo, mo); VERIFY( !ok && a1.load() == 12.5 && expected == 12.5 ); VERIFY( expected == 12.5 ); expected = 1.6; ok = a0.compare_exchange_strong(expected, 3.2, mo, mo); VERIFY( ok && a0.load() == 3.2 ); VERIFY( expected == 1.6 ); expected = 1.5; ok = a1.compare_exchange_strong(expected, 3.2, mo, mo); VERIFY( !ok && a1.load() == 12.5 && expected == 12.5 ); expected = 3.2; while (!a0.compare_exchange_weak(expected, .64)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64 ); expected = 12.5; while (!a1.compare_exchange_weak(expected, 1.6, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6 ); expected = 0.5; ok = a0.compare_exchange_weak(expected, 3.2); VERIFY( !ok && a0.load() == .64 && expected == .64 ); expected = 0.5; ok = a1.compare_exchange_weak(expected, 3.2, mo); VERIFY( !ok && a1.load() == 1.6 && expected == 1.6 ); expected = .64; ok = a0.compare_exchange_strong(expected, 12.8); VERIFY( ok && a0.load() == 12.8 ); expected = 1.6; ok = a1.compare_exchange_strong(expected, 2.56, mo); VERIFY( ok && a1.load() == 2.56 ); expected = 0.5; ok = a0.compare_exchange_strong(expected, 3.2); VERIFY( !ok && a0.load() == 12.8 && expected == 12.8 ); expected = 0.5; ok = a1.compare_exchange_strong(expected, 3.2, mo); VERIFY( !ok && a1.load() == 2.56 && expected == 2.56 ); f0 = a0.fetch_add(1.2); VERIFY( f0 == 12.8 ); VERIFY( a0 == 14.0 ); f1 = a1.fetch_add(2.4, mo); VERIFY( f1 == 2.56 ); VERIFY( a1 == 4.96 ); f0 = a0.fetch_sub(1.2); VERIFY( f0 == 14.0 ); VERIFY( a0 == 12.8 ); f1 = a1.fetch_sub(3.5, mo); VERIFY( f1 == 4.96 ); VERIFY( a1 == 1.46 ); f0 = a0 += 1.2; VERIFY( f0 == 14.0 ); VERIFY( a0 == 14.0 ); f0 = a0 -= 0.8; VERIFY( f0 == 13.2 ); VERIFY( a0 == 13.2 ); } // Repeat for volatile std::atomic if constexpr (std::atomic::is_always_lock_free) { volatile std::atomic a0; volatile std::atomic a1(1.0); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5); a1.store(0.5, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5); auto f1 = a1.exchange(12.5, mo); VERIFY( a0 == 12.5 ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5 ); VERIFY( f0 == f1 ); expected = 12.5; while (!a0.compare_exchange_weak(expected, 1.6, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6 ); VERIFY( expected == 12.5 ); expected = 1.5; ok = a1.compare_exchange_weak(expected, 1.6, mo, mo); VERIFY( !ok && a1.load() == 12.5 && expected == 12.5 ); VERIFY( expected == 12.5 ); expected = 1.6; ok = a0.compare_exchange_strong(expected, 3.2, mo, mo); VERIFY( ok && a0.load() == 3.2 ); VERIFY( expected == 1.6 ); expected = 1.5; ok = a1.compare_exchange_strong(expected, 3.2, mo, mo); VERIFY( !ok && a1.load() == 12.5 && expected == 12.5 ); expected = 3.2; while (!a0.compare_exchange_weak(expected, .64)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64 ); expected = 12.5; while (!a1.compare_exchange_weak(expected, 1.6, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6 ); expected = 0.5; ok = a0.compare_exchange_weak(expected, 3.2); VERIFY( !ok && a0.load() == .64 && expected == .64 ); expected = 0.5; ok = a1.compare_exchange_weak(expected, 3.2, mo); VERIFY( !ok && a1.load() == 1.6 && expected == 1.6 ); expected = .64; ok = a0.compare_exchange_strong(expected, 12.8); VERIFY( ok && a0.load() == 12.8 ); expected = 1.6; ok = a1.compare_exchange_strong(expected, 2.56, mo); VERIFY( ok && a1.load() == 2.56 ); expected = 0.5; ok = a0.compare_exchange_strong(expected, 3.2); VERIFY( !ok && a0.load() == 12.8 && expected == 12.8 ); expected = 0.5; ok = a1.compare_exchange_strong(expected, 3.2, mo); VERIFY( !ok && a1.load() == 2.56 && expected == 2.56 ); f0 = a0.fetch_add(1.2); VERIFY( f0 == 12.8 ); VERIFY( a0 == 14.0 ); f1 = a1.fetch_add(2.4, mo); VERIFY( f1 == 2.56 ); VERIFY( a1 == 4.96 ); f0 = a0.fetch_sub(1.2); VERIFY( f0 == 14.0 ); VERIFY( a0 == 12.8 ); f1 = a1.fetch_sub(3.5, mo); VERIFY( f1 == 4.96 ); VERIFY( a1 == 1.46 ); f0 = a0 += 1.2; VERIFY( f0 == 14.0 ); VERIFY( a0 == 14.0 ); f0 = a0 -= 0.8; VERIFY( f0 == 13.2 ); VERIFY( a0 == 13.2 ); } } void test03() { const auto mo = std::memory_order_relaxed; bool ok; long double expected; if constexpr (std::atomic::is_always_lock_free) { std::atomic a0; std::atomic a1(1.0l); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5l); a1.store(0.5l, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5l); auto f1 = a1.exchange(12.5l, mo); VERIFY( a0 == 12.5l ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5l ); VERIFY( f0 == f1 ); expected = 12.5l; while (!a0.compare_exchange_weak(expected, 1.6l, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6l ); VERIFY( expected == 12.5l ); expected = 1.5l; ok = a1.compare_exchange_weak(expected, 1.6l, mo, mo); VERIFY( !ok && a1.load() == 12.5l && expected == 12.5l ); VERIFY( expected == 12.5l ); expected = 1.6l; ok = a0.compare_exchange_strong(expected, 3.2l, mo, mo); VERIFY( ok && a0.load() == 3.2l ); VERIFY( expected == 1.6l ); expected = 1.5l; ok = a1.compare_exchange_strong(expected, 3.2l, mo, mo); VERIFY( !ok && a1.load() == 12.5l && expected == 12.5l ); expected = 3.2l; while (!a0.compare_exchange_weak(expected, .64l)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64l ); expected = 12.5l; while (!a1.compare_exchange_weak(expected, 1.6l, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6l ); expected = 0.5l; ok = a0.compare_exchange_weak(expected, 3.2l); VERIFY( !ok && a0.load() == .64l && expected == .64l ); expected = 0.5l; ok = a1.compare_exchange_weak(expected, 3.2l, mo); VERIFY( !ok && a1.load() == 1.6l && expected == 1.6l ); expected = .64l; ok = a0.compare_exchange_strong(expected, 12.8l); VERIFY( ok && a0.load() == 12.8l ); expected = 1.6l; ok = a1.compare_exchange_strong(expected, 2.56l, mo); VERIFY( ok && a1.load() == 2.56l ); expected = 0.5l; ok = a0.compare_exchange_strong(expected, 3.2l); VERIFY( !ok && a0.load() == 12.8l && expected == 12.8l ); expected = 0.5l; ok = a1.compare_exchange_strong(expected, 3.2l, mo); VERIFY( !ok && a1.load() == 2.56l && expected == 2.56l ); a1 = a0 = 0.5l; f0 = a0.fetch_add(0.25l); VERIFY( f0 == 0.5l ); VERIFY( a0 == 0.75l ); f1 = a1.fetch_add(0.25l, mo); VERIFY( f1 == 0.5l ); VERIFY( a1 == 0.75l ); f0 = a0.fetch_sub(0.5l); VERIFY( f0 == 0.75l ); VERIFY( a0 == 0.25l ); f1 = a1.fetch_sub(0.5l, mo); VERIFY( f1 == 0.75l ); VERIFY( a1 == 0.25l ); f0 = a0 += 0.75l; VERIFY( f0 == 1.0l ); VERIFY( a0 == 1.0l ); f0 = a0 -= 0.5l; VERIFY( f0 == 0.5l ); VERIFY( a0 == 0.5l ); } // Repeat for volatile std::atomic if constexpr (std::atomic::is_always_lock_free) { volatile std::atomic a0; volatile std::atomic a1(1.0l); ok = a0.is_lock_free(); a0 = a1.load(); VERIFY( a0.load() == a1.load() ); VERIFY( a0.load(mo) == a0.load() ); a0.store(0.5l); a1.store(0.5l, mo); VERIFY( a0.load() == a1.load() ); auto f0 = a0.exchange(12.5l); auto f1 = a1.exchange(12.5l, mo); VERIFY( a0 == 12.5l ); VERIFY( a0.load() == a1.load() ); VERIFY( f0 == 0.5l ); VERIFY( f0 == f1 ); expected = 12.5l; while (!a0.compare_exchange_weak(expected, 1.6l, mo, mo)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == 1.6l ); VERIFY( expected == 12.5l ); expected = 1.5l; ok = a1.compare_exchange_weak(expected, 1.6l, mo, mo); VERIFY( !ok && a1.load() == 12.5l && expected == 12.5l ); VERIFY( expected == 12.5l ); expected = 1.6l; ok = a0.compare_exchange_strong(expected, 3.2l, mo, mo); VERIFY( ok && a0.load() == 3.2l ); VERIFY( expected == 1.6l ); expected = 1.5l; ok = a1.compare_exchange_strong(expected, 3.2l, mo, mo); VERIFY( !ok && a1.load() == 12.5l && expected == 12.5l ); expected = 3.2l; while (!a0.compare_exchange_weak(expected, .64l)) { /* weak form can fail spuriously */ } VERIFY( a0.load() == .64l ); expected = 12.5l; while (!a1.compare_exchange_weak(expected, 1.6l, mo)) { /* weak form can fail spuriously */ } VERIFY( a1.load() == 1.6l ); expected = 0.5l; ok = a0.compare_exchange_weak(expected, 3.2l); VERIFY( !ok && a0.load() == .64l && expected == .64l ); expected = 0.5l; ok = a1.compare_exchange_weak(expected, 3.2l, mo); VERIFY( !ok && a1.load() == 1.6l && expected == 1.6l ); expected = .64l; ok = a0.compare_exchange_strong(expected, 12.8l); VERIFY( ok && a0.load() == 12.8l ); expected = 1.6l; ok = a1.compare_exchange_strong(expected, 2.56l, mo); VERIFY( ok && a1.load() == 2.56l ); expected = 0.5l; ok = a0.compare_exchange_strong(expected, 3.2l); VERIFY( !ok && a0.load() == 12.8l && expected == 12.8l ); expected = 0.5l; ok = a1.compare_exchange_strong(expected, 3.2l, mo); VERIFY( !ok && a1.load() == 2.56l && expected == 2.56l ); a1 = a0 = 0.5l; f0 = a0.fetch_add(0.25l); VERIFY( f0 == 0.5l ); VERIFY( a0 == 0.75l ); f1 = a1.fetch_add(0.25l, mo); VERIFY( f1 == 0.5l ); VERIFY( a1 == 0.75l ); f0 = a0.fetch_sub(0.5l); VERIFY( f0 == 0.75l ); VERIFY( a0 == 0.25l ); f1 = a1.fetch_sub(0.5l, mo); VERIFY( f1 == 0.75l ); VERIFY( a1 == 0.25l ); f0 = a0 += 0.75l; VERIFY( f0 == 1.0l ); VERIFY( a0 == 1.0l ); f0 = a0 -= 0.5l; VERIFY( f0 == 0.5l ); VERIFY( a0 == 0.5l ); } } int main() { test01(); test02(); test03(); }