Revert r354244 "[DAGCombiner] Eliminate dead stores to stack."
[llvm-complete.git] / unittests / DebugInfo / PDB / HashTableTest.cpp
blob4ebde45ff9a621a10ceb8a31137271ccffafbeec
1 //===- llvm/unittest/DebugInfo/PDB/HashTableTest.cpp ----------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/Native/HashTable.h"
11 #include "llvm/DebugInfo/PDB/Native/Hash.h"
12 #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
13 #include "llvm/Support/Allocator.h"
14 #include "llvm/Support/BinaryByteStream.h"
15 #include "llvm/Support/BinaryStreamReader.h"
16 #include "llvm/Support/BinaryStreamWriter.h"
17 #include "llvm/Support/StringSaver.h"
18 #include "llvm/Testing/Support/Error.h"
20 #include "gtest/gtest.h"
22 #include <vector>
24 using namespace llvm;
25 using namespace llvm::pdb;
26 using namespace llvm::support;
28 namespace {
30 class HashTableInternals : public HashTable<uint32_t> {
31 public:
32 using HashTable::Buckets;
33 using HashTable::Present;
34 using HashTable::Deleted;
38 TEST(HashTableTest, TestSimple) {
39 HashTableInternals Table;
40 EXPECT_EQ(0u, Table.size());
41 EXPECT_GT(Table.capacity(), 0u);
43 Table.set_as(3u, 7);
44 EXPECT_EQ(1u, Table.size());
45 ASSERT_NE(Table.end(), Table.find_as(3u));
46 EXPECT_EQ(7u, Table.get(3u));
49 TEST(HashTableTest, TestCollision) {
50 HashTableInternals Table;
51 EXPECT_EQ(0u, Table.size());
52 EXPECT_GT(Table.capacity(), 0u);
54 // We use knowledge of the hash table's implementation details to make sure
55 // to add another value that is the equivalent to the first value modulo the
56 // hash table's capacity.
57 uint32_t N1 = Table.capacity() + 1;
58 uint32_t N2 = 2 * N1;
60 Table.set_as(N1, 7);
61 Table.set_as(N2, 12);
62 EXPECT_EQ(2u, Table.size());
63 ASSERT_NE(Table.end(), Table.find_as(N1));
64 ASSERT_NE(Table.end(), Table.find_as(N2));
66 EXPECT_EQ(7u, Table.get(N1));
67 EXPECT_EQ(12u, Table.get(N2));
70 TEST(HashTableTest, TestRemove) {
71 HashTableInternals Table;
72 EXPECT_EQ(0u, Table.size());
73 EXPECT_GT(Table.capacity(), 0u);
75 Table.set_as(1u, 2);
76 Table.set_as(3u, 4);
77 EXPECT_EQ(2u, Table.size());
78 ASSERT_NE(Table.end(), Table.find_as(1u));
79 ASSERT_NE(Table.end(), Table.find_as(3u));
81 EXPECT_EQ(2u, Table.get(1u));
82 EXPECT_EQ(4u, Table.get(3u));
85 TEST(HashTableTest, TestCollisionAfterMultipleProbes) {
86 HashTableInternals Table;
87 EXPECT_EQ(0u, Table.size());
88 EXPECT_GT(Table.capacity(), 0u);
90 // Probing looks for the first available slot. A slot may already be filled
91 // as a result of an item with a *different* hash value already being there.
92 // Test that when this happens, the probe still finds the value.
93 uint32_t N1 = Table.capacity() + 1;
94 uint32_t N2 = N1 + 1;
95 uint32_t N3 = 2 * N1;
97 Table.set_as(N1, 7);
98 Table.set_as(N2, 11);
99 Table.set_as(N3, 13);
100 EXPECT_EQ(3u, Table.size());
101 ASSERT_NE(Table.end(), Table.find_as(N1));
102 ASSERT_NE(Table.end(), Table.find_as(N2));
103 ASSERT_NE(Table.end(), Table.find_as(N3));
105 EXPECT_EQ(7u, Table.get(N1));
106 EXPECT_EQ(11u, Table.get(N2));
107 EXPECT_EQ(13u, Table.get(N3));
110 TEST(HashTableTest, Grow) {
111 // So that we are independent of the load factor, `capacity` items, which is
112 // guaranteed to trigger a grow. Then verify that the size is the same, the
113 // capacity is larger, and all the original items are still in the table.
115 HashTableInternals Table;
116 uint32_t OldCapacity = Table.capacity();
117 for (uint32_t I = 0; I < OldCapacity; ++I) {
118 Table.set_as(OldCapacity + I * 2 + 1, I * 2 + 3);
120 EXPECT_EQ(OldCapacity, Table.size());
121 EXPECT_GT(Table.capacity(), OldCapacity);
122 for (uint32_t I = 0; I < OldCapacity; ++I) {
123 ASSERT_NE(Table.end(), Table.find_as(OldCapacity + I * 2 + 1));
124 EXPECT_EQ(I * 2 + 3, Table.get(OldCapacity + I * 2 + 1));
128 TEST(HashTableTest, Serialization) {
129 HashTableInternals Table;
130 uint32_t Cap = Table.capacity();
131 for (uint32_t I = 0; I < Cap; ++I) {
132 Table.set_as(Cap + I * 2 + 1, I * 2 + 3);
135 std::vector<uint8_t> Buffer(Table.calculateSerializedLength());
136 MutableBinaryByteStream Stream(Buffer, little);
137 BinaryStreamWriter Writer(Stream);
138 EXPECT_THAT_ERROR(Table.commit(Writer), Succeeded());
139 // We should have written precisely the number of bytes we calculated earlier.
140 EXPECT_EQ(Buffer.size(), Writer.getOffset());
142 HashTableInternals Table2;
143 BinaryStreamReader Reader(Stream);
144 EXPECT_THAT_ERROR(Table2.load(Reader), Succeeded());
145 // We should have read precisely the number of bytes we calculated earlier.
146 EXPECT_EQ(Buffer.size(), Reader.getOffset());
148 EXPECT_EQ(Table.size(), Table2.size());
149 EXPECT_EQ(Table.capacity(), Table2.capacity());
150 EXPECT_EQ(Table.Buckets, Table2.Buckets);
151 EXPECT_EQ(Table.Present, Table2.Present);
152 EXPECT_EQ(Table.Deleted, Table2.Deleted);
155 TEST(HashTableTest, NamedStreamMap) {
156 std::vector<StringRef> Streams = {"One", "Two", "Three", "Four",
157 "Five", "Six", "Seven"};
158 StringMap<uint32_t> ExpectedIndices;
159 for (uint32_t I = 0; I < Streams.size(); ++I)
160 ExpectedIndices[Streams[I]] = I + 1;
162 // To verify the hash table actually works, we want to verify that insertion
163 // order doesn't matter. So try inserting in every possible order of 7 items.
164 do {
165 NamedStreamMap NSM;
166 for (StringRef S : Streams)
167 NSM.set(S, ExpectedIndices[S]);
169 EXPECT_EQ(Streams.size(), NSM.size());
171 uint32_t N;
172 EXPECT_TRUE(NSM.get("One", N));
173 EXPECT_EQ(1U, N);
175 EXPECT_TRUE(NSM.get("Two", N));
176 EXPECT_EQ(2U, N);
178 EXPECT_TRUE(NSM.get("Three", N));
179 EXPECT_EQ(3U, N);
181 EXPECT_TRUE(NSM.get("Four", N));
182 EXPECT_EQ(4U, N);
184 EXPECT_TRUE(NSM.get("Five", N));
185 EXPECT_EQ(5U, N);
187 EXPECT_TRUE(NSM.get("Six", N));
188 EXPECT_EQ(6U, N);
190 EXPECT_TRUE(NSM.get("Seven", N));
191 EXPECT_EQ(7U, N);
192 } while (std::next_permutation(Streams.begin(), Streams.end()));
195 namespace {
196 struct FooBar {
197 uint32_t X;
198 uint32_t Y;
201 } // namespace
203 namespace llvm {
204 namespace pdb {
205 template <> struct PdbHashTraits<FooBar> {
206 std::vector<char> Buffer;
208 PdbHashTraits() { Buffer.push_back(0); }
210 uint32_t hashLookupKey(StringRef S) const {
211 return llvm::pdb::hashStringV1(S);
214 StringRef storageKeyToLookupKey(uint32_t N) const {
215 if (N >= Buffer.size())
216 return StringRef();
218 return StringRef(Buffer.data() + N);
221 uint32_t lookupKeyToStorageKey(StringRef S) {
222 uint32_t N = Buffer.size();
223 Buffer.insert(Buffer.end(), S.begin(), S.end());
224 Buffer.push_back('\0');
225 return N;
228 } // namespace pdb
229 } // namespace llvm
231 TEST(HashTableTest, NonTrivialValueType) {
232 HashTable<FooBar> Table;
233 uint32_t Cap = Table.capacity();
234 for (uint32_t I = 0; I < Cap; ++I) {
235 FooBar F;
236 F.X = I;
237 F.Y = I + 1;
238 Table.set_as(utostr(I), F);
241 std::vector<uint8_t> Buffer(Table.calculateSerializedLength());
242 MutableBinaryByteStream Stream(Buffer, little);
243 BinaryStreamWriter Writer(Stream);
244 EXPECT_THAT_ERROR(Table.commit(Writer), Succeeded());
245 // We should have written precisely the number of bytes we calculated earlier.
246 EXPECT_EQ(Buffer.size(), Writer.getOffset());
248 HashTable<FooBar> Table2;
249 BinaryStreamReader Reader(Stream);
250 EXPECT_THAT_ERROR(Table2.load(Reader), Succeeded());
251 // We should have read precisely the number of bytes we calculated earlier.
252 EXPECT_EQ(Buffer.size(), Reader.getOffset());
254 EXPECT_EQ(Table.size(), Table2.size());
255 EXPECT_EQ(Table.capacity(), Table2.capacity());
256 // EXPECT_EQ(Table.Buckets, Table2.Buckets);
257 // EXPECT_EQ(Table.Present, Table2.Present);
258 // EXPECT_EQ(Table.Deleted, Table2.Deleted);