1 | //=== - llvm/unittest/Support/Alignment.cpp - Alignment utility tests -----===// |
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 "llvm/Support/Alignment.h" |
10 | #include "llvm/ADT/STLExtras.h" |
11 | #include "gtest/gtest.h" |
12 | |
13 | #include <vector> |
14 | |
15 | #ifdef _MSC_VER |
16 | // Disable warnings about potential divide by 0. |
17 | #pragma warning(push) |
18 | #pragma warning(disable : 4723) |
19 | #endif |
20 | |
21 | using namespace llvm; |
22 | |
23 | namespace { |
24 | |
25 | TEST(AlignmentTest, AlignOfConstant) { |
26 | EXPECT_EQ(Align::Of<uint8_t>(), Align(alignof(uint8_t))); |
27 | EXPECT_EQ(Align::Of<uint16_t>(), Align(alignof(uint16_t))); |
28 | EXPECT_EQ(Align::Of<uint32_t>(), Align(alignof(uint32_t))); |
29 | EXPECT_EQ(Align::Of<uint64_t>(), Align(alignof(uint64_t))); |
30 | } |
31 | |
32 | TEST(AlignmentTest, AlignConstant) { |
33 | EXPECT_EQ(Align::Constant<1>(), Align(1)); |
34 | EXPECT_EQ(Align::Constant<2>(), Align(2)); |
35 | EXPECT_EQ(Align::Constant<4>(), Align(4)); |
36 | EXPECT_EQ(Align::Constant<8>(), Align(8)); |
37 | EXPECT_EQ(Align::Constant<16>(), Align(16)); |
38 | EXPECT_EQ(Align::Constant<32>(), Align(32)); |
39 | EXPECT_EQ(Align::Constant<64>(), Align(64)); |
40 | } |
41 | |
42 | TEST(AlignmentTest, AlignConstexprConstant) { |
43 | constexpr Align kConstantAlign = Align::Of<uint64_t>(); |
44 | EXPECT_EQ(Align(alignof(uint64_t)), kConstantAlign); |
45 | } |
46 | |
47 | std::vector<uint64_t> getValidAlignments() { |
48 | std::vector<uint64_t> Out; |
49 | for (size_t Shift = 0; Shift < 64; ++Shift) |
50 | Out.push_back(x: 1ULL << Shift); |
51 | return Out; |
52 | } |
53 | |
54 | TEST(AlignmentTest, AlignDefaultCTor) { EXPECT_EQ(Align().value(), 1ULL); } |
55 | |
56 | TEST(AlignmentTest, MaybeAlignDefaultCTor) { EXPECT_FALSE(MaybeAlign()); } |
57 | |
58 | TEST(AlignmentTest, ValidCTors) { |
59 | for (uint64_t Value : getValidAlignments()) { |
60 | EXPECT_EQ(Align(Value).value(), Value); |
61 | EXPECT_EQ((*MaybeAlign(Value)).value(), Value); |
62 | } |
63 | } |
64 | |
65 | TEST(AlignmentTest, CheckMaybeAlignHasValue) { |
66 | EXPECT_TRUE(MaybeAlign(1)); |
67 | EXPECT_TRUE(MaybeAlign(1).has_value()); |
68 | EXPECT_FALSE(MaybeAlign(0)); |
69 | EXPECT_FALSE(MaybeAlign(0).has_value()); |
70 | EXPECT_FALSE(MaybeAlign()); |
71 | EXPECT_FALSE(MaybeAlign().has_value()); |
72 | } |
73 | |
74 | TEST(AlignmentTest, Division) { |
75 | for (uint64_t Value : getValidAlignments()) { |
76 | if (Value > 1) { |
77 | EXPECT_EQ(Align(Value).previous(), Value / 2); |
78 | } |
79 | } |
80 | } |
81 | |
82 | TEST(AlignmentTest, AlignTo) { |
83 | struct { |
84 | uint64_t alignment; |
85 | uint64_t offset; |
86 | uint64_t rounded; |
87 | const void *forgedAddr() const { |
88 | // A value of any integral or enumeration type can be converted to a |
89 | // pointer type. |
90 | return reinterpret_cast<const void *>(offset); |
91 | } |
92 | } kTests[] = { |
93 | // Align |
94 | {.alignment: 1, .offset: 0, .rounded: 0}, {.alignment: 1, .offset: 1, .rounded: 1}, {.alignment: 1, .offset: 5, .rounded: 5}, {.alignment: 2, .offset: 0, .rounded: 0}, {.alignment: 2, .offset: 1, .rounded: 2}, {.alignment: 2, .offset: 2, .rounded: 2}, |
95 | {.alignment: 2, .offset: 7, .rounded: 8}, {.alignment: 2, .offset: 16, .rounded: 16}, {.alignment: 4, .offset: 0, .rounded: 0}, {.alignment: 4, .offset: 1, .rounded: 4}, {.alignment: 4, .offset: 4, .rounded: 4}, {.alignment: 4, .offset: 6, .rounded: 8}, |
96 | }; |
97 | for (const auto &T : kTests) { |
98 | Align A = Align(T.alignment); |
99 | EXPECT_EQ(alignTo(T.offset, A), T.rounded); |
100 | EXPECT_EQ(alignAddr(T.forgedAddr(), A), T.rounded); |
101 | } |
102 | } |
103 | |
104 | TEST(AlignmentTest, AlignToWithSkew) { |
105 | EXPECT_EQ(alignTo(5, Align(8), 0), alignTo(5, Align(8))); |
106 | EXPECT_EQ(alignTo(5, Align(8), 7), 7U); |
107 | EXPECT_EQ(alignTo(17, Align(8), 1), 17U); |
108 | EXPECT_EQ(alignTo(~0LL, Align(8), 3), 3U); |
109 | } |
110 | |
111 | TEST(AlignmentTest, Log2) { |
112 | for (uint64_t Value : getValidAlignments()) { |
113 | EXPECT_EQ(Log2(Align(Value)), Log2_64(Value)); |
114 | } |
115 | } |
116 | |
117 | TEST(AlignmentTest, Encode_Decode) { |
118 | for (uint64_t Value : getValidAlignments()) { |
119 | { |
120 | Align Actual(Value); |
121 | Align Expected = *decodeMaybeAlign(Value: encode(A: Actual)); |
122 | EXPECT_EQ(Expected, Actual); |
123 | } |
124 | { |
125 | MaybeAlign Actual(Value); |
126 | MaybeAlign Expected = decodeMaybeAlign(Value: encode(A: Actual)); |
127 | EXPECT_EQ(Expected, Actual); |
128 | } |
129 | } |
130 | MaybeAlign Actual(0); |
131 | MaybeAlign Expected = decodeMaybeAlign(Value: encode(A: Actual)); |
132 | EXPECT_EQ(Expected, Actual); |
133 | } |
134 | |
135 | TEST(AlignmentTest, isAligned_isAddrAligned) { |
136 | struct { |
137 | uint64_t alignment; |
138 | uint64_t offset; |
139 | bool isAligned; |
140 | const void *forgedAddr() const { |
141 | // A value of any integral or enumeration type can be converted to a |
142 | // pointer type. |
143 | return reinterpret_cast<const void *>(offset); |
144 | } |
145 | } kTests[] = { |
146 | {.alignment: 1, .offset: 0, .isAligned: true}, {.alignment: 1, .offset: 1, .isAligned: true}, {.alignment: 1, .offset: 5, .isAligned: true}, {.alignment: 2, .offset: 0, .isAligned: true}, |
147 | {.alignment: 2, .offset: 1, .isAligned: false}, {.alignment: 2, .offset: 2, .isAligned: true}, {.alignment: 2, .offset: 7, .isAligned: false}, {.alignment: 2, .offset: 16, .isAligned: true}, |
148 | {.alignment: 4, .offset: 0, .isAligned: true}, {.alignment: 4, .offset: 1, .isAligned: false}, {.alignment: 4, .offset: 4, .isAligned: true}, {.alignment: 4, .offset: 6, .isAligned: false}, |
149 | }; |
150 | for (const auto &T : kTests) { |
151 | MaybeAlign A(T.alignment); |
152 | // Test Align |
153 | if (A) { |
154 | EXPECT_EQ(isAligned(*A, T.offset), T.isAligned); |
155 | EXPECT_EQ(isAddrAligned(*A, T.forgedAddr()), T.isAligned); |
156 | } |
157 | } |
158 | } |
159 | |
160 | TEST(AlignmentTest, offsetToAlignment) { |
161 | struct { |
162 | uint64_t alignment; |
163 | uint64_t offset; |
164 | uint64_t alignedOffset; |
165 | const void *forgedAddr() const { |
166 | // A value of any integral or enumeration type can be converted to a |
167 | // pointer type. |
168 | return reinterpret_cast<const void *>(offset); |
169 | } |
170 | } kTests[] = { |
171 | {.alignment: 1, .offset: 0, .alignedOffset: 0}, {.alignment: 1, .offset: 1, .alignedOffset: 0}, {.alignment: 1, .offset: 5, .alignedOffset: 0}, {.alignment: 2, .offset: 0, .alignedOffset: 0}, {.alignment: 2, .offset: 1, .alignedOffset: 1}, {.alignment: 2, .offset: 2, .alignedOffset: 0}, |
172 | {.alignment: 2, .offset: 7, .alignedOffset: 1}, {.alignment: 2, .offset: 16, .alignedOffset: 0}, {.alignment: 4, .offset: 0, .alignedOffset: 0}, {.alignment: 4, .offset: 1, .alignedOffset: 3}, {.alignment: 4, .offset: 4, .alignedOffset: 0}, {.alignment: 4, .offset: 6, .alignedOffset: 2}, |
173 | }; |
174 | for (const auto &T : kTests) { |
175 | const Align A(T.alignment); |
176 | EXPECT_EQ(offsetToAlignment(T.offset, A), T.alignedOffset); |
177 | EXPECT_EQ(offsetToAlignedAddr(T.forgedAddr(), A), T.alignedOffset); |
178 | } |
179 | } |
180 | |
181 | TEST(AlignmentTest, AlignComparisons) { |
182 | std::vector<uint64_t> ValidAlignments = getValidAlignments(); |
183 | llvm::sort(C&: ValidAlignments); |
184 | for (size_t I = 1; I < ValidAlignments.size(); ++I) { |
185 | assert(I >= 1); |
186 | const Align A(ValidAlignments[I - 1]); |
187 | const Align B(ValidAlignments[I]); |
188 | EXPECT_EQ(A, A); |
189 | EXPECT_NE(A, B); |
190 | EXPECT_LT(A, B); |
191 | EXPECT_GT(B, A); |
192 | EXPECT_LE(A, B); |
193 | EXPECT_GE(B, A); |
194 | EXPECT_LE(A, A); |
195 | EXPECT_GE(A, A); |
196 | |
197 | EXPECT_EQ(A, A.value()); |
198 | EXPECT_NE(A, B.value()); |
199 | EXPECT_LT(A, B.value()); |
200 | EXPECT_GT(B, A.value()); |
201 | EXPECT_LE(A, B.value()); |
202 | EXPECT_GE(B, A.value()); |
203 | EXPECT_LE(A, A.value()); |
204 | EXPECT_GE(A, A.value()); |
205 | |
206 | EXPECT_EQ(std::max(A, B), B); |
207 | EXPECT_EQ(std::min(A, B), A); |
208 | |
209 | const MaybeAlign MA(ValidAlignments[I - 1]); |
210 | const MaybeAlign MB(ValidAlignments[I]); |
211 | EXPECT_EQ(MA, MA); |
212 | EXPECT_NE(MA, MB); |
213 | |
214 | EXPECT_EQ(std::max(A, B), B); |
215 | EXPECT_EQ(std::min(A, B), A); |
216 | } |
217 | } |
218 | |
219 | TEST(AlignmentTest, AssumeAligned) { |
220 | EXPECT_EQ(assumeAligned(0), Align(1)); |
221 | EXPECT_EQ(assumeAligned(0), Align()); |
222 | EXPECT_EQ(assumeAligned(1), Align(1)); |
223 | EXPECT_EQ(assumeAligned(1), Align()); |
224 | } |
225 | |
226 | // Death tests reply on assert which is disabled in release mode. |
227 | #ifndef NDEBUG |
228 | |
229 | // We use a subset of valid alignments for DEATH_TESTs as they are particularly |
230 | // slow. |
231 | std::vector<uint64_t> getValidAlignmentsForDeathTest() { |
232 | return {1, 1ULL << 31, 1ULL << 63}; |
233 | } |
234 | |
235 | std::vector<uint64_t> getNonPowerOfTwo() { return {3, 10, 15}; } |
236 | |
237 | TEST(AlignmentDeathTest, InvalidCTors) { |
238 | EXPECT_DEATH((Align(0)), "Value must not be 0" ); |
239 | for (uint64_t Value : getNonPowerOfTwo()) { |
240 | EXPECT_DEATH((Align(Value)), "Alignment is not a power of 2" ); |
241 | EXPECT_DEATH((MaybeAlign(Value)), |
242 | "Alignment is neither 0 nor a power of 2" ); |
243 | } |
244 | } |
245 | |
246 | TEST(AlignmentDeathTest, ComparisonsWithZero) { |
247 | for (uint64_t Value : getValidAlignmentsForDeathTest()) { |
248 | EXPECT_DEATH((void)(Align(Value) == 0), ".* should be defined" ); |
249 | EXPECT_DEATH((void)(Align(Value) != 0), ".* should be defined" ); |
250 | EXPECT_DEATH((void)(Align(Value) >= 0), ".* should be defined" ); |
251 | EXPECT_DEATH((void)(Align(Value) <= 0), ".* should be defined" ); |
252 | EXPECT_DEATH((void)(Align(Value) > 0), ".* should be defined" ); |
253 | EXPECT_DEATH((void)(Align(Value) < 0), ".* should be defined" ); |
254 | } |
255 | } |
256 | |
257 | TEST(AlignmentDeathTest, AlignAddr) { |
258 | const void *const unaligned_high_ptr = |
259 | reinterpret_cast<const void *>(std::numeric_limits<uintptr_t>::max() - 1); |
260 | EXPECT_DEATH(alignAddr(unaligned_high_ptr, Align(16)), "Overflow" ); |
261 | } |
262 | |
263 | #endif // NDEBUG |
264 | |
265 | } // end anonymous namespace |
266 | |
267 | #ifdef _MSC_VER |
268 | #pragma warning(pop) |
269 | #endif |
270 | |