mirror of
https://github.com/autc04/Retro68.git
synced 2026-10-25 02:02:50 +00:00
205 lines
4.6 KiB
C++
205 lines
4.6 KiB
C++
#include "Test.h"
|
|
|
|
#include <atomic>
|
|
|
|
/*
|
|
* Exercises the out-of-line __atomic_* helpers provided by libretro/atomic.c.
|
|
*
|
|
* The compiler emits those helpers for operations it cannot perform inline:
|
|
* 64-bit atomics on both 68K and PowerPC, and narrower sizes on 68K/68000 and
|
|
* on classic PowerPC. Alignment and type coverage matter, so all of the
|
|
* integer widths plus a pointer and atomic_flag are tested.
|
|
*/
|
|
|
|
static std::atomic<int> ai;
|
|
static std::atomic<long long> all;
|
|
static std::atomic<char> ac;
|
|
static std::atomic<short> as;
|
|
static std::atomic<int *> ap;
|
|
static std::atomic_flag aflag = ATOMIC_FLAG_INIT;
|
|
|
|
static bool testAtomicInt()
|
|
{
|
|
ai.store(1);
|
|
if (ai.load() != 1)
|
|
return false;
|
|
|
|
if (ai.fetch_add(2) != 1)
|
|
return false;
|
|
if (ai.load() != 3)
|
|
return false;
|
|
if (ai.fetch_sub(1) != 3)
|
|
return false;
|
|
if (ai.load() != 2)
|
|
return false;
|
|
|
|
if (ai.exchange(10) != 2)
|
|
return false;
|
|
if (ai.load() != 10)
|
|
return false;
|
|
|
|
int expected = 10;
|
|
if (!ai.compare_exchange_strong(expected, 20))
|
|
return false;
|
|
if (ai.load() != 20)
|
|
return false;
|
|
|
|
expected = 999;
|
|
if (ai.compare_exchange_strong(expected, 30))
|
|
return false;
|
|
if (expected != 20)
|
|
return false;
|
|
if (ai.load() != 20)
|
|
return false;
|
|
|
|
if (ai.fetch_or(1) != 20)
|
|
return false;
|
|
if (ai.load() != 21)
|
|
return false;
|
|
if (ai.fetch_and(0x1e) != 21)
|
|
return false;
|
|
if (ai.load() != 20)
|
|
return false;
|
|
if (ai.fetch_xor(3) != 20)
|
|
return false;
|
|
if (ai.load() != 23)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool testAtomicLongLong()
|
|
{
|
|
all.store(0x100000000LL);
|
|
if (all.load() != 0x100000000LL)
|
|
return false;
|
|
|
|
if (all.fetch_add(1) != 0x100000000LL)
|
|
return false;
|
|
if (all.load() != 0x100000001LL)
|
|
return false;
|
|
|
|
long long expected = 0x100000001LL;
|
|
if (!all.compare_exchange_strong(expected, 0x200000002LL))
|
|
return false;
|
|
if (all.load() != 0x200000002LL)
|
|
return false;
|
|
|
|
if (all.exchange(5) != 0x200000002LL)
|
|
return false;
|
|
if (all.load() != 5)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool testAtomicNarrow()
|
|
{
|
|
ac.store(1);
|
|
if (ac.load() != 1)
|
|
return false;
|
|
if (ac.fetch_add(2) != 1)
|
|
return false;
|
|
if (ac.load() != 3)
|
|
return false;
|
|
|
|
char charExpected = 3;
|
|
if (!ac.compare_exchange_strong(charExpected, 4))
|
|
return false;
|
|
if (ac.load() != 4)
|
|
return false;
|
|
|
|
as.store(1000);
|
|
if (as.load() != 1000)
|
|
return false;
|
|
if (as.fetch_add(23) != 1000)
|
|
return false;
|
|
if (as.load() != 1023)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool testAtomicPointer()
|
|
{
|
|
int array[4];
|
|
|
|
ap.store(&array[0]);
|
|
if (ap.load() != &array[0])
|
|
return false;
|
|
if (ap.fetch_add(2) != &array[0])
|
|
return false;
|
|
if (ap.load() != &array[2])
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool testAtomicFlag()
|
|
{
|
|
aflag.clear();
|
|
if (aflag.test_and_set())
|
|
return false;
|
|
if (!aflag.test_and_set())
|
|
return false;
|
|
aflag.clear();
|
|
if (aflag.test_and_set())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool testIsLockFree()
|
|
{
|
|
/* Only checks that the runtime query is callable and self-consistent;
|
|
the answer itself depends on the CPU and multilib. */
|
|
return ai.is_lock_free() == ai.is_lock_free();
|
|
}
|
|
|
|
static bool testSyncBuiltins()
|
|
{
|
|
int value = 0;
|
|
if (__sync_fetch_and_add(&value, 5) != 0)
|
|
return false;
|
|
if (value != 5)
|
|
return false;
|
|
if (__sync_add_and_fetch(&value, 1) != 6)
|
|
return false;
|
|
if (__sync_bool_compare_and_swap(&value, 6, 7) != true)
|
|
return false;
|
|
if (value != 7)
|
|
return false;
|
|
if (__sync_bool_compare_and_swap(&value, 6, 8) != false)
|
|
return false;
|
|
if (__sync_val_compare_and_swap(&value, 7, 9) != 7)
|
|
return false;
|
|
if (value != 9)
|
|
return false;
|
|
|
|
/* The 64-bit form is a helper on every CPU, so this pulls the __sync
|
|
implementations in on 68020 and PowerPC as well. */
|
|
long long wide = 0;
|
|
if (__sync_fetch_and_add(&wide, 1) != 0)
|
|
return false;
|
|
if (wide != 1)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
bool ok = testAtomicInt()
|
|
&& testAtomicLongLong()
|
|
&& testAtomicNarrow()
|
|
&& testAtomicPointer()
|
|
&& testAtomicFlag()
|
|
&& testIsLockFree()
|
|
&& testSyncBuiltins();
|
|
|
|
if (ok)
|
|
TestLog("OK");
|
|
else
|
|
TestLog("NO");
|
|
}
|