1 //===- llvm/unittest/DebugInfo/CodeView/TypeHashingTest.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 "llvm/DebugInfo/CodeView/TypeHashing.h"
10 #include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
11 
12 #include "gtest/gtest.h"
13 
14 using namespace llvm;
15 using namespace llvm::codeview;
16 
createPointerRecord(AppendingTypeTableBuilder & Builder,TypeIndex TI)17 static TypeIndex createPointerRecord(AppendingTypeTableBuilder &Builder,
18                                      TypeIndex TI) {
19   PointerRecord PR(TypeRecordKind::Pointer);
20   PR.setAttrs(PointerKind::Near32, PointerMode::Pointer, PointerOptions::None,
21               4);
22   PR.ReferentType = TI;
23   return Builder.writeLeafType(PR);
24 }
25 
createArgListRecord(AppendingTypeTableBuilder & Builder,TypeIndex Q,TypeIndex R)26 static TypeIndex createArgListRecord(AppendingTypeTableBuilder &Builder,
27                                      TypeIndex Q, TypeIndex R) {
28   ArgListRecord AR(TypeRecordKind::ArgList);
29   AR.ArgIndices.push_back(Q);
30   AR.ArgIndices.push_back(R);
31   return Builder.writeLeafType(AR);
32 }
33 
createProcedureRecord(AppendingTypeTableBuilder & Builder,uint32_t ParamCount,TypeIndex Return,TypeIndex ArgList)34 static TypeIndex createProcedureRecord(AppendingTypeTableBuilder &Builder,
35                                        uint32_t ParamCount, TypeIndex Return,
36                                        TypeIndex ArgList) {
37   ProcedureRecord PR(TypeRecordKind::Procedure);
38   PR.ArgumentList = ArgList;
39   PR.CallConv = CallingConvention::NearC;
40   PR.Options = FunctionOptions::None;
41   PR.ParameterCount = ParamCount;
42   PR.ReturnType = Return;
43   return Builder.writeLeafType(PR);
44 }
45 
hash_of(ArrayRef<GloballyHashedType> Hashes,TypeIndex TI)46 static ArrayRef<uint8_t> hash_of(ArrayRef<GloballyHashedType> Hashes,
47                                  TypeIndex TI) {
48   return Hashes[TI.toArrayIndex()].Hash;
49 }
50 
verifyHashUniqueness(ArrayRef<GloballyHashedType> Hashes)51 static void verifyHashUniqueness(ArrayRef<GloballyHashedType> Hashes) {
52   assert(!Hashes.empty());
53 
54   for (size_t I = 0; I < Hashes.size() - 1; ++I) {
55     for (size_t J = I + 1; J < Hashes.size(); ++J) {
56       EXPECT_NE(Hashes[I].Hash, Hashes[J].Hash);
57     }
58   }
59 }
60 
TEST(TypeHashingTest,ContentHash)61 TEST(TypeHashingTest, ContentHash) {
62   SimpleTypeSerializer Serializer;
63 
64   TypeIndex CharStar(SimpleTypeKind::SignedCharacter,
65                      SimpleTypeMode::NearPointer32);
66 
67   BumpPtrAllocator Alloc;
68   AppendingTypeTableBuilder Ordering1(Alloc);
69   AppendingTypeTableBuilder Ordering2(Alloc);
70 
71   TypeIndex CharP(SimpleTypeKind::SignedCharacter, SimpleTypeMode::NearPointer);
72   TypeIndex IntP(SimpleTypeKind::Int32, SimpleTypeMode::NearPointer);
73   TypeIndex DoubleP(SimpleTypeKind::Float64, SimpleTypeMode::NearPointer);
74 
75   // We're going to the same type sequence with two different orderings, and
76   // then confirm all records are hashed the same.
77 
78   TypeIndex CharPP[2];
79   TypeIndex IntPP[2];
80   TypeIndex IntPPP[2];
81   TypeIndex DoublePP[2];
82   TypeIndex Args[2];
83   TypeIndex Proc[2];
84 
85   // Ordering 1
86   // ----------------------------------------
87   // LF_POINTER             0x1000   {char**}
88   //   Referent = char*
89   // LF_POINTER             0x1001   {int**}
90   //   Referent = int*
91   // LF_POINTER             0x1002   {int***}
92   //   Referent = 0x1001
93   // LF_ARGLIST             0x1003   {(char**, int***)}
94   //   Arg[0] = 0x1000
95   //   Arg[1] = 0x1002
96   // LF_PROCEDURE           0x1004   {int** func(char**, int***)}
97   //   ArgList = 0x1003
98   //   ReturnType = 0x1001
99   std::vector<GloballyHashedType> Ordering1Hashes;
100   CharPP[0] = createPointerRecord(Ordering1, CharP);
101   IntPP[0] = createPointerRecord(Ordering1, IntP);
102   IntPPP[0] = createPointerRecord(Ordering1, IntPP[0]);
103   Args[0] = createArgListRecord(Ordering1, CharPP[0], IntPPP[0]);
104   Proc[0] = createProcedureRecord(Ordering1, 2, IntPP[0], Args[0]);
105 
106   ASSERT_EQ(0x1000U, CharPP[0].getIndex());
107   ASSERT_EQ(0x1001U, IntPP[0].getIndex());
108   ASSERT_EQ(0x1002U, IntPPP[0].getIndex());
109   ASSERT_EQ(0x1003U, Args[0].getIndex());
110   ASSERT_EQ(0x1004U, Proc[0].getIndex());
111 
112   auto Hashes1 = GloballyHashedType::hashTypes(Ordering1.records());
113 
114   // Ordering 2
115   // ----------------------------------------
116   // LF_POINTER             0x1000   {int**}
117   //   Referent = int*
118   // LF_POINTER             0x1001   {int***}
119   //   Referent = 0x1000
120   // LF_POINTER             0x1002   {char**}
121   //   Referent = char*
122   // LF_POINTER             0x1003   {double**}
123   //   Referent = double*
124   // LF_ARGLIST             0x1004   {(char**, int***)}
125   //   Arg[0] = 0x1002
126   //   Arg[1] = 0x1001
127   // LF_PROCEDURE           0x1005   {int** func(char**, int***)}
128   //   ArgList = 0x1004
129   //   ReturnType = 0x1000
130   IntPP[1] = createPointerRecord(Ordering2, IntP);
131   IntPPP[1] = createPointerRecord(Ordering2, IntPP[1]);
132   CharPP[1] = createPointerRecord(Ordering2, CharP);
133   DoublePP[1] = createPointerRecord(Ordering2, DoubleP);
134   Args[1] = createArgListRecord(Ordering2, CharPP[1], IntPPP[1]);
135   Proc[1] = createProcedureRecord(Ordering2, 2, IntPP[1], Args[1]);
136   auto Hashes2 = GloballyHashedType::hashTypes(Ordering2.records());
137 
138   ASSERT_EQ(0x1000U, IntPP[1].getIndex());
139   ASSERT_EQ(0x1001U, IntPPP[1].getIndex());
140   ASSERT_EQ(0x1002U, CharPP[1].getIndex());
141   ASSERT_EQ(0x1003U, DoublePP[1].getIndex());
142   ASSERT_EQ(0x1004U, Args[1].getIndex());
143   ASSERT_EQ(0x1005U, Proc[1].getIndex());
144 
145   // Sanity check to make sure all same-ordering hashes are different
146   // from each other.
147   verifyHashUniqueness(Hashes1);
148   verifyHashUniqueness(Hashes2);
149 
150   EXPECT_EQ(hash_of(Hashes1, IntPP[0]), hash_of(Hashes2, IntPP[1]));
151   EXPECT_EQ(hash_of(Hashes1, IntPPP[0]), hash_of(Hashes2, IntPPP[1]));
152   EXPECT_EQ(hash_of(Hashes1, CharPP[0]), hash_of(Hashes2, CharPP[1]));
153   EXPECT_EQ(hash_of(Hashes1, Args[0]), hash_of(Hashes2, Args[1]));
154   EXPECT_EQ(hash_of(Hashes1, Proc[0]), hash_of(Hashes2, Proc[1]));
155 }
156