TestAlignment.cpp 13 KB

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