int_test.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/base/int.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <algorithm>
  8. #include <limits>
  9. namespace Carbon::Testing {
  10. struct IntStoreTestPeer {
  11. static constexpr int MinAPWidth = IntStore::MinAPWidth;
  12. static constexpr int32_t MaxIdEmbeddedValue = IntId::MaxValue;
  13. static constexpr int32_t MinIdEmbeddedValue = IntId::MinValue;
  14. };
  15. namespace {
  16. using ::testing::Eq;
  17. static constexpr int MinAPWidth = IntStoreTestPeer::MinAPWidth;
  18. static constexpr int32_t MaxIdEmbeddedValue =
  19. IntStoreTestPeer::MaxIdEmbeddedValue;
  20. static constexpr int32_t MinIdEmbeddedValue =
  21. IntStoreTestPeer::MinIdEmbeddedValue;
  22. TEST(IntStore, Basic) {
  23. IntStore ints;
  24. IntId id_0 = ints.Add(0);
  25. IntId id_1 = ints.Add(1);
  26. IntId id_2 = ints.Add(2);
  27. IntId id_42 = ints.Add(42);
  28. IntId id_n1 = ints.Add(-1);
  29. IntId id_n42 = ints.Add(-42);
  30. IntId id_nines = ints.Add(999'999'999'999);
  31. IntId id_max64 = ints.Add(std::numeric_limits<int64_t>::max());
  32. IntId id_min64 = ints.Add(std::numeric_limits<int64_t>::min());
  33. for (IntId id :
  34. {id_0, id_1, id_2, id_42, id_n1, id_n42, id_nines, id_max64, id_min64}) {
  35. ASSERT_TRUE(id.has_value());
  36. }
  37. // Small values should be embedded.
  38. EXPECT_THAT(id_0.AsValue(), Eq(0));
  39. EXPECT_THAT(id_1.AsValue(), Eq(1));
  40. EXPECT_THAT(id_2.AsValue(), Eq(2));
  41. EXPECT_THAT(id_42.AsValue(), Eq(42));
  42. EXPECT_THAT(id_n1.AsValue(), Eq(-1));
  43. EXPECT_THAT(id_n42.AsValue(), Eq(-42));
  44. // Rest should be indices as they don't fit as embedded values.
  45. EXPECT_TRUE(!id_nines.is_embedded_value());
  46. EXPECT_TRUE(id_nines.is_index());
  47. EXPECT_TRUE(!id_max64.is_embedded_value());
  48. EXPECT_TRUE(id_max64.is_index());
  49. EXPECT_TRUE(!id_min64.is_embedded_value());
  50. EXPECT_TRUE(id_min64.is_index());
  51. // And round tripping all the way through the store should work.
  52. EXPECT_THAT(ints.Get(id_0), Eq(0));
  53. EXPECT_THAT(ints.Get(id_1), Eq(1));
  54. EXPECT_THAT(ints.Get(id_2), Eq(2));
  55. EXPECT_THAT(ints.Get(id_42), Eq(42));
  56. EXPECT_THAT(ints.Get(id_n1), Eq(-1));
  57. EXPECT_THAT(ints.Get(id_n42), Eq(-42));
  58. EXPECT_THAT(ints.Get(id_nines), Eq(999'999'999'999));
  59. EXPECT_THAT(ints.Get(id_max64), Eq(std::numeric_limits<int64_t>::max()));
  60. EXPECT_THAT(ints.Get(id_min64), Eq(std::numeric_limits<int64_t>::min()));
  61. }
  62. // Helper struct to hold test values and the resulting IDs.
  63. struct APAndId {
  64. llvm::APInt ap;
  65. IntId id = IntId::None;
  66. };
  67. TEST(IntStore, APSigned) {
  68. IntStore ints;
  69. llvm::APInt big_128_ap =
  70. llvm::APInt(128, 0x1234'abcd'1234'abcd, /*isSigned=*/true) * 0xabcd'0000;
  71. llvm::APInt max_embedded_ap(MinAPWidth, MaxIdEmbeddedValue,
  72. /*isSigned=*/true);
  73. llvm::APInt min_embedded_ap(MinAPWidth, MinIdEmbeddedValue,
  74. /*isSigned=*/true);
  75. APAndId ap_and_ids[] = {
  76. {.ap = llvm::APInt(MinAPWidth, 1, /*isSigned=*/true)},
  77. {.ap = llvm::APInt(MinAPWidth, 2, /*isSigned=*/true)},
  78. {.ap = llvm::APInt(MinAPWidth, 999'999'999'999, /*isSigned=*/true)},
  79. {.ap = big_128_ap},
  80. {.ap = -big_128_ap},
  81. {.ap =
  82. big_128_ap.sext(512) * big_128_ap.sext(512) * big_128_ap.sext(512)},
  83. {.ap =
  84. -big_128_ap.sext(512) * big_128_ap.sext(512) * big_128_ap.sext(512)},
  85. {.ap = max_embedded_ap},
  86. {.ap = max_embedded_ap + 1},
  87. {.ap = min_embedded_ap},
  88. {.ap = min_embedded_ap - 1},
  89. };
  90. for (auto& [ap, id] : ap_and_ids) {
  91. id = ints.AddSigned(ap);
  92. ASSERT_TRUE(id.has_value()) << ap;
  93. }
  94. for (const auto& [ap, id] : ap_and_ids) {
  95. // The sign extend here may be a no-op, but the original bit width is a
  96. // reliable one at which to do the comparison.
  97. EXPECT_THAT(ints.Get(id).sext(ap.getBitWidth()), Eq(ap));
  98. }
  99. }
  100. TEST(IntStore, APUnsigned) {
  101. IntStore ints;
  102. llvm::APInt big_128_ap =
  103. llvm::APInt(128, 0xabcd'abcd'abcd'abcd) * 0xabcd'0000'abcd'0000;
  104. llvm::APInt max_embedded_ap(MinAPWidth, MaxIdEmbeddedValue);
  105. APAndId ap_and_ids[] = {
  106. {.ap = llvm::APInt(MinAPWidth, 1)},
  107. {.ap = llvm::APInt(MinAPWidth, 2)},
  108. {.ap = llvm::APInt(MinAPWidth, 999'999'999'999)},
  109. {.ap = llvm::APInt(MinAPWidth, std::numeric_limits<uint64_t>::max())},
  110. {.ap = llvm::APInt(MinAPWidth + 1, std::numeric_limits<uint64_t>::max()) +
  111. 1},
  112. {.ap = big_128_ap},
  113. {.ap =
  114. big_128_ap.zext(512) * big_128_ap.zext(512) * big_128_ap.zext(512)},
  115. {.ap = max_embedded_ap},
  116. {.ap = max_embedded_ap + 1},
  117. };
  118. for (auto& [ap, id] : ap_and_ids) {
  119. id = ints.AddUnsigned(ap);
  120. ASSERT_TRUE(id.has_value()) << ap;
  121. }
  122. for (const auto& [ap, id] : ap_and_ids) {
  123. auto stored_ap = ints.Get(id);
  124. // Pick a bit width wide enough to represent both whatever is returned and
  125. // the original value as a *signed* integer without any truncation.
  126. int width = std::max(stored_ap.getBitWidth(), ap.getBitWidth() + 1);
  127. // We sign extend the stored value and zero extend the original number. This
  128. // ensures that anything added as unsigned ends up stored as a positive
  129. // number even when sign extended.
  130. EXPECT_THAT(stored_ap.sext(width), Eq(ap.zext(width)));
  131. }
  132. }
  133. } // namespace
  134. } // namespace Carbon::Testing