xref: /llvm-project/libc/test/src/string/memory_utils/utils_test.cpp (revision 2cfae7cdf4514652156bfbc0c240df2112ab925c)
1 //===-- Unittests for memory_utils ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/CPP/array.h"
10 #include "src/string/memory_utils/utils.h"
11 #include "test/UnitTest/Test.h"
12 
13 namespace __llvm_libc {
14 
15 TEST(LlvmLibcUtilsTest, IsPowerOfTwoOrZero) {
16   static const cpp::array<bool, 65> kExpectedValues{
17       1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 0-15
18       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
19       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47
20       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63
21       1                                               // 64
22   };
23   for (size_t i = 0; i < kExpectedValues.size(); ++i)
24     EXPECT_EQ(is_power2_or_zero(i), kExpectedValues[i]);
25 }
26 
27 TEST(LlvmLibcUtilsTest, IsPowerOfTwo) {
28   static const cpp::array<bool, 65> kExpectedValues{
29       0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 0-15
30       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
31       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47
32       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48-63
33       1                                               // 64
34   };
35   for (size_t i = 0; i < kExpectedValues.size(); ++i)
36     EXPECT_EQ(is_power2(i), kExpectedValues[i]);
37 }
38 
39 TEST(LlvmLibcUtilsTest, Log2) {
40   static const cpp::array<size_t, 65> kExpectedValues{
41       0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 0-15
42       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16-31
43       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 32-47
44       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 48-63
45       6                                               // 64
46   };
47   for (size_t i = 0; i < kExpectedValues.size(); ++i)
48     EXPECT_EQ(log2s(i), kExpectedValues[i]);
49 }
50 
51 TEST(LlvmLibcUtilsTest, LEPowerOf2) {
52   static const cpp::array<size_t, 65> kExpectedValues{
53       0,  1,  2,  2,  4,  4,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  // 0-15
54       16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, // 16-31
55       32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 32-47
56       32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 48-63
57       64                                                              // 64
58   };
59   for (size_t i = 0; i < kExpectedValues.size(); ++i)
60     EXPECT_EQ(le_power2(i), kExpectedValues[i]);
61 }
62 
63 TEST(LlvmLibcUtilsTest, GEPowerOf2) {
64   static const cpp::array<size_t, 66> kExpectedValues{
65       0,  1,  2,  4,  4,  8,  8,  8,  8,  16, 16, 16, 16, 16, 16, 16, // 0-15
66       16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 16-31
67       32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 32-47
68       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 48-63
69       64, 128                                                         // 64-65
70   };
71   for (size_t i = 0; i < kExpectedValues.size(); ++i)
72     EXPECT_EQ(ge_power2(i), kExpectedValues[i]);
73 }
74 
75 using UINT = uintptr_t;
76 
77 // Converts an offset into a pointer.
78 const void *forge(size_t offset) {
79   return reinterpret_cast<const void *>(offset);
80 }
81 
82 TEST(LlvmLibcUtilsTest, DistanceToNextAligned) {
83   EXPECT_EQ(distance_to_next_aligned<16>(forge(0)), UINT(16));
84   EXPECT_EQ(distance_to_next_aligned<16>(forge(1)), UINT(15));
85   EXPECT_EQ(distance_to_next_aligned<16>(forge(16)), UINT(16));
86   EXPECT_EQ(distance_to_next_aligned<16>(forge(15)), UINT(1));
87   EXPECT_EQ(distance_to_next_aligned<32>(forge(16)), UINT(16));
88 }
89 
90 TEST(LlvmLibcUtilsTest, DistanceToAlignUp) {
91   EXPECT_EQ(distance_to_align_up<16>(forge(0)), UINT(0));
92   EXPECT_EQ(distance_to_align_up<16>(forge(1)), UINT(15));
93   EXPECT_EQ(distance_to_align_up<16>(forge(16)), UINT(0));
94   EXPECT_EQ(distance_to_align_up<16>(forge(15)), UINT(1));
95   EXPECT_EQ(distance_to_align_up<32>(forge(16)), UINT(16));
96 }
97 
98 TEST(LlvmLibcUtilsTest, DistanceToAlignDown) {
99   EXPECT_EQ(distance_to_align_down<16>(forge(0)), UINT(0));
100   EXPECT_EQ(distance_to_align_down<16>(forge(1)), UINT(1));
101   EXPECT_EQ(distance_to_align_down<16>(forge(16)), UINT(0));
102   EXPECT_EQ(distance_to_align_down<16>(forge(15)), UINT(15));
103   EXPECT_EQ(distance_to_align_down<32>(forge(16)), UINT(16));
104 }
105 
106 TEST(LlvmLibcUtilsTest, Adjust2) {
107   char a, b;
108   const size_t base_size = 10;
109   for (ptrdiff_t I = -2; I < 2; ++I) {
110     auto *p1 = &a;
111     auto *p2 = &b;
112     size_t size = base_size;
113     adjust(I, p1, p2, size);
114     EXPECT_EQ(intptr_t(p1), intptr_t(&a + I));
115     EXPECT_EQ(intptr_t(p2), intptr_t(&b + I));
116     EXPECT_EQ(size, base_size - I);
117   }
118 }
119 
120 TEST(LlvmLibcUtilsTest, Align2) {
121   char a, b;
122   const size_t base_size = 10;
123   {
124     auto *p1 = &a;
125     auto *p2 = &b;
126     size_t size = base_size;
127     align_to_next_boundary<128, Arg::P1>(p1, p2, size);
128     EXPECT_TRUE(uintptr_t(p1) % 128 == 0);
129     EXPECT_GT(p1, &a);
130     EXPECT_GT(p2, &b);
131     EXPECT_EQ(size_t(p1 - &a), base_size - size);
132     EXPECT_EQ(size_t(p2 - &b), base_size - size);
133   }
134   {
135     auto *p1 = &a;
136     auto *p2 = &b;
137     size_t size = base_size;
138     align_to_next_boundary<128, Arg::P2>(p1, p2, size);
139     EXPECT_TRUE(uintptr_t(p2) % 128 == 0);
140     EXPECT_GT(p1, &a);
141     EXPECT_GT(p2, &b);
142     EXPECT_EQ(size_t(p1 - &a), base_size - size);
143     EXPECT_EQ(size_t(p2 - &b), base_size - size);
144   }
145 }
146 
147 TEST(LlvmLibcUtilsTest, DisjointBuffers) {
148   char buf[3];
149   const char *const a = buf + 0;
150   const char *const b = buf + 1;
151   EXPECT_TRUE(is_disjoint(a, b, 0));
152   EXPECT_TRUE(is_disjoint(a, b, 1));
153   EXPECT_FALSE(is_disjoint(a, b, 2));
154 
155   EXPECT_TRUE(is_disjoint(b, a, 0));
156   EXPECT_TRUE(is_disjoint(b, a, 1));
157   EXPECT_FALSE(is_disjoint(b, a, 2));
158 }
159 
160 TEST(LlvmLibcUtilsTest, LoadStoreAligned) {
161   const uint64_t init = 0xDEAD'C0DE'BEEF'F00D;
162   CPtr const src = reinterpret_cast<CPtr>(&init);
163   uint64_t store;
164   Ptr const dst = reinterpret_cast<Ptr>(&store);
165 
166   using LoadFun = uint64_t (*)(CPtr);
167   using StoreFun = void (*)(uint64_t, Ptr);
168 
169   {
170     LoadFun ld = load_aligned<uint64_t, uint64_t>;
171     StoreFun st = store_aligned<uint64_t, uint64_t>;
172     const uint64_t loaded = ld(src);
173     EXPECT_EQ(init, loaded);
174     store = 0;
175     st(init, dst);
176     EXPECT_EQ(init, store);
177   }
178 
179   {
180     LoadFun ld = load_aligned<uint64_t, uint32_t, uint32_t>;
181     StoreFun st = store_aligned<uint64_t, uint32_t, uint32_t>;
182     const uint64_t loaded = ld(src);
183     EXPECT_EQ(init, loaded);
184     store = 0;
185     st(init, dst);
186     EXPECT_EQ(init, store);
187   }
188 
189   {
190     LoadFun ld = load_aligned<uint64_t, uint32_t, uint16_t, uint8_t, uint8_t>;
191     StoreFun st = store_aligned<uint64_t, uint32_t, uint16_t, uint8_t, uint8_t>;
192     const uint64_t loaded = ld(src);
193     EXPECT_EQ(init, loaded);
194     store = 0;
195     st(init, dst);
196     EXPECT_EQ(init, store);
197   }
198 }
199 
200 } // namespace __llvm_libc
201