unaligned_mem_ut.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #include "unaligned_mem.h"
  2. #include <library/cpp/testing/benchmark/bench.h>
  3. #include <library/cpp/testing/unittest/registar.h>
  4. #include <util/system/compiler.h>
  5. #ifdef Y_HAVE_INT128
  6. namespace {
  7. struct TUInt128 {
  8. bool operator==(const TUInt128& other) const {
  9. return x == other.x;
  10. }
  11. ui64 Low() const {
  12. return (ui64)x;
  13. }
  14. ui64 High() const {
  15. return (ui64)(x >> 64);
  16. }
  17. static TUInt128 Max() {
  18. return {~(__uint128_t)0};
  19. }
  20. __uint128_t x;
  21. };
  22. } // namespace
  23. #endif
  24. Y_UNIT_TEST_SUITE(UnalignedMem) {
  25. Y_UNIT_TEST(TestReadWrite) {
  26. alignas(ui64) char buf[100];
  27. WriteUnaligned<ui16>(buf + 1, (ui16)1);
  28. WriteUnaligned<ui32>(buf + 1 + 2, (ui32)2);
  29. WriteUnaligned<ui64>(buf + 1 + 2 + 4, (ui64)3);
  30. UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui16>(buf + 1), 1);
  31. UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui32>(buf + 1 + 2), 2);
  32. UNIT_ASSERT_VALUES_EQUAL(ReadUnaligned<ui64>(buf + 1 + 2 + 4), 3);
  33. }
  34. Y_UNIT_TEST(TestReadWriteRuntime) {
  35. // Unlike the test above, this test avoids compile-time execution by a smart compiler.
  36. // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction.
  37. alignas(ui64) static char buf[100] = {0}; // static is required for Clobber to work
  38. WriteUnaligned<ui16>(buf + 1, (ui16)1);
  39. WriteUnaligned<ui32>(buf + 1 + 2, (ui32)2);
  40. WriteUnaligned<ui64>(buf + 1 + 2 + 4, (ui64)3);
  41. NBench::Clobber();
  42. auto val1 = ReadUnaligned<ui16>(buf + 1);
  43. auto val2 = ReadUnaligned<ui32>(buf + 1 + 2);
  44. auto val3 = ReadUnaligned<ui64>(buf + 1 + 2 + 4);
  45. Y_DO_NOT_OPTIMIZE_AWAY(&val1);
  46. Y_DO_NOT_OPTIMIZE_AWAY(&val2);
  47. Y_DO_NOT_OPTIMIZE_AWAY(&val3);
  48. Y_DO_NOT_OPTIMIZE_AWAY(val1);
  49. Y_DO_NOT_OPTIMIZE_AWAY(val2);
  50. Y_DO_NOT_OPTIMIZE_AWAY(val3);
  51. UNIT_ASSERT_VALUES_EQUAL(val1, 1);
  52. UNIT_ASSERT_VALUES_EQUAL(val2, 2);
  53. UNIT_ASSERT_VALUES_EQUAL(val3, 3);
  54. }
  55. #ifdef Y_HAVE_INT128
  56. Y_UNIT_TEST(TestReadWrite128) {
  57. alignas(TUInt128) char buf[100] = {0};
  58. WriteUnaligned<TUInt128>(buf + 1, TUInt128::Max());
  59. auto val = ReadUnaligned<TUInt128>(buf + 1);
  60. UNIT_ASSERT(val == TUInt128::Max());
  61. }
  62. Y_UNIT_TEST(TestReadWriteRuntime128) {
  63. // Unlike the test above, this test avoids compile-time execution by a smart compiler.
  64. // It is required to catch the SIGSEGV in case compiler emits an alignment-sensitive instruction.
  65. alignas(TUInt128) static char buf[100] = {0}; // static is required for Clobber to work
  66. WriteUnaligned<TUInt128>(buf + 1, TUInt128::Max());
  67. NBench::Clobber();
  68. auto val = ReadUnaligned<TUInt128>(buf + 1);
  69. Y_DO_NOT_OPTIMIZE_AWAY(&val);
  70. Y_DO_NOT_OPTIMIZE_AWAY(val.Low());
  71. Y_DO_NOT_OPTIMIZE_AWAY(val.High());
  72. UNIT_ASSERT(val == TUInt128::Max());
  73. }
  74. #endif
  75. } // Y_UNIT_TEST_SUITE(UnalignedMem)