TestAlignment.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EAStdC/EAAlignment.h>
  5. #include <EAStdCTest/EAStdCTest.h>
  6. #include <EATest/EATest.h>
  7. // Conditionally include SSE headers which some of the tests conditionally rely upon.
  8. #if EA_SSE
  9. #if EA_SSE >= 1
  10. #include <xmmintrin.h>
  11. #endif
  12. #if EA_SSE >= 2
  13. #include <emmintrin.h>
  14. #endif
  15. #if EA_SSE >= 1
  16. EASTDC_DECLARE_TRIVIAL_DESTRUCTOR(__m128)
  17. EASTDC_DECLARE_TRIVIAL_DESTRUCTOR(__m128i)
  18. #endif
  19. #endif
  20. using namespace EA::StdC;
  21. using namespace EA::UnitTest;
  22. ///////////////////////////////////////////////////////////////////////////////
  23. // TestStruct
  24. //
  25. // Helper class for our unit test.
  26. //
  27. struct TestStruct
  28. {
  29. uint32_t a;
  30. uint64_t b;
  31. char c;
  32. void* d;
  33. TestStruct() : a(0), b(0), c(0), d(0) {}
  34. };
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // TestTemplate
  37. //
  38. // Helper class for our unit test.
  39. //
  40. template <typename T>
  41. struct TestTemplate
  42. {
  43. uint32_t a;
  44. uint64_t b;
  45. char c;
  46. void* d;
  47. TestTemplate() : a(0), b(0), c(0), d(0) {}
  48. };
  49. ///////////////////////////////////////////////////////////////////////////////
  50. // TestAlignment
  51. //
  52. int TestAlignment()
  53. {
  54. int nErrorCount(0);
  55. ///////////////////////////////////////////////////////////////////////////
  56. // EAAlignOf
  57. ///////////////////////////////////////////////////////////////////////////
  58. {
  59. size_t a;
  60. // Type-based AlignOf
  61. a = EAAlignOf(uint32_t);
  62. EATEST_VERIFY(a == sizeof(uint32_t));
  63. #if (EA_PLATFORM_WORD_SIZE >= 8)
  64. a = EAAlignOf(uint64_t);
  65. EATEST_VERIFY(a == sizeof(uint64_t));
  66. #endif
  67. a = EAAlignOf(TestStruct);
  68. EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
  69. a = EAAlignOf(TestTemplate<int>);
  70. EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
  71. // Instance-based AlignOf
  72. uint32_t x32 = 0;
  73. a = AlignOf(x32);
  74. EATEST_VERIFY(a == sizeof(uint32_t));
  75. #if (EA_PLATFORM_WORD_SIZE >= 8)
  76. uint64_t x64 = 0;
  77. a = AlignOf(x64);
  78. EATEST_VERIFY(a == sizeof(uint64_t));
  79. #endif
  80. TestStruct testStruct;
  81. a = AlignOf(testStruct);
  82. EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
  83. TestTemplate<int> testTemplate;
  84. a = AlignOf(testTemplate);
  85. EATEST_VERIFY(((a * 2) / 2) == a); // This should always be true.
  86. }
  87. ///////////////////////////////////////////////////////////////////////////
  88. // AlignAddressUp, AlignObjectUp, AlignAddressDown, AlignObjectDown, GetAlignment
  89. ///////////////////////////////////////////////////////////////////////////
  90. {
  91. void* pResult;
  92. for(char* p = 0; p < (char*)100000; p++)
  93. {
  94. for(size_t i = 0; i < 18; i++)
  95. {
  96. uintptr_t a = ((size_t)1 << i);
  97. pResult = AlignAddressUp(p, a);
  98. EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
  99. pResult = AlignObjectUp(p, a);
  100. EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
  101. pResult = AlignAddressDown(p, ((size_t)1 << i));
  102. EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
  103. pResult = AlignObjectDown(p, ((size_t)1 << i));
  104. EATEST_VERIFY(((uintptr_t)pResult % a) == (uintptr_t)0);
  105. size_t alignment = GetAlignment(pResult);
  106. EATEST_VERIFY(alignment >= a); // We test >= because sometimes values are coincidentally aligned to a higher value than intended. Which is OK.
  107. bool bResult = IsAligned(pResult, a);
  108. EATEST_VERIFY(bResult);
  109. }
  110. }
  111. for(TestStruct* p = 0, *pTestStruct; p < (TestStruct*)100000; p++)
  112. {
  113. for(size_t i = 0; i < 18; i++)
  114. {
  115. uintptr_t a = ((size_t)1 << i);
  116. pTestStruct = AlignObjectUp(p, a);
  117. EATEST_VERIFY(((uintptr_t)pTestStruct % a) == (uintptr_t)0);
  118. pTestStruct = AlignObjectDown(p, ((size_t)1 << i));
  119. EATEST_VERIFY(((uintptr_t)pTestStruct % a) == (uintptr_t)0);
  120. size_t alignment = GetAlignment(pTestStruct);
  121. EATEST_VERIFY(alignment >= a); // We test >= because sometimes values are coincidentally aligned to a higher value than intended. Which is OK.
  122. bool bResult = IsAligned(pTestStruct, a);
  123. EATEST_VERIFY(bResult);
  124. }
  125. }
  126. }
  127. ///////////////////////////////////////////////////////////////////////////
  128. // AlignAddressUp
  129. ///////////////////////////////////////////////////////////////////////////
  130. {
  131. for(uintptr_t address = 0; address < 1024; ++address)
  132. {
  133. for(size_t a = 1; a < 1024*1024; a <<= 1)
  134. {
  135. const void* up = AlignAddressUp ((void*)address, a);
  136. const void* down = AlignAddressDown((void*)address, a);
  137. EATEST_VERIFY(((uintptr_t)up >= address) && IsAligned(up, a));
  138. EATEST_VERIFY(((uintptr_t)down <= address) && IsAligned(down, a));
  139. }
  140. }
  141. }
  142. ///////////////////////////////////////////////////////////////////////////
  143. // AlignUp, AlignDown
  144. ///////////////////////////////////////////////////////////////////////////
  145. {
  146. for(uint8_t u8 = 0; u8 < 150; ++u8)
  147. {
  148. for(size_t a = 1; a < 64; a <<= 1)
  149. {
  150. uint8_t n = AlignUp(u8, a);
  151. EATEST_VERIFY(IsAligned(n, a) && (n >= u8));
  152. n = AlignDown(u8, a);
  153. EATEST_VERIFY(IsAligned(n, a) && (n <= u8));
  154. }
  155. }
  156. for(int16_t i16 = 0; i16 < 10000; ++i16)
  157. {
  158. for(size_t a = 1; a < 1024; a <<= 1)
  159. {
  160. int16_t n = AlignUp(i16, a);
  161. EATEST_VERIFY(IsAligned(n, a) && (n >= i16));
  162. n = AlignDown(i16, a);
  163. EATEST_VERIFY(IsAligned(n, a) && (n <= i16));
  164. }
  165. }
  166. for(uint32_t u32 = 0; u32 < 10000; ++u32)
  167. {
  168. for(size_t a = 1; a < 1024; a <<= 1)
  169. {
  170. uint32_t n = AlignUp(u32, a);
  171. EATEST_VERIFY(IsAligned(n, a) && (n >= u32));
  172. n = AlignDown(u32, a);
  173. EATEST_VERIFY(IsAligned(n, a) && (n <= u32));
  174. }
  175. }
  176. for(int64_t i64 = 0; i64 < 10000; ++i64)
  177. {
  178. for(size_t a = 1; a < 1024; a <<= 1)
  179. {
  180. int64_t n = AlignUp(i64, a);
  181. EATEST_VERIFY(IsAligned(n, a) && (n >= i64));
  182. n = AlignDown(i64, a);
  183. EATEST_VERIFY(IsAligned(n, a) && (n <= i64));
  184. }
  185. }
  186. for(char* p8 = 0; p8 < (char*)(uintptr_t)1000; ++p8)
  187. {
  188. for(size_t a = 1; a < 64; a <<= 1)
  189. {
  190. TestStruct* pTestStruct = (TestStruct*)(uintptr_t)p8;
  191. pTestStruct = AlignUp(pTestStruct, a);
  192. EATEST_VERIFY(IsAligned(pTestStruct, a) && ((uintptr_t)pTestStruct >= (uintptr_t)p8));
  193. pTestStruct = (TestStruct*)(uintptr_t)p8;
  194. pTestStruct = AlignDown(pTestStruct, a);
  195. EATEST_VERIFY(IsAligned(pTestStruct, a) && ((uintptr_t)pTestStruct <= (uintptr_t)p8));
  196. }
  197. }
  198. for(uint64_t x = 0; x < 1024; ++x)
  199. {
  200. for(size_t a = 1; a < 1024*1024; a <<= 1)
  201. {
  202. const uint64_t up = AlignUp(x, a);
  203. const uint64_t down = AlignDown(x, a);
  204. EATEST_VERIFY((up >= x) && IsAligned(up, a));
  205. EATEST_VERIFY((down <= x) && IsAligned(up, a));
  206. const uint64_t up1 = AlignUp <uint64_t, 1>(x);
  207. const uint64_t down1 = AlignDown<uint64_t, 1>(x);
  208. EATEST_VERIFY((up1 >= x) && IsAligned(up1, 1));
  209. EATEST_VERIFY((down1 <= x) && IsAligned(up1, 1));
  210. const uint64_t up2 = AlignUp <uint64_t, 2>(x);
  211. const uint64_t down2 = AlignDown<uint64_t, 2>(x);
  212. EATEST_VERIFY((up2 >= x) && IsAligned(up2, 2));
  213. EATEST_VERIFY((down2 <= x) && IsAligned(up2, 2));
  214. const uint64_t up4 = AlignUp <uint64_t, 4>(x);
  215. const uint64_t down4 = AlignDown<uint64_t, 4>(x);
  216. EATEST_VERIFY((up4 >= x) && IsAligned(up4, 4));
  217. EATEST_VERIFY((down4 <= x) && IsAligned(up4, 4));
  218. const uint64_t up8 = AlignUp <uint64_t, 8>(x);
  219. const uint64_t down8 = AlignDown<uint64_t, 8>(x);
  220. EATEST_VERIFY((up8 >= x) && IsAligned(up8, 8));
  221. EATEST_VERIFY((down8 <= x) && IsAligned(up8, 8));
  222. const uint64_t up16 = AlignUp <uint64_t, 16>(x);
  223. const uint64_t down16 = AlignDown<uint64_t, 16>(x);
  224. EATEST_VERIFY((up16 >= x) && IsAligned(up16, 16));
  225. EATEST_VERIFY((down16 <= x) && IsAligned(up16, 16));
  226. }
  227. }
  228. // Try again with address values around INT32_MAX
  229. for(uint64_t x = 0x7ffffff0; x < 0x800000ff; ++x)
  230. {
  231. for(size_t a = 1; a < 1024*1024; a <<= 1)
  232. {
  233. const uint64_t up = AlignUp(x, a);
  234. const uint64_t down = AlignDown(x, a);
  235. EATEST_VERIFY((up >= x) && IsAligned(up, a));
  236. EATEST_VERIFY((down <= x) && IsAligned(up, a));
  237. const uint64_t up1 = AlignUp <uint64_t, 1>(x);
  238. const uint64_t down1 = AlignDown<uint64_t, 1>(x);
  239. EATEST_VERIFY((up1 >= x) && IsAligned(up1, 1));
  240. EATEST_VERIFY((down1 <= x) && IsAligned(up1, 1));
  241. const uint64_t up2 = AlignUp <uint64_t, 2>(x);
  242. const uint64_t down2 = AlignDown<uint64_t, 2>(x);
  243. EATEST_VERIFY((up2 >= x) && IsAligned(up2, 2));
  244. EATEST_VERIFY((down2 <= x) && IsAligned(up2, 2));
  245. const uint64_t up4 = AlignUp <uint64_t, 4>(x);
  246. const uint64_t down4 = AlignDown<uint64_t, 4>(x);
  247. EATEST_VERIFY((up4 >= x) && IsAligned(up4, 4));
  248. EATEST_VERIFY((down4 <= x) && IsAligned(up4, 4));
  249. const uint64_t up8 = AlignUp <uint64_t, 8>(x);
  250. const uint64_t down8 = AlignDown<uint64_t, 8>(x);
  251. EATEST_VERIFY((up8 >= x) && IsAligned(up8, 8));
  252. EATEST_VERIFY((down8 <= x) && IsAligned(up8, 8));
  253. const uint64_t up16 = AlignUp <uint64_t, 16>(x);
  254. const uint64_t down16 = AlignDown<uint64_t, 16>(x);
  255. EATEST_VERIFY((up16 >= x) && IsAligned(up16, 16));
  256. EATEST_VERIFY((down16 <= x) && IsAligned(up16, 16));
  257. }
  258. }
  259. }
  260. ///////////////////////////////////////////////////////////////////////////
  261. // IsAligned
  262. ///////////////////////////////////////////////////////////////////////////
  263. {
  264. // template <typename T, int a>
  265. // inline bool IsAligned(T x)
  266. bool b = IsAligned<int, 8>(64);
  267. EATEST_VERIFY(b);
  268. b = IsAligned<int, 8>(67);
  269. EATEST_VERIFY(!b);
  270. // template <typename T, int a>
  271. // inline bool IsAligned(T* p)
  272. b = IsAligned<int, 64>((int*)NULL + 0);
  273. EATEST_VERIFY(b);
  274. b = IsAligned<int, 64>((int*)NULL + 1);
  275. EATEST_VERIFY(!b);
  276. // template <typename T>
  277. // inline bool IsAligned(T x, size_t a)
  278. EATEST_VERIFY( IsAligned(64, 8));
  279. EATEST_VERIFY(!IsAligned(67, 8));
  280. // template <typename T>
  281. // inline bool IsAligned(T* p, size_t a)
  282. EATEST_VERIFY( IsAligned((int*)NULL + 0, 64));
  283. EATEST_VERIFY(!IsAligned((int*)NULL + 1, 64));
  284. }
  285. ///////////////////////////////////////////////////////////////////////////
  286. // AlignedType
  287. ///////////////////////////////////////////////////////////////////////////
  288. {
  289. // Disabled until we can find a way that works for all compilers.
  290. #if 0 // !defined(__GNUC__) || (__GNUC__ < 4) // GCC4 lost the ability to do this
  291. const size_t kAlignment = 128;
  292. AlignedType<int, kAlignment>::Type intAlignedAt128;
  293. EATEST_VERIFY(((uintptr_t)&intAlignedAt128) % kAlignment == (uintptr_t)0);
  294. intAlignedAt128 = 12345;
  295. EATEST_VERIFY(intAlignedAt128 == 12345);
  296. #endif
  297. }
  298. ///////////////////////////////////////////////////////////////////////////
  299. // AlignedArray
  300. ///////////////////////////////////////////////////////////////////////////
  301. {
  302. const size_t kSize = 10;
  303. const size_t kAlignment = 64;
  304. {
  305. AlignedArray<TestStruct, kSize, kAlignment> mTestStructArray;
  306. // Note that as of this writing the convention is that only the first element
  307. // of the array should be aligned. Other elements should follow the first as
  308. // they naturally would otherwise.
  309. EATEST_VERIFY(((uintptr_t)&mTestStructArray[0]) % kAlignment == (uintptr_t)0);
  310. mTestStructArray[0] = mTestStructArray[1];
  311. AlignedArray<TestStruct, kSize, kAlignment> mTestStructArray2(mTestStructArray);
  312. mTestStructArray = mTestStructArray2;
  313. }
  314. // These tests instantiate SSE types to ensure they are supported by the AlignedArray. Previously,
  315. // these tests didn't work on Clang.
  316. #if defined EA_SSE && (EA_SSE >= 1)
  317. {
  318. AlignedArray<__m128, kSize, kAlignment> mTestVectorArray;
  319. // Note that as of this writing the convention is that only the first element
  320. // of the array should be aligned. Other elements should follow the first as
  321. // they naturally would otherwise.
  322. EATEST_VERIFY(((uintptr_t)&mTestVectorArray[0]) % kAlignment == (uintptr_t)0);
  323. mTestVectorArray[0] = mTestVectorArray[1];
  324. }
  325. #endif
  326. #if defined EA_SSE && (EA_SSE >= 2)
  327. {
  328. AlignedArray<__m128i, kSize, kAlignment> mTestVectorArray;
  329. // Note that as of this writing the convention is that only the first element
  330. // of the array should be aligned. Other elements should follow the first as
  331. // they naturally would otherwise.
  332. EATEST_VERIFY(((uintptr_t)&mTestVectorArray[0]) % kAlignment == (uintptr_t)0);
  333. mTestVectorArray[0] = mTestVectorArray[1];
  334. }
  335. #endif
  336. }
  337. ///////////////////////////////////////////////////////////////////////////
  338. // AlignedObject
  339. ///////////////////////////////////////////////////////////////////////////
  340. {
  341. const size_t kAlignment = 64;
  342. AlignedObject<TestStruct, kAlignment> mTestStruct;
  343. EATEST_VERIFY((uintptr_t)&mTestStruct % kAlignment == (uintptr_t)0);
  344. mTestStruct->a = 1;
  345. EATEST_VERIFY(mTestStruct->a == (unsigned)1);
  346. // (*(&mTestStruct))->b = 2; This is not possible; we need to use '.'
  347. (*(&mTestStruct)).b = 2;
  348. EATEST_VERIFY(mTestStruct->b == (unsigned)2);
  349. AlignedObject<TestStruct, kAlignment> mTestStruct2(mTestStruct);
  350. mTestStruct = mTestStruct2;
  351. // Todo: Test the following
  352. // T* operator &()
  353. // T* Get()
  354. // const T* Get() const
  355. // operator T&()
  356. // operator const T&() const
  357. // T* operator->()
  358. // const T* operator->() const
  359. // operator T*()
  360. // operator const T*() const
  361. }
  362. return nErrorCount;
  363. }