1//===- llvm/unittest/CodeGen/DIEHashTest.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//===----------------------------------------------------------------------===//
8
9#include "../lib/CodeGen/AsmPrinter/DIEHash.h"
10#include "TestAsmPrinter.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/BinaryFormat/Dwarf.h"
13#include "llvm/CodeGen/DIE.h"
14#include "llvm/CodeGen/DwarfStringPoolEntry.h"
15#include "llvm/Support/Debug.h"
16#include "llvm/Support/Format.h"
17#include "llvm/TargetParser/Host.h"
18#include "llvm/Testing/Support/Error.h"
19#include "gtest/gtest.h"
20
21using namespace llvm;
22
23namespace {
24
25// Test fixture
26class DIEHashTest : public testing::Test {
27public:
28 BumpPtrAllocator Alloc;
29
30private:
31 StringMap<DwarfStringPoolEntry> Pool;
32 std::unique_ptr<TestAsmPrinter> TestPrinter;
33
34 void setupTestPrinter() {
35 auto ExpectedTestPrinter = TestAsmPrinter::create(
36 TripleStr: sys::getDefaultTargetTriple(), /*DwarfVersion=*/4, DwarfFormat: dwarf::DWARF32);
37 ASSERT_THAT_EXPECTED(ExpectedTestPrinter, Succeeded());
38 TestPrinter = std::move(ExpectedTestPrinter.get());
39 }
40
41public:
42 DIEString getString(StringRef S) {
43 DwarfStringPoolEntry Entry = {.Symbol: nullptr, .Offset: 1, .Index: 1};
44 return DIEString(
45 DwarfStringPoolEntryRef(*Pool.insert(KV: std::make_pair(x&: S, y&: Entry)).first));
46 }
47
48 AsmPrinter *getAsmPrinter() {
49 if (!TestPrinter)
50 setupTestPrinter();
51 return TestPrinter ? TestPrinter->getAP() : nullptr;
52 }
53};
54
55TEST_F(DIEHashTest, Data1) {
56 DIEHash Hash;
57 DIE &Die = *DIE::get(Alloc, Tag: dwarf::DW_TAG_base_type);
58 DIEInteger Size(4);
59 Die.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Size);
60 uint64_t MD5Res = Hash.computeTypeSignature(Die);
61 ASSERT_EQ(0x1AFE116E83701108ULL, MD5Res);
62}
63
64// struct {};
65TEST_F(DIEHashTest, TrivialType) {
66 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
67 DIEInteger One(1);
68 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
69
70 // Line and file number are ignored.
71 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
72 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: One);
73 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Unnamed);
74
75 // The exact same hash GCC produces for this DIE.
76 ASSERT_EQ(0x715305CE6CFD9AD1ULL, MD5Res);
77}
78
79// struct foo { };
80TEST_F(DIEHashTest, NamedType) {
81 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
82 DIEInteger One(1);
83 DIEString FooStr = getString(S: "foo");
84 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
85 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
86
87 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
88
89 // The exact same hash GCC produces for this DIE.
90 ASSERT_EQ(0xD566DBD2CA5265FFULL, MD5Res);
91}
92
93// namespace space { struct foo { }; }
94TEST_F(DIEHashTest, NamespacedType) {
95 DIE &CU = *DIE::get(Alloc, Tag: dwarf::DW_TAG_compile_unit);
96
97 auto Space = DIE::get(Alloc, Tag: dwarf::DW_TAG_namespace);
98 DIEInteger One(1);
99 DIEString SpaceStr = getString(S: "space");
100 Space->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: SpaceStr);
101 // DW_AT_declaration is ignored.
102 Space->addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
103 Value&: One);
104 // sibling?
105
106 auto Foo = DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
107 DIEString FooStr = getString(S: "foo");
108 Foo->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
109 Foo->addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
110
111 DIE &N = *Foo;
112 Space->addChild(Child: std::move(Foo));
113 CU.addChild(Child: std::move(Space));
114
115 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: N);
116
117 // The exact same hash GCC produces for this DIE.
118 ASSERT_EQ(0x7b80381fd17f1e33ULL, MD5Res);
119}
120
121// struct { int member; };
122TEST_F(DIEHashTest, TypeWithMember) {
123 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
124 DIEInteger Four(4);
125 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Four);
126
127 DIE &Int = *DIE::get(Alloc, Tag: dwarf::DW_TAG_base_type);
128 DIEString IntStr = getString(S: "int");
129 Int.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: IntStr);
130 Int.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Four);
131 DIEInteger Five(5);
132 Int.addValue(Alloc, Attribute: dwarf::DW_AT_encoding, Form: dwarf::DW_FORM_data1, Value&: Five);
133
134 DIEEntry IntRef(Int);
135
136 auto Member = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
137 DIEString MemberStr = getString(S: "member");
138 Member->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemberStr);
139 DIEInteger Zero(0);
140 Member->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location,
141 Form: dwarf::DW_FORM_data1, Value&: Zero);
142 Member->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: IntRef);
143
144 Unnamed.addChild(Child: std::move(Member));
145
146 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Unnamed);
147
148 ASSERT_EQ(0x5646aa436b7e07c6ULL, MD5Res);
149}
150
151// struct foo { int mem1, mem2; };
152TEST_F(DIEHashTest, ReusedType) {
153 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
154 DIEInteger Eight(8);
155 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
156
157 DIEInteger Four(4);
158 DIE &Int = *DIE::get(Alloc, Tag: dwarf::DW_TAG_base_type);
159 DIEString IntStr = getString(S: "int");
160 Int.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: IntStr);
161 Int.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Four);
162 DIEInteger Five(5);
163 Int.addValue(Alloc, Attribute: dwarf::DW_AT_encoding, Form: dwarf::DW_FORM_data1, Value&: Five);
164
165 DIEEntry IntRef(Int);
166
167 auto Mem1 = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
168 DIEString Mem1Str = getString(S: "mem1");
169 Mem1->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: Mem1Str);
170 DIEInteger Zero(0);
171 Mem1->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
172 Value&: Zero);
173 Mem1->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: IntRef);
174
175 Unnamed.addChild(Child: std::move(Mem1));
176
177 auto Mem2 = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
178 DIEString Mem2Str = getString(S: "mem2");
179 Mem2->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: Mem2Str);
180 Mem2->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
181 Value&: Four);
182 Mem2->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: IntRef);
183
184 Unnamed.addChild(Child: std::move(Mem2));
185
186 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Unnamed);
187
188 ASSERT_EQ(0x3a7dc3ed7b76b2f8ULL, MD5Res);
189}
190
191// struct foo { static foo f; };
192TEST_F(DIEHashTest, RecursiveType) {
193 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
194 DIEInteger One(1);
195 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
196 DIEString FooStr = getString(S: "foo");
197 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
198
199 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
200 DIEString MemStr = getString(S: "mem");
201 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
202 DIEEntry FooRef(Foo);
203 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooRef);
204 // DW_AT_external and DW_AT_declaration are ignored anyway, so skip them.
205
206 Foo.addChild(Child: std::move(Mem));
207
208 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
209
210 ASSERT_EQ(0x73d8b25aef227b06ULL, MD5Res);
211}
212
213// struct foo { foo *mem; };
214TEST_F(DIEHashTest, Pointer) {
215 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
216 DIEInteger Eight(8);
217 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
218 DIEString FooStr = getString(S: "foo");
219 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
220
221 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
222 DIEString MemStr = getString(S: "mem");
223 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
224 DIEInteger Zero(0);
225 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
226 Value&: Zero);
227
228 DIE &FooPtr = *DIE::get(Alloc, Tag: dwarf::DW_TAG_pointer_type);
229 FooPtr.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
230 DIEEntry FooRef(Foo);
231 FooPtr.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooRef);
232
233 DIEEntry FooPtrRef(FooPtr);
234 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooPtrRef);
235
236 Foo.addChild(Child: std::move(Mem));
237
238 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
239
240 ASSERT_EQ(0x74ea73862e8708d2ULL, MD5Res);
241}
242
243// struct foo { foo &mem; };
244TEST_F(DIEHashTest, Reference) {
245 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
246 DIEInteger Eight(8);
247 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
248 DIEString FooStr = getString(S: "foo");
249 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
250
251 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
252 DIEString MemStr = getString(S: "mem");
253 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
254 DIEInteger Zero(0);
255 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
256 Value&: Zero);
257
258 DIE &FooRef = *DIE::get(Alloc, Tag: dwarf::DW_TAG_reference_type);
259 FooRef.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
260 DIEEntry FooEntry(Foo);
261 FooRef.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooEntry);
262
263 DIE &FooRefConst = *DIE::get(Alloc, Tag: dwarf::DW_TAG_const_type);
264 DIEEntry FooRefRef(FooRef);
265 FooRefConst.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
266 Value&: FooRefRef);
267
268 DIEEntry FooRefConstRef(FooRefConst);
269 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooRefConstRef);
270
271 Foo.addChild(Child: std::move(Mem));
272
273 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
274
275 ASSERT_EQ(0xa0b15f467ad4525bULL, MD5Res);
276}
277
278// struct foo { foo &&mem; };
279TEST_F(DIEHashTest, RValueReference) {
280 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
281 DIEInteger Eight(8);
282 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
283 DIEString FooStr = getString(S: "foo");
284 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
285
286 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
287 DIEString MemStr = getString(S: "mem");
288 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
289 DIEInteger Zero(0);
290 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
291 Value&: Zero);
292
293 DIE &FooRef = *DIE::get(Alloc, Tag: dwarf::DW_TAG_rvalue_reference_type);
294 FooRef.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
295 DIEEntry FooEntry(Foo);
296 FooRef.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooEntry);
297
298 DIE &FooRefConst = *DIE::get(Alloc, Tag: dwarf::DW_TAG_const_type);
299 DIEEntry FooRefRef(FooRef);
300 FooRefConst.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
301 Value&: FooRefRef);
302
303 DIEEntry FooRefConstRef(FooRefConst);
304 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooRefConstRef);
305
306 Foo.addChild(Child: std::move(Mem));
307
308 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
309
310 ASSERT_EQ(0xad211c8c3b31e57ULL, MD5Res);
311}
312
313// struct foo { foo foo::*mem; };
314TEST_F(DIEHashTest, PtrToMember) {
315 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
316 DIEInteger Eight(8);
317 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
318 DIEString FooStr = getString(S: "foo");
319 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
320
321 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
322 DIEString MemStr = getString(S: "mem");
323 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
324 DIEInteger Zero(0);
325 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
326 Value&: Zero);
327
328 DIE &PtrToFooMem = *DIE::get(Alloc, Tag: dwarf::DW_TAG_ptr_to_member_type);
329 DIEEntry FooEntry(Foo);
330 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FooEntry);
331 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_containing_type, Form: dwarf::DW_FORM_ref4,
332 Value&: FooEntry);
333
334 DIEEntry PtrToFooMemRef(PtrToFooMem);
335 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: PtrToFooMemRef);
336
337 Foo.addChild(Child: std::move(Mem));
338
339 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
340
341 ASSERT_EQ(0x852e0c9ff7c04ebULL, MD5Res);
342}
343
344// Check that the hash for a pointer-to-member matches regardless of whether the
345// pointed-to type is a declaration or a definition.
346//
347// struct bar; // { };
348// struct foo { bar foo::*mem; };
349TEST_F(DIEHashTest, PtrToMemberDeclDefMatch) {
350 DIEInteger Zero(0);
351 DIEInteger One(1);
352 DIEInteger Eight(8);
353 DIEString FooStr = getString(S: "foo");
354 DIEString BarStr = getString(S: "bar");
355 DIEString MemStr = getString(S: "mem");
356 uint64_t MD5ResDecl;
357 {
358 DIE &Bar = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
359 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: BarStr);
360 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
361 Value&: One);
362
363 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
364 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
365 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
366
367 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
368 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
369 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location,
370 Form: dwarf::DW_FORM_data1, Value&: Zero);
371
372 DIE &PtrToFooMem = *DIE::get(Alloc, Tag: dwarf::DW_TAG_ptr_to_member_type);
373 DIEEntry BarEntry(Bar);
374 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
375 Value&: BarEntry);
376 DIEEntry FooEntry(Foo);
377 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_containing_type,
378 Form: dwarf::DW_FORM_ref4, Value&: FooEntry);
379
380 DIEEntry PtrToFooMemRef(PtrToFooMem);
381 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
382 Value&: PtrToFooMemRef);
383
384 Foo.addChild(Child: std::move(Mem));
385
386 MD5ResDecl = DIEHash().computeTypeSignature(Die: Foo);
387 }
388 uint64_t MD5ResDef;
389 {
390 DIE &Bar = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
391 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: BarStr);
392 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
393
394 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
395 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
396 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
397
398 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
399 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
400 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location,
401 Form: dwarf::DW_FORM_data1, Value&: Zero);
402
403 DIE &PtrToFooMem = *DIE::get(Alloc, Tag: dwarf::DW_TAG_ptr_to_member_type);
404 DIEEntry BarEntry(Bar);
405 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
406 Value&: BarEntry);
407 DIEEntry FooEntry(Foo);
408 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_containing_type,
409 Form: dwarf::DW_FORM_ref4, Value&: FooEntry);
410
411 DIEEntry PtrToFooMemRef(PtrToFooMem);
412 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
413 Value&: PtrToFooMemRef);
414
415 Foo.addChild(Child: std::move(Mem));
416
417 MD5ResDef = DIEHash().computeTypeSignature(Die: Foo);
418 }
419 ASSERT_EQ(MD5ResDef, MD5ResDecl);
420}
421
422// Check that the hash for a pointer-to-member matches regardless of whether the
423// pointed-to type is a declaration or a definition.
424//
425// struct bar; // { };
426// struct foo { bar bar::*mem; };
427TEST_F(DIEHashTest, PtrToMemberDeclDefMisMatch) {
428 DIEInteger Zero(0);
429 DIEInteger One(1);
430 DIEInteger Eight(8);
431 DIEString FooStr = getString(S: "foo");
432 DIEString BarStr = getString(S: "bar");
433 DIEString MemStr = getString(S: "mem");
434 uint64_t MD5ResDecl;
435 {
436 DIE &Bar = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
437 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: BarStr);
438 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
439 Value&: One);
440
441 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
442 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
443 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
444
445 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
446 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
447 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location,
448 Form: dwarf::DW_FORM_data1, Value&: Zero);
449
450 DIE &PtrToFooMem = *DIE::get(Alloc, Tag: dwarf::DW_TAG_ptr_to_member_type);
451 DIEEntry BarEntry(Bar);
452 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
453 Value&: BarEntry);
454 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_containing_type,
455 Form: dwarf::DW_FORM_ref4, Value&: BarEntry);
456
457 DIEEntry PtrToFooMemRef(PtrToFooMem);
458 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
459 Value&: PtrToFooMemRef);
460
461 Foo.addChild(Child: std::move(Mem));
462
463 MD5ResDecl = DIEHash().computeTypeSignature(Die: Foo);
464 }
465 uint64_t MD5ResDef;
466 {
467 DIE &Bar = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
468 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: BarStr);
469 Bar.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
470
471 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
472 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
473 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
474
475 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
476 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
477 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location,
478 Form: dwarf::DW_FORM_data1, Value&: Zero);
479
480 DIE &PtrToFooMem = *DIE::get(Alloc, Tag: dwarf::DW_TAG_ptr_to_member_type);
481 DIEEntry BarEntry(Bar);
482 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
483 Value&: BarEntry);
484 PtrToFooMem.addValue(Alloc, Attribute: dwarf::DW_AT_containing_type,
485 Form: dwarf::DW_FORM_ref4, Value&: BarEntry);
486
487 DIEEntry PtrToFooMemRef(PtrToFooMem);
488 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
489 Value&: PtrToFooMemRef);
490
491 Foo.addChild(Child: std::move(Mem));
492
493 MD5ResDef = DIEHash().computeTypeSignature(Die: Foo);
494 }
495 // FIXME: This seems to be a bug in the DWARF type hashing specification that
496 // only uses the brief name hashing for types referenced via DW_AT_type. In
497 // this case the type is referenced via DW_AT_containing_type and full hashing
498 // causes a hash to differ when the containing type is a declaration in one TU
499 // and a definition in another.
500 ASSERT_NE(MD5ResDef, MD5ResDecl);
501}
502
503// struct { } a;
504// struct foo { decltype(a) mem; };
505TEST_F(DIEHashTest, RefUnnamedType) {
506 DIEInteger Zero(0);
507 DIEInteger One(1);
508 DIEInteger Eight(8);
509 DIEString FooStr = getString(S: "foo");
510 DIEString MemStr = getString(S: "mem");
511
512 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
513 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
514
515 DIE &Foo = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
516 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Eight);
517 Foo.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
518
519 auto Mem = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
520 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: MemStr);
521 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_data_member_location, Form: dwarf::DW_FORM_data1,
522 Value&: Zero);
523
524 DIE &UnnamedPtr = *DIE::get(Alloc, Tag: dwarf::DW_TAG_pointer_type);
525 UnnamedPtr.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1,
526 Value&: Eight);
527 DIEEntry UnnamedRef(Unnamed);
528 UnnamedPtr.addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4,
529 Value&: UnnamedRef);
530
531 DIEEntry UnnamedPtrRef(UnnamedPtr);
532 Mem->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: UnnamedPtrRef);
533
534 Foo.addChild(Child: std::move(Mem));
535
536 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Foo);
537
538 ASSERT_EQ(0x954e026f01c02529ULL, MD5Res);
539}
540
541// struct { struct foo { }; };
542TEST_F(DIEHashTest, NestedType) {
543 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
544 DIEInteger One(1);
545 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
546
547 auto Foo = DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
548 DIEString FooStr = getString(S: "foo");
549 Foo->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FooStr);
550 Foo->addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
551
552 Unnamed.addChild(Child: std::move(Foo));
553
554 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Unnamed);
555
556 // The exact same hash GCC produces for this DIE.
557 ASSERT_EQ(0xde8a3b7b43807f4aULL, MD5Res);
558}
559
560// struct { static void func(); };
561TEST_F(DIEHashTest, MemberFunc) {
562 DIE &Unnamed = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
563 DIEInteger One(1);
564 Unnamed.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
565
566 auto Func = DIE::get(Alloc, Tag: dwarf::DW_TAG_subprogram);
567 DIEString FuncStr = getString(S: "func");
568 Func->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FuncStr);
569
570 Unnamed.addChild(Child: std::move(Func));
571
572 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: Unnamed);
573
574 // The exact same hash GCC produces for this DIE.
575 ASSERT_EQ(0xd36a1b6dfb604ba0ULL, MD5Res);
576}
577
578// struct A {
579// static void func();
580// };
581TEST_F(DIEHashTest, MemberFuncFlag) {
582 DIE &A = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
583 DIEInteger One(1);
584 DIEString AStr = getString(S: "A");
585 A.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: AStr);
586 A.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
587 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
588 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: One);
589
590 auto Func = DIE::get(Alloc, Tag: dwarf::DW_TAG_subprogram);
591 DIEString FuncStr = getString(S: "func");
592 DIEString FuncLinkage = getString(S: "_ZN1A4funcEv");
593 DIEInteger Two(2);
594 Func->addValue(Alloc, Attribute: dwarf::DW_AT_external, Form: dwarf::DW_FORM_flag_present,
595 Value&: One);
596 Func->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FuncStr);
597 Func->addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
598 Func->addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: Two);
599 Func->addValue(Alloc, Attribute: dwarf::DW_AT_linkage_name, Form: dwarf::DW_FORM_strp,
600 Value&: FuncLinkage);
601 Func->addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
602 Value&: One);
603
604 A.addChild(Child: std::move(Func));
605
606 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: A);
607
608 // The exact same hash GCC produces for this DIE.
609 ASSERT_EQ(0x8F78211DDCE3DF10ULL, MD5Res);
610}
611
612// Derived from:
613// struct A {
614// const static int PI = -3;
615// };
616// A a;
617TEST_F(DIEHashTest, MemberSdata) {
618 DIE &A = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
619 DIEInteger One(1);
620 DIEString AStr = getString(S: "A");
621 A.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: AStr);
622 A.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
623 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
624 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: One);
625
626 DIEInteger Four(4);
627 DIEInteger Five(5);
628 DIEString FStr = getString(S: "int");
629 DIE &IntTyDIE = *DIE::get(Alloc, Tag: dwarf::DW_TAG_base_type);
630 IntTyDIE.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: Four);
631 IntTyDIE.addValue(Alloc, Attribute: dwarf::DW_AT_encoding, Form: dwarf::DW_FORM_data1, Value&: Five);
632 IntTyDIE.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FStr);
633
634 DIEEntry IntTy(IntTyDIE);
635 auto PITyDIE = DIE::get(Alloc, Tag: dwarf::DW_TAG_const_type);
636 PITyDIE->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: IntTy);
637
638 DIEEntry PITy(*PITyDIE);
639 auto PI = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
640 DIEString PIStr = getString(S: "PI");
641 DIEInteger Two(2);
642 DIEInteger NegThree(-3);
643 PI->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: PIStr);
644 PI->addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
645 PI->addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: Two);
646 PI->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: PITy);
647 PI->addValue(Alloc, Attribute: dwarf::DW_AT_external, Form: dwarf::DW_FORM_flag_present, Value&: One);
648 PI->addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
649 Value&: One);
650 PI->addValue(Alloc, Attribute: dwarf::DW_AT_const_value, Form: dwarf::DW_FORM_sdata, Value&: NegThree);
651
652 A.addChild(Child: std::move(PI));
653
654 uint64_t MD5Res = DIEHash().computeTypeSignature(Die: A);
655 ASSERT_EQ(0x9A216000DD3788A7ULL, MD5Res);
656}
657
658// Derived from:
659// struct A {
660// const static float PI = 3.14;
661// };
662// A a;
663TEST_F(DIEHashTest, MemberBlock) {
664 if (!this->getAsmPrinter())
665 GTEST_SKIP();
666
667 DIE &A = *DIE::get(Alloc, Tag: dwarf::DW_TAG_structure_type);
668 DIEInteger One(1);
669 DIEString AStr = getString(S: "A");
670 A.addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: AStr);
671 A.addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1, Value&: One);
672 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
673 A.addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: One);
674
675 DIEInteger Four(4);
676 DIEString FStr = getString(S: "float");
677 auto FloatTyDIE = DIE::get(Alloc, Tag: dwarf::DW_TAG_base_type);
678 FloatTyDIE->addValue(Alloc, Attribute: dwarf::DW_AT_byte_size, Form: dwarf::DW_FORM_data1,
679 Value&: Four);
680 FloatTyDIE->addValue(Alloc, Attribute: dwarf::DW_AT_encoding, Form: dwarf::DW_FORM_data1,
681 Value&: Four);
682 FloatTyDIE->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: FStr);
683 DIEEntry FloatTy(*FloatTyDIE);
684 auto PITyDIE = DIE::get(Alloc, Tag: dwarf::DW_TAG_const_type);
685 PITyDIE->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: FloatTy);
686
687 DIEEntry PITy(*PITyDIE);
688 auto PI = DIE::get(Alloc, Tag: dwarf::DW_TAG_member);
689 DIEString PIStr = getString(S: "PI");
690 DIEInteger Two(2);
691 PI->addValue(Alloc, Attribute: dwarf::DW_AT_name, Form: dwarf::DW_FORM_strp, Value&: PIStr);
692 PI->addValue(Alloc, Attribute: dwarf::DW_AT_decl_file, Form: dwarf::DW_FORM_data1, Value&: One);
693 PI->addValue(Alloc, Attribute: dwarf::DW_AT_decl_line, Form: dwarf::DW_FORM_data1, Value&: Two);
694 PI->addValue(Alloc, Attribute: dwarf::DW_AT_type, Form: dwarf::DW_FORM_ref4, Value&: PITy);
695 PI->addValue(Alloc, Attribute: dwarf::DW_AT_external, Form: dwarf::DW_FORM_flag_present, Value&: One);
696 PI->addValue(Alloc, Attribute: dwarf::DW_AT_declaration, Form: dwarf::DW_FORM_flag_present,
697 Value&: One);
698
699 DIEBlock PIBlock;
700 DIEInteger Blk1(0xc3);
701 DIEInteger Blk2(0xf5);
702 DIEInteger Blk3(0x48);
703 DIEInteger Blk4(0x40);
704
705 PIBlock.addValue(Alloc, Attribute: (dwarf::Attribute)0, Form: dwarf::DW_FORM_data1, Value&: Blk1);
706 PIBlock.addValue(Alloc, Attribute: (dwarf::Attribute)0, Form: dwarf::DW_FORM_data1, Value&: Blk2);
707 PIBlock.addValue(Alloc, Attribute: (dwarf::Attribute)0, Form: dwarf::DW_FORM_data1, Value&: Blk3);
708 PIBlock.addValue(Alloc, Attribute: (dwarf::Attribute)0, Form: dwarf::DW_FORM_data1, Value&: Blk4);
709
710 PI->addValue(Alloc, Attribute: dwarf::DW_AT_const_value, Form: dwarf::DW_FORM_block1,
711 Value: &PIBlock);
712
713 A.addChild(Child: std::move(PI));
714
715 uint64_t MD5Res = DIEHash(this->getAsmPrinter()).computeTypeSignature(Die: A);
716 ASSERT_EQ(0x493AF53AD3D3F651ULL, MD5Res);
717}
718}
719

source code of llvm/unittests/CodeGen/DIEHashTest.cpp