| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include <EAStdC/EAAlignment.h>
- #include <EAStdCTest/EAStdCTest.h>
- #include <EATest/EATest.h>
- // Conditionally include SSE headers which some of the tests conditionally rely upon.
- #if EA_SSE
- #if EA_SSE >= 1
- #include <xmmintrin.h>
- #endif
- #if EA_SSE >= 2
- #include <emmintrin.h>
- #endif
- #if EA_SSE >= 1
- EASTDC_DECLARE_TRIVIAL_DESTRUCTOR(__m128)
- EASTDC_DECLARE_TRIVIAL_DESTRUCTOR(__m128i)
- #endif
- #endif
- using namespace EA::StdC;
- using namespace EA::UnitTest;
- ///////////////////////////////////////////////////////////////////////////////
- // TestStruct
- //
- // Helper class for our unit test.
- //
- struct TestStruct
- {
- uint32_t a;
- uint64_t b;
- char c;
- void* d;
- TestStruct() : a(0), b(0), c(0), d(0) {}
- };
- ///////////////////////////////////////////////////////////////////////////////
- // TestTemplate
- //
- // Helper class for our unit test.
- //
- template <typename T>
- struct TestTemplate
- {
- uint32_t a;
- uint64_t b;
- char c;
- void* d;
- TestTemplate() : a(0), b(0), c(0), d(0) {}
- };
- ///////////////////////////////////////////////////////////////////////////////
- // TestAlignment
- //
- int TestAlignment()
- {
- int nErrorCount(0);
- EA::UnitTest::Report("TestAlignment\n");
- ///////////////////////////////////////////////////////////////////////////
- // EAAlignOf
- ///////////////////////////////////////////////////////////////////////////
- {
- size_t a;
- // Type-based AlignOf
- a = EAAlignOf(uint32_t);
- EATEST_VERIFY(a == sizeof(uint32_t));
- #if (EA_PLATFORM_WORD_SIZE >= 8)
- a = EAAlignOf(uint64_t);
- EATEST_VERIFY(a == sizeof(uint64_t));
- #endif
- a = EAAlignOf(TestStruct);
- EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
- a = EAAlignOf(TestTemplate<int>);
- EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
- // Instance-based AlignOf
- uint32_t x32 = 0;
- a = AlignOf(x32);
- EATEST_VERIFY(a == sizeof(uint32_t));
- #if (EA_PLATFORM_WORD_SIZE >= 8)
- uint64_t x64 = 0;
- a = AlignOf(x64);
- EATEST_VERIFY(a == sizeof(uint64_t));
- #endif
- TestStruct testStruct;
- a = AlignOf(testStruct);
- EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
- TestTemplate<int> testTemplate;
- a = AlignOf(testTemplate);
- EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignAddressUp, AlignObjectUp, AlignAddressDown, AlignObjectDown, GetAlignment
- ///////////////////////////////////////////////////////////////////////////
- {
- void* pResult;
- for(char* p = 0; p < (char*)100000; p++)
- {
- for(size_t i = 0; i < 18; i++)
- {
- uintptr_t a = ((size_t)1 << i);
- pResult = AlignAddressUp(p, a);
- EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
- pResult = AlignObjectUp(p, a);
- EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
- pResult = AlignAddressDown(p, ((size_t)1 << i));
- EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
- pResult = AlignObjectDown(p, ((size_t)1 << i));
- EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
- size_t alignment = GetAlignment(pResult);
- EATEST_VERIFY(alignment >= a); // We test >= because sometimes values are coincidentally aligned to a higher value than intended. Which is OK.
- bool bResult = IsAligned(pResult, a);
- EATEST_VERIFY(bResult);
- }
- }
- for(TestStruct* p = 0, *pTestStruct; p < (TestStruct*)100000; p++)
- {
- for(size_t i = 0; i < 18; i++)
- {
- uintptr_t a = ((size_t)1 << i);
- pTestStruct = AlignObjectUp(p, a);
- EATEST_VERIFY(((uintptr_t)pTestStruct % a) == (uintptr_t)0);
- pTestStruct = AlignObjectDown(p, ((size_t)1 << i));
- EATEST_VERIFY(((uintptr_t)pTestStruct % a) == (uintptr_t)0);
- size_t alignment = GetAlignment(pTestStruct);
- EATEST_VERIFY(alignment >= a); // We test >= because sometimes values are coincidentally aligned to a higher value than intended. Which is OK.
- bool bResult = IsAligned(pTestStruct, a);
- EATEST_VERIFY(bResult);
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignAddressUp
- ///////////////////////////////////////////////////////////////////////////
- {
- for(uintptr_t address = 0; address < 1024; ++address)
- {
- for(size_t a = 1; a < 1024*1024; a <<= 1)
- {
- const void* up = AlignAddressUp ((void*)address, a);
- const void* down = AlignAddressDown((void*)address, a);
- EATEST_VERIFY(((uintptr_t)up >= address) && IsAligned(up, a));
- EATEST_VERIFY(((uintptr_t)down <= address) && IsAligned(down, a));
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignUp, AlignDown
- ///////////////////////////////////////////////////////////////////////////
- {
- for(uint8_t u8 = 0; u8 < 150; ++u8)
- {
- for(size_t a = 1; a < 64; a <<= 1)
- {
- uint8_t n = AlignUp(u8, a);
- EATEST_VERIFY(IsAligned(n, a) && (n >= u8));
- n = AlignDown(u8, a);
- EATEST_VERIFY(IsAligned(n, a) && (n <= u8));
- }
- }
- for(int16_t i16 = 0; i16 < 10000; ++i16)
- {
- for(size_t a = 1; a < 1024; a <<= 1)
- {
- int16_t n = AlignUp(i16, a);
- EATEST_VERIFY(IsAligned(n, a) && (n >= i16));
- n = AlignDown(i16, a);
- EATEST_VERIFY(IsAligned(n, a) && (n <= i16));
- }
- }
- for(uint32_t u32 = 0; u32 < 10000; ++u32)
- {
- for(size_t a = 1; a < 1024; a <<= 1)
- {
- uint32_t n = AlignUp(u32, a);
- EATEST_VERIFY(IsAligned(n, a) && (n >= u32));
- n = AlignDown(u32, a);
- EATEST_VERIFY(IsAligned(n, a) && (n <= u32));
- }
- }
- for(int64_t i64 = 0; i64 < 10000; ++i64)
- {
- for(size_t a = 1; a < 1024; a <<= 1)
- {
- int64_t n = AlignUp(i64, a);
- EATEST_VERIFY(IsAligned(n, a) && (n >= i64));
- n = AlignDown(i64, a);
- EATEST_VERIFY(IsAligned(n, a) && (n <= i64));
- }
- }
- for(char* p8 = 0; p8 < (char*)(uintptr_t)1000; ++p8)
- {
- for(size_t a = 1; a < 64; a <<= 1)
- {
- TestStruct* pTestStruct = (TestStruct*)(uintptr_t)p8;
- pTestStruct = AlignUp(pTestStruct, a);
- EATEST_VERIFY(IsAligned(pTestStruct, a) && ((uintptr_t)pTestStruct >= (uintptr_t)p8));
- pTestStruct = (TestStruct*)(uintptr_t)p8;
- pTestStruct = AlignDown(pTestStruct, a);
- EATEST_VERIFY(IsAligned(pTestStruct, a) && ((uintptr_t)pTestStruct <= (uintptr_t)p8));
- }
- }
- for(uint64_t x = 0; x < 1024; ++x)
- {
- for(size_t a = 1; a < 1024*1024; a <<= 1)
- {
- const uint64_t up = AlignUp(x, a);
- const uint64_t down = AlignDown(x, a);
- EATEST_VERIFY((up >= x) && IsAligned(up, a));
- EATEST_VERIFY((down <= x) && IsAligned(up, a));
- const uint64_t up1 = AlignUp <uint64_t, 1>(x);
- const uint64_t down1 = AlignDown<uint64_t, 1>(x);
- EATEST_VERIFY((up1 >= x) && IsAligned(up1, 1));
- EATEST_VERIFY((down1 <= x) && IsAligned(up1, 1));
- const uint64_t up2 = AlignUp <uint64_t, 2>(x);
- const uint64_t down2 = AlignDown<uint64_t, 2>(x);
- EATEST_VERIFY((up2 >= x) && IsAligned(up2, 2));
- EATEST_VERIFY((down2 <= x) && IsAligned(up2, 2));
- const uint64_t up4 = AlignUp <uint64_t, 4>(x);
- const uint64_t down4 = AlignDown<uint64_t, 4>(x);
- EATEST_VERIFY((up4 >= x) && IsAligned(up4, 4));
- EATEST_VERIFY((down4 <= x) && IsAligned(up4, 4));
- const uint64_t up8 = AlignUp <uint64_t, 8>(x);
- const uint64_t down8 = AlignDown<uint64_t, 8>(x);
- EATEST_VERIFY((up8 >= x) && IsAligned(up8, 8));
- EATEST_VERIFY((down8 <= x) && IsAligned(up8, 8));
- const uint64_t up16 = AlignUp <uint64_t, 16>(x);
- const uint64_t down16 = AlignDown<uint64_t, 16>(x);
- EATEST_VERIFY((up16 >= x) && IsAligned(up16, 16));
- EATEST_VERIFY((down16 <= x) && IsAligned(up16, 16));
- }
- }
- // Try again with address values around INT32_MAX
- for(uint64_t x = 0x7ffffff0; x < 0x800000ff; ++x)
- {
- for(size_t a = 1; a < 1024*1024; a <<= 1)
- {
- const uint64_t up = AlignUp(x, a);
- const uint64_t down = AlignDown(x, a);
- EATEST_VERIFY((up >= x) && IsAligned(up, a));
- EATEST_VERIFY((down <= x) && IsAligned(up, a));
- const uint64_t up1 = AlignUp <uint64_t, 1>(x);
- const uint64_t down1 = AlignDown<uint64_t, 1>(x);
- EATEST_VERIFY((up1 >= x) && IsAligned(up1, 1));
- EATEST_VERIFY((down1 <= x) && IsAligned(up1, 1));
- const uint64_t up2 = AlignUp <uint64_t, 2>(x);
- const uint64_t down2 = AlignDown<uint64_t, 2>(x);
- EATEST_VERIFY((up2 >= x) && IsAligned(up2, 2));
- EATEST_VERIFY((down2 <= x) && IsAligned(up2, 2));
- const uint64_t up4 = AlignUp <uint64_t, 4>(x);
- const uint64_t down4 = AlignDown<uint64_t, 4>(x);
- EATEST_VERIFY((up4 >= x) && IsAligned(up4, 4));
- EATEST_VERIFY((down4 <= x) && IsAligned(up4, 4));
- const uint64_t up8 = AlignUp <uint64_t, 8>(x);
- const uint64_t down8 = AlignDown<uint64_t, 8>(x);
- EATEST_VERIFY((up8 >= x) && IsAligned(up8, 8));
- EATEST_VERIFY((down8 <= x) && IsAligned(up8, 8));
- const uint64_t up16 = AlignUp <uint64_t, 16>(x);
- const uint64_t down16 = AlignDown<uint64_t, 16>(x);
- EATEST_VERIFY((up16 >= x) && IsAligned(up16, 16));
- EATEST_VERIFY((down16 <= x) && IsAligned(up16, 16));
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- // IsAligned
- ///////////////////////////////////////////////////////////////////////////
- {
- // template <typename T, int a>
- // inline bool IsAligned(T x)
- bool b = IsAligned<int, 8>(64);
- EATEST_VERIFY(b);
- b = IsAligned<int, 8>(67);
- EATEST_VERIFY(!b);
- // template <typename T, int a>
- // inline bool IsAligned(T* p)
- b = IsAligned<int, 64>((int*)NULL + 0);
- EATEST_VERIFY(b);
- b = IsAligned<int, 64>((int*)NULL + 1);
- EATEST_VERIFY(!b);
- // template <typename T>
- // inline bool IsAligned(T x, size_t a)
- EATEST_VERIFY( IsAligned(64, 8));
- EATEST_VERIFY(!IsAligned(67, 8));
- // template <typename T>
- // inline bool IsAligned(T* p, size_t a)
- EATEST_VERIFY( IsAligned((int*)NULL + 0, 64));
- EATEST_VERIFY(!IsAligned((int*)NULL + 1, 64));
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignedType
- ///////////////////////////////////////////////////////////////////////////
- {
- // Disabled until we can find a way that works for all compilers.
- #if 0 // !defined(__GNUC__) || (__GNUC__ < 4) // GCC4 lost the ability to do this
- const size_t kAlignment = 128;
- AlignedType<int, kAlignment>::Type intAlignedAt128;
- EATEST_VERIFY(((uintptr_t)&intAlignedAt128) % kAlignment == (uintptr_t)0);
- intAlignedAt128 = 12345;
- EATEST_VERIFY(intAlignedAt128 == 12345);
- #endif
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignedArray
- ///////////////////////////////////////////////////////////////////////////
- {
- const size_t kSize = 10;
- const size_t kAlignment = 64;
- {
- AlignedArray<TestStruct, kSize, kAlignment> mTestStructArray;
-
- // Note that as of this writing the convention is that only the first element
- // of the array should be aligned. Other elements should follow the first as
- // they naturally would otherwise.
- EATEST_VERIFY(((uintptr_t)&mTestStructArray[0]) % kAlignment == (uintptr_t)0);
- mTestStructArray[0] = mTestStructArray[1];
- AlignedArray<TestStruct, kSize, kAlignment> mTestStructArray2(mTestStructArray);
- mTestStructArray = mTestStructArray2;
- }
- // These tests instantiate SSE types to ensure they are supported by the AlignedArray. Previously,
- // these tests didn't work on Clang.
- #if defined EA_SSE && (EA_SSE >= 1)
- {
- AlignedArray<__m128, kSize, kAlignment> mTestVectorArray;
-
- // Note that as of this writing the convention is that only the first element
- // of the array should be aligned. Other elements should follow the first as
- // they naturally would otherwise.
- EATEST_VERIFY(((uintptr_t)&mTestVectorArray[0]) % kAlignment == (uintptr_t)0);
- mTestVectorArray[0] = mTestVectorArray[1];
- }
- #endif
- #if defined EA_SSE && (EA_SSE >= 2)
- {
- AlignedArray<__m128i, kSize, kAlignment> mTestVectorArray;
-
- // Note that as of this writing the convention is that only the first element
- // of the array should be aligned. Other elements should follow the first as
- // they naturally would otherwise.
- EATEST_VERIFY(((uintptr_t)&mTestVectorArray[0]) % kAlignment == (uintptr_t)0);
- mTestVectorArray[0] = mTestVectorArray[1];
- }
- #endif
- }
- ///////////////////////////////////////////////////////////////////////////
- // AlignedObject
- ///////////////////////////////////////////////////////////////////////////
- {
- const size_t kAlignment = 64;
- AlignedObject<TestStruct, kAlignment> mTestStruct;
-
- EATEST_VERIFY((uintptr_t)&mTestStruct % kAlignment == (uintptr_t)0);
- mTestStruct->a = 1;
- EATEST_VERIFY(mTestStruct->a == (unsigned)1);
- // (*(&mTestStruct))->b = 2; This is not possible; we need to use '.'
- (*(&mTestStruct)).b = 2;
- EATEST_VERIFY(mTestStruct->b == (unsigned)2);
- AlignedObject<TestStruct, kAlignment> mTestStruct2(mTestStruct);
- mTestStruct = mTestStruct2;
- // Todo: Test the following
- // T* operator &()
- // T* Get()
- // const T* Get() const
- // operator T&()
- // operator const T&() const
- // T* operator->()
- // const T* operator->() const
- // operator T*()
- // operator const T*() const
- }
- return nErrorCount;
- }
|